diff --git a/src/Plugins/OrientationAnalysis/CMakeLists.txt b/src/Plugins/OrientationAnalysis/CMakeLists.txt index 04db9fa738..db67e04473 100644 --- a/src/Plugins/OrientationAnalysis/CMakeLists.txt +++ b/src/Plugins/OrientationAnalysis/CMakeLists.txt @@ -189,7 +189,6 @@ set(filter_algorithms GenerateGBCDPoleFigure GenerateIPFColors GenerateQuaternionConjugate - GroupFeatures MergeTwins NeighborOrientationCorrelation ReadAngData diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/CAxisSegmentFeatures.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/CAxisSegmentFeatures.cpp index bee4edd294..1b4a0bf627 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/CAxisSegmentFeatures.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/CAxisSegmentFeatures.cpp @@ -64,11 +64,6 @@ Result<> CAxisSegmentFeatures::operator()() active->fill(1); // Generate the random voxel indices that will be used for the seed points to start a new grain growth/agglomeration - constexpr int64 rangeMin = 0; - const int64 rangeMax = m_FeatureIdsArray->getNumberOfTuples() - 1; - Int64Distribution distribution; - initializeStaticVoxelSeedGenerator(distribution, rangeMin, rangeMax); - execute(imageGeometry); const auto totalFeatures = static_cast(active->getNumberOfTuples()); @@ -80,7 +75,7 @@ Result<> CAxisSegmentFeatures::operator()() // By default we randomize grains if(m_InputValues->RandomizeFeatureIds) { - randomizeFeatureIds(m_FeatureIdsArray, imageGeometry->getNumberOfCells(), totalFeatures, distribution); + randomizeFeatureIds(m_FeatureIdsArray, totalFeatures); } return {}; diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/EBSDSegmentFeatures.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/EBSDSegmentFeatures.cpp index 2623052b4d..6ca1919397 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/EBSDSegmentFeatures.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/EBSDSegmentFeatures.cpp @@ -45,7 +45,7 @@ Result<> EBSDSegmentFeatures::operator()() execute(gridGeom); - IDataArray* activeArray = m_DataStructure.getDataAs(m_InputValues->activeArrayPath); + auto* activeArray = m_DataStructure.getDataAs(m_InputValues->activeArrayPath); auto totalFeatures = activeArray->getNumberOfTuples(); if(totalFeatures < 2) { @@ -57,15 +57,7 @@ Result<> EBSDSegmentFeatures::operator()() // would look like a smooth gradient. This is a user input parameter if(m_InputValues->shouldRandomizeFeatureIds) { - auto totalPoints = m_QuatsArray->getNumberOfTuples(); - - const int64 rangeMin = 0; - const auto rangeMax = static_cast(totalPoints - 1); - Int64Distribution distribution; - initializeStaticVoxelSeedGenerator(distribution, rangeMin, rangeMax); - - totalPoints = gridGeom->getNumberOfCells(); - randomizeFeatureIds(m_FeatureIdsArray, totalPoints, totalFeatures, distribution); + randomizeFeatureIds(m_FeatureIdsArray, totalFeatures); } return {}; @@ -81,29 +73,29 @@ int64_t EBSDSegmentFeatures::getSeed(int32 gnum, int64 nextSeed) const int64 seed = -1; // start with the next voxel after the last seed - usize randpoint = static_cast(nextSeed); - while(seed == -1 && randpoint < totalPoints) + auto randPoint = static_cast(nextSeed); + while(seed == -1 && randPoint < totalPoints) { - if(featureIds->getValue(randpoint) == 0) // If the GrainId of the voxel is ZERO then we can use this as a seed point + if(featureIds->getValue(randPoint) == 0) // If the GrainId of the voxel is ZERO then we can use this as a seed point { - if((!m_InputValues->useGoodVoxels || m_GoodVoxelsArray->isTrue(randpoint)) && cellPhases->getValue(randpoint) > 0) + if((!m_InputValues->useGoodVoxels || m_GoodVoxelsArray->isTrue(randPoint)) && cellPhases->getValue(randPoint) > 0) { - seed = static_cast(randpoint); + seed = static_cast(randPoint); } else { - randpoint += 1; + randPoint += 1; } } else { - randpoint += 1; + randPoint += 1; } } if(seed >= 0) { - UInt8Array& activeArray = m_DataStructure.getDataRefAs(m_InputValues->activeArrayPath); - AttributeMatrix& cellFeatureAM = m_DataStructure.getDataRefAs(m_InputValues->cellFeatureAttributeMatrixPath); + auto& activeArray = m_DataStructure.getDataAs(m_InputValues->activeArrayPath)->getDataStoreRef(); + auto& cellFeatureAM = m_DataStructure.getDataRefAs(m_InputValues->cellFeatureAttributeMatrixPath); featureIds->setValue(static_cast(seed), gnum); std::vector tDims = {static_cast(gnum) + 1}; cellFeatureAM.resizeTuples(tDims); // This will resize the actives array @@ -113,15 +105,15 @@ int64_t EBSDSegmentFeatures::getSeed(int32 gnum, int64 nextSeed) const } // ----------------------------------------------------------------------------- -bool EBSDSegmentFeatures::determineGrouping(int64 referencepoint, int64 neighborpoint, int32 gnum) const +bool EBSDSegmentFeatures::determineGrouping(int64 referencePoint, int64 neighborPoint, int32 gnum) const { bool group = false; // Get the phases for each voxel nx::core::AbstractDataStore* cellPhases = m_CellPhases->getDataStore(); - int32_t phase1 = (*m_CrystalStructures)[(*cellPhases)[referencepoint]]; - int32_t phase2 = (*m_CrystalStructures)[(*cellPhases)[neighborpoint]]; + int32_t phase1 = (*m_CrystalStructures)[(*cellPhases)[referencePoint]]; + int32_t phase2 = (*m_CrystalStructures)[(*cellPhases)[neighborPoint]]; // If either of the phases is 999 then we bail out now. if(phase1 >= m_OrientationOps.size() || phase2 >= m_OrientationOps.size()) { @@ -133,16 +125,16 @@ bool EBSDSegmentFeatures::determineGrouping(int64 referencepoint, int64 neighbor bool neighborPointIsGood = false; if(m_GoodVoxelsArray != nullptr) { - neighborPointIsGood = m_GoodVoxelsArray->isTrue(neighborpoint); + neighborPointIsGood = m_GoodVoxelsArray->isTrue(neighborPoint); } - if(featureIds[neighborpoint] == 0 && (m_GoodVoxelsArray == nullptr || neighborPointIsGood)) + if(featureIds[neighborPoint] == 0 && (m_GoodVoxelsArray == nullptr || neighborPointIsGood)) { float w = std::numeric_limits::max(); - QuatF q1(currentQuatPtr[referencepoint * 4], currentQuatPtr[referencepoint * 4 + 1], currentQuatPtr[referencepoint * 4 + 2], currentQuatPtr[referencepoint * 4 + 3]); - QuatF q2(currentQuatPtr[neighborpoint * 4 + 0], currentQuatPtr[neighborpoint * 4 + 1], currentQuatPtr[neighborpoint * 4 + 2], currentQuatPtr[neighborpoint * 4 + 3]); + QuatF q1(currentQuatPtr[referencePoint * 4], currentQuatPtr[referencePoint * 4 + 1], currentQuatPtr[referencePoint * 4 + 2], currentQuatPtr[referencePoint * 4 + 3]); + QuatF q2(currentQuatPtr[neighborPoint * 4 + 0], currentQuatPtr[neighborPoint * 4 + 1], currentQuatPtr[neighborPoint * 4 + 2], currentQuatPtr[neighborPoint * 4 + 3]); - if((*cellPhases)[referencepoint] == (*cellPhases)[neighborpoint]) + if((*cellPhases)[referencePoint] == (*cellPhases)[neighborPoint]) { OrientationF axisAngle = m_OrientationOps[phase1]->calculateMisorientation(q1, q2); w = axisAngle[3]; @@ -150,7 +142,7 @@ bool EBSDSegmentFeatures::determineGrouping(int64 referencepoint, int64 neighbor if(w < m_InputValues->misorientationTolerance) { group = true; - featureIds[neighborpoint] = gnum; + featureIds[neighborPoint] = gnum; } } diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/GroupFeatures.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/GroupFeatures.cpp deleted file mode 100644 index 749577b913..0000000000 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/GroupFeatures.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include "GroupFeatures.hpp" - -#include "simplnx/DataStructure/DataGroup.hpp" -#include "simplnx/DataStructure/NeighborList.hpp" - -using namespace nx::core; - -// ----------------------------------------------------------------------------- -GroupFeatures::GroupFeatures(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, GroupFeaturesInputValues* inputValues) -: m_DataStructure(dataStructure) -, m_GroupInputValues(inputValues) -, m_ShouldCancel(shouldCancel) -, m_MessageHandler(mesgHandler) -{ -} - -// ----------------------------------------------------------------------------- -GroupFeatures::~GroupFeatures() noexcept = default; - -// ----------------------------------------------------------------------------- -const std::atomic_bool& GroupFeatures::getCancel() -{ - return m_ShouldCancel; -} - -// ----------------------------------------------------------------------------- -int GroupFeatures::getSeed(int32 newFid) -{ - return -1; -} - -// ----------------------------------------------------------------------------- -bool GroupFeatures::determineGrouping(int32 referenceFeature, int32 neighborFeature, int32 newFid) -{ - return false; -} - -// ----------------------------------------------------------------------------- -bool GroupFeatures::growPatch(int32_t currentPatch) -{ - return false; -} - -// ----------------------------------------------------------------------------- -bool GroupFeatures::growGrouping(int32_t referenceFeature, int32_t neighborFeature, int32_t newFid) -{ - return false; -} - -// ----------------------------------------------------------------------------- -Result<> GroupFeatures::operator()() -{ - execute(); - return {}; -} - -void GroupFeatures::execute() -{ - NeighborList& neighborlist = m_DataStructure.getDataRefAs>(m_GroupInputValues->ContiguousNeighborListArrayPath); - NeighborList* nonContigNeighList = nullptr; - if(m_GroupInputValues->UseNonContiguousNeighbors) - { - nonContigNeighList = m_DataStructure.getDataAs>(m_GroupInputValues->NonContiguousNeighborListArrayPath); - } - - std::vector grouplist; - - int32 parentcount = 0; - int32 seed = 0; - int32 list1size = 0, list2size = 0, listsize = 0; - int32 neigh = 0; - bool patchGrouping = false; - - 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_GroupInputValues->UseNonContiguousNeighbors) - { - list2size = nonContigNeighList->getListSize(firstfeature); - } - for(int32 k = 0; k < 2; k++) - { - if(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(!patchGrouping) - { - grouplist.push_back(neigh); - } - } - } - } - } - } - if(patchGrouping) - { - if(growPatch(parentcount)) - { - for(std::vector::size_type j = 0; j < grouplist.size(); j++) - { - int32_t firstfeature = grouplist[j]; - listsize = int32_t(neighborlist[firstfeature].size()); - for(int32_t l = 0; l < listsize; l++) - { - neigh = neighborlist[firstfeature][l]; - if(neigh != firstfeature) - { - if(growGrouping(firstfeature, neigh, parentcount)) - { - grouplist.push_back(neigh); - } - } - } - } - } - } - } - grouplist.clear(); - } -} diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/GroupFeatures.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/GroupFeatures.hpp deleted file mode 100644 index d2a33716e0..0000000000 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/GroupFeatures.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include "OrientationAnalysis/OrientationAnalysis_export.hpp" - -#include "simplnx/DataStructure/DataPath.hpp" -#include "simplnx/DataStructure/DataStructure.hpp" -#include "simplnx/Filter/IFilter.hpp" - -namespace nx::core -{ - -struct ORIENTATIONANALYSIS_EXPORT GroupFeaturesInputValues -{ - bool UseNonContiguousNeighbors; - DataPath NonContiguousNeighborListArrayPath; - DataPath ContiguousNeighborListArrayPath; - bool m_PatchGrouping = false; -}; - -/** - * @class - */ -class ORIENTATIONANALYSIS_EXPORT GroupFeatures -{ -public: - GroupFeatures(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, GroupFeaturesInputValues* inputValues); - ~GroupFeatures() noexcept; - - GroupFeatures(const GroupFeatures&) = delete; - GroupFeatures(GroupFeatures&&) noexcept = delete; - GroupFeatures& operator=(const GroupFeatures&) = delete; - GroupFeatures& operator=(GroupFeatures&&) noexcept = delete; - - Result<> operator()(); - - const std::atomic_bool& getCancel(); - - virtual int getSeed(int32 newFid); - virtual bool determineGrouping(int32 referenceFeature, int32 neighborFeature, int32 newFid); - virtual bool growPatch(int32 currentPatch); - virtual bool growGrouping(int32 referenceFeature, int32 neighborFeature, int32 newFid); - -protected: - DataStructure& m_DataStructure; - const std::atomic_bool& m_ShouldCancel; - const IFilter::MessageHandler& m_MessageHandler; - - void execute(); - -private: - const GroupFeaturesInputValues* m_GroupInputValues = nullptr; -}; - -} // namespace nx::core diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeTwins.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeTwins.cpp index 9e1ef1b907..4ba17ce74a 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeTwins.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeTwins.cpp @@ -3,7 +3,6 @@ #include "simplnx/Common/Numbers.hpp" #include "simplnx/DataStructure/DataArray.hpp" #include "simplnx/DataStructure/DataGroup.hpp" -#include "simplnx/DataStructure/DataStore.hpp" #include "simplnx/Utilities/DataArrayUtilities.hpp" #include "EbsdLib/Core/EbsdLibConstants.h" @@ -16,10 +15,11 @@ using namespace nx::core; // ----------------------------------------------------------------------------- -MergeTwins::MergeTwins(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MergeTwinsInputValues* inputValues, - GroupFeaturesInputValues* groupInputValues) -: GroupFeatures(dataStructure, mesgHandler, shouldCancel, groupInputValues) +MergeTwins::MergeTwins(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MergeTwinsInputValues* inputValues) +: m_DataStructure(dataStructure) , m_InputValues(inputValues) +, m_ShouldCancel(shouldCancel) +, m_MessageHandler(mesgHandler) { } @@ -27,52 +27,40 @@ MergeTwins::MergeTwins(DataStructure& dataStructure, const IFilter::MessageHandl MergeTwins::~MergeTwins() noexcept = default; // ----------------------------------------------------------------------------- -void MergeTwins::characterize_twins() +int MergeTwins::getSeed(int32 newFid) const { -} - -// ----------------------------------------------------------------------------- -int MergeTwins::getSeed(int32 newFid) -{ - Int32Array& phases = m_DataStructure.getDataRefAs(m_InputValues->FeaturePhasesArrayPath); - Int32Array& featureIds = m_DataStructure.getDataRefAs(m_InputValues->FeatureIdsArrayPath); - Int32Array& featureParentIds = m_DataStructure.getDataRefAs(m_InputValues->FeatureParentIdsArrayName); - AttributeMatrix& cellFeaturesAttMatrix = m_DataStructure.getDataRefAs(m_InputValues->NewCellFeatureAttributeMatrixName); - BoolArray& active = m_DataStructure.getDataRefAs(m_InputValues->ActiveArrayName); + auto& phases = m_DataStructure.getDataAs(m_InputValues->FeaturePhasesArrayPath)->getDataStoreRef(); + auto& featureParentIds = m_DataStructure.getDataAs(m_InputValues->FeatureParentIdsArrayPath)->getDataStoreRef(); + auto& cellFeaturesAttMatrix = m_DataStructure.getDataRefAs(m_InputValues->NewCellFeatureAttributeMatrixPath); - int32 numfeatures = static_cast(phases.getNumberOfTuples()); + auto numFeatures = static_cast(phases.getNumberOfTuples()); int32 seed = -1; - int32 randfeature = 0; // Precalculate some constants - int32 totalFMinus1 = numfeatures - 1; - - size_t counter = 0; - double rangeMin = 0; - double rangeMax = 1; - std::random_device randomDevice; // Will be used to obtain a seed for the random number engine - std::mt19937_64 generator(randomDevice()); // Standard mersenne_twister_engine seeded with rd() - generator.seed(m_InputValues->Seed); - std::uniform_real_distribution<> distribution(rangeMin, rangeMax); - randfeature = int32(float(distribution(generator)) * float(totalFMinus1)); - while(seed == -1 && counter < numfeatures) + int32 totalFMinus1 = numFeatures - 1; + + usize counter = 0; + std::mt19937_64 generator(m_InputValues->Seed); // Standard mersenne_twister_engine seeded + std::uniform_real_distribution distribution(0, 1); + auto randFeature = static_cast(distribution(generator) * static_cast(totalFMinus1)); + while(seed == -1 && counter < numFeatures) { - if(randfeature > totalFMinus1) + if(randFeature > totalFMinus1) { - randfeature = randfeature - numfeatures; + randFeature = randFeature - numFeatures; } - if(featureParentIds[randfeature] == -1) + if(featureParentIds[randFeature] == -1) { - seed = randfeature; + seed = randFeature; } - randfeature++; + randFeature++; counter++; } if(seed >= 0) { featureParentIds[seed] = newFid; - std::vector tDims(1, newFid + 1); + std::vector tDims(1, newFid + 1); cellFeaturesAttMatrix.resizeTuples(tDims); // this will resize the active array as well } return seed; @@ -81,33 +69,31 @@ int MergeTwins::getSeed(int32 newFid) // ----------------------------------------------------------------------------- bool MergeTwins::determineGrouping(int32 referenceFeature, int32 neighborFeature, int32 newFid) { - Int32Array& phases = m_DataStructure.getDataRefAs(m_InputValues->FeaturePhasesArrayPath); - Int32Array& featureParentIds = m_DataStructure.getDataRefAs(m_InputValues->FeatureParentIdsArrayName); - UInt32Array& crystalStructures = m_DataStructure.getDataRefAs(m_InputValues->CrystalStructuresArrayPath); - Float32Array& avgQuats = m_DataStructure.getDataRefAs(m_InputValues->AvgQuatsArrayPath); + auto& phases = m_DataStructure.getDataAs(m_InputValues->FeaturePhasesArrayPath)->getDataStoreRef(); + auto& featureParentIds = m_DataStructure.getDataAs(m_InputValues->FeatureParentIdsArrayPath)->getDataStoreRef(); + auto& crystalStructures = m_DataStructure.getDataAs(m_InputValues->CrystalStructuresArrayPath)->getDataStoreRef(); + auto& avgQuats = m_DataStructure.getDataAs(m_InputValues->AvgQuatsArrayPath)->getDataStoreRef(); auto axisToleranceRad = m_InputValues->AxisTolerance * numbers::pi_v / 180.0f; - // float w = 0.0f; - // float n1 = 0.0f, n2 = 0.0f, n3 = 0.0f; bool twin = false; std::vector m_OrientationOps = LaueOps::GetAllOrientationOps(); if(featureParentIds[neighborFeature] == -1 && phases[referenceFeature] > 0 && phases[neighborFeature] > 0) { - uint32_t phase1 = crystalStructures[phases[referenceFeature]]; + uint32 phase1 = crystalStructures[phases[referenceFeature]]; QuatF q1(avgQuats[referenceFeature * 4], avgQuats[referenceFeature * 4 + 1], avgQuats[referenceFeature * 4 + 2], avgQuats[referenceFeature * 4 + 3]); QuatF q2(avgQuats[neighborFeature * 4], avgQuats[neighborFeature * 4 + 1], avgQuats[neighborFeature * 4 + 2], avgQuats[neighborFeature * 4 + 3]); - uint32_t phase2 = crystalStructures[phases[neighborFeature]]; + uint32 phase2 = crystalStructures[phases[neighborFeature]]; if(phase1 == phase2 && (phase1 == EbsdLib::CrystalStructure::Cubic_High)) { OrientationD axisAngle = m_OrientationOps[phase1]->calculateMisorientation(q1, q2); double w = axisAngle[3]; - w = w * (180.0f / numbers::pi); - double axisdiff111 = acosf(fabs(axisAngle[0]) * 0.57735f + fabs(axisAngle[1]) * 0.57735f + fabs(axisAngle[2]) * 0.57735f); - double angdiff60 = fabs(w - 60.0f); - if(axisdiff111 < axisToleranceRad && angdiff60 < m_InputValues->AngleTolerance) + w *= (180.0f / numbers::pi); + double axisDiff111 = std::acos(std::fabs(axisAngle[0]) * 0.57735f + std::fabs(axisAngle[1]) * 0.57735f + fabs(axisAngle[2]) * 0.57735f); + double angDiff60 = std::fabs(w - 60.0f); + if(axisDiff111 < axisToleranceRad && angDiff60 < m_InputValues->AngleTolerance) { twin = true; } @@ -128,16 +114,16 @@ Result<> MergeTwins::operator()() /* Sanity check that each phase is Cubic High (m3m) Laue class. If not then warn the user. * There is code later on to ensure that only m3m Laue class is used. */ - UInt32Array& laueClasses = m_DataStructure.getDataRefAs(m_InputValues->CrystalStructuresArrayPath); - Int32Array& featureIds = m_DataStructure.getDataRefAs(m_InputValues->FeatureIdsArrayPath); - Int32Array& cellParentIds = m_DataStructure.getDataRefAs(m_InputValues->CellParentIdsArrayName); + auto& laueClasses = m_DataStructure.getDataAs(m_InputValues->CrystalStructuresArrayPath)->getDataStoreRef(); + auto& featureIds = m_DataStructure.getDataAs(m_InputValues->FeatureIdsArrayPath)->getDataStoreRef(); + auto& cellParentIds = m_DataStructure.getDataAs(m_InputValues->CellParentIdsArrayPath)->getDataStoreRef(); cellParentIds.fill(-1); - Int32Array& featureParentIds = m_DataStructure.getDataRefAs(m_InputValues->FeatureParentIdsArrayName); + auto& featureParentIds = m_DataStructure.getDataAs(m_InputValues->FeatureParentIdsArrayPath)->getDataStoreRef(); featureParentIds.fill(-1); - BoolArray& active = m_DataStructure.getDataRefAs(m_InputValues->ActiveArrayName); + auto& active = m_DataStructure.getDataAs(m_InputValues->ActiveArrayPath)->getDataStoreRef(); active.fill(true); - for(size_t i = 1; i < laueClasses.getSize(); i++) + for(usize i = 1; i < laueClasses.getSize(); i++) { if(laueClasses[i] != EbsdLib::CrystalStructure::Cubic_High) { @@ -148,9 +134,38 @@ Result<> MergeTwins::operator()() featureParentIds[0] = 0; // set feature 0 to be parent 0 - GroupFeatures::execute(); + { // This code used to be in GroupFeatures Superclass + auto& contNeighborList = m_DataStructure.getDataRefAs>(m_InputValues->ContiguousNeighborListArrayPath); + + int32 parentCount = 1; + int32 seed = getSeed(parentCount); + int32 neigh; + while(seed >= 0) + { + std::vector groupList = {seed}; + for(std::vector::size_type j = 0; j < groupList.size(); j++) + { + int32 firstFeature = groupList[j]; + auto list1size = static_cast(contNeighborList[firstFeature].size()); + for(int32 l = 0; l < list1size; l++) + { + neigh = contNeighborList[firstFeature][l]; + if(neigh != firstFeature) + { + if(determineGrouping(firstFeature, neigh, parentCount)) + { + groupList.push_back(neigh); + } + } + } + } + + parentCount++; + seed = getSeed(parentCount); + } + } - size_t totalFeatures = active.getNumberOfTuples(); + usize totalFeatures = active.getNumberOfTuples(); if(totalFeatures < 2) { return MergeResults( @@ -158,68 +173,50 @@ Result<> MergeTwins::operator()() } int32 numParents = 0; - size_t totalPoints = featureIds.getNumberOfTuples(); - for(size_t k = 0; k < totalPoints; k++) + usize totalPoints = featureIds.getNumberOfTuples(); + for(usize k = 0; k < totalPoints; k++) { - int32_t featurename = featureIds[k]; - cellParentIds[k] = featureParentIds[featurename]; - if(featureParentIds[featurename] > numParents) + int32 featureName = featureIds[k]; + cellParentIds[k] = featureParentIds[featureName]; + if(featureParentIds[featureName] > numParents) { - numParents = featureParentIds[featurename]; + numParents = featureParentIds[featureName]; } } numParents += 1; - m_MessageHandler({IFilter::Message::Type::Info, "Characterizing Twins Starting"}); - characterize_twins(); - m_MessageHandler({IFilter::Message::Type::Info, "Characterizing Twins Complete"}); - - if(m_InputValues->RandomizeParentIds) - { + // Randomize the feature Ids for purely visual clarify. Having random Feature Ids + // allows users visualizing the data to better discern each grain otherwise the coloring + // would look like a smooth gradient. This is a user input parameter + { // Randomize Parent IDs m_MessageHandler({IFilter::Message::Type::Info, "Randomizing Parent Ids...."}); - // Generate all the numbers up front - const int32 rangeMin = 1; - const int32 rangeMax = numParents - 1; - std::mt19937_64 generator(std::mt19937_64::default_seed); // Standard mersenne_twister_engine seeded with milliseconds - std::uniform_int_distribution distribution(rangeMin, rangeMax); - - size_t nParents = static_cast(numParents); - - DataStructure tmpStructure; - Int32Array* rndNumbers = Int32Array::CreateWithStore(tmpStructure, std::string("_INTERNAL_USE_ONLY_NewParentIds"), std::vector{nParents}, std::vector{1}); - Int32DataStore* rndStore = dynamic_cast(rndNumbers->getDataStore()); - int32* pid = rndStore->data(); - pid[0] = 0; - std::set parentIdSet; - parentIdSet.insert(0); - for(int32 i = 1; i < numParents; ++i) // TODO : easily parallelized - { - pid[i] = i; // numberGenerator(); - parentIdSet.insert(rndStore->getValue(i)); - } - m_MessageHandler({IFilter::Message::Type::Info, "Shuffle elements ...."}); + std::mt19937_64 gen(std::mt19937_64::default_seed); // Standard mersenne_twister_engine seeded with milliseconds + std::uniform_real_distribution dist(0, 1); + + auto nParents = static_cast(numParents); + + std::vector parentIds(numParents); + std::iota(parentIds.begin(), parentIds.end(), 0); + + m_MessageHandler({IFilter::Message::Type::Info, "Shuffling elements ...."}); //--- Shuffle elements by randomly exchanging each with one other. - for(size_t i = 1; i < nParents; i++) + for(usize i = 1; i < nParents; i++) { - size_t r = static_cast(distribution(generator)); // Random remaining position. - int32 pid_i = rndStore->getValue(i); - if(r >= numParents) - { - continue; - } - int32 pid_r = rndStore->getValue(r); - rndStore->setValue(i, pid_r); - rndStore->setValue(r, pid_i); + auto r = static_cast(std::floor(dist(gen) * static_cast(numParents - 1))); // Random remaining position. + int32 pid_i = parentIds[i]; + parentIds[i] = parentIds[r]; + parentIds[r] = pid_i; } m_MessageHandler({IFilter::Message::Type::Info, "Adjusting Feature Ids Array...."}); - // Now adjust all the Feature Id values for each Voxel - for(size_t i = 0; i < totalPoints; ++i) // TODO : easily parallelized + // Now adjust all the Feature ID values for each Voxel + for(usize i = 0; i < totalPoints; ++i) { - cellParentIds[i] = pid[cellParentIds[i]]; + cellParentIds[i] = parentIds[cellParentIds[i]]; featureParentIds[featureIds[i]] = cellParentIds[i]; } } + return result; } diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeTwins.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeTwins.hpp index 4e59800dc1..68edf35fa7 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeTwins.hpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/MergeTwins.hpp @@ -1,6 +1,5 @@ #pragma once -#include "OrientationAnalysis/Filters/Algorithms/GroupFeatures.hpp" #include "OrientationAnalysis/OrientationAnalysis_export.hpp" #include "simplnx/DataStructure/DataPath.hpp" @@ -9,11 +8,8 @@ namespace nx::core { - struct ORIENTATIONANALYSIS_EXPORT MergeTwinsInputValues { - bool UseNonContiguousNeighbors; - DataPath NonContiguousNeighborListArrayPath; DataPath ContiguousNeighborListArrayPath; float32 AxisTolerance; float32 AngleTolerance; @@ -21,22 +17,20 @@ struct ORIENTATIONANALYSIS_EXPORT MergeTwinsInputValues DataPath AvgQuatsArrayPath; DataPath FeatureIdsArrayPath; DataPath CrystalStructuresArrayPath; - DataPath CellParentIdsArrayName; - DataPath NewCellFeatureAttributeMatrixName; - DataPath FeatureParentIdsArrayName; - DataPath ActiveArrayName; - bool RandomizeParentIds = true; + DataPath CellParentIdsArrayPath; + DataPath NewCellFeatureAttributeMatrixPath; + DataPath FeatureParentIdsArrayPath; + DataPath ActiveArrayPath; uint64 Seed; }; /** * @class */ -class ORIENTATIONANALYSIS_EXPORT MergeTwins : public GroupFeatures +class ORIENTATIONANALYSIS_EXPORT MergeTwins { public: - MergeTwins(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MergeTwinsInputValues* inputValues, - GroupFeaturesInputValues* groupInputValues); + MergeTwins(DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, MergeTwinsInputValues* inputValues); ~MergeTwins() noexcept; MergeTwins(const MergeTwins&) = delete; @@ -48,12 +42,14 @@ class ORIENTATIONANALYSIS_EXPORT MergeTwins : public GroupFeatures const std::atomic_bool& getCancel(); - void characterize_twins(); - int getSeed(int32 newFid) override; - bool determineGrouping(int32 referenceFeature, int32 neighborFeature, int32 newFid) override; + int getSeed(int32 newFid) const; + bool determineGrouping(int32 referenceFeature, int32 neighborFeature, int32 newFid); private: + DataStructure& m_DataStructure; const MergeTwinsInputValues* m_InputValues = nullptr; + const std::atomic_bool& m_ShouldCancel; + const IFilter::MessageHandler& m_MessageHandler; }; } // namespace nx::core diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeTwinsFilter.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeTwinsFilter.cpp index b99c5a8020..49a867b474 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeTwinsFilter.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeTwinsFilter.cpp @@ -64,9 +64,6 @@ Parameters MergeTwinsFilter::parameters() const params.insert(std::make_unique(k_SeedArrayName_Key, "Stored Seed Value Array Name", "Name of array holding the seed value", "MergeTwins SeedValue")); params.insertSeparator(Parameters::Separator{"Input Parameter(s)"}); - params.insertLinkableParameter(std::make_unique(k_UseNonContiguousNeighbors_Key, "Use Non-Contiguous Neighbors", - "Whether to use a list of non-contiguous or contiguous neighbors for each feature when merging", false)); - params.insert(std::make_unique(k_AxisTolerance_Key, "Axis Tolerance (Degrees)", "Tolerance allowed when comparing the axis part of the axis-angle representation of the misorientation", 3.0F)); params.insert(std::make_unique(k_AngleTolerance_Key, "Angle Tolerance (Degrees)", @@ -79,10 +76,6 @@ Parameters MergeTwinsFilter::parameters() const params.insertSeparator(Parameters::Separator{"Input Feature Data"}); params.insert(std::make_unique(k_ContiguousNeighborListArrayPath_Key, "Contiguous Neighbor List", "List of contiguous neighbors for each Feature.", DataPath({"NeighborList2"}), NeighborListSelectionParameter::AllowedTypes{DataType::int32})); - params.insert(std::make_unique(k_NonContiguousNeighborListArrayPath_Key, "Non-Contiguous Neighbor List", "List of non-contiguous neighbors for each Feature.", - DataPath{}, NeighborListSelectionParameter::AllowedTypes{DataType::int32})); - params.linkParameters(k_UseNonContiguousNeighbors_Key, k_ContiguousNeighborListArrayPath_Key, false); - params.linkParameters(k_UseNonContiguousNeighbors_Key, k_NonContiguousNeighborListArrayPath_Key, true); params.insert(std::make_unique(k_FeaturePhasesArrayPath_Key, "Phases", "Specifies to which Ensemble each cell belongs", DataPath({"Phases"}), ArraySelectionParameter::AllowedTypes{DataType::int32}, ArraySelectionParameter::AllowedComponentShapes{{1}})); @@ -122,8 +115,6 @@ IFilter::UniquePointer MergeTwinsFilter::clone() const IFilter::PreflightResult MergeTwinsFilter::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 pFeaturePhasesArrayPathValue = filterArgs.value(k_FeaturePhasesArrayPath_Key); auto pAvgQuatsArrayPathValue = filterArgs.value(k_AvgQuatsArrayPath_Key); @@ -141,20 +132,11 @@ IFilter::PreflightResult MergeTwinsFilter::preflightImpl(const DataStructure& da std::vector preflightUpdatedValues; std::vector cDims(1, 1); - const NeighborList* contiguousNeighborList = dataStructure.getDataAs>(pContiguousNeighborListArrayPathValue); + const auto* contiguousNeighborList = dataStructure.getDataAs>(pContiguousNeighborListArrayPathValue); if(contiguousNeighborList == nullptr) { return {MakeErrorResult(-6874600, fmt::format("Could not find contiguous neighbor list of type Int32 at path '{}' ", pContiguousNeighborListArrayPathValue.toString())), {}}; } - if(pUseNonContiguousNeighborsValue) - { - const NeighborList* nonContiguousNeighborList = dataStructure.getDataAs>(pNonContiguousNeighborListArrayPathValue); - if(nonContiguousNeighborList == nullptr) - { - return {MakeErrorResult(-6874601, fmt::format("Could not find non contiguous neighbor list of type Int32 at path '{}' ", pNonContiguousNeighborListArrayPathValue.toString())), - {}}; - } - } std::vector tDims(1, 0); auto newCellFeatureAction = std::make_unique(pNewCellFeatureAttributeMatrixNameValue, tDims); @@ -163,7 +145,7 @@ IFilter::PreflightResult MergeTwinsFilter::preflightImpl(const DataStructure& da std::vector dataArrayPaths; // Cell Data - const Int32Array* featureIds = dataStructure.getDataAs(pFeatureIdsArrayPathValue); + const auto* featureIds = dataStructure.getDataAs(pFeatureIdsArrayPathValue); if(nullptr == featureIds) { return {MakeErrorResult(-6874602, fmt::format("Could not find feature ids array of type Int32 at path '{}' ", pFeatureIdsArrayPathValue.toString())), {}}; @@ -172,7 +154,7 @@ IFilter::PreflightResult MergeTwinsFilter::preflightImpl(const DataStructure& da resultOutputActions.value().appendAction(std::move(cellParentIdsAction)); // Feature Data - const Int32Array* phases = dataStructure.getDataAs(pFeaturePhasesArrayPathValue); + const auto* phases = dataStructure.getDataAs(pFeaturePhasesArrayPathValue); if(nullptr == phases) { return {MakeErrorResult(-6874603, fmt::format("Could not find phases array of type Int32 at path '{}' ", pFeaturePhasesArrayPathValue.toString())), {}}; @@ -183,7 +165,7 @@ IFilter::PreflightResult MergeTwinsFilter::preflightImpl(const DataStructure& da resultOutputActions.value().appendAction(std::move(featureParentIdsAction)); cDims[0] = 4; - const Float32Array* avgQuats = dataStructure.getDataAs(pAvgQuatsArrayPathValue); + const auto* avgQuats = dataStructure.getDataAs(pAvgQuatsArrayPathValue); if(nullptr == avgQuats) { return {MakeErrorResult(-6874602, fmt::format("Could not find average quaternions array of type Float32 at path '{}' ", pAvgQuatsArrayPathValue.toString())), {}}; @@ -196,7 +178,7 @@ IFilter::PreflightResult MergeTwinsFilter::preflightImpl(const DataStructure& da resultOutputActions.value().appendAction(std::move(activeAction)); // Ensemble Data - const UInt32Array* crystalStructures = dataStructure.getDataAs(pCrystalStructuresArrayPathValue); + const auto* crystalStructures = dataStructure.getDataAs(pCrystalStructuresArrayPathValue); if(nullptr == crystalStructures) { return {MakeErrorResult(-6874602, fmt::format("Could not find crystal structures array of type UInt32 at path '{}' ", pCrystalStructuresArrayPathValue.toString())), {}}; @@ -226,11 +208,8 @@ Result<> MergeTwinsFilter::executeImpl(DataStructure& dataStructure, const Argum dataStructure.getDataRefAs(DataPath({filterArgs.value(k_SeedArrayName_Key)}))[0] = seed; MergeTwinsInputValues inputValues; - GroupFeaturesInputValues groupInputValues; - groupInputValues.UseNonContiguousNeighbors = filterArgs.value(k_UseNonContiguousNeighbors_Key); - groupInputValues.NonContiguousNeighborListArrayPath = filterArgs.value(k_NonContiguousNeighborListArrayPath_Key); - groupInputValues.ContiguousNeighborListArrayPath = filterArgs.value(k_ContiguousNeighborListArrayPath_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); @@ -238,21 +217,19 @@ Result<> MergeTwinsFilter::executeImpl(DataStructure& dataStructure, const Argum inputValues.FeatureIdsArrayPath = filterArgs.value(k_CellFeatureIdsArrayPath_Key); inputValues.CrystalStructuresArrayPath = filterArgs.value(k_CrystalStructuresArrayPath_Key); DataPath cellFeatureDataPath = inputValues.FeaturePhasesArrayPath.getParent(); - inputValues.CellParentIdsArrayName = inputValues.FeatureIdsArrayPath.replaceName(filterArgs.value(k_CellParentIdsArrayName_Key)); - inputValues.NewCellFeatureAttributeMatrixName = cellFeatureDataPath.replaceName(filterArgs.value(k_CreatedFeatureAttributeMatrixName_Key)); - inputValues.FeatureParentIdsArrayName = cellFeatureDataPath.createChildPath(filterArgs.value(k_FeatureParentIdsArrayName_Key)); - inputValues.ActiveArrayName = inputValues.NewCellFeatureAttributeMatrixName.createChildPath(filterArgs.value(k_ActiveArrayName_Key)); + inputValues.CellParentIdsArrayPath = inputValues.FeatureIdsArrayPath.replaceName(filterArgs.value(k_CellParentIdsArrayName_Key)); + inputValues.NewCellFeatureAttributeMatrixPath = cellFeatureDataPath.replaceName(filterArgs.value(k_CreatedFeatureAttributeMatrixName_Key)); + inputValues.FeatureParentIdsArrayPath = cellFeatureDataPath.createChildPath(filterArgs.value(k_FeatureParentIdsArrayName_Key)); + inputValues.ActiveArrayPath = inputValues.NewCellFeatureAttributeMatrixPath.createChildPath(filterArgs.value(k_ActiveArrayName_Key)); inputValues.Seed = seed; - return MergeTwins(dataStructure, messageHandler, shouldCancel, &inputValues, &groupInputValues)(); + return MergeTwins(dataStructure, messageHandler, shouldCancel, &inputValues)(); } namespace { namespace SIMPL { -constexpr StringLiteral k_UseNonContiguousNeighborsKey = "UseNonContiguousNeighbors"; -constexpr StringLiteral k_NonContiguousNeighborListArrayPathKey = "NonContiguousNeighborListArrayPath"; constexpr StringLiteral k_ContiguousNeighborListArrayPathKey = "ContiguousNeighborListArrayPath"; constexpr StringLiteral k_AxisToleranceKey = "AxisTolerance"; constexpr StringLiteral k_AngleToleranceKey = "AngleTolerance"; @@ -273,9 +250,6 @@ Result MergeTwinsFilter::FromSIMPLJson(const nlohmann::json& json) std::vector> results; - results.push_back(SIMPLConversion::ConvertParameter(args, json, SIMPL::k_UseNonContiguousNeighborsKey, k_UseNonContiguousNeighbors_Key)); - results.push_back(SIMPLConversion::ConvertParameter(args, json, SIMPL::k_NonContiguousNeighborListArrayPathKey, - k_NonContiguousNeighborListArrayPath_Key)); results.push_back( SIMPLConversion::ConvertParameter(args, json, SIMPL::k_ContiguousNeighborListArrayPathKey, k_ContiguousNeighborListArrayPath_Key)); results.push_back(SIMPLConversion::ConvertParameter>(args, json, SIMPL::k_AxisToleranceKey, k_AxisTolerance_Key)); diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeTwinsFilter.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeTwinsFilter.hpp index 2969dc7829..9dddaad50c 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeTwinsFilter.hpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/MergeTwinsFilter.hpp @@ -24,8 +24,6 @@ class ORIENTATIONANALYSIS_EXPORT MergeTwinsFilter : public IFilter MergeTwinsFilter& operator=(MergeTwinsFilter&&) 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"; diff --git a/src/Plugins/OrientationAnalysis/test/MergeTwinsTest.cpp b/src/Plugins/OrientationAnalysis/test/MergeTwinsTest.cpp index 3d82050cd5..f70a838821 100644 --- a/src/Plugins/OrientationAnalysis/test/MergeTwinsTest.cpp +++ b/src/Plugins/OrientationAnalysis/test/MergeTwinsTest.cpp @@ -199,8 +199,6 @@ TEST_CASE("Reconstruction::MergeTwinsFilter: Valid Execution", "[Reconstruction] DataPath nonContiguousNeighborList; // Create default Parameters for the filter. - args.insertOrAssign(MergeTwinsFilter::k_UseNonContiguousNeighbors_Key, std::make_any(false)); - args.insertOrAssign(MergeTwinsFilter::k_NonContiguousNeighborListArrayPath_Key, std::make_any(nonContiguousNeighborList)); args.insertOrAssign(MergeTwinsFilter::k_ContiguousNeighborListArrayPath_Key, std::make_any(k_NeighborListPath)); args.insertOrAssign(MergeTwinsFilter::k_AxisTolerance_Key, std::make_any(1.0f)); args.insertOrAssign(MergeTwinsFilter::k_AngleTolerance_Key, std::make_any(1.0f)); diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ScalarSegmentFeatures.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ScalarSegmentFeatures.cpp index d67e441173..53b64767e3 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ScalarSegmentFeatures.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ScalarSegmentFeatures.cpp @@ -207,9 +207,6 @@ Result<> ScalarSegmentFeatures::operator()() m_CompareFunctor = std::shared_ptr(new SegmentFeatures::CompareFunctor()); // The default CompareFunctor which ALWAYS returns false for the comparison } - // Generate the random voxel indices that will be used for the seed points to start a new grain growth/agglomeration - auto totalPoints = inputDataArray->getNumberOfTuples(); - // // Add compare function to arguments // Arguments newArgs = args; // newArgs.insert(k_CompareFunctKey, compare.get()); @@ -232,12 +229,7 @@ Result<> ScalarSegmentFeatures::operator()() // would look like a smooth gradient. This is a user input parameter if(m_InputValues->pShouldRandomizeFeatureIds) { - const int64 rangeMin = 0; - const int64 rangeMax = totalPoints - 1; - Int64Distribution distribution; - initializeStaticVoxelSeedGenerator(distribution, rangeMin, rangeMax); - totalPoints = gridGeom->getNumberOfCells(); - randomizeFeatureIds(m_FeatureIdsArray, totalPoints, totalFeatures, distribution); + randomizeFeatureIds(m_FeatureIdsArray, totalFeatures); } return {}; diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ScalarSegmentFeatures.hpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ScalarSegmentFeatures.hpp index 4aa36b8f58..2239932aa5 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ScalarSegmentFeatures.hpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ScalarSegmentFeatures.hpp @@ -34,8 +34,6 @@ struct SIMPLNXCORE_EXPORT ScalarSegmentFeaturesInputValues class SIMPLNXCORE_EXPORT ScalarSegmentFeatures : public SegmentFeatures { public: - using SeedGenerator = std::mt19937_64; - using Int64Distribution = std::uniform_int_distribution; using FeatureIdsArrayType = Int32Array; using GoodVoxelsArrayType = BoolArray; @@ -64,8 +62,8 @@ class SIMPLNXCORE_EXPORT ScalarSegmentFeatures : public SegmentFeatures * @brief * @param data * @param args - * @param referencepoint - * @param neighborpoint + * @param referencePoint + * @param neighborPoint * @param gnum * @return bool */ diff --git a/src/simplnx/Utilities/SegmentFeatures.cpp b/src/simplnx/Utilities/SegmentFeatures.cpp index b97491e73c..0452c00848 100644 --- a/src/simplnx/Utilities/SegmentFeatures.cpp +++ b/src/simplnx/Utilities/SegmentFeatures.cpp @@ -22,22 +22,30 @@ Result<> SegmentFeatures::execute(IGridGeometry* gridGeom) int64 dims[3] = {static_cast(udims[0]), static_cast(udims[1]), static_cast(udims[2])}; + // Initialize sequence of execution modifiers int32 gnum = 1; - int64 seed = 0; + int64 nextSeed = 0; + int64 seed = getSeed(gnum, nextSeed); + usize size = 0; + + // Initialize calculation modifiers int64 neighbor = 0; bool good = false; int64 col = 0, row = 0, plane = 0; - usize size = 0; + + // Initialize containers usize initialVoxelsListSize = 100000; - std::vector voxelslist(initialVoxelsListSize, -1); - int64 neighpoints[6] = {0, 0, 0, 0, 0, 0}; - neighpoints[0] = -(dims[0] * dims[1]); - neighpoints[1] = -dims[0]; - neighpoints[2] = -1; - neighpoints[3] = 1; - neighpoints[4] = dims[0]; - neighpoints[5] = (dims[0] * dims[1]); - int64 nextSeed = 0; + std::vector voxelsList(initialVoxelsListSize, -1); + + int64 neighPoints[6] = {0, 0, 0, 0, 0, 0}; + { // Initialize neighPoints in a readable fashion + neighPoints[0] = -(dims[0] * dims[1]); + neighPoints[1] = -dims[0]; + neighPoints[2] = -1; + neighPoints[3] = 1; + neighPoints[4] = dims[0]; + neighPoints[5] = (dims[0] * dims[1]); + } auto start = std::chrono::steady_clock::now(); @@ -47,84 +55,83 @@ Result<> SegmentFeatures::execute(IGridGeometry* gridGeom) { return {}; } - seed = getSeed(gnum, nextSeed); - nextSeed = seed + 1; - if(seed >= 0) + + size = 0; + voxelsList[size] = seed; + size++; + while(size > 0) { - size = 0; - voxelslist[size] = seed; - size++; - while(size > 0) + int64 currentPoint = voxelsList[size - 1]; + size -= 1; + col = currentPoint % dims[0]; + row = (currentPoint / dims[0]) % dims[1]; + plane = currentPoint / (dims[0] * dims[1]); + for(int32 i = 0; i < 6; i++) { - int64 currentpoint = voxelslist[size - 1]; - size -= 1; - col = currentpoint % dims[0]; - row = (currentpoint / dims[0]) % dims[1]; - plane = currentpoint / (dims[0] * dims[1]); - for(int32 i = 0; i < 6; i++) + good = true; + neighbor = currentPoint + neighPoints[i]; + if(i == 0 && plane == 0) { - good = true; - neighbor = currentpoint + neighpoints[i]; - if(i == 0 && plane == 0) - { - good = false; - } - if(i == 5 && plane == (dims[2] - 1)) - { - good = false; - } - if(i == 1 && row == 0) - { - good = false; - } - if(i == 4 && row == (dims[1] - 1)) - { - good = false; - } - if(i == 2 && col == 0) - { - good = false; - } - if(i == 3 && col == (dims[0] - 1)) - { - good = false; - } - if(good) + good = false; + } + if(i == 5 && plane == (dims[2] - 1)) + { + good = false; + } + if(i == 1 && row == 0) + { + good = false; + } + if(i == 4 && row == (dims[1] - 1)) + { + good = false; + } + if(i == 2 && col == 0) + { + good = false; + } + if(i == 3 && col == (dims[0] - 1)) + { + good = false; + } + if(good) + { + if(determineGrouping(currentPoint, neighbor, gnum)) { - if(determineGrouping(currentpoint, neighbor, gnum)) + voxelsList[size] = neighbor; + size++; + if(neighbor == nextSeed) { - voxelslist[size] = neighbor; - size++; - if(neighbor == nextSeed) - { - nextSeed = neighbor + 1; - } - if(size >= voxelslist.size()) + nextSeed = neighbor + 1; + } + if(size >= voxelsList.size()) + { + size = voxelsList.size(); + voxelsList.resize(size + initialVoxelsListSize); + for(std::vector::size_type j = size; j < voxelsList.size(); ++j) { - size = voxelslist.size(); - voxelslist.resize(size + initialVoxelsListSize); - for(std::vector::size_type j = size; j < voxelslist.size(); ++j) - { - voxelslist[j] = -1; - } + voxelsList[j] = -1; } } } } } + } - voxelslist.assign(initialVoxelsListSize, -1); - gnum++; + voxelsList.assign(initialVoxelsListSize, -1); + gnum++; - auto now = std::chrono::steady_clock::now(); - // Only send updates every 1 second - if(std::chrono::duration_cast(now - start).count() > 1000) - { - std::string message = fmt::format("Features Found: {}", gnum); - m_MessageHandler(nx::core::IFilter::ProgressMessage{nx::core::IFilter::Message::Type::Info, message, 0}); - start = std::chrono::steady_clock::now(); - } + auto now = std::chrono::steady_clock::now(); + // Only send updates every 1 second + if(std::chrono::duration_cast(now - start).count() > 1000) + { + std::string message = fmt::format("Features Found: {}", gnum); + m_MessageHandler(nx::core::IFilter::ProgressMessage{nx::core::IFilter::Message::Type::Info, message, 0}); + start = std::chrono::steady_clock::now(); } + + nextSeed = seed + 1; + seed = getSeed(gnum, nextSeed); } m_MessageHandler({IFilter::Message::Type::Info, fmt::format("Total Features Found: {}", gnum)}); @@ -143,53 +150,45 @@ bool SegmentFeatures::determineGrouping(int64 referencePoint, int64 neighborPoin } // ----------------------------------------------------------------------------- -SegmentFeatures::SeedGenerator SegmentFeatures::initializeStaticVoxelSeedGenerator(Int64Distribution& distribution, const int64 rangeMin, const int64 rangeMax) const +SegmentFeatures::SeedGenerator SegmentFeatures::initializeStaticVoxelSeedGenerator() const { - SeedGenerator generator; - generator.seed(SeedGenerator::default_seed); - distribution = std::uniform_int_distribution(rangeMin, rangeMax); - - return generator; + return SeedGenerator(SeedGenerator::default_seed); } // ----------------------------------------------------------------------------- -void SegmentFeatures::randomizeFeatureIds(nx::core::Int32Array* featureIds, uint64 totalPoints, uint64 totalFeatures, Int64Distribution& distribution) const +void SegmentFeatures::randomizeFeatureIds(nx::core::Int32Array* featureIds, uint64 totalFeatures) const { m_MessageHandler(IFilter::Message::Type::Info, "Randomizing Feature Ids"); // Generate an even distribution of numbers between the min and max range - const int64 rangeMin = 1; - const int64 rangeMax = totalFeatures - 1; - auto generator = initializeStaticVoxelSeedGenerator(distribution, rangeMin, rangeMax); + const usize rangeMin = 1; + const usize rangeMax = totalFeatures - 1; + auto gen = initializeStaticVoxelSeedGenerator(); + std::uniform_real_distribution dist(0, 1); - DataStructure tmpStructure; - auto* rndNumbers = Int64Array::CreateWithStore>(tmpStructure, std::string("_INTERNAL_USE_ONLY_NewFeatureIds"), std::vector{totalFeatures}, std::vector{1}); - auto& rndStore = rndNumbers->getDataStoreRef(); - - for(int64 i = 0; i < totalFeatures; ++i) - { - rndStore.setValue(i, i); - } - - int64 r = 0; - int64 temp = 0; + std::vector randomIds(totalFeatures); + std::iota(randomIds.begin(), randomIds.end(), 0); //--- Shuffle elements by randomly exchanging each with one other. - for(int64 i = 1; i < totalFeatures; i++) + for(usize i = 1; i < totalFeatures; i++) { - r = distribution(generator); // Random remaining position. - if(r >= totalFeatures) + auto r = static_cast(std::floor(dist(gen) * static_cast(rangeMax))); // Random remaining position. + if(r < rangeMin) { continue; } - temp = rndStore.getValue(i); - rndStore.setValue(i, rndStore.getValue(r)); - rndStore.setValue(r, temp); + + int32 randId_i = randomIds[i]; + randomIds[i] = randomIds[r]; + randomIds[r] = randId_i; } - // Now adjust all the Grain Id values for each Voxel + // Now adjust all the Grain ID values for each Voxel auto& featureIdsStore = featureIds->getDataStoreRef(); + + // instead of taking total points as an input just extract the size, so we don't walk of + usize totalPoints = featureIdsStore.getSize(); for(int64 i = 0; i < totalPoints; ++i) { - featureIdsStore[i] = rndStore[featureIdsStore[i]]; + featureIdsStore[i] = randomIds[featureIdsStore[i]]; } } diff --git a/src/simplnx/Utilities/SegmentFeatures.hpp b/src/simplnx/Utilities/SegmentFeatures.hpp index 0f97abf25b..2a0523477d 100644 --- a/src/simplnx/Utilities/SegmentFeatures.hpp +++ b/src/simplnx/Utilities/SegmentFeatures.hpp @@ -20,7 +20,6 @@ class SIMPLNX_EXPORT SegmentFeatures public: using SeedGenerator = std::mt19937_64; - using Int64Distribution = std::uniform_int_distribution; SegmentFeatures(DataStructure& dataStructure, const std::atomic_bool& shouldCancel, const IFilter::MessageHandler& mesgHandler); @@ -62,20 +61,16 @@ class SIMPLNX_EXPORT SegmentFeatures /** * @brief * @param featureIds - * @param totalPoints * @param totalFeatures * @param distribution */ - virtual void randomizeFeatureIds(Int32Array* featureIds, uint64 totalPoints, uint64 totalFeatures, Int64Distribution& distribution) const; + virtual void randomizeFeatureIds(Int32Array* featureIds, uint64 totalFeatures) const; /** * @brief - * @param distribution - * @param rangeMin - * @param rangeMax * @return */ - virtual SeedGenerator initializeStaticVoxelSeedGenerator(Int64Distribution& distribution, const int64 rangeMin, const int64 rangeMax) const; + virtual SeedGenerator initializeStaticVoxelSeedGenerator() const; /* from http://www.newty.de/fpt/functor.html */ /** diff --git a/wrapping/python/examples/pipelines/OrientationAnalysis/08_Small_IN100_Full_Reconstruction.py b/wrapping/python/examples/pipelines/OrientationAnalysis/08_Small_IN100_Full_Reconstruction.py index e6afc1b6a4..5d2d88d916 100644 --- a/wrapping/python/examples/pipelines/OrientationAnalysis/08_Small_IN100_Full_Reconstruction.py +++ b/wrapping/python/examples/pipelines/OrientationAnalysis/08_Small_IN100_Full_Reconstruction.py @@ -239,8 +239,8 @@ feature_ids_path=nx.DataPath("DataContainer/CellData/FeatureIds"), feature_parent_ids_array_name="ParentIds", feature_phases_array_path=nx.DataPath("DataContainer/CellFeatureData/Phases"), - created_feature_attribute_matrix_name="NewGrain Data", - use_non_contiguous_neighbors=False + created_feature_attribute_matrix_name="NewGrain Data" + # use_non_contiguous_neighbors=False # non_contiguous_neighbor_list_array_path: DataPath = ..., # Not currently part of the code ) nxtest.check_filter_result(nx_filter, result)