Summary
GeometryHelpers::Topology::AdjustCentroidsForPeriodicFaces(const BoundingBox3Df&, const BoundingBoxFaces&, ...) — used by ComputeTriangleGeomCentroids — computes a periodic (wrap-aware) centroid by adding a constant offset to the naive centroid:
// src/simplnx/Utilities/GeometryHelpers.cpp
centroids[3 * featureId + 0] += std::abs(maxPoint[0] - minPoint[0]) / 2.0f; // and y, z
This is the same class of defect that was found and fixed for ComputeFeatureCentroids during its V&V (see the ImageGeom overload, now removed). A constant offset cannot compute a correct wrapped centroid: the true minimum-image centroid depends on where the feature's mass actually sits, not merely that the feature spans/touches opposing periodic faces. Two features that trip the same face condition but have different point distributions require different corrections, so no single offset is correct for both.
Why it's wrong
For a feature whose vertices wrap across a periodic boundary, the correct centroid is the minimum-image (circular) mean — unwrap the points at their largest empty gap (equivalently, average the unit vectors of their angular positions around the domain) and map the result back into the domain. Adding |max - min| / 2 instead lands the centroid in the empty middle of the wrapped feature, offset by an amount that is only coincidentally right for symmetric cases.
Note: unlike the ComputeFeatureCentroids ImageGeom overload (which also had a cell-units-vs-physical spacing bug), this BoundingBox overload works in physical coordinates, so it does not have a spacing bug — the flaw here is purely the constant-offset model.
Suggested fix
Apply the same treatment used in ComputeFeatureCentroids: replace the constant offset with a wrap-aware minimum-image / circular mean for any axis the feature spans, keeping the arithmetic mean for non-spanning axes and an arithmetic fallback for degenerate (domain-filling) features. For triangle geometry the per-feature vertex set is available, so the largest-gap method can be applied directly.
Reference
- Fixed analog:
ComputeFeatureCentroids periodic path (reimplemented as circular mean; the wrong ImageGeom overload of AdjustCentroidsForPeriodicFaces was removed).
- Affected code:
src/simplnx/Utilities/GeometryHelpers.cpp (AdjustCentroidsForPeriodicFaces BoundingBox overload) and its caller src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeTriangleGeomCentroids.cpp.
- Affected users: only those enabling the
Is Periodic option on ComputeTriangleGeomCentroids; the default is off.
Suggested scope
Fold this into a dedicated V&V of ComputeTriangleGeomCentroids (independent oracle for the periodic case, e.g. hand-derived minimum-image values on a small wrapping mesh), mirroring the ComputeFeatureCentroids V&V.
Surfaced by the ComputeFeatureCentroids V&V / adversarial review. Filed with Claude Code.
Summary
GeometryHelpers::Topology::AdjustCentroidsForPeriodicFaces(const BoundingBox3Df&, const BoundingBoxFaces&, ...)— used byComputeTriangleGeomCentroids— computes a periodic (wrap-aware) centroid by adding a constant offset to the naive centroid:This is the same class of defect that was found and fixed for
ComputeFeatureCentroidsduring its V&V (see theImageGeomoverload, now removed). A constant offset cannot compute a correct wrapped centroid: the true minimum-image centroid depends on where the feature's mass actually sits, not merely that the feature spans/touches opposing periodic faces. Two features that trip the same face condition but have different point distributions require different corrections, so no single offset is correct for both.Why it's wrong
For a feature whose vertices wrap across a periodic boundary, the correct centroid is the minimum-image (circular) mean — unwrap the points at their largest empty gap (equivalently, average the unit vectors of their angular positions around the domain) and map the result back into the domain. Adding
|max - min| / 2instead lands the centroid in the empty middle of the wrapped feature, offset by an amount that is only coincidentally right for symmetric cases.Note: unlike the
ComputeFeatureCentroidsImageGeomoverload (which also had a cell-units-vs-physical spacing bug), this BoundingBox overload works in physical coordinates, so it does not have a spacing bug — the flaw here is purely the constant-offset model.Suggested fix
Apply the same treatment used in
ComputeFeatureCentroids: replace the constant offset with a wrap-aware minimum-image / circular mean for any axis the feature spans, keeping the arithmetic mean for non-spanning axes and an arithmetic fallback for degenerate (domain-filling) features. For triangle geometry the per-feature vertex set is available, so the largest-gap method can be applied directly.Reference
ComputeFeatureCentroidsperiodic path (reimplemented as circular mean; the wrongImageGeomoverload ofAdjustCentroidsForPeriodicFaceswas removed).src/simplnx/Utilities/GeometryHelpers.cpp(AdjustCentroidsForPeriodicFacesBoundingBox overload) and its callersrc/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeTriangleGeomCentroids.cpp.Is Periodicoption onComputeTriangleGeomCentroids; the default is off.Suggested scope
Fold this into a dedicated V&V of
ComputeTriangleGeomCentroids(independent oracle for the periodic case, e.g. hand-derived minimum-image values on a small wrapping mesh), mirroring theComputeFeatureCentroidsV&V.Surfaced by the ComputeFeatureCentroids V&V / adversarial review. Filed with Claude Code.