1use std::fmt::Debug;
7use thiserror::Error;
8
9#[derive(Debug, Error)]
11pub enum MeshSieveError {
12 #[error("Missing overlap: {source}")]
14 MissingOverlap {
15 source: Box<dyn std::error::Error + Send + Sync>,
16 },
17 #[error("mesh error: {0}")]
19 MeshError(Box<MeshSieveError>),
20 #[error("Invalid renumbering permutation: {0}")]
22 InvalidPermutation(String),
23 #[error("GPU buffer mapping failed")]
25 GpuMappingFailed,
26 #[error("PointId must be non-zero (0 is reserved as invalid/sentinel)")]
28 InvalidPointId,
29 #[error("stack arrow references missing point in {role}: {point}")]
31 StackMissingPoint { role: &'static str, point: String },
32 #[error("Unsupported stack operation: {0}")]
34 UnsupportedStackOperation(&'static str),
35 #[error("Topology error: point `{0}` found in cone but not in point set")]
37 MissingPointInCone(String),
38 #[error("Topology error: point `{0}` not present in chart")]
40 UnknownPoint(String),
41 #[error("Topology error: cycle detected in mesh (expected DAG)")]
43 CycleDetected,
44 #[error("Atlas error: zero-length slice is not allowed")]
46 ZeroLengthSlice,
47 #[error("Atlas error: point {0:?} already present")]
49 DuplicatePoint(crate::topology::point::PointId),
50 #[error("Atlas internal error: missing length for point {0:?}")]
52 MissingAtlasPoint(crate::topology::point::PointId),
53 #[error("Section error: point {0:?} not found in atlas")]
55 PointNotInAtlas(crate::topology::point::PointId),
56 #[error("SievedArray error: point {0:?} not found in atlas")]
58 SievedArrayPointNotInAtlas(crate::topology::point::PointId),
59
60 #[error("Section error: slice length mismatch for {point:?}: expected {expected}, got {found}")]
62 SliceLengthMismatch {
63 point: crate::topology::point::PointId,
64 expected: usize,
65 found: usize,
66 },
67 #[deprecated(note = "Use AtlasPointLengthChanged")]
69 #[error("atlas slice length changed for {point:?}: {old} -> {new}")]
70 AtlasSliceLengthChanged {
71 point: crate::topology::point::PointId,
72 old: usize,
73 new: usize,
74 },
75 #[error(
77 "SievedArray error: slice length mismatch at {point:?}: expected {expected}, got {found}"
78 )]
79 SievedArraySliceLengthMismatch {
80 point: crate::topology::point::PointId,
81 expected: usize,
82 found: usize,
83 },
84
85 #[error("Refinement maps more than one coarse point into the same fine point {fine:?}")]
87 DuplicateRefinementTarget {
88 fine: crate::topology::point::PointId,
89 },
90
91 #[error("Section error: failed to add point {0:?} to atlas: {1}")]
93 AtlasInsertionFailed(
94 crate::topology::point::PointId,
95 #[source] Box<MeshSieveError>,
96 ),
97 #[error("Section internal error: missing data for point {0:?}")]
99 MissingSectionPoint(crate::topology::point::PointId),
100 #[error("scatter total length mismatch (expected={expected}, found={found})")]
102 ScatterLengthMismatch { expected: usize, found: usize },
103 #[error("scatter chunk out of bounds or overflow (offset={offset}, len={len})")]
105 ScatterChunkMismatch { offset: usize, len: usize },
106 #[error("plan stale: built for atlas version {expected}, current {found}")]
108 AtlasPlanStale { expected: u64, found: u64 },
109 #[error("Missing section name {name}")]
111 MissingSectionName { name: String },
112 #[error("vector section mismatch: expected {expected}, found {found:?}")]
114 VectorSectionMismatch {
115 expected: String,
116 found: Option<String>,
117 },
118 #[error("Tagged section type mismatch (expected {expected:?}, found {found:?})")]
120 TaggedSectionTypeMismatch {
121 expected: crate::data::mixed_section::ScalarType,
122 found: crate::data::mixed_section::ScalarType,
123 },
124 #[error("Ownership missing for point {0:?}")]
126 MissingOwnership(crate::topology::point::PointId),
127 #[error("atlas point length changed for {point:?} (expected={expected}, found={found})")]
129 AtlasPointLengthChanged {
130 point: crate::topology::point::PointId,
131 expected: usize,
132 found: usize,
133 },
134 #[error("reduction length mismatch (expected={expected}, found={found})")]
136 ReducerLengthMismatch { expected: usize, found: usize },
137 #[error(
139 "atlas contiguity mismatch for {point:?} (expected_offset={expected}, found_offset={found})"
140 )]
141 AtlasContiguityMismatch {
142 point: crate::topology::point::PointId,
143 expected: usize,
144 found: usize,
145 },
146 #[error("SievedArray error: cannot convert count {0} via FromPrimitive")]
148 SievedArrayPrimitiveConversionFailure(usize),
149 #[error("Delta error: slice length mismatch (src.len={expected}, dest.len={found})")]
151 DeltaLengthMismatch { expected: usize, found: usize },
152 #[error("Constraint error at point {point:?}: DOF index {index} out of bounds (len={len})")]
154 ConstraintIndexOutOfBounds {
155 point: crate::topology::point::PointId,
156 index: usize,
157 len: usize,
158 },
159 #[error(
161 "Refinement topology mismatch for cell {cell:?}: template {template} expects {expected} vertices, found {found}"
162 )]
163 RefinementTopologyMismatch {
164 cell: crate::topology::point::PointId,
165 template: &'static str,
166 expected: usize,
167 found: usize,
168 },
169 #[error("Unsupported refinement cell type {cell_type:?} at cell {cell:?}")]
171 UnsupportedRefinementCellType {
172 cell: crate::topology::point::PointId,
173 cell_type: crate::topology::cell_type::CellType,
174 },
175 #[error("Invalid partition owner: computed raw ID = 0")]
177 PartitionPointOverflow,
178 #[error("No partition mapping for point ID {0}")]
180 PartitionIndexOutOfBounds(usize),
181 #[error("communication error: {0}")]
183 Communication(#[from] CommError),
184
185 #[error("Missing recv count for neighbor {neighbor}")]
187 MissingRecvCount { neighbor: usize },
188 #[error("Section access error at point {point:?}: {source}")]
190 SectionAccess {
191 point: crate::topology::point::PointId,
192 #[source]
193 source: Box<dyn std::error::Error + Send + Sync>,
194 },
195 #[error("Communication error with neighbor {neighbor}: {source}")]
197 CommError {
198 neighbor: usize,
199 #[source]
200 source: Box<dyn std::error::Error + Send + Sync>,
201 },
202 #[error("Buffer size mismatch for neighbor {neighbor}: expected {expected}, got {got}")]
204 BufferSizeMismatch {
205 neighbor: usize,
206 expected: usize,
207 got: usize,
208 },
209 #[error("Part count mismatch for neighbor {neighbor}: expected {expected}, got {got}")]
211 PartCountMismatch {
212 neighbor: usize,
213 expected: usize,
214 got: usize,
215 },
216 #[error("Lengths count mismatch for neighbor {neighbor}: expected {expected}, got {got}")]
218 LengthsCountMismatch {
219 neighbor: usize,
220 expected: usize,
221 got: usize,
222 },
223 #[error("Payload count mismatch for neighbor {neighbor}: expected {expected}, got {got}")]
225 PayloadCountMismatch {
226 neighbor: usize,
227 expected: usize,
228 got: usize,
229 },
230
231 #[error("Overlap link not found for (local={0}, rank={1})")]
232 OverlapLinkMissing(crate::topology::point::PointId, usize),
233
234 #[error("Overlap: edge must be Local->Part, found {src:?} -> {dst:?}")]
235 OverlapNonBipartite {
236 src: crate::overlap::overlap::OvlId,
237 dst: crate::overlap::overlap::OvlId,
238 },
239 #[error("expected Local(_), found {found:?}")]
240 OverlapExpectedLocal {
241 found: crate::overlap::overlap::OvlId,
242 },
243 #[error("expected Part(_), found {found:?}")]
244 OverlapExpectedPart {
245 found: crate::overlap::overlap::OvlId,
246 },
247
248 #[error("I/O error: {0}")]
250 Io(#[from] std::io::Error),
251 #[error("HDF5 error: {0}")]
253 Hdf5(#[from] hdf5::Error),
254 #[error("Geometry error: {0}")]
256 InvalidGeometry(String),
257 #[error("Mesh I/O parse error: {0}")]
259 MeshIoParse(String),
260 #[error("Topology error: duplicate arrow {src:?} -> {dst:?}")]
262 DuplicateArrow {
263 src: crate::topology::point::PointId,
264 dst: crate::topology::point::PointId,
265 },
266 #[error(
268 "Topology error: cell {cell:?} of type {cell_type:?} expects cone size {expected}, found {found}"
269 )]
270 ConeSizeMismatch {
271 cell: crate::topology::point::PointId,
272 cell_type: crate::topology::cell_type::CellType,
273 expected: usize,
274 found: usize,
275 },
276 #[error(
278 "Topology error: cell {cell:?} of type {cell_type:?} expects {expected} vertices in closure, found {found}"
279 )]
280 ClosureVertexCountMismatch {
281 cell: crate::topology::point::PointId,
282 cell_type: crate::topology::cell_type::CellType,
283 expected: usize,
284 found: usize,
285 },
286 #[error(
288 "Topology error: non-manifold entity {point:?} (dim={dimension}) has {incident_cells} incident cells"
289 )]
290 NonManifoldIncidentCells {
291 point: crate::topology::point::PointId,
292 dimension: u32,
293 incident_cells: usize,
294 },
295 #[error("Overlap: payload.rank {found} != Part({expected})")]
296 OverlapRankMismatch { expected: usize, found: usize },
297 #[error(
299 "Periodic mapping conflict for slave {slave:?}: existing master {existing:?}, new master {new:?}"
300 )]
301 PeriodicMappingConflict {
302 slave: crate::topology::point::PointId,
303 existing: crate::topology::point::PointId,
304 new: crate::topology::point::PointId,
305 },
306 #[error("Overlap: Part node found in base_points()")]
307 OverlapPartInBasePoints,
308 #[error("Overlap: Local node found in cap_points()")]
309 OverlapLocalInCapPoints,
310 #[error("Overlap: duplicate edge {src:?} -> {dst:?}")]
311 OverlapDuplicateEdge {
312 src: crate::overlap::overlap::OvlId,
313 dst: crate::overlap::overlap::OvlId,
314 },
315 #[error("Overlap: empty Part({rank}) node (no incoming edges)")]
316 OverlapEmptyPart { rank: usize },
317
318 #[error("Topology point {point:?} missing ownership metadata")]
320 TopologyPointMissingOwnership {
321 point: crate::topology::point::PointId,
322 },
323 #[error("Ownership entry for point {point:?} missing from local topology")]
325 OwnershipPointMissingTopology {
326 point: crate::topology::point::PointId,
327 },
328 #[error("Ownership ghost flag mismatch for point {point:?}: owner={owner}, my_rank={my_rank}")]
330 OwnershipGhostMismatch {
331 point: crate::topology::point::PointId,
332 owner: usize,
333 my_rank: usize,
334 },
335 #[error("Ghost point {point:?} owned by rank {owner} missing overlap link")]
337 GhostPointMissingOverlapLink {
338 point: crate::topology::point::PointId,
339 owner: usize,
340 },
341 #[error("Overlap link references point {point:?} missing from local topology")]
343 OverlapPointMissingTopology {
344 point: crate::topology::point::PointId,
345 },
346 #[error("Overlap link references point {point:?} missing ownership metadata")]
348 OverlapPointMissingOwnership {
349 point: crate::topology::point::PointId,
350 },
351
352 #[error("overlap in/out mirror missing: {src:?} -> {dst:?}")]
354 OverlapInOutMirrorMissing {
355 src: crate::overlap::overlap::OvlId,
356 dst: crate::overlap::overlap::OvlId,
357 },
358
359 #[error("overlap in/out payload mismatch on {src:?} -> {dst:?}: out={out:?} in={inn:?}")]
361 OverlapInOutPayloadMismatch {
362 src: crate::overlap::overlap::OvlId,
363 dst: crate::overlap::overlap::OvlId,
364 out: crate::overlap::overlap::Remote,
365 inn: crate::overlap::overlap::Remote,
366 },
367
368 #[error("overlap in/out edge count mismatch: out={out_edges}, in={in_edges}")]
370 OverlapInOutEdgeCountMismatch { out_edges: usize, in_edges: usize },
371
372 #[error(
373 "Overlap resolution conflict for (local={local}, rank={rank}): existing={existing:?}, new={new:?}"
374 )]
375 OverlapResolutionConflict {
376 local: crate::topology::point::PointId,
377 rank: usize,
378 existing: Option<crate::topology::point::PointId>,
379 new: crate::topology::point::PointId,
380 },
381}
382
383impl PartialEq for MeshSieveError {
384 fn eq(&self, other: &MeshSieveError) -> bool {
385 use MeshSieveError::*;
386 match (self, other) {
387 (InvalidPointId, InvalidPointId)
388 | (CycleDetected, CycleDetected)
389 | (ZeroLengthSlice, ZeroLengthSlice)
390 | (PartitionPointOverflow, PartitionPointOverflow)
391 | (GpuMappingFailed, GpuMappingFailed) => true,
392 (InvalidGeometry(a), InvalidGeometry(b)) => a == b,
393 (DuplicateArrow { src: s1, dst: d1 }, DuplicateArrow { src: s2, dst: d2 }) => {
394 s1 == s2 && d1 == d2
395 }
396 (
397 ConeSizeMismatch {
398 cell: c1,
399 cell_type: t1,
400 expected: e1,
401 found: f1,
402 },
403 ConeSizeMismatch {
404 cell: c2,
405 cell_type: t2,
406 expected: e2,
407 found: f2,
408 },
409 ) => c1 == c2 && t1 == t2 && e1 == e2 && f1 == f2,
410 (
411 ClosureVertexCountMismatch {
412 cell: c1,
413 cell_type: t1,
414 expected: e1,
415 found: f1,
416 },
417 ClosureVertexCountMismatch {
418 cell: c2,
419 cell_type: t2,
420 expected: e2,
421 found: f2,
422 },
423 ) => c1 == c2 && t1 == t2 && e1 == e2 && f1 == f2,
424 (
425 NonManifoldIncidentCells {
426 point: p1,
427 dimension: d1,
428 incident_cells: c1,
429 },
430 NonManifoldIncidentCells {
431 point: p2,
432 dimension: d2,
433 incident_cells: c2,
434 },
435 ) => p1 == p2 && d1 == d2 && c1 == c2,
436 (UnsupportedStackOperation(a), UnsupportedStackOperation(b)) => a == b,
437 (
438 VectorSectionMismatch {
439 expected: e1,
440 found: f1,
441 },
442 VectorSectionMismatch {
443 expected: e2,
444 found: f2,
445 },
446 ) => e1 == e2 && f1 == f2,
447 (MissingPointInCone(a), MissingPointInCone(b)) => a == b,
448 (UnknownPoint(a), UnknownPoint(b)) => a == b,
449 (DuplicatePoint(a), DuplicatePoint(b)) => a == b,
450 (MissingAtlasPoint(a), MissingAtlasPoint(b)) => a == b,
451 (PointNotInAtlas(a), PointNotInAtlas(b)) => a == b,
452 (SievedArrayPointNotInAtlas(a), SievedArrayPointNotInAtlas(b)) => a == b,
453 (
454 SliceLengthMismatch {
455 point: p1,
456 expected: e1,
457 found: f1,
458 },
459 SliceLengthMismatch {
460 point: p2,
461 expected: e2,
462 found: f2,
463 },
464 ) => p1 == p2 && e1 == e2 && f1 == f2,
465 (
466 AtlasSliceLengthChanged {
467 point: p1,
468 old: o1,
469 new: n1,
470 },
471 AtlasSliceLengthChanged {
472 point: p2,
473 old: o2,
474 new: n2,
475 },
476 ) => p1 == p2 && o1 == o2 && n1 == n2,
477 (
478 AtlasPointLengthChanged {
479 point: p1,
480 expected: e1,
481 found: f1,
482 },
483 AtlasPointLengthChanged {
484 point: p2,
485 expected: e2,
486 found: f2,
487 },
488 ) => p1 == p2 && e1 == e2 && f1 == f2,
489 (
490 SievedArraySliceLengthMismatch {
491 point: p1,
492 expected: e1,
493 found: f1,
494 },
495 SievedArraySliceLengthMismatch {
496 point: p2,
497 expected: e2,
498 found: f2,
499 },
500 ) => p1 == p2 && e1 == e2 && f1 == f2,
501 (DuplicateRefinementTarget { fine: f1 }, DuplicateRefinementTarget { fine: f2 }) => {
502 f1 == f2
503 }
504 (AtlasInsertionFailed(p1, _), AtlasInsertionFailed(p2, _)) => p1 == p2,
505 (MissingSectionPoint(a), MissingSectionPoint(b)) => a == b,
506 (
507 ScatterLengthMismatch {
508 expected: e1,
509 found: f1,
510 },
511 ScatterLengthMismatch {
512 expected: e2,
513 found: f2,
514 },
515 ) => e1 == e2 && f1 == f2,
516 (
517 ReducerLengthMismatch {
518 expected: e1,
519 found: f1,
520 },
521 ReducerLengthMismatch {
522 expected: e2,
523 found: f2,
524 },
525 ) => e1 == e2 && f1 == f2,
526 (
527 ScatterChunkMismatch {
528 offset: o1,
529 len: l1,
530 },
531 ScatterChunkMismatch {
532 offset: o2,
533 len: l2,
534 },
535 ) => o1 == o2 && l1 == l2,
536 (
537 AtlasContiguityMismatch {
538 point: p1,
539 expected: e1,
540 found: f1,
541 },
542 AtlasContiguityMismatch {
543 point: p2,
544 expected: e2,
545 found: f2,
546 },
547 ) => p1 == p2 && e1 == e2 && f1 == f2,
548 (
549 AtlasPlanStale {
550 expected: e1,
551 found: f1,
552 },
553 AtlasPlanStale {
554 expected: e2,
555 found: f2,
556 },
557 ) => e1 == e2 && f1 == f2,
558 (MissingSectionName { name: n1 }, MissingSectionName { name: n2 }) => n1 == n2,
559 (
560 TaggedSectionTypeMismatch {
561 expected: e1,
562 found: f1,
563 },
564 TaggedSectionTypeMismatch {
565 expected: e2,
566 found: f2,
567 },
568 ) => e1 == e2 && f1 == f2,
569 (MissingOwnership(a), MissingOwnership(b)) => a == b,
570 (
571 SievedArrayPrimitiveConversionFailure(a),
572 SievedArrayPrimitiveConversionFailure(b),
573 ) => a == b,
574 (
575 DeltaLengthMismatch {
576 expected: e1,
577 found: f1,
578 },
579 DeltaLengthMismatch {
580 expected: e2,
581 found: f2,
582 },
583 ) => e1 == e2 && f1 == f2,
584 (PartitionIndexOutOfBounds(a), PartitionIndexOutOfBounds(b)) => a == b,
585 (MissingRecvCount { neighbor: n1 }, MissingRecvCount { neighbor: n2 }) => n1 == n2,
586 (SectionAccess { point: p1, .. }, SectionAccess { point: p2, .. }) => p1 == p2,
587 (CommError { neighbor: n1, .. }, CommError { neighbor: n2, .. }) => n1 == n2,
588 (
589 BufferSizeMismatch {
590 neighbor: n1,
591 expected: e1,
592 got: g1,
593 },
594 BufferSizeMismatch {
595 neighbor: n2,
596 expected: e2,
597 got: g2,
598 },
599 ) => n1 == n2 && e1 == e2 && g1 == g2,
600 (
601 PartCountMismatch {
602 neighbor: n1,
603 expected: e1,
604 got: g1,
605 },
606 PartCountMismatch {
607 neighbor: n2,
608 expected: e2,
609 got: g2,
610 },
611 ) => n1 == n2 && e1 == e2 && g1 == g2,
612 (
613 LengthsCountMismatch {
614 neighbor: n1,
615 expected: e1,
616 got: g1,
617 },
618 LengthsCountMismatch {
619 neighbor: n2,
620 expected: e2,
621 got: g2,
622 },
623 ) => n1 == n2 && e1 == e2 && g1 == g2,
624 (
625 PayloadCountMismatch {
626 neighbor: n1,
627 expected: e1,
628 got: g1,
629 },
630 PayloadCountMismatch {
631 neighbor: n2,
632 expected: e2,
633 got: g2,
634 },
635 ) => n1 == n2 && e1 == e2 && g1 == g2,
636 (Communication(a), Communication(b)) => a == b,
637 (OverlapLinkMissing(a1, b1), OverlapLinkMissing(a2, b2)) => a1 == a2 && b1 == b2,
638 (
639 OverlapNonBipartite { src: s1, dst: d1 },
640 OverlapNonBipartite { src: s2, dst: d2 },
641 ) => s1 == s2 && d1 == d2,
642 (OverlapExpectedLocal { found: f1 }, OverlapExpectedLocal { found: f2 }) => f1 == f2,
643 (OverlapExpectedPart { found: f1 }, OverlapExpectedPart { found: f2 }) => f1 == f2,
644 (
645 OverlapRankMismatch {
646 expected: e1,
647 found: f1,
648 },
649 OverlapRankMismatch {
650 expected: e2,
651 found: f2,
652 },
653 ) => e1 == e2 && f1 == f2,
654 (OverlapPartInBasePoints, OverlapPartInBasePoints) => true,
655 (OverlapLocalInCapPoints, OverlapLocalInCapPoints) => true,
656 (
657 OverlapDuplicateEdge { src: s1, dst: d1 },
658 OverlapDuplicateEdge { src: s2, dst: d2 },
659 ) => s1 == s2 && d1 == d2,
660 (OverlapEmptyPart { rank: r1 }, OverlapEmptyPart { rank: r2 }) => r1 == r2,
661 (
662 TopologyPointMissingOwnership { point: p1 },
663 TopologyPointMissingOwnership { point: p2 },
664 ) => p1 == p2,
665 (
666 OwnershipPointMissingTopology { point: p1 },
667 OwnershipPointMissingTopology { point: p2 },
668 ) => p1 == p2,
669 (
670 OwnershipGhostMismatch {
671 point: p1,
672 owner: o1,
673 my_rank: m1,
674 },
675 OwnershipGhostMismatch {
676 point: p2,
677 owner: o2,
678 my_rank: m2,
679 },
680 ) => p1 == p2 && o1 == o2 && m1 == m2,
681 (
682 GhostPointMissingOverlapLink {
683 point: p1,
684 owner: o1,
685 },
686 GhostPointMissingOverlapLink {
687 point: p2,
688 owner: o2,
689 },
690 ) => p1 == p2 && o1 == o2,
691 (
692 OverlapPointMissingTopology { point: p1 },
693 OverlapPointMissingTopology { point: p2 },
694 ) => p1 == p2,
695 (
696 OverlapPointMissingOwnership { point: p1 },
697 OverlapPointMissingOwnership { point: p2 },
698 ) => p1 == p2,
699 (
700 OverlapInOutMirrorMissing { src: s1, dst: d1 },
701 OverlapInOutMirrorMissing { src: s2, dst: d2 },
702 ) => s1 == s2 && d1 == d2,
703 (
704 OverlapInOutPayloadMismatch {
705 src: s1,
706 dst: d1,
707 out: o1,
708 inn: i1,
709 },
710 OverlapInOutPayloadMismatch {
711 src: s2,
712 dst: d2,
713 out: o2,
714 inn: i2,
715 },
716 ) => s1 == s2 && d1 == d2 && o1 == o2 && i1 == i2,
717 (
718 OverlapInOutEdgeCountMismatch {
719 out_edges: o1,
720 in_edges: i1,
721 },
722 OverlapInOutEdgeCountMismatch {
723 out_edges: o2,
724 in_edges: i2,
725 },
726 ) => o1 == o2 && i1 == i2,
727 (
728 OverlapResolutionConflict {
729 local: l1,
730 rank: r1,
731 existing: ex1,
732 new: n1,
733 },
734 OverlapResolutionConflict {
735 local: l2,
736 rank: r2,
737 existing: ex2,
738 new: n2,
739 },
740 ) => l1 == l2 && r1 == r2 && ex1 == ex2 && n1 == n2,
741 _ => false,
742 }
743 }
744}
745impl Eq for MeshSieveError {}
746
747#[derive(Debug, thiserror::Error, Clone)]
749#[error("{0}")]
750pub struct CommError(pub String);
751
752impl PartialEq for CommError {
753 fn eq(&self, other: &CommError) -> bool {
754 self.0 == other.0
755 }
756}
757impl Eq for CommError {}