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")
-//{
-//
-// }