Skip to content

Commit 81c9de0

Browse files
imikejacksonclaude
andcommitted
REV: PR #1631 review round-2 — revert IPF Phase2 fix + cleanup pass
Round-2 PR-review feedback on PR #1631 of `topic/ebsdlib_v3_updates`. ComputeFaceIPFColoring Phase 2 bug revert. - Revert the Phase 2 IPF coloring fix (`phase1`→`phase2` at the validity guard + IPF operator lookup) that was applied earlier in this PR. The fix is provably correct, but the existing test exemplar in `6_6_Small_IN100_GBCD.tar.gz` encodes pre-EbsdLib-3.0 colors and now fails for a broader reason than just the phase2 bug (EbsdLib 2.4.1→3.0.0 ripple through `_calcRodNearestOrigin` + HexConvention defaults). Tracked at #1635; the V&V cycle on this filter will regenerate the exemplar AND re-apply the phase2 fix. The known-bug location is now flagged with an inline block comment. Dead-code removal: `getCancel()` API. - All 5 of the PR's algorithm classes (BadDataNeighborOrientationCheck, ComputeFaceIPFColoring, ComputeFeatureFaceMisorientation, ComputeFeatureNeighborMisorientations, WritePoleFigure) declared a `const std::atomic_bool& getCancel()` member that returned `m_ShouldCancel`. None had any callers — algorithm bodies use `m_ShouldCancel` directly. Removed declarations from headers and definitions from `.cpp` files. LLM-style boilerplate scrub. - ComputeAvgCAxes.cpp: 6-line "2 possibilities that could have happened" multi-bullet hedge comment block in the per-feature finalize loop collapsed to a one-line sentence stating the actual reason for NaN. - ComputeFaceIPFColoring.cpp + ComputeFeatureFaceMisorientation.cpp: removed boilerplate Doxygen blocks above the parallel-impl classes that just restated the class name in English. Readability polish. - ComputeAvgCAxes.cpp: replaced the `temp` scratch float used 3× to narrow Eigen-double → float32 with inline `static_cast<float32>`. - BadDataNeighborOrientationCheck.cpp: error message at the mask-load catch now includes the underlying `std::out_of_range::what()` and uses positive phrasing ("could not be loaded; expected Bool or UInt8"). - BadDataNeighborOrientationCheck.cpp: 3 of 4 `if(!maskCompare->isTrue(...))` sites now resolve the double negative via a named local (`voxelIsBad` / `neighborIsBad`); the one positive-form `if(maskCompare->isTrue(...))` site is unchanged. - ComputeFeatureNeighborCAxisMisalignments.cpp: added a one-line inline comment on the `w` variable's first use to disambiguate the cos(angle)→angle reassignment chain. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent ce3d290 commit 81c9de0

12 files changed

Lines changed: 24 additions & 75 deletions

src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/BadDataNeighborOrientationCheck.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,6 @@ BadDataNeighborOrientationCheck::BadDataNeighborOrientationCheck(DataStructure&
2424
// -----------------------------------------------------------------------------
2525
BadDataNeighborOrientationCheck::~BadDataNeighborOrientationCheck() noexcept = default;
2626

27-
// -----------------------------------------------------------------------------
28-
const std::atomic_bool& BadDataNeighborOrientationCheck::getCancel()
29-
{
30-
return m_ShouldCancel;
31-
}
32-
3327
// -----------------------------------------------------------------------------
3428
Result<> BadDataNeighborOrientationCheck::operator()()
3529
{
@@ -53,9 +47,10 @@ Result<> BadDataNeighborOrientationCheck::operator()()
5347
maskCompare = MaskCompareUtilities::InstantiateMaskCompare(m_DataStructure, m_InputValues->MaskArrayPath);
5448
} catch(const std::out_of_range& exception)
5549
{
56-
// This really should NOT be happening as the path was verified during preflight, BUT we may be calling this from
57-
// somewhere else that is NOT going through the normal nx::core::IFilter API of Preflight and Execute
58-
return MakeErrorResult(-54900, fmt::format("Mask Array DataPath does not exist or is not of the correct type (Bool | UInt8) {}", m_InputValues->MaskArrayPath.toString()));
50+
// Defensive: the path was verified during preflight, but this algorithm may be called outside the standard
51+
// IFilter Preflight/Execute path.
52+
return MakeErrorResult(-54900,
53+
fmt::format("Mask Array at '{}' could not be loaded; expected Bool or UInt8 backing. Underlying error: {}", m_InputValues->MaskArrayPath.toString(), exception.what()));
5954
}
6055

6156
std::array<int64, 3> dims = {
@@ -106,7 +101,9 @@ Result<> BadDataNeighborOrientationCheck::operator()()
106101
}
107102
throttledMessenger.sendThrottledMessage([&] { return fmt::format("Processing Data {:.2f}% completed", CalculatePercentComplete(voxelIndex, totalPoints)); });
108103
// If the mask was set to false, then we check this voxel
109-
if(!maskCompare->isTrue(voxelIndex))
104+
// "Bad" voxels are those whose mask value is false; only these get processed.
105+
const bool voxelIsBad = !maskCompare->isTrue(voxelIndex);
106+
if(voxelIsBad)
110107
{
111108
// We precalculate the positive voxel quaternion and laue class here to prevent reading and recalculating it for each face below
112109
ebsdlib::QuatD quat1(quats[voxelIndex * 4], quats[voxelIndex * 4 + 1], quats[voxelIndex * 4 + 2], quats[voxelIndex * 4 + 3]);
@@ -196,7 +193,8 @@ Result<> BadDataNeighborOrientationCheck::operator()()
196193

197194
// If the current voxel's neighbor count is >= the current level and the mask is FALSE,
198195
// we flip the voxel to TRUE and recompute its (still-bad) neighbors' counts below.
199-
if(neighborCount[voxelIndex] >= currentLevel && !maskCompare->isTrue(voxelIndex))
196+
const bool voxelIsBad = !maskCompare->isTrue(voxelIndex);
197+
if(neighborCount[voxelIndex] >= currentLevel && voxelIsBad)
200198
{
201199
maskCompare->setValue(voxelIndex, true);
202200
counter++; // Increment the `counter` to force the loop to iterate again
@@ -232,7 +230,8 @@ Result<> BadDataNeighborOrientationCheck::operator()()
232230
const int64 neighborPoint = voxelIndexI64 + neighborVoxelIndexOffsets[faceIndex];
233231

234232
// If the neighbor voxel's mask is false, then compute misorientation angle
235-
if(!maskCompare->isTrue(neighborPoint))
233+
const bool neighborIsBad = !maskCompare->isTrue(neighborPoint);
234+
if(neighborIsBad)
236235
{
237236
// Make sure both cells phase values are identical and valid
238237
if(cellPhases[voxelIndex] == cellPhases[neighborPoint] && cellPhases[voxelIndex] > 0)

src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/BadDataNeighborOrientationCheck.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ class ORIENTATIONANALYSIS_EXPORT BadDataNeighborOrientationCheck
3737

3838
Result<> operator()();
3939

40-
const std::atomic_bool& getCancel();
41-
4240
private:
4341
DataStructure& m_DataStructure;
4442
const BadDataNeighborOrientationCheckInputValues* m_InputValues = nullptr;

src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ComputeAvgCAxes.cpp

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,10 @@ Result<> ComputeAvgCAxes::operator()()
121121
cellCAxis *= -1.0f;
122122
}
123123

124-
// Continue summing up the rotations
125-
// Eigen math is double; output array is float32
126-
float temp = avgCAxes[cAxesIndex] + cellCAxis[0];
127-
avgCAxes[cAxesIndex] = temp;
128-
129-
temp = avgCAxes[cAxesIndex + 1] + cellCAxis[1];
130-
avgCAxes[cAxesIndex + 1] = temp;
131-
132-
temp = avgCAxes[cAxesIndex + 2] + cellCAxis[2];
133-
avgCAxes[cAxesIndex + 2] = temp;
124+
// Accumulate per-component into the float32 output (Eigen math is double; narrow on store).
125+
avgCAxes[cAxesIndex] = static_cast<float32>(avgCAxes[cAxesIndex] + cellCAxis[0]);
126+
avgCAxes[cAxesIndex + 1] = static_cast<float32>(avgCAxes[cAxesIndex + 1] + cellCAxis[1]);
127+
avgCAxes[cAxesIndex + 2] = static_cast<float32>(avgCAxes[cAxesIndex + 2] + cellCAxis[2]);
134128
}
135129
}
136130

@@ -144,16 +138,10 @@ Result<> ComputeAvgCAxes::operator()()
144138
return result;
145139
}
146140

147-
// If the value of this feature's counter == 0, then there are 2 possibilities
148-
// that could have happened:
149-
// [1] The feature's phase was not hexagonal and therefore in the "totalPoints" loop above the counter never got incremented.
150-
// [2] There is a featureId that does not have any voxels assigned to it. We need more information here to determine what to do.
151-
// - If we had the "Feature-Phases array then we could look up the phase and then we would know. This would require another input from the user
152-
// - If the featureId does not have any voxels assigned, then how would you generate an average anyway, so applying NaN to the value is the right move here
153-
154141
const usize cAxesIndex = 3 * currentFeatureId;
155142
if(cellCount[currentFeatureId] == 0)
156143
{
144+
// Feature is either non-hexagonal or has no assigned voxels; either way, no meaningful average exists.
157145
avgCAxes[cAxesIndex] = NAN;
158146
avgCAxes[cAxesIndex + 1] = NAN;
159147
avgCAxes[cAxesIndex + 2] = NAN;

src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ComputeFaceIPFColoring.cpp

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@
2121

2222
using namespace nx::core;
2323

24-
/**
25-
* @brief The CalculateNormalsImpl class implements a threaded algorithm that computes the IPF colors for the given list of
26-
* surface mesh labels
27-
*/
2824
class CalculateFaceIPFColorsImpl
2925
{
3026
const Int32Array& m_Labels;
@@ -110,8 +106,12 @@ class CalculateFaceIPFColorsImpl
110106
// Now compute for Phase 2
111107
if(phase2 > 0)
112108
{
113-
// Make sure we are using a valid Euler Angles with valid crystal symmetry
114-
if(m_CrystalStructures[phase2] < ebsdlib::CrystalStructure::LaueGroupEnd)
109+
// KNOWN BUG — tracked at https://github.com/BlueQuartzSoftware/simplnx/issues/1635.
110+
// Both the validity guard and the IPF operator lookup below use phase1 instead of phase2,
111+
// assigning Phase 1's symmetry operator to Phase 2's Euler angles on mixed-phase faces.
112+
// The 2-line fix (phase1→phase2) is held pending a V&V cycle that will regenerate the
113+
// test exemplar (which currently encodes the bug — a circular oracle).
114+
if(m_CrystalStructures[phase1] < ebsdlib::CrystalStructure::LaueGroupEnd)
115115
{
116116
dEuler[0] = m_Eulers[3 * feature2 + 0];
117117
dEuler[1] = m_Eulers[3 * feature2 + 1];
@@ -120,7 +120,7 @@ class CalculateFaceIPFColorsImpl
120120
refDir[1] = -m_Normals[3 * i + 1];
121121
refDir[2] = -m_Normals[3 * i + 2];
122122

123-
argb = ops[m_CrystalStructures[phase2]]->generateIPFColor(dEuler, refDir, false, m_ColorKey);
123+
argb = ops[m_CrystalStructures[phase1]]->generateIPFColor(dEuler, refDir, false, m_ColorKey);
124124
m_SecondColors[3 * i + 0] = RgbColor::dRed(argb);
125125
m_SecondColors[3 * i + 1] = RgbColor::dGreen(argb);
126126
m_SecondColors[3 * i + 2] = RgbColor::dBlue(argb);
@@ -158,12 +158,6 @@ ComputeFaceIPFColoring::ComputeFaceIPFColoring(DataStructure& dataStructure, con
158158
// -----------------------------------------------------------------------------
159159
ComputeFaceIPFColoring::~ComputeFaceIPFColoring() noexcept = default;
160160

161-
// -----------------------------------------------------------------------------
162-
const std::atomic_bool& ComputeFaceIPFColoring::getCancel()
163-
{
164-
return m_ShouldCancel;
165-
}
166-
167161
// -----------------------------------------------------------------------------
168162
Result<> ComputeFaceIPFColoring::operator()()
169163
{

src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ComputeFaceIPFColoring.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ class ORIENTATIONANALYSIS_EXPORT ComputeFaceIPFColoring
4141

4242
Result<> operator()();
4343

44-
const std::atomic_bool& getCancel();
45-
4644
private:
4745
DataStructure& m_DataStructure;
4846
const ComputeFaceIPFColoringInputValues* m_InputValues = nullptr;

src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ComputeFeatureFaceMisorientation.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ using LaueOpsContainer = std::vector<LaueOpsShPtrType>;
1212

1313
using namespace nx::core;
1414

15-
/**
16-
* @brief The CalculateFaceMisorientationColorsImpl class implements a threaded algorithm that computes the misorientation
17-
* colors for the given list of surface mesh labels
18-
*/
19-
2015
class ComputeFeatureMisorientationPerTriangleImpl
2116
{
2217
const Int32Array& m_FaceLabels;
@@ -121,12 +116,6 @@ ComputeFeatureFaceMisorientation::ComputeFeatureFaceMisorientation(DataStructure
121116
// -----------------------------------------------------------------------------
122117
ComputeFeatureFaceMisorientation::~ComputeFeatureFaceMisorientation() noexcept = default;
123118

124-
// -----------------------------------------------------------------------------
125-
const std::atomic_bool& ComputeFeatureFaceMisorientation::getCancel()
126-
{
127-
return m_ShouldCancel;
128-
}
129-
130119
// -----------------------------------------------------------------------------
131120
Result<> ComputeFeatureFaceMisorientation::operator()()
132121
{

src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ComputeFeatureFaceMisorientation.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ class ORIENTATIONANALYSIS_EXPORT ComputeFeatureFaceMisorientation
3535

3636
Result<> operator()();
3737

38-
const std::atomic_bool& getCancel();
39-
4038
private:
4139
DataStructure& m_DataStructure;
4240
const ComputeFeatureFaceMisorientationInputValues* m_InputValues = nullptr;

src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ComputeFeatureNeighborCAxisMisalignments.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ Result<> ComputeFeatureNeighborCAxisMisalignments::operator()()
128128
// dividing by the magnitudes (they would be 1)
129129
c2.normalize();
130130

131+
// w holds cos(angle) here; converted to the angle (radians) on the next assignment.
131132
float64 w = ImageRotationUtilities::CosBetweenVectors(c1, c2);
132133
w = std::clamp(w, -1.0, 1.0);
133134
w = std::acos(w);

src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ComputeFeatureNeighborMisorientations.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,6 @@ ComputeFeatureNeighborMisorientations::ComputeFeatureNeighborMisorientations(Dat
2222
// -----------------------------------------------------------------------------
2323
ComputeFeatureNeighborMisorientations::~ComputeFeatureNeighborMisorientations() noexcept = default;
2424

25-
// -----------------------------------------------------------------------------
26-
const std::atomic_bool& ComputeFeatureNeighborMisorientations::getCancel()
27-
{
28-
return m_ShouldCancel;
29-
}
30-
3125
// -----------------------------------------------------------------------------
3226
Result<> ComputeFeatureNeighborMisorientations::operator()()
3327
{

src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ComputeFeatureNeighborMisorientations.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ class ORIENTATIONANALYSIS_EXPORT ComputeFeatureNeighborMisorientations
3737

3838
Result<> operator()();
3939

40-
const std::atomic_bool& getCancel();
41-
4240
private:
4341
DataStructure& m_DataStructure;
4442
const ComputeFeatureNeighborMisorientationsInputValues* m_InputValues = nullptr;

0 commit comments

Comments
 (0)