11#include " BadDataNeighborOrientationCheck.hpp"
22
3- #include " simplnx/Common/Numbers.hpp"
4- #include " simplnx/DataStructure/DataArray.hpp"
5- #include " simplnx/DataStructure/Geometry/ImageGeom.hpp"
6- #include " simplnx/Utilities/MaskCompareUtilities.hpp"
7- #include " simplnx/Utilities/MessageHelper.hpp"
8- #include " simplnx/Utilities/NeighborUtilities.hpp"
3+ #include " BadDataNeighborOrientationCheckScanline.hpp"
4+ #include " BadDataNeighborOrientationCheckWorklist.hpp"
95
10- #include < EbsdLib/LaueOps/LaueOps.h>
6+ #include " simplnx/DataStructure/DataArray.hpp"
7+ #include " simplnx/Utilities/AlgorithmDispatch.hpp"
118
129using namespace nx ::core;
1310
@@ -33,170 +30,10 @@ const std::atomic_bool& BadDataNeighborOrientationCheck::getCancel()
3330// -----------------------------------------------------------------------------
3431Result<> BadDataNeighborOrientationCheck::operator ()()
3532{
36- const float misorientationTolerance = m_InputValues->MisorientationTolerance * numbers::pi_v<float > / 180 .0f ;
37-
38- const auto * imageGeomPtr = m_DataStructure.getDataAs <ImageGeom>(m_InputValues->ImageGeomPath );
39- SizeVec3 udims = imageGeomPtr->getDimensions ();
40- const auto & cellPhases = m_DataStructure.getDataRefAs <Int32Array>(m_InputValues->CellPhasesArrayPath );
41- const auto & quats = m_DataStructure.getDataRefAs <Float32Array>(m_InputValues->QuatsArrayPath );
42- const auto & crystalStructures = m_DataStructure.getDataRefAs <UInt32Array>(m_InputValues->CrystalStructuresArrayPath );
43- const usize totalPoints = quats.getNumberOfTuples ();
44-
45- std::unique_ptr<MaskCompareUtilities::MaskCompare> maskCompare;
46- try
47- {
48- maskCompare = MaskCompareUtilities::InstantiateMaskCompare (m_DataStructure, m_InputValues->MaskArrayPath );
49- } catch (const std::out_of_range& exception)
50- {
51- // This really should NOT be happening as the path was verified during preflight, BUT we may be calling this from
52- // somewhere else that is NOT going through the normal nx::core::IFilter API of Preflight and Execute
53- return MakeErrorResult (-54900 , fmt::format (" Mask Array DataPath does not exist or is not of the correct type (Bool | UInt8) {}" , m_InputValues->MaskArrayPath .toString ()));
54- }
55-
56- std::array<int64, 3 > dims = {
57- static_cast <int64>(udims[0 ]),
58- static_cast <int64>(udims[1 ]),
59- static_cast <int64>(udims[2 ]),
60- };
61-
62- std::array<int64, 6 > neighborVoxelIndexOffsets = initializeFaceNeighborOffsets (dims);
63- std::array<FaceNeighborType, 6 > faceNeighborInternalIdx = initializeFaceNeighborInternalIdx ();
64-
65- std::vector<ebsdlib::LaueOps::Pointer> orientationOps = ebsdlib::LaueOps::GetAllOrientationOps ();
66-
67- std::vector<int32> neighborCount (totalPoints, 0 );
68-
69- MessageHelper messageHelper (m_MessageHandler);
70- ThrottledMessenger throttledMessenger = messageHelper.createThrottledMessenger ();
71- // Loop over every point finding the number of neighbors that fall within the
72- // user defined angle tolerance.
73- for (int64 voxelIndex = 0 ; voxelIndex < totalPoints; voxelIndex++)
74- {
75- throttledMessenger.sendThrottledMessage ([&] { return fmt::format (" Processing Data {:.2f}% completed" , CalculatePercentComplete (voxelIndex, totalPoints)); });
76- // If the mask was set to false, then we check this voxel
77- if (!maskCompare->isTrue (voxelIndex))
78- {
79- // We precalculate the positive voxel quaternion and laue class here to prevent reading and recalculating it for each face below
80- ebsdlib::QuatD quat1 (quats[voxelIndex * 4 ], quats[voxelIndex * 4 + 1 ], quats[voxelIndex * 4 + 2 ], quats[voxelIndex * 4 + 3 ]);
81- quat1.positiveOrientation ();
82- const uint32 laueClass1 = crystalStructures[cellPhases[voxelIndex]];
83-
84- int64 xIdx = voxelIndex % dims[0 ];
85- int64 yIdx = (voxelIndex / dims[0 ]) % dims[1 ];
86- int64 zIdx = voxelIndex / (dims[0 ] * dims[1 ]);
87-
88- // Loop over the 6 face neighbors of the voxel
89- std::array<bool , 6 > isValidFaceNeighbor = computeValidFaceNeighbors (xIdx, yIdx, zIdx, dims);
90- for (const auto & faceIndex : faceNeighborInternalIdx)
91- {
92- if (!isValidFaceNeighbor[faceIndex])
93- {
94- continue ;
95- }
96- const int64 neighborPoint = voxelIndex + neighborVoxelIndexOffsets[faceIndex];
97-
98- // Now compare the mask of the neighbor. If the mask is TRUE, i.e., that voxel
99- // did not fail the threshold filter that most likely produced the mask array,
100- // then we can look at that voxel.
101- if (maskCompare->isTrue (neighborPoint))
102- {
103- // Both Cell Phases MUST be the same and be a valid Phase
104- if (cellPhases[voxelIndex] == cellPhases[neighborPoint] && cellPhases[voxelIndex] > 0 )
105- {
106- ebsdlib::QuatD quat2 (quats[neighborPoint * 4 ], quats[neighborPoint * 4 + 1 ], quats[neighborPoint * 4 + 2 ], quats[neighborPoint * 4 + 3 ]);
107- quat2.positiveOrientation ();
108- // Compute the Axis_Angle misorientation between those 2 quaternions
109- ebsdlib::AxisAngleDType axisAngle = orientationOps[laueClass1]->calculateMisorientation (quat1, quat2);
110- // if the angle is less than our tolerance, then we increment the neighbor count
111- // for this voxel
112- if (axisAngle[3 ] < misorientationTolerance)
113- {
114- neighborCount[voxelIndex]++;
115- }
116- }
117- }
118- }
119- }
120- }
121-
122- constexpr int32 startLevel = 6 ;
123- int32 currentLevel = startLevel;
124- int32 counter = 0 ;
125-
126- // Now we loop over all the points again, but this time we do it as many times
127- // as the user has requested to iteratively flip voxels
128- while (currentLevel >= m_InputValues->NumberOfNeighbors )
129- {
130- counter = 1 ;
131- int32 loopNumber = 0 ;
132- while (counter > 0 )
133- {
134- counter = 0 ; // Set this while control variable to zero
135- for (usize voxelIndex = 0 ; voxelIndex < totalPoints; voxelIndex++)
136- {
137- throttledMessenger.sendThrottledMessage ([&] {
138- return fmt::format (" Level '{}' of '{}' || Processing Data ('{}') {:.2f}% completed" , (startLevel - currentLevel) + 1 , startLevel - m_InputValues->NumberOfNeighbors , loopNumber,
139- CalculatePercentComplete (voxelIndex, totalPoints));
140- });
141-
142- // We are comparing the number-of-neighbors of the current voxel, and if it
143- // is > the current level and the mask is FALSE, then we drop into this
144- // conditional. The first thing that happens in the conditional is that
145- // the current voxel's mask value is set to TRUE.
146- if (neighborCount[voxelIndex] >= currentLevel && !maskCompare->isTrue (voxelIndex))
147- {
148- maskCompare->setValue (voxelIndex, true ); // the current voxel's mask value is set to TRUE.
149- counter++; // Increment the `counter` to force the loop to iterate again
150-
151- // We precalculate the positive voxel quaternion and laue class here to prevent reading and recalculating it for each face below
152- ebsdlib::QuatD quat1 (quats[voxelIndex * 4 ], quats[voxelIndex * 4 + 1 ], quats[voxelIndex * 4 + 2 ], quats[voxelIndex * 4 + 3 ]);
153- quat1.positiveOrientation ();
154- const uint32 laueClass1 = crystalStructures[cellPhases[voxelIndex]];
155-
156- // This whole section below is to now look at the neighbor voxels of the
157- // current voxel that just got flipped to true. This is needed because
158- // if any of those neighbor's mask was `false`, then its neighbor count
159- // is now not correct and will be off-by-one. So we run _almost_ the same
160- // loop code as above but checking the specific neighbors of the current
161- // voxel. This part should be termed the "Update Neighbor's Neighbor Count"
162- int64 xIdx = voxelIndex % dims[0 ];
163- int64 yIdx = (voxelIndex / dims[0 ]) % dims[1 ];
164- int64 zIdx = voxelIndex / (dims[0 ] * dims[1 ]);
165-
166- // Loop over the 6 face neighbors of the voxel
167- std::array<bool , 6 > isValidFaceNeighbor = computeValidFaceNeighbors (xIdx, yIdx, zIdx, dims);
168- for (const auto & faceIndex : faceNeighborInternalIdx)
169- {
170- if (!isValidFaceNeighbor[faceIndex])
171- {
172- continue ;
173- }
174-
175- int64 neighborPoint = voxelIndex + neighborVoxelIndexOffsets[faceIndex];
176-
177- // If the neighbor voxel's mask is false, then ....
178- if (!maskCompare->isTrue (neighborPoint))
179- {
180- // Make sure both cells phase values are identical and valid
181- if (cellPhases[voxelIndex] == cellPhases[neighborPoint] && cellPhases[voxelIndex] > 0 )
182- {
183- ebsdlib::QuatD quat2 (quats[neighborPoint * 4 ], quats[neighborPoint * 4 + 1 ], quats[neighborPoint * 4 + 2 ], quats[neighborPoint * 4 + 3 ]);
184- quat2.positiveOrientation ();
185- // Quaternion Math is not commutative so do not reorder
186- ebsdlib::AxisAngleDType axisAngle = orientationOps[laueClass1]->calculateMisorientation (quat1, quat2);
187- if (axisAngle[3 ] < misorientationTolerance)
188- {
189- neighborCount[neighborPoint]++;
190- }
191- }
192- }
193- }
194- }
195- }
196- ++loopNumber;
197- }
198- currentLevel = currentLevel - 1 ;
199- }
33+ auto * quatsArray = m_DataStructure.getDataAs <IDataArray>(m_InputValues->QuatsArrayPath );
34+ auto * maskArray = m_DataStructure.getDataAs <IDataArray>(m_InputValues->MaskArrayPath );
35+ auto * phasesArray = m_DataStructure.getDataAs <IDataArray>(m_InputValues->CellPhasesArrayPath );
20036
201- return {};
37+ return DispatchAlgorithm<BadDataNeighborOrientationCheckWorklist, BadDataNeighborOrientationCheckScanline>({quatsArray, maskArray, phasesArray}, m_DataStructure, m_MessageHandler, m_ShouldCancel,
38+ m_InputValues);
20239}
0 commit comments