From 296afc26bb168718ef6d33c36c4d041300c133ed Mon Sep 17 00:00:00 2001 From: Michael Jackson Date: Wed, 25 Feb 2026 23:45:00 -0500 Subject: [PATCH 1/2] FILT: Promote Compute Grouping Density to SimplnxCore --- CMakeLists.txt | 2 - .../Algorithms/ComputeGroupingDensity.cpp | 224 --------------- .../Algorithms/ComputeGroupingDensity.hpp | 52 ---- .../Filters/ComputeGroupingDensityFilter.cpp | 254 ------------------ .../Filters/ComputeGroupingDensityFilter.hpp | 126 --------- .../SimplnxReviewLegacyUUIDMapping.hpp | 2 - 6 files changed, 660 deletions(-) delete mode 100644 src/SimplnxReview/Filters/Algorithms/ComputeGroupingDensity.cpp delete mode 100644 src/SimplnxReview/Filters/Algorithms/ComputeGroupingDensity.hpp delete mode 100644 src/SimplnxReview/Filters/ComputeGroupingDensityFilter.cpp delete mode 100644 src/SimplnxReview/Filters/ComputeGroupingDensityFilter.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d887159..31ad0bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,6 @@ set(${PLUGIN_NAME}_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}) # These are all the filters in the plugin. All filters should be kept in the # SimplnxReview/src/SimplnxReview/Filters/ directory. set(FilterList - ComputeGroupingDensityFilter ComputeLocalAverageCAxisMisalignmentsFilter ComputeMicroTextureRegionsFilter ComputeSaltykovSizesFilter @@ -44,7 +43,6 @@ set(ActionList # This should be integrated with the `create_simplnx_plugin` function call # ------------------------------------------------------------------------------ set(AlgorithmList - ComputeGroupingDensity ComputeLocalAverageCAxisMisalignments ComputeMicroTextureRegions ComputeSaltykovSizes diff --git a/src/SimplnxReview/Filters/Algorithms/ComputeGroupingDensity.cpp b/src/SimplnxReview/Filters/Algorithms/ComputeGroupingDensity.cpp deleted file mode 100644 index 31e20a2..0000000 --- a/src/SimplnxReview/Filters/Algorithms/ComputeGroupingDensity.cpp +++ /dev/null @@ -1,224 +0,0 @@ -#include "ComputeGroupingDensity.hpp" - -#include "simplnx/DataStructure/DataArray.hpp" -#include "simplnx/DataStructure/NeighborList.hpp" -#include "simplnx/Utilities/MessageHelper.hpp" - -using namespace nx::core; - -namespace -{ -template -struct FindDensitySpecializations -{ - static inline constexpr bool UsingNonContiguousNeighbors = UseNonContiguousNeighbors; - static inline constexpr bool FindingCheckedFeatures = FindCheckedFeatures; -}; - -template > -class FindDensityGrouping -{ -public: - FindDensityGrouping(const std::atomic_bool& shouldCancel, const IFilter::MessageHandler& mesgHandler, const Int32Array& parentIds, const Float32Array& parentVolumes, const Float32Array& volumes, - const Int32NeighborList& contiguousNL, Float32Array& groupingDensities, Int32NeighborList& nonContiguousNL, Int32Array& checkedFeatures) - : m_ShouldCancel(shouldCancel) - , m_MessageHandler(mesgHandler) - , m_ParentIds(parentIds) - , m_ParentVolumes(parentVolumes) - , m_Volumes(volumes) - , m_ContiguousNL(contiguousNL) - , m_GroupingDensities(groupingDensities) - , m_NonContiguousNL(nonContiguousNL) - , m_CheckedFeatures(checkedFeatures) - { - } - ~FindDensityGrouping() noexcept = default; - - FindDensityGrouping(const FindDensityGrouping&) = delete; // Copy Constructor Default Implemented - FindDensityGrouping(FindDensityGrouping&&) = delete; // Move Constructor Not Implemented - FindDensityGrouping& operator=(const FindDensityGrouping&) = delete; // Copy Assignment Not Implemented - FindDensityGrouping& operator=(FindDensityGrouping&&) = delete; // Move Assignment Not Implemented - - Result<> operator()() - { - const auto& parentIds = m_ParentIds.getDataStoreRef(); - const auto& parentVolumes = m_ParentVolumes.getDataStoreRef(); - const auto& volumes = m_Volumes.getDataStoreRef(); - - auto& checkedFeatures = m_CheckedFeatures.getDataStoreRef(); - auto& groupingDensities = m_GroupingDensities.getDataStoreRef(); - - usize numFeatures = volumes.getNumberOfTuples(); - usize numParents = parentVolumes.getNumberOfTuples(); - - int kMax = 1; - if constexpr(FindDensitySpecializations::UsingNonContiguousNeighbors) - { - kMax = 2; - } - - int32 numNeighbors, numNeighborhoods, numCurNeighborList, neigh; - float32 totalCheckVolume, curParentVolume; - std::set totalCheckList = {}; - - std::vector checkedFeatureVolumes(1, 0.0f); - if constexpr(FindDensitySpecializations::FindingCheckedFeatures) - { - // Default value-initialized to zeroes: https://en.cppreference.com/w/cpp/named_req/DefaultInsertable - checkedFeatureVolumes.resize(numFeatures); - } - MessageHelper messageHelper(m_MessageHandler); - ThrottledMessenger throttledMessenger = messageHelper.createThrottledMessenger(); - - for(usize parentIdx = 1; parentIdx < numParents; parentIdx++) - { - throttledMessenger.sendThrottledMessage([&]() { return fmt::format("[{}%]", CalculatePercentComplete(parentIdx, numParents)); }); - - if(m_ShouldCancel) - { - return {}; - } - for(usize j = 1; j < numFeatures; j++) - { - if(parentIds[j] == parentIdx) - { - if(totalCheckList.find(j) == totalCheckList.end()) - // if(std::find(totalCheckList.begin(), totalCheckList.end(), j) == totalCheckList.end()) - { - totalCheckVolume += m_Volumes[j]; - totalCheckList.insert(static_cast(j)); - if constexpr(FindDensitySpecializations::FindingCheckedFeatures) - { - if(parentVolumes[parentIdx] > checkedFeatureVolumes[j]) - { - checkedFeatureVolumes[j] = parentVolumes[parentIdx]; - checkedFeatures[j] = static_cast(parentIdx); - } - } - } - numNeighbors = m_ContiguousNL.getListSize(static_cast(j)); - if constexpr(FindDensitySpecializations::UsingNonContiguousNeighbors) - { - numNeighborhoods = static_cast(m_NonContiguousNL[j].size()); - } - for(int k = 0; k < kMax; k++) - { - if(k == 0) - { - numCurNeighborList = numNeighbors; - } - if constexpr(FindDensitySpecializations::UsingNonContiguousNeighbors) - { - if(k == 1) - { - numCurNeighborList = numNeighborhoods; - } - } - for(int32_t l = 0; l < numCurNeighborList; l++) - { - if(k == 0) - { - bool ok = false; - neigh = m_ContiguousNL.getValue(static_cast(j), l, ok); - } - else if(k == 1) - { - neigh = m_NonContiguousNL[j][l]; - } - if(totalCheckList.find(neigh) == totalCheckList.end()) - // if(std::find(totalCheckList.begin(), totalCheckList.end(), neigh) == totalCheckList.end()) - { - totalCheckVolume += m_Volumes[neigh]; - totalCheckList.insert(neigh); - if constexpr(FindDensitySpecializations::FindingCheckedFeatures) - { - if(parentVolumes[parentIdx] > checkedFeatureVolumes[neigh]) - { - checkedFeatureVolumes[neigh] = parentVolumes[parentIdx]; - checkedFeatures[neigh] = static_cast(parentIdx); - } - } - } - } - } - } - } - curParentVolume = parentVolumes[parentIdx]; - if(totalCheckVolume == 0.0f) - { - groupingDensities[parentIdx] = -1.0f; - } - else - { - groupingDensities[parentIdx] = (curParentVolume / totalCheckVolume); - } - totalCheckList.clear(); - totalCheckVolume = 0.0f; - } - - return {}; - } - -private: - const std::atomic_bool& m_ShouldCancel; - const IFilter::MessageHandler& m_MessageHandler; - const Int32Array& m_ParentIds; - const Float32Array& m_ParentVolumes; - const Float32Array& m_Volumes; - const Int32NeighborList& m_ContiguousNL; - Float32Array& m_GroupingDensities; - Int32NeighborList& m_NonContiguousNL; - Int32Array& m_CheckedFeatures; -}; -} // namespace - -// ----------------------------------------------------------------------------- -ComputeGroupingDensity::ComputeGroupingDensity(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, - ComputeGroupingDensityInputValues* inputValues) -: m_DataStructure(dataStructure) -, m_InputValues(inputValues) -, m_ShouldCancel(shouldCancel) -, m_MessageHandler(mesgHandler) -{ -} - -// ----------------------------------------------------------------------------- -const std::atomic_bool& ComputeGroupingDensity::getCancel() -{ - return m_ShouldCancel; -} - -// ----------------------------------------------------------------------------- -Result<> ComputeGroupingDensity::operator()() -{ - auto& parentIds = m_DataStructure.getDataRefAs(m_InputValues->ParentIdsPath); - auto& parentVolumes = m_DataStructure.getDataRefAs(m_InputValues->ParentVolumesPath); - auto& volumes = m_DataStructure.getDataRefAs(m_InputValues->VolumesPath); - auto& contiguousNL = m_DataStructure.getDataRefAs>(m_InputValues->ContiguousNLPath); - auto& groupingDensities = m_DataStructure.getDataRefAs(m_InputValues->GroupingDensitiesPath); - - // These may or may not be empty depending on the parameters - auto& nonContiguousNL = m_DataStructure.getDataRefAs>(m_InputValues->NonContiguousNLPath); - auto& checkedFeatures = m_DataStructure.getDataRefAs(m_InputValues->CheckedFeaturesPath); - - if(m_InputValues->UseNonContiguousNeighbors) - { - if(m_InputValues->FindCheckedFeatures) - { - return ::FindDensityGrouping>(getCancel(), m_MessageHandler, parentIds, parentVolumes, volumes, contiguousNL, groupingDensities, nonContiguousNL, - checkedFeatures)(); - } - return ::FindDensityGrouping>(getCancel(), m_MessageHandler, parentIds, parentVolumes, volumes, contiguousNL, groupingDensities, nonContiguousNL, - checkedFeatures)(); - } - else if(m_InputValues->FindCheckedFeatures) - { - return ::FindDensityGrouping>(getCancel(), m_MessageHandler, parentIds, parentVolumes, volumes, contiguousNL, groupingDensities, nonContiguousNL, - checkedFeatures)(); - } - else - { - return ::FindDensityGrouping>(getCancel(), m_MessageHandler, parentIds, parentVolumes, volumes, contiguousNL, groupingDensities, nonContiguousNL, - checkedFeatures)(); - } -} diff --git a/src/SimplnxReview/Filters/Algorithms/ComputeGroupingDensity.hpp b/src/SimplnxReview/Filters/Algorithms/ComputeGroupingDensity.hpp deleted file mode 100644 index 3b2dc60..0000000 --- a/src/SimplnxReview/Filters/Algorithms/ComputeGroupingDensity.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include "SimplnxReview/SimplnxReview_export.hpp" - -#include "simplnx/DataStructure/DataPath.hpp" -#include "simplnx/DataStructure/DataStructure.hpp" -#include "simplnx/Filter/IFilter.hpp" - -namespace nx::core -{ - -struct SIMPLNXREVIEW_EXPORT ComputeGroupingDensityInputValues -{ - DataPath VolumesPath; - DataPath ContiguousNLPath; - bool UseNonContiguousNeighbors; - DataPath NonContiguousNLPath; - DataPath ParentIdsPath; - DataPath ParentVolumesPath; - bool FindCheckedFeatures; - DataPath CheckedFeaturesPath; - DataPath GroupingDensitiesPath; -}; - -/** - * @class ComputeGroupingDensity - * @brief This filter determines the average C-axis location of each Feature. - */ - -class SIMPLNXREVIEW_EXPORT ComputeGroupingDensity -{ -public: - ComputeGroupingDensity(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, ComputeGroupingDensityInputValues* inputValues); - ~ComputeGroupingDensity() noexcept = default; - - ComputeGroupingDensity(const ComputeGroupingDensity&) = delete; - ComputeGroupingDensity(ComputeGroupingDensity&&) noexcept = delete; - ComputeGroupingDensity& operator=(const ComputeGroupingDensity&) = delete; - ComputeGroupingDensity& operator=(ComputeGroupingDensity&&) noexcept = delete; - - Result<> operator()(); - - const std::atomic_bool& getCancel(); - -private: - DataStructure& m_DataStructure; - const ComputeGroupingDensityInputValues* m_InputValues = nullptr; - const std::atomic_bool& m_ShouldCancel; - const IFilter::MessageHandler& m_MessageHandler; -}; - -} // namespace nx::core diff --git a/src/SimplnxReview/Filters/ComputeGroupingDensityFilter.cpp b/src/SimplnxReview/Filters/ComputeGroupingDensityFilter.cpp deleted file mode 100644 index a2f79ff..0000000 --- a/src/SimplnxReview/Filters/ComputeGroupingDensityFilter.cpp +++ /dev/null @@ -1,254 +0,0 @@ -#include "ComputeGroupingDensityFilter.hpp" - -#include "SimplnxReview/Filters/Algorithms/ComputeGroupingDensity.hpp" - -#include "simplnx/DataStructure/AttributeMatrix.hpp" -#include "simplnx/DataStructure/DataPath.hpp" -#include "simplnx/Filter/Actions/CreateArrayAction.hpp" -#include "simplnx/Filter/Actions/CreateNeighborListAction.hpp" -#include "simplnx/Filter/Actions/DeleteDataAction.hpp" -#include "simplnx/Parameters/ArraySelectionParameter.hpp" -#include "simplnx/Parameters/BoolParameter.hpp" -#include "simplnx/Parameters/DataObjectNameParameter.hpp" -#include "simplnx/Parameters/NeighborListSelectionParameter.hpp" -#include "simplnx/Utilities/SIMPLConversion.hpp" - -using namespace nx::core; - -namespace -{ -const DataPath k_ThrowawayCheckedFeatures = DataPath({"HiddenTempCheckedFeatures"}); -const DataPath k_ThrowawayNonContiguous = DataPath({"HiddenContiguousNL"}); -} // namespace - -namespace nx::core -{ -//------------------------------------------------------------------------------ -std::string ComputeGroupingDensityFilter::name() const -{ - return FilterTraits::name.str(); -} - -//------------------------------------------------------------------------------ -std::string ComputeGroupingDensityFilter::className() const -{ - return FilterTraits::className; -} - -//------------------------------------------------------------------------------ -Uuid ComputeGroupingDensityFilter::uuid() const -{ - return FilterTraits::uuid; -} - -//------------------------------------------------------------------------------ -std::string ComputeGroupingDensityFilter::humanName() const -{ - return "Compute Grouping Densities"; -} - -//------------------------------------------------------------------------------ -std::vector ComputeGroupingDensityFilter::defaultTags() const -{ - return {className(), "Statistics", "Reconstruction"}; -} - -//------------------------------------------------------------------------------ -Parameters ComputeGroupingDensityFilter::parameters() const -{ - Parameters params; - // Create the parameter descriptors that are needed for this filter - params.insertSeparator(Parameters::Separator{"Input Parameter(s)"}); - params.insertLinkableParameter(std::make_unique(k_FindCheckedFeatures_Key, "Find Checked Features", "Find checked features", false)); - - params.insertSeparator(Parameters::Separator{"Non-Contiguous Neighborhood Option"}); - params.insertLinkableParameter(std::make_unique(k_UseNonContiguousNeighbors_Key, "Use Non-Contiguous Neighbors", "Use non-contiguous neighborhoods for computations", false)); - params.insert(std::make_unique(k_NonContiguousNeighborListArrayPath_Key, "Non-Contiguous Neighborhoods", "List of non-contiguous neighbors for each Feature.", - DataPath{}, NeighborListSelectionParameter::AllowedTypes{DataType::int32})); - - params.insertSeparator(Parameters::Separator{"Input Cell Data"}); - params.insert(std::make_unique(k_ParentIdsPath_Key, "Parent Ids", "Input Cell level ParentIds", DataPath{}, ArraySelectionParameter::AllowedTypes{DataType::int32}, - ArraySelectionParameter::AllowedComponentShapes{{1}})); - - params.insertSeparator(Parameters::Separator{"Input Feature Data"}); - params.insert(std::make_unique(k_VolumesArrayPath_Key, "Volumes", "The Feature Volumes Data Array", DataPath{}, - ArraySelectionParameter::AllowedTypes{nx::core::DataType::float32}, ArraySelectionParameter::AllowedComponentShapes{{1}})); - - params.insert(std::make_unique(k_ContiguousNeighborListArrayPath_Key, "Contiguous Neighbor List", "List of contiguous neighbors for each Feature.", DataPath{}, - NeighborListSelectionParameter::AllowedTypes{DataType::int32})); - - params.insert(std::make_unique(k_ParentVolumesPath_Key, "Parent Volumes", "Input feature level parent volume data array", DataPath{}, - ArraySelectionParameter::AllowedTypes{DataType::float32}, ArraySelectionParameter::AllowedComponentShapes{{1}})); - - params.insertSeparator(Parameters::Separator{"Output Feature Data"}); - - params.insert(std::make_unique(k_CheckedFeaturesName_Key, "Checked Features Name", "Output feature level data array to hold 'Checked Features' values", "Checked Features")); - params.insert( - std::make_unique(k_GroupingDensitiesName_Key, "Grouping Densities Name", "Output feature level data array to hold 'Grouping Densities' values", "Grouping Densities")); - - // Link params - params.linkParameters(k_UseNonContiguousNeighbors_Key, k_NonContiguousNeighborListArrayPath_Key, true); - params.linkParameters(k_FindCheckedFeatures_Key, k_CheckedFeaturesName_Key, true); - - return params; -} - -//------------------------------------------------------------------------------ -IFilter::UniquePointer ComputeGroupingDensityFilter::clone() const -{ - return std::make_unique(); -} - -//------------------------------------------------------------------------------ -IFilter::VersionType ComputeGroupingDensityFilter::parametersVersion() const -{ - return 1; -} - -//------------------------------------------------------------------------------ -IFilter::PreflightResult ComputeGroupingDensityFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, - const std::atomic_bool& shouldCancel, const ExecutionContext& executionContext) const -{ - auto pParentIdsPath = filterArgs.value(k_ParentIdsPath_Key); - auto pParentVolumesPath = filterArgs.value(k_ParentVolumesPath_Key); - auto pContiguousNLPath = filterArgs.value(k_ContiguousNeighborListArrayPath_Key); - auto pVolumesPath = filterArgs.value(k_VolumesArrayPath_Key); - auto pGroupingDensitiesName = filterArgs.value(k_GroupingDensitiesName_Key); - - auto pUseNonContiguousNeighbors = filterArgs.value(k_UseNonContiguousNeighbors_Key); - auto pNonContiguousNLPath = filterArgs.value(k_NonContiguousNeighborListArrayPath_Key); - auto pFindCheckedFeatures = filterArgs.value(k_FindCheckedFeatures_Key); - auto pCheckedFeaturesName = filterArgs.value(k_CheckedFeaturesName_Key); - - Result resultOutputActions; - std::vector preflightUpdatedValues; - - auto* pParentAM = dataStructure.getDataAs(pParentVolumesPath.getParent()); - if(pParentAM == nullptr) - { - return MakePreflightErrorResult(-15670, fmt::format("Parent Volumes [{}] must be stored in an Attribute Matrix.", pParentVolumesPath.toString())); - } - { - DataPath groupingDataPath = pParentVolumesPath.replaceName(pGroupingDensitiesName); - auto createArrayAction = std::make_unique(nx::core::DataType::float32, pParentAM->getShape(), std::vector{1}, groupingDataPath); - resultOutputActions.value().appendAction(std::move(createArrayAction)); - } - - auto* pFeatureAM = dataStructure.getDataAs(pVolumesPath.getParent()); - if(pFeatureAM == nullptr) - { - return MakePreflightErrorResult(-15671, fmt::format("Feature Volumes [{}] must be stored in an Attribute Matrix.", pVolumesPath.toString())); - } - - if(pFindCheckedFeatures) - { - DataPath checkedFeaturesPath = pVolumesPath.replaceName(pCheckedFeaturesName); - { - auto createArrayAction = std::make_unique(nx::core::DataType::int32, pFeatureAM->getShape(), std::vector{1}, checkedFeaturesPath); - resultOutputActions.value().appendAction(std::move(createArrayAction)); - } - } - else - { - { - auto createArrayAction = std::make_unique(nx::core::DataType::int32, ShapeType{1}, ShapeType{1}, k_ThrowawayCheckedFeatures); - resultOutputActions.value().appendAction(std::move(createArrayAction)); - } - { - auto removeAction = std::make_unique(k_ThrowawayCheckedFeatures); - resultOutputActions.value().appendDeferredAction(std::move(removeAction)); - } - } - - if(!pUseNonContiguousNeighbors) - { - { - auto createArrayAction = std::make_unique(nx::core::DataType::int32, ShapeType{1}, k_ThrowawayNonContiguous); - resultOutputActions.value().appendAction(std::move(createArrayAction)); - } - { - auto removeAction = std::make_unique(k_ThrowawayNonContiguous); - resultOutputActions.value().appendDeferredAction(std::move(removeAction)); - } - } - - preflightUpdatedValues.push_back({"WARNING: This filter is experimental in nature and has not had any testing, validation or verification. Use at your own risk"}); - resultOutputActions.warnings().push_back({-65432, "WARNING: This filter is experimental in nature and has not had any testing, validation or verification. Use at your own risk"}); - - return {std::move(resultOutputActions), std::move(preflightUpdatedValues)}; -} - -//------------------------------------------------------------------------------ -Result<> ComputeGroupingDensityFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, - const std::atomic_bool& shouldCancel, const ExecutionContext& executionContext) const -{ - ComputeGroupingDensityInputValues inputValues; - - inputValues.ParentIdsPath = filterArgs.value(k_ParentIdsPath_Key); - inputValues.ParentVolumesPath = filterArgs.value(k_ParentVolumesPath_Key); - inputValues.ContiguousNLPath = filterArgs.value(k_ContiguousNeighborListArrayPath_Key); - inputValues.VolumesPath = filterArgs.value(k_VolumesArrayPath_Key); - inputValues.GroupingDensitiesPath = inputValues.ParentVolumesPath.replaceName(filterArgs.value(k_GroupingDensitiesName_Key)); - - inputValues.UseNonContiguousNeighbors = filterArgs.value(k_UseNonContiguousNeighbors_Key); - if(inputValues.UseNonContiguousNeighbors) - { - inputValues.NonContiguousNLPath = filterArgs.value(k_NonContiguousNeighborListArrayPath_Key); - } - else - { - inputValues.NonContiguousNLPath = k_ThrowawayNonContiguous; - } - - inputValues.FindCheckedFeatures = filterArgs.value(k_FindCheckedFeatures_Key); - if(inputValues.FindCheckedFeatures) - { - inputValues.CheckedFeaturesPath = inputValues.VolumesPath.replaceName(filterArgs.value(k_CheckedFeaturesName_Key)); - } - else - { - inputValues.CheckedFeaturesPath = k_ThrowawayCheckedFeatures; - } - - return ComputeGroupingDensity(dataStructure, messageHandler, shouldCancel, &inputValues)(); -} - -namespace -{ -namespace SIMPL -{ -constexpr StringLiteral k_CheckedFeaturesArrayNameKey = "CheckedFeaturesArrayName"; -constexpr StringLiteral k_ContiguousNeighborListArrayPathKey = "ContiguousNeighborListArrayPath"; -constexpr StringLiteral k_FindCheckedFeaturesKey = "FindCheckedFeatures"; -constexpr StringLiteral k_NonContiguousNeighborListArrayPathKey = "NonContiguousNeighborListArrayPath"; -constexpr StringLiteral k_ParentDensitiesArrayNameKey = "ParentDensitiesArrayName"; -constexpr StringLiteral k_ParentIdsArrayPathKey = "ParentIdsArrayPath"; -constexpr StringLiteral k_ParentVolumesArrayPathKey = "ParentVolumesArrayPath"; -constexpr StringLiteral k_UseNonContiguousNeighborsKey = "UseNonContiguousNeighbors"; -constexpr StringLiteral k_VolumesArrayPathKey = "VolumesArrayPath"; -} // namespace SIMPL -} // namespace - -Result ComputeGroupingDensityFilter::FromSIMPLJson(const nlohmann::json& json) -{ - Arguments args = ComputeGroupingDensityFilter().getDefaultArguments(); - - std::vector> results; - - results.push_back(SIMPLConversion::ConvertParameter(args, json, SIMPL::k_CheckedFeaturesArrayNameKey, k_CheckedFeaturesName_Key)); - results.push_back( - SIMPLConversion::ConvertParameter(args, json, SIMPL::k_ContiguousNeighborListArrayPathKey, k_ContiguousNeighborListArrayPath_Key)); - results.push_back(SIMPLConversion::ConvertParameter(args, json, SIMPL::k_FindCheckedFeaturesKey, k_FindCheckedFeatures_Key)); - results.push_back(SIMPLConversion::ConvertParameter(args, json, SIMPL::k_NonContiguousNeighborListArrayPathKey, - k_NonContiguousNeighborListArrayPath_Key)); - results.push_back(SIMPLConversion::ConvertParameter(args, json, SIMPL::k_ParentDensitiesArrayNameKey, k_GroupingDensitiesName_Key)); - results.push_back(SIMPLConversion::ConvertParameter(args, json, SIMPL::k_ParentIdsArrayPathKey, k_ParentIdsPath_Key)); - results.push_back(SIMPLConversion::ConvertParameter(args, json, SIMPL::k_ParentVolumesArrayPathKey, k_ParentVolumesPath_Key)); - results.push_back(SIMPLConversion::ConvertParameter(args, json, SIMPL::k_UseNonContiguousNeighborsKey, k_UseNonContiguousNeighbors_Key)); - results.push_back(SIMPLConversion::ConvertParameter(args, json, SIMPL::k_VolumesArrayPathKey, k_VolumesArrayPath_Key)); - - Result<> conversionResult = MergeResults(std::move(results)); - - return ConvertResultTo(std::move(conversionResult), std::move(args)); -} -} // namespace nx::core diff --git a/src/SimplnxReview/Filters/ComputeGroupingDensityFilter.hpp b/src/SimplnxReview/Filters/ComputeGroupingDensityFilter.hpp deleted file mode 100644 index 0614178..0000000 --- a/src/SimplnxReview/Filters/ComputeGroupingDensityFilter.hpp +++ /dev/null @@ -1,126 +0,0 @@ -#pragma once - -#include "SimplnxReview/SimplnxReview_export.hpp" - -#include "simplnx/Filter/FilterTraits.hpp" -#include "simplnx/Filter/IFilter.hpp" - -namespace nx::core -{ -/** - * @class ComputeGroupingDensityFilter - * @brief This filter determines the average C-axis location of each Feature - */ -class SIMPLNXREVIEW_EXPORT ComputeGroupingDensityFilter : public IFilter -{ -public: - ComputeGroupingDensityFilter() = default; - ~ComputeGroupingDensityFilter() noexcept override = default; - - ComputeGroupingDensityFilter(const ComputeGroupingDensityFilter&) = delete; - ComputeGroupingDensityFilter(ComputeGroupingDensityFilter&&) noexcept = delete; - - ComputeGroupingDensityFilter& operator=(const ComputeGroupingDensityFilter&) = delete; - ComputeGroupingDensityFilter& operator=(ComputeGroupingDensityFilter&&) noexcept = delete; - - // Parameter Keys - static constexpr StringLiteral k_VolumesArrayPath_Key = "volumes_path"; - static constexpr StringLiteral k_ContiguousNeighborListArrayPath_Key = "contiguous_neighbor_list_path"; - static constexpr StringLiteral k_UseNonContiguousNeighbors_Key = "use_non_contiguous_neighbors"; - static constexpr StringLiteral k_NonContiguousNeighborListArrayPath_Key = "non_contiguous_neighbor_list_path"; - static constexpr StringLiteral k_ParentIdsPath_Key = "parent_ids_path"; - static constexpr StringLiteral k_ParentVolumesPath_Key = "parent_volumes_path"; - static constexpr StringLiteral k_FindCheckedFeatures_Key = "find_checked_features"; - static constexpr StringLiteral k_CheckedFeaturesName_Key = "checked_features_name"; - static constexpr StringLiteral k_GroupingDensitiesName_Key = "grouping_densities_name"; - - /** - * @brief Reads SIMPL json and converts it simplnx Arguments. - * @param json - * @return Result - */ - static Result FromSIMPLJson(const nlohmann::json& json); - - /** - * @brief Returns the name of the filter. - * @return - */ - std::string name() const override; - - /** - * @brief Returns the C++ classname of this filter. - * @return - */ - std::string className() const override; - - /** - * @brief Returns the uuid of the filter. - * @return - */ - Uuid uuid() const override; - - /** - * @brief Returns the human-readable name of the filter. - * @return - */ - std::string humanName() const override; - - /** - * @brief Returns the default tags for this filter. - * @return - */ - std::vector defaultTags() const override; - - /** - * @brief Returns the parameters of the filter (i.e. its inputs) - * @return - */ - Parameters parameters() const override; - - /** - * @brief Returns parameters version integer. - * Initial version should always be 1. - * Should be incremented everytime the parameters change. - * @return VersionType - */ - VersionType parametersVersion() const override; - - /** - * @brief Returns a copy of the filter. - * @return - */ - UniquePointer clone() const override; - -protected: - /** - * @brief Takes in a DataStructure and checks that the filter can be run on it with the given arguments. - * Returns any warnings/errors. Also returns the changes that would be applied to the DataStructure. - * Some parts of the actions may not be completely filled out if all the required information is not available at preflight time. - * @param dataStructure The input DataStructure instance - * @param filterArgs These are the input values for each parameter that is required for the filter - * @param messageHandler The MessageHandler object - * @param shouldCancel Atomic boolean value that can be checked to cancel the filter - * @param executionContext The ExecutionContext that can be used to determine the correct absolute path from a relative path - * @return Returns a Result object with error or warning values if any of those occurred during execution of this function - */ - PreflightResult preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel, - const ExecutionContext& executionContext) const override; - - /** - * @brief Applies the filter's algorithm to the DataStructure with the given arguments. Returns any warnings/errors. - * On failure, there is no guarantee that the DataStructure is in a correct state. - * @param dataStructure The input DataStructure instance - * @param filterArgs These are the input values for each parameter that is required for the filter - * @param pipelineNode The node in the pipeline that is being executed - * @param messageHandler The MessageHandler object - * @param shouldCancel Atomic boolean value that can be checked to cancel the filter - * @param executionContext The ExecutionContext that can be used to determine the correct absolute path from a relative path - * @return Returns a Result object with error or warning values if any of those occurred during execution of this function - */ - Result<> executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel, - const ExecutionContext& executionContext) const override; -}; -} // namespace nx::core - -SIMPLNX_DEF_FILTER_TRAITS(nx::core, ComputeGroupingDensityFilter, "ff46afcf-de32-4f37-98bc-8f0fd4b3c122"); -/* LEGACY UUID FOR THIS FILTER 708be082-8b08-4db2-94be-52781ed4d53d */ diff --git a/src/SimplnxReview/SimplnxReviewLegacyUUIDMapping.hpp b/src/SimplnxReview/SimplnxReviewLegacyUUIDMapping.hpp index d56f487..6e8ca58 100644 --- a/src/SimplnxReview/SimplnxReviewLegacyUUIDMapping.hpp +++ b/src/SimplnxReview/SimplnxReviewLegacyUUIDMapping.hpp @@ -10,7 +10,6 @@ #include "SimplnxReview/Filters/ComputeSaltykovSizesFilter.hpp" #include "SimplnxReview/Filters/ComputeMicroTextureRegionsFilter.hpp" #include "SimplnxReview/Filters/ComputeLocalAverageCAxisMisalignmentsFilter.hpp" -#include "SimplnxReview/Filters/ComputeGroupingDensityFilter.hpp" // @@__HEADER__TOKEN__DO__NOT__DELETE__@@ @@ -27,7 +26,6 @@ namespace nx::core {nx::core::Uuid::FromString("cc76cffe-81ad-5ece-be2a-ce127c5fa6d7").value(), {nx::core::FilterTraits::uuid, &ComputeSaltykovSizesFilter::FromSIMPLJson}}, // FindSaltykovSizes {nx::core::Uuid::FromString("90f8e3b1-2460-5862-95a1-a9e06f5ee75e").value(), {nx::core::FilterTraits::uuid, &ComputeMicroTextureRegionsFilter::FromSIMPLJson}}, // FindMicroTextureRegions {nx::core::Uuid::FromString("49b2dd47-bb29-50d4-a051-5bad9b6b9f80").value(), {nx::core::FilterTraits::uuid, &ComputeLocalAverageCAxisMisalignmentsFilter::FromSIMPLJson}}, // FindLocalAverageCAxisMisalignments - {nx::core::Uuid::FromString("708be082-8b08-4db2-94be-52781ed4d53d").value(), {nx::core::FilterTraits::uuid, &ComputeGroupingDensityFilter::FromSIMPLJson}}, // FindGroupingDensity // @@__MAP__UPDATE__TOKEN__DO__NOT__DELETE__@@ }; From 7fdbb2f944689069071a12d509a90da95ec8eb7e Mon Sep 17 00:00:00 2001 From: Michael Jackson Date: Wed, 10 Dec 2025 10:21:13 -0500 Subject: [PATCH 2/2] FILT: Compute Direction Vectors filter has been added. No unit test has been created. --- CMakeLists.txt | 4 + docs/ComputeDirectionVectorsFilter.md | 28 ++ .../Algorithms/ComputeDirectionVectors.cpp | 253 ++++++++++++++++++ .../Algorithms/ComputeDirectionVectors.hpp | 53 ++++ .../Filters/ComputeDirectionVectorsFilter.cpp | 138 ++++++++++ .../Filters/ComputeDirectionVectorsFilter.hpp | 117 ++++++++ 6 files changed, 593 insertions(+) create mode 100644 docs/ComputeDirectionVectorsFilter.md create mode 100644 src/SimplnxReview/Filters/Algorithms/ComputeDirectionVectors.cpp create mode 100644 src/SimplnxReview/Filters/Algorithms/ComputeDirectionVectors.hpp create mode 100644 src/SimplnxReview/Filters/ComputeDirectionVectorsFilter.cpp create mode 100644 src/SimplnxReview/Filters/ComputeDirectionVectorsFilter.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 31ad0bd..215c9c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,8 @@ set(${PLUGIN_NAME}_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}) # These are all the filters in the plugin. All filters should be kept in the # SimplnxReview/src/SimplnxReview/Filters/ directory. set(FilterList + ComputeDirectionVectorsFilter + ComputeGroupingDensityFilter ComputeLocalAverageCAxisMisalignmentsFilter ComputeMicroTextureRegionsFilter ComputeSaltykovSizesFilter @@ -43,6 +45,8 @@ set(ActionList # This should be integrated with the `create_simplnx_plugin` function call # ------------------------------------------------------------------------------ set(AlgorithmList + ComputeDirectionVectors + ComputeGroupingDensity ComputeLocalAverageCAxisMisalignments ComputeMicroTextureRegions ComputeSaltykovSizes diff --git a/docs/ComputeDirectionVectorsFilter.md b/docs/ComputeDirectionVectorsFilter.md new file mode 100644 index 0000000..3fed27a --- /dev/null +++ b/docs/ComputeDirectionVectorsFilter.md @@ -0,0 +1,28 @@ +# Compute Direction Vectors + +**THIS FILTER IS UNTESTED, UNVERIFIED AND UNVALIDATED. IT IS AN EXPERIMENTAL FILTER THAT IS UNDERGOING LONG TERM DEVELOPMENT +AND TESTING. USE AT YOUR OWN RISK** + +## Group (Subgroup) + +Visualization Helpers + +## Description + +This **Filter** computes the crystallographic Z Axis in a cartesian coordinate system. + +This results from this filter can then be used in various visualization applications to visually inspect the crystallographic system. + +% Auto generated parameter table will be inserted here + +## References + +## Example Pipelines + +## License & Copyright + +Please see the description file distributed with this **Plugin** + +## DREAM3D-NX Help + +If you need help, need to file a bug report or want to request a new feature, please head over to the [DREAM3DNX-Issues](https://github.com/BlueQuartzSoftware/DREAM3DNX-Issues/discussions) GitHub site where the community of DREAM3D-NX users can help answer your questions. diff --git a/src/SimplnxReview/Filters/Algorithms/ComputeDirectionVectors.cpp b/src/SimplnxReview/Filters/Algorithms/ComputeDirectionVectors.cpp new file mode 100644 index 0000000..71bab35 --- /dev/null +++ b/src/SimplnxReview/Filters/Algorithms/ComputeDirectionVectors.cpp @@ -0,0 +1,253 @@ +#include "ComputeDirectionVectors.hpp" + +#include "EbsdLib/Core/Orientation.hpp" +#include "EbsdLib/Orientation/AxisAngle.hpp" +#include "EbsdLib/Orientation/Euler.hpp" +#include "EbsdLib/Orientation/OrientationMatrix.hpp" +#include "EbsdLib/Orientation/Quaternion.hpp" +#include "EbsdLib/Orientation/Rodrigues.hpp" + +#include + +#include "simplnx/Common/Constants.hpp" +#include "simplnx/DataStructure/DataArray.hpp" +#include "simplnx/Utilities/DataArrayUtilities.hpp" +#include "simplnx/Utilities/ParallelTaskAlgorithm.hpp" + +using namespace nx::core; + +namespace +{ +/** + * + * @param latticeParameters The lattice Parameters in the order, a, b, c, alpha, beta, gamma. Note that alpha, beta, gamma are all stored as degrees. + * @return + */ +template +ebsdlib::Matrix3X3 DirectStructureMatrix(const Vec3& latticeParametersLengths, const Vec3& latticeParametersAngles) +{ + /* This code is taken from EMsoftOO/mod_crystallography.f90 - computeMatrices() function */ + + T a = latticeParametersLengths[0]; + T b = latticeParametersLengths[1]; + T c = latticeParametersLengths[2]; + T alpha = latticeParametersAngles[0]; + T beta = latticeParametersAngles[1]; + T gamma = latticeParametersAngles[2]; + + // auxiliary variables for the various tensors + T pirad = Constants::k_PiOver180F; + T ca = std::cos(pirad * alpha); + T cb = std::cos(pirad * beta); + T cg = std::cos(pirad * gamma); + T sg = std::sin(pirad * gamma); + + // cell volume via the determinant of dmt + T det = (a * b * c) * (a * b * c) * (1.0f - ca * ca - cb * cb - cg * cg + 1.0f * ca * cb * cg); + T vol = std::sqrt(det); + + ebsdlib::Matrix3X3 dsm; + dsm[0] = a; + dsm[1] = b * cg; + dsm[2] = c * cb; + dsm[3] = 0.0; + dsm[4] = b * sg; + dsm[5] = -c * (cb * cg - ca) / sg; + dsm[6] = 0.0; + dsm[7] = 0.0; + dsm[8] = vol / (a * b * sg); + return dsm; +} + +template +class ComputeDirectionVectorsImpl +{ +public: + ComputeDirectionVectorsImpl(const DataArray& inputOrientationsArray, ebsdlib::orientations::Type inputRepType, const ebsdlib::Matrix3X1& cartesian, Float32Array& outputArray, + const std::atomic_bool& shouldCancel) + : m_InputOrientationsArray(inputOrientationsArray) + , m_InputRepType(inputRepType) + , m_Cartesian(cartesian) + , m_OutputArray(outputArray) + , m_ShouldCancel(shouldCancel) + { + } + ~ComputeDirectionVectorsImpl() = default; + + ComputeDirectionVectorsImpl(const ComputeDirectionVectorsImpl&) = default; + ComputeDirectionVectorsImpl(ComputeDirectionVectorsImpl&&) noexcept = default; + ComputeDirectionVectorsImpl& operator=(const ComputeDirectionVectorsImpl&) = delete; + ComputeDirectionVectorsImpl& operator=(ComputeDirectionVectorsImpl&&) noexcept = delete; + + void convert(usize start, usize end) const + { + // For each orientation matrix, convert to gmatrix, transpose, and multiply by the cartesian point. + // The result is the direction vector that will be stored in the output array. + + const auto& inputOrientationsDataStore = m_InputOrientationsArray.template getIDataStoreRefAs>(); + auto& outputDataStore = m_OutputArray.template getIDataStoreRefAs>(); + ebsdlib::OrientationMatrix om; + for(usize i = start; i < end; i++) + { + if(m_ShouldCancel) + { + return; + } + + switch(m_InputRepType) + { + case ebsdlib::orientations::Type::Euler: { + // Euler has 3 components + om = ebsdlib::Euler(inputOrientationsDataStore.getValue(i * 3), inputOrientationsDataStore.getValue(i * 3 + 1), inputOrientationsDataStore.getValue(i * 3 + 2)).toOrientationMatrix(); + break; + } + case ebsdlib::orientations::Type::OrientationMatrix: { + // OrientationMatrix has 9 components + om = ebsdlib::OrientationMatrix(inputOrientationsDataStore.getValue(i * 3), inputOrientationsDataStore.getValue(i * 3 + 1), inputOrientationsDataStore.getValue(i * 3 + 2), + inputOrientationsDataStore.getValue(i * 3 + 3), inputOrientationsDataStore.getValue(i * 3 + 4), inputOrientationsDataStore.getValue(i * 3 + 5), + inputOrientationsDataStore.getValue(i * 3 + 6), inputOrientationsDataStore.getValue(i * 3 + 7), inputOrientationsDataStore.getValue(i * 3 + 8)); + break; + } + case ebsdlib::orientations::Type::Rodrigues: { + // Rodrigues has 4 components + om = ebsdlib::Rodrigues(inputOrientationsDataStore.getValue(i * 3), inputOrientationsDataStore.getValue(i * 3 + 1), inputOrientationsDataStore.getValue(i * 3 + 2), + inputOrientationsDataStore.getValue(i * 3 + 3)) + .toOrientationMatrix(); + break; + } + case ebsdlib::orientations::Type::Quaternion: { + // Quaternion has 4 components + om = ebsdlib::Quaternion(inputOrientationsDataStore.getValue(i * 3), inputOrientationsDataStore.getValue(i * 3 + 1), inputOrientationsDataStore.getValue(i * 3 + 2), + inputOrientationsDataStore.getValue(i * 3 + 3)) + .toOrientationMatrix(); + break; + } + case ebsdlib::orientations::Type::AxisAngle: { + // AxisAngle has 4 components + om = ebsdlib::AxisAngle(inputOrientationsDataStore.getValue(i * 3), inputOrientationsDataStore.getValue(i * 3 + 1), inputOrientationsDataStore.getValue(i * 3 + 2), + inputOrientationsDataStore.getValue(i * 3 + 3)) + .toOrientationMatrix(); + break; + } + case ebsdlib::orientations::Type::Homochoric: { + // Homochoric has 3 components + om = ebsdlib::Homochoric(inputOrientationsDataStore.getValue(i * 3), inputOrientationsDataStore.getValue(i * 3 + 1), inputOrientationsDataStore.getValue(i * 3 + 2)).toOrientationMatrix(); + break; + } + case ebsdlib::orientations::Type::Cubochoric: { + // Cubochoric has 3 components + om = ebsdlib::Cubochoric(inputOrientationsDataStore.getValue(i * 3), inputOrientationsDataStore.getValue(i * 3 + 1), inputOrientationsDataStore.getValue(i * 3 + 2)).toOrientationMatrix(); + break; + } + case ebsdlib::orientations::Type::Stereographic: { + // Stereographic has 3 components + om = + ebsdlib::Stereographic(inputOrientationsDataStore.getValue(i * 3), inputOrientationsDataStore.getValue(i * 3 + 1), inputOrientationsDataStore.getValue(i * 3 + 2)).toOrientationMatrix(); + break; + } + case ebsdlib::orientations::Type::Unknown: { + throw std::runtime_error("Unknown Orientation Representation Type. This should not happen, contact the developers."); + } + } + + ebsdlib::Matrix3X1 point = om.toGMatrix().transpose() * m_Cartesian; + std::copy(point.data(), point.data() + 3, outputDataStore.begin() + i * outputDataStore.getNumberOfComponents()); + + // std::cout << fmt::format("Cartesian: ({}, {}, {})", m_Cartesian[0], m_Cartesian[1], m_Cartesian[2]) << std::endl; + // std::cout << fmt::format("Point: ({}, {}, {})", point[0], point[1], point[2]) << std::endl; + } + } + + void operator()() const + { + convert(0, m_InputOrientationsArray.getNumberOfTuples()); + } + +private: + const DataArray& m_InputOrientationsArray; + Float32Array& m_OutputArray; + const ebsdlib::Matrix3X1& m_Cartesian; + ebsdlib::orientations::Type m_InputRepType; + const std::atomic_bool& m_ShouldCancel; +}; + +template || std::is_same_v>> +Result<> ExecuteComputeDirectionVectors(DataStructure& dataStructure, const DataPath& inputOrientationsArrayPath, const DataPath& outputArrayPath, ebsdlib::orientations::Type inputRepType, + const Vec3& latticeParametersLengths, const Vec3& latticeParametersAngles, const IFilter::MessageHandler& msgHandler, + const std::atomic_bool& shouldCancel) +{ + msgHandler("Computing Direction Vectors..."); + + // Convert the lattice parameters to a direct structure matrix, and calculate the cartesian point + ebsdlib::Matrix3X3 dsm = DirectStructureMatrix(latticeParametersLengths, latticeParametersAngles); + ebsdlib::Matrix3X1 latticePoint(0.0f, 0.0f, 1.0f); + auto cartesian = dsm * latticePoint; + + // Parallelize the implementation method + ParallelTaskAlgorithm taskRunner; + auto& inputOrientationsArray = dataStructure.getDataRefAs>(inputOrientationsArrayPath); + auto& outputArray = dataStructure.getDataRefAs(outputArrayPath); + taskRunner.template execute<>(ComputeDirectionVectorsImpl(inputOrientationsArray, inputRepType, cartesian, outputArray, shouldCancel)); + + return {}; +} +} // namespace + +// ----------------------------------------------------------------------------- +ComputeDirectionVectors::ComputeDirectionVectors(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, + ComputeDirectionVectorsInputValues* inputValues) +: m_DataStructure(dataStructure) +, m_InputValues(inputValues) +, m_ShouldCancel(shouldCancel) +, m_MessageHandler(mesgHandler) +{ +} + +// ----------------------------------------------------------------------------- +ComputeDirectionVectors::~ComputeDirectionVectors() noexcept = default; + +// ----------------------------------------------------------------------------- +Result<> ComputeDirectionVectors::operator()() +{ + Vec3 latticeParametersLengths; + Vec3 latticeParametersAngles; + switch(m_InputValues->LatticeConstantsInputType) + { + case LatticeConstantsInputType::DataArrayPath: { + auto& latticeConstantsArray = m_DataStructure.getDataRefAs(m_InputValues->LatticeConstantsArrayPath); + latticeParametersLengths[0] = latticeConstantsArray[0]; + latticeParametersLengths[1] = latticeConstantsArray[1]; + latticeParametersLengths[2] = latticeConstantsArray[2]; + latticeParametersAngles[0] = latticeConstantsArray[3]; + latticeParametersAngles[1] = latticeConstantsArray[4]; + latticeParametersAngles[2] = latticeConstantsArray[5]; + break; + } + case LatticeConstantsInputType::Manual: { + latticeParametersLengths = m_InputValues->ManualLatticeConstantsLengths; + latticeParametersAngles = m_InputValues->ManualLatticeConstantsAngles; + break; + } + } + + DataPath orientationsParentPath = m_InputValues->InputOrientationsArrayPath.getParent(); + DataPath outputDirectionVectorsPath = orientationsParentPath.createChildPath(m_InputValues->OutputDirectionVectorsArrayName); + + auto& inputOrientationsArray = m_DataStructure.getDataRefAs(m_InputValues->InputOrientationsArrayPath); + DataType inputDataType = inputOrientationsArray.getDataType(); + switch(inputDataType) + { + case DataType::float32: { + return ExecuteComputeDirectionVectors(m_DataStructure, m_InputValues->InputOrientationsArrayPath, outputDirectionVectorsPath, m_InputValues->InputRepType, latticeParametersLengths, + latticeParametersAngles, m_MessageHandler, m_ShouldCancel); + } + case DataType::float64: { + return ExecuteComputeDirectionVectors(m_DataStructure, m_InputValues->InputOrientationsArrayPath, outputDirectionVectorsPath, m_InputValues->InputRepType, latticeParametersLengths, + latticeParametersAngles, m_MessageHandler, m_ShouldCancel); + } + default: { + return MakeErrorResult( + -2300, fmt::format("Input Orientations array has incompatible data type: the data type is {} but this filter only supports float32 and float64 data types.", DataTypeToString(inputDataType))); + } + } +} diff --git a/src/SimplnxReview/Filters/Algorithms/ComputeDirectionVectors.hpp b/src/SimplnxReview/Filters/Algorithms/ComputeDirectionVectors.hpp new file mode 100644 index 0000000..58aedc8 --- /dev/null +++ b/src/SimplnxReview/Filters/Algorithms/ComputeDirectionVectors.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include "SimplnxReview/SimplnxReview_export.hpp" + +#include "EbsdLib/Orientation/OrientationFwd.hpp" + +#include "simplnx/Common/Array.hpp" +#include "simplnx/DataStructure/DataPath.hpp" +#include "simplnx/Filter/IFilter.hpp" +#include "simplnx/Parameters/ChoicesParameter.hpp" + +namespace nx::core +{ +enum LatticeConstantsInputType : uint8 +{ + DataArrayPath = 0, + Manual = 1 +}; + +struct SIMPLNXREVIEW_EXPORT ComputeDirectionVectorsInputValues +{ + ebsdlib::orientations::Type InputRepType; + DataPath InputOrientationsArrayPath; + LatticeConstantsInputType LatticeConstantsInputType; + DataPath LatticeConstantsArrayPath; + FloatVec3 ManualLatticeConstantsLengths; + FloatVec3 ManualLatticeConstantsAngles; + std::string OutputDirectionVectorsArrayName; +}; + +/** + * @class + */ +class SIMPLNXREVIEW_EXPORT ComputeDirectionVectors +{ +public: + ComputeDirectionVectors(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, ComputeDirectionVectorsInputValues* inputValues); + ~ComputeDirectionVectors() noexcept; + + ComputeDirectionVectors(const ComputeDirectionVectors&) = delete; + ComputeDirectionVectors(ComputeDirectionVectors&&) noexcept = delete; + ComputeDirectionVectors& operator=(const ComputeDirectionVectors&) = delete; + ComputeDirectionVectors& operator=(ComputeDirectionVectors&&) noexcept = delete; + + Result<> operator()(); + +private: + DataStructure& m_DataStructure; + const ComputeDirectionVectorsInputValues* m_InputValues = nullptr; + const std::atomic_bool& m_ShouldCancel; + const IFilter::MessageHandler& m_MessageHandler; +}; +} // namespace nx::core diff --git a/src/SimplnxReview/Filters/ComputeDirectionVectorsFilter.cpp b/src/SimplnxReview/Filters/ComputeDirectionVectorsFilter.cpp new file mode 100644 index 0000000..8f4bb8a --- /dev/null +++ b/src/SimplnxReview/Filters/ComputeDirectionVectorsFilter.cpp @@ -0,0 +1,138 @@ +#include "ComputeDirectionVectorsFilter.hpp" +#include "Algorithms/ComputeDirectionVectors.hpp" + +#include "EbsdLib/Core/EbsdDataArray.hpp" +#include "EbsdLib/OrientationMath/OrientationConverter.hpp" + +#include "simplnx/DataStructure/IDataArray.hpp" +#include "simplnx/Filter/Actions/CreateArrayAction.hpp" +#include "simplnx/Parameters/ArraySelectionParameter.hpp" +#include "simplnx/Parameters/DataObjectNameParameter.hpp" +#include "simplnx/Parameters/VectorParameter.hpp" + +namespace nx::core +{ +namespace +{ +// constexpr int32 k_MissingInputArray = -567; +// constexpr int32 k_ComponentCountMismatchError = -90003; +// constexpr int32 k_InvalidNumTuples = -90004; +} // namespace + +//------------------------------------------------------------------------------ +std::string ComputeDirectionVectorsFilter::name() const +{ + return FilterTraits::name; +} + +//------------------------------------------------------------------------------ +std::string ComputeDirectionVectorsFilter::className() const +{ + return FilterTraits::className; +} + +//------------------------------------------------------------------------------ +Uuid ComputeDirectionVectorsFilter::uuid() const +{ + return FilterTraits::uuid; +} + +//------------------------------------------------------------------------------ +std::string ComputeDirectionVectorsFilter::humanName() const +{ + return "Compute Direction Vectors"; +} + +//------------------------------------------------------------------------------ +std::vector ComputeDirectionVectorsFilter::defaultTags() const +{ + return {className(), "Statistics", "SimplnxCore", "Find"}; +} + +//------------------------------------------------------------------------------ +Parameters ComputeDirectionVectorsFilter::parameters() const +{ + Parameters params; + + using OrientationConverterType = ebsdlib::OrientationConverter, float32>; + + params.insertSeparator(Parameters::Separator{"Input Parameter(s)"}); + params.insert(std::make_unique(k_InputType_Key, "Input Orientation Type", "Specifies the incoming orientation representation enumeration index", 0, + OrientationConverterType::GetOrientationTypeStrings())); + params.insert(std::make_unique(k_InputOrientationArrayPath_Key, "Input Orientations", "The complete path to the incoming orientation representation data array", DataPath{}, + ArraySelectionParameter::AllowedTypes{DataType::float32, DataType::float64}, ArraySelectionParameter::AllowedComponentShapes{{3}, {4}, {9}})); + params.insertLinkableParameter(std::make_unique(k_LatticeConstantsInputType_Key, "Lattice Constants Input Type", + "Specifies the method that the lattice constants will be input into this filter.", 0, + ChoicesParameter::Choices{"Existing Array", "Manual Entry"})); + params.insert(std::make_unique(k_LatticeConstantsArrayPath_Key, "Lattice Constants", + "The complete path to the lattice constants data array that will be imported and used by this filter.", DataPath{}, + ArraySelectionParameter::AllowedTypes{DataType::float32}, ArraySelectionParameter::AllowedComponentShapes{{6}})); + params.insert(std::make_unique(k_LatticeConstantsLength_Key, "Lattice Constants Lengths (A, B, C)", "The manual lattice constants that will be used by this filter.", + VectorFloat32Parameter::ValueType{0.0f, 0.0f, 0.0f}, std::vector{"a", "b", "c"})); + params.insert(std::make_unique(k_LatticeConstantsAngles_Key, "Lattice Constants Angles (Alpha, Beta, Gamma)", + "The manual lattice constants that will be used by this filter.", VectorFloat32Parameter::ValueType{0.0f, 0.0f, 0.0f}, + std::vector{"alpha", "beta", "gamma"})); + + params.insertSeparator(Parameters::Separator{"Output Parameter(s)"}); + params.insert(std::make_unique(k_OutputDirectionVectorsArrayName_Key, "Output Direction Vectors Array Name", + "The name of the output direction vectors array that will be created.", "Direction Vectors")); + + params.linkParameters(k_LatticeConstantsInputType_Key, k_LatticeConstantsArrayPath_Key, std::make_any(0)); + params.linkParameters(k_LatticeConstantsInputType_Key, k_LatticeConstantsLength_Key, std::make_any(1)); + params.linkParameters(k_LatticeConstantsInputType_Key, k_LatticeConstantsAngles_Key, std::make_any(1)); + + return params; +} + +//------------------------------------------------------------------------------ +IFilter::VersionType ComputeDirectionVectorsFilter::parametersVersion() const +{ + return 1; +} + +//------------------------------------------------------------------------------ +IFilter::UniquePointer ComputeDirectionVectorsFilter::clone() const +{ + return std::make_unique(); +} + +//------------------------------------------------------------------------------ +IFilter::PreflightResult ComputeDirectionVectorsFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel, const ExecutionContext& executionContext) const +{ + auto inputRepType = static_cast(filterArgs.value(k_InputType_Key)); + auto inputOrientationsArrayPath = filterArgs.value(k_InputOrientationArrayPath_Key); + auto latticeConstantsType = static_cast(filterArgs.value(k_LatticeConstantsInputType_Key)); + auto latticeConstantsArrayPath = filterArgs.value(k_LatticeConstantsArrayPath_Key); + auto latticeConstantsLengths = filterArgs.value(k_LatticeConstantsLength_Key); + auto latticeConstantsAngles = filterArgs.value(k_LatticeConstantsAngles_Key); + auto outputDirectionVectorsArrayName = filterArgs.value(k_OutputDirectionVectorsArrayName_Key); + + DataPath orientationsParentPath = inputOrientationsArrayPath.getParent(); + DataPath outputDirectionVectorsPath = orientationsParentPath.createChildPath(outputDirectionVectorsArrayName); + auto& orientationsArray = dataStructure.getDataRefAs(inputOrientationsArrayPath); + + nx::core::Result resultOutputActions; + auto action = std::make_unique(DataType::float32, orientationsArray.getTupleShape(), std::vector{3}, outputDirectionVectorsPath); + resultOutputActions.value().appendAction(std::move(action)); + + return {std::move(resultOutputActions)}; +} + +//------------------------------------------------------------------------------ +Result<> ComputeDirectionVectorsFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel, const ExecutionContext& executionContext) const +{ + ComputeDirectionVectorsInputValues inputValues; + + inputValues.InputRepType = static_cast(filterArgs.value(k_InputType_Key)); + inputValues.InputOrientationsArrayPath = filterArgs.value(k_InputOrientationArrayPath_Key); + inputValues.LatticeConstantsInputType = static_cast(filterArgs.value(k_LatticeConstantsInputType_Key)); + inputValues.LatticeConstantsArrayPath = filterArgs.value(k_LatticeConstantsArrayPath_Key); + inputValues.ManualLatticeConstantsLengths = filterArgs.value(k_LatticeConstantsLength_Key); + inputValues.ManualLatticeConstantsAngles = filterArgs.value(k_LatticeConstantsAngles_Key); + inputValues.OutputDirectionVectorsArrayName = filterArgs.value(k_OutputDirectionVectorsArrayName_Key); + + return ComputeDirectionVectors(dataStructure, messageHandler, shouldCancel, &inputValues)(); +} +} // namespace nx::core diff --git a/src/SimplnxReview/Filters/ComputeDirectionVectorsFilter.hpp b/src/SimplnxReview/Filters/ComputeDirectionVectorsFilter.hpp new file mode 100644 index 0000000..aa8c3ff --- /dev/null +++ b/src/SimplnxReview/Filters/ComputeDirectionVectorsFilter.hpp @@ -0,0 +1,117 @@ +#pragma once + +#include "SimplnxReview/SimplnxReview_export.hpp" + +#include "simplnx/Common/StringLiteral.hpp" +#include "simplnx/Filter/FilterTraits.hpp" +#include "simplnx/Filter/IFilter.hpp" + +namespace nx::core +{ +/** + * @class ComputeDirectionVectorsFilter + * @brief + */ +class SIMPLNXREVIEW_EXPORT ComputeDirectionVectorsFilter : public IFilter +{ +public: + ComputeDirectionVectorsFilter() = default; + ~ComputeDirectionVectorsFilter() noexcept override = default; + + ComputeDirectionVectorsFilter(const ComputeDirectionVectorsFilter&) = delete; + ComputeDirectionVectorsFilter(ComputeDirectionVectorsFilter&&) noexcept = delete; + + ComputeDirectionVectorsFilter& operator=(const ComputeDirectionVectorsFilter&) = delete; + ComputeDirectionVectorsFilter& operator=(ComputeDirectionVectorsFilter&&) noexcept = delete; + + // Parameter Keys + static inline constexpr StringLiteral k_InputType_Key = "input_representation_index"; + static inline constexpr StringLiteral k_InputOrientationArrayPath_Key = "input_orientation_array_path"; + static inline constexpr StringLiteral k_LatticeConstantsInputType_Key = "lattice_constants_input_type_index"; + static inline constexpr StringLiteral k_LatticeConstantsArrayPath_Key = "lattice_constants_array_path"; + static inline constexpr StringLiteral k_LatticeConstantsLength_Key = "lattice_constants_length"; + static inline constexpr StringLiteral k_LatticeConstantsAngles_Key = "lattice_constants_angles"; + static inline constexpr StringLiteral k_OutputDirectionVectorsArrayName_Key = "output_direction_vectors_array_name"; + + /** + * @brief Returns the name of the filter. + * @return std::string + */ + std::string name() const override; + + /** + * @brief Returns the C++ classname of this filter. + * @return std::string + */ + std::string className() const override; + + /** + * @brief Returns the filter's UUID. + * @return Uuid + */ + Uuid uuid() const override; + + /** + * @brief Returns the filter name name presented to the user. + * @return std::string + */ + std::string humanName() const override; + + /** + * @brief Returns the default tags for this filter. + * @return + */ + std::vector defaultTags() const override; + + /** + * @brief Returns the parameters required to run the filter. + * @return Parameters + */ + Parameters parameters() const override; + + /** + * @brief Returns parameters version integer. + * The Initial version should always be 1. + * Should be incremented everytime the parameters change. + * @return VersionType + */ + VersionType parametersVersion() const override; + + /** + * @brief Creates a copy of the filter. + * @return IFilter::UniquePointer + */ + UniquePointer clone() const override; + +protected: + /** + * @brief Takes in a DataStructure and checks that the filter can be run on it with the given arguments. + * Returns any warnings/errors. Also returns the changes that would be applied to the DataStructure. + * Some parts of the actions may not be completely filled out if all the required information is not available at preflight time. + * @param dataStructure The input DataStructure instance + * @param filterArgs These are the input values for each parameter that is required for the filter + * @param messageHandler The MessageHandler object + * @param shouldCancel The atomic boolean that holds if the filter should be canceled + * @param executionContext The ExecutionContext that can be used to determine the correct absolute path from a relative path + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + PreflightResult preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel, + const ExecutionContext& executionContext) const override; + + /** + * @brief Applies the filter's algorithm to the DataStructure with the given arguments. Returns any warnings/errors. + * On failure, there is no guarantee that the DataStructure is in a correct state. + * @param dataStructure The input DataStructure instance + * @param filterArgs These are the input values for each parameter that is required for the filter + * @param pipelineNode The node in the pipeline that is being executed + * @param messageHandler The MessageHandler object + * @param shouldCancel Atomic boolean value that can be checked to cancel the filter + * @param executionContext The ExecutionContext that can be used to determine the correct absolute path from a relative path + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + Result<> executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel, + const ExecutionContext& executionContext) const override; +}; +} // namespace nx::core + +SIMPLNX_DEF_FILTER_TRAITS(nx::core, ComputeDirectionVectorsFilter, "1e2386db-c1a3-4e6a-b30b-34837d0a8555");