use std::fmt::Debug;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum MeshSieveError {
#[error("Missing overlap: {source}")]
MissingOverlap {
source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("mesh error: {0}")]
MeshError(Box<MeshSieveError>),
#[error("Invalid renumbering permutation: {0}")]
InvalidPermutation(String),
#[error("GPU buffer mapping failed")]
GpuMappingFailed,
#[error("PointId must be non-zero (0 is reserved as invalid/sentinel)")]
InvalidPointId,
#[error("stack arrow references missing point in {role}: {point}")]
StackMissingPoint { role: &'static str, point: String },
#[error("Unsupported stack operation: {0}")]
UnsupportedStackOperation(&'static str),
#[error("Topology error: point `{0}` found in cone but not in point set")]
MissingPointInCone(String),
#[error("Topology error: point `{0}` not present in chart")]
UnknownPoint(String),
#[error("Topology error: cycle detected in mesh (expected DAG)")]
CycleDetected,
#[error("Atlas error: zero-length slice is not allowed")]
ZeroLengthSlice,
#[error("Atlas error: point {0:?} already present")]
DuplicatePoint(crate::topology::point::PointId),
#[error("Atlas internal error: missing length for point {0:?}")]
MissingAtlasPoint(crate::topology::point::PointId),
#[error("Section error: point {0:?} not found in atlas")]
PointNotInAtlas(crate::topology::point::PointId),
#[error("SievedArray error: point {0:?} not found in atlas")]
SievedArrayPointNotInAtlas(crate::topology::point::PointId),
#[error("Section error: slice length mismatch for {point:?}: expected {expected}, got {found}")]
SliceLengthMismatch {
point: crate::topology::point::PointId,
expected: usize,
found: usize,
},
#[deprecated(note = "Use AtlasPointLengthChanged")]
#[error("atlas slice length changed for {point:?}: {old} -> {new}")]
AtlasSliceLengthChanged {
point: crate::topology::point::PointId,
old: usize,
new: usize,
},
#[error(
"SievedArray error: slice length mismatch at {point:?}: expected {expected}, got {found}"
)]
SievedArraySliceLengthMismatch {
point: crate::topology::point::PointId,
expected: usize,
found: usize,
},
#[error("Refinement maps more than one coarse point into the same fine point {fine:?}")]
DuplicateRefinementTarget {
fine: crate::topology::point::PointId,
},
#[error("Section error: failed to add point {0:?} to atlas: {1}")]
AtlasInsertionFailed(
crate::topology::point::PointId,
#[source] Box<MeshSieveError>,
),
#[error("Section internal error: missing data for point {0:?}")]
MissingSectionPoint(crate::topology::point::PointId),
#[error("scatter total length mismatch (expected={expected}, found={found})")]
ScatterLengthMismatch { expected: usize, found: usize },
#[error("scatter chunk out of bounds or overflow (offset={offset}, len={len})")]
ScatterChunkMismatch { offset: usize, len: usize },
#[error("plan stale: built for atlas version {expected}, current {found}")]
AtlasPlanStale { expected: u64, found: u64 },
#[error("Missing section name {name}")]
MissingSectionName { name: String },
#[error("vector section mismatch: expected {expected}, found {found:?}")]
VectorSectionMismatch {
expected: String,
found: Option<String>,
},
#[error("Tagged section type mismatch (expected {expected:?}, found {found:?})")]
TaggedSectionTypeMismatch {
expected: crate::data::mixed_section::ScalarType,
found: crate::data::mixed_section::ScalarType,
},
#[error("Ownership missing for point {0:?}")]
MissingOwnership(crate::topology::point::PointId),
#[error("atlas point length changed for {point:?} (expected={expected}, found={found})")]
AtlasPointLengthChanged {
point: crate::topology::point::PointId,
expected: usize,
found: usize,
},
#[error("reduction length mismatch (expected={expected}, found={found})")]
ReducerLengthMismatch { expected: usize, found: usize },
#[error(
"atlas contiguity mismatch for {point:?} (expected_offset={expected}, found_offset={found})"
)]
AtlasContiguityMismatch {
point: crate::topology::point::PointId,
expected: usize,
found: usize,
},
#[error("SievedArray error: cannot convert count {0} via FromPrimitive")]
SievedArrayPrimitiveConversionFailure(usize),
#[error("Delta error: slice length mismatch (src.len={expected}, dest.len={found})")]
DeltaLengthMismatch { expected: usize, found: usize },
#[error("Constraint error at point {point:?}: DOF index {index} out of bounds (len={len})")]
ConstraintIndexOutOfBounds {
point: crate::topology::point::PointId,
index: usize,
len: usize,
},
#[error(
"Refinement topology mismatch for cell {cell:?}: template {template} expects {expected} vertices, found {found}"
)]
RefinementTopologyMismatch {
cell: crate::topology::point::PointId,
template: &'static str,
expected: usize,
found: usize,
},
#[error("Unsupported refinement cell type {cell_type:?} at cell {cell:?}")]
UnsupportedRefinementCellType {
cell: crate::topology::point::PointId,
cell_type: crate::topology::cell_type::CellType,
},
#[error("Invalid partition owner: computed raw ID = 0")]
PartitionPointOverflow,
#[error("No partition mapping for point ID {0}")]
PartitionIndexOutOfBounds(usize),
#[error("communication error: {0}")]
Communication(#[from] CommError),
#[error("Missing recv count for neighbor {neighbor}")]
MissingRecvCount { neighbor: usize },
#[error("Section access error at point {point:?}: {source}")]
SectionAccess {
point: crate::topology::point::PointId,
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("Communication error with neighbor {neighbor}: {source}")]
CommError {
neighbor: usize,
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("Buffer size mismatch for neighbor {neighbor}: expected {expected}, got {got}")]
BufferSizeMismatch {
neighbor: usize,
expected: usize,
got: usize,
},
#[error("Part count mismatch for neighbor {neighbor}: expected {expected}, got {got}")]
PartCountMismatch {
neighbor: usize,
expected: usize,
got: usize,
},
#[error("Lengths count mismatch for neighbor {neighbor}: expected {expected}, got {got}")]
LengthsCountMismatch {
neighbor: usize,
expected: usize,
got: usize,
},
#[error("Payload count mismatch for neighbor {neighbor}: expected {expected}, got {got}")]
PayloadCountMismatch {
neighbor: usize,
expected: usize,
got: usize,
},
#[error("Overlap link not found for (local={0}, rank={1})")]
OverlapLinkMissing(crate::topology::point::PointId, usize),
#[error("Overlap: edge must be Local->Part, found {src:?} -> {dst:?}")]
OverlapNonBipartite {
src: crate::overlap::overlap::OvlId,
dst: crate::overlap::overlap::OvlId,
},
#[error("expected Local(_), found {found:?}")]
OverlapExpectedLocal {
found: crate::overlap::overlap::OvlId,
},
#[error("expected Part(_), found {found:?}")]
OverlapExpectedPart {
found: crate::overlap::overlap::OvlId,
},
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("HDF5 error: {0}")]
Hdf5(#[from] hdf5::Error),
#[error("Geometry error: {0}")]
InvalidGeometry(String),
#[error("Mesh I/O parse error: {0}")]
MeshIoParse(String),
#[error("Topology error: duplicate arrow {src:?} -> {dst:?}")]
DuplicateArrow {
src: crate::topology::point::PointId,
dst: crate::topology::point::PointId,
},
#[error(
"Topology error: cell {cell:?} of type {cell_type:?} expects cone size {expected}, found {found}"
)]
ConeSizeMismatch {
cell: crate::topology::point::PointId,
cell_type: crate::topology::cell_type::CellType,
expected: usize,
found: usize,
},
#[error(
"Topology error: cell {cell:?} of type {cell_type:?} expects {expected} vertices in closure, found {found}"
)]
ClosureVertexCountMismatch {
cell: crate::topology::point::PointId,
cell_type: crate::topology::cell_type::CellType,
expected: usize,
found: usize,
},
#[error(
"Topology error: non-manifold entity {point:?} (dim={dimension}) has {incident_cells} incident cells"
)]
NonManifoldIncidentCells {
point: crate::topology::point::PointId,
dimension: u32,
incident_cells: usize,
},
#[error("Overlap: payload.rank {found} != Part({expected})")]
OverlapRankMismatch { expected: usize, found: usize },
#[error(
"Periodic mapping conflict for slave {slave:?}: existing master {existing:?}, new master {new:?}"
)]
PeriodicMappingConflict {
slave: crate::topology::point::PointId,
existing: crate::topology::point::PointId,
new: crate::topology::point::PointId,
},
#[error("Overlap: Part node found in base_points()")]
OverlapPartInBasePoints,
#[error("Overlap: Local node found in cap_points()")]
OverlapLocalInCapPoints,
#[error("Overlap: duplicate edge {src:?} -> {dst:?}")]
OverlapDuplicateEdge {
src: crate::overlap::overlap::OvlId,
dst: crate::overlap::overlap::OvlId,
},
#[error("Overlap: empty Part({rank}) node (no incoming edges)")]
OverlapEmptyPart { rank: usize },
#[error("Topology point {point:?} missing ownership metadata")]
TopologyPointMissingOwnership {
point: crate::topology::point::PointId,
},
#[error("Ownership entry for point {point:?} missing from local topology")]
OwnershipPointMissingTopology {
point: crate::topology::point::PointId,
},
#[error("Ownership ghost flag mismatch for point {point:?}: owner={owner}, my_rank={my_rank}")]
OwnershipGhostMismatch {
point: crate::topology::point::PointId,
owner: usize,
my_rank: usize,
},
#[error("Ghost point {point:?} owned by rank {owner} missing overlap link")]
GhostPointMissingOverlapLink {
point: crate::topology::point::PointId,
owner: usize,
},
#[error("Overlap link references point {point:?} missing from local topology")]
OverlapPointMissingTopology {
point: crate::topology::point::PointId,
},
#[error("Overlap link references point {point:?} missing ownership metadata")]
OverlapPointMissingOwnership {
point: crate::topology::point::PointId,
},
#[error("overlap in/out mirror missing: {src:?} -> {dst:?}")]
OverlapInOutMirrorMissing {
src: crate::overlap::overlap::OvlId,
dst: crate::overlap::overlap::OvlId,
},
#[error("overlap in/out payload mismatch on {src:?} -> {dst:?}: out={out:?} in={inn:?}")]
OverlapInOutPayloadMismatch {
src: crate::overlap::overlap::OvlId,
dst: crate::overlap::overlap::OvlId,
out: crate::overlap::overlap::Remote,
inn: crate::overlap::overlap::Remote,
},
#[error("overlap in/out edge count mismatch: out={out_edges}, in={in_edges}")]
OverlapInOutEdgeCountMismatch { out_edges: usize, in_edges: usize },
#[error(
"Overlap resolution conflict for (local={local}, rank={rank}): existing={existing:?}, new={new:?}"
)]
OverlapResolutionConflict {
local: crate::topology::point::PointId,
rank: usize,
existing: Option<crate::topology::point::PointId>,
new: crate::topology::point::PointId,
},
}
impl PartialEq for MeshSieveError {
fn eq(&self, other: &MeshSieveError) -> bool {
use MeshSieveError::*;
match (self, other) {
(InvalidPointId, InvalidPointId)
| (CycleDetected, CycleDetected)
| (ZeroLengthSlice, ZeroLengthSlice)
| (PartitionPointOverflow, PartitionPointOverflow)
| (GpuMappingFailed, GpuMappingFailed) => true,
(InvalidGeometry(a), InvalidGeometry(b)) => a == b,
(DuplicateArrow { src: s1, dst: d1 }, DuplicateArrow { src: s2, dst: d2 }) => {
s1 == s2 && d1 == d2
}
(
ConeSizeMismatch {
cell: c1,
cell_type: t1,
expected: e1,
found: f1,
},
ConeSizeMismatch {
cell: c2,
cell_type: t2,
expected: e2,
found: f2,
},
) => c1 == c2 && t1 == t2 && e1 == e2 && f1 == f2,
(
ClosureVertexCountMismatch {
cell: c1,
cell_type: t1,
expected: e1,
found: f1,
},
ClosureVertexCountMismatch {
cell: c2,
cell_type: t2,
expected: e2,
found: f2,
},
) => c1 == c2 && t1 == t2 && e1 == e2 && f1 == f2,
(
NonManifoldIncidentCells {
point: p1,
dimension: d1,
incident_cells: c1,
},
NonManifoldIncidentCells {
point: p2,
dimension: d2,
incident_cells: c2,
},
) => p1 == p2 && d1 == d2 && c1 == c2,
(UnsupportedStackOperation(a), UnsupportedStackOperation(b)) => a == b,
(
VectorSectionMismatch {
expected: e1,
found: f1,
},
VectorSectionMismatch {
expected: e2,
found: f2,
},
) => e1 == e2 && f1 == f2,
(MissingPointInCone(a), MissingPointInCone(b)) => a == b,
(UnknownPoint(a), UnknownPoint(b)) => a == b,
(DuplicatePoint(a), DuplicatePoint(b)) => a == b,
(MissingAtlasPoint(a), MissingAtlasPoint(b)) => a == b,
(PointNotInAtlas(a), PointNotInAtlas(b)) => a == b,
(SievedArrayPointNotInAtlas(a), SievedArrayPointNotInAtlas(b)) => a == b,
(
SliceLengthMismatch {
point: p1,
expected: e1,
found: f1,
},
SliceLengthMismatch {
point: p2,
expected: e2,
found: f2,
},
) => p1 == p2 && e1 == e2 && f1 == f2,
(
AtlasSliceLengthChanged {
point: p1,
old: o1,
new: n1,
},
AtlasSliceLengthChanged {
point: p2,
old: o2,
new: n2,
},
) => p1 == p2 && o1 == o2 && n1 == n2,
(
AtlasPointLengthChanged {
point: p1,
expected: e1,
found: f1,
},
AtlasPointLengthChanged {
point: p2,
expected: e2,
found: f2,
},
) => p1 == p2 && e1 == e2 && f1 == f2,
(
SievedArraySliceLengthMismatch {
point: p1,
expected: e1,
found: f1,
},
SievedArraySliceLengthMismatch {
point: p2,
expected: e2,
found: f2,
},
) => p1 == p2 && e1 == e2 && f1 == f2,
(DuplicateRefinementTarget { fine: f1 }, DuplicateRefinementTarget { fine: f2 }) => {
f1 == f2
}
(AtlasInsertionFailed(p1, _), AtlasInsertionFailed(p2, _)) => p1 == p2,
(MissingSectionPoint(a), MissingSectionPoint(b)) => a == b,
(
ScatterLengthMismatch {
expected: e1,
found: f1,
},
ScatterLengthMismatch {
expected: e2,
found: f2,
},
) => e1 == e2 && f1 == f2,
(
ReducerLengthMismatch {
expected: e1,
found: f1,
},
ReducerLengthMismatch {
expected: e2,
found: f2,
},
) => e1 == e2 && f1 == f2,
(
ScatterChunkMismatch {
offset: o1,
len: l1,
},
ScatterChunkMismatch {
offset: o2,
len: l2,
},
) => o1 == o2 && l1 == l2,
(
AtlasContiguityMismatch {
point: p1,
expected: e1,
found: f1,
},
AtlasContiguityMismatch {
point: p2,
expected: e2,
found: f2,
},
) => p1 == p2 && e1 == e2 && f1 == f2,
(
AtlasPlanStale {
expected: e1,
found: f1,
},
AtlasPlanStale {
expected: e2,
found: f2,
},
) => e1 == e2 && f1 == f2,
(MissingSectionName { name: n1 }, MissingSectionName { name: n2 }) => n1 == n2,
(
TaggedSectionTypeMismatch {
expected: e1,
found: f1,
},
TaggedSectionTypeMismatch {
expected: e2,
found: f2,
},
) => e1 == e2 && f1 == f2,
(MissingOwnership(a), MissingOwnership(b)) => a == b,
(
SievedArrayPrimitiveConversionFailure(a),
SievedArrayPrimitiveConversionFailure(b),
) => a == b,
(
DeltaLengthMismatch {
expected: e1,
found: f1,
},
DeltaLengthMismatch {
expected: e2,
found: f2,
},
) => e1 == e2 && f1 == f2,
(PartitionIndexOutOfBounds(a), PartitionIndexOutOfBounds(b)) => a == b,
(MissingRecvCount { neighbor: n1 }, MissingRecvCount { neighbor: n2 }) => n1 == n2,
(SectionAccess { point: p1, .. }, SectionAccess { point: p2, .. }) => p1 == p2,
(CommError { neighbor: n1, .. }, CommError { neighbor: n2, .. }) => n1 == n2,
(
BufferSizeMismatch {
neighbor: n1,
expected: e1,
got: g1,
},
BufferSizeMismatch {
neighbor: n2,
expected: e2,
got: g2,
},
) => n1 == n2 && e1 == e2 && g1 == g2,
(
PartCountMismatch {
neighbor: n1,
expected: e1,
got: g1,
},
PartCountMismatch {
neighbor: n2,
expected: e2,
got: g2,
},
) => n1 == n2 && e1 == e2 && g1 == g2,
(
LengthsCountMismatch {
neighbor: n1,
expected: e1,
got: g1,
},
LengthsCountMismatch {
neighbor: n2,
expected: e2,
got: g2,
},
) => n1 == n2 && e1 == e2 && g1 == g2,
(
PayloadCountMismatch {
neighbor: n1,
expected: e1,
got: g1,
},
PayloadCountMismatch {
neighbor: n2,
expected: e2,
got: g2,
},
) => n1 == n2 && e1 == e2 && g1 == g2,
(Communication(a), Communication(b)) => a == b,
(OverlapLinkMissing(a1, b1), OverlapLinkMissing(a2, b2)) => a1 == a2 && b1 == b2,
(
OverlapNonBipartite { src: s1, dst: d1 },
OverlapNonBipartite { src: s2, dst: d2 },
) => s1 == s2 && d1 == d2,
(OverlapExpectedLocal { found: f1 }, OverlapExpectedLocal { found: f2 }) => f1 == f2,
(OverlapExpectedPart { found: f1 }, OverlapExpectedPart { found: f2 }) => f1 == f2,
(
OverlapRankMismatch {
expected: e1,
found: f1,
},
OverlapRankMismatch {
expected: e2,
found: f2,
},
) => e1 == e2 && f1 == f2,
(OverlapPartInBasePoints, OverlapPartInBasePoints) => true,
(OverlapLocalInCapPoints, OverlapLocalInCapPoints) => true,
(
OverlapDuplicateEdge { src: s1, dst: d1 },
OverlapDuplicateEdge { src: s2, dst: d2 },
) => s1 == s2 && d1 == d2,
(OverlapEmptyPart { rank: r1 }, OverlapEmptyPart { rank: r2 }) => r1 == r2,
(
TopologyPointMissingOwnership { point: p1 },
TopologyPointMissingOwnership { point: p2 },
) => p1 == p2,
(
OwnershipPointMissingTopology { point: p1 },
OwnershipPointMissingTopology { point: p2 },
) => p1 == p2,
(
OwnershipGhostMismatch {
point: p1,
owner: o1,
my_rank: m1,
},
OwnershipGhostMismatch {
point: p2,
owner: o2,
my_rank: m2,
},
) => p1 == p2 && o1 == o2 && m1 == m2,
(
GhostPointMissingOverlapLink {
point: p1,
owner: o1,
},
GhostPointMissingOverlapLink {
point: p2,
owner: o2,
},
) => p1 == p2 && o1 == o2,
(
OverlapPointMissingTopology { point: p1 },
OverlapPointMissingTopology { point: p2 },
) => p1 == p2,
(
OverlapPointMissingOwnership { point: p1 },
OverlapPointMissingOwnership { point: p2 },
) => p1 == p2,
(
OverlapInOutMirrorMissing { src: s1, dst: d1 },
OverlapInOutMirrorMissing { src: s2, dst: d2 },
) => s1 == s2 && d1 == d2,
(
OverlapInOutPayloadMismatch {
src: s1,
dst: d1,
out: o1,
inn: i1,
},
OverlapInOutPayloadMismatch {
src: s2,
dst: d2,
out: o2,
inn: i2,
},
) => s1 == s2 && d1 == d2 && o1 == o2 && i1 == i2,
(
OverlapInOutEdgeCountMismatch {
out_edges: o1,
in_edges: i1,
},
OverlapInOutEdgeCountMismatch {
out_edges: o2,
in_edges: i2,
},
) => o1 == o2 && i1 == i2,
(
OverlapResolutionConflict {
local: l1,
rank: r1,
existing: ex1,
new: n1,
},
OverlapResolutionConflict {
local: l2,
rank: r2,
existing: ex2,
new: n2,
},
) => l1 == l2 && r1 == r2 && ex1 == ex2 && n1 == n2,
_ => false,
}
}
}
impl Eq for MeshSieveError {}
#[derive(Debug, thiserror::Error, Clone)]
#[error("{0}")]
pub struct CommError(pub String);
impl PartialEq for CommError {
fn eq(&self, other: &CommError) -> bool {
self.0 == other.0
}
}
impl Eq for CommError {}