diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ReadH5Ebsd.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ReadH5Ebsd.cpp index 54dd80e122..028d1e15ce 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ReadH5Ebsd.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ReadH5Ebsd.cpp @@ -179,7 +179,7 @@ nx::core::Result<> LoadEbsdData(const nx::core::ReadH5EbsdInputValues* mInputVal err = ebsdReader->loadData(dcDims[0], dcDims[1], dcDims[2], mRefFrameZDir); if(err < 0) { - return {nx::core::MakeErrorResult(-50003, fmt::format("Error loading data from H5Ebsd file '{}'", mInputValues->inputFilePath))}; + return {nx::core::MakeErrorResult(-50003, fmt::format("Error loading data from H5Ebsd file '{}'. Error from EbsdLib is {}", mInputValues->inputFilePath, err))}; } nx::core::DataPath geometryPath = mInputValues->dataContainerPath; diff --git a/src/Plugins/SimplnxCore/docs/ComputeArrayHistogramFilter.md b/src/Plugins/SimplnxCore/docs/ComputeArrayHistogramFilter.md index 5b4fa50638..5186deb103 100644 --- a/src/Plugins/SimplnxCore/docs/ComputeArrayHistogramFilter.md +++ b/src/Plugins/SimplnxCore/docs/ComputeArrayHistogramFilter.md @@ -8,6 +8,11 @@ Statistics(Ensemble) This **Filter** accepts **DataArray(s)** as input, creates histogram **DataArray(s)** in specified **DataGroup** from input **DataArray(s)**, then calculates histogram values according to user parameters and stores values in created histogram **DataArray(s)**. +The output is in the form of 2 Data Arrays. The first data array will have the counts. The number of tuples of the array is +the same as the number of bins in the histogram. The second data array will have the bin ranges. The array has 2 components +where the first component of each tuple is the minimum of the bin (inclusive) and the second component of the tuple +is the maximum for that bin (exclusive). + ## Example Data Using some data about the "Old Faithful" geyser in the United States from the [R site](http://www.r-tutor.com/elementary-statistics/quantitative-data/frequency-distribution-quantitative-data), here is the top few lines of data: diff --git a/src/Plugins/SimplnxCore/docs/ComputeArrayStatisticsFilter.md b/src/Plugins/SimplnxCore/docs/ComputeArrayStatisticsFilter.md index 62bce10df2..8c972d3b89 100644 --- a/src/Plugins/SimplnxCore/docs/ComputeArrayStatisticsFilter.md +++ b/src/Plugins/SimplnxCore/docs/ComputeArrayStatisticsFilter.md @@ -30,7 +30,27 @@ The user must select a destination **Attribute Matrix** in which the computed st Special operations occur for certain statistics if the supplied array is of type *bool* (for example, a mask array produced [when thresholding](@ref multithresholdobjects)). The length, minimum, maximum, median, mode, and summation are computed as normal (although the resulting values may be platform dependent). The mean and standard deviation for a boolean array will be true if there are more instances of true in the array than false. If *Standardize Data* is chosen for a boolean array, no actual modifications will be made to the input. These operations for boolean inputs are chosen as a basic convention, and are not intended be representative of true boolean logic. -**Note**: If *Find Histogram* is on AND *Compute Statistics Per Feature/Ensemble* is on, then any features that have the exact same value throughout the entire feature will have its first histogram bin set to the total count of feature values. All other bins will be 0. + +## Hisogram Notes: + +When creating a histogram the output arrays can take 2 different layouts. + +### Histogram and "Compute Statistics by Feature/Ensemble" is NOT selected + +The output is in the form of 2 Data Arrays. The first data array will have the counts. The number of tuples of the array is +the same as the number of bins in the histogram. The second data array will have the bin ranges. The array has 2 components +where the first component of each tuple is the minimum of the bin (inclusive) and the second component of the tuple +is the maximum for that bin (exclusive). + +### Histogram and "Compute Statistics by Feature/Ensemble" IS selected + +The output is in the form of 2 arrays, but for each output array the number of tuples of the array +is the same as the number of features/ensembles for which you are calculating the statistics. The number of components +for the "Counts" array is now the number of bins. The second array is the same tuple shape as the +counts array but now the number of components is the number of bins * 2 and the data +is encoded as [Bin Min, Bin Max], [Bin Min, Bin Max]. + +**Note**: % Auto generated parameter table will be inserted here diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeArrayStatistics.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeArrayStatistics.cpp index 2258cef499..9f5e5c3513 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeArrayStatistics.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeArrayStatistics.cpp @@ -236,7 +236,7 @@ class ComputeArrayStatisticsByIndexImpl if(m_Histogram && binCountsStorePtr != nullptr && binRangesStorePtr != nullptr) { - std::vector ranges(m_NumBins + 1); + std::vector ranges(m_NumBins * 2); std::vector histogram(m_NumBins, 0); if(length[localFeatureIndex] > 0) { @@ -630,7 +630,7 @@ void FindStatisticsImpl(const ContainerType& data, std::vector& arrays, std::atomic_bool neverCancel{false}; std::atomic overflow{0}; std::vector binCounts(inputValues->NumBins, 0); - std::vector binRanges(inputValues->NumBins + 1); + std::vector binRanges(inputValues->NumBins * 2); Result<> result = {}; if constexpr(std::is_same_v, ContainerType>) @@ -642,8 +642,12 @@ void FindStatisticsImpl(const ContainerType& data, std::vector& arrays, result = HistogramUtilities::serial::GenerateHistogram(data, binRanges, range, neverCancel, inputValues->NumBins, binCounts, overflow); } - binCountsStore.setTuple(0, binCounts); - binRangesStore.setTuple(0, binRanges); + for(size_t i = 0; i < inputValues->NumBins; i++) + { + binCountsStore.setComponent(i, 0, binCounts[i]); + binRangesStore.setComponent(i, 0, binRanges[i * 2]); + binRangesStore.setComponent(i, 1, binRanges[i * 2 + 1]); + } auto maxElementIt = std::max_element(binCounts.begin(), binCounts.end()); uint64 index = std::distance(binCounts.begin(), maxElementIt); @@ -699,10 +703,12 @@ 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* histBinCountsArrayPtr = dynamic_cast(arrays[8]); + auto* histBinRangesArrayPtr = dynamic_cast*>(arrays[12]); auto* mostPopulatedBinPtr = dynamic_cast(arrays[10]); auto* modalBinsArrayPtr = dynamic_cast*>(arrays[11]); - auto* histBinRangesArrayPtr = dynamic_cast*>(arrays[12]); + auto* featureHasDataPtr = dynamic_cast(arrays[13]); IParallelAlgorithm::AlgorithmArrays indexAlgArrays; @@ -1094,8 +1100,8 @@ Result<> ComputeArrayStatistics::operator()() const auto& featureIds = m_DataStructure.getDataRefAs(m_InputValues->FeatureIdsArrayPath); numFeatures = findNumFeatures(featureIds); - auto* destAttrMatPtr = m_DataStructure.getDataAs(m_InputValues->DestinationAttributeMatrix); - destAttrMatPtr->resizeTuples({numFeatures}); + // auto* destAttrMatPtr = m_DataStructure.getDataAs(m_InputValues->DestinationAttributeMatrix); + // destAttrMatPtr->resizeTuples({numFeatures}); for(const auto& array : arrays) { diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeArrayHistogramFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeArrayHistogramFilter.cpp index fe24bb3043..0c9e2a7934 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeArrayHistogramFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeArrayHistogramFilter.cpp @@ -40,13 +40,13 @@ Uuid ComputeArrayHistogramFilter::uuid() const //------------------------------------------------------------------------------ std::string ComputeArrayHistogramFilter::humanName() const { - return "Calculate Frequency Histogram"; + return "Compute Attribute Array Frequency Histogram"; } //------------------------------------------------------------------------------ std::vector ComputeArrayHistogramFilter::defaultTags() const { - return {className(), "Statistics", "Ensemble"}; + return {className(), "Statistics", "Ensemble", "Histogram"}; } //------------------------------------------------------------------------------ @@ -56,7 +56,7 @@ Parameters ComputeArrayHistogramFilter::parameters() const // Create the parameter descriptors that are needed for this filter params.insertSeparator(Parameters::Separator{"Input Parameter(s)"}); - params.insert(std::make_unique(k_NumberOfBins_Key, "Number of Bins", "Specifies number of histogram bins (greater than zero)", 1)); + params.insert(std::make_unique(k_NumberOfBins_Key, "Number of Bins", "Specifies number of histogram bins (greater than zero)", 10)); params.insertLinkableParameter( std::make_unique(k_UserDefinedRange_Key, "Use Custom Min & Max Range", "Whether the user can set the min and max values to consider for the histogram", false)); params.insert(std::make_unique(k_MinRange_Key, "Min Value", "Specifies the inclusive lower bound of the histogram.", 0.0)); @@ -67,7 +67,7 @@ Parameters ComputeArrayHistogramFilter::parameters() const MultiArraySelectionParameter::ValueType{}, MultiArraySelectionParameter::AllowedTypes{IArray::ArrayType::DataArray}, nx::core::GetAllNumericTypes())); - params.insertSeparator(Parameters::Separator{"Output parameters"}); + params.insertSeparator(Parameters::Separator{"Output Parameters"}); params.insertLinkableParameter( std::make_unique(k_CreateNewDataGroup_Key, "Create New DataGroup for Histograms", "Whether or not to store the calculated histogram(s) in a new DataGroup", true)); params.insert(std::make_unique(k_NewDataGroupPath_Key, "New DataGroup Path", "The path to the new DataGroup in which to store the calculated histogram(s)", DataPath{})); @@ -111,7 +111,6 @@ IFilter::PreflightResult ComputeArrayHistogramFilter::preflightImpl(const DataSt auto pBinRangeSuffix = filterArgs.value(k_HistoBinRangeName_Key); nx::core::Result resultOutputActions; - ; if(pNewDataGroupValue) { @@ -137,7 +136,7 @@ IFilter::PreflightResult ComputeArrayHistogramFilter::preflightImpl(const DataSt } { - auto createArrayAction = std::make_unique(dataArray->getDataType(), std::vector{static_cast(pNumberOfBinsValue + 1)}, std::vector{1}, + auto createArrayAction = std::make_unique(dataArray->getDataType(), std::vector{static_cast(pNumberOfBinsValue)}, std::vector{2}, parentPath.createChildPath((dataArray->getName() + pBinRangeSuffix))); resultOutputActions.value().appendAction(std::move(createArrayAction)); } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeArrayStatisticsFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeArrayStatisticsFilter.cpp index 1dc089c4b3..aaeb1ba60b 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeArrayStatisticsFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ComputeArrayStatisticsFilter.cpp @@ -7,6 +7,7 @@ #include "simplnx/DataStructure/DataPath.hpp" #include "simplnx/Filter/Actions/CreateArrayAction.hpp" #include "simplnx/Filter/Actions/CreateAttributeMatrixAction.hpp" +#include "simplnx/Filter/Actions/CreateDataGroupAction.hpp" #include "simplnx/Filter/Actions/CreateNeighborListAction.hpp" #include "simplnx/Parameters/ArraySelectionParameter.hpp" #include "simplnx/Parameters/AttributeMatrixSelectionParameter.hpp" @@ -57,7 +58,8 @@ OutputActions CreateCompatibleArrays(const DataStructure& dataStructure, const A OutputActions actions; - auto amAction = std::make_unique(destinationAttributeMatrixValue, tupleDims); + auto amAction = std::make_unique(destinationAttributeMatrixValue); + actions.appendAction(std::move(amAction)); if(computeByIndexValue) @@ -115,7 +117,31 @@ OutputActions CreateCompatibleArrays(const DataStructure& dataStructure, const A auto action = std::make_unique(DataType::float32, tupleDims, std::vector{1}, destinationAttributeMatrixValue.createChildPath(arrayPath)); actions.appendAction(std::move(action)); } - if(findHistogramValue) + if(findHistogramValue && !computeByIndexValue) + { + { + auto arrayPath = args.value(ComputeArrayStatisticsFilter::k_HistoBinCountName_Key); + auto action = std::make_unique(DataType::uint64, std::vector{numBins}, std::vector{1ULL}, destinationAttributeMatrixValue.createChildPath(arrayPath)); + actions.appendAction(std::move(action)); + } + { + auto arrayPath = args.value(ComputeArrayStatisticsFilter::k_HistoBinRangeName_Key); + auto action = std::make_unique(dataType, std::vector{numBins}, std::vector{2ULL}, destinationAttributeMatrixValue.createChildPath(arrayPath)); + actions.appendAction(std::move(action)); + } + { + auto arrayPath = args.value(ComputeArrayStatisticsFilter::k_MostPopulatedBinArrayName_Key); + auto action = std::make_unique(DataType::uint64, tupleDims, std::vector{2}, destinationAttributeMatrixValue.createChildPath(arrayPath)); + actions.appendAction(std::move(action)); + } + if(findModalBinRanges) + { + auto arrayPath = args.value(ComputeArrayStatisticsFilter::k_ModalBinArrayName_Key); + auto action = std::make_unique(dataType, tupleSize, destinationAttributeMatrixValue.createChildPath(arrayPath)); + actions.appendAction(std::move(action)); + } + } + if(findHistogramValue && computeByIndexValue) { { auto arrayPath = args.value(ComputeArrayStatisticsFilter::k_HistoBinCountName_Key); @@ -124,7 +150,7 @@ OutputActions CreateCompatibleArrays(const DataStructure& dataStructure, const A } { auto arrayPath = args.value(ComputeArrayStatisticsFilter::k_HistoBinRangeName_Key); - auto action = std::make_unique(dataType, tupleDims, std::vector{numBins + 1}, destinationAttributeMatrixValue.createChildPath(arrayPath)); + auto action = std::make_unique(dataType, tupleDims, std::vector{numBins * 2}, destinationAttributeMatrixValue.createChildPath(arrayPath)); actions.appendAction(std::move(action)); } { @@ -186,7 +212,7 @@ std::string ComputeArrayStatisticsFilter::humanName() const //------------------------------------------------------------------------------ std::vector ComputeArrayStatisticsFilter::defaultTags() const { - return {className(), "SimplnxCore", "Statistics"}; + return {className(), "SimplnxCore", "Statistics", "Histogram", "Mean", "Average", "Min", "Max", "Standard Deviation", "Length"}; } //------------------------------------------------------------------------------ @@ -198,16 +224,19 @@ Parameters ComputeArrayStatisticsFilter::parameters() const params.insertSeparator(Parameters::Separator{"Input Data"}); params.insert(std::make_unique(k_SelectedArrayPath_Key, "Attribute Array to Compute Statistics", "Input Attribute Array for which to compute statistics", DataPath{}, nx::core::GetAllDataTypes(), ArraySelectionParameter::AllowedComponentShapes{{1}})); + params.insertSeparator(Parameters::Separator{"Output Data"}); params.insert( std::make_unique(k_DestinationAttributeMatrixPath_Key, "Destination Attribute Matrix", "Attribute Matrix in which to store the computed statistics", DataPath{})); params.insertSeparator(Parameters::Separator{"Histogram Options"}); params.insertLinkableParameter(std::make_unique(k_FindHistogram_Key, "Find Histogram", "Whether to compute the histogram of the input array", false)); - params.insert(std::make_unique(k_MinRange_Key, "Histogram Min Value", "Min cutoff value for histogram", 0.0)); - params.insert(std::make_unique(k_MaxRange_Key, "Histogram Max Value", "Max cutoff value for histogram", 0.0)); + params.insert(std::make_unique(k_NumBins_Key, "Number of Bins", "Number of bins in histogram", 10)); params.insert( std::make_unique(k_UseFullRange_Key, "Use Full Range for Histogram", "If true, ignore min and max and use min and max from array upon which histogram is computed", false)); - params.insert(std::make_unique(k_NumBins_Key, "Number of Bins", "Number of bins in histogram", 1)); + + params.insert(std::make_unique(k_MinRange_Key, "Custom Histogram Min Value", "Min cutoff value for histogram", 0.0)); + params.insert(std::make_unique(k_MaxRange_Key, "Custom Histogram Max Value", "Max cutoff value for histogram", 1.0)); + params.insert(std::make_unique(k_HistoBinCountName_Key, "Histogram Bin Counts Array Name", "The name of the histogram bin counts array", "Histogram Bin Counts")); params.insert(std::make_unique(k_HistoBinRangeName_Key, "Histogram Bin Ranges Array Name", "The name of the histogram bin ranges array", "Histogram Bin Ranges")); params.insert(std::make_unique(k_MostPopulatedBinArrayName_Key, "Most Populated Bin Array Name", "The name of the Most Populated Bin array", "Most Populated Bin")); diff --git a/src/Plugins/SimplnxCore/test/ComputeArrayHistogramTest.cpp b/src/Plugins/SimplnxCore/test/ComputeArrayHistogramTest.cpp index 7e2f600c66..dc949324f6 100644 --- a/src/Plugins/SimplnxCore/test/ComputeArrayHistogramTest.cpp +++ b/src/Plugins/SimplnxCore/test/ComputeArrayHistogramTest.cpp @@ -25,7 +25,7 @@ void compareHistograms(const AbstractDataStore& calculated, const std::array< { if(calculated.getSize() != actual.size()) { - throw std::runtime_error("Improper sizing of DataStore"); + throw std::runtime_error(fmt::format("Improper sizing of DataStore. {} vs {}", calculated.getSize(), actual.size())); } for(int32 i = 0; i < N; i++) { @@ -81,7 +81,7 @@ TEST_CASE("SimplnxCore::ComputeArrayHistogram: Valid Filter Execution", "[Simpln SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result); { - std::array binRangesSet = {-56.8, 184.475, 425.75, 667.025, 908.3}; + std::array binRangesSet = {-56.8, 184.475, 184.475, 425.75, 425.75, 667.025, 667.025, 908.3}; std::array binCountsSet = {11, 0, 0, 1}; const std::string name = k_Array0Name; @@ -89,7 +89,7 @@ TEST_CASE("SimplnxCore::ComputeArrayHistogram: Valid Filter Execution", "[Simpln compareHistograms(dataStruct.getDataAs(dataGPath.createChildPath((name + std::string{k_BinCountsSuffix})))->getDataStoreRef(), binCountsSet); } { - std::array binRangesSet = {-90, -44, 2, 48, 94}; + std::array binRangesSet = {-90, -44, -44, 2, 2, 48, 48, 94}; std::array binCountsSet = {1, 2, 3, 6}; const std::string name = k_Array1Name; @@ -97,7 +97,7 @@ TEST_CASE("SimplnxCore::ComputeArrayHistogram: Valid Filter Execution", "[Simpln compareHistograms(dataStruct.getDataAs(dataGPath.createChildPath((name + std::string{k_BinCountsSuffix})))->getDataStoreRef(), binCountsSet); } { - std::array binRangesSet = {34, 2270, 4506, 6742, 8978}; + std::array binRangesSet = {34, 2270, 2270, 4506, 4506, 6742, 6742, 8978}; std::array binCountsSet = {11, 0, 0, 1}; const std::string name = k_Array2Name; diff --git a/src/Plugins/SimplnxCore/test/ComputeArrayStatisticsTest.cpp b/src/Plugins/SimplnxCore/test/ComputeArrayStatisticsTest.cpp index 33f7eec76d..7ae42cb4d1 100644 --- a/src/Plugins/SimplnxCore/test/ComputeArrayStatisticsTest.cpp +++ b/src/Plugins/SimplnxCore/test/ComputeArrayStatisticsTest.cpp @@ -110,19 +110,17 @@ TEST_CASE("SimplnxCore::ComputeArrayStatisticsFilter: Test Algorithm", "[Simplnx // Preflight the filter and check result auto preflightResult = filter.preflight(dataStructure, args); - REQUIRE(preflightResult.outputActions.valid()); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions); // Execute the filter and check the result auto executeResult = filter.execute(dataStructure, args); - REQUIRE(executeResult.result.valid()); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result); } // Check resulting values { - auto* attrMatrix = dataStructure.getDataAs(statsDataPath); - REQUIRE(attrMatrix != nullptr); - REQUIRE(attrMatrix->getShape().size() == 1); - REQUIRE(attrMatrix->getShape()[0] == 1); + auto* dataGroup = dataStructure.getDataAs(statsDataPath); + REQUIRE(dataGroup != nullptr); auto* lengthArray = dataStructure.getDataAs(statsDataPath.createChildPath(length)); REQUIRE(lengthArray != nullptr); auto* minArray = dataStructure.getDataAs(statsDataPath.createChildPath(min)); @@ -170,7 +168,7 @@ TEST_CASE("SimplnxCore::ComputeArrayStatisticsFilter: Test Algorithm", "[Simplnx REQUIRE(modeVals[0] == 1); REQUIRE(modalBinRangesVals.size() == 2); REQUIRE(modalBinRangesVals[0] == 1); - REQUIRE(modalBinRangesVals[1] == 10); + REQUIRE(modalBinRangesVals[1] == 6); REQUIRE(std::fabs(meanVal - 14.3333f) < UnitTest::EPSILON); REQUIRE(std::fabs(medianVal - 10.0f) < UnitTest::EPSILON); REQUIRE(std::fabs(stdVal - 13.02f) < UnitTest::EPSILON); @@ -315,19 +313,17 @@ TEST_CASE("SimplnxCore::ComputeArrayStatisticsFilter: Test Algorithm By Index", // Preflight the filter and check result auto preflightResult = filter.preflight(dataStructure, args); - REQUIRE(preflightResult.outputActions.valid()); + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions); // Execute the filter and check the result auto executeResult = filter.execute(dataStructure, args); - REQUIRE(executeResult.result.valid()); + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result); } // Check resulting values { - auto* attrMatrix = dataStructure.getDataAs(statsDataPath); - REQUIRE(attrMatrix != nullptr); - REQUIRE(attrMatrix->getShape().size() == 1); - REQUIRE(attrMatrix->getShape()[0] == 3); + auto* dataGroup = dataStructure.getDataAs(statsDataPath); + REQUIRE(dataGroup != nullptr); auto* lengthArray = dataStructure.getDataAs(statsDataPath.createChildPath(length)); REQUIRE(lengthArray != nullptr); REQUIRE(lengthArray->getNumberOfTuples() == 3); @@ -493,13 +489,15 @@ TEST_CASE("SimplnxCore::ComputeArrayStatisticsFilter: Test Algorithm By Index", REQUIRE((*mostPopulatedBinArray)[5] == 2); REQUIRE(modalBinRange0[0] == 1); REQUIRE(modalBinRange0[1] == 15); - REQUIRE(modalBinRange0[2] == 59); - REQUIRE(modalBinRange0[3] == 74); - REQUIRE(modalBinRange1[0] == 17); - REQUIRE(modalBinRange1[1] == 21); + REQUIRE(modalBinRange0[2] == 30); + REQUIRE(modalBinRange0[3] == 44); + + REQUIRE(modalBinRange1[0] == 11); + REQUIRE(modalBinRange1[1] == 14); + REQUIRE(modalBinRange2[0] == 10); REQUIRE(modalBinRange2[1] == 12); - REQUIRE(modalBinRange2[2] == 20); - REQUIRE(modalBinRange2[3] == 23); + REQUIRE(modalBinRange2[2] == 15); + REQUIRE(modalBinRange2[3] == 17); } } diff --git a/src/simplnx/Utilities/HistogramUtilities.hpp b/src/simplnx/Utilities/HistogramUtilities.hpp index 0316045d8f..9478a27cde 100644 --- a/src/simplnx/Utilities/HistogramUtilities.hpp +++ b/src/simplnx/Utilities/HistogramUtilities.hpp @@ -40,12 +40,13 @@ void FillBinRanges(Container& outputContainer, const std::pair& rang } // iterate through loading the middle values of the sequence considering `lower bound inclusive, upper bound exclusive` + // We are filling a 2 component array. For STL containers this means the size of the container is 2*numbins + // We are going to put all the lower bin values into a component and the upper bin values in another component for(int32 i = 0; i < numBins; i++) { - outputContainer[i] = rangeMinMax.first + static_cast(increment * i); + outputContainer[i * 2 + 0] = rangeMinMax.first + static_cast(increment * i); + outputContainer[i * 2 + 1] = rangeMinMax.first + static_cast(increment * (i + 1.0F)); } - - outputContainer[numBins] = rangeMinMax.second; } /** @@ -108,7 +109,7 @@ Result<> GenerateHistogram(const InputContainer& inputStore, RangesContainer& bi static_assert(std::is_same_v, "HistogramUtilities::GenerateHistogram: inputStore and binRangesStore must be of the same type. HistogramUtilities:99"); - if(binRangesStore.size() < numBins + 1) + if(binRangesStore.size() < numBins * 2) { return MakeErrorResult(-23761, fmt::format("HistogramUtilities::{}: binRangesStore is too small to hold ranges. Needed: {} | Current Size: {}. {}:{}", __func__, numBins + 1, binRangesStore.size(), __FILE__, __LINE__));