diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeArrayStatistics.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeArrayStatistics.cpp index fb3c0dbdd5..ececcfedbe 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeArrayStatistics.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeArrayStatistics.cpp @@ -44,8 +44,8 @@ class ComputeArrayStatisticsByIndexImpl ComputeArrayStatisticsByIndexImpl(bool length, bool min, bool max, bool mean, bool mode, bool stdDeviation, bool summation, bool hist, float64 histmin, float64 histmax, bool histfullrange, int32 numBins, bool modalBinRanges, const std::unique_ptr& mask, const Int32Array* featureIds, const DataArray& source, BoolArray* featureHasDataArray, UInt64Array* lengthArray, DataArray* minArray, DataArray* maxArray, Float32Array* meanArray, NeighborList* modeArray, - Float32Array* stdDevArray, Float32Array* summationArray, UInt64Array* histArray, UInt64Array* mostPopulatedBinArray, NeighborList* modalBinRangesArray, - ComputeArrayStatistics* filter) + Float32Array* stdDevArray, Float32Array* summationArray, UInt64Array* histBinCountsArray, DataArray* histBinRangesArray, UInt64Array* mostPopulatedBinArray, + NeighborList* modalBinRangesArray, ComputeArrayStatistics* filter) : m_Length(length) , m_Min(min) , m_Max(max) @@ -70,7 +70,8 @@ class ComputeArrayStatisticsByIndexImpl , m_ModeArray(modeArray) , m_StdDevArray(stdDevArray) , m_SummationArray(summationArray) - , m_HistArray(histArray) + , m_HistBinCountsArray(histBinCountsArray) + , m_HistBinRangesArray(histBinRangesArray) , m_MostPopulatedBinArray(mostPopulatedBinArray) , m_ModalBinRangesArray(modalBinRangesArray) , m_Filter(filter) @@ -215,10 +216,16 @@ class ComputeArrayStatisticsByIndexImpl } } - AbstractDataStore* histDataStorePtr = nullptr; - if(m_HistArray != nullptr) + AbstractDataStore* binCountsStorePtr = nullptr; + if(m_HistBinCountsArray != nullptr) { - histDataStorePtr = m_HistArray->getDataStore(); + binCountsStorePtr = m_HistBinCountsArray->getDataStore(); + } + + AbstractDataStore* binRangesStorePtr = nullptr; + if(m_HistBinRangesArray != nullptr) + { + binRangesStorePtr = m_HistBinRangesArray->getDataStore(); } AbstractDataStore* mostPopulatedBinDataStorePtr = nullptr; @@ -227,8 +234,9 @@ class ComputeArrayStatisticsByIndexImpl mostPopulatedBinDataStorePtr = m_MostPopulatedBinArray->getDataStore(); } - if(m_Histogram && histDataStorePtr != nullptr) + if(m_Histogram && binCountsStorePtr != nullptr && binRangesStorePtr != nullptr) { + std::vector ranges(m_NumBins + 1); std::vector histogram(m_NumBins, 0); if(length[localFeatureIndex] > 0) { @@ -241,6 +249,8 @@ class ComputeArrayStatisticsByIndexImpl histMax = static_cast(max[localFeatureIndex]); } + HistogramUtilities::serial::FillBinRanges(ranges, std::make_pair(static_cast(histMin), static_cast(histMax)), m_NumBins); + const float32 increment = (histMax - histMin) / (m_NumBins); if(std::fabs(increment) < 1E-10) { @@ -263,8 +273,8 @@ class ComputeArrayStatisticsByIndexImpl continue; } const auto value = static_cast(m_Source[i]); - const auto bin = static_cast((value - histMin) / increment); // find bin for this input array value - if((bin >= 0) && (bin < m_NumBins)) // make certain bin is in range + const auto bin = static_cast(HistogramUtilities::serial::CalculateBin(value, histMin, increment)); // find bin for this input array value + if((bin >= 0) && (bin < m_NumBins)) // make certain bin is in range { ++histogram[bin]; // increment histogram element corresponding to this input array value } @@ -288,7 +298,7 @@ class ComputeArrayStatisticsByIndexImpl for(int i = 0; i < modeList->size(); i++) { const float32 mode = modeList->at(i); - const auto modalBin = static_cast((mode - histMin) / increment); + const auto modalBin = static_cast(HistogramUtilities::serial::CalculateBin(mode, histMin, increment)); float32 minBinValue = 0.0f; float32 maxBinValue = 0.0f; if((modalBin >= 0) && (modalBin < m_NumBins)) // make certain bin is in range @@ -308,7 +318,8 @@ class ComputeArrayStatisticsByIndexImpl } } // end of length if - histDataStorePtr->setTuple(j, histogram); + binCountsStorePtr->setTuple(j, histogram); + binRangesStorePtr->setTuple(j, ranges); auto maxElementIt = std::max_element(histogram.begin(), histogram.end()); uint64 index = std::distance(histogram.begin(), maxElementIt); @@ -405,7 +416,8 @@ class ComputeArrayStatisticsByIndexImpl NeighborList* m_ModeArray = nullptr; Float32Array* m_StdDevArray = nullptr; Float32Array* m_SummationArray = nullptr; - UInt64Array* m_HistArray = nullptr; + UInt64Array* m_HistBinCountsArray = nullptr; + DataArray* m_HistBinRangesArray = nullptr; UInt64Array* m_MostPopulatedBinArray = nullptr; NeighborList* m_ModalBinRangesArray = nullptr; ComputeArrayStatistics* m_Filter = nullptr; @@ -625,12 +637,18 @@ void FindStatisticsImpl(const ContainerType& data, std::vector& arrays, std::atomic_bool neverCancel{false}; std::atomic overflow{0}; - Result<> result = HistogramUtilities::serial::GenerateHistogram(data, binRangesStore, range, neverCancel, inputValues->NumBins, binCountsStore, overflow); + std::vector binCounts(inputValues->NumBins, 0); + std::vector binRanges(inputValues->NumBins + 1); + + Result<> result = HistogramUtilities::serial::GenerateHistogram(data, binRanges, range, neverCancel, inputValues->NumBins, binCounts, overflow); + + binCountsStore.setTuple(0, binCounts); + binRangesStore.setTuple(0, binRanges); - auto maxElementIt = std::max_element(binCountsStore.begin(), binCountsStore.end()); - uint64 index = std::distance(binCountsStore.begin(), maxElementIt); + auto maxElementIt = std::max_element(binCounts.begin(), binCounts.end()); + uint64 index = std::distance(binCounts.begin(), maxElementIt); mostPopBinStore.setComponent(0, 0, index); - mostPopBinStore.setComponent(0, 1, binCountsStore[index]); + mostPopBinStore.setComponent(0, 1, binCounts[index]); if(inputValues->FindModalBinRanges) { @@ -648,7 +666,7 @@ void FindStatisticsImpl(const ContainerType& data, std::vector& arrays, for(const T& mode : array5Ptr->at(0)) { - std::pair modalRange = StatisticsCalculations::findModalBinRange(data, binRangesStore, mode); + std::pair modalRange = StatisticsCalculations::findModalBinRange(data, binRanges, mode); array11Ptr->addEntry(0, modalRange.first); array11Ptr->addEntry(0, modalRange.second); } @@ -681,10 +699,11 @@ void FindStatistics(const DataArray& source, const Int32Array* featureIds, co auto* modeArrayPtr = dynamic_cast*>(arrays[5]); auto* stdDevArrayPtr = dynamic_cast(arrays[6]); auto* summationArrayPtr = dynamic_cast(arrays[7]); - auto* histArrayPtr = dynamic_cast(arrays[8]); + auto* histBinCountsArrayPtr = dynamic_cast(arrays[8]); auto* mostPopulatedBinPtr = dynamic_cast(arrays[10]); auto* modalBinsArrayPtr = dynamic_cast*>(arrays[11]); - auto* featureHasDataPtr = dynamic_cast(arrays[12]); + auto* histBinRangesArrayPtr = dynamic_cast*>(arrays[12]); + auto* featureHasDataPtr = dynamic_cast(arrays[13]); IParallelAlgorithm::AlgorithmArrays indexAlgArrays; indexAlgArrays.push_back(&source); @@ -695,7 +714,8 @@ void FindStatistics(const DataArray& source, const Int32Array* featureIds, co indexAlgArrays.push_back(meanArrayPtr); indexAlgArrays.push_back(stdDevArrayPtr); indexAlgArrays.push_back(summationArrayPtr); - indexAlgArrays.push_back(histArrayPtr); + indexAlgArrays.push_back(histBinCountsArrayPtr); + indexAlgArrays.push_back(histBinRangesArrayPtr); indexAlgArrays.push_back(mostPopulatedBinPtr); #ifdef SIMPLNX_ENABLE_MULTICORE @@ -708,8 +728,8 @@ void FindStatistics(const DataArray& source, const Int32Array* featureIds, co ComputeArrayStatisticsByIndexImpl(inputValues->FindLength, inputValues->FindMin, inputValues->FindMax, inputValues->FindMean, inputValues->FindMode, inputValues->FindStdDeviation, inputValues->FindSummation, inputValues->FindHistogram, inputValues->MinRange, inputValues->MaxRange, inputValues->UseFullRange, inputValues->NumBins, inputValues->FindModalBinRanges, mask, featureIds, source, featureHasDataPtr, - lengthArrayPtr, minArrayPtr, maxArrayPtr, meanArrayPtr, modeArrayPtr, stdDevArrayPtr, summationArrayPtr, histArrayPtr, mostPopulatedBinPtr, - modalBinsArrayPtr, filter), + lengthArrayPtr, minArrayPtr, maxArrayPtr, meanArrayPtr, modeArrayPtr, stdDevArrayPtr, summationArrayPtr, histBinCountsArrayPtr, + histBinRangesArrayPtr, mostPopulatedBinPtr, modalBinsArrayPtr, filter), simplePartitioner); } else @@ -717,10 +737,11 @@ void FindStatistics(const DataArray& source, const Int32Array* featureIds, co ParallelDataAlgorithm indexAlg; indexAlg.setRange(0, numFeatures); indexAlg.requireArraysInMemory(indexAlgArrays); - indexAlg.execute(ComputeArrayStatisticsByIndexImpl( - inputValues->FindLength, inputValues->FindMin, inputValues->FindMax, inputValues->FindMean, inputValues->FindMode, inputValues->FindStdDeviation, inputValues->FindSummation, - inputValues->FindHistogram, inputValues->MinRange, inputValues->MaxRange, inputValues->UseFullRange, inputValues->NumBins, inputValues->FindModalBinRanges, mask, featureIds, source, - featureHasDataPtr, lengthArrayPtr, minArrayPtr, maxArrayPtr, meanArrayPtr, modeArrayPtr, stdDevArrayPtr, summationArrayPtr, histArrayPtr, mostPopulatedBinPtr, modalBinsArrayPtr, filter)); + indexAlg.execute(ComputeArrayStatisticsByIndexImpl(inputValues->FindLength, inputValues->FindMin, inputValues->FindMax, inputValues->FindMean, inputValues->FindMode, + inputValues->FindStdDeviation, inputValues->FindSummation, inputValues->FindHistogram, inputValues->MinRange, inputValues->MaxRange, + inputValues->UseFullRange, inputValues->NumBins, inputValues->FindModalBinRanges, mask, featureIds, source, featureHasDataPtr, + lengthArrayPtr, minArrayPtr, maxArrayPtr, meanArrayPtr, modeArrayPtr, stdDevArrayPtr, summationArrayPtr, histBinCountsArrayPtr, + histBinRangesArrayPtr, mostPopulatedBinPtr, modalBinsArrayPtr, filter)); } #endif @@ -1067,8 +1088,8 @@ Result<> ComputeArrayStatistics::operator()() usize numFeatures = 0; if(m_InputValues->ComputeByIndex) { - arrays.resize(13); - arrays[12] = m_DataStructure.getDataAs(m_InputValues->FeatureHasDataArrayName); + arrays.resize(14); + arrays[13] = m_DataStructure.getDataAs(m_InputValues->FeatureHasDataArrayName); const auto& featureIds = m_DataStructure.getDataRefAs(m_InputValues->FeatureIdsArrayPath); numFeatures = findNumFeatures(featureIds); diff --git a/src/simplnx/Utilities/HistogramUtilities.hpp b/src/simplnx/Utilities/HistogramUtilities.hpp index 9797e37b27..f53fb45ce7 100644 --- a/src/simplnx/Utilities/HistogramUtilities.hpp +++ b/src/simplnx/Utilities/HistogramUtilities.hpp @@ -5,9 +5,11 @@ #include "simplnx/Common/Result.hpp" #include "simplnx/DataStructure/IDataArray.hpp" -namespace nx::core::HistogramUtilities +namespace nx::core { -namespace serial +namespace SIMPLNX_EXPORT HistogramUtilities +{ +namespace SIMPLNX_EXPORT serial { /** * @function FillBinRange @@ -21,12 +23,12 @@ namespace serial * @param increment this is the uniform size of the bins */ template -SIMPLNX_EXPORT void FillBinRanges(Container& outputContainer, const std::pair& rangeMinMax, const int32 numBins, const Type increment) +void FillBinRanges(Container& outputContainer, const std::pair& rangeMinMax, const int32 numBins, const Type increment) { // WARNING: No bounds checking for type compatibility, it is expected to be done higher up where the type is not abstracted // EXPECTED CONTAINER SIZE: numBins + 1 - if(numBins == 1) // if one bin, just set the first element to total number of points + if(numBins == 1) // if one bin, just set the range to the inputs { outputContainer[0] = rangeMinMax.first; outputContainer[1] = rangeMinMax.second; @@ -52,7 +54,7 @@ SIMPLNX_EXPORT void FillBinRanges(Container& outputContainer, const std::pair -SIMPLNX_EXPORT void FillBinRanges(Container& outputContainer, const std::pair& rangeMinMax, const int32 numBins) +void FillBinRanges(Container& outputContainer, const std::pair& rangeMinMax, const int32 numBins) { // DEV NOTE: this function also serves to act as a jumping off point for implementing logarithmic histograms down the line @@ -63,7 +65,7 @@ SIMPLNX_EXPORT void FillBinRanges(Container& outputContainer, const std::pair -SIMPLNX_EXPORT Type CalculateBin(Type value, Type min, Type increment) +Type CalculateBin(Type value, Type min, Type increment) { return std::floor((value - min) / increment); } @@ -87,8 +89,8 @@ SIMPLNX_EXPORT Type CalculateBin(Type value, Type min, Type increment) * @param overflow this is an atomic counter for the number of values that fall outside the bin range */ template class InputContainer, template class OutputContainer> -SIMPLNX_EXPORT Result<> GenerateHistogram(const InputContainer& inputStore, OutputContainer& binRangesStore, const std::pair& rangeMinMax, const std::atomic_bool& shouldCancel, - const int32 numBins, OutputContainer& histogramCountsStore, std::atomic& overflow) +Result<> GenerateHistogram(const InputContainer& inputStore, OutputContainer& binRangesStore, const std::pair& rangeMinMax, const std::atomic_bool& shouldCancel, + const int32 numBins, OutputContainer& histogramCountsStore, std::atomic& overflow) { usize end = 0; if constexpr(std::is_same_v, InputContainer>) @@ -159,7 +161,7 @@ SIMPLNX_EXPORT Result<> GenerateHistogram(const InputContainer& inputStore * @brief This is a compatibility functor that leverages existing typecasting functions to execute GenerateHistogram() cleanly. In it there are two * definitions for the `()` operator that allows for implicit calculation of range, predicated whether a range is passed in or not */ -struct SIMPLNX_EXPORT GenerateHistogramFunctor +struct GenerateHistogramFunctor { template Result<> operator()(const IDataArray* inputArray, IDataArray* binRangesArray, ArgsT&&... args) const @@ -190,7 +192,7 @@ struct SIMPLNX_EXPORT GenerateHistogramFunctor }; } // namespace serial -namespace concurrent +namespace SIMPLNX_EXPORT concurrent { /** * @class GenerateHistogramImpl @@ -199,7 +201,7 @@ namespace concurrent * @tparam SizeType this is the scalar type of the bin counts container */ template -class SIMPLNX_EXPORT GenerateHistogramImpl +class GenerateHistogramImpl { public: /** @@ -283,4 +285,5 @@ struct InstantiateHistogramImplFunctor } }; } // namespace concurrent -} // namespace nx::core::HistogramUtilities +} // namespace HistogramUtilities +} // namespace nx::core diff --git a/src/simplnx/Utilities/Math/StatisticsCalculations.hpp b/src/simplnx/Utilities/Math/StatisticsCalculations.hpp index a5996ff4a2..c65b8b5593 100644 --- a/src/simplnx/Utilities/Math/StatisticsCalculations.hpp +++ b/src/simplnx/Utilities/Math/StatisticsCalculations.hpp @@ -248,17 +248,17 @@ std::pair findHistogramRange(const C& source, T histmin, T histm // ----------------------------------------------------------------------------- template