From dce2df9534a150c042f90f476b33d3845fe75109 Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Thu, 22 Jun 2023 10:59:01 -0400 Subject: [PATCH] FIlter complete - unit test pending --- .../docs/MergeColoniesFilter.md | 69 ++++++++++++++++ .../Filters/Algorithms/MergeColonies.cpp | 8 +- .../Filters/Algorithms/MergeColonies.hpp | 1 + .../Filters/MergeColoniesFilter.cpp | 82 ++++++++++++++----- .../Filters/MergeColoniesFilter.hpp | 2 + .../test/MergeColoniesTest.cpp | 15 +--- 6 files changed, 142 insertions(+), 35 deletions(-) create mode 100644 src/Plugins/OrientationAnalysis/docs/MergeColoniesFilter.md diff --git a/src/Plugins/OrientationAnalysis/docs/MergeColoniesFilter.md b/src/Plugins/OrientationAnalysis/docs/MergeColoniesFilter.md new file mode 100644 index 0000000000..08d5eb84d1 --- /dev/null +++ b/src/Plugins/OrientationAnalysis/docs/MergeColoniesFilter.md @@ -0,0 +1,69 @@ +# Merge Colonies # + +## Group (Subgroup) ## + +Reconstruction (Grouping) + +## Description ## + +This **Filter** groups neighboring **Features** that have a *special* misorientation that is associated with *alpha* variants that transformed from the same *beta* grain in titanium. The algorithm for grouping the **Features** is analogous to the algorithm for segmenting the **Features**, except the average orientation of the **Features** are used instead of the orientations of the individual **Elements** and the criterion for grouping is specific to the *alpha-beta transformation*. The user can specify a tolerance on both the *axis* and the *angle* that defines the misorientation relationship (i.e., a tolerance of 1 degree for both tolerances would allow the neighboring **Features** to be grouped if their misorientation was between 59-61 degrees about an axis within 1 degree of a2, as given by the 3rd *special* misorientation below). + +The list of *special* misorientations can be found in the paper by Germain et al.1 and are listed here: + +| Angle | Axis | +|------|------| +| 0 | Identity | +| 10.529 | c = <0001> | +| 60 | a2 = <-12-10> | +| 60.832 | d1 at 80.97 degrees from c in the plane of (d3,c) | +| 63.262 | d2 at 72.73 degrees from c in the plane of (a2,c) | +| 90 | d3 at 5.26 degrees from a2 in the basal plane | + +## Parameters ## + +| Name | Type | Description | +|------|------| ----------- | +| Use Seed | bool | Whether a seed shouold be used for random generation | +| Seed | uint64 | This is the value fed into the random generator | +| Axis Tolerance (Degrees) | float32 | Tolerance allowed when comparing the axis part of the axis-angle representation of the misorientation to the *special* misorientations listed above | +| Angle Tolerance (Degrees) | float32 | Tolerance allowed when comparing the angle part of the axis-angle representation of the misorientation to the *special* misorientations listed above | +| Use Non-Contiguous Neighbors | bool | Whether to use a non-contiguous neighbor list during the merging process | + +## Required Geometry ## + +Not Applicable + +## Required Objects ## + +| Kind | Default Name | Type | Component Dimensions | Description | +|------|--------------|------|----------------------|-------------| +| **Feature Attribute Array** | NonContiguousNeighbors | Int32NeighborList | (1) | List of non-contiguous neighbors for each **Feature**. Only needed if *Use Non-Contiguous Neighbors* is checked | +| **Feature Attribute Array** | NeighborList | Int32NeighborList | (1) | List of neighbors for each **Feature** | +| **Element Attribute Array** | FeatureIds | int32 | (1) | Specifies to which **Feature** each **Element** belongs | +| **Element Attribute Array** | Phases | int32 | (1) | Specifies to which **Ensemble** each **Element** belongs | +| **Feature Attribute Array** | Phases | int32 | (1) | Specifies to which **Ensemble** each **Feature** belongs | +| **Feature Attribute Array** | AvgQuats | float32 | (4) | Specifies the average orientation of the **Feature** in quaternion representation | +| **Ensemble Attribute Array** | CrystalStructures | uint32 | (1) | Enumeration representing the crystal structure for each **Ensemble** | + +## Created Objects ## + +| Kind | Default Name | Type | Component Dimensions | Description | +|------|--------------|------|----------------------|-------------| +| **Element Attribute Array** | ParentIds | int32 | (1) | Specifies to which *parent* each **Element** belongs | +| **Attribute Matrix** | NewFeatureData | Feature | N/A | Created **Feature Attribute Matrix** name | +| **Feature Attribute Array** | ParentIds | int32 | (1) | Specifies to which *parent* each **Feature** belongs | +| **Feature Attribute Array** | Active | bool | (1) | Specifies if the **Feature** is still in the sample (*true* if the **Feature** is in the sample and *false* if it is not). At the end of the **Filter**, all **Features** will be *Active* | + +## References ## + +[1] L. Germain, N. Gey and M. Humbert, Reliability of reconstructed Beta orientation maps in titanium alloys, Ultramicrscopy, 2007, 1129-1135. + +## Example Pipelines ## + +## License & Copyright ## + +Please see the description file distributed with this **Plugin** + +## DREAM.3D Mailing Lists ## + +If you need more help with a **Filter**, please consider asking your question on the [DREAM.3D Users Google group!](https://groups.google.com/forum/?hl=en#!forum/dream3d-users) diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp index 10aa3cd0dc..e9149cbefc 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp @@ -195,8 +195,7 @@ Result<> MergeColonies::operator()() // Generate all the numbers up front const int32 rangeMin = 1; const int32 rangeMax = numParents - 1; - std::mt19937::result_type seed = static_cast(std::chrono::steady_clock::now().time_since_epoch().count()); - std::mt19937 generator(seed); // Standard mersenne_twister_engine seeded with milliseconds + std::mt19937 generator(m_InputValues->SeedValue); // Standard mersenne_twister_engine seeded std::uniform_int_distribution distribution(rangeMin, rangeMax); std::vector pid(numParents); @@ -245,7 +244,8 @@ int32 MergeColonies::getSeed(int32 newFid) { usize numFeatures = m_FeaturePhases.getNumberOfTuples(); - SIMPL_RANDOMNG_NEW(); + std::mt19937 generator(m_InputValues->SeedValue); // Standard mersenne_twister_engine seeded + std::uniform_real_distribution distribution(0, 1); int32 seed = -1; int32 randFeature = 0; @@ -253,7 +253,7 @@ int32 MergeColonies::getSeed(int32 newFid) usize totalFMinus1 = numFeatures - 1; usize counter = 0; - randFeature = int32(float32(rg.genrand_res53()) * float32(totalFMinus1)); + randFeature = int32(distribution(generator) * float32(totalFMinus1)); while(seed == -1 && counter < numFeatures) { if(randFeature > totalFMinus1) diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp index d44fab7986..24046d85ae 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp @@ -29,6 +29,7 @@ struct ORIENTATIONANALYSIS_EXPORT MergeColoniesInputValues DataPath CellFeatureAMPath; DataPath FeatureParentIdsPath; DataPath ActivePath; + uint64 SeedValue; bool RandomizeParentIds = true; }; diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.cpp index 76ea649d78..2a9014b1a8 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.cpp @@ -3,13 +3,17 @@ #include "OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp" #include "complex/DataStructure/DataPath.hpp" -#include "complex/Filter/Actions/EmptyAction.hpp" -#include "complex/Parameters/ArrayCreationParameter.hpp" +#include "complex/Filter/Actions/CreateArrayAction.hpp" +#include "complex/Filter/Actions/CreateAttributeMatrixAction.hpp" #include "complex/Parameters/ArraySelectionParameter.hpp" #include "complex/Parameters/BoolParameter.hpp" +#include "complex/Parameters/DataGroupCreationParameter.hpp" +#include "complex/Parameters/DataObjectNameParameter.hpp" #include "complex/Parameters/NeighborListSelectionParameter.hpp" #include "complex/Parameters/NumberParameter.hpp" +#include + using namespace complex; namespace complex @@ -50,6 +54,10 @@ Parameters MergeColoniesFilter::parameters() const Parameters params; // Create the parameter descriptors that are needed for this filter + params.insertSeparator(Parameters::Separator{"Optional Variables"}); + params.insertLinkableParameter(std::make_unique(k_UseSeed_Key, "Use Seed for Random Generation", "When true the user will be able to put in a seed for random generation", false)); + params.insert(std::make_unique>(k_SeedValue_Key, "Seed", "The seed fed into the random generator", std::mt19937::default_seed)); + params.insertSeparator(Parameters::Separator{"Input Parameters"}); params.insertLinkableParameter(std::make_unique(k_UseNonContiguousNeighbors_Key, "Use Non-Contiguous Neighbors", "", false)); params.insert(std::make_unique(k_AxisTolerance_Key, "Axis Tolerance (Degrees)", "", 0.0f)); @@ -68,7 +76,7 @@ Parameters MergeColoniesFilter::parameters() const params.insertSeparator(Parameters::Separator{"Required Element Data"}); params.insert(std::make_unique(k_FeatureIdsArrayPath_Key, "Feature Ids", "", DataPath{}, ArraySelectionParameter::AllowedTypes{DataType::int32}, ArraySelectionParameter::AllowedComponentShapes{{1}})); - params.insert(std::make_unique(k_CellPhasesArrayPath_Key, "Phases", "", DataPath{}, ArraySelectionParameter::AllowedTypes{DataType::int32}, + params.insert(std::make_unique(k_CellPhasesArrayPath_Key, "Cell Phases", "", DataPath{}, ArraySelectionParameter::AllowedTypes{DataType::int32}, ArraySelectionParameter::AllowedComponentShapes{{1}})); params.insertSeparator(Parameters::Separator{"Required Ensemble Data"}); @@ -76,15 +84,16 @@ Parameters MergeColoniesFilter::parameters() const ArraySelectionParameter::AllowedComponentShapes{{1}})); params.insertSeparator(Parameters::Separator{"Created Element Data"}); - params.insert(std::make_unique(k_CellParentIdsArrayName_Key, "Parent Ids", "", DataPath{})); + params.insert(std::make_unique(k_CellParentIdsArrayName_Key, "Cell Parent Ids", "", "Cell Parent Ids")); params.insertSeparator(Parameters::Separator{"Created Feature Data"}); - params.insert(std::make_unique(k_NewCellFeatureAttributeMatrixName_Key, "Feature Attribute Matrix", "", DataPath{})); - params.insert(std::make_unique(k_FeatureParentIdsArrayName_Key, "Parent Ids", "", DataPath{})); - params.insert(std::make_unique(k_ActiveArrayName_Key, "Active", "", DataPath{})); + params.insert(std::make_unique(k_NewCellFeatureAttributeMatrixName_Key, "Feature Attribute Matrix", "", DataPath{})); + params.insert(std::make_unique(k_FeatureParentIdsArrayName_Key, "Feature Parent Ids", "", "Feature Parent Ids")); + params.insert(std::make_unique(k_ActiveArrayName_Key, "Active", "", "Active Features")); // Associate the Linkable Parameter(s) to the children parameters that they control params.linkParameters(k_UseNonContiguousNeighbors_Key, k_NonContiguousNeighborListArrayPath_Key, true); + params.linkParameters(k_UseSeed_Key, k_SeedValue_Key, true); return params; } @@ -99,20 +108,48 @@ IFilter::UniquePointer MergeColoniesFilter::clone() const IFilter::PreflightResult MergeColoniesFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const { - auto pFeaturePhasesArrayPathValue = filterArgs.value(k_FeaturePhasesArrayPath_Key); - auto pAvgQuatsArrayPathValue = filterArgs.value(k_AvgQuatsArrayPath_Key); - auto pFeatureIdsArrayPathValue = filterArgs.value(k_FeatureIdsArrayPath_Key); - auto pCellPhasesArrayPathValue = filterArgs.value(k_CellPhasesArrayPath_Key); - auto pCrystalStructuresArrayPathValue = filterArgs.value(k_CrystalStructuresArrayPath_Key); - auto pCellParentIdsArrayNameValue = filterArgs.value(k_CellParentIdsArrayName_Key); - auto pNewCellFeatureAttributeMatrixNameValue = filterArgs.value(k_NewCellFeatureAttributeMatrixName_Key); - auto pFeatureParentIdsArrayNameValue = filterArgs.value(k_FeatureParentIdsArrayName_Key); - auto pActiveArrayNameValue = filterArgs.value(k_ActiveArrayName_Key); + auto pFeaturePhasesPathValue = filterArgs.value(k_FeaturePhasesArrayPath_Key); + auto pAvgQuatsPathValue = filterArgs.value(k_AvgQuatsArrayPath_Key); + auto pFeatureIdsPathValue = filterArgs.value(k_FeatureIdsArrayPath_Key); + auto pCellPhasesPathValue = filterArgs.value(k_CellPhasesArrayPath_Key); + auto pCrystalStructuresPathValue = filterArgs.value(k_CrystalStructuresArrayPath_Key); + auto pCellParentIdsNameValue = filterArgs.value(k_CellParentIdsArrayName_Key); + auto pCellFeatureAMPathValue = filterArgs.value(k_NewCellFeatureAttributeMatrixName_Key); + auto pFeatureParentIdsNameValue = filterArgs.value(k_FeatureParentIdsArrayName_Key); + auto pActiveNameValue = filterArgs.value(k_ActiveArrayName_Key); PreflightResult preflightResult; complex::Result resultOutputActions; std::vector preflightUpdatedValues; + // Create the CreateArray action and add it to the resultOutputActions object + { + auto action = std::make_unique(pCellFeatureAMPathValue, std::vector{0}); + resultOutputActions.value().appendAction(std::move(action)); + } + + // Create the CreateArray action and add it to the resultOutputActions object + { + auto action = std::make_unique(DataType::boolean, std::vector{0}, std::vector{1}, pCellFeatureAMPathValue.createChildPath(pActiveNameValue)); + resultOutputActions.value().appendAction(std::move(action)); + } + + // Create the CreateArray action and add it to the resultOutputActions object + { + std::vector tupDims = dataStructure.getDataAs(pFeaturePhasesPathValue)->getTupleShape(); + DataPath featureParentIdsPath = pFeaturePhasesPathValue.getParent().createChildPath(pFeatureParentIdsNameValue); + auto action = std::make_unique(DataType::int32, tupDims, std::vector{1}, featureParentIdsPath); + resultOutputActions.value().appendAction(std::move(action)); + } + + // Create the CreateArray action and add it to the resultOutputActions object + { + std::vector tupDims = dataStructure.getDataAs(pFeatureIdsPathValue)->getTupleShape(); + DataPath cellParentIdsPath = pFeatureIdsPathValue.getParent().createChildPath(pCellParentIdsNameValue); + auto action = std::make_unique(DataType::int32, tupDims, std::vector{1}, cellParentIdsPath); + resultOutputActions.value().appendAction(std::move(action)); + } + // Return both the resultOutputActions and the preflightUpdatedValues via std::move() return {std::move(resultOutputActions), std::move(preflightUpdatedValues)}; } @@ -123,6 +160,13 @@ Result<> MergeColoniesFilter::executeImpl(DataStructure& dataStructure, const Ar { MergeColoniesInputValues inputValues; + auto seed = filterArgs.value(k_SeedValue_Key); + if(!filterArgs.value(k_UseSeed_Key)) + { + seed = static_cast(std::chrono::steady_clock::now().time_since_epoch().count()); + } + + inputValues.SeedValue = seed; inputValues.AxisTolerance = filterArgs.value(k_AxisTolerance_Key); inputValues.AngleTolerance = filterArgs.value(k_AngleTolerance_Key); inputValues.FeaturePhasesPath = filterArgs.value(k_FeaturePhasesArrayPath_Key); @@ -130,10 +174,10 @@ Result<> MergeColoniesFilter::executeImpl(DataStructure& dataStructure, const Ar inputValues.FeatureIdsPath = filterArgs.value(k_FeatureIdsArrayPath_Key); inputValues.CellPhasesPath = filterArgs.value(k_CellPhasesArrayPath_Key); inputValues.CrystalStructuresPath = filterArgs.value(k_CrystalStructuresArrayPath_Key); - inputValues.CellParentIdsPath = filterArgs.value(k_CellParentIdsArrayName_Key); + inputValues.CellParentIdsPath = inputValues.FeatureIdsPath.getParent().createChildPath(filterArgs.value(k_CellParentIdsArrayName_Key)); inputValues.CellFeatureAMPath = filterArgs.value(k_NewCellFeatureAttributeMatrixName_Key); - inputValues.FeatureParentIdsPath = filterArgs.value(k_FeatureParentIdsArrayName_Key); - inputValues.ActivePath = filterArgs.value(k_ActiveArrayName_Key); + inputValues.FeatureParentIdsPath = inputValues.FeaturePhasesPath.getParent().createChildPath(filterArgs.value(k_FeatureParentIdsArrayName_Key)); + inputValues.ActivePath = inputValues.CellFeatureAMPath.createChildPath(filterArgs.value(k_ActiveArrayName_Key)); GroupFeaturesInputValues gpInputValues; diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.hpp index 5bca7600ca..4631dfbb6c 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.hpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.hpp @@ -38,6 +38,8 @@ class ORIENTATIONANALYSIS_EXPORT MergeColoniesFilter : public IFilter static inline constexpr StringLiteral k_NewCellFeatureAttributeMatrixName_Key = "new_cell_feature_attribute_matrix_name"; static inline constexpr StringLiteral k_FeatureParentIdsArrayName_Key = "feature_parent_ids_array_name"; static inline constexpr StringLiteral k_ActiveArrayName_Key = "active_array_name"; + static inline constexpr StringLiteral k_UseSeed_Key = "use_seed"; + static inline constexpr StringLiteral k_SeedValue_Key = "seed_value"; /** * @brief Returns the name of the filter. diff --git a/src/Plugins/OrientationAnalysis/test/MergeColoniesTest.cpp b/src/Plugins/OrientationAnalysis/test/MergeColoniesTest.cpp index f8f6790700..8d03c7edbb 100644 --- a/src/Plugins/OrientationAnalysis/test/MergeColoniesTest.cpp +++ b/src/Plugins/OrientationAnalysis/test/MergeColoniesTest.cpp @@ -1,16 +1,14 @@ #include #include "complex/Parameters/ArrayCreationParameter.hpp" -#include "complex/Parameters/ArraySelectionParameter.hpp" #include "complex/Parameters/BoolParameter.hpp" -#include "complex/Parameters/NumberParameter.hpp" -#include "ComplexCore/ComplexCore_test_dirs.hpp" -#include "ComplexCore/Filters/MergeColoniesFilter.hpp" +#include "OrientationAnalysis/Filters/MergeColoniesFilter.hpp" +#include "OrientationAnalysis/OrientationAnalysis_test_dirs.hpp" using namespace complex; -TEST_CASE("ComplexCore::MergeColoniesFilter: Valid Filter Execution", "[ComplexCore][MergeColoniesFilter][.][UNIMPLEMENTED][!mayfail]") +TEST_CASE("OrientationAnalysis::MergeColoniesFilter: Valid Filter Execution", "[ComplexCore][MergeColoniesFilter]") { // Instantiate the filter, a DataStructure object and an Arguments Object MergeColoniesFilter filter; @@ -23,14 +21,12 @@ TEST_CASE("ComplexCore::MergeColoniesFilter: Valid Filter Execution", "[ComplexC args.insertOrAssign(MergeColoniesFilter::k_ContiguousNeighborListArrayPath_Key, std::make_any(DataPath{})); args.insertOrAssign(MergeColoniesFilter::k_AxisTolerance_Key, std::make_any(1.23345f)); args.insertOrAssign(MergeColoniesFilter::k_AngleTolerance_Key, std::make_any(1.23345f)); - args.insertOrAssign(MergeColoniesFilter::k_IdentifyGlobAlpha_Key, std::make_any(false)); args.insertOrAssign(MergeColoniesFilter::k_FeaturePhasesArrayPath_Key, std::make_any(DataPath{})); args.insertOrAssign(MergeColoniesFilter::k_AvgQuatsArrayPath_Key, std::make_any(DataPath{})); args.insertOrAssign(MergeColoniesFilter::k_FeatureIdsArrayPath_Key, std::make_any(DataPath{})); args.insertOrAssign(MergeColoniesFilter::k_CellPhasesArrayPath_Key, std::make_any(DataPath{})); args.insertOrAssign(MergeColoniesFilter::k_CrystalStructuresArrayPath_Key, std::make_any(DataPath{})); args.insertOrAssign(MergeColoniesFilter::k_CellParentIdsArrayName_Key, std::make_any(DataPath{})); - args.insertOrAssign(MergeColoniesFilter::k_GlobAlphaArrayName_Key, std::make_any(DataPath{})); args.insertOrAssign(MergeColoniesFilter::k_NewCellFeatureAttributeMatrixName_Key, std::make_any(DataPath{})); args.insertOrAssign(MergeColoniesFilter::k_FeatureParentIdsArrayName_Key, std::make_any(DataPath{})); args.insertOrAssign(MergeColoniesFilter::k_ActiveArrayName_Key, std::make_any(DataPath{})); @@ -43,8 +39,3 @@ TEST_CASE("ComplexCore::MergeColoniesFilter: Valid Filter Execution", "[ComplexC auto executeResult = filter.execute(ds, args); REQUIRE(executeResult.result.valid()); } - -// TEST_CASE("ComplexCore::MergeColoniesFilter: InValid Filter Execution") -//{ -// -// }