diff --git a/src/Plugins/OrientationAnalysis/CMakeLists.txt b/src/Plugins/OrientationAnalysis/CMakeLists.txt index f478a521e3..d100edde2d 100644 --- a/src/Plugins/OrientationAnalysis/CMakeLists.txt +++ b/src/Plugins/OrientationAnalysis/CMakeLists.txt @@ -79,11 +79,11 @@ set(FilterList WriteINLFileFilter WritePoleFigureFilter WriteStatsGenOdfAngleFileFilter + EMsoftSO3SamplerFilter ) set(STUB_FILTERS CreateLambertSphere - EMsoftSO3Sampler ComputeBoundaryStrengths FindDistsToCharactGBs ComputeKernelAvgMisorientations @@ -214,6 +214,7 @@ set(filter_algorithms WriteINLFile WritePoleFigure WriteStatsGenOdfAngleFile + EMsoftSO3Sampler ) diff --git a/src/Plugins/OrientationAnalysis/docs/EMsoftSO3SamplerFilter.md b/src/Plugins/OrientationAnalysis/docs/EMsoftSO3SamplerFilter.md new file mode 100644 index 0000000000..c685cfa358 --- /dev/null +++ b/src/Plugins/OrientationAnalysis/docs/EMsoftSO3SamplerFilter.md @@ -0,0 +1,89 @@ +# EMsoftSO3Sampler # + + +## Group (Subgroup) ## + +EMsoftToolbox (EMsoftToolbox) + +## Description ## + +The EMsoftSO3Sampler filter produces several different types of uniform samples of SO(3): + +| Mode | Description | +|------|-------------| +| 0 | a uniform sampling of a Rodrigues fundamental zone (FZ) | +| 1 | a uniform sampling of orientations at a constant misorientation from a given orientation | +| 2 | a uniform sampling of orientations at less than a given misorientation from a given orientation. | + +All three sampling methods are based on the cubochoric rotation representation, which starts with a cubical grid inside the cubochoric cube. This cube represents an equal-volume mapping of the quaternion Northern hemisphere (i.e., all 3D rotations with positive scalar quaternion component). For sampling mode 0, the filter creates a uniform grid of cubochoric vectors, transforms each vector to the Rodrigues representation and determines whether or not the point lies inside the FZ for the point group symmetry set by the user. The filter then returns an array of Euler angle triplets (Bunge convention) for use in subsequent filters. The sampling grid can be offset from the center of the cube, in which case the identity orientation will not be part of the sample. + +For sampling mode 0, the filter samples the surface of a centered cube inside the cubochoric cube and converts those points to a quadratic surface (prolate spheroid, spheroidal paraboloid, or double-sheet hyperboloid, depending on the parameter choices) in Rodrigues Space; all generated points will have the same misorientation with respect to a user defined reference point. + +Sampling mode 2 does the same as mode 1, but now the inside of the starting cube is also filled with sampling points, leading to a uniform sampling of orientations surrounding a user defined orientation with up to a maximum misorientation with respect to that orientation. + +Detailed information on the cubo-choric rotation representation can be found in the following paper: D. Rosca, A. Morawiec, and M. De Graef. **"A new method of constructing a grid in the space of 3D rotations and its applications to texture analysis,"** _Modeling and Simulations in Materials Science and Engineering **22**, 075013 (2014)._ + +Details on the misorientation sampling approach can be found in the following paper: S. Singh and M. De Graef, **"Orientation sampling for dictionary-based diffraction pattern indexing methods"** submitted to _MSMSE (2016)_. + +## DREAM3D-NX Laue Group to Point Group Table +| EbsdLib Laue Group | EbsdLib Laue Group Name | HM Sym | Point Group | +|--------------------|-------------------------|--------|-------------| +| 0 | Hexagonal_High | 6/mmm | 27 | +| 1 | Cubic_High | m-3m | 32 | +| 2 | Hexagonal_Low | 6/m | 23 | +| 3 | Cubic_Low | m-3 | 29 | +| 4 | Triclinic | -1 | 2 | +| 5 | Monoclinic | 2/m | 5 | +| 6 | OrthoRhombic | mmm | 8 | +| 7 | Tetragonal_Low | 4/m | 11 | +| 8 | Tetragonal_High | 4/mmm | 15 | +| 9 | Trigonal_Low | -3 | 17 | +| 10 | Trigonal_High | -3m | 20 | + + +## Point group identifiers ## + +Crystallographic point groups are identified by an integer from 1 to 32 according to the International Tables for Crystallography (Volume A). The valid numbers, along with the corresponding Hermann-Mauguin point group symbols (HM Sym), are listed here, along with the point group symbol between double quotation marks, the corresponding rotation group and its order M (in bold face): + +[Table adapted from http://pd.chem.ucl.ac.uk/pdnn/symm2/group32.htm](http://pd.chem.ucl.ac.uk/pdnn/symm2/group32.htm) + +| Laue Group | ID,HM Sym,Rot.Grp(Order) | ID,HM Sym,Rot.Grp(Order) | ID,HM Sym,Rot.Grp(Order) | ID,HM Sym,Rot.Grp(Order) | ID,HM Sym,Rot.Grp(Order) | ID,HM Sym,Rot.Grp(Order) | ID,HM Sym,Rot.Grp(Order) | +|------|------|------|------|------|------|------|------| +| Triclinic | [1], "1", **1(1)** | [2], "-1", **1(1)** | | | | | | +| Monoclinic | [3], "2", **2(2)**| [4], "m", **2(2)**| [5], "2/m", **2(2)**| | | | | +| Orthorhombic | [6], "222" , **222(4)**| [7], "mm2" , **222(4)**| [8], "mmm" , **222(4)**| | | | | +| Tetragonal | [9], "4" , **4(4)** | [10], "-4", **4(4)** | [11], "4/m", **4(4)** | [12], "422", **422(8)** | [13], "4mm", **422(8)** | [14], "-42m", **422(8)** | [15], "4/mmm", **422(8)** | +| Trigonal | [16], "3", **3(3)** | [17], "-3", **3(3)** | [18], "32", **32(6)** | [19], "3m" , **32(6)** | [20], "-3m", **32(6)** | | | +| Hexagonal | [21], "6", **6(6)** | [22], "-6" , **6(6)** | [23], "6/m", **6(6)** | [24], "622", **622(12)** | [25], "6mm", **622(12)** | [26], "-6m2", **622(12)** | [27], "6/mmm", **622(12)** | +| Cubic | [28], "23", **23(12)**| [29], "m-3", **23(12)** | [30], "432", **432(24)** | [31], "-43m", **432(24)** | [32], "m-3m", **432(24)** | | | | + + + +## Number of grid points ## + +The cubo-choric space is a cube with edge length pi^(2/3) and origin (the identity rotation) at the center of the cube. The number of sampling points entered by the user represents the number of grid points **along a semi-edge of the cube**. In other words, if the user requests N=50 sampling points, and the origin is part of the grid (see next item), then there will be 2N+1 actual sampling points along each cube edge. The total number of sampling points in the grid will then be (2N+1)^3. For point groups #1 and #2, in the absence of any rotational symmetry, the Rodrigues FZ will correspond to the full cubochoric grid, with (2N+1)^3 grid points. For any other point group, the Rodrigues FZ will correspond to a portion of the cubochoric grid, and the number of points will be approximately given by (2N+1)^3 /M, where M is the order of the rotation group corresponding to the point group. In the table above, the rotation group and its order are indicated in bold face. + +## Grid offset switch ## + +For sampling mode 0, the user has the option to offset the cubochoric grid from the origin by half a grid unit. In that case, the grid will have a maximum of 8N^3 grid points, and the identity rotation will **not** be part of the sample. The total number of points inside the Rodrigues FZ will then be approximately 8N^3 /M. + +## Misorientation sampling ## + +For sampling modes 1 and 2, the user must provide a reference orientation in the form of an Euler angle triplet (Bunge convention); this orientation will be used as the reference orientation around which the misorientation sampling will be computed. The output of all three sampling modes will be in Euler angles. + +## Funding Acknowledgment ## + +This filter was developed with financial support from contract AFRL FA8650-10-D-5210, Task Order 0034. + +% Auto generated parameter table will be inserted here + +## Example Pipelines ## + + +## License & Copyright + +Please see the description file distributed with this **Plugin** + +## DREAM3D-NX Help + +If you need help, need to file a bug report or want to request a new feature, please head over to the [DREAM3DNX-Issues](https://github.com/BlueQuartzSoftware/DREAM3DNX-Issues/discussions) GitHub site where the community of DREAM3D-NX users can help answer your questions. diff --git a/src/Plugins/OrientationAnalysis/pipelines/EMsoftSO3Sampler.d3dpipeline b/src/Plugins/OrientationAnalysis/pipelines/EMsoftSO3Sampler.d3dpipeline new file mode 100644 index 0000000000..0b52cdfb9a --- /dev/null +++ b/src/Plugins/OrientationAnalysis/pipelines/EMsoftSO3Sampler.d3dpipeline @@ -0,0 +1,338 @@ +{ + "isDisabled": false, + "name": "EMsoftSO3Sampler.d3dpipeline", + "pinnedParams": [], + "pipeline": [ + { + "args": { + "cell_attribute_matrix_name": { + "value": "Sampling Data", + "version": 1 + }, + "cell_ensemble_attribute_matrix_path": { + "value": "Ensemble Attribute Matrix", + "version": 1 + }, + "crystal_structure_index": { + "value": 3, + "version": 1 + }, + "mode_1_euler_angle": { + "value": [ + 0.0, + 0.0, + 0.0 + ], + "version": 1 + }, + "mode_1_misorientation": { + "value": 1.0, + "version": 1 + }, + "mode_2_euler_angle": { + "value": [ + 0.0, + 0.0, + 0.0 + ], + "version": 1 + }, + "mode_2_misorientation": { + "value": 1.0, + "version": 1 + }, + "number_of_samples": { + "value": 50, + "version": 1 + }, + "offset_grid": { + "value": false, + "version": 1 + }, + "output_euler_angles_path": { + "value": "Euler Angles", + "version": 1 + }, + "parameters_version": 1, + "sample_mode_index": { + "value": 0, + "version": 1 + } + }, + "comments": "", + "filter": { + "name": "nx::core::EMsoftSO3SamplerFilter", + "uuid": "74478e86-ce29-40b8-8c17-d20009195f91" + }, + "isDisabled": false + }, + { + "args": { + "input_orientation_array_path": { + "value": "Euler Angles", + "version": 1 + }, + "input_representation_index": { + "value": 0, + "version": 1 + }, + "output_orientation_array_name": { + "value": "SharedVertexList", + "version": 1 + }, + "output_representation_index": { + "value": 7, + "version": 1 + }, + "parameters_version": 1 + }, + "comments": "", + "filter": { + "name": "nx::core::ConvertOrientationsFilter", + "uuid": "501e54e6-a66f-4eeb-ae37-00e649c00d4b" + }, + "isDisabled": false + }, + { + "args": { + "array_handling_index": { + "value": 1, + "version": 1 + }, + "cell_attribute_matrix_name": { + "value": "Cell Data", + "version": 1 + }, + "dimensions": { + "value": [ + 20, + 60, + 200 + ], + "version": 1 + }, + "edge_attribute_matrix_name": { + "value": "Edge Data", + "version": 1 + }, + "edge_list_path": { + "value": "", + "version": 1 + }, + "face_attribute_matrix_name": { + "value": "Face Data", + "version": 1 + }, + "geometry_type_index": { + "value": 2, + "version": 1 + }, + "hexahedral_list_path": { + "value": "", + "version": 1 + }, + "length_unit_index": { + "value": 7, + "version": 1 + }, + "origin": { + "value": [ + 0.0, + 0.0, + 0.0 + ], + "version": 1 + }, + "output_geometry_path": { + "value": "SO3 Sampled Points", + "version": 1 + }, + "parameters_version": 1, + "quadrilateral_list_path": { + "value": "", + "version": 1 + }, + "spacing": { + "value": [ + 1.0, + 1.0, + 1.0 + ], + "version": 1 + }, + "tetrahedral_list_path": { + "value": "", + "version": 1 + }, + "triangle_list_path": { + "value": "", + "version": 1 + }, + "vertex_attribute_matrix_name": { + "value": "Vertex Data", + "version": 1 + }, + "vertex_list_path": { + "value": "SharedVertexList", + "version": 1 + }, + "warnings_as_errors": { + "value": false, + "version": 1 + }, + "x_bounds_path": { + "value": "", + "version": 1 + }, + "y_bounds_path": { + "value": "", + "version": 1 + }, + "z_bounds_path": { + "value": "", + "version": 1 + } + }, + "comments": "", + "filter": { + "name": "nx::core::CreateGeometryFilter", + "uuid": "24768170-5b90-4a9d-82ac-9aeecd9f892e" + }, + "isDisabled": false + }, + { + "args": { + "destination_parent_path": { + "value": "SO3 Sampled Points/Vertex Data", + "version": 1 + }, + "parameters_version": 1, + "source_data_paths": { + "value": [ + "Euler Angles" + ], + "version": 1 + } + }, + "comments": "", + "filter": { + "name": "nx::core::MoveDataFilter", + "uuid": "651e5894-ab7c-4176-b7f0-ea466c521753" + }, + "isDisabled": false + }, + { + "args": { + "component_count": { + "value": 1, + "version": 1 + }, + "data_format": { + "value": "", + "version": 1 + }, + "initialization_value_str": { + "value": "1", + "version": 1 + }, + "numeric_type_index": { + "value": 4, + "version": 1 + }, + "output_array_path": { + "value": "SO3 Sampled Points/Vertex Data/Phases", + "version": 1 + }, + "parameters_version": 1, + "set_tuple_dimensions": { + "value": true, + "version": 1 + }, + "tuple_dimensions": { + "value": [ + [ + 0.0 + ] + ], + "version": 1 + } + }, + "comments": "", + "filter": { + "name": "nx::core::CreateDataArrayFilter", + "uuid": "67041f9b-bdc6-4122-acc6-c9fe9280e90d" + }, + "isDisabled": false + }, + { + "args": { + "cell_euler_angles_array_path": { + "value": "SO3 Sampled Points/Vertex Data/Euler Angles", + "version": 1 + }, + "cell_ipf_colors_array_name": { + "value": "IPFColors", + "version": 1 + }, + "cell_phases_array_path": { + "value": "SO3 Sampled Points/Vertex Data/Phases", + "version": 1 + }, + "crystal_structures_array_path": { + "value": "Ensemble Attribute Matrix/CrystalStructures", + "version": 1 + }, + "mask_array_path": { + "value": "", + "version": 1 + }, + "parameters_version": 1, + "reference_dir": { + "value": [ + 0.0, + 0.0, + 1.0 + ], + "version": 1 + }, + "use_mask": { + "value": false, + "version": 1 + } + }, + "comments": "", + "filter": { + "name": "nx::core::ComputeIPFColorsFilter", + "uuid": "64cb4f27-6e5e-4dd2-8a03-0c448cb8f5e6" + }, + "isDisabled": false + }, + { + "args": { + "import_data_object": { + "value": { + "data_paths": [ + "Laue_422/Edge Data", + "Laue_422/Shared Edge List", + "Laue_422/Shared Vertex List", + "Laue_422/Vertex Data" + ], + "file_path": "/Users/Shared/Data/MTR_Data/OrientationSampling/Laue_FZ_Wireframes.dream3d", + "path_import_policy": 1 + }, + "version": 2 + }, + "parameters_version": 1 + }, + "comments": "", + "filter": { + "name": "nx::core::ReadDREAM3DFilter", + "uuid": "0dbd31c7-19e0-4077-83ef-f4a6459a0e2d" + }, + "isDisabled": true + } + ], + "pipeline_uuid": "3d2f82b9-2d46-4bc1-9c48-d63625374070", + "version": 1, + "workflowParams": [] +} diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/EMsoftSO3Sampler.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/EMsoftSO3Sampler.cpp new file mode 100644 index 0000000000..caba7b622a --- /dev/null +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/EMsoftSO3Sampler.cpp @@ -0,0 +1,313 @@ +#include "EMsoftSO3Sampler.hpp" + +#include "simplnx/Common/Constants.hpp" +#include "simplnx/DataStructure/DataArray.hpp" +#include "simplnx/DataStructure/StringArray.hpp" +#include "simplnx/Utilities/MessageHelper.hpp" + +#include "EbsdLib/Core/EbsdLibConstants.h" +#include "EbsdLib/Core/Orientation.hpp" +#include "EbsdLib/Core/OrientationTransformation.hpp" +#include "EbsdLib/IO/TSL/AngConstants.h" +#include "EbsdLib/LaueOps/LaueOps.h" + +using namespace nx::core; + +// ----------------------------------------------------------------------------- +EMsoftSO3Sampler::EMsoftSO3Sampler(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, EMsoftSO3SamplerInputValues* inputValues) +: m_DataStructure(dataStructure) +, m_InputValues(inputValues) +, m_ShouldCancel(shouldCancel) +, m_MessageHandler(mesgHandler) +{ +} + +// ----------------------------------------------------------------------------- +EMsoftSO3Sampler::~EMsoftSO3Sampler() noexcept = default; + +// ----------------------------------------------------------------------------- +Result<> EMsoftSO3Sampler::operator()() +{ + typedef std::list OrientationListArrayType; + + OrientationListArrayType FZlist; + + if(m_InputValues->sampleModeSelector == orientation_sampling::k_FZModeIndex) + { + // here we perform the actual calculation; once we have the FZlist, + // we can allocate the data array and copy all entries + double x, y, z, delta; + + // step size for sampling of grid; maximum total number of samples = pow(2*m_InputValues->Numsp+1,3) + delta = (0.50 * LPs::ap) / static_cast(m_InputValues->Numsp); + + // do we need to shift this array away from the origin? + double gridShift = 0.0; + if(m_InputValues->OffsetGrid) + { + gridShift = 0.5; + } + + std::vector ops = LaueOps::GetAllOrientationOps(); + // determine which function we should call for this point group symmetry + LaueOps::FZType fzType = ops[m_InputValues->CrystalStructureIndex]->getFZType(); + LaueOps::AxisOrderingType fzAxisOrder = ops[m_InputValues->CrystalStructureIndex]->getAxisOrderingType(); + + // loop over the cube of volume pi^2; note that we do not want to include + // the opposite edges/facets of the cube, to avoid double counting rotations + // with a rotation angle of 180 degrees. This only affects the cyclic groups. + int Np = m_InputValues->Numsp; + int Totp = (2 * Np + 1) * (2 * Np + 1) * (2 * Np + 1); + int Dn = Totp / 10; + int Dc = Dn; + int Di = 0; + int Dg = 0; + + // eliminate points for which any of the coordinates lies outside the cube with semi-edge length "edge" + double edge = 0.5 * LPs::ap; + + for(int i = -Np + 1; i < Np + 1; i++) + { + x = (static_cast(i) + gridShift) * delta; + + if(fabs(x) <= edge) + { + + for(int j = -Np + 1; j < Np + 1; j++) + { + y = (static_cast(j) + gridShift) * delta; + + if(fabs(y) <= edge) + { + + for(int k = -Np + 1; k < Np + 1; k++) + { + z = (static_cast(k) + gridShift) * delta; + + if(fabs(z) <= edge) + { + + // convert to Rodrigues representation + OrientationD cu(x, y, z); + OrientationD rod = OrientationTransformation::cu2ro(cu); + + // If insideFZ=true, then add this point to FZlist + if(LaueOps::IsInsideFZ(rod, fzType, fzAxisOrder)) + { + FZlist.push_back(rod); + Dg += 1; + } + Di += 1; + } + } + } + } + } + + // report on status of computation + if(Di > Dc) + { + m_MessageHandler(IFilter::Message::Type::Info, fmt::format("Euler Angles | Tested: {} of {} | Inside RFZ: {} ", Di, Totp, Dg)); + Dc += Dn; + } + if(m_ShouldCancel) + { + break; + } + } + } + + // here are the misorientation sampling cases: + if(m_InputValues->sampleModeSelector != 0) + { + // here we perform the actual calculation; once we have the FZlist, + // we can allocate the data array and copy all entries + double x, y, z, delta, omega, semi; + + // step size for sampling of grid; the edge length of the cube is (pi ( w - sin(w) ))^1/3 with w the misorientation angle + omega = m_InputValues->MisOr * Constants::k_PiOver180D; + semi = pow(Constants::k_PiD * (omega - sin(omega)), 1.0 / 3.0) * 0.5; + delta = semi / static_cast(m_InputValues->Numsp); + + // convert the reference orientation to a 3-component Rodrigues vector sigma + OrientationD sigma(3), referenceOrientation(3); + referenceOrientation[0] = static_cast(m_InputValues->RefOr[0] * Constants::k_PiOver180D); + referenceOrientation[1] = static_cast(m_InputValues->RefOr[1] * Constants::k_PiOver180D); + referenceOrientation[2] = static_cast(m_InputValues->RefOr[2] * Constants::k_PiOver180D); + OrientationD sigm = OrientationTransformation::eu2ro(referenceOrientation); + sigma[0] = sigm[0] * sigm[3]; + sigma[1] = sigm[1] * sigm[3]; + sigma[2] = sigm[2] * sigm[3]; + + if(m_InputValues->sampleModeSelector == 1) + { + // set counter parameters for the loop over the sub-cube surface + int Np = m_InputValues->Numsp; + int Totp = 24 * Np * Np + 2; + int Dn = Totp / 20; + int Dc = Dn; + int Dg = 0; + + // x-y bottom and top planes + for(int i = -Np; i <= Np; i++) + { + x = static_cast(i) * delta; + for(int j = -Np; j <= Np; j++) + { + y = static_cast(j) * delta; + // convert to Rodrigues representation and apply Rodrigues composition formula + { + OrientationD cu(-x, -y, -semi); + OrientationD rod = OrientationTransformation::cu2ro(cu); + LaueOps::RodriguesComposition(sigma, rod); + FZlist.push_back(rod); + Dg += 1; + } + { + OrientationD cu(-x, -y, semi); + OrientationD rod = OrientationTransformation::cu2ro(cu); + LaueOps::RodriguesComposition(sigma, rod); + FZlist.push_back(rod); + Dg += 1; + } + } + if(m_ShouldCancel) + { + break; + } + } + // y-z planes + for(int j = -Np; j <= Np; j++) + { + y = static_cast(j) * delta; + for(int k = -Np + 1; k <= Np - 1; k++) + { + z = static_cast(k) * delta; + // convert to Rodrigues representation and apply Rodrigues composition formula + { + OrientationD cu(-semi, -y, -z); + OrientationD rod = OrientationTransformation::cu2ro(cu); + LaueOps::RodriguesComposition(sigma, rod); + FZlist.push_back(rod); + Dg += 1; + } + { + OrientationD cu(semi, -y, -z); + OrientationD rod = OrientationTransformation::cu2ro(cu); + LaueOps::RodriguesComposition(sigma, rod); + FZlist.push_back(rod); + Dg += 1; + } + } + if(m_ShouldCancel) + { + break; + } + } + // finally the x-z planes + for(int i = -Np + 1; i <= Np - 1; i++) + { + x = static_cast(i) * delta; + for(int k = -Np + 1; k <= Np - 1; k++) + { + z = static_cast(k) * delta; + // convert to Rodrigues representation and apply Rodrigues composition formula + { + OrientationD cu(-x, -semi, -z); + OrientationD rod = OrientationTransformation::cu2ro(cu); + LaueOps::RodriguesComposition(sigma, rod); + FZlist.push_back(rod); + Dg += 1; + } + { + OrientationD cu(-x, semi, -z); + OrientationD rod = OrientationTransformation::cu2ro(cu); + LaueOps::RodriguesComposition(sigma, rod); + FZlist.push_back(rod); + Dg += 1; + } + } + if(m_ShouldCancel) + { + break; + } + } + + // report on status of computation + if(Dg > Dc) + { + m_MessageHandler(IFilter::Message::Type::Info, fmt::format("Euler Angles | Generated: {} / {}", Dg, Totp)); + + Dc += Dn; + } + } + else + { + // set counter parameters for the loop over the sub-cube surface + int Np = m_InputValues->Numsp; + int Totp = (2 * Np + 1) * (2 * Np + 1) * (2 * Np + 1); // see misorientation sampling paper for this expression + int Dn = Totp / 20; + int Dc = Dn; + int Dg = 0; + + for(int i = -Np; i <= Np; i++) + { + x = static_cast(i) * delta; + for(int j = -Np; j <= Np; j++) + { + y = static_cast(j) * delta; + for(int k = -Np; k <= Np; k++) + { + z = static_cast(k) * delta; + // convert to Rodrigues representation and apply Rodrigues composition formula + { + OrientationD cu(-x, -y, -z); + OrientationD rod = OrientationTransformation::cu2ro(cu); + LaueOps::RodriguesComposition(sigma, rod); + FZlist.push_back(rod); + Dg += 1; + } + } + } + // report on status of computation + if(Dg > Dc) + { + m_MessageHandler(IFilter::Message::Type::Info, fmt::format("Euler Angles | Generated: {} / {}", Dg, Totp)); + Dc += Dn; + } + } + } + } + + // resize the EulerAngles array to the number of items in FZlist; don't forget to redefine the hard pointer + std::vector tDims = {FZlist.size()}; + + auto& m_EulerAngles = m_DataStructure.getDataRefAs(m_InputValues->EulerAnglesArrayName); + m_EulerAngles.resizeTuples(tDims); + auto& m_EulerAnglesStoreRef = m_EulerAngles.getDataStoreRef(); + // copy the Rodrigues vectors as Euler angles into the m_EulerAngles array; convert doubles to floats along the way + int j = -1; + for(const OrientationD& rod : FZlist) + { + j += 1; + OrientationD eu = OrientationTransformation::ro2eu(rod); + + m_EulerAnglesStoreRef.setValue(j * 3 + 0, static_cast(eu[0])); + m_EulerAnglesStoreRef.setValue(j * 3 + 1, static_cast(eu[1])); + m_EulerAnglesStoreRef.setValue(j * 3 + 2, static_cast(eu[2])); + } + + auto& crystalStructures = m_DataStructure.getDataRefAs(m_InputValues->EnsembleAttrMatrixPath.createChildPath(EbsdLib::AngFile::CrystalStructures)); + + auto& materialNames = m_DataStructure.getDataRefAs(m_InputValues->EnsembleAttrMatrixPath.createChildPath(EbsdLib::AngFile::MaterialName)); + const std::string k_InvalidPhase = "Invalid Phase"; + + // Initialize the zero'th element to unknowns. + crystalStructures.setValue(0, EbsdLib::CrystalStructure::UnknownCrystalStructure); + materialNames.setValue(0, k_InvalidPhase); + + crystalStructures.setValue(1, m_InputValues->CrystalStructureIndex); + materialNames.setValue(1, "EMSoftSO3Sampler"); + + return {}; +} diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/EMsoftSO3Sampler.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/EMsoftSO3Sampler.hpp new file mode 100644 index 0000000000..b42d7693da --- /dev/null +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/EMsoftSO3Sampler.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "OrientationAnalysis/OrientationAnalysis_export.hpp" + +#include "simplnx/DataStructure/DataPath.hpp" +#include "simplnx/DataStructure/DataStructure.hpp" +#include "simplnx/Filter/IFilter.hpp" +#include "simplnx/Parameters/ChoicesParameter.hpp" +#include "simplnx/Parameters/VectorParameter.hpp" + +namespace nx::core +{ + +struct ORIENTATIONANALYSIS_EXPORT EMsoftSO3SamplerInputValues +{ + ChoicesParameter::ValueType sampleModeSelector; + usize CrystalStructureIndex; + bool OffsetGrid; + float64 MisOr; + VectorFloat32Parameter::ValueType RefOr; + float64 MisOrFull; + VectorFloat32Parameter::ValueType RefOrFull; + int32 Numsp; + DataPath EulerAnglesArrayName; + DataPath EnsembleAttrMatrixPath; +}; + +namespace orientation_sampling +{ +const std::string k_FZMode("Rodrigues fundamental zone (0)"); +const std::string k_ConstantMode("Constant misorientation (1)"); +const std::string k_LessThan("Less than given misorientation (2)"); +const ChoicesParameter::Choices k_Choices = {k_FZMode, k_ConstantMode, k_LessThan}; + +constexpr ChoicesParameter::ValueType k_FZModeIndex = 0; +constexpr ChoicesParameter::ValueType k_ConstantModeIndex = 1; +constexpr ChoicesParameter::ValueType k_LessThanModeIndex = 2; +} // namespace orientation_sampling + +/** + * @class EMsoftSO3Sampler + * @brief This algorithm implements support code for the EMsoftSO3SamplerFilter + */ + +class ORIENTATIONANALYSIS_EXPORT EMsoftSO3Sampler +{ +public: + EMsoftSO3Sampler(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, EMsoftSO3SamplerInputValues* inputValues); + ~EMsoftSO3Sampler() noexcept; + + EMsoftSO3Sampler(const EMsoftSO3Sampler&) = delete; + EMsoftSO3Sampler(EMsoftSO3Sampler&&) noexcept = delete; + EMsoftSO3Sampler& operator=(const EMsoftSO3Sampler&) = delete; + EMsoftSO3Sampler& operator=(EMsoftSO3Sampler&&) noexcept = delete; + + Result<> operator()(); + +private: + DataStructure& m_DataStructure; + const EMsoftSO3SamplerInputValues* m_InputValues = nullptr; + const std::atomic_bool& m_ShouldCancel; + const IFilter::MessageHandler& m_MessageHandler; +}; + +} // namespace nx::core diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/EMsoftSO3SamplerFilter.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/EMsoftSO3SamplerFilter.cpp new file mode 100644 index 0000000000..74f359e1d1 --- /dev/null +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/EMsoftSO3SamplerFilter.cpp @@ -0,0 +1,247 @@ +#include "EMsoftSO3SamplerFilter.hpp" + +#include "OrientationAnalysis/Filters/Algorithms/EMsoftSO3Sampler.hpp" +#include "simplnx/DataStructure/DataGroup.hpp" + +#include "simplnx/DataStructure/DataPath.hpp" +#include "simplnx/Filter/Actions/CreateArrayAction.hpp" +#include "simplnx/Filter/Actions/CreateAttributeMatrixAction.hpp" +#include "simplnx/Filter/Actions/CreateStringArrayAction.hpp" +#include "simplnx/Filter/Actions/EmptyAction.hpp" +#include "simplnx/Parameters/ArrayCreationParameter.hpp" +#include "simplnx/Parameters/BoolParameter.hpp" +#include "simplnx/Parameters/ChoicesParameter.hpp" +#include "simplnx/Parameters/DataGroupCreationParameter.hpp" +#include "simplnx/Parameters/DataObjectNameParameter.hpp" +#include "simplnx/Parameters/EnsembleInfoParameter.hpp" +#include "simplnx/Parameters/NumberParameter.hpp" +#include "simplnx/Parameters/VectorParameter.hpp" + +#include "EbsdLib/IO/TSL/AngConstants.h" + +using namespace nx::core; + +namespace +{ + +} + +namespace nx::core +{ +//------------------------------------------------------------------------------ +std::string EMsoftSO3SamplerFilter::name() const +{ + return FilterTraits::name.str(); +} + +//------------------------------------------------------------------------------ +std::string EMsoftSO3SamplerFilter::className() const +{ + return FilterTraits::className; +} + +//------------------------------------------------------------------------------ +Uuid EMsoftSO3SamplerFilter::uuid() const +{ + return FilterTraits::uuid; +} + +//------------------------------------------------------------------------------ +std::string EMsoftSO3SamplerFilter::humanName() const +{ + return "SO3 Orientation Sampler"; +} + +//------------------------------------------------------------------------------ +std::vector EMsoftSO3SamplerFilter::defaultTags() const +{ + return {className(), "Sampling", "Crystallography"}; +} + +//------------------------------------------------------------------------------ +Parameters EMsoftSO3SamplerFilter::parameters() const +{ + Parameters params; + // Create the parameter descriptors that are needed for this filter + params.insertSeparator(Parameters::Separator{"Input Parameter(s)"}); + params.insert(std::make_unique(k_NumberSamples_Key, "Number of sampling points along cube semi-axis", "The number of sampling points along the cube semi-axis", 101)); + params.insertLinkableParameter(std::make_unique(k_SampleModeSelector_Key, "Select the desired SO(3) sampling mode", + "This is the mode that is ued to sample the orientation space. [0-2]", orientation_sampling::k_FZModeIndex, + orientation_sampling::k_Choices)); + + params.insert(std::make_unique(k_CrystalStructure_Index, "Laue Class", "Laue Class Index. See documentation for list.", 1, EnsembleInfoParameter::k_CrystalStructures)); + + params.insert(std::make_unique(k_OffsetGrid_Key, "Offset sampling grid from origin?", "Offset the cubo-choric grid from the origin by half a grid unit.", false)); + params.insert(std::make_unique(k_Mode1Misorientation_Key, "Misorientation angle (degree)", "Reference Misorientation in Degrees", 1.0)); + params.insert(std::make_unique(k_Mode1EulerAngle_Key, "Reference orientation (Euler, °)", "Reference Orientation as a Bunge Euler Triplet in Degrees", + std::vector{0.0F, 0.0F, 0.0F}, std::vector{"phi-1", "PHI", "phi-2"})); + params.insert(std::make_unique(k_Mode2Misorientation_Key, "Misorientation angle (degree)", "Reference Misorientation in Degrees", 1.0)); + params.insert(std::make_unique(k_Mode2EulerAngle_Key, "Reference orientation (Euler, °)", "Reference Orientation as a Bunge Euler Triplet in Degrees", + std::vector{0.0F, 0.0F, 0.0F}, std::vector{"phi-1", "PHI", "phi-2"})); + + params.insertSeparator(Parameters::Separator{"Output Data"}); + params.insert(std::make_unique(k_EulerAnglesArrayPath_Key, "Euler Angles", "Output array to hold the generated Euler Angles", DataPath({"Euler Angles"}))); + + params.insert(std::make_unique(k_CellAttributeMatrixName_Key, "Output Attribute Matrix", "The name of the cell data attribute matrix for the created Image Geometry", + DataGroupCreationParameter::ValueType({"Sampling Data"}))); + params.insert(std::make_unique(k_EnsembleAttributeMatrixPath_Key, "Ensemble Attribute Matrix", "The Attribute Matrix where the phase information is stored.", + DataGroupCreationParameter::ValueType({"Ensemble Attribute Matrix"}))); + + // Associate the Linkable Parameter(s) to the children parameters that they control + params.linkParameters(k_SampleModeSelector_Key, k_CrystalStructure_Index, static_cast(0)); + params.linkParameters(k_SampleModeSelector_Key, k_OffsetGrid_Key, static_cast(0)); + + params.linkParameters(k_SampleModeSelector_Key, k_Mode1Misorientation_Key, static_cast(1)); + params.linkParameters(k_SampleModeSelector_Key, k_Mode1EulerAngle_Key, static_cast(1)); + + params.linkParameters(k_SampleModeSelector_Key, k_Mode2Misorientation_Key, static_cast(2)); + params.linkParameters(k_SampleModeSelector_Key, k_Mode2EulerAngle_Key, static_cast(2)); + + return params; +} + +//------------------------------------------------------------------------------ +IFilter::VersionType EMsoftSO3SamplerFilter::parametersVersion() const +{ + return 1; +} + +//------------------------------------------------------------------------------ +IFilter::UniquePointer EMsoftSO3SamplerFilter::clone() const +{ + return std::make_unique(); +} + +//------------------------------------------------------------------------------ +IFilter::PreflightResult EMsoftSO3SamplerFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel, const ExecutionContext& executionContext) const +{ + auto psampleModeSelectorValue = filterArgs.value(k_SampleModeSelector_Key); + auto pCrystalStructureIndex = filterArgs.value(k_CrystalStructure_Index); + auto pOffsetGridValue = filterArgs.value(k_OffsetGrid_Key); + auto pMisOrValue = filterArgs.value(k_Mode1Misorientation_Key); + auto pRefOrValue = filterArgs.value(k_Mode1EulerAngle_Key); + auto pMisOrFullValue = filterArgs.value(k_Mode2Misorientation_Key); + auto pRefOrFullValue = filterArgs.value(k_Mode2EulerAngle_Key); + auto pNumspValue = filterArgs.value(k_NumberSamples_Key); + auto pEulerAnglesArrayPath = filterArgs.value(k_EulerAnglesArrayPath_Key); + // auto pCellAttributeMatrixNameValue = filterArgs.value(k_CellAttributeMatrixName_Key); + auto ensembleAttributeMatrixPath = filterArgs.value(k_EnsembleAttributeMatrixPath_Key); + + nx::core::Result resultOutputActions; + + std::vector preflightUpdatedValues; + + // check on the point group index; must be between 1 and 32. + if(psampleModeSelectorValue == 0) + { + if(pCrystalStructureIndex > 10) + { + return MakePreflightErrorResult(-78760, "Crystal Structure Index must be in range [0,10]. See documentation for table of values"); + } + } + + // make sure that the misorientation angle lies in [0,90], and the Euler angles in [0,360], [0,180], [0,360] + if(psampleModeSelectorValue == 1) + { + if((pMisOrValue < 0.0) || (pMisOrValue > 90.0)) + { + return MakePreflightErrorResult(-70002, "Misorientation angle must fall in interval [0,90]"); + } + if((pRefOrValue[0] < 0.0) || (pRefOrValue[0] > 360.0f) || (pRefOrValue[1] < 0.0f) || (pRefOrValue[1] > 180.0f) || (pRefOrValue[2] < 0.0f) || (pRefOrValue[2] > 360.0f)) + { + return MakePreflightErrorResult(-70003, "Euler angles must be positive and less than [360°,180°,360°]"); + } + } + if(psampleModeSelectorValue == 2) + { + if((pMisOrFullValue < 0.0) || (pMisOrFullValue > 90.0)) + { + return MakePreflightErrorResult(-70004, "Misorientation angle must fall in interval [0,90]"); + } + if((pRefOrFullValue[0] < 0.0f) || (pRefOrFullValue[0] > 360.0f) || (pRefOrFullValue[1] < 0.0f) || (pRefOrFullValue[1] > 180.0f) || (pRefOrFullValue[2] < 0.0f) || (pRefOrFullValue[2] > 360.0f)) + { + return MakePreflightErrorResult(-70005, "Euler angles must be positive and less than [360°,180°,360°]"); + } + } + + // check on the number of sampling intervals (>1) + if(pNumspValue < 1) + { + return MakePreflightErrorResult(-70002, "Number of sampling intervals must be at least 1 "); + } + + // create the destination array for the calculated results + { + auto createArrayAction = std::make_unique(DataType::float32, std::vector{1}, std::vector{3}, pEulerAnglesArrayPath); + resultOutputActions.value().appendAction(std::move(createArrayAction)); + } + + // Create the Ensemble AttributeMatrix + nx::core::ShapeType tupleDims = {2}; // Always create 1 extra slot for the phases. + { + auto createAttributeMatrixAction = std::make_unique(ensembleAttributeMatrixPath, tupleDims); + resultOutputActions.value().appendAction(std::move(createAttributeMatrixAction)); + } + + // Create the Crystal Structures Array + nx::core::ShapeType cDims = {1}; + { + DataPath dataArrayPath = ensembleAttributeMatrixPath.createChildPath(EbsdLib::AngFile::CrystalStructures); + auto action = std::make_unique(nx::core::DataType::uint32, tupleDims, cDims, dataArrayPath); + resultOutputActions.value().appendAction(std::move(action)); + } + // Create the Material Names Array + { + DataPath dataArrayPath = ensembleAttributeMatrixPath.createChildPath(EbsdLib::AngFile::MaterialName); + auto action = std::make_unique(tupleDims, dataArrayPath); + resultOutputActions.value().appendAction(std::move(action)); + } + + // Return both the resultOutputActions and the preflightUpdatedValues via std::move() + return {std::move(resultOutputActions), std::move(preflightUpdatedValues)}; +} + +//------------------------------------------------------------------------------ +Result<> EMsoftSO3SamplerFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel, const ExecutionContext& executionContext) const +{ + + EMsoftSO3SamplerInputValues inputValues; + + inputValues.sampleModeSelector = filterArgs.value(k_SampleModeSelector_Key); + inputValues.CrystalStructureIndex = filterArgs.value(k_CrystalStructure_Index); + inputValues.OffsetGrid = filterArgs.value(k_OffsetGrid_Key); + inputValues.MisOr = filterArgs.value(k_Mode1Misorientation_Key); + inputValues.RefOr = filterArgs.value(k_Mode1EulerAngle_Key); + inputValues.MisOrFull = filterArgs.value(k_Mode2Misorientation_Key); + inputValues.RefOrFull = filterArgs.value(k_Mode2EulerAngle_Key); + inputValues.Numsp = filterArgs.value(k_NumberSamples_Key); + inputValues.EulerAnglesArrayName = filterArgs.value(k_EulerAnglesArrayPath_Key); + + inputValues.EnsembleAttrMatrixPath = filterArgs.value(k_EnsembleAttributeMatrixPath_Key); + + return EMsoftSO3Sampler(dataStructure, messageHandler, shouldCancel, &inputValues)(); +} + +namespace +{ +namespace SIMPL +{ + +} // namespace SIMPL +} // namespace + +//------------------------------------------------------------------------------ +Result EMsoftSO3SamplerFilter::FromSIMPLJson(const nlohmann::json& json) +{ + Arguments args = EMsoftSO3SamplerFilter().getDefaultArguments(); + + std::vector> results; + + Result<> conversionResult = MergeResults(std::move(results)); + + return ConvertResultTo(std::move(conversionResult), std::move(args)); +} + +} // namespace nx::core diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/EMsoftSO3SamplerFilter.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/EMsoftSO3SamplerFilter.hpp new file mode 100644 index 0000000000..2ff45fd7f1 --- /dev/null +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/EMsoftSO3SamplerFilter.hpp @@ -0,0 +1,133 @@ +#pragma once + +#include "OrientationAnalysis/OrientationAnalysis_export.hpp" + +#include "simplnx/Filter/FilterTraits.hpp" +#include "simplnx/Filter/IFilter.hpp" + +namespace nx::core +{ +/** + * @class EMsoftSO3SamplerFilter + * @brief This filter will .... + */ +class ORIENTATIONANALYSIS_EXPORT EMsoftSO3SamplerFilter : public IFilter +{ +public: + EMsoftSO3SamplerFilter() = default; + ~EMsoftSO3SamplerFilter() noexcept override = default; + + EMsoftSO3SamplerFilter(const EMsoftSO3SamplerFilter&) = delete; + EMsoftSO3SamplerFilter(EMsoftSO3SamplerFilter&&) noexcept = delete; + + EMsoftSO3SamplerFilter& operator=(const EMsoftSO3SamplerFilter&) = delete; + EMsoftSO3SamplerFilter& operator=(EMsoftSO3SamplerFilter&&) noexcept = delete; + + // Parameter Keys + static constexpr StringLiteral k_SampleModeSelector_Key = "sample_mode_index"; + static constexpr StringLiteral k_OffsetGrid_Key = "offset_grid"; + + static constexpr StringLiteral k_Mode1Misorientation_Key = "mode_1_misorientation"; + static constexpr StringLiteral k_Mode1EulerAngle_Key = "mode_1_euler_angle"; + + static constexpr StringLiteral k_Mode2Misorientation_Key = "mode_2_misorientation"; + static constexpr StringLiteral k_Mode2EulerAngle_Key = "mode_2_euler_angle"; + + static constexpr StringLiteral k_NumberSamples_Key = "number_of_samples"; + static constexpr StringLiteral k_EulerAnglesArrayPath_Key = "output_euler_angles_path"; + + static constexpr StringLiteral k_CrystalStructure_Index = "crystal_structure_index"; + + static inline constexpr StringLiteral k_CellAttributeMatrixName_Key = "cell_attribute_matrix_name"; + static inline constexpr StringLiteral k_EnsembleAttributeMatrixPath_Key = "cell_ensemble_attribute_matrix_path"; + + /** + * @brief Reads SIMPL json and converts it simplnx Arguments. + * @param json + * @return Result + */ + static Result FromSIMPLJson(const nlohmann::json& json); + + /** + * @brief Returns the name of the filter. + * @return + */ + std::string name() const override; + + /** + * @brief Returns the C++ classname of this filter. + * @return + */ + std::string className() const override; + + /** + * @brief Returns the uuid of the filter. + * @return + */ + Uuid uuid() const override; + + /** + * @brief Returns the human-readable name of the filter. + * @return + */ + std::string humanName() const override; + + /** + * @brief Returns the default tags for this filter. + * @return + */ + std::vector defaultTags() const override; + + /** + * @brief Returns the parameters of the filter (i.e. its inputs) + * @return + */ + Parameters parameters() const override; + + /** + * @brief Returns parameters version integer. + * Initial version should always be 1. + * Should be incremented everytime the parameters change. + * @return VersionType + */ + VersionType parametersVersion() const override; + + /** + * @brief Returns a copy of the filter. + * @return + */ + UniquePointer clone() const override; + +protected: + /** + * @brief Takes in a DataStructure and checks that the filter can be run on it with the given arguments. + * Returns any warnings/errors. Also returns the changes that would be applied to the DataStructure. + * Some parts of the actions may not be completely filled out if all the required information is not available at preflight time. + * @param dataStructure The input DataStructure instance + * @param filterArgs These are the input values for each parameter that is required for the filter + * @param messageHandler The MessageHandler object + * @param shouldCancel Atomic boolean value that can be checked to cancel the filter + * @param executionContext The ExecutionContext that can be used to determine the correct absolute path from a relative path + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + PreflightResult preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel, + const ExecutionContext& executionContext) const override; + + /** + * @brief Applies the filter's algorithm to the DataStructure with the given arguments. Returns any warnings/errors. + * On failure, there is no guarantee that the DataStructure is in a correct state. + * @param dataStructure The input DataStructure instance + * @param filterArgs These are the input values for each parameter that is required for the filter + * @param pipelineNode The node in the pipeline that is being executed + * @param messageHandler The MessageHandler object + * @param shouldCancel Atomic boolean value that can be checked to cancel the filter + * @param executionContext The ExecutionContext that can be used to determine the correct absolute path from a relative path + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + Result<> executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel, + const ExecutionContext& executionContext) const override; +}; +} // namespace nx::core + +SIMPLNX_DEF_FILTER_TRAITS(nx::core, EMsoftSO3SamplerFilter, "74478e86-ce29-40b8-8c17-d20009195f91"); +/* LEGACY UUID FOR THIS FILTER b78d8825-d3ac-5351-be20-172f07fd2aec */ diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/OrientationAnalysisLegacyUUIDMapping.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/OrientationAnalysisLegacyUUIDMapping.hpp index 4191359117..b9f9956a82 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/OrientationAnalysisLegacyUUIDMapping.hpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/OrientationAnalysisLegacyUUIDMapping.hpp @@ -73,6 +73,7 @@ #include "OrientationAnalysis/Filters/ComputeSlipTransmissionMetricsFilter.hpp" #include "OrientationAnalysis/Filters/WriteStatsGenOdfAngleFileFilter.hpp" #include "OrientationAnalysis/Filters/WriteINLFileFilter.hpp" +#include "OrientationAnalysis/Filters/EMsoftSO3SamplerFilter.hpp" // @@__HEADER__TOKEN__DO__NOT__DELETE__@@ #include @@ -147,6 +148,7 @@ namespace nx::core {nx::core::Uuid::FromString("d67e9f28-2fe5-5188-b0f8-323a7e603de6").value(), {nx::core::FilterTraits::uuid, &ComputeGBCDMetricBasedFilter::FromSIMPLJson}}, // ComputeGBCDMetricBased {nx::core::Uuid::FromString("a4952f40-22dd-54ec-8c38-69c3fcd0e6f7").value(), {nx::core::FilterTraits::uuid, &WriteStatsGenOdfAngleFileFilter::FromSIMPLJson}}, // WriteStatsGenOdfAngleFile {nx::core::Uuid::FromString("27c724cc-8b69-5ebe-b90e-29d33858a032").value(), {nx::core::FilterTraits::uuid, &WriteINLFileFilter::FromSIMPLJson}}, // INLWriter + {nx::core::Uuid::FromString("b78d8825-d3ac-5351-be20-172f07fd2aec").value(), {nx::core::FilterTraits::uuid, &EMsoftSO3SamplerFilter::FromSIMPLJson}}, // EMsoftSO3Sampler // @@__MAP__UPDATE__TOKEN__DO__NOT__DELETE__@@ }; diff --git a/src/Plugins/OrientationAnalysis/test/CMakeLists.txt b/src/Plugins/OrientationAnalysis/test/CMakeLists.txt index 7b5bfad4e7..84e0b0f88a 100644 --- a/src/Plugins/OrientationAnalysis/test/CMakeLists.txt +++ b/src/Plugins/OrientationAnalysis/test/CMakeLists.txt @@ -58,10 +58,10 @@ set(${PLUGIN_NAME}UnitTest_SRCS WriteINLFileTest.cpp WritePoleFigureTest.cpp WriteStatsGenOdfAngleFileTest.cpp + EMsoftSO3SamplerTest.cpp ) set(DISABLED_TESTS CreateLambertSphereTest.cpp - EMsoftSO3SamplerTest.cpp FindDistsToCharactGBsTest.cpp ComputeFeatureReferenceCAxisMisorientationsTest.cpp FindTwinBoundariesTest.cpp diff --git a/src/Plugins/OrientationAnalysis/test/EMsoftSO3SamplerTest.cpp b/src/Plugins/OrientationAnalysis/test/EMsoftSO3SamplerTest.cpp new file mode 100644 index 0000000000..089366c515 --- /dev/null +++ b/src/Plugins/OrientationAnalysis/test/EMsoftSO3SamplerTest.cpp @@ -0,0 +1,64 @@ +/** + * This file is auto generated from the original OrientationAnalysis/EMsoftSO3SamplerFilter + * runtime information. These are the steps that need to be taken to utilize this + * unit test in the proper way. + * + * 1: Validate each of the default parameters that gets created. + * 2: Inspect the actual filter to determine if the filter in its default state + * would pass or fail BOTH the preflight() and execute() methods + * 3: UPDATE the ```REQUIRE(result.result.valid());``` code to have the proper + * + * 4: Add additional unit tests to actually test each code path within the filter + * + * There are some example Catch2 ```TEST_CASE``` sections for your inspiration. + * + * NOTE the format of the ```TEST_CASE``` macro. Please stick to this format to + * allow easier parsing of the unit tests. + * + * When you start working on this unit test remove "[EMsoftSO3SamplerFilter][.][UNIMPLEMENTED]" + * from the TEST_CASE macro. This will enable this unit test to be run by default + * and report errors. + */ + +#include + +#include "simplnx/Parameters/ArrayCreationParameter.hpp" +#include "simplnx/Parameters/BoolParameter.hpp" +#include "simplnx/Parameters/NumberParameter.hpp" +#include "simplnx/Parameters/VectorParameter.hpp" + +#include "OrientationAnalysis/Filters/EMsoftSO3SamplerFilter.hpp" +#include "OrientationAnalysis/OrientationAnalysis_test_dirs.hpp" + +using namespace nx::core; + +TEST_CASE("OrientationAnalysis::EMsoftSO3SamplerFilter: Valid Filter Execution", "[OrientationAnalysis][EMsoftSO3SamplerFilter][.][UNIMPLEMENTED][!mayfail]") +{ + // Instantiate the filter, a DataStructure object and an Arguments Object + EMsoftSO3SamplerFilter filter; + DataStructure ds; + Arguments args; + + // Create default Parameters for the filter. + args.insertOrAssign(EMsoftSO3SamplerFilter::k_CrystalStructure_Index, std::make_any(1)); + args.insertOrAssign(EMsoftSO3SamplerFilter::k_OffsetGrid_Key, std::make_any(false)); + args.insertOrAssign(EMsoftSO3SamplerFilter::k_Mode1Misorientation_Key, std::make_any(2.3456789)); + args.insertOrAssign(EMsoftSO3SamplerFilter::k_Mode1EulerAngle_Key, std::make_any(std::vector(3))); + args.insertOrAssign(EMsoftSO3SamplerFilter::k_Mode2Misorientation_Key, std::make_any(2.3456789)); + args.insertOrAssign(EMsoftSO3SamplerFilter::k_Mode2EulerAngle_Key, std::make_any(std::vector(3))); + args.insertOrAssign(EMsoftSO3SamplerFilter::k_NumberSamples_Key, std::make_any(1234356)); + args.insertOrAssign(EMsoftSO3SamplerFilter::k_EulerAnglesArrayPath_Key, std::make_any(DataPath{})); + + // Preflight the filter and check result + auto preflightResult = filter.preflight(ds, args); + REQUIRE(preflightResult.outputActions.valid()); + + // Execute the filter and check the result + auto executeResult = filter.execute(ds, args); + REQUIRE(executeResult.result.valid()); +} + +// TEST_CASE("OrientationAnalysis::EMsoftSO3SamplerFilter: InValid Filter Execution") +//{ +// +// }