From f01fa17b38b595ff0d6a769fa1c021fc9f9b1661 Mon Sep 17 00:00:00 2001 From: Joey Kleingers Date: Wed, 5 Jul 2023 13:21:55 -0400 Subject: [PATCH 1/8] Update ApplyTransformationToGeometry.cpp --- .../ApplyTransformationToGeometry.cpp | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/ApplyTransformationToGeometry.cpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/ApplyTransformationToGeometry.cpp index f9a7856302..eeb6561967 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/ApplyTransformationToGeometry.cpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/ApplyTransformationToGeometry.cpp @@ -148,6 +148,20 @@ Result<> ApplyTransformationToGeometry::operator()() return MakeErrorResult(-84500, fmt::format("Keeping the original geometry is not supported.")); } + auto* imageGeometryPtr = m_DataStructure.getDataAs(m_InputValues->SelectedGeometryPath); + const bool isNodeBased = (imageGeometryPtr == nullptr); + + ImageRotationUtilities::Matrix4fR translationToGlobalOriginMat = ImageRotationUtilities::Matrix4fR::Identity(); + ImageRotationUtilities::Matrix4fR translationFromGlobalOriginMat = ImageRotationUtilities::Matrix4fR::Identity(); + if(isNodeBased) + { + auto& nodeGeometry0D = m_DataStructure.getDataRefAs(m_InputValues->SelectedGeometryPath); + auto boundingBox = nodeGeometry0D.getBoundingBox(); + Point3Df minPoint = boundingBox.getMinPoint(); + translationToGlobalOriginMat = ImageRotationUtilities::GenerateTranslationTransformationMatrix({-minPoint[0], -minPoint[1], -minPoint[2]}); + translationFromGlobalOriginMat = ImageRotationUtilities::GenerateTranslationTransformationMatrix({minPoint[0], minPoint[1], minPoint[2]}); + } + switch(m_InputValues->TransformationSelection) { case k_NoTransformIdx: // No-Op @@ -168,6 +182,12 @@ Result<> ApplyTransformationToGeometry::operator()() case k_RotationIdx: // Rotation via axis-angle { m_TransformationMatrix = ImageRotationUtilities::GenerateRotationTransformationMatrix(m_InputValues->Rotation); + if(isNodeBased) + { + // Translate the geometry to/from the global origin + m_TransformationMatrix = translationFromGlobalOriginMat * m_TransformationMatrix * translationToGlobalOriginMat; + } + break; } case k_TranslationIdx: // Translation @@ -178,6 +198,11 @@ Result<> ApplyTransformationToGeometry::operator()() case k_ScaleIdx: // Scale { m_TransformationMatrix = ImageRotationUtilities::GenerateScaleTransformationMatrix(m_InputValues->Scale); + if(isNodeBased) + { + // Translate the geometry to/from the global origin + m_TransformationMatrix = translationFromGlobalOriginMat * m_TransformationMatrix * translationToGlobalOriginMat; + } break; } } From 1d406e0134dff09da3283bebdbd162a3a4a9e31e Mon Sep 17 00:00:00 2001 From: Nathan Young Date: Tue, 20 Jun 2023 10:07:00 -0400 Subject: [PATCH 2/8] Update ComplexCoreLegacyUUIDMapping.hpp, MergeColonies.cpp, MergeColonies.hpp, and 3 more files --- .../ComplexCoreLegacyUUIDMapping.hpp | 2 + .../Filters/Algorithms/MergeColonies.cpp | 48 +++++ .../Filters/Algorithms/MergeColonies.hpp | 100 +++++++++ .../Filters/MergeColoniesFilter.cpp | 198 ++++++++++++++++++ .../Filters/MergeColoniesFilter.hpp | 112 ++++++++++ .../ComplexCore/test/MergeColoniesTest.cpp | 74 +++++++ 6 files changed, 534 insertions(+) create mode 100644 src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp create mode 100644 src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.hpp create mode 100644 src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.cpp create mode 100644 src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.hpp create mode 100644 src/Plugins/ComplexCore/test/MergeColoniesTest.cpp diff --git a/src/Plugins/ComplexCore/src/ComplexCore/ComplexCoreLegacyUUIDMapping.hpp b/src/Plugins/ComplexCore/src/ComplexCore/ComplexCoreLegacyUUIDMapping.hpp index 73f387c2b3..c3829fb38d 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/ComplexCoreLegacyUUIDMapping.hpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/ComplexCoreLegacyUUIDMapping.hpp @@ -114,6 +114,7 @@ #include "ComplexCore/Filters/KMedoidsFilter.hpp" #include "ComplexCore/Filters/KMeansFilter.hpp" #include "ComplexCore/Filters/SilhouetteFilter.hpp" +#include "ComplexCore/Filters/MergeColoniesFilter.hpp" // @@__HEADER__TOKEN__DO__NOT__DELETE__@@ namespace complex @@ -237,6 +238,7 @@ namespace complex {complex::Uuid::FromString("f7486aa6-3049-5be7-8511-ae772b70c90b").value(), complex::FilterTraits::uuid}, // KMedoids {complex::Uuid::FromString("b56a04de-0ca0-509d-809f-52219fca9c98").value(), complex::FilterTraits::uuid}, // KMeans {complex::Uuid::FromString("f84d4d69-9ea5-54b6-a71c-df76d76d50cf").value(), complex::FilterTraits::uuid}, // Silhouette + {complex::Uuid::FromString("2c4a6d83-6a1b-56d8-9f65-9453b28845b9").value(), complex::FilterTraits::uuid}, // MergeColonies // @@__MAP__UPDATE__TOKEN__DO__NOT__DELETE__@@ }; diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp new file mode 100644 index 0000000000..bf8a1fbe00 --- /dev/null +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp @@ -0,0 +1,48 @@ +#include "MergeColonies.hpp" + +#include "complex/DataStructure/DataArray.hpp" +#include "complex/DataStructure/DataGroup.hpp" + +using namespace complex; + +// ----------------------------------------------------------------------------- +MergeColonies::MergeColonies(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MergeColoniesInputValues* inputValues) +: m_DataStructure(dataStructure) +, m_InputValues(inputValues) +, m_ShouldCancel(shouldCancel) +, m_MessageHandler(mesgHandler) +{ +} + +// ----------------------------------------------------------------------------- +MergeColonies::~MergeColonies() noexcept = default; + +// ----------------------------------------------------------------------------- +const std::atomic_bool& MergeColonies::getCancel() +{ + return m_ShouldCancel; +} + +// ----------------------------------------------------------------------------- +Result<> MergeColonies::operator()() +{ + /** + * This section of the code should contain the actual algorithmic codes that + * will accomplish the goal of the file. + * + * If you can parallelize the code there are a number of examples on how to do that. + * GenerateIPFColors is one example + * + * If you need to determine what kind of array you have (Int32Array, Float32Array, etc) + * look to the ExecuteDataFunction() in complex/Utilities/FilterUtilities.hpp template + * function to help with that code. + * An Example algorithm class is `CombineAttributeArrays` and `RemoveFlaggedVertices` + * + * There are other utility classes that can help alleviate the amount of code that needs + * to be written. + * + * REMOVE THIS COMMENT BLOCK WHEN YOU ARE FINISHED WITH THE FILTER_HUMAN_NAME + */ + + return {}; +} diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.hpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.hpp new file mode 100644 index 0000000000..f3105bfcde --- /dev/null +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.hpp @@ -0,0 +1,100 @@ +#pragma once + +#include "ComplexCore/ComplexCore_export.hpp" + +#include "complex/DataStructure/DataPath.hpp" +#include "complex/DataStructure/DataStructure.hpp" +#include "complex/Filter/IFilter.hpp" +#include "complex/Parameters/ArraySelectionParameter.hpp" +#include "complex/Parameters/ArraySelectionParameter.hpp" +#include "complex/Parameters/NumberParameter.hpp" +#include "complex/Parameters/NumberParameter.hpp" +#include "complex/Parameters/ArraySelectionParameter.hpp" +#include "complex/Parameters/ArraySelectionParameter.hpp" +#include "complex/Parameters/ArraySelectionParameter.hpp" +#include "complex/Parameters/ArraySelectionParameter.hpp" +#include "complex/Parameters/ArraySelectionParameter.hpp" +#include "complex/Parameters/ArrayCreationParameter.hpp" +#include "complex/Parameters/ArrayCreationParameter.hpp" +#include "complex/Parameters/ArrayCreationParameter.hpp" +#include "complex/Parameters/ArrayCreationParameter.hpp" +#include "complex/Parameters/ArrayCreationParameter.hpp" + + +/** +* This is example code to put in the Execute Method of the filter. + MergeColoniesInputValues inputValues; + + inputValues.UseNonContiguousNeighbors = filterArgs.value(k_UseNonContiguousNeighbors_Key); + inputValues.NonContiguousNeighborListArrayPath = filterArgs.value(k_NonContiguousNeighborListArrayPath_Key); + inputValues.ContiguousNeighborListArrayPath = filterArgs.value(k_ContiguousNeighborListArrayPath_Key); + inputValues.AxisTolerance = filterArgs.value(k_AxisTolerance_Key); + inputValues.AngleTolerance = filterArgs.value(k_AngleTolerance_Key); + inputValues.IdentifyGlobAlpha = filterArgs.value(k_IdentifyGlobAlpha_Key); + inputValues.FeaturePhasesArrayPath = filterArgs.value(k_FeaturePhasesArrayPath_Key); + inputValues.AvgQuatsArrayPath = filterArgs.value(k_AvgQuatsArrayPath_Key); + inputValues.FeatureIdsArrayPath = filterArgs.value(k_FeatureIdsArrayPath_Key); + inputValues.CellPhasesArrayPath = filterArgs.value(k_CellPhasesArrayPath_Key); + inputValues.CrystalStructuresArrayPath = filterArgs.value(k_CrystalStructuresArrayPath_Key); + inputValues.CellParentIdsArrayName = filterArgs.value(k_CellParentIdsArrayName_Key); + inputValues.GlobAlphaArrayName = filterArgs.value(k_GlobAlphaArrayName_Key); + inputValues.NewCellFeatureAttributeMatrixName = filterArgs.value(k_NewCellFeatureAttributeMatrixName_Key); + inputValues.FeatureParentIdsArrayName = filterArgs.value(k_FeatureParentIdsArrayName_Key); + inputValues.ActiveArrayName = filterArgs.value(k_ActiveArrayName_Key); + + return MergeColonies(dataStructure, messageHandler, shouldCancel, &inputValues)(); +*/ + +namespace complex +{ + +struct COMPLEXCORE_EXPORT MergeColoniesInputValues +{ + bool UseNonContiguousNeighbors; + DataPath NonContiguousNeighborListArrayPath; + DataPath ContiguousNeighborListArrayPath; + float32 AxisTolerance; + float32 AngleTolerance; + bool IdentifyGlobAlpha; + DataPath FeaturePhasesArrayPath; + DataPath AvgQuatsArrayPath; + DataPath FeatureIdsArrayPath; + DataPath CellPhasesArrayPath; + DataPath CrystalStructuresArrayPath; + DataPath CellParentIdsArrayName; + DataPath GlobAlphaArrayName; + DataPath NewCellFeatureAttributeMatrixName; + DataPath FeatureParentIdsArrayName; + DataPath ActiveArrayName; + +}; + +/** + * @class ConditionalSetValue + * @brief This filter replaces values in the target array with a user specified value + * where a bool mask array specifies. + */ + +class COMPLEXCORE_EXPORT MergeColonies +{ +public: + MergeColonies(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MergeColoniesInputValues* inputValues); + ~MergeColonies() noexcept; + + MergeColonies(const MergeColonies&) = delete; + MergeColonies(MergeColonies&&) noexcept = delete; + MergeColonies& operator=(const MergeColonies&) = delete; + MergeColonies& operator=(MergeColonies&&) noexcept = delete; + + Result<> operator()(); + + const std::atomic_bool& getCancel(); + +private: + DataStructure& m_DataStructure; + const MergeColoniesInputValues* m_InputValues = nullptr; + const std::atomic_bool& m_ShouldCancel; + const IFilter::MessageHandler& m_MessageHandler; +}; + +} // namespace complex diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.cpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.cpp new file mode 100644 index 0000000000..5bd771b773 --- /dev/null +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.cpp @@ -0,0 +1,198 @@ +#include "MergeColoniesFilter.hpp" + +#include "ComplexCore/Filters/Algorithms/MergeColonies.hpp" + +#include "complex/DataStructure/DataPath.hpp" +#include "complex/Filter/Actions/EmptyAction.hpp" +#include "complex/Parameters/BoolParameter.hpp" +#include "complex/Parameters/ArraySelectionParameter.hpp" +#include "complex/Parameters/NumberParameter.hpp" +#include "complex/Parameters/ArrayCreationParameter.hpp" + +using namespace complex; + +namespace complex +{ +//------------------------------------------------------------------------------ +std::string MergeColoniesFilter::name() const +{ + return FilterTraits::name.str(); +} + +//------------------------------------------------------------------------------ +std::string MergeColoniesFilter::className() const +{ + return FilterTraits::className; +} + +//------------------------------------------------------------------------------ +Uuid MergeColoniesFilter::uuid() const +{ + return FilterTraits::uuid; +} + +//------------------------------------------------------------------------------ +std::string MergeColoniesFilter::humanName() const +{ + return "Merge Colonies"; +} + +//------------------------------------------------------------------------------ +std::vector MergeColoniesFilter::defaultTags() const +{ + return {"Reconstruction", "Grouping"}; +} + +//------------------------------------------------------------------------------ +Parameters MergeColoniesFilter::parameters() const +{ + Parameters params; + + /** + * Please separate the parameters into groups generally of the following: + * + * params.insertSeparator(Parameters::Separator{"Input Parameters"}); + * params.insertSeparator(Parameters::Separator{"Required Input Cell Data"}); + * params.insertSeparator(Parameters::Separator{"Required Input Feature Data"}); + * params.insertSeparator(Parameters::Separator{"Created Cell Data"}); + * params.insertSeparator(Parameters::Separator{"Created Cell Feature Data"}); + * + * .. or create appropriate separators as needed. The UI in COMPLEX no longer + * does this for the developer by using catgories as in SIMPL + */ + + // Create the parameter descriptors that are needed for this filter + params.insertLinkableParameter(std::make_unique(k_UseNonContiguousNeighbors_Key, "Use Non-Contiguous Neighbors", "", false #error Check default values)); + params.insertSeparator(Parameters::Separator{"Feature Data"}); + params.insert(std::make_unique(k_NonContiguousNeighborListArrayPath_Key, "Non-Contiguous Neighbor List", "", DataPath{}, complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); + params.insert(std::make_unique(k_ContiguousNeighborListArrayPath_Key, "Contiguous Neighbor List", "", DataPath{}, complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); + params.insert(std::make_unique(k_AxisTolerance_Key, "Axis Tolerance (Degrees)", "", 0.0f #error Check default values)); + params.insert(std::make_unique(k_AngleTolerance_Key, "Angle Tolerance (Degrees)", "", 0.0f #error Check default values)); + params.insertLinkableParameter(std::make_unique(k_IdentifyGlobAlpha_Key, "Identify Glob Alpha", "", false #error Check default values)); + params.insert(std::make_unique(k_FeaturePhasesArrayPath_Key, "Feature Phases", "", DataPath{}, complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); + params.insert(std::make_unique(k_AvgQuatsArrayPath_Key, "Average Quaternions", "", DataPath{}, complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); + params.insertSeparator(Parameters::Separator{"Element Data"}); + params.insert(std::make_unique(k_FeatureIdsArrayPath_Key, "Feature Ids", "", DataPath{}, complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); + params.insert(std::make_unique(k_CellPhasesArrayPath_Key, "Phases", "", DataPath{}, complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); + params.insertSeparator(Parameters::Separator{"Ensemble Data"}); + params.insert(std::make_unique(k_CrystalStructuresArrayPath_Key, "Crystal Structures", "", DataPath{}, complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); + params.insertSeparator(Parameters::Separator{"Element Data"}); + params.insert(std::make_unique(k_CellParentIdsArrayName_Key, "Parent Ids", "", DataPath{})); + params.insert(std::make_unique(k_GlobAlphaArrayName_Key, "Glob Alpha", "", DataPath{})); + params.insertSeparator(Parameters::Separator{"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{})); + // Associate the Linkable Parameter(s) to the children parameters that they control + params.linkParameters(k_UseNonContiguousNeighbors_Key, k_NonContiguousNeighborListArrayPath_Key, true); + params.linkParameters(k_IdentifyGlobAlpha_Key, k_GlobAlphaArrayName_Key, true); + + return params; +} + +//------------------------------------------------------------------------------ +IFilter::UniquePointer MergeColoniesFilter::clone() const +{ + return std::make_unique(); +} + +//------------------------------------------------------------------------------ +IFilter::PreflightResult MergeColoniesFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const +{ + /**************************************************************************** + * Write any preflight sanity checking codes in this function + ***************************************************************************/ + + /** + * These are the values that were gathered from the UI or the pipeline file or + * otherwise passed into the filter. These are here for your convenience. If you + * do not need some of them remove them. + */ + auto pUseNonContiguousNeighborsValue = filterArgs.value(k_UseNonContiguousNeighbors_Key); + auto pNonContiguousNeighborListArrayPathValue = filterArgs.value(k_NonContiguousNeighborListArrayPath_Key); + auto pContiguousNeighborListArrayPathValue = filterArgs.value(k_ContiguousNeighborListArrayPath_Key); + auto pAxisToleranceValue = filterArgs.value(k_AxisTolerance_Key); + auto pAngleToleranceValue = filterArgs.value(k_AngleTolerance_Key); + auto pIdentifyGlobAlphaValue = filterArgs.value(k_IdentifyGlobAlpha_Key); + 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 pGlobAlphaArrayNameValue = filterArgs.value(k_GlobAlphaArrayName_Key); + auto pNewCellFeatureAttributeMatrixNameValue = filterArgs.value(k_NewCellFeatureAttributeMatrixName_Key); + auto pFeatureParentIdsArrayNameValue = filterArgs.value(k_FeatureParentIdsArrayName_Key); + auto pActiveArrayNameValue = filterArgs.value(k_ActiveArrayName_Key); + + + + // Declare the preflightResult variable that will be populated with the results + // of the preflight. The PreflightResult type contains the output Actions and + // any preflight updated values that you want to be displayed to the user, typically + // through a user interface (UI). + PreflightResult preflightResult; + + // If your filter is making structural changes to the DataStructure then the filter + // is going to create OutputActions subclasses that need to be returned. This will + // store those actions. + complex::Result resultOutputActions; + + // If your filter is going to pass back some `preflight updated values` then this is where you + // would create the code to store those values in the appropriate object. Note that we + // in line creating the pair (NOT a std::pair<>) of Key:Value that will get stored in + // the std::vector object. + std::vector preflightUpdatedValues; + + // If the filter needs to pass back some updated values via a key:value string:string set of values + // you can declare and update that string here. + // None found in this filter based on the filter parameters + + // If this filter makes changes to the DataStructure in the form of + // creating/deleting/moving/renaming DataGroups, Geometries, DataArrays then you + // will need to use one of the `*Actions` classes located in complex/Filter/Actions + // to relay that information to the preflight and execute methods. This is done by + // creating an instance of the Action class and then storing it in the resultOutputActions variable. + // This is done through a `push_back()` method combined with a `std::move()`. For the + // newly initiated to `std::move` once that code is executed what was once inside the Action class + // instance variable is *no longer there*. The memory has been moved. If you try to access that + // variable after this line you will probably get a crash or have subtle bugs. To ensure that this + // does not happen we suggest using braces `{}` to scope each of the action's declaration and store + // so that the programmer is not tempted to use the action instance past where it should be used. + // You have to create your own Actions class if there isn't something specific for your filter's needs + + // Store the preflight updated value(s) into the preflightUpdatedValues vector using + // the appropriate methods. + // None found based on the filter parameters + + // Return both the resultOutputActions and the preflightUpdatedValues via std::move() + return {std::move(resultOutputActions), std::move(preflightUpdatedValues)}; +} + +//------------------------------------------------------------------------------ +Result<> MergeColoniesFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const +{ + + MergeColoniesInputValues inputValues; + + inputValues.UseNonContiguousNeighbors = filterArgs.value(k_UseNonContiguousNeighbors_Key); + inputValues.NonContiguousNeighborListArrayPath = filterArgs.value(k_NonContiguousNeighborListArrayPath_Key); + inputValues.ContiguousNeighborListArrayPath = filterArgs.value(k_ContiguousNeighborListArrayPath_Key); + inputValues.AxisTolerance = filterArgs.value(k_AxisTolerance_Key); + inputValues.AngleTolerance = filterArgs.value(k_AngleTolerance_Key); + inputValues.IdentifyGlobAlpha = filterArgs.value(k_IdentifyGlobAlpha_Key); + inputValues.FeaturePhasesArrayPath = filterArgs.value(k_FeaturePhasesArrayPath_Key); + inputValues.AvgQuatsArrayPath = filterArgs.value(k_AvgQuatsArrayPath_Key); + inputValues.FeatureIdsArrayPath = filterArgs.value(k_FeatureIdsArrayPath_Key); + inputValues.CellPhasesArrayPath = filterArgs.value(k_CellPhasesArrayPath_Key); + inputValues.CrystalStructuresArrayPath = filterArgs.value(k_CrystalStructuresArrayPath_Key); + inputValues.CellParentIdsArrayName = filterArgs.value(k_CellParentIdsArrayName_Key); + inputValues.GlobAlphaArrayName = filterArgs.value(k_GlobAlphaArrayName_Key); + inputValues.NewCellFeatureAttributeMatrixName = filterArgs.value(k_NewCellFeatureAttributeMatrixName_Key); + inputValues.FeatureParentIdsArrayName = filterArgs.value(k_FeatureParentIdsArrayName_Key); + inputValues.ActiveArrayName = filterArgs.value(k_ActiveArrayName_Key); + + + return MergeColonies(dataStructure, messageHandler, shouldCancel, &inputValues)(); +} +} // namespace complex diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.hpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.hpp new file mode 100644 index 0000000000..66491fabe9 --- /dev/null +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.hpp @@ -0,0 +1,112 @@ +#pragma once + +#include "ComplexCore/ComplexCore_export.hpp" + +#include "complex/Filter/FilterTraits.hpp" +#include "complex/Filter/IFilter.hpp" + +namespace complex +{ +/** + * @class MergeColoniesFilter + * @brief This filter will .... + */ +class COMPLEXCORE_EXPORT MergeColoniesFilter : public IFilter +{ +public: + MergeColoniesFilter() = default; + ~MergeColoniesFilter() noexcept override = default; + + MergeColoniesFilter(const MergeColoniesFilter&) = delete; + MergeColoniesFilter(MergeColoniesFilter&&) noexcept = delete; + + MergeColoniesFilter& operator=(const MergeColoniesFilter&) = delete; + MergeColoniesFilter& operator=(MergeColoniesFilter&&) noexcept = delete; + + // Parameter Keys + static inline constexpr StringLiteral k_UseNonContiguousNeighbors_Key = "use_non_contiguous_neighbors"; + static inline constexpr StringLiteral k_NonContiguousNeighborListArrayPath_Key = "non_contiguous_neighbor_list_array_path"; + static inline constexpr StringLiteral k_ContiguousNeighborListArrayPath_Key = "contiguous_neighbor_list_array_path"; + static inline constexpr StringLiteral k_AxisTolerance_Key = "axis_tolerance"; + static inline constexpr StringLiteral k_AngleTolerance_Key = "angle_tolerance"; + static inline constexpr StringLiteral k_IdentifyGlobAlpha_Key = "identify_glob_alpha"; + static inline constexpr StringLiteral k_FeaturePhasesArrayPath_Key = "feature_phases_array_path"; + static inline constexpr StringLiteral k_AvgQuatsArrayPath_Key = "avg_quats_array_path"; + static inline constexpr StringLiteral k_FeatureIdsArrayPath_Key = "feature_ids_array_path"; + static inline constexpr StringLiteral k_CellPhasesArrayPath_Key = "cell_phases_array_path"; + static inline constexpr StringLiteral k_CrystalStructuresArrayPath_Key = "crystal_structures_array_path"; + static inline constexpr StringLiteral k_CellParentIdsArrayName_Key = "cell_parent_ids_array_name"; + static inline constexpr StringLiteral k_GlobAlphaArrayName_Key = "glob_alpha_array_name"; + 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"; + + /** + * @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 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 ds 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 + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + PreflightResult preflightImpl(const DataStructure& ds, const Arguments& filterArgs, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) 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 ds 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 + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + Result<> executeImpl(DataStructure & data, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) + const override; +}; +} // namespace complex + +COMPLEX_DEF_FILTER_TRAITS(complex, MergeColoniesFilter, "7e3dbc15-51a3-482c-97c2-f82f7af685bf"); +/* LEGACY UUID FOR THIS FILTER 2c4a6d83-6a1b-56d8-9f65-9453b28845b9 */ diff --git a/src/Plugins/ComplexCore/test/MergeColoniesTest.cpp b/src/Plugins/ComplexCore/test/MergeColoniesTest.cpp new file mode 100644 index 0000000000..194b9020c0 --- /dev/null +++ b/src/Plugins/ComplexCore/test/MergeColoniesTest.cpp @@ -0,0 +1,74 @@ +/** + * This file is auto generated from the original ComplexCore/MergeColoniesFilter + * 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 "[MergeColoniesFilter][.][UNIMPLEMENTED]" + * from the TEST_CASE macro. This will enable this unit test to be run by default + * and report errors. + */ + + +#include + +#include "complex/Parameters/BoolParameter.hpp" +#include "complex/Parameters/ArraySelectionParameter.hpp" +#include "complex/Parameters/NumberParameter.hpp" +#include "complex/Parameters/ArrayCreationParameter.hpp" + +#include "ComplexCore/Filters/MergeColoniesFilter.hpp" +#include "ComplexCore/ComplexCore_test_dirs.hpp" + +using namespace complex; + +TEST_CASE("ComplexCore::MergeColoniesFilter: Valid Filter Execution","[ComplexCore][MergeColoniesFilter][.][UNIMPLEMENTED][!mayfail]") +{ + // Instantiate the filter, a DataStructure object and an Arguments Object + MergeColoniesFilter filter; + DataStructure ds; + Arguments args; + + // Create default Parameters for the filter. + args.insertOrAssign(MergeColoniesFilter::k_UseNonContiguousNeighbors_Key, std::make_any(false)); + args.insertOrAssign(MergeColoniesFilter::k_NonContiguousNeighborListArrayPath_Key, std::make_any(DataPath{})); + 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{})); + + + // 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("ComplexCore::MergeColoniesFilter: InValid Filter Execution") +//{ +// +//} From f8f27efbc2ae82e525f40663fb3ff0aae9379272 Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Tue, 20 Jun 2023 10:13:25 -0400 Subject: [PATCH 3/8] Update CMakeLists.txt, MergeColonies.cpp, MergeColonies.hpp, and 4 more files --- src/Plugins/ComplexCore/CMakeLists.txt | 2 + .../Filters/Algorithms/MergeColonies.cpp | 18 ----- .../Filters/Algorithms/MergeColonies.hpp | 39 +-------- .../Filters/MergeColoniesFilter.cpp | 80 +++++-------------- .../Filters/MergeColoniesFilter.hpp | 3 +- src/Plugins/ComplexCore/test/CMakeLists.txt | 1 + .../ComplexCore/test/MergeColoniesTest.cpp | 36 ++------- 7 files changed, 32 insertions(+), 147 deletions(-) diff --git a/src/Plugins/ComplexCore/CMakeLists.txt b/src/Plugins/ComplexCore/CMakeLists.txt index 962c09532a..ca6ffc55ca 100644 --- a/src/Plugins/ComplexCore/CMakeLists.txt +++ b/src/Plugins/ComplexCore/CMakeLists.txt @@ -91,6 +91,7 @@ set(FilterList LaplacianSmoothingFilter LosAlamosFFTWriterFilter MapPointCloudToRegularGridFilter + MergeColoniesFilter MinNeighbors MoveData MultiThresholdObjects @@ -178,6 +179,7 @@ set(AlgorithmList KMedoids LaplacianSmoothing LosAlamosFFTWriter + MergeColonies NearestPointFuseRegularGrids PartitionGeometry PointSampleTriangleGeometry diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp index bf8a1fbe00..3ebe41ce3b 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp @@ -26,23 +26,5 @@ const std::atomic_bool& MergeColonies::getCancel() // ----------------------------------------------------------------------------- Result<> MergeColonies::operator()() { - /** - * This section of the code should contain the actual algorithmic codes that - * will accomplish the goal of the file. - * - * If you can parallelize the code there are a number of examples on how to do that. - * GenerateIPFColors is one example - * - * If you need to determine what kind of array you have (Int32Array, Float32Array, etc) - * look to the ExecuteDataFunction() in complex/Utilities/FilterUtilities.hpp template - * function to help with that code. - * An Example algorithm class is `CombineAttributeArrays` and `RemoveFlaggedVertices` - * - * There are other utility classes that can help alleviate the amount of code that needs - * to be written. - * - * REMOVE THIS COMMENT BLOCK WHEN YOU ARE FINISHED WITH THE FILTER_HUMAN_NAME - */ - return {}; } diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.hpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.hpp index f3105bfcde..0df94cce37 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.hpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.hpp @@ -5,45 +5,9 @@ #include "complex/DataStructure/DataPath.hpp" #include "complex/DataStructure/DataStructure.hpp" #include "complex/Filter/IFilter.hpp" +#include "complex/Parameters/ArrayCreationParameter.hpp" #include "complex/Parameters/ArraySelectionParameter.hpp" -#include "complex/Parameters/ArraySelectionParameter.hpp" -#include "complex/Parameters/NumberParameter.hpp" #include "complex/Parameters/NumberParameter.hpp" -#include "complex/Parameters/ArraySelectionParameter.hpp" -#include "complex/Parameters/ArraySelectionParameter.hpp" -#include "complex/Parameters/ArraySelectionParameter.hpp" -#include "complex/Parameters/ArraySelectionParameter.hpp" -#include "complex/Parameters/ArraySelectionParameter.hpp" -#include "complex/Parameters/ArrayCreationParameter.hpp" -#include "complex/Parameters/ArrayCreationParameter.hpp" -#include "complex/Parameters/ArrayCreationParameter.hpp" -#include "complex/Parameters/ArrayCreationParameter.hpp" -#include "complex/Parameters/ArrayCreationParameter.hpp" - - -/** -* This is example code to put in the Execute Method of the filter. - MergeColoniesInputValues inputValues; - - inputValues.UseNonContiguousNeighbors = filterArgs.value(k_UseNonContiguousNeighbors_Key); - inputValues.NonContiguousNeighborListArrayPath = filterArgs.value(k_NonContiguousNeighborListArrayPath_Key); - inputValues.ContiguousNeighborListArrayPath = filterArgs.value(k_ContiguousNeighborListArrayPath_Key); - inputValues.AxisTolerance = filterArgs.value(k_AxisTolerance_Key); - inputValues.AngleTolerance = filterArgs.value(k_AngleTolerance_Key); - inputValues.IdentifyGlobAlpha = filterArgs.value(k_IdentifyGlobAlpha_Key); - inputValues.FeaturePhasesArrayPath = filterArgs.value(k_FeaturePhasesArrayPath_Key); - inputValues.AvgQuatsArrayPath = filterArgs.value(k_AvgQuatsArrayPath_Key); - inputValues.FeatureIdsArrayPath = filterArgs.value(k_FeatureIdsArrayPath_Key); - inputValues.CellPhasesArrayPath = filterArgs.value(k_CellPhasesArrayPath_Key); - inputValues.CrystalStructuresArrayPath = filterArgs.value(k_CrystalStructuresArrayPath_Key); - inputValues.CellParentIdsArrayName = filterArgs.value(k_CellParentIdsArrayName_Key); - inputValues.GlobAlphaArrayName = filterArgs.value(k_GlobAlphaArrayName_Key); - inputValues.NewCellFeatureAttributeMatrixName = filterArgs.value(k_NewCellFeatureAttributeMatrixName_Key); - inputValues.FeatureParentIdsArrayName = filterArgs.value(k_FeatureParentIdsArrayName_Key); - inputValues.ActiveArrayName = filterArgs.value(k_ActiveArrayName_Key); - - return MergeColonies(dataStructure, messageHandler, shouldCancel, &inputValues)(); -*/ namespace complex { @@ -66,7 +30,6 @@ struct COMPLEXCORE_EXPORT MergeColoniesInputValues DataPath NewCellFeatureAttributeMatrixName; DataPath FeatureParentIdsArrayName; DataPath ActiveArrayName; - }; /** diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.cpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.cpp index 5bd771b773..87e47e01be 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.cpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.cpp @@ -4,10 +4,10 @@ #include "complex/DataStructure/DataPath.hpp" #include "complex/Filter/Actions/EmptyAction.hpp" -#include "complex/Parameters/BoolParameter.hpp" +#include "complex/Parameters/ArrayCreationParameter.hpp" #include "complex/Parameters/ArraySelectionParameter.hpp" +#include "complex/Parameters/BoolParameter.hpp" #include "complex/Parameters/NumberParameter.hpp" -#include "complex/Parameters/ArrayCreationParameter.hpp" using namespace complex; @@ -64,18 +64,25 @@ Parameters MergeColoniesFilter::parameters() const // Create the parameter descriptors that are needed for this filter params.insertLinkableParameter(std::make_unique(k_UseNonContiguousNeighbors_Key, "Use Non-Contiguous Neighbors", "", false #error Check default values)); params.insertSeparator(Parameters::Separator{"Feature Data"}); - params.insert(std::make_unique(k_NonContiguousNeighborListArrayPath_Key, "Non-Contiguous Neighbor List", "", DataPath{}, complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); - params.insert(std::make_unique(k_ContiguousNeighborListArrayPath_Key, "Contiguous Neighbor List", "", DataPath{}, complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); + params.insert(std::make_unique(k_NonContiguousNeighborListArrayPath_Key, "Non-Contiguous Neighbor List", "", DataPath{}, + complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); + params.insert(std::make_unique(k_ContiguousNeighborListArrayPath_Key, "Contiguous Neighbor List", "", DataPath{}, + complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); params.insert(std::make_unique(k_AxisTolerance_Key, "Axis Tolerance (Degrees)", "", 0.0f #error Check default values)); params.insert(std::make_unique(k_AngleTolerance_Key, "Angle Tolerance (Degrees)", "", 0.0f #error Check default values)); params.insertLinkableParameter(std::make_unique(k_IdentifyGlobAlpha_Key, "Identify Glob Alpha", "", false #error Check default values)); - params.insert(std::make_unique(k_FeaturePhasesArrayPath_Key, "Feature Phases", "", DataPath{}, complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); - params.insert(std::make_unique(k_AvgQuatsArrayPath_Key, "Average Quaternions", "", DataPath{}, complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); + params.insert(std::make_unique(k_FeaturePhasesArrayPath_Key, "Feature Phases", "", DataPath{}, + complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); + params.insert(std::make_unique(k_AvgQuatsArrayPath_Key, "Average Quaternions", "", DataPath{}, + complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); params.insertSeparator(Parameters::Separator{"Element Data"}); - params.insert(std::make_unique(k_FeatureIdsArrayPath_Key, "Feature Ids", "", DataPath{}, complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); - params.insert(std::make_unique(k_CellPhasesArrayPath_Key, "Phases", "", DataPath{}, complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); + params.insert(std::make_unique(k_FeatureIdsArrayPath_Key, "Feature Ids", "", DataPath{}, + complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); + params.insert(std::make_unique(k_CellPhasesArrayPath_Key, "Phases", "", DataPath{}, + complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); params.insertSeparator(Parameters::Separator{"Ensemble Data"}); - params.insert(std::make_unique(k_CrystalStructuresArrayPath_Key, "Crystal Structures", "", DataPath{}, complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); + params.insert(std::make_unique(k_CrystalStructuresArrayPath_Key, "Crystal Structures", "", DataPath{}, + complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); params.insertSeparator(Parameters::Separator{"Element Data"}); params.insert(std::make_unique(k_CellParentIdsArrayName_Key, "Parent Ids", "", DataPath{})); params.insert(std::make_unique(k_GlobAlphaArrayName_Key, "Glob Alpha", "", DataPath{})); @@ -97,17 +104,9 @@ IFilter::UniquePointer MergeColoniesFilter::clone() const } //------------------------------------------------------------------------------ -IFilter::PreflightResult MergeColoniesFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const +IFilter::PreflightResult MergeColoniesFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const { - /**************************************************************************** - * Write any preflight sanity checking codes in this function - ***************************************************************************/ - - /** - * These are the values that were gathered from the UI or the pipeline file or - * otherwise passed into the filter. These are here for your convenience. If you - * do not need some of them remove them. - */ auto pUseNonContiguousNeighborsValue = filterArgs.value(k_UseNonContiguousNeighbors_Key); auto pNonContiguousNeighborListArrayPathValue = filterArgs.value(k_NonContiguousNeighborListArrayPath_Key); auto pContiguousNeighborListArrayPathValue = filterArgs.value(k_ContiguousNeighborListArrayPath_Key); @@ -125,57 +124,21 @@ IFilter::PreflightResult MergeColoniesFilter::preflightImpl(const DataStructure& auto pFeatureParentIdsArrayNameValue = filterArgs.value(k_FeatureParentIdsArrayName_Key); auto pActiveArrayNameValue = filterArgs.value(k_ActiveArrayName_Key); - - - // Declare the preflightResult variable that will be populated with the results - // of the preflight. The PreflightResult type contains the output Actions and - // any preflight updated values that you want to be displayed to the user, typically - // through a user interface (UI). PreflightResult preflightResult; - - // If your filter is making structural changes to the DataStructure then the filter - // is going to create OutputActions subclasses that need to be returned. This will - // store those actions. complex::Result resultOutputActions; - - // If your filter is going to pass back some `preflight updated values` then this is where you - // would create the code to store those values in the appropriate object. Note that we - // in line creating the pair (NOT a std::pair<>) of Key:Value that will get stored in - // the std::vector object. std::vector preflightUpdatedValues; - // If the filter needs to pass back some updated values via a key:value string:string set of values - // you can declare and update that string here. - // None found in this filter based on the filter parameters - - // If this filter makes changes to the DataStructure in the form of - // creating/deleting/moving/renaming DataGroups, Geometries, DataArrays then you - // will need to use one of the `*Actions` classes located in complex/Filter/Actions - // to relay that information to the preflight and execute methods. This is done by - // creating an instance of the Action class and then storing it in the resultOutputActions variable. - // This is done through a `push_back()` method combined with a `std::move()`. For the - // newly initiated to `std::move` once that code is executed what was once inside the Action class - // instance variable is *no longer there*. The memory has been moved. If you try to access that - // variable after this line you will probably get a crash or have subtle bugs. To ensure that this - // does not happen we suggest using braces `{}` to scope each of the action's declaration and store - // so that the programmer is not tempted to use the action instance past where it should be used. - // You have to create your own Actions class if there isn't something specific for your filter's needs - - // Store the preflight updated value(s) into the preflightUpdatedValues vector using - // the appropriate methods. - // None found based on the filter parameters - // Return both the resultOutputActions and the preflightUpdatedValues via std::move() return {std::move(resultOutputActions), std::move(preflightUpdatedValues)}; } //------------------------------------------------------------------------------ -Result<> MergeColoniesFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const +Result<> MergeColoniesFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const { - MergeColoniesInputValues inputValues; - inputValues.UseNonContiguousNeighbors = filterArgs.value(k_UseNonContiguousNeighbors_Key); + inputValues.UseNonContiguousNeighbors = filterArgs.value(k_UseNonContiguousNeighbors_Key); inputValues.NonContiguousNeighborListArrayPath = filterArgs.value(k_NonContiguousNeighborListArrayPath_Key); inputValues.ContiguousNeighborListArrayPath = filterArgs.value(k_ContiguousNeighborListArrayPath_Key); inputValues.AxisTolerance = filterArgs.value(k_AxisTolerance_Key); @@ -192,7 +155,6 @@ Result<> MergeColoniesFilter::executeImpl(DataStructure& dataStructure, const Ar inputValues.FeatureParentIdsArrayName = filterArgs.value(k_FeatureParentIdsArrayName_Key); inputValues.ActiveArrayName = filterArgs.value(k_ActiveArrayName_Key); - return MergeColonies(dataStructure, messageHandler, shouldCancel, &inputValues)(); } } // namespace complex diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.hpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.hpp index 66491fabe9..c936977eab 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.hpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.hpp @@ -103,8 +103,7 @@ class COMPLEXCORE_EXPORT MergeColoniesFilter : public IFilter * @param messageHandler The MessageHandler object * @return Returns a Result object with error or warning values if any of those occurred during execution of this function */ - Result<> executeImpl(DataStructure & data, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) - const override; + Result<> executeImpl(DataStructure& data, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const override; }; } // namespace complex diff --git a/src/Plugins/ComplexCore/test/CMakeLists.txt b/src/Plugins/ComplexCore/test/CMakeLists.txt index 3d7c1fc089..9d413b3b1b 100644 --- a/src/Plugins/ComplexCore/test/CMakeLists.txt +++ b/src/Plugins/ComplexCore/test/CMakeLists.txt @@ -92,6 +92,7 @@ set(${PLUGIN_NAME}UnitTest_SRCS LosAlamosFFTWriterTest.cpp MultiThresholdObjectsTest.cpp MapPointCloudToRegularGridTest.cpp + MergeColoniesTest.cpp MinNeighborsTest.cpp MoveDataTest.cpp NearestPointFuseRegularGridsTest.cpp diff --git a/src/Plugins/ComplexCore/test/MergeColoniesTest.cpp b/src/Plugins/ComplexCore/test/MergeColoniesTest.cpp index 194b9020c0..f8f6790700 100644 --- a/src/Plugins/ComplexCore/test/MergeColoniesTest.cpp +++ b/src/Plugins/ComplexCore/test/MergeColoniesTest.cpp @@ -1,39 +1,16 @@ -/** - * This file is auto generated from the original ComplexCore/MergeColoniesFilter - * 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 "[MergeColoniesFilter][.][UNIMPLEMENTED]" - * from the TEST_CASE macro. This will enable this unit test to be run by default - * and report errors. - */ - - #include -#include "complex/Parameters/BoolParameter.hpp" +#include "complex/Parameters/ArrayCreationParameter.hpp" #include "complex/Parameters/ArraySelectionParameter.hpp" +#include "complex/Parameters/BoolParameter.hpp" #include "complex/Parameters/NumberParameter.hpp" -#include "complex/Parameters/ArrayCreationParameter.hpp" -#include "ComplexCore/Filters/MergeColoniesFilter.hpp" #include "ComplexCore/ComplexCore_test_dirs.hpp" +#include "ComplexCore/Filters/MergeColoniesFilter.hpp" using namespace complex; -TEST_CASE("ComplexCore::MergeColoniesFilter: Valid Filter Execution","[ComplexCore][MergeColoniesFilter][.][UNIMPLEMENTED][!mayfail]") +TEST_CASE("ComplexCore::MergeColoniesFilter: Valid Filter Execution", "[ComplexCore][MergeColoniesFilter][.][UNIMPLEMENTED][!mayfail]") { // Instantiate the filter, a DataStructure object and an Arguments Object MergeColoniesFilter filter; @@ -58,7 +35,6 @@ TEST_CASE("ComplexCore::MergeColoniesFilter: Valid Filter Execution","[ComplexCo args.insertOrAssign(MergeColoniesFilter::k_FeatureParentIdsArrayName_Key, std::make_any(DataPath{})); args.insertOrAssign(MergeColoniesFilter::k_ActiveArrayName_Key, std::make_any(DataPath{})); - // Preflight the filter and check result auto preflightResult = filter.preflight(ds, args); REQUIRE(preflightResult.outputActions.valid()); @@ -68,7 +44,7 @@ TEST_CASE("ComplexCore::MergeColoniesFilter: Valid Filter Execution","[ComplexCo REQUIRE(executeResult.result.valid()); } -//TEST_CASE("ComplexCore::MergeColoniesFilter: InValid Filter Execution") +// TEST_CASE("ComplexCore::MergeColoniesFilter: InValid Filter Execution") //{ // -//} +// } From e4206332418490c9724796fcd689c5cf4ce83101 Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Tue, 20 Jun 2023 12:51:20 -0400 Subject: [PATCH 4/8] initial changes --- .../Filters/Algorithms/MergeColonies.cpp | 375 ++++++++++++++++++ .../Filters/Algorithms/MergeColonies.hpp | 1 - .../Filters/MergeColoniesFilter.cpp | 70 ++-- .../Filters/MergeColoniesFilter.hpp | 1 - 4 files changed, 405 insertions(+), 42 deletions(-) diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp index 3ebe41ce3b..a8a6695bbd 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp @@ -2,9 +2,231 @@ #include "complex/DataStructure/DataArray.hpp" #include "complex/DataStructure/DataGroup.hpp" +#include "complex/DataStructure/NeighborList.hpp" +#include "complex/Common/Constants.hpp" +#include "complex/Utilities/Math/GeometryMath.hpp" +#include "complex/Utilities/Math/MatrixMath.hpp" + +#include "EbsdLib/Core/EbsdLibConstants.h" +#include "EbsdLib/Core/Quaternion.hpp" +#include "EbsdLib/Core/Orientation.hpp" +#include "EbsdLib/Core/OrientationTransformation.hpp" using namespace complex; +namespace +{ +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +int32 getSeed(int32 newFid) +{ + int32 numfeatures = static_cast(m_FeaturePhasesPtr.lock()->getNumberOfTuples()); + + SIMPL_RANDOMNG_NEW(); + int32 seed = -1; + int32 randfeature = 0; + + // Precalculate some constants + int32 totalFMinus1 = numfeatures - 1; + + usize counter = 0; + randfeature = int32(float32(rg.genrand_res53()) * float32(totalFMinus1)); + while(seed == -1 && counter < numfeatures) + { + if(randfeature > totalFMinus1) + { + randfeature = randfeature - numfeatures; + } + if(m_FeatureParentIds[randfeature] == -1) + { + seed = randfeature; + } + randfeature++; + counter++; + } + if(seed >= 0) + { + m_FeatureParentIds[seed] = newFid; + std::vector tDims(1, newFid + 1); + getDataContainerArray()->getDataContainer(m_FeatureIdsArrayPath.getDataContainerName())->getAttributeMatrix(getNewCellFeatureAttributeMatrixName())->resizeAttributeArrays(tDims); + updateFeatureInstancePointers(); + } + return seed; +} + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +bool determineGrouping(int32 referenceFeature, int32 neighborFeature, int32 newFid) +{ + double w = 0.0f; + bool colony = false; + + if(m_FeatureParentIds[neighborFeature] == -1 && m_FeaturePhases[referenceFeature] > 0 && m_FeaturePhases[neighborFeature] > 0) + { + w = std::numeric_limits::max(); + float32* avgQuatPtr = m_AvgQuats + referenceFeature * 4; + QuatD q1(avgQuatPtr[0], avgQuatPtr[1], avgQuatPtr[2], avgQuatPtr[3]); + avgQuatPtr = m_AvgQuats + neighborFeature * 4; + QuatD q2(avgQuatPtr[0], avgQuatPtr[1], avgQuatPtr[2], avgQuatPtr[3]); + + uint32 phase1 = m_CrystalStructures[m_FeaturePhases[referenceFeature]]; + uint32 phase2 = m_CrystalStructures[m_FeaturePhases[neighborFeature]]; + if(phase1 == phase2 && (phase1 == EbsdLib::CrystalStructure::Hexagonal_High)) + { + OrientationD ax = m_OrientationOps[phase1]->calculateMisorientation(q1, q2); + + OrientationD rod = OrientationTransformation::ax2ro(ax); + rod = m_OrientationOps[phase1]->getMDFFZRod(rod); + ax = OrientationTransformation::ro2ax(rod); + + w = ax[3] * (Constants::k_180OverPiD); + float angdiff1 = std::fabs(w - 10.53f); + float axisdiff1 = std::acos(/*std::fabs(n1) * 0.0000f + std::fabs(n2) * 0.0000f +*/ std::fabs(ax[2]) /* * 1.0000f */); + if(angdiff1 < m_AngleTolerance && axisdiff1 < m_AxisToleranceRad) + { + colony = true; + } + float angdiff2 = std::fabs(w - 90.00f); + float axisdiff2 = std::acos(std::fabs(ax[0]) * 0.9958f + std::fabs(ax[1]) * 0.0917f /* + std::fabs(n3) * 0.0000f */); + if(angdiff2 < m_AngleTolerance && axisdiff2 < m_AxisToleranceRad) + { + colony = true; + } + float angdiff3 = std::fabs(w - 60.00f); + float axisdiff3 = std::acos(std::fabs(ax[0]) /* * 1.0000f + std::fabs(n2) * 0.0000f + std::fabs(n3) * 0.0000f*/); + if(angdiff3 < m_AngleTolerance && axisdiff3 < m_AxisToleranceRad) + { + colony = true; + } + float angdiff4 = std::fabs(w - 60.83f); + float axisdiff4 = std::acos(std::fabs(ax[0]) * 0.9834f + std::fabs(ax[1]) * 0.0905f + std::fabs(ax[2]) * 0.1570f); + if(angdiff4 < m_AngleTolerance && axisdiff4 < m_AxisToleranceRad) + { + colony = true; + } + float angdiff5 = std::fabs(w - 63.26f); + float axisdiff5 = std::acos(std::fabs(ax[0]) * 0.9549f /* + std::fabs(n2) * 0.0000f */ + std::fabs(ax[2]) * 0.2969f); + if(angdiff5 < m_AngleTolerance && axisdiff5 < m_AxisToleranceRad) + { + colony = true; + } + if(colony) + { + m_FeatureParentIds[neighborFeature] = newFid; + return true; + } + } + else if(EbsdLib::CrystalStructure::Cubic_High == phase2 && EbsdLib::CrystalStructure::Hexagonal_High == phase1) + { + colony = check_for_burgers(q2, q1); + if(colony) + { + m_FeatureParentIds[neighborFeature] = newFid; + return true; + } + } + else if(EbsdLib::CrystalStructure::Cubic_High == phase1 && EbsdLib::CrystalStructure::Hexagonal_High == phase2) + { + colony = check_for_burgers(q1, q2); + if(colony) + { + m_FeatureParentIds[neighborFeature] = newFid; + return true; + } + } + } + return false; +} + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +bool check_for_burgers(const QuatD& betaQuat, const QuatD& alphaQuat) const +{ + double dP = 0.0; + double angle = 0.0; + double radToDeg = 180.0 / Constants::k_PiD; + + double gBeta[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + double gBetaT[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + OrientationTransformation::qu2om(betaQuat).toGMatrix(gBeta); + // transpose gBeta so the sample direction is the output when + // gBeta is multiplied by the crystal directions below + MatrixMath::Transpose3x3(gBeta, gBetaT); + + double gAlpha[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + double gAlphaT[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + OrientationTransformation::qu2om(alphaQuat).toGMatrix(gAlpha); + // transpose gBeta so the sample direction is the output when + // gBeta is multiplied by the crystal directions below + MatrixMath::Transpose3x3(gAlpha, gAlphaT); + + double mat[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + double a[3] = {0.0, 0.0, 0.0}; + double b[3] = {0.0, 0.0, 0.0}; + for(int32 i = 0; i < 12; i++) + { + MatrixMath::Multiply3x3with3x3(gBetaT, crystalDirections[i], mat); + a[0] = mat[0][2]; + a[1] = mat[1][2]; + a[2] = mat[2][2]; + b[0] = gAlphaT[0][2]; + b[1] = gAlphaT[1][2]; + b[2] = gAlphaT[2][2]; + dP = GeometryMath::CosThetaBetweenVectors(a, b); + angle = std::acos(dP); + if((angle * radToDeg) < m_AngleTolerance || (180.0f - (angle * radToDeg)) < m_AngleTolerance) + { + a[0] = mat[0][0]; + a[1] = mat[1][0]; + a[2] = mat[2][0]; + b[0] = gAlphaT[0][0]; + b[1] = gAlphaT[1][0]; + b[2] = gAlphaT[2][0]; + dP = GeometryMath::CosThetaBetweenVectors(a, b); + angle = std::acos(dP); + if((angle * radToDeg) < m_AngleTolerance) + { + return true; + } + if((180.0 - (angle * radToDeg)) < m_AngleTolerance) + { + return true; + } + b[0] = -0.5 * gAlphaT[0][0] + 0.866025 * gAlphaT[0][1]; + b[1] = -0.5 * gAlphaT[1][0] + 0.866025 * gAlphaT[1][1]; + b[2] = -0.5 * gAlphaT[2][0] + 0.866025 * gAlphaT[2][1]; + dP = GeometryMath::CosThetaBetweenVectors(a, b); + angle = std::acos(dP); + if((angle * radToDeg) < m_AngleTolerance) + { + return true; + } + if((180.0 - (angle * radToDeg)) < m_AngleTolerance) + { + return true; + } + b[0] = -0.5 * gAlphaT[0][0] - 0.866025 * gAlphaT[0][1]; + b[1] = -0.5 * gAlphaT[1][0] - 0.866025 * gAlphaT[1][1]; + b[2] = -0.5 * gAlphaT[2][0] - 0.866025 * gAlphaT[2][1]; + dP = GeometryMath::CosThetaBetweenVectors(a, b); + angle = std::acos(dP); + if((angle * radToDeg) < m_AngleTolerance) + { + return true; + } + if((180.0 - (angle * radToDeg)) < m_AngleTolerance) + { + return true; + } + } + } + return false; +} +} + // ----------------------------------------------------------------------------- MergeColonies::MergeColonies(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MergeColoniesInputValues* inputValues) : m_DataStructure(dataStructure) @@ -26,5 +248,158 @@ const std::atomic_bool& MergeColonies::getCancel() // ----------------------------------------------------------------------------- Result<> MergeColonies::operator()() { + m_AxisToleranceRad = m_AxisTolerance * Constants::k_PiD / 180.0f; + + Int32NeighborList& neighborlist = *(m_ContiguousNeighborList.lock()); + Int32NeighborList& nonContigNeighList = m_NonContiguousNeighborList.lock().get(); + + std::vector grouplist; + + int32 parentcount = 0; + int32 seed = 0; + int32 list1size = 0, list2size = 0, listsize = 0; + int32 neigh = 0; + + while(seed >= 0) + { + parentcount++; + seed = getSeed(parentcount); + if(seed >= 0) + { + grouplist.push_back(seed); + for(std::vector::size_type j = 0; j < grouplist.size(); j++) + { + int32 firstfeature = grouplist[j]; + list1size = int32(neighborlist[firstfeature].size()); + if(m_UseNonContiguousNeighbors) + { + list2size = nonContigNeighList.getListSize(firstfeature); + } + for(int32 k = 0; k < 2; k++) + { + if(m_PatchGrouping) + { + k = 1; + } + if(k == 0) + { + listsize = list1size; + } + else if(k == 1) + { + listsize = list2size; + } + for(int32 l = 0; l < listsize; l++) + { + if(k == 0) + { + neigh = neighborlist[firstfeature][l]; + } + else if(k == 1) + { + neigh = nonContigNeighList.getListReference(firstfeature)[l]; + } + if(neigh != firstfeature) + { + if(determineGrouping(firstfeature, neigh, parentcount)) + { + if(!m_PatchGrouping) + { + grouplist.push_back(neigh); + } + } + } + } + } + } + if(m_PatchGrouping) + { + if(growPatch(parentcount)) + { + for(std::vector::size_type j = 0; j < grouplist.size(); j++) + { + int32 firstfeature = grouplist[j]; + listsize = int32(neighborlist[firstfeature].size()); + for(int32 l = 0; l < listsize; l++) + { + neigh = neighborlist[firstfeature][l]; + if(neigh != firstfeature) + { + if(growGrouping(firstfeature, neigh, parentcount)) + { + grouplist.push_back(neigh); + } + } + } + } + } + } + } + grouplist.clear(); + } + + usize totalFeatures = m_ActivePtr.lock()->getNumberOfTuples(); + if(totalFeatures < 2) + { + return MakeErrorResult(-87000, "The number of Grouped Features was 0 or 1 which means no grouped Features were detected. A grouping value may be set too high"); + } + + int32 numParents = 0; + usize totalPoints = m_FeatureIdsPtr.lock()->getNumberOfTuples(); + for(usize k = 0; k < totalPoints; k++) + { + int32 featurename = m_FeatureIds[k]; + m_CellParentIds[k] = m_FeatureParentIds[featurename]; + if(m_FeatureParentIds[featurename] > numParents) + { + numParents = m_FeatureParentIds[featurename]; + } + } + numParents += 1; + + if(m_RandomizeParentIds) + { + // 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::uniform_int_distribution distribution(rangeMin, rangeMax); + + DataArray rndNumbers = DataArray::CreateArray(numParents, std::string("_INTERNAL_USE_ONLY_NewParentIds"), true); + int32* pid = rndNumbers->getPointer(0); + pid[0] = 0; + QSet parentIdSet; + parentIdSet.insert(0); + for(int32 i = 1; i < numParents; ++i) + { + pid[i] = i; // numberGenerator(); + parentIdSet.insert(pid[i]); + } + + int32 r = 0; + int32 temp = 0; + + //--- Shuffle elements by randomly exchanging each with one other. + for(int32 i = 1; i < numParents; i++) + { + r = distribution(generator); // Random remaining position. + if(r >= numParents) + { + continue; + } + temp = pid[i]; + pid[i] = pid[r]; + pid[r] = temp; + } + + // Now adjust all the Feature Id values for each Voxel + for(usize i = 0; i < totalPoints; ++i) + { + m_CellParentIds[i] = pid[m_CellParentIds[i]]; + m_FeatureParentIds[m_FeatureIds[i]] = m_CellParentIds[i]; + } + } + return {}; } diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.hpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.hpp index 0df94cce37..22a695b40c 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.hpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.hpp @@ -19,7 +19,6 @@ struct COMPLEXCORE_EXPORT MergeColoniesInputValues DataPath ContiguousNeighborListArrayPath; float32 AxisTolerance; float32 AngleTolerance; - bool IdentifyGlobAlpha; DataPath FeaturePhasesArrayPath; DataPath AvgQuatsArrayPath; DataPath FeatureIdsArrayPath; diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.cpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.cpp index 87e47e01be..58fa92bbd9 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.cpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.cpp @@ -7,6 +7,7 @@ #include "complex/Parameters/ArrayCreationParameter.hpp" #include "complex/Parameters/ArraySelectionParameter.hpp" #include "complex/Parameters/BoolParameter.hpp" +#include "complex/Parameters/NeighborListSelectionParameter.hpp" #include "complex/Parameters/NumberParameter.hpp" using namespace complex; @@ -48,51 +49,42 @@ Parameters MergeColoniesFilter::parameters() const { Parameters params; - /** - * Please separate the parameters into groups generally of the following: - * - * params.insertSeparator(Parameters::Separator{"Input Parameters"}); - * params.insertSeparator(Parameters::Separator{"Required Input Cell Data"}); - * params.insertSeparator(Parameters::Separator{"Required Input Feature Data"}); - * params.insertSeparator(Parameters::Separator{"Created Cell Data"}); - * params.insertSeparator(Parameters::Separator{"Created Cell Feature Data"}); - * - * .. or create appropriate separators as needed. The UI in COMPLEX no longer - * does this for the developer by using catgories as in SIMPL - */ - // Create the parameter descriptors that are needed for this filter - params.insertLinkableParameter(std::make_unique(k_UseNonContiguousNeighbors_Key, "Use Non-Contiguous Neighbors", "", false #error Check default values)); - params.insertSeparator(Parameters::Separator{"Feature Data"}); - params.insert(std::make_unique(k_NonContiguousNeighborListArrayPath_Key, "Non-Contiguous Neighbor List", "", DataPath{}, - complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); - params.insert(std::make_unique(k_ContiguousNeighborListArrayPath_Key, "Contiguous Neighbor List", "", DataPath{}, - complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); - params.insert(std::make_unique(k_AxisTolerance_Key, "Axis Tolerance (Degrees)", "", 0.0f #error Check default values)); - params.insert(std::make_unique(k_AngleTolerance_Key, "Angle Tolerance (Degrees)", "", 0.0f #error Check default values)); - params.insertLinkableParameter(std::make_unique(k_IdentifyGlobAlpha_Key, "Identify Glob Alpha", "", false #error Check default values)); - params.insert(std::make_unique(k_FeaturePhasesArrayPath_Key, "Feature Phases", "", DataPath{}, - complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); - params.insert(std::make_unique(k_AvgQuatsArrayPath_Key, "Average Quaternions", "", DataPath{}, - complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); - params.insertSeparator(Parameters::Separator{"Element Data"}); - params.insert(std::make_unique(k_FeatureIdsArrayPath_Key, "Feature Ids", "", DataPath{}, - complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); - params.insert(std::make_unique(k_CellPhasesArrayPath_Key, "Phases", "", DataPath{}, - complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); - params.insertSeparator(Parameters::Separator{"Ensemble Data"}); - params.insert(std::make_unique(k_CrystalStructuresArrayPath_Key, "Crystal Structures", "", DataPath{}, - complex::GetAllDataTypes() /* This will allow ANY data type. Adjust as necessary for your filter*/)); - params.insertSeparator(Parameters::Separator{"Element Data"}); + 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)); + params.insert(std::make_unique(k_AngleTolerance_Key, "Angle Tolerance (Degrees)", "", 0.0f)); + + params.insertSeparator(Parameters::Separator{"Required Feature Data"}); + params.insert(std::make_unique(k_NonContiguousNeighborListArrayPath_Key, "Non-Contiguous Neighbor List", "", DataPath{}, + NeighborListSelectionParameter::AllowedTypes{DataType::int32})); + params.insert(std::make_unique(k_ContiguousNeighborListArrayPath_Key, "Contiguous Neighbor List", "", DataPath{}, + NeighborListSelectionParameter::AllowedTypes{DataType::int32})); + params.insert(std::make_unique(k_FeaturePhasesArrayPath_Key, "Feature Phases", "", DataPath{}, ArraySelectionParameter::AllowedTypes{DataType::int32}, + ArraySelectionParameter::AllowedComponentShapes{{1}})); + params.insert(std::make_unique(k_AvgQuatsArrayPath_Key, "Average Quaternions", "", DataPath{}, ArraySelectionParameter::AllowedTypes{DataType::float32}, + ArraySelectionParameter::AllowedComponentShapes{{4}})); + + 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}, + ArraySelectionParameter::AllowedComponentShapes{{1}})); + + params.insertSeparator(Parameters::Separator{"Required Ensemble Data"}); + params.insert(std::make_unique(k_CrystalStructuresArrayPath_Key, "Crystal Structures", "", DataPath{}, ArraySelectionParameter::AllowedTypes{DataType::uint32}, + 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_GlobAlphaArrayName_Key, "Glob Alpha", "", DataPath{})); - params.insertSeparator(Parameters::Separator{"Feature Data"}); + + 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{})); + // Associate the Linkable Parameter(s) to the children parameters that they control params.linkParameters(k_UseNonContiguousNeighbors_Key, k_NonContiguousNeighborListArrayPath_Key, true); - params.linkParameters(k_IdentifyGlobAlpha_Key, k_GlobAlphaArrayName_Key, true); return params; } @@ -112,7 +104,6 @@ IFilter::PreflightResult MergeColoniesFilter::preflightImpl(const DataStructure& auto pContiguousNeighborListArrayPathValue = filterArgs.value(k_ContiguousNeighborListArrayPath_Key); auto pAxisToleranceValue = filterArgs.value(k_AxisTolerance_Key); auto pAngleToleranceValue = filterArgs.value(k_AngleTolerance_Key); - auto pIdentifyGlobAlphaValue = filterArgs.value(k_IdentifyGlobAlpha_Key); auto pFeaturePhasesArrayPathValue = filterArgs.value(k_FeaturePhasesArrayPath_Key); auto pAvgQuatsArrayPathValue = filterArgs.value(k_AvgQuatsArrayPath_Key); auto pFeatureIdsArrayPathValue = filterArgs.value(k_FeatureIdsArrayPath_Key); @@ -143,7 +134,6 @@ Result<> MergeColoniesFilter::executeImpl(DataStructure& dataStructure, const Ar inputValues.ContiguousNeighborListArrayPath = filterArgs.value(k_ContiguousNeighborListArrayPath_Key); inputValues.AxisTolerance = filterArgs.value(k_AxisTolerance_Key); inputValues.AngleTolerance = filterArgs.value(k_AngleTolerance_Key); - inputValues.IdentifyGlobAlpha = filterArgs.value(k_IdentifyGlobAlpha_Key); inputValues.FeaturePhasesArrayPath = filterArgs.value(k_FeaturePhasesArrayPath_Key); inputValues.AvgQuatsArrayPath = filterArgs.value(k_AvgQuatsArrayPath_Key); inputValues.FeatureIdsArrayPath = filterArgs.value(k_FeatureIdsArrayPath_Key); diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.hpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.hpp index c936977eab..8223d943b7 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.hpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.hpp @@ -29,7 +29,6 @@ class COMPLEXCORE_EXPORT MergeColoniesFilter : public IFilter static inline constexpr StringLiteral k_ContiguousNeighborListArrayPath_Key = "contiguous_neighbor_list_array_path"; static inline constexpr StringLiteral k_AxisTolerance_Key = "axis_tolerance"; static inline constexpr StringLiteral k_AngleTolerance_Key = "angle_tolerance"; - static inline constexpr StringLiteral k_IdentifyGlobAlpha_Key = "identify_glob_alpha"; static inline constexpr StringLiteral k_FeaturePhasesArrayPath_Key = "feature_phases_array_path"; static inline constexpr StringLiteral k_AvgQuatsArrayPath_Key = "avg_quats_array_path"; static inline constexpr StringLiteral k_FeatureIdsArrayPath_Key = "feature_ids_array_path"; From 1fe63f1d0af10cc5e305166e0f91cc914d9ab1a4 Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Wed, 21 Jun 2023 10:59:44 -0400 Subject: [PATCH 5/8] Update CMakeLists.txt, ComplexCoreLegacyUUIDMapping.hpp, MergeColonies.cpp, and 13 more files --- src/Plugins/ComplexCore/CMakeLists.txt | 2 - .../ComplexCoreLegacyUUIDMapping.hpp | 2 - .../Filters/Algorithms/MergeColonies.cpp | 405 ---------------- src/Plugins/ComplexCore/test/CMakeLists.txt | 1 - .../OrientationAnalysis/CMakeLists.txt | 2 + .../Filters/Algorithms/MergeColonies.cpp | 453 ++++++++++++++++++ .../Filters/Algorithms/MergeColonies.hpp | 8 +- .../Filters/MergeColoniesFilter.cpp | 2 - .../Filters/MergeColoniesFilter.hpp | 5 +- .../OrientationAnalysisLegacyUUIDMapping.hpp | 2 + .../OrientationAnalysis/test/CMakeLists.txt | 1 + .../test/MergeColoniesTest.cpp | 0 12 files changed, 464 insertions(+), 419 deletions(-) delete mode 100644 src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp create mode 100644 src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp rename src/Plugins/{ComplexCore/src/ComplexCore => OrientationAnalysis/src/OrientationAnalysis}/Filters/Algorithms/MergeColonies.hpp (86%) rename src/Plugins/{ComplexCore/src/ComplexCore => OrientationAnalysis/src/OrientationAnalysis}/Filters/MergeColoniesFilter.cpp (98%) rename src/Plugins/{ComplexCore/src/ComplexCore => OrientationAnalysis/src/OrientationAnalysis}/Filters/MergeColoniesFilter.hpp (95%) rename src/Plugins/{ComplexCore => OrientationAnalysis}/test/MergeColoniesTest.cpp (100%) diff --git a/src/Plugins/ComplexCore/CMakeLists.txt b/src/Plugins/ComplexCore/CMakeLists.txt index ca6ffc55ca..962c09532a 100644 --- a/src/Plugins/ComplexCore/CMakeLists.txt +++ b/src/Plugins/ComplexCore/CMakeLists.txt @@ -91,7 +91,6 @@ set(FilterList LaplacianSmoothingFilter LosAlamosFFTWriterFilter MapPointCloudToRegularGridFilter - MergeColoniesFilter MinNeighbors MoveData MultiThresholdObjects @@ -179,7 +178,6 @@ set(AlgorithmList KMedoids LaplacianSmoothing LosAlamosFFTWriter - MergeColonies NearestPointFuseRegularGrids PartitionGeometry PointSampleTriangleGeometry diff --git a/src/Plugins/ComplexCore/src/ComplexCore/ComplexCoreLegacyUUIDMapping.hpp b/src/Plugins/ComplexCore/src/ComplexCore/ComplexCoreLegacyUUIDMapping.hpp index c3829fb38d..73f387c2b3 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/ComplexCoreLegacyUUIDMapping.hpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/ComplexCoreLegacyUUIDMapping.hpp @@ -114,7 +114,6 @@ #include "ComplexCore/Filters/KMedoidsFilter.hpp" #include "ComplexCore/Filters/KMeansFilter.hpp" #include "ComplexCore/Filters/SilhouetteFilter.hpp" -#include "ComplexCore/Filters/MergeColoniesFilter.hpp" // @@__HEADER__TOKEN__DO__NOT__DELETE__@@ namespace complex @@ -238,7 +237,6 @@ namespace complex {complex::Uuid::FromString("f7486aa6-3049-5be7-8511-ae772b70c90b").value(), complex::FilterTraits::uuid}, // KMedoids {complex::Uuid::FromString("b56a04de-0ca0-509d-809f-52219fca9c98").value(), complex::FilterTraits::uuid}, // KMeans {complex::Uuid::FromString("f84d4d69-9ea5-54b6-a71c-df76d76d50cf").value(), complex::FilterTraits::uuid}, // Silhouette - {complex::Uuid::FromString("2c4a6d83-6a1b-56d8-9f65-9453b28845b9").value(), complex::FilterTraits::uuid}, // MergeColonies // @@__MAP__UPDATE__TOKEN__DO__NOT__DELETE__@@ }; diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp deleted file mode 100644 index a8a6695bbd..0000000000 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.cpp +++ /dev/null @@ -1,405 +0,0 @@ -#include "MergeColonies.hpp" - -#include "complex/DataStructure/DataArray.hpp" -#include "complex/DataStructure/DataGroup.hpp" -#include "complex/DataStructure/NeighborList.hpp" -#include "complex/Common/Constants.hpp" -#include "complex/Utilities/Math/GeometryMath.hpp" -#include "complex/Utilities/Math/MatrixMath.hpp" - -#include "EbsdLib/Core/EbsdLibConstants.h" -#include "EbsdLib/Core/Quaternion.hpp" -#include "EbsdLib/Core/Orientation.hpp" -#include "EbsdLib/Core/OrientationTransformation.hpp" - -using namespace complex; - -namespace -{ -// ----------------------------------------------------------------------------- -// -// ----------------------------------------------------------------------------- -int32 getSeed(int32 newFid) -{ - int32 numfeatures = static_cast(m_FeaturePhasesPtr.lock()->getNumberOfTuples()); - - SIMPL_RANDOMNG_NEW(); - int32 seed = -1; - int32 randfeature = 0; - - // Precalculate some constants - int32 totalFMinus1 = numfeatures - 1; - - usize counter = 0; - randfeature = int32(float32(rg.genrand_res53()) * float32(totalFMinus1)); - while(seed == -1 && counter < numfeatures) - { - if(randfeature > totalFMinus1) - { - randfeature = randfeature - numfeatures; - } - if(m_FeatureParentIds[randfeature] == -1) - { - seed = randfeature; - } - randfeature++; - counter++; - } - if(seed >= 0) - { - m_FeatureParentIds[seed] = newFid; - std::vector tDims(1, newFid + 1); - getDataContainerArray()->getDataContainer(m_FeatureIdsArrayPath.getDataContainerName())->getAttributeMatrix(getNewCellFeatureAttributeMatrixName())->resizeAttributeArrays(tDims); - updateFeatureInstancePointers(); - } - return seed; -} - -// ----------------------------------------------------------------------------- -// -// ----------------------------------------------------------------------------- -bool determineGrouping(int32 referenceFeature, int32 neighborFeature, int32 newFid) -{ - double w = 0.0f; - bool colony = false; - - if(m_FeatureParentIds[neighborFeature] == -1 && m_FeaturePhases[referenceFeature] > 0 && m_FeaturePhases[neighborFeature] > 0) - { - w = std::numeric_limits::max(); - float32* avgQuatPtr = m_AvgQuats + referenceFeature * 4; - QuatD q1(avgQuatPtr[0], avgQuatPtr[1], avgQuatPtr[2], avgQuatPtr[3]); - avgQuatPtr = m_AvgQuats + neighborFeature * 4; - QuatD q2(avgQuatPtr[0], avgQuatPtr[1], avgQuatPtr[2], avgQuatPtr[3]); - - uint32 phase1 = m_CrystalStructures[m_FeaturePhases[referenceFeature]]; - uint32 phase2 = m_CrystalStructures[m_FeaturePhases[neighborFeature]]; - if(phase1 == phase2 && (phase1 == EbsdLib::CrystalStructure::Hexagonal_High)) - { - OrientationD ax = m_OrientationOps[phase1]->calculateMisorientation(q1, q2); - - OrientationD rod = OrientationTransformation::ax2ro(ax); - rod = m_OrientationOps[phase1]->getMDFFZRod(rod); - ax = OrientationTransformation::ro2ax(rod); - - w = ax[3] * (Constants::k_180OverPiD); - float angdiff1 = std::fabs(w - 10.53f); - float axisdiff1 = std::acos(/*std::fabs(n1) * 0.0000f + std::fabs(n2) * 0.0000f +*/ std::fabs(ax[2]) /* * 1.0000f */); - if(angdiff1 < m_AngleTolerance && axisdiff1 < m_AxisToleranceRad) - { - colony = true; - } - float angdiff2 = std::fabs(w - 90.00f); - float axisdiff2 = std::acos(std::fabs(ax[0]) * 0.9958f + std::fabs(ax[1]) * 0.0917f /* + std::fabs(n3) * 0.0000f */); - if(angdiff2 < m_AngleTolerance && axisdiff2 < m_AxisToleranceRad) - { - colony = true; - } - float angdiff3 = std::fabs(w - 60.00f); - float axisdiff3 = std::acos(std::fabs(ax[0]) /* * 1.0000f + std::fabs(n2) * 0.0000f + std::fabs(n3) * 0.0000f*/); - if(angdiff3 < m_AngleTolerance && axisdiff3 < m_AxisToleranceRad) - { - colony = true; - } - float angdiff4 = std::fabs(w - 60.83f); - float axisdiff4 = std::acos(std::fabs(ax[0]) * 0.9834f + std::fabs(ax[1]) * 0.0905f + std::fabs(ax[2]) * 0.1570f); - if(angdiff4 < m_AngleTolerance && axisdiff4 < m_AxisToleranceRad) - { - colony = true; - } - float angdiff5 = std::fabs(w - 63.26f); - float axisdiff5 = std::acos(std::fabs(ax[0]) * 0.9549f /* + std::fabs(n2) * 0.0000f */ + std::fabs(ax[2]) * 0.2969f); - if(angdiff5 < m_AngleTolerance && axisdiff5 < m_AxisToleranceRad) - { - colony = true; - } - if(colony) - { - m_FeatureParentIds[neighborFeature] = newFid; - return true; - } - } - else if(EbsdLib::CrystalStructure::Cubic_High == phase2 && EbsdLib::CrystalStructure::Hexagonal_High == phase1) - { - colony = check_for_burgers(q2, q1); - if(colony) - { - m_FeatureParentIds[neighborFeature] = newFid; - return true; - } - } - else if(EbsdLib::CrystalStructure::Cubic_High == phase1 && EbsdLib::CrystalStructure::Hexagonal_High == phase2) - { - colony = check_for_burgers(q1, q2); - if(colony) - { - m_FeatureParentIds[neighborFeature] = newFid; - return true; - } - } - } - return false; -} - -// ----------------------------------------------------------------------------- -// -// ----------------------------------------------------------------------------- -bool check_for_burgers(const QuatD& betaQuat, const QuatD& alphaQuat) const -{ - double dP = 0.0; - double angle = 0.0; - double radToDeg = 180.0 / Constants::k_PiD; - - double gBeta[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; - double gBetaT[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; - OrientationTransformation::qu2om(betaQuat).toGMatrix(gBeta); - // transpose gBeta so the sample direction is the output when - // gBeta is multiplied by the crystal directions below - MatrixMath::Transpose3x3(gBeta, gBetaT); - - double gAlpha[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; - double gAlphaT[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; - OrientationTransformation::qu2om(alphaQuat).toGMatrix(gAlpha); - // transpose gBeta so the sample direction is the output when - // gBeta is multiplied by the crystal directions below - MatrixMath::Transpose3x3(gAlpha, gAlphaT); - - double mat[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; - double a[3] = {0.0, 0.0, 0.0}; - double b[3] = {0.0, 0.0, 0.0}; - for(int32 i = 0; i < 12; i++) - { - MatrixMath::Multiply3x3with3x3(gBetaT, crystalDirections[i], mat); - a[0] = mat[0][2]; - a[1] = mat[1][2]; - a[2] = mat[2][2]; - b[0] = gAlphaT[0][2]; - b[1] = gAlphaT[1][2]; - b[2] = gAlphaT[2][2]; - dP = GeometryMath::CosThetaBetweenVectors(a, b); - angle = std::acos(dP); - if((angle * radToDeg) < m_AngleTolerance || (180.0f - (angle * radToDeg)) < m_AngleTolerance) - { - a[0] = mat[0][0]; - a[1] = mat[1][0]; - a[2] = mat[2][0]; - b[0] = gAlphaT[0][0]; - b[1] = gAlphaT[1][0]; - b[2] = gAlphaT[2][0]; - dP = GeometryMath::CosThetaBetweenVectors(a, b); - angle = std::acos(dP); - if((angle * radToDeg) < m_AngleTolerance) - { - return true; - } - if((180.0 - (angle * radToDeg)) < m_AngleTolerance) - { - return true; - } - b[0] = -0.5 * gAlphaT[0][0] + 0.866025 * gAlphaT[0][1]; - b[1] = -0.5 * gAlphaT[1][0] + 0.866025 * gAlphaT[1][1]; - b[2] = -0.5 * gAlphaT[2][0] + 0.866025 * gAlphaT[2][1]; - dP = GeometryMath::CosThetaBetweenVectors(a, b); - angle = std::acos(dP); - if((angle * radToDeg) < m_AngleTolerance) - { - return true; - } - if((180.0 - (angle * radToDeg)) < m_AngleTolerance) - { - return true; - } - b[0] = -0.5 * gAlphaT[0][0] - 0.866025 * gAlphaT[0][1]; - b[1] = -0.5 * gAlphaT[1][0] - 0.866025 * gAlphaT[1][1]; - b[2] = -0.5 * gAlphaT[2][0] - 0.866025 * gAlphaT[2][1]; - dP = GeometryMath::CosThetaBetweenVectors(a, b); - angle = std::acos(dP); - if((angle * radToDeg) < m_AngleTolerance) - { - return true; - } - if((180.0 - (angle * radToDeg)) < m_AngleTolerance) - { - return true; - } - } - } - return false; -} -} - -// ----------------------------------------------------------------------------- -MergeColonies::MergeColonies(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MergeColoniesInputValues* inputValues) -: m_DataStructure(dataStructure) -, m_InputValues(inputValues) -, m_ShouldCancel(shouldCancel) -, m_MessageHandler(mesgHandler) -{ -} - -// ----------------------------------------------------------------------------- -MergeColonies::~MergeColonies() noexcept = default; - -// ----------------------------------------------------------------------------- -const std::atomic_bool& MergeColonies::getCancel() -{ - return m_ShouldCancel; -} - -// ----------------------------------------------------------------------------- -Result<> MergeColonies::operator()() -{ - m_AxisToleranceRad = m_AxisTolerance * Constants::k_PiD / 180.0f; - - Int32NeighborList& neighborlist = *(m_ContiguousNeighborList.lock()); - Int32NeighborList& nonContigNeighList = m_NonContiguousNeighborList.lock().get(); - - std::vector grouplist; - - int32 parentcount = 0; - int32 seed = 0; - int32 list1size = 0, list2size = 0, listsize = 0; - int32 neigh = 0; - - while(seed >= 0) - { - parentcount++; - seed = getSeed(parentcount); - if(seed >= 0) - { - grouplist.push_back(seed); - for(std::vector::size_type j = 0; j < grouplist.size(); j++) - { - int32 firstfeature = grouplist[j]; - list1size = int32(neighborlist[firstfeature].size()); - if(m_UseNonContiguousNeighbors) - { - list2size = nonContigNeighList.getListSize(firstfeature); - } - for(int32 k = 0; k < 2; k++) - { - if(m_PatchGrouping) - { - k = 1; - } - if(k == 0) - { - listsize = list1size; - } - else if(k == 1) - { - listsize = list2size; - } - for(int32 l = 0; l < listsize; l++) - { - if(k == 0) - { - neigh = neighborlist[firstfeature][l]; - } - else if(k == 1) - { - neigh = nonContigNeighList.getListReference(firstfeature)[l]; - } - if(neigh != firstfeature) - { - if(determineGrouping(firstfeature, neigh, parentcount)) - { - if(!m_PatchGrouping) - { - grouplist.push_back(neigh); - } - } - } - } - } - } - if(m_PatchGrouping) - { - if(growPatch(parentcount)) - { - for(std::vector::size_type j = 0; j < grouplist.size(); j++) - { - int32 firstfeature = grouplist[j]; - listsize = int32(neighborlist[firstfeature].size()); - for(int32 l = 0; l < listsize; l++) - { - neigh = neighborlist[firstfeature][l]; - if(neigh != firstfeature) - { - if(growGrouping(firstfeature, neigh, parentcount)) - { - grouplist.push_back(neigh); - } - } - } - } - } - } - } - grouplist.clear(); - } - - usize totalFeatures = m_ActivePtr.lock()->getNumberOfTuples(); - if(totalFeatures < 2) - { - return MakeErrorResult(-87000, "The number of Grouped Features was 0 or 1 which means no grouped Features were detected. A grouping value may be set too high"); - } - - int32 numParents = 0; - usize totalPoints = m_FeatureIdsPtr.lock()->getNumberOfTuples(); - for(usize k = 0; k < totalPoints; k++) - { - int32 featurename = m_FeatureIds[k]; - m_CellParentIds[k] = m_FeatureParentIds[featurename]; - if(m_FeatureParentIds[featurename] > numParents) - { - numParents = m_FeatureParentIds[featurename]; - } - } - numParents += 1; - - if(m_RandomizeParentIds) - { - // 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::uniform_int_distribution distribution(rangeMin, rangeMax); - - DataArray rndNumbers = DataArray::CreateArray(numParents, std::string("_INTERNAL_USE_ONLY_NewParentIds"), true); - int32* pid = rndNumbers->getPointer(0); - pid[0] = 0; - QSet parentIdSet; - parentIdSet.insert(0); - for(int32 i = 1; i < numParents; ++i) - { - pid[i] = i; // numberGenerator(); - parentIdSet.insert(pid[i]); - } - - int32 r = 0; - int32 temp = 0; - - //--- Shuffle elements by randomly exchanging each with one other. - for(int32 i = 1; i < numParents; i++) - { - r = distribution(generator); // Random remaining position. - if(r >= numParents) - { - continue; - } - temp = pid[i]; - pid[i] = pid[r]; - pid[r] = temp; - } - - // Now adjust all the Feature Id values for each Voxel - for(usize i = 0; i < totalPoints; ++i) - { - m_CellParentIds[i] = pid[m_CellParentIds[i]]; - m_FeatureParentIds[m_FeatureIds[i]] = m_CellParentIds[i]; - } - } - - return {}; -} diff --git a/src/Plugins/ComplexCore/test/CMakeLists.txt b/src/Plugins/ComplexCore/test/CMakeLists.txt index 9d413b3b1b..3d7c1fc089 100644 --- a/src/Plugins/ComplexCore/test/CMakeLists.txt +++ b/src/Plugins/ComplexCore/test/CMakeLists.txt @@ -92,7 +92,6 @@ set(${PLUGIN_NAME}UnitTest_SRCS LosAlamosFFTWriterTest.cpp MultiThresholdObjectsTest.cpp MapPointCloudToRegularGridTest.cpp - MergeColoniesTest.cpp MinNeighborsTest.cpp MoveDataTest.cpp NearestPointFuseRegularGridsTest.cpp diff --git a/src/Plugins/OrientationAnalysis/CMakeLists.txt b/src/Plugins/OrientationAnalysis/CMakeLists.txt index 2fd722e2f0..3c12884616 100644 --- a/src/Plugins/OrientationAnalysis/CMakeLists.txt +++ b/src/Plugins/OrientationAnalysis/CMakeLists.txt @@ -65,6 +65,7 @@ set(FilterList ImportH5EspritDataFilter ImportH5OimDataFilter INLWriterFilter + MergeColoniesFilter MergeTwinsFilter NeighborOrientationCorrelationFilter ReadAngDataFilter @@ -199,6 +200,7 @@ set(filter_algorithms ImportH5EspritData ImportH5OimData INLWriter + MergeColonies MergeTwins NeighborOrientationCorrelation ReadAngData diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp new file mode 100644 index 0000000000..c27efe3c43 --- /dev/null +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp @@ -0,0 +1,453 @@ +#include "MergeColonies.hpp" + +#include "complex/Common/Array.hpp" +#include "complex/Common/Constants.hpp" +#include "complex/DataStructure/DataArray.hpp" +#include "complex/DataStructure/DataGroup.hpp" +#include "complex/DataStructure/NeighborList.hpp" +#include "complex/Utilities/Math/GeometryMath.hpp" +#include "complex/Utilities/Math/MatrixMath.hpp" + +#include "EbsdLib/Core/EbsdLibConstants.h" +#include "EbsdLib/Core/Orientation.hpp" +#include "EbsdLib/Core/OrientationTransformation.hpp" +#include "EbsdLib/Core/Quaternion.hpp" +#include "EbsdLib/LaueOps/LaueOps.h" + +using namespace complex; +using LaueOpsShPtrType = std::shared_ptr; +using LaueOpsContainer = std::vector; + +namespace +{ +const float64 unit110 = 1.0 / std::sqrt(2.0); +const float64 unit111 = 1.0 / std::sqrt(3.0); +const float64 unit112_1 = 1.0 / std::sqrt(6.0); +const float64 unit112_2 = 2.0 / std::sqrt(6.0); + +float64 crystalDirections[12][3][3] = {{{unit111, unit112_1, unit110}, {-unit111, -unit112_1, unit110}, {unit111, -unit112_2, 0}}, + + {{-unit111, unit112_1, unit110}, {unit111, -unit112_1, unit110}, {unit111, unit112_2, 0}}, + + {{unit111, -unit112_1, unit110}, {unit111, -unit112_1, -unit110}, {unit111, unit112_2, 0}}, + + {{unit111, unit112_1, unit110}, {unit111, unit112_1, -unit110}, {-unit111, unit112_2, 0}}, + + {{unit111, unit112_1, unit110}, {unit111, -unit112_2, 0}, {unit111, unit112_1, -unit110}}, + + {{unit111, -unit112_1, unit110}, {-unit111, -unit112_2, 0}, {unit111, -unit112_1, -unit110}}, + + {{unit111, -unit112_1, unit110}, {unit111, unit112_2, 0}, {-unit111, unit112_1, unit110}}, + + {{-unit111, -unit112_1, unit110}, {unit111, -unit112_2, 0}, {unit111, unit112_1, unit110}}, + + {{unit111, -unit112_2, 0}, {unit111, unit112_1, unit110}, {-unit111, -unit112_1, unit110}}, + + {{unit111, unit112_2, 0}, {-unit111, unit112_1, unit110}, {unit111, -unit112_1, unit110}}, + + {{unit111, unit112_2, 0}, {unit111, -unit112_1, unit110}, {unit111, -unit112_1, -unit110}}, + + {{-unit111, unit112_2, 0}, {unit111, unit112_1, unit110}, {unit111, unit112_1, -unit110}}}; + +class MergeColoniesAlg +{ +public: + MergeColoniesAlg(Int32Array& featureParentIds, AttributeMatrix& cellFeatureAM, Int32Array& featurePhases, float64 axisToleranceRad, float64 angleTolerance) + : + , m_OrientationOps(LaueOps::GetAllOrientationOps()) + { + } + ~MergeColoniesAlg() = default; + + void execute() + { + Int32NeighborList& neighborlist = *(m_ContiguousNeighborList.lock()); + Int32NeighborList& nonContigNeighList = m_NonContiguousNeighborList.lock().get(); + + std::vector grouplist; + + int32 parentcount = 0; + int32 seed = 0; + int32 list1size = 0, list2size = 0, listsize = 0; + int32 neigh = 0; + + while(seed >= 0) + { + parentcount++; + seed = getSeed(parentcount); + if(seed >= 0) + { + grouplist.push_back(seed); + for(std::vector::size_type j = 0; j < grouplist.size(); j++) + { + int32 firstfeature = grouplist[j]; + list1size = int32(neighborlist[firstfeature].size()); + if(m_UseNonContiguousNeighbors) + { + list2size = nonContigNeighList.getListSize(firstfeature); + } + for(int32 k = 0; k < 2; k++) + { + if(m_PatchGrouping) + { + k = 1; + } + if(k == 0) + { + listsize = list1size; + } + else if(k == 1) + { + listsize = list2size; + } + for(int32 l = 0; l < listsize; l++) + { + if(k == 0) + { + neigh = neighborlist[firstfeature][l]; + } + else if(k == 1) + { + neigh = nonContigNeighList.getListReference(firstfeature)[l]; + } + if(neigh != firstfeature) + { + if(determineGrouping(firstfeature, neigh, parentcount)) + { + if(!m_PatchGrouping) + { + grouplist.push_back(neigh); + } + } + } + } + } + } + if(m_PatchGrouping) + { + if(growPatch(parentcount)) + { + for(std::vector::size_type j = 0; j < grouplist.size(); j++) + { + int32 firstfeature = grouplist[j]; + listsize = int32(neighborlist[firstfeature].size()); + for(int32 l = 0; l < listsize; l++) + { + neigh = neighborlist[firstfeature][l]; + if(neigh != firstfeature) + { + if(growGrouping(firstfeature, neigh, parentcount)) + { + grouplist.push_back(neigh); + } + } + } + } + } + } + } + grouplist.clear(); + } + } + +private: + LaueOpsContainer m_OrientationOps; + Int32Array& m_FeatureParentIds; + AttributeMatrix& m_CellFeatureAM; + Int32Array& m_FeaturePhases; + Float32Array& m_AvgQuats; + const UInt32Array& m_CrystalStructures; + float64 m_AxisToleranceRad = 0.0; + float64 m_AngleTolerance = 1.0; + + // ----------------------------------------------------------------------------- + // + // ----------------------------------------------------------------------------- + int32 getSeed(int32 newFid) + { + usize numFeatures = m_FeaturePhases.getNumberOfTuples(); + + SIMPL_RANDOMNG_NEW(); + int32 seed = -1; + int32 randFeature = 0; + + // Precalculate some constants + usize totalFMinus1 = numFeatures - 1; + + usize counter = 0; + randFeature = int32(float32(rg.genrand_res53()) * float32(totalFMinus1)); + while(seed == -1 && counter < numFeatures) + { + if(randFeature > totalFMinus1) + { + randFeature = randFeature - numFeatures; + } + if(m_FeatureParentIds[randFeature] == -1) + { + seed = randFeature; + } + randFeature++; + counter++; + } + if(seed >= 0) + { + m_FeatureParentIds[seed] = newFid; + std::vector tDims(1, newFid + 1); + m_CellFeatureAM.resizeTuples(tDims); + } + return seed; + } + + // ----------------------------------------------------------------------------- + // + // ----------------------------------------------------------------------------- + bool check_for_burgers(const QuatD& betaQuat, const QuatD& alphaQuat) + { + float64 dP = 0.0; + float64 angle = 0.0; + float64 radToDeg = 180.0 / Constants::k_PiD; + + float64 gBeta[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + float64 gBetaT[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + OrientationTransformation::qu2om(betaQuat).toGMatrix(gBeta); + // transpose gBeta so the sample direction is the output when + // gBeta is multiplied by the crystal directions below + MatrixMath::Transpose3x3(gBeta, gBetaT); + + float64 gAlpha[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + float64 gAlphaT[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + OrientationTransformation::qu2om(alphaQuat).toGMatrix(gAlpha); + // transpose gBeta so the sample direction is the output when + // gBeta is multiplied by the crystal directions below + MatrixMath::Transpose3x3(gAlpha, gAlphaT); + + float64 mat[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + for(int32 i = 0; i < 12; i++) + { + MatrixMath::Multiply3x3with3x3(gBetaT, crystalDirections[i], mat); + Point3Dd a = Point3Dd(mat[0][2], mat[1][2], mat[2][2]); + Point3Dd b = Point3Dd(gAlphaT[0][2], gAlphaT[1][2], gAlphaT[2][2]); + dP = GeometryMath::CosThetaBetweenVectors(a, b); + angle = std::acos(dP); + if((angle * radToDeg) < m_AngleTolerance || (180.0f - (angle * radToDeg)) < m_AngleTolerance) + { + a[0] = mat[0][0]; + a[1] = mat[1][0]; + a[2] = mat[2][0]; + b[0] = gAlphaT[0][0]; + b[1] = gAlphaT[1][0]; + b[2] = gAlphaT[2][0]; + dP = GeometryMath::CosThetaBetweenVectors(a, b); + angle = std::acos(dP); + if((angle * radToDeg) < m_AngleTolerance) + { + return true; + } + if((180.0 - (angle * radToDeg)) < m_AngleTolerance) + { + return true; + } + b[0] = -0.5 * gAlphaT[0][0] + 0.866025 * gAlphaT[0][1]; + b[1] = -0.5 * gAlphaT[1][0] + 0.866025 * gAlphaT[1][1]; + b[2] = -0.5 * gAlphaT[2][0] + 0.866025 * gAlphaT[2][1]; + dP = GeometryMath::CosThetaBetweenVectors(a, b); + angle = std::acos(dP); + if((angle * radToDeg) < m_AngleTolerance) + { + return true; + } + if((180.0 - (angle * radToDeg)) < m_AngleTolerance) + { + return true; + } + b[0] = -0.5 * gAlphaT[0][0] - 0.866025 * gAlphaT[0][1]; + b[1] = -0.5 * gAlphaT[1][0] - 0.866025 * gAlphaT[1][1]; + b[2] = -0.5 * gAlphaT[2][0] - 0.866025 * gAlphaT[2][1]; + dP = GeometryMath::CosThetaBetweenVectors(a, b); + angle = std::acos(dP); + if((angle * radToDeg) < m_AngleTolerance) + { + return true; + } + if((180.0 - (angle * radToDeg)) < m_AngleTolerance) + { + return true; + } + } + } + return false; + } + + // ----------------------------------------------------------------------------- + // + // ----------------------------------------------------------------------------- + bool determineGrouping(int32 referenceFeature, int32 neighborFeature, int32 newFid) + { + float64 w = std::numeric_limits::max(); + bool colony = false; + + if(m_FeatureParentIds[neighborFeature] == -1 && m_FeaturePhases[referenceFeature] > 0 && m_FeaturePhases[neighborFeature] > 0) + { + usize avgQuatIdx = referenceFeature * 4; + QuatD q1(m_AvgQuats[avgQuatIdx], m_AvgQuats[avgQuatIdx + 1], m_AvgQuats[avgQuatIdx + 2], m_AvgQuats[avgQuatIdx + 3]); + avgQuatIdx = neighborFeature * 4; + QuatD q2(m_AvgQuats[avgQuatIdx], m_AvgQuats[avgQuatIdx + 1], m_AvgQuats[avgQuatIdx + 2], m_AvgQuats[avgQuatIdx + 3]); + + uint32 phase1 = m_CrystalStructures[m_FeaturePhases[referenceFeature]]; + uint32 phase2 = m_CrystalStructures[m_FeaturePhases[neighborFeature]]; + if(phase1 == phase2 && (phase1 == EbsdLib::CrystalStructure::Hexagonal_High)) + { + OrientationD ax = m_OrientationOps[phase1]->calculateMisorientation(q1, q2); + + auto rod = OrientationTransformation::ax2ro(ax); + rod = m_OrientationOps[phase1]->getMDFFZRod(rod); + ax = OrientationTransformation::ro2ax(rod); + + w = ax[3] * (Constants::k_180OverPiD); + float angdiff1 = std::fabs(w - 10.53f); + float axisdiff1 = std::acos(/*std::fabs(n1) * 0.0000f + std::fabs(n2) * 0.0000f +*/ std::fabs(ax[2]) /* * 1.0000f */); + if(angdiff1 < m_AngleTolerance && axisdiff1 < m_AxisToleranceRad) + { + colony = true; + } + float angdiff2 = std::fabs(w - 90.00f); + float axisdiff2 = std::acos(std::fabs(ax[0]) * 0.9958f + std::fabs(ax[1]) * 0.0917f /* + std::fabs(n3) * 0.0000f */); + if(angdiff2 < m_AngleTolerance && axisdiff2 < m_AxisToleranceRad) + { + colony = true; + } + float angdiff3 = std::fabs(w - 60.00f); + float axisdiff3 = std::acos(std::fabs(ax[0]) /* * 1.0000f + std::fabs(n2) * 0.0000f + std::fabs(n3) * 0.0000f*/); + if(angdiff3 < m_AngleTolerance && axisdiff3 < m_AxisToleranceRad) + { + colony = true; + } + float angdiff4 = std::fabs(w - 60.83f); + float axisdiff4 = std::acos(std::fabs(ax[0]) * 0.9834f + std::fabs(ax[1]) * 0.0905f + std::fabs(ax[2]) * 0.1570f); + if(angdiff4 < m_AngleTolerance && axisdiff4 < m_AxisToleranceRad) + { + colony = true; + } + float angdiff5 = std::fabs(w - 63.26f); + float axisdiff5 = std::acos(std::fabs(ax[0]) * 0.9549f /* + std::fabs(n2) * 0.0000f */ + std::fabs(ax[2]) * 0.2969f); + if(angdiff5 < m_AngleTolerance && axisdiff5 < m_AxisToleranceRad) + { + colony = true; + } + if(colony) + { + m_FeatureParentIds[neighborFeature] = newFid; + return true; + } + } + else if(EbsdLib::CrystalStructure::Cubic_High == phase2 && EbsdLib::CrystalStructure::Hexagonal_High == phase1) + { + colony = check_for_burgers(q2, q1); + if(colony) + { + m_FeatureParentIds[neighborFeature] = newFid; + return true; + } + } + else if(EbsdLib::CrystalStructure::Cubic_High == phase1 && EbsdLib::CrystalStructure::Hexagonal_High == phase2) + { + colony = check_for_burgers(q1, q2); + if(colony) + { + m_FeatureParentIds[neighborFeature] = newFid; + return true; + } + } + } + return false; + } +}; +} // namespace + +// ----------------------------------------------------------------------------- +MergeColonies::MergeColonies(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MergeColoniesInputValues* inputValues) +: m_DataStructure(dataStructure) +, m_InputValues(inputValues) +, m_ShouldCancel(shouldCancel) +, m_MessageHandler(mesgHandler) +{ +} + +// ----------------------------------------------------------------------------- +MergeColonies::~MergeColonies() noexcept = default; + +// ----------------------------------------------------------------------------- +const std::atomic_bool& MergeColonies::getCancel() +{ + return m_ShouldCancel; +} + +// ----------------------------------------------------------------------------- +Result<> MergeColonies::operator()() +{ + m_AxisToleranceRad = m_AxisTolerance * Constants::k_PiD / 180.0f; + + usize totalFeatures = m_ActivePtr.lock()->getNumberOfTuples(); + if(totalFeatures < 2) + { + return MakeErrorResult(-87000, "The number of Grouped Features was 0 or 1 which means no grouped Features were detected. A grouping value may be set too high"); + } + + int32 numParents = 0; + usize totalPoints = m_FeatureIdsPtr.lock()->getNumberOfTuples(); + for(usize k = 0; k < totalPoints; k++) + { + int32 featurename = m_FeatureIds[k]; + m_CellParentIds[k] = m_FeatureParentIds[featurename]; + if(m_FeatureParentIds[featurename] > numParents) + { + numParents = m_FeatureParentIds[featurename]; + } + } + numParents += 1; + + if(m_RandomizeParentIds) + { + // 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::uniform_int_distribution distribution(rangeMin, rangeMax); + + std::vector pid(numParents); + pid.push_back(0); + QSet parentIdSet; + parentIdSet.insert(0); + for(int32 i = 1; i < numParents; ++i) + { + pid.push_back(i); // numberGenerator(); + parentIdSet.insert(pid[i]); + } + + int32 r = 0; + int32 temp = 0; + + //--- Shuffle elements by randomly exchanging each with one other. + for(int32 i = 1; i < numParents; i++) + { + r = distribution(generator); // Random remaining position. + if(r >= numParents) + { + continue; + } + temp = pid[i]; + pid[i] = pid[r]; + pid[r] = temp; + } + + // Now adjust all the Feature Id values for each Voxel + for(usize i = 0; i < totalPoints; ++i) + { + m_CellParentIds[i] = pid[m_CellParentIds[i]]; + m_FeatureParentIds[m_FeatureIds[i]] = m_CellParentIds[i]; + } + } + + return {}; +} diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp similarity index 86% rename from src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.hpp rename to src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp index 22a695b40c..d41b3ca8bc 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/Algorithms/MergeColonies.hpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp @@ -1,6 +1,7 @@ #pragma once -#include "ComplexCore/ComplexCore_export.hpp" +#include "OrientationAnalysis/Filters/Algorithms/GroupFeatures.hpp" +#include "OrientationAnalysis/OrientationAnalysis_export.hpp" #include "complex/DataStructure/DataPath.hpp" #include "complex/DataStructure/DataStructure.hpp" @@ -12,7 +13,7 @@ namespace complex { -struct COMPLEXCORE_EXPORT MergeColoniesInputValues +struct ORIENTATIONANALYSIS_EXPORT MergeColoniesInputValues { bool UseNonContiguousNeighbors; DataPath NonContiguousNeighborListArrayPath; @@ -25,7 +26,6 @@ struct COMPLEXCORE_EXPORT MergeColoniesInputValues DataPath CellPhasesArrayPath; DataPath CrystalStructuresArrayPath; DataPath CellParentIdsArrayName; - DataPath GlobAlphaArrayName; DataPath NewCellFeatureAttributeMatrixName; DataPath FeatureParentIdsArrayName; DataPath ActiveArrayName; @@ -37,7 +37,7 @@ struct COMPLEXCORE_EXPORT MergeColoniesInputValues * where a bool mask array specifies. */ -class COMPLEXCORE_EXPORT MergeColonies +class ORIENTATIONANALYSIS_EXPORT MergeColonies : public GroupFeatures { public: MergeColonies(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MergeColoniesInputValues* inputValues); diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.cpp similarity index 98% rename from src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.cpp rename to src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.cpp index 58fa92bbd9..65adfeefbd 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.cpp @@ -110,7 +110,6 @@ IFilter::PreflightResult MergeColoniesFilter::preflightImpl(const DataStructure& auto pCellPhasesArrayPathValue = filterArgs.value(k_CellPhasesArrayPath_Key); auto pCrystalStructuresArrayPathValue = filterArgs.value(k_CrystalStructuresArrayPath_Key); auto pCellParentIdsArrayNameValue = filterArgs.value(k_CellParentIdsArrayName_Key); - auto pGlobAlphaArrayNameValue = filterArgs.value(k_GlobAlphaArrayName_Key); auto pNewCellFeatureAttributeMatrixNameValue = filterArgs.value(k_NewCellFeatureAttributeMatrixName_Key); auto pFeatureParentIdsArrayNameValue = filterArgs.value(k_FeatureParentIdsArrayName_Key); auto pActiveArrayNameValue = filterArgs.value(k_ActiveArrayName_Key); @@ -140,7 +139,6 @@ Result<> MergeColoniesFilter::executeImpl(DataStructure& dataStructure, const Ar inputValues.CellPhasesArrayPath = filterArgs.value(k_CellPhasesArrayPath_Key); inputValues.CrystalStructuresArrayPath = filterArgs.value(k_CrystalStructuresArrayPath_Key); inputValues.CellParentIdsArrayName = filterArgs.value(k_CellParentIdsArrayName_Key); - inputValues.GlobAlphaArrayName = filterArgs.value(k_GlobAlphaArrayName_Key); inputValues.NewCellFeatureAttributeMatrixName = filterArgs.value(k_NewCellFeatureAttributeMatrixName_Key); inputValues.FeatureParentIdsArrayName = filterArgs.value(k_FeatureParentIdsArrayName_Key); inputValues.ActiveArrayName = filterArgs.value(k_ActiveArrayName_Key); diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.hpp similarity index 95% rename from src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.hpp rename to src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.hpp index 8223d943b7..5bca7600ca 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/MergeColoniesFilter.hpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.hpp @@ -1,6 +1,6 @@ #pragma once -#include "ComplexCore/ComplexCore_export.hpp" +#include "OrientationAnalysis/OrientationAnalysis_export.hpp" #include "complex/Filter/FilterTraits.hpp" #include "complex/Filter/IFilter.hpp" @@ -11,7 +11,7 @@ namespace complex * @class MergeColoniesFilter * @brief This filter will .... */ -class COMPLEXCORE_EXPORT MergeColoniesFilter : public IFilter +class ORIENTATIONANALYSIS_EXPORT MergeColoniesFilter : public IFilter { public: MergeColoniesFilter() = default; @@ -35,7 +35,6 @@ class COMPLEXCORE_EXPORT MergeColoniesFilter : public IFilter static inline constexpr StringLiteral k_CellPhasesArrayPath_Key = "cell_phases_array_path"; static inline constexpr StringLiteral k_CrystalStructuresArrayPath_Key = "crystal_structures_array_path"; static inline constexpr StringLiteral k_CellParentIdsArrayName_Key = "cell_parent_ids_array_name"; - static inline constexpr StringLiteral k_GlobAlphaArrayName_Key = "glob_alpha_array_name"; 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"; diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/OrientationAnalysisLegacyUUIDMapping.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/OrientationAnalysisLegacyUUIDMapping.hpp index 0ac13383e6..508ff3c838 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/OrientationAnalysisLegacyUUIDMapping.hpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/OrientationAnalysisLegacyUUIDMapping.hpp @@ -69,6 +69,7 @@ #include "OrientationAnalysis/Filters/FindSlipTransmissionMetricsFilter.hpp" #include "OrientationAnalysis/Filters/WriteStatsGenOdfAngleFileFilter.hpp" #include "OrientationAnalysis/Filters/INLWriterFilter.hpp" +#include "OrientationAnalysis/Filters/MergeColoniesFilter.hpp" // @@__HEADER__TOKEN__DO__NOT__DELETE__@@ #include @@ -108,6 +109,7 @@ namespace complex {complex::Uuid::FromString("bf7036d8-25bd-540e-b6de-3a5ab0e42c5f").value(), complex::FilterTraits::uuid}, // FindAvgOrientations {complex::Uuid::FromString("bff6be19-1219-5876-8838-1574ad29d965").value(), complex::FilterTraits::uuid}, // CAxisSegmentFeatures {complex::Uuid::FromString("c5a9a96c-7570-5279-b383-cc25ebae0046").value(), complex::FilterTraits::uuid}, // FindAvgCAxes + {complex::Uuid::FromString("2c4a6d83-6a1b-56d8-9f65-9453b28845b9").value(), complex::FilterTraits::uuid}, // MergeColonies {complex::Uuid::FromString("c9af506e-9ea1-5ff5-a882-fa561def5f52").value(), complex::FilterTraits::uuid}, // MergeTwins {complex::Uuid::FromString("d1df969c-0428-53c3-b61d-99ea2bb6da28").value(), complex::FilterTraits::uuid}, // ReadCtfData {complex::Uuid::FromString("e5629880-98c4-5656-82b8-c9fe2b9744de").value(), complex::FilterTraits::uuid}, // ConvertOrientations diff --git a/src/Plugins/OrientationAnalysis/test/CMakeLists.txt b/src/Plugins/OrientationAnalysis/test/CMakeLists.txt index 3d96ac3716..a92e73b9d0 100644 --- a/src/Plugins/OrientationAnalysis/test/CMakeLists.txt +++ b/src/Plugins/OrientationAnalysis/test/CMakeLists.txt @@ -44,6 +44,7 @@ set(${PLUGIN_NAME}UnitTest_SRCS ImportH5EspritDataTest.cpp ImportH5OimDataTest.cpp INLWriterTest.cpp + MergeColoniesTest.cpp MergeTwinsTest.cpp NeighborOrientationCorrelationTest.cpp ReadAngDataTest.cpp diff --git a/src/Plugins/ComplexCore/test/MergeColoniesTest.cpp b/src/Plugins/OrientationAnalysis/test/MergeColoniesTest.cpp similarity index 100% rename from src/Plugins/ComplexCore/test/MergeColoniesTest.cpp rename to src/Plugins/OrientationAnalysis/test/MergeColoniesTest.cpp From f9fb5ed1ef64d81e51f9bfa00ae91c7a229b1f8f Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Wed, 21 Jun 2023 12:29:52 -0400 Subject: [PATCH 6/8] further clean up --- .../Filters/Algorithms/MergeColonies.cpp | 516 +++++++----------- .../Filters/Algorithms/MergeColonies.hpp | 42 +- .../Filters/MergeColoniesFilter.cpp | 2 +- 3 files changed, 240 insertions(+), 320 deletions(-) diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp index c27efe3c43..4051ff7d9a 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp @@ -12,7 +12,6 @@ #include "EbsdLib/Core/Orientation.hpp" #include "EbsdLib/Core/OrientationTransformation.hpp" #include "EbsdLib/Core/Quaternion.hpp" -#include "EbsdLib/LaueOps/LaueOps.h" using namespace complex; using LaueOpsShPtrType = std::shared_ptr; @@ -49,327 +48,96 @@ float64 crystalDirections[12][3][3] = {{{unit111, unit112_1, unit110}, {-unit111 {{-unit111, unit112_2, 0}, {unit111, unit112_1, unit110}, {unit111, unit112_1, -unit110}}}; -class MergeColoniesAlg +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +bool check_for_burgers(const QuatD& betaQuat, const QuatD& alphaQuat, float64 angleTolerance) { -public: - MergeColoniesAlg(Int32Array& featureParentIds, AttributeMatrix& cellFeatureAM, Int32Array& featurePhases, float64 axisToleranceRad, float64 angleTolerance) - : - , m_OrientationOps(LaueOps::GetAllOrientationOps()) - { - } - ~MergeColoniesAlg() = default; - - void execute() - { - Int32NeighborList& neighborlist = *(m_ContiguousNeighborList.lock()); - Int32NeighborList& nonContigNeighList = m_NonContiguousNeighborList.lock().get(); - - std::vector grouplist; - - int32 parentcount = 0; - int32 seed = 0; - int32 list1size = 0, list2size = 0, listsize = 0; - int32 neigh = 0; - - while(seed >= 0) - { - parentcount++; - seed = getSeed(parentcount); - if(seed >= 0) - { - grouplist.push_back(seed); - for(std::vector::size_type j = 0; j < grouplist.size(); j++) - { - int32 firstfeature = grouplist[j]; - list1size = int32(neighborlist[firstfeature].size()); - if(m_UseNonContiguousNeighbors) - { - list2size = nonContigNeighList.getListSize(firstfeature); - } - for(int32 k = 0; k < 2; k++) - { - if(m_PatchGrouping) - { - k = 1; - } - if(k == 0) - { - listsize = list1size; - } - else if(k == 1) - { - listsize = list2size; - } - for(int32 l = 0; l < listsize; l++) - { - if(k == 0) - { - neigh = neighborlist[firstfeature][l]; - } - else if(k == 1) - { - neigh = nonContigNeighList.getListReference(firstfeature)[l]; - } - if(neigh != firstfeature) - { - if(determineGrouping(firstfeature, neigh, parentcount)) - { - if(!m_PatchGrouping) - { - grouplist.push_back(neigh); - } - } - } - } - } - } - if(m_PatchGrouping) - { - if(growPatch(parentcount)) - { - for(std::vector::size_type j = 0; j < grouplist.size(); j++) - { - int32 firstfeature = grouplist[j]; - listsize = int32(neighborlist[firstfeature].size()); - for(int32 l = 0; l < listsize; l++) - { - neigh = neighborlist[firstfeature][l]; - if(neigh != firstfeature) - { - if(growGrouping(firstfeature, neigh, parentcount)) - { - grouplist.push_back(neigh); - } - } - } - } - } - } - } - grouplist.clear(); - } - } - -private: - LaueOpsContainer m_OrientationOps; - Int32Array& m_FeatureParentIds; - AttributeMatrix& m_CellFeatureAM; - Int32Array& m_FeaturePhases; - Float32Array& m_AvgQuats; - const UInt32Array& m_CrystalStructures; - float64 m_AxisToleranceRad = 0.0; - float64 m_AngleTolerance = 1.0; - - // ----------------------------------------------------------------------------- - // - // ----------------------------------------------------------------------------- - int32 getSeed(int32 newFid) + float64 dP = 0.0; + float64 angle = 0.0; + float64 radToDeg = 180.0 / Constants::k_PiD; + + float64 gBeta[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + float64 gBetaT[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + OrientationTransformation::qu2om(betaQuat).toGMatrix(gBeta); + // transpose gBeta so the sample direction is the output when + // gBeta is multiplied by the crystal directions below + MatrixMath::Transpose3x3(gBeta, gBetaT); + + float64 gAlpha[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + float64 gAlphaT[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + OrientationTransformation::qu2om(alphaQuat).toGMatrix(gAlpha); + // transpose gBeta so the sample direction is the output when + // gBeta is multiplied by the crystal directions below + MatrixMath::Transpose3x3(gAlpha, gAlphaT); + + float64 mat[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; + for(int32 i = 0; i < 12; i++) { - usize numFeatures = m_FeaturePhases.getNumberOfTuples(); - - SIMPL_RANDOMNG_NEW(); - int32 seed = -1; - int32 randFeature = 0; - - // Precalculate some constants - usize totalFMinus1 = numFeatures - 1; - - usize counter = 0; - randFeature = int32(float32(rg.genrand_res53()) * float32(totalFMinus1)); - while(seed == -1 && counter < numFeatures) + MatrixMath::Multiply3x3with3x3(gBetaT, crystalDirections[i], mat); + Point3Dd a = Point3Dd(mat[0][2], mat[1][2], mat[2][2]); + Point3Dd b = Point3Dd(gAlphaT[0][2], gAlphaT[1][2], gAlphaT[2][2]); + dP = GeometryMath::CosThetaBetweenVectors(a, b); + angle = std::acos(dP); + if((angle * radToDeg) < angleTolerance || (180.0f - (angle * radToDeg)) < angleTolerance) { - if(randFeature > totalFMinus1) + a[0] = mat[0][0]; + a[1] = mat[1][0]; + a[2] = mat[2][0]; + b[0] = gAlphaT[0][0]; + b[1] = gAlphaT[1][0]; + b[2] = gAlphaT[2][0]; + dP = GeometryMath::CosThetaBetweenVectors(a, b); + angle = std::acos(dP); + if((angle * radToDeg) < angleTolerance) { - randFeature = randFeature - numFeatures; + return true; } - if(m_FeatureParentIds[randFeature] == -1) + if((180.0 - (angle * radToDeg)) < angleTolerance) { - seed = randFeature; + return true; } - randFeature++; - counter++; - } - if(seed >= 0) - { - m_FeatureParentIds[seed] = newFid; - std::vector tDims(1, newFid + 1); - m_CellFeatureAM.resizeTuples(tDims); - } - return seed; - } - - // ----------------------------------------------------------------------------- - // - // ----------------------------------------------------------------------------- - bool check_for_burgers(const QuatD& betaQuat, const QuatD& alphaQuat) - { - float64 dP = 0.0; - float64 angle = 0.0; - float64 radToDeg = 180.0 / Constants::k_PiD; - - float64 gBeta[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; - float64 gBetaT[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; - OrientationTransformation::qu2om(betaQuat).toGMatrix(gBeta); - // transpose gBeta so the sample direction is the output when - // gBeta is multiplied by the crystal directions below - MatrixMath::Transpose3x3(gBeta, gBetaT); - - float64 gAlpha[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; - float64 gAlphaT[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; - OrientationTransformation::qu2om(alphaQuat).toGMatrix(gAlpha); - // transpose gBeta so the sample direction is the output when - // gBeta is multiplied by the crystal directions below - MatrixMath::Transpose3x3(gAlpha, gAlphaT); - - float64 mat[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; - for(int32 i = 0; i < 12; i++) - { - MatrixMath::Multiply3x3with3x3(gBetaT, crystalDirections[i], mat); - Point3Dd a = Point3Dd(mat[0][2], mat[1][2], mat[2][2]); - Point3Dd b = Point3Dd(gAlphaT[0][2], gAlphaT[1][2], gAlphaT[2][2]); + b[0] = -0.5 * gAlphaT[0][0] + 0.866025 * gAlphaT[0][1]; + b[1] = -0.5 * gAlphaT[1][0] + 0.866025 * gAlphaT[1][1]; + b[2] = -0.5 * gAlphaT[2][0] + 0.866025 * gAlphaT[2][1]; dP = GeometryMath::CosThetaBetweenVectors(a, b); angle = std::acos(dP); - if((angle * radToDeg) < m_AngleTolerance || (180.0f - (angle * radToDeg)) < m_AngleTolerance) + if((angle * radToDeg) < angleTolerance) { - a[0] = mat[0][0]; - a[1] = mat[1][0]; - a[2] = mat[2][0]; - b[0] = gAlphaT[0][0]; - b[1] = gAlphaT[1][0]; - b[2] = gAlphaT[2][0]; - dP = GeometryMath::CosThetaBetweenVectors(a, b); - angle = std::acos(dP); - if((angle * radToDeg) < m_AngleTolerance) - { - return true; - } - if((180.0 - (angle * radToDeg)) < m_AngleTolerance) - { - return true; - } - b[0] = -0.5 * gAlphaT[0][0] + 0.866025 * gAlphaT[0][1]; - b[1] = -0.5 * gAlphaT[1][0] + 0.866025 * gAlphaT[1][1]; - b[2] = -0.5 * gAlphaT[2][0] + 0.866025 * gAlphaT[2][1]; - dP = GeometryMath::CosThetaBetweenVectors(a, b); - angle = std::acos(dP); - if((angle * radToDeg) < m_AngleTolerance) - { - return true; - } - if((180.0 - (angle * radToDeg)) < m_AngleTolerance) - { - return true; - } - b[0] = -0.5 * gAlphaT[0][0] - 0.866025 * gAlphaT[0][1]; - b[1] = -0.5 * gAlphaT[1][0] - 0.866025 * gAlphaT[1][1]; - b[2] = -0.5 * gAlphaT[2][0] - 0.866025 * gAlphaT[2][1]; - dP = GeometryMath::CosThetaBetweenVectors(a, b); - angle = std::acos(dP); - if((angle * radToDeg) < m_AngleTolerance) - { - return true; - } - if((180.0 - (angle * radToDeg)) < m_AngleTolerance) - { - return true; - } + return true; } - } - return false; - } - - // ----------------------------------------------------------------------------- - // - // ----------------------------------------------------------------------------- - bool determineGrouping(int32 referenceFeature, int32 neighborFeature, int32 newFid) - { - float64 w = std::numeric_limits::max(); - bool colony = false; - - if(m_FeatureParentIds[neighborFeature] == -1 && m_FeaturePhases[referenceFeature] > 0 && m_FeaturePhases[neighborFeature] > 0) - { - usize avgQuatIdx = referenceFeature * 4; - QuatD q1(m_AvgQuats[avgQuatIdx], m_AvgQuats[avgQuatIdx + 1], m_AvgQuats[avgQuatIdx + 2], m_AvgQuats[avgQuatIdx + 3]); - avgQuatIdx = neighborFeature * 4; - QuatD q2(m_AvgQuats[avgQuatIdx], m_AvgQuats[avgQuatIdx + 1], m_AvgQuats[avgQuatIdx + 2], m_AvgQuats[avgQuatIdx + 3]); - - uint32 phase1 = m_CrystalStructures[m_FeaturePhases[referenceFeature]]; - uint32 phase2 = m_CrystalStructures[m_FeaturePhases[neighborFeature]]; - if(phase1 == phase2 && (phase1 == EbsdLib::CrystalStructure::Hexagonal_High)) + if((180.0 - (angle * radToDeg)) < angleTolerance) { - OrientationD ax = m_OrientationOps[phase1]->calculateMisorientation(q1, q2); - - auto rod = OrientationTransformation::ax2ro(ax); - rod = m_OrientationOps[phase1]->getMDFFZRod(rod); - ax = OrientationTransformation::ro2ax(rod); - - w = ax[3] * (Constants::k_180OverPiD); - float angdiff1 = std::fabs(w - 10.53f); - float axisdiff1 = std::acos(/*std::fabs(n1) * 0.0000f + std::fabs(n2) * 0.0000f +*/ std::fabs(ax[2]) /* * 1.0000f */); - if(angdiff1 < m_AngleTolerance && axisdiff1 < m_AxisToleranceRad) - { - colony = true; - } - float angdiff2 = std::fabs(w - 90.00f); - float axisdiff2 = std::acos(std::fabs(ax[0]) * 0.9958f + std::fabs(ax[1]) * 0.0917f /* + std::fabs(n3) * 0.0000f */); - if(angdiff2 < m_AngleTolerance && axisdiff2 < m_AxisToleranceRad) - { - colony = true; - } - float angdiff3 = std::fabs(w - 60.00f); - float axisdiff3 = std::acos(std::fabs(ax[0]) /* * 1.0000f + std::fabs(n2) * 0.0000f + std::fabs(n3) * 0.0000f*/); - if(angdiff3 < m_AngleTolerance && axisdiff3 < m_AxisToleranceRad) - { - colony = true; - } - float angdiff4 = std::fabs(w - 60.83f); - float axisdiff4 = std::acos(std::fabs(ax[0]) * 0.9834f + std::fabs(ax[1]) * 0.0905f + std::fabs(ax[2]) * 0.1570f); - if(angdiff4 < m_AngleTolerance && axisdiff4 < m_AxisToleranceRad) - { - colony = true; - } - float angdiff5 = std::fabs(w - 63.26f); - float axisdiff5 = std::acos(std::fabs(ax[0]) * 0.9549f /* + std::fabs(n2) * 0.0000f */ + std::fabs(ax[2]) * 0.2969f); - if(angdiff5 < m_AngleTolerance && axisdiff5 < m_AxisToleranceRad) - { - colony = true; - } - if(colony) - { - m_FeatureParentIds[neighborFeature] = newFid; - return true; - } + return true; } - else if(EbsdLib::CrystalStructure::Cubic_High == phase2 && EbsdLib::CrystalStructure::Hexagonal_High == phase1) + b[0] = -0.5 * gAlphaT[0][0] - 0.866025 * gAlphaT[0][1]; + b[1] = -0.5 * gAlphaT[1][0] - 0.866025 * gAlphaT[1][1]; + b[2] = -0.5 * gAlphaT[2][0] - 0.866025 * gAlphaT[2][1]; + dP = GeometryMath::CosThetaBetweenVectors(a, b); + angle = std::acos(dP); + if((angle * radToDeg) < angleTolerance) { - colony = check_for_burgers(q2, q1); - if(colony) - { - m_FeatureParentIds[neighborFeature] = newFid; - return true; - } + return true; } - else if(EbsdLib::CrystalStructure::Cubic_High == phase1 && EbsdLib::CrystalStructure::Hexagonal_High == phase2) + if((180.0 - (angle * radToDeg)) < angleTolerance) { - colony = check_for_burgers(q1, q2); - if(colony) - { - m_FeatureParentIds[neighborFeature] = newFid; - return true; - } + return true; } } - return false; } -}; + return false; +} } // namespace // ----------------------------------------------------------------------------- -MergeColonies::MergeColonies(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MergeColoniesInputValues* inputValues) -: m_DataStructure(dataStructure) +MergeColonies::MergeColonies(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MergeColoniesInputValues* inputValues, + GroupFeaturesInputValues* groupInputValues) +: GroupFeatures(dataStructure, mesgHandler, shouldCancel, groupInputValues) +, m_DataStructure(dataStructure) , m_InputValues(inputValues) , m_ShouldCancel(shouldCancel) , m_MessageHandler(mesgHandler) +, m_OrientationOps(LaueOps::GetAllOrientationOps()) { } @@ -385,20 +153,33 @@ const std::atomic_bool& MergeColonies::getCancel() // ----------------------------------------------------------------------------- Result<> MergeColonies::operator()() { - m_AxisToleranceRad = m_AxisTolerance * Constants::k_PiD / 180.0f; + m_FeatureParentIds = m_DataStructure.getDataRefAs(m_InputValues->FeatureParentIdsPath); + m_FeaturePhases = m_DataStructure.getDataRefAs(m_InputValues->FeaturePhasesPath); + m_AvgQuats = m_DataStructure.getDataRefAs(m_InputValues->AvgQuatsPath); + m_CrystalStructures = m_DataStructure.getDataRefAs(m_InputValues->CrystalStructuresPath); + + m_AxisToleranceRad = m_InputValues->AxisTolerance * Constants::k_PiF / 180.0f; + m_AngleTolerance = m_InputValues->AngleTolerance; + + GroupFeatures::execute(); + + auto active = m_DataStructure.getDataRefAs(m_InputValues->ActivePath); - usize totalFeatures = m_ActivePtr.lock()->getNumberOfTuples(); + usize totalFeatures = active.getNumberOfTuples(); if(totalFeatures < 2) { return MakeErrorResult(-87000, "The number of Grouped Features was 0 or 1 which means no grouped Features were detected. A grouping value may be set too high"); } + auto featureIds = m_DataStructure.getDataRefAs(m_InputValues->FeatureIdsPath); + auto cellParentIds = m_DataStructure.getDataRefAs(m_InputValues->CellParentIdsPath); + int32 numParents = 0; - usize totalPoints = m_FeatureIdsPtr.lock()->getNumberOfTuples(); + usize totalPoints = featureIds.getNumberOfTuples(); for(usize k = 0; k < totalPoints; k++) { - int32 featurename = m_FeatureIds[k]; - m_CellParentIds[k] = m_FeatureParentIds[featurename]; + int32 featurename = featureIds[k]; + cellParentIds[k] = m_FeatureParentIds[featurename]; if(m_FeatureParentIds[featurename] > numParents) { numParents = m_FeatureParentIds[featurename]; @@ -406,8 +187,9 @@ Result<> MergeColonies::operator()() } numParents += 1; - if(m_RandomizeParentIds) + if(m_InputValues->RandomizeParentIds) { + m_MessageHandler({IFilter::Message::Type::Info, "Randomizing Parent Ids...."}); // Generate all the numbers up front const int32 rangeMin = 1; const int32 rangeMax = numParents - 1; @@ -417,7 +199,7 @@ Result<> MergeColonies::operator()() std::vector pid(numParents); pid.push_back(0); - QSet parentIdSet; + std::set parentIdSet; parentIdSet.insert(0); for(int32 i = 1; i < numParents; ++i) { @@ -428,6 +210,7 @@ Result<> MergeColonies::operator()() int32 r = 0; int32 temp = 0; + m_MessageHandler({IFilter::Message::Type::Info, "Shuffle elements ...."}); //--- Shuffle elements by randomly exchanging each with one other. for(int32 i = 1; i < numParents; i++) { @@ -441,13 +224,134 @@ Result<> MergeColonies::operator()() pid[r] = temp; } + m_MessageHandler({IFilter::Message::Type::Info, "Adjusting Feature Ids Array...."}); // Now adjust all the Feature Id values for each Voxel for(usize i = 0; i < totalPoints; ++i) { - m_CellParentIds[i] = pid[m_CellParentIds[i]]; - m_FeatureParentIds[m_FeatureIds[i]] = m_CellParentIds[i]; + cellParentIds[i] = pid[cellParentIds[i]]; + m_FeatureParentIds[featureIds[i]] = cellParentIds[i]; } } return {}; } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +int32 MergeColonies::getSeed(int32 newFid) +{ + usize numFeatures = m_FeaturePhases.getNumberOfTuples(); + + SIMPL_RANDOMNG_NEW(); + int32 seed = -1; + int32 randFeature = 0; + + // Precalculate some constants + usize totalFMinus1 = numFeatures - 1; + + usize counter = 0; + randFeature = int32(float32(rg.genrand_res53()) * float32(totalFMinus1)); + while(seed == -1 && counter < numFeatures) + { + if(randFeature > totalFMinus1) + { + randFeature = randFeature - numFeatures; + } + if(m_FeatureParentIds[randFeature] == -1) + { + seed = randFeature; + } + randFeature++; + counter++; + } + if(seed >= 0) + { + m_FeatureParentIds[seed] = newFid; + std::vector tDims(1, newFid + 1); + m_DataStructure.getDataRefAs(m_InputValues->CellFeatureAMPath).resizeTuples(tDims); + } + return seed; +} + +// ----------------------------------------------------------------------------- +bool MergeColonies::determineGrouping(int32 referenceFeature, int32 neighborFeature, int32 newFid) +{ + float64 w = std::numeric_limits::max(); + bool colony = false; + + if(m_FeatureParentIds[neighborFeature] == -1 && m_FeaturePhases[referenceFeature] > 0 && m_FeaturePhases[neighborFeature] > 0) + { + usize avgQuatIdx = referenceFeature * 4; + QuatD q1(m_AvgQuats[avgQuatIdx], m_AvgQuats[avgQuatIdx + 1], m_AvgQuats[avgQuatIdx + 2], m_AvgQuats[avgQuatIdx + 3]); + avgQuatIdx = neighborFeature * 4; + QuatD q2(m_AvgQuats[avgQuatIdx], m_AvgQuats[avgQuatIdx + 1], m_AvgQuats[avgQuatIdx + 2], m_AvgQuats[avgQuatIdx + 3]); + + uint32 phase1 = m_CrystalStructures[m_FeaturePhases[referenceFeature]]; + uint32 phase2 = m_CrystalStructures[m_FeaturePhases[neighborFeature]]; + if(phase1 == phase2 && (phase1 == EbsdLib::CrystalStructure::Hexagonal_High)) + { + OrientationD ax = m_OrientationOps[phase1]->calculateMisorientation(q1, q2); + + auto rod = OrientationTransformation::ax2ro(ax); + rod = m_OrientationOps[phase1]->getMDFFZRod(rod); + ax = OrientationTransformation::ro2ax(rod); + + w = ax[3] * (Constants::k_180OverPiD); + float angdiff1 = std::fabs(w - 10.53f); + float axisdiff1 = std::acos(/*std::fabs(n1) * 0.0000f + std::fabs(n2) * 0.0000f +*/ std::fabs(ax[2]) /* * 1.0000f */); + if(angdiff1 < m_AngleTolerance && axisdiff1 < m_AxisToleranceRad) + { + colony = true; + } + float angdiff2 = std::fabs(w - 90.00f); + float axisdiff2 = std::acos(std::fabs(ax[0]) * 0.9958f + std::fabs(ax[1]) * 0.0917f /* + std::fabs(n3) * 0.0000f */); + if(angdiff2 < m_AngleTolerance && axisdiff2 < m_AxisToleranceRad) + { + colony = true; + } + float angdiff3 = std::fabs(w - 60.00f); + float axisdiff3 = std::acos(std::fabs(ax[0]) /* * 1.0000f + std::fabs(n2) * 0.0000f + std::fabs(n3) * 0.0000f*/); + if(angdiff3 < m_AngleTolerance && axisdiff3 < m_AxisToleranceRad) + { + colony = true; + } + float angdiff4 = std::fabs(w - 60.83f); + float axisdiff4 = std::acos(std::fabs(ax[0]) * 0.9834f + std::fabs(ax[1]) * 0.0905f + std::fabs(ax[2]) * 0.1570f); + if(angdiff4 < m_AngleTolerance && axisdiff4 < m_AxisToleranceRad) + { + colony = true; + } + float angdiff5 = std::fabs(w - 63.26f); + float axisdiff5 = std::acos(std::fabs(ax[0]) * 0.9549f /* + std::fabs(n2) * 0.0000f */ + std::fabs(ax[2]) * 0.2969f); + if(angdiff5 < m_AngleTolerance && axisdiff5 < m_AxisToleranceRad) + { + colony = true; + } + if(colony) + { + m_FeatureParentIds[neighborFeature] = newFid; + return true; + } + } + else if(EbsdLib::CrystalStructure::Cubic_High == phase2 && EbsdLib::CrystalStructure::Hexagonal_High == phase1) + { + colony = check_for_burgers(q2, q1, m_AngleTolerance); + if(colony) + { + m_FeatureParentIds[neighborFeature] = newFid; + return true; + } + } + else if(EbsdLib::CrystalStructure::Cubic_High == phase1 && EbsdLib::CrystalStructure::Hexagonal_High == phase2) + { + colony = check_for_burgers(q1, q2, m_AngleTolerance); + if(colony) + { + m_FeatureParentIds[neighborFeature] = newFid; + return true; + } + } + } + return false; +} diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp index d41b3ca8bc..113129bac2 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp @@ -3,6 +3,8 @@ #include "OrientationAnalysis/Filters/Algorithms/GroupFeatures.hpp" #include "OrientationAnalysis/OrientationAnalysis_export.hpp" +#include "complex/DataStructure/AttributeMatrix.hpp" +#include "complex/DataStructure/DataArray.hpp" #include "complex/DataStructure/DataPath.hpp" #include "complex/DataStructure/DataStructure.hpp" #include "complex/Filter/IFilter.hpp" @@ -10,25 +12,27 @@ #include "complex/Parameters/ArraySelectionParameter.hpp" #include "complex/Parameters/NumberParameter.hpp" +#include "EbsdLib/LaueOps/LaueOps.h" + namespace complex { - struct ORIENTATIONANALYSIS_EXPORT MergeColoniesInputValues { bool UseNonContiguousNeighbors; - DataPath NonContiguousNeighborListArrayPath; - DataPath ContiguousNeighborListArrayPath; + DataPath NonContiguousNLPath; + DataPath ContiguousNLPath; float32 AxisTolerance; float32 AngleTolerance; - DataPath FeaturePhasesArrayPath; - DataPath AvgQuatsArrayPath; - DataPath FeatureIdsArrayPath; - DataPath CellPhasesArrayPath; - DataPath CrystalStructuresArrayPath; - DataPath CellParentIdsArrayName; - DataPath NewCellFeatureAttributeMatrixName; - DataPath FeatureParentIdsArrayName; - DataPath ActiveArrayName; + DataPath FeaturePhasesPath; + DataPath AvgQuatsPath; + DataPath FeatureIdsPath; + DataPath CellPhasesPath; + DataPath CrystalStructuresPath; + DataPath CellParentIdsPath; + DataPath CellFeatureAMPath; + DataPath FeatureParentIdsPath; + DataPath ActivePath; + bool RandomizeParentIds = true; }; /** @@ -39,6 +43,9 @@ struct ORIENTATIONANALYSIS_EXPORT MergeColoniesInputValues class ORIENTATIONANALYSIS_EXPORT MergeColonies : public GroupFeatures { + using LaueOpsShPtrType = std::shared_ptr; + using LaueOpsContainer = std::vector; + public: MergeColonies(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MergeColoniesInputValues* inputValues); ~MergeColonies() noexcept; @@ -52,11 +59,20 @@ class ORIENTATIONANALYSIS_EXPORT MergeColonies : public GroupFeatures const std::atomic_bool& getCancel(); + int getSeed(int32 newFid) override; + bool determineGrouping(int32 referenceFeature, int32 neighborFeature, int32 newFid) override; + private: DataStructure& m_DataStructure; const MergeColoniesInputValues* m_InputValues = nullptr; const std::atomic_bool& m_ShouldCancel; const IFilter::MessageHandler& m_MessageHandler; + LaueOpsContainer m_OrientationOps; + Int32Array& m_FeatureParentIds; + Int32Array& m_FeaturePhases; + Float32Array& m_AvgQuats; + UInt32Array& m_CrystalStructures; + float32 m_AxisToleranceRad = 0.0; + float32 m_AngleTolerance = 1.0; }; - } // namespace complex diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.cpp index 65adfeefbd..9575b35242 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.cpp @@ -1,6 +1,6 @@ #include "MergeColoniesFilter.hpp" -#include "ComplexCore/Filters/Algorithms/MergeColonies.hpp" +#include "OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp" #include "complex/DataStructure/DataPath.hpp" #include "complex/Filter/Actions/EmptyAction.hpp" From 7c24ab49fc52002f625bb00df7357242d04b9afb Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Wed, 21 Jun 2023 13:13:13 -0400 Subject: [PATCH 7/8] algorithm almost complete - randomness pending --- .../Filters/Algorithms/MergeColonies.cpp | 25 ++++++++----- .../Filters/Algorithms/MergeColonies.hpp | 7 ++-- .../Filters/MergeColoniesFilter.cpp | 36 +++++++++---------- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp index 4051ff7d9a..10aa3cd0dc 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.cpp @@ -138,6 +138,12 @@ MergeColonies::MergeColonies(DataStructure& dataStructure, const IFilter::Messag , m_ShouldCancel(shouldCancel) , m_MessageHandler(mesgHandler) , m_OrientationOps(LaueOps::GetAllOrientationOps()) +, m_FeatureParentIds(dataStructure.getDataRefAs(inputValues->FeatureParentIdsPath)) +, m_FeaturePhases(dataStructure.getDataRefAs(inputValues->FeaturePhasesPath)) +, m_AvgQuats(dataStructure.getDataRefAs(inputValues->AvgQuatsPath)) +, m_CrystalStructures(dataStructure.getDataRefAs(inputValues->CrystalStructuresPath)) +, m_AxisToleranceRad(inputValues->AxisTolerance * Constants::k_PiF / 180.0f) +, m_AngleTolerance(inputValues->AngleTolerance) { } @@ -153,14 +159,6 @@ const std::atomic_bool& MergeColonies::getCancel() // ----------------------------------------------------------------------------- Result<> MergeColonies::operator()() { - m_FeatureParentIds = m_DataStructure.getDataRefAs(m_InputValues->FeatureParentIdsPath); - m_FeaturePhases = m_DataStructure.getDataRefAs(m_InputValues->FeaturePhasesPath); - m_AvgQuats = m_DataStructure.getDataRefAs(m_InputValues->AvgQuatsPath); - m_CrystalStructures = m_DataStructure.getDataRefAs(m_InputValues->CrystalStructuresPath); - - m_AxisToleranceRad = m_InputValues->AxisTolerance * Constants::k_PiF / 180.0f; - m_AngleTolerance = m_InputValues->AngleTolerance; - GroupFeatures::execute(); auto active = m_DataStructure.getDataRefAs(m_InputValues->ActivePath); @@ -187,6 +185,10 @@ Result<> MergeColonies::operator()() } numParents += 1; + m_MessageHandler({IFilter::Message::Type::Info, "Characterizing Colonies Starting"}); + characterize_colonies(); + m_MessageHandler({IFilter::Message::Type::Info, "Characterizing Colonies Complete"}); + if(m_InputValues->RandomizeParentIds) { m_MessageHandler({IFilter::Message::Type::Info, "Randomizing Parent Ids...."}); @@ -355,3 +357,10 @@ bool MergeColonies::determineGrouping(int32 referenceFeature, int32 neighborFeat } return false; } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +void MergeColonies::characterize_colonies() +{ +} diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp index 113129bac2..d44fab7986 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeColonies.hpp @@ -18,9 +18,6 @@ namespace complex { struct ORIENTATIONANALYSIS_EXPORT MergeColoniesInputValues { - bool UseNonContiguousNeighbors; - DataPath NonContiguousNLPath; - DataPath ContiguousNLPath; float32 AxisTolerance; float32 AngleTolerance; DataPath FeaturePhasesPath; @@ -47,7 +44,8 @@ class ORIENTATIONANALYSIS_EXPORT MergeColonies : public GroupFeatures using LaueOpsContainer = std::vector; public: - MergeColonies(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MergeColoniesInputValues* inputValues); + MergeColonies(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MergeColoniesInputValues* inputValues, + GroupFeaturesInputValues* groupInputValues); ~MergeColonies() noexcept; MergeColonies(const MergeColonies&) = delete; @@ -61,6 +59,7 @@ class ORIENTATIONANALYSIS_EXPORT MergeColonies : public GroupFeatures int getSeed(int32 newFid) override; bool determineGrouping(int32 referenceFeature, int32 neighborFeature, int32 newFid) override; + void characterize_colonies(); private: DataStructure& m_DataStructure; diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.cpp index 9575b35242..76ea649d78 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeColoniesFilter.cpp @@ -99,11 +99,6 @@ 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 pUseNonContiguousNeighborsValue = filterArgs.value(k_UseNonContiguousNeighbors_Key); - auto pNonContiguousNeighborListArrayPathValue = filterArgs.value(k_NonContiguousNeighborListArrayPath_Key); - auto pContiguousNeighborListArrayPathValue = filterArgs.value(k_ContiguousNeighborListArrayPath_Key); - auto pAxisToleranceValue = filterArgs.value(k_AxisTolerance_Key); - auto pAngleToleranceValue = filterArgs.value(k_AngleTolerance_Key); auto pFeaturePhasesArrayPathValue = filterArgs.value(k_FeaturePhasesArrayPath_Key); auto pAvgQuatsArrayPathValue = filterArgs.value(k_AvgQuatsArrayPath_Key); auto pFeatureIdsArrayPathValue = filterArgs.value(k_FeatureIdsArrayPath_Key); @@ -128,21 +123,24 @@ Result<> MergeColoniesFilter::executeImpl(DataStructure& dataStructure, const Ar { MergeColoniesInputValues inputValues; - inputValues.UseNonContiguousNeighbors = filterArgs.value(k_UseNonContiguousNeighbors_Key); - inputValues.NonContiguousNeighborListArrayPath = filterArgs.value(k_NonContiguousNeighborListArrayPath_Key); - inputValues.ContiguousNeighborListArrayPath = filterArgs.value(k_ContiguousNeighborListArrayPath_Key); inputValues.AxisTolerance = filterArgs.value(k_AxisTolerance_Key); inputValues.AngleTolerance = filterArgs.value(k_AngleTolerance_Key); - inputValues.FeaturePhasesArrayPath = filterArgs.value(k_FeaturePhasesArrayPath_Key); - inputValues.AvgQuatsArrayPath = filterArgs.value(k_AvgQuatsArrayPath_Key); - inputValues.FeatureIdsArrayPath = filterArgs.value(k_FeatureIdsArrayPath_Key); - inputValues.CellPhasesArrayPath = filterArgs.value(k_CellPhasesArrayPath_Key); - inputValues.CrystalStructuresArrayPath = filterArgs.value(k_CrystalStructuresArrayPath_Key); - inputValues.CellParentIdsArrayName = filterArgs.value(k_CellParentIdsArrayName_Key); - inputValues.NewCellFeatureAttributeMatrixName = filterArgs.value(k_NewCellFeatureAttributeMatrixName_Key); - inputValues.FeatureParentIdsArrayName = filterArgs.value(k_FeatureParentIdsArrayName_Key); - inputValues.ActiveArrayName = filterArgs.value(k_ActiveArrayName_Key); - - return MergeColonies(dataStructure, messageHandler, shouldCancel, &inputValues)(); + inputValues.FeaturePhasesPath = filterArgs.value(k_FeaturePhasesArrayPath_Key); + inputValues.AvgQuatsPath = filterArgs.value(k_AvgQuatsArrayPath_Key); + 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.CellFeatureAMPath = filterArgs.value(k_NewCellFeatureAttributeMatrixName_Key); + inputValues.FeatureParentIdsPath = filterArgs.value(k_FeatureParentIdsArrayName_Key); + inputValues.ActivePath = filterArgs.value(k_ActiveArrayName_Key); + + GroupFeaturesInputValues gpInputValues; + + gpInputValues.UseNonContiguousNeighbors = filterArgs.value(k_UseNonContiguousNeighbors_Key); + gpInputValues.NonContiguousNeighborListArrayPath = filterArgs.value(k_NonContiguousNeighborListArrayPath_Key); + gpInputValues.ContiguousNeighborListArrayPath = filterArgs.value(k_ContiguousNeighborListArrayPath_Key); + + return MergeColonies(dataStructure, messageHandler, shouldCancel, &inputValues, &gpInputValues)(); } } // namespace complex From 7c5dde4d7f8851d523e0369ac9cf1384e9965539 Mon Sep 17 00:00:00 2001 From: nyoungbq Date: Thu, 22 Jun 2023 10:59:01 -0400 Subject: [PATCH 8/8] 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") -//{ -// -// }