|
| 1 | +#include "ComputeFZQuaternions.hpp" |
| 2 | + |
| 3 | +#include "simplnx/DataStructure/DataArray.hpp" |
| 4 | +#include "simplnx/DataStructure/DataGroup.hpp" |
| 5 | +#include "simplnx/Utilities/ParallelDataAlgorithm.hpp" |
| 6 | + |
| 7 | +#include "EbsdLib/Core/EbsdLibConstants.h" |
| 8 | +#include "EbsdLib/LaueOps/LaueOps.h" |
| 9 | + |
| 10 | +using namespace nx::core; |
| 11 | + |
| 12 | +namespace |
| 13 | +{ |
| 14 | +/** |
| 15 | + * @brief The GenerateFZQuatsImpl class implements a threaded algorithm that computes the Fundamental Zone Quaternion |
| 16 | + * for a given Quaternion and Laue Class (which is based from the crystalStructures array |
| 17 | + */ |
| 18 | +template <typename MaskArrayType> |
| 19 | +class GenerateFZQuatsImpl |
| 20 | +{ |
| 21 | +public: |
| 22 | + GenerateFZQuatsImpl(Float32Array& quats, Int32Array& phases, UInt32Array& crystalStructures, int32_t numPhases, MaskArrayType* goodVoxels, Float32Array& fzQuats, |
| 23 | + const std::atomic_bool& shouldCancel, std::atomic_int32_t& warningCount) |
| 24 | + : m_Quats(quats) |
| 25 | + , m_CellPhases(phases) |
| 26 | + , m_CrystalStructures(crystalStructures) |
| 27 | + , m_NumPhases(numPhases) |
| 28 | + , m_GoodVoxels(goodVoxels) |
| 29 | + , m_FZQuats(fzQuats) |
| 30 | + , m_ShouldCancel(shouldCancel) |
| 31 | + , m_WarningCount(warningCount) |
| 32 | + { |
| 33 | + } |
| 34 | + |
| 35 | + virtual ~GenerateFZQuatsImpl() = default; |
| 36 | + |
| 37 | + /** |
| 38 | + * @brief convert |
| 39 | + * @param start |
| 40 | + * @param end |
| 41 | + */ |
| 42 | + void convert(size_t start, size_t end) const |
| 43 | + { |
| 44 | + std::vector<LaueOps::Pointer> ops = LaueOps::GetAllOrientationOps(); |
| 45 | + int32_t phase = 0; |
| 46 | + bool generateFZQuat = false; |
| 47 | + size_t index = 0; |
| 48 | + |
| 49 | + for(size_t i = start; i < end; i++) |
| 50 | + { |
| 51 | + if(m_ShouldCancel) |
| 52 | + { |
| 53 | + break; |
| 54 | + } |
| 55 | + phase = m_CellPhases[i]; |
| 56 | + |
| 57 | + generateFZQuat = true; |
| 58 | + if(nullptr != m_GoodVoxels) |
| 59 | + { |
| 60 | + generateFZQuat = static_cast<bool>((*m_GoodVoxels)[i]); |
| 61 | + } |
| 62 | + |
| 63 | + // Sanity check the phase data to make sure we do not walk off the end of the array |
| 64 | + if(phase >= m_NumPhases) |
| 65 | + { |
| 66 | + m_WarningCount++; |
| 67 | + } |
| 68 | + |
| 69 | + // Initialize the output to zero. There really isn't a good value to use. |
| 70 | + index = i * 4; |
| 71 | + m_FZQuats[index] = 0.0f; |
| 72 | + m_FZQuats[index + 1] = 0.0f; |
| 73 | + m_FZQuats[index + 2] = 0.0f; |
| 74 | + m_FZQuats[index + 3] = 0.0f; |
| 75 | + |
| 76 | + if(phase < m_NumPhases && generateFZQuat && m_CrystalStructures[phase] < EbsdLib::CrystalStructure::LaueGroupEnd) |
| 77 | + { |
| 78 | + QuatD quatD = QuatD(m_Quats[index], m_Quats[index + 1], m_Quats[index + 2], m_Quats[index + 3]); // Makes a copy into q |
| 79 | + int32_t xtal = static_cast<int32_t>(m_CrystalStructures[phase]); // get the Laue Group |
| 80 | + quatD = ops[xtal]->getFZQuat(quatD); |
| 81 | + m_FZQuats[index] = quatD.x(); |
| 82 | + m_FZQuats[index + 1] = quatD.y(); |
| 83 | + m_FZQuats[index + 2] = quatD.z(); |
| 84 | + m_FZQuats[index + 3] = quatD.w(); |
| 85 | + } |
| 86 | + } |
| 87 | + } |
| 88 | + |
| 89 | + void operator()(const Range& range) const |
| 90 | + { |
| 91 | + convert(range.min(), range.max()); |
| 92 | + } |
| 93 | + |
| 94 | +private: |
| 95 | + Float32Array& m_Quats; |
| 96 | + Int32Array& m_CellPhases; |
| 97 | + UInt32Array& m_CrystalStructures; |
| 98 | + int32_t m_NumPhases = 0; |
| 99 | + MaskArrayType* m_GoodVoxels; |
| 100 | + Float32Array& m_FZQuats; |
| 101 | + const std::atomic_bool& m_ShouldCancel; |
| 102 | + std::atomic_int32_t& m_WarningCount; |
| 103 | +}; |
| 104 | +} // namespace |
| 105 | + |
| 106 | +// ----------------------------------------------------------------------------- |
| 107 | +ComputeFZQuaternions::ComputeFZQuaternions(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, ComputeFZQuaternionsInputValues* inputValues) |
| 108 | +: m_DataStructure(dataStructure) |
| 109 | +, m_InputValues(inputValues) |
| 110 | +, m_ShouldCancel(shouldCancel) |
| 111 | +, m_MessageHandler(mesgHandler) |
| 112 | +{ |
| 113 | +} |
| 114 | + |
| 115 | +// ----------------------------------------------------------------------------- |
| 116 | +ComputeFZQuaternions::~ComputeFZQuaternions() noexcept = default; |
| 117 | + |
| 118 | +// ----------------------------------------------------------------------------- |
| 119 | +Result<> ComputeFZQuaternions::operator()() |
| 120 | +{ |
| 121 | + |
| 122 | + Int32Array& phaseArray = m_DataStructure.getDataRefAs<Int32Array>(m_InputValues->CellPhasesArrayPath); |
| 123 | + Float32Array& quatArray = m_DataStructure.getDataRefAs<Float32Array>(m_InputValues->InputQuatsArrayPath); |
| 124 | + UInt32Array& xtalArray = m_DataStructure.getDataRefAs<UInt32Array>(m_InputValues->CrystalStructuresArrayPath); |
| 125 | + IDataArray* maskArray = m_DataStructure.getDataAs<IDataArray>(m_InputValues->MaskArrayPath); |
| 126 | + Float32Array& fzQuatArray = m_DataStructure.getDataRefAs<Float32Array>(m_InputValues->InputQuatsArrayPath.replaceName(m_InputValues->OutputFzQuatsArrayName)); |
| 127 | + |
| 128 | + std::atomic_int32_t warningCount = 0; |
| 129 | + int32_t numPhases = static_cast<int32_t>(xtalArray.getNumberOfTuples()); |
| 130 | + |
| 131 | + typename IParallelAlgorithm::AlgorithmArrays algArrays; |
| 132 | + algArrays.push_back(&phaseArray); |
| 133 | + algArrays.push_back(&quatArray); |
| 134 | + algArrays.push_back(&xtalArray); |
| 135 | + algArrays.push_back(&fzQuatArray); |
| 136 | + |
| 137 | + if(m_InputValues->UseMask) |
| 138 | + { |
| 139 | + algArrays.push_back(maskArray); |
| 140 | + } |
| 141 | + |
| 142 | + // Parallel algorithm |
| 143 | + ParallelDataAlgorithm dataAlg; |
| 144 | + dataAlg.setRange(0ULL, static_cast<size_t>(quatArray.getNumberOfTuples())); |
| 145 | + dataAlg.requireArraysInMemory(algArrays); |
| 146 | + |
| 147 | + if(m_InputValues->UseMask) |
| 148 | + { |
| 149 | + if(maskArray->getDataType() == DataType::boolean) |
| 150 | + { |
| 151 | + BoolArray* goodVoxelsArray = m_DataStructure.getDataAs<BoolArray>(m_InputValues->MaskArrayPath); |
| 152 | + dataAlg.execute(::GenerateFZQuatsImpl<BoolArray>(quatArray, phaseArray, xtalArray, numPhases, goodVoxelsArray, fzQuatArray, m_ShouldCancel, warningCount)); |
| 153 | + } |
| 154 | + else if(maskArray->getDataType() == DataType::uint8) |
| 155 | + { |
| 156 | + UInt32Array* goodVoxelsArray = m_DataStructure.getDataAs<UInt32Array>(m_InputValues->MaskArrayPath); |
| 157 | + dataAlg.execute(::GenerateFZQuatsImpl<UInt32Array>(quatArray, phaseArray, xtalArray, numPhases, goodVoxelsArray, fzQuatArray, m_ShouldCancel, warningCount)); |
| 158 | + } |
| 159 | + else if(maskArray->getDataType() == DataType::int8) |
| 160 | + { |
| 161 | + Int8Array* goodVoxelsArray = m_DataStructure.getDataAs<Int8Array>(m_InputValues->MaskArrayPath); |
| 162 | + dataAlg.execute(::GenerateFZQuatsImpl<Int8Array>(quatArray, phaseArray, xtalArray, numPhases, goodVoxelsArray, fzQuatArray, m_ShouldCancel, warningCount)); |
| 163 | + } |
| 164 | + } |
| 165 | + else |
| 166 | + { |
| 167 | + dataAlg.execute(::GenerateFZQuatsImpl<Int8Array>(quatArray, phaseArray, xtalArray, numPhases, nullptr, fzQuatArray, m_ShouldCancel, warningCount)); |
| 168 | + } |
| 169 | + |
| 170 | + if(warningCount > 0) |
| 171 | + { |
| 172 | + std::string errorMessage = fmt::format("The Ensemble Phase information only references {} phase(s) but {} cell(s) had a phase value greater than {}. \ |
| 173 | +This indicates a problem with the input cell phase data. DREAM3D-NX may have given INCORRECT RESULTS.", |
| 174 | + numPhases - 1, warningCount.load(), numPhases - 1); |
| 175 | + |
| 176 | + return {MakeErrorResult<>(-49008, errorMessage)}; |
| 177 | + } |
| 178 | + |
| 179 | + return {}; |
| 180 | +} |
0 commit comments