Skip to content

Commit 7cff7f2

Browse files
authored
ENH: Compute Feature Face Misorientation Output Rework (#1618)
Filter and unit test updated to fix various bugs.
1 parent b2f17cc commit 7cff7f2

7 files changed

Lines changed: 558 additions & 181 deletions

File tree

src/Plugins/OrientationAnalysis/docs/ComputeFeatureFaceMisorientationFilter.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@ Processing (Crystallography)
66

77
## Description
88

9-
This **Filter** generates a 3 component vector for each **Triangle** in a **Triangle Geometry** that is the axis-angle of the misorientation associated with the **Features** that lie on either side of the **Triangle**. The axis is normalized, so if the magnitude of the vector is viewed, it will be the *misorientation angle* in degrees.
9+
This **Filter** generates a 3 component vector for each **Triangle** in a **Triangle Geometry** that is the axis-angle of the misorientation associated with the **Features** that lie on either side of the **Triangle**. The axis is normalized, so if the magnitude of the vector is viewed, it will be the *misorientation angle* in degrees. This filter works on all valid crystal-structures/laue classes.
10+
11+
If you want to get the "raw" (un-normalized) axis-angle of the misorientation, enable "Store Full Axis Angle" and then (optionally) modify the "Axis Angle Array Name" parameter. The actual axis-angle is stored in a 4 component DataArray with the format as follows:
12+
13+
```text
14+
{{x_axis, y_axis, z_axis, angle}, ...}
15+
```
1016

1117
% Auto generated parameter table will be inserted here
1218

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

Lines changed: 60 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
#include "simplnx/Common/Constants.hpp"
44
#include "simplnx/DataStructure/DataArray.hpp"
5-
#include "simplnx/DataStructure/DataGroup.hpp"
65
#include "simplnx/Utilities/ParallelDataAlgorithm.hpp"
76

87
#include <EbsdLib/Core/EbsdLibConstants.h>
@@ -17,77 +16,84 @@ using namespace nx::core;
1716
* @brief The CalculateFaceMisorientationColorsImpl class implements a threaded algorithm that computes the misorientation
1817
* colors for the given list of surface mesh labels
1918
*/
20-
class CalculateFaceMisorientationColorsImpl
19+
20+
class ComputeFeatureMisorientationPerTriangleImpl
2121
{
22-
const Int32Array& m_Labels;
23-
const Int32Array& m_Phases;
24-
const Float32Array& m_Quats;
22+
const Int32Array& m_FaceLabels;
23+
const Int32Array& m_FeaturePhases;
24+
const Float32Array& m_FeatureAvgQuats;
2525
const UInt32Array& m_CrystalStructures;
26-
Float32Array& m_Colors;
27-
LaueOpsContainer m_OrientationOps;
26+
const std::atomic_bool& m_ShouldCancel;
27+
Float32Array& m_Misorientations;
28+
LaueOpsContainer m_LaueOrientationOps;
2829

2930
public:
30-
CalculateFaceMisorientationColorsImpl(const Int32Array& labels, const Int32Array& phases, const Float32Array& quats, const UInt32Array& crystalStructures, Float32Array& colors)
31-
: m_Labels(labels)
32-
, m_Phases(phases)
33-
, m_Quats(quats)
31+
ComputeFeatureMisorientationPerTriangleImpl(const Int32Array& labels, const Int32Array& phases, const Float32Array& quats, const UInt32Array& crystalStructures, const std::atomic_bool& shouldCancel,
32+
Float32Array& output)
33+
: m_FaceLabels(labels)
34+
, m_FeaturePhases(phases)
35+
, m_FeatureAvgQuats(quats)
3436
, m_CrystalStructures(crystalStructures)
35-
, m_Colors(colors)
37+
, m_ShouldCancel(shouldCancel)
38+
, m_Misorientations(output)
3639
{
37-
m_OrientationOps = ebsdlib::LaueOps::GetAllOrientationOps();
40+
m_LaueOrientationOps = ebsdlib::LaueOps::GetAllOrientationOps();
3841
}
39-
virtual ~CalculateFaceMisorientationColorsImpl() = default;
42+
virtual ~ComputeFeatureMisorientationPerTriangleImpl() = default;
4043

41-
void generate(usize start, usize end) const
44+
void generate(const usize start, const usize end) const
4245
{
43-
int32 feature1 = 0, feature2 = 0, phase1 = 0, phase2 = 0;
46+
// Since our meshes use unified triangles, there are two triangles
47+
// per entry. These are distinguished via the face labels array,
48+
// which contains the feature id of each respective face. Here, the
49+
// first entry in face labels is denoted as "front" and the second "back"
50+
int32 frontFeature = 0, backFeature = 0, frontPhase = 0, backPhase = 0;
4451

4552
for(usize i = start; i < end; i++)
4653
{
47-
feature1 = m_Labels[2 * i];
48-
feature2 = m_Labels[2 * i + 1];
49-
if(feature1 > 0)
54+
if(m_ShouldCancel)
5055
{
51-
phase1 = m_Phases[feature1];
56+
return;
57+
}
58+
59+
frontFeature = m_FaceLabels[2 * i];
60+
backFeature = m_FaceLabels[2 * i + 1];
61+
if(frontFeature > 0)
62+
{
63+
frontPhase = m_FeaturePhases[frontFeature];
5264
}
5365
else
5466
{
55-
phase1 = 0;
67+
frontPhase = 0;
5668
}
57-
if(feature2 > 0)
69+
if(backFeature > 0)
5870
{
59-
phase2 = m_Phases[feature2];
71+
backPhase = m_FeaturePhases[backFeature];
6072
}
6173
else
6274
{
63-
phase2 = 0;
75+
backPhase = 0;
6476
}
65-
if(phase1 > 0 && phase1 == phase2)
77+
// Make sure the crystal structure is a valid laue class
78+
uint32 laueIndex = m_CrystalStructures[frontPhase];
79+
if(frontPhase > 0 && frontPhase == backPhase && laueIndex < m_LaueOrientationOps.size())
6680
{
67-
if((m_CrystalStructures[phase1] == ebsdlib::CrystalStructure::Hexagonal_High) || (m_CrystalStructures[phase1] == ebsdlib::CrystalStructure::Cubic_High))
68-
{
69-
float32 quat0 = m_Quats[feature1 * 4];
70-
float32 quat1 = m_Quats[feature1 * 4 + 1];
71-
float32 quat2 = m_Quats[feature1 * 4 + 2];
72-
float32 quat3 = m_Quats[feature1 * 4 + 3];
73-
ebsdlib::QuatD q1(quat0, quat1, quat2, quat3);
74-
quat0 = m_Quats[feature2 * 4];
75-
quat1 = m_Quats[feature2 * 4 + 1];
76-
quat2 = m_Quats[feature2 * 4 + 2];
77-
quat3 = m_Quats[feature2 * 4 + 3];
78-
ebsdlib::QuatD q2(quat0, quat1, quat2, quat3);
79-
ebsdlib::AxisAngleDType axisAngle = m_OrientationOps[m_CrystalStructures[phase1]]->calculateMisorientation(q1, q2);
80-
81-
m_Colors[3 * i + 0] = axisAngle[0] * (axisAngle[3] * nx::core::Constants::k_180OverPiD);
82-
m_Colors[3 * i + 1] = axisAngle[1] * (axisAngle[3] * nx::core::Constants::k_180OverPiD);
83-
m_Colors[3 * i + 2] = axisAngle[2] * (axisAngle[3] * nx::core::Constants::k_180OverPiD);
84-
}
81+
float32 quat0 = m_FeatureAvgQuats[frontFeature * 4];
82+
float32 quat1 = m_FeatureAvgQuats[frontFeature * 4 + 1];
83+
float32 quat2 = m_FeatureAvgQuats[frontFeature * 4 + 2];
84+
float32 quat3 = m_FeatureAvgQuats[frontFeature * 4 + 3];
85+
ebsdlib::QuatD q1(quat0, quat1, quat2, quat3);
86+
quat0 = m_FeatureAvgQuats[backFeature * 4];
87+
quat1 = m_FeatureAvgQuats[backFeature * 4 + 1];
88+
quat2 = m_FeatureAvgQuats[backFeature * 4 + 2];
89+
quat3 = m_FeatureAvgQuats[backFeature * 4 + 3];
90+
ebsdlib::QuatD q2(quat0, quat1, quat2, quat3);
91+
ebsdlib::AxisAngleDType axisAngle = m_LaueOrientationOps[laueIndex]->calculateMisorientation(q1, q2);
92+
m_Misorientations.setValue(i, static_cast<float32>(axisAngle[3] * Constants::k_180OverPiD));
8593
}
8694
else
8795
{
88-
m_Colors[3 * i + 0] = 0;
89-
m_Colors[3 * i + 1] = 0;
90-
m_Colors[3 * i + 2] = 0;
96+
m_Misorientations.setValue(i, static_cast<float>(std::nan("0")));
9197
}
9298
}
9399
}
@@ -124,17 +130,16 @@ const std::atomic_bool& ComputeFeatureFaceMisorientation::getCancel()
124130
// -----------------------------------------------------------------------------
125131
Result<> ComputeFeatureFaceMisorientation::operator()()
126132
{
127-
auto& faceLabels = m_DataStructure.getDataRefAs<Int32Array>(m_InputValues->SurfaceMeshFaceLabelsArrayPath);
128-
auto& avgQuats = m_DataStructure.getDataRefAs<Float32Array>(m_InputValues->AvgQuatsArrayPath);
129-
auto& phases = m_DataStructure.getDataRefAs<Int32Array>(m_InputValues->FeaturePhasesArrayPath);
130-
auto& crystalStructures = m_DataStructure.getDataRefAs<UInt32Array>(m_InputValues->CrystalStructuresArrayPath);
131-
DataPath faceMisorientationColorsArrayPath = m_InputValues->SurfaceMeshFaceLabelsArrayPath.replaceName(m_InputValues->SurfaceMeshFaceMisorientationColorsArrayName);
132-
auto& faceMisorientationColors = m_DataStructure.getDataRefAs<Float32Array>(faceMisorientationColorsArrayPath);
133-
int64 numTriangles = faceLabels.getNumberOfTuples();
133+
const auto& faceLabels = m_DataStructure.getDataRefAs<Int32Array>(m_InputValues->surfaceMeshFaceLabelsArrayPath);
134+
const auto& avgQuats = m_DataStructure.getDataRefAs<Float32Array>(m_InputValues->avgQuatsArrayPath);
135+
const auto& phases = m_DataStructure.getDataRefAs<Int32Array>(m_InputValues->featurePhasesArrayPath);
136+
const auto& crystalStructures = m_DataStructure.getDataRefAs<UInt32Array>(m_InputValues->crystalStructuresArrayPath);
137+
auto& misorientations = m_DataStructure.getDataRefAs<Float32Array>(m_InputValues->misorientationArrayPath);
138+
const usize numTriangles = faceLabels.getNumberOfTuples();
134139

135140
ParallelDataAlgorithm parallelTask;
136141
parallelTask.setRange(0, numTriangles);
137-
parallelTask.execute(CalculateFaceMisorientationColorsImpl(faceLabels, phases, avgQuats, crystalStructures, faceMisorientationColors));
138-
142+
parallelTask.setParallelizationEnabled(false);
143+
parallelTask.execute(ComputeFeatureMisorientationPerTriangleImpl(faceLabels, phases, avgQuats, crystalStructures, m_ShouldCancel, misorientations));
139144
return {};
140145
}

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

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,17 @@
55
#include "simplnx/DataStructure/DataPath.hpp"
66
#include "simplnx/DataStructure/DataStructure.hpp"
77
#include "simplnx/Filter/IFilter.hpp"
8-
#include "simplnx/Parameters/ArrayCreationParameter.hpp"
9-
#include "simplnx/Parameters/ArraySelectionParameter.hpp"
108

119
namespace nx::core
1210
{
1311

1412
struct ORIENTATIONANALYSIS_EXPORT ComputeFeatureFaceMisorientationInputValues
1513
{
16-
DataPath SurfaceMeshFaceLabelsArrayPath;
17-
DataPath AvgQuatsArrayPath;
18-
DataPath FeaturePhasesArrayPath;
19-
DataPath CrystalStructuresArrayPath;
20-
std::string SurfaceMeshFaceMisorientationColorsArrayName;
14+
DataPath surfaceMeshFaceLabelsArrayPath;
15+
DataPath avgQuatsArrayPath;
16+
DataPath featurePhasesArrayPath;
17+
DataPath crystalStructuresArrayPath;
18+
DataPath misorientationArrayPath;
2119
};
2220

2321
/**

src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ComputeFeatureFaceMisorientationFilter.cpp

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@
66
#include "simplnx/DataStructure/DataPath.hpp"
77
#include "simplnx/Filter/Actions/CreateArrayAction.hpp"
88
#include "simplnx/Parameters/ArraySelectionParameter.hpp"
9-
10-
#include "simplnx/Utilities/SIMPLConversion.hpp"
11-
9+
#include "simplnx/Parameters/BoolParameter.hpp"
1210
#include "simplnx/Parameters/DataObjectNameParameter.hpp"
11+
#include "simplnx/Utilities/SIMPLConversion.hpp"
1312

1413
using namespace nx::core;
1514

@@ -63,16 +62,24 @@ Parameters ComputeFeatureFaceMisorientationFilter::parameters() const
6362
params.insert(std::make_unique<ArraySelectionParameter>(k_CrystalStructuresArrayPath_Key, "Crystal Structures", "Enumeration representing the crystal structure for each Ensemble", DataPath{},
6463
ArraySelectionParameter::AllowedTypes{DataType::uint32}, ArraySelectionParameter::AllowedComponentShapes{{1}}));
6564
params.insertSeparator(Parameters::Separator{"Output Face Data"});
66-
params.insert(std::make_unique<DataObjectNameParameter>(k_SurfaceMeshFaceMisorientationColorsArrayName_Key, "Misorientation Colors", "A set of RGB color schemes encoded as floats for each Face",
67-
"FaceMisorientationColors"));
65+
66+
params.insert(std::make_unique<DataObjectNameParameter>(k_MisorientationArrayName_Key, "Misorientation",
67+
"The name of the array containing the misorientation angle (in degrees) between the 2 features.", "Face Misorientations"));
6868

6969
return params;
7070
}
7171

7272
//------------------------------------------------------------------------------
7373
IFilter::VersionType ComputeFeatureFaceMisorientationFilter::parametersVersion() const
7474
{
75-
return 1;
75+
return 2;
76+
77+
// Version 1 -> 2
78+
// Description:
79+
//
80+
// Change 1:
81+
// Added - k_StoreAxisAngle_Key = "store_axis_angle" && k_AxisAngleArrayName_Key = "axis_angle_array_name";
82+
// Solution - None. Default behavior preserves backward compatibility
7683
}
7784

7885
//------------------------------------------------------------------------------
@@ -85,14 +92,13 @@ IFilter::UniquePointer ComputeFeatureFaceMisorientationFilter::clone() const
8592
IFilter::PreflightResult ComputeFeatureFaceMisorientationFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler,
8693
const std::atomic_bool& shouldCancel, const ExecutionContext& executionContext) const
8794
{
88-
auto pSurfaceMeshFaceLabelsArrayPathValue = filterArgs.value<DataPath>(k_SurfaceMeshFaceLabelsArrayPath_Key);
89-
auto pAvgQuatsArrayPathValue = filterArgs.value<DataPath>(k_AvgQuatsArrayPath_Key);
90-
auto pFeaturePhasesArrayPathValue = filterArgs.value<DataPath>(k_FeaturePhasesArrayPath_Key);
91-
auto pCrystalStructuresArrayPathValue = filterArgs.value<DataPath>(k_CrystalStructuresArrayPath_Key);
92-
auto pSurfaceMeshFaceMisorientationColorsArrayNameValue = filterArgs.value<std::string>(k_SurfaceMeshFaceMisorientationColorsArrayName_Key);
93-
94-
PreflightResult preflightResult;
95-
nx::core::Result<OutputActions> resultOutputActions;
95+
auto pSurfaceMeshFaceLabelsArrayPathValue = filterArgs.value<ArraySelectionParameter::ValueType>(k_SurfaceMeshFaceLabelsArrayPath_Key);
96+
auto pAvgQuatsArrayPathValue = filterArgs.value<ArraySelectionParameter::ValueType>(k_AvgQuatsArrayPath_Key);
97+
auto pFeaturePhasesArrayPathValue = filterArgs.value<ArraySelectionParameter::ValueType>(k_FeaturePhasesArrayPath_Key);
98+
auto pCrystalStructuresArrayPathValue = filterArgs.value<ArraySelectionParameter::ValueType>(k_CrystalStructuresArrayPath_Key);
99+
auto pSurfaceMeshFaceMisorientationColorsArrayNameValue = filterArgs.value<DataObjectNameParameter::ValueType>(k_MisorientationArrayName_Key);
100+
101+
Result<OutputActions> resultOutputActions;
96102
std::vector<PreflightValue> preflightUpdatedValues;
97103

98104
// make sure all the cell data has same number of tuples (i.e. they should all be coming from the same Image Geometry)
@@ -109,9 +115,11 @@ IFilter::PreflightResult ComputeFeatureFaceMisorientationFilter::preflightImpl(c
109115
return MakePreflightErrorResult(-98411, fmt::format("Could not find the face labels data array at path '{}'", pSurfaceMeshFaceLabelsArrayPathValue.toString()));
110116
}
111117

112-
DataPath faceMisorientationColorsArrayPath = pSurfaceMeshFaceLabelsArrayPathValue.replaceName(pSurfaceMeshFaceMisorientationColorsArrayNameValue);
113-
auto action = std::make_unique<CreateArrayAction>(DataType::float32, faceLabels->getTupleShape(), std::vector<usize>{3}, faceMisorientationColorsArrayPath);
114-
resultOutputActions.value().appendAction(std::move(action));
118+
{
119+
DataPath faceMisorientationColorsArrayPath = pSurfaceMeshFaceLabelsArrayPathValue.replaceName(pSurfaceMeshFaceMisorientationColorsArrayNameValue);
120+
auto action = std::make_unique<CreateArrayAction>(DataType::float32, faceLabels->getTupleShape(), std::vector<usize>{1}, faceMisorientationColorsArrayPath);
121+
resultOutputActions.value().appendAction(std::move(action));
122+
}
115123

116124
return {std::move(resultOutputActions), std::move(preflightUpdatedValues)};
117125
}
@@ -122,11 +130,11 @@ Result<> ComputeFeatureFaceMisorientationFilter::executeImpl(DataStructure& data
122130
{
123131
ComputeFeatureFaceMisorientationInputValues inputValues;
124132

125-
inputValues.SurfaceMeshFaceLabelsArrayPath = filterArgs.value<DataPath>(k_SurfaceMeshFaceLabelsArrayPath_Key);
126-
inputValues.AvgQuatsArrayPath = filterArgs.value<DataPath>(k_AvgQuatsArrayPath_Key);
127-
inputValues.FeaturePhasesArrayPath = filterArgs.value<DataPath>(k_FeaturePhasesArrayPath_Key);
128-
inputValues.CrystalStructuresArrayPath = filterArgs.value<DataPath>(k_CrystalStructuresArrayPath_Key);
129-
inputValues.SurfaceMeshFaceMisorientationColorsArrayName = filterArgs.value<std::string>(k_SurfaceMeshFaceMisorientationColorsArrayName_Key);
133+
inputValues.surfaceMeshFaceLabelsArrayPath = filterArgs.value<ArraySelectionParameter::ValueType>(k_SurfaceMeshFaceLabelsArrayPath_Key);
134+
inputValues.avgQuatsArrayPath = filterArgs.value<ArraySelectionParameter::ValueType>(k_AvgQuatsArrayPath_Key);
135+
inputValues.featurePhasesArrayPath = filterArgs.value<ArraySelectionParameter::ValueType>(k_FeaturePhasesArrayPath_Key);
136+
inputValues.crystalStructuresArrayPath = filterArgs.value<ArraySelectionParameter::ValueType>(k_CrystalStructuresArrayPath_Key);
137+
inputValues.misorientationArrayPath = inputValues.surfaceMeshFaceLabelsArrayPath.replaceName(filterArgs.value<DataObjectNameParameter::ValueType>(k_MisorientationArrayName_Key));
130138

131139
return ComputeFeatureFaceMisorientation(dataStructure, messageHandler, shouldCancel, &inputValues)();
132140
}
@@ -156,7 +164,7 @@ Result<Arguments> ComputeFeatureFaceMisorientationFilter::FromSIMPLJson(const nl
156164
results.push_back(
157165
SIMPLConversion::ConvertParameter<SIMPLConversion::DataArraySelectionFilterParameterConverter>(args, json, SIMPL::k_CrystalStructuresArrayPathKey, k_CrystalStructuresArrayPath_Key));
158166
results.push_back(SIMPLConversion::ConvertParameter<SIMPLConversion::LinkedPathCreationFilterParameterConverter>(args, json, SIMPL::k_SurfaceMeshFaceMisorientationColorsArrayNameKey,
159-
k_SurfaceMeshFaceMisorientationColorsArrayName_Key));
167+
k_MisorientationArrayName_Key));
160168

161169
Result<> conversionResult = MergeResults(std::move(results));
162170

src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ComputeFeatureFaceMisorientationFilter.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ class ORIENTATIONANALYSIS_EXPORT ComputeFeatureFaceMisorientationFilter : public
2929
static constexpr StringLiteral k_AvgQuatsArrayPath_Key = "avg_quats_array_path";
3030
static constexpr StringLiteral k_FeaturePhasesArrayPath_Key = "feature_phases_array_path";
3131
static constexpr StringLiteral k_CrystalStructuresArrayPath_Key = "crystal_structures_array_path";
32-
static constexpr StringLiteral k_SurfaceMeshFaceMisorientationColorsArrayName_Key = "surface_mesh_face_misorientation_colors_array_name";
32+
33+
// Parameter Keys V2
34+
static constexpr StringLiteral k_MisorientationArrayName_Key = "misorientation_array_name";
3335

3436
/**
3537
* @brief Reads SIMPL json and converts it simplnx Arguments.

0 commit comments

Comments
 (0)