From 98f529372e2ff4dbab8feca0e5d9a9a813a50429 Mon Sep 17 00:00:00 2001 From: Luke Pickering Date: Fri, 6 Mar 2026 16:30:54 +0000 Subject: [PATCH 1/8] Adds unit tests for the binning parser - Tests range-based uniform binning specifiers - Tests file-based non-uniform binning specifier --- CIValidations/UnitTests/CMakeLists.txt | 1 + .../UnitTests/binning_parser_tests.cpp | 215 ++++++++++++++++++ 2 files changed, 216 insertions(+) create mode 100644 CIValidations/UnitTests/binning_parser_tests.cpp diff --git a/CIValidations/UnitTests/CMakeLists.txt b/CIValidations/UnitTests/CMakeLists.txt index d75022b..3cc2ecf 100644 --- a/CIValidations/UnitTests/CMakeLists.txt +++ b/CIValidations/UnitTests/CMakeLists.txt @@ -2,6 +2,7 @@ foreach(TEST manager_tests histogram_tests statistical_tests + binning_parser_tests ) add_executable(${TEST} ${TEST}.cpp) diff --git a/CIValidations/UnitTests/binning_parser_tests.cpp b/CIValidations/UnitTests/binning_parser_tests.cpp new file mode 100644 index 0000000..6f7651a --- /dev/null +++ b/CIValidations/UnitTests/binning_parser_tests.cpp @@ -0,0 +1,215 @@ +#include "catch2/catch_test_macros.hpp" +#include "catch2/matchers/catch_matchers_floating_point.hpp" + +#include "Samples/BinningHandler.h" + +TEST_CASE("Parse 1D implicit outerbrace", "[BinningHandler]") { + MACH3LOG_INFO(""); + std::string yamlContent_1DRangeRangeBug = R"( + VarStr : x + BinEdges: [0,1,2,3] + Uniform: true + )"; + + auto Binning = std::make_unique(); + SampleInfo SingleSample; + YAML::Node BinningNode = + STRINGtoYAML(yamlContent_1DRangeRangeBug); + Binning->SetupSampleBinning(BinningNode, SingleSample); + + std::vector ref = {0, 1, 2, 3}; + std::vector parsed_dim0 = Binning->GetBinEdges(0, 0); + REQUIRE(Binning->GetNDim(0) == 1); + REQUIRE(ref.size() == parsed_dim0.size()); + for (size_t i = 0; i < ref.size(); ++i) { + REQUIRE(ref[i] == parsed_dim0[i]); + } +} + +TEST_CASE("Parse 1D explicit outerbrace", "[BinningHandler]") { + MACH3LOG_INFO(""); + std::string yamlContent_1DRangeRangeBug = R"( + VarStr : [ x ] + BinEdges: [ [0,1,2,3] ] + Uniform: true + )"; + + auto Binning = std::make_unique(); + SampleInfo SingleSample; + YAML::Node BinningNode = + STRINGtoYAML(yamlContent_1DRangeRangeBug); + Binning->SetupSampleBinning(BinningNode, SingleSample); + + std::vector ref = {0, 1, 2, 3}; + std::vector parsed_dim0 = Binning->GetBinEdges(0, 0); + REQUIRE(Binning->GetNDim(0) == 1); + REQUIRE(ref.size() == parsed_dim0.size()); + for (size_t i = 0; i < ref.size(); ++i) { + REQUIRE(ref[i] == parsed_dim0[i]); + } +} + +TEST_CASE("Parse 2D scalar binning", "[BinningHandler]") { + MACH3LOG_INFO(""); + std::string yamlContent_1DRangeRangeBug = R"( + VarStr : [ x, y ] + BinEdges: [ [0,1,2,3], [4,5,6,7] ] + Uniform: true + )"; + + auto Binning = std::make_unique(); + SampleInfo SingleSample; + YAML::Node BinningNode = + STRINGtoYAML(yamlContent_1DRangeRangeBug); + Binning->SetupSampleBinning(BinningNode, SingleSample); + + std::vector ref_dim0 = {0, 1, 2, 3}; + std::vector ref_dim1 = {4,5,6,7}; + std::vector parsed_dim0 = Binning->GetBinEdges(0, 0); + std::vector parsed_dim1 = Binning->GetBinEdges(0, 1); + REQUIRE(Binning->GetNDim(0) == 2); + REQUIRE(ref_dim0.size() == parsed_dim0.size()); + REQUIRE(ref_dim1.size() == parsed_dim1.size()); + for (size_t i = 0; i < ref_dim0.size(); ++i) { + REQUIRE(ref_dim0[i] == parsed_dim0[i]); + REQUIRE(ref_dim1[i] == parsed_dim1[i]); + } +} + +TEST_CASE("Parse 1D linspace implicit outerbrace", "[BinningHandler]") { + MACH3LOG_INFO(""); + std::string yamlContent_1DRangeRangeBug = R"( + VarStr : [ x ] + BinEdges: { linspace: {nb: 3, low: 0, up: 3} } + Uniform: true + )"; + + auto Binning = std::make_unique(); + SampleInfo SingleSample; + YAML::Node BinningNode = + STRINGtoYAML(yamlContent_1DRangeRangeBug); + Binning->SetupSampleBinning(BinningNode, SingleSample); + + std::vector ref = {0, 1, 2, 3}; + std::vector parsed_dim0 = Binning->GetBinEdges(0, 0); + REQUIRE(Binning->GetNDim(0) == 1); + REQUIRE(ref.size() == parsed_dim0.size()); + for (size_t i = 0; i < ref.size(); ++i) { + REQUIRE(ref[i] == parsed_dim0[i]); + } +} + +TEST_CASE("Parse 1D linspace explicit outerbrace", "[BinningHandler]") { + MACH3LOG_INFO(""); + std::string yamlContent_1DRangeRangeBug = R"( + VarStr : [ x ] + BinEdges: [ { linspace: {nb: 3, low: 0, up: 3} } ] + Uniform: true + )"; + + auto Binning = std::make_unique(); + SampleInfo SingleSample; + YAML::Node BinningNode = + STRINGtoYAML(yamlContent_1DRangeRangeBug); + Binning->SetupSampleBinning(BinningNode, SingleSample); + + std::vector ref = {0, 1, 2, 3}; + std::vector parsed_dim0 = Binning->GetBinEdges(0, 0); + REQUIRE(Binning->GetNDim(0) == 1); + REQUIRE(ref.size() == parsed_dim0.size()); + for (size_t i = 0; i < ref.size(); ++i) { + REQUIRE(ref[i] == parsed_dim0[i]); + } +} + +TEST_CASE("Parse 1D linspace & scalar", "[BinningHandler]") { + MACH3LOG_INFO(""); + std::string yamlContent_1DRangeRangeBug = R"( + VarStr : [ x ] + BinEdges: [ -1, { linspace: {nb: 3, low: 0, up: 3} }, 4, 5, 6 ] + Uniform: true + )"; + + auto Binning = std::make_unique(); + SampleInfo SingleSample; + YAML::Node BinningNode = + STRINGtoYAML(yamlContent_1DRangeRangeBug); + Binning->SetupSampleBinning(BinningNode, SingleSample); + + std::vector ref = {-1, 0, 1, 2, 3, 4, 5, 6}; + std::vector parsed_dim0 = Binning->GetBinEdges(0, 0); + REQUIRE(Binning->GetNDim(0) == 1); + REQUIRE(ref.size() == parsed_dim0.size()); + for (size_t i = 0; i < ref.size(); ++i) { + REQUIRE(ref[i] == parsed_dim0[i]); + } +} + +TEST_CASE("Parse 1D logspace", "[BinningHandler]") { + MACH3LOG_INFO(""); + std::string yamlContent_1DRangeRangeBug = R"( + VarStr : [ x ] + BinEdges: { logspace: {nb: 2, low: 1, up: 100} } + Uniform: true + )"; + + auto Binning = std::make_unique(); + SampleInfo SingleSample; + YAML::Node BinningNode = + STRINGtoYAML(yamlContent_1DRangeRangeBug); + Binning->SetupSampleBinning(BinningNode, SingleSample); + + std::vector ref = {1, 10, 100}; + std::vector parsed_dim0 = Binning->GetBinEdges(0, 0); + REQUIRE(Binning->GetNDim(0) == 1); + REQUIRE(ref.size() == parsed_dim0.size()); + for (size_t i = 0; i < ref.size(); ++i) { + REQUIRE(ref[i] == parsed_dim0[i]); + } +} + +TEST_CASE("Throw on ambiguous 1D range specifier", "[BinningHandler]") { + MACH3LOG_INFO(""); + std::string yamlContent_1DRangeRangeBug = R"( + VarStr : [ "x", "y" ] + BinEdges: [ { linspace: { nb: 10, low: 0, up: 10 } }, { linspace: { nb: 10, low: 10, up: 100 } } ] + Uniform: true + )"; + + auto Binning = std::make_unique(); + SampleInfo SingleSample; + YAML::Node BinningNode = + STRINGtoYAML(yamlContent_1DRangeRangeBug); + REQUIRE_THROWS( + Binning->SetupSampleBinning(BinningNode, SingleSample)); +} + +TEST_CASE("Non-uniform External Binning File", "[BinningHandler]") { + MACH3LOG_INFO(""); + std::string yamlContent_1DRangeRangeBug = R"( + VarStr : [ x, y ] + Bins: { File: testbinning.yml, Key: mybins } + Uniform: false + )"; + + std::ofstream testbinning("testbinning.yml"); + testbinning << R"(--- +mybins: [ [[0.0, 0.1], [0.0, 0.1]], + [[0.0, 0.1], [0.1, 0.2]], + [[0.0, 0.1], [0.2, 0.3]], + [[0.0, 0.1], [0.3, 0.4]], + [[0.0, 0.1], [0.4, 0.5]], + [[0.1, 0.3], [0.0, 0.5]], + [[0.3, 0.5], [0.0, 0.5]], + [[0.5, 0.7], [0.0, 0.5]] +] +)"; + testbinning.close(); + + auto Binning = std::make_unique(); + SampleInfo SingleSample; + YAML::Node BinningNode = + STRINGtoYAML(yamlContent_1DRangeRangeBug); + Binning->SetupSampleBinning(BinningNode, SingleSample); + REQUIRE(Binning->GetNBins() == 8); +} From 83eef2795abcb8beac6513c31cf853547de35849 Mon Sep 17 00:00:00 2001 From: Luke Pickering Date: Fri, 6 Mar 2026 16:41:24 +0000 Subject: [PATCH 2/8] adds uniform range-based binning output to BinningValidations --- CIValidations/BinningValidations.cpp | 67 ++++++++++++++++++++++++ CIValidations/TestOutputs/BinningOut.txt | 6 +++ 2 files changed, 73 insertions(+) diff --git a/CIValidations/BinningValidations.cpp b/CIValidations/BinningValidations.cpp index d7b2d7d..676a31f 100755 --- a/CIValidations/BinningValidations.cpp +++ b/CIValidations/BinningValidations.cpp @@ -2,6 +2,8 @@ #include "Utils/Comparison.h" #include "Samples/BinningHandler.h" +#include "spdlog/fmt/ranges.h" + void BinningHandlerValidationsNonUniform(std::ostream& outFile) { auto Binning = std::make_unique(); std::string yamlBinning = R"( @@ -158,6 +160,71 @@ Uniform: true << std::endl; } } + + MACH3LOG_INFO(""); + std::string yamlContent_implicit1D = R"( + VarStr : [ "x" ] + BinEdges: [ 0,1,2,3 ] + Uniform: true + )"; + + YAML::Node Binning_implicit1D = STRINGtoYAML(yamlContent_implicit1D); + Binning->SetupSampleBinning(Binning_implicit1D, SingleSample); + + outFile << "[Binning_implicit1D]: BinEdges: " << fmt::format("{::.2}",Binning->GetBinEdges(3,0)) << std::endl; + + MACH3LOG_INFO(""); + std::string yamlContent_implicit1DRange = R"( + VarStr : [ "x" ] + BinEdges: { linspace: { nb: 10, low: 0, up: 10 } } + Uniform: true + )"; + + YAML::Node Binning_implicit1DRange = STRINGtoYAML(yamlContent_implicit1DRange); + Binning->SetupSampleBinning(Binning_implicit1DRange, SingleSample); + + outFile << "[Binning_implicit1DRange]: BinEdges: " << fmt::format("{::.2}",Binning->GetBinEdges(4,0)) << std::endl; + + MACH3LOG_INFO(""); + std::string yamlContent_1DRangeRange = R"( + VarStr : [ "x" ] + BinEdges: [ { linspace: { nb: 10, low: 0, up: 10 } }, + { linspace: { nb: 10, low: 10, up: 11 } } ] + Uniform: true + )"; + + YAML::Node Binning_1DRangeRange = STRINGtoYAML(yamlContent_1DRangeRange); + Binning->SetupSampleBinning(Binning_1DRangeRange, SingleSample); + + outFile << "[Binning_1DRangeRange]: BinEdges: " << fmt::format("{::.2}",Binning->GetBinEdges(5,0)) << std::endl; + + MACH3LOG_INFO(""); + std::string yamlContent_1DRangeRangeScalar = R"( + VarStr : [ "x" ] + BinEdges: [ -1, { linspace: { nb: 10, low: 0, up: 10 } }, + { linspace: { nb: 10, low: 10, up: 11 } }, 100 ] + Uniform: true + )"; + + YAML::Node Binning_1DRangeRangeScalar = STRINGtoYAML(yamlContent_1DRangeRangeScalar); + Binning->SetupSampleBinning(Binning_1DRangeRangeScalar, SingleSample); + + outFile << "[Binning_1DRangeRangeScalar]: BinEdges: " << fmt::format("{::.2}",Binning->GetBinEdges(6,0)) << std::endl; + + MACH3LOG_INFO(""); + std::string yamlContent_2DRangeRange = R"( + VarStr : [ "x", "y" ] + BinEdges: [ [ { linspace: { nb: 10, low: 0, up: 10 } } ], + [ { linspace: { nb: 10, low: 0, up: 100 } } ] ] + Uniform: true + )"; + + YAML::Node Binning_2DRangeRange = STRINGtoYAML(yamlContent_2DRangeRange); + Binning->SetupSampleBinning(Binning_2DRangeRange, SingleSample); + + outFile << "[Binning_2DRangeRange]: BinEdges[0]: " << fmt::format("{::.2}",Binning->GetBinEdges(7,0)) << std::endl; + outFile << "[Binning_2DRangeRange]: BinEdges[1]: " << fmt::format("{::.2}",Binning->GetBinEdges(7,1)) << std::endl; + } diff --git a/CIValidations/TestOutputs/BinningOut.txt b/CIValidations/TestOutputs/BinningOut.txt index 069955e..1ca76c3 100644 --- a/CIValidations/TestOutputs/BinningOut.txt +++ b/CIValidations/TestOutputs/BinningOut.txt @@ -1002,6 +1002,12 @@ Sample 1, bin: 6, name: Dim0 (0.6, 0.7) Sample 1, bin: 7, name: Dim0 (0.7, 0.8) Sample 1, bin: 8, name: Dim0 (0.8, 0.9) Sample 1, bin: 9, name: Dim0 (0.9, 1) +[Binning_implicit1D]: BinEdges: [0, 1, 2, 3] +[Binning_implicit1DRange]: BinEdges: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +[Binning_1DRangeRange]: BinEdges: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11] +[Binning_1DRangeRangeScalar]: BinEdges: [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 1e+02] +[Binning_2DRangeRange]: BinEdges[0]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +[Binning_2DRangeRange]: BinEdges[1]: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 1e+02] Sample 0, XVar: -0.05, YVar: -0.1, NomXBin: -1, NomYBin: -1, GlobalBin: -1 (Under/Overflow) Sample 0, XVar: -0.05, YVar: 0, NomXBin: -1, NomYBin: -1, GlobalBin: -1 (Under/Overflow) Sample 0, XVar: -0.05, YVar: 0.05, NomXBin: -1, NomYBin: -1, GlobalBin: -1 (Under/Overflow) From 92f7b964d29efe47582d256eeded7a02c9c46a8b Mon Sep 17 00:00:00 2001 From: Luke Pickering Date: Fri, 6 Mar 2026 16:41:55 +0000 Subject: [PATCH 3/8] updates README with range-based uniform and file-based non-uniform examples --- README.md | 109 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 96 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index ebcd141..1e04b9a 100644 --- a/README.md +++ b/README.md @@ -359,6 +359,7 @@ Analysis samples are where we compare data and simulation to extract our physics In this section, we will modify an existing analysis sample to explore how the inner workings of MaCh3 operate, and then see how to add a new one. ### Modifying Analysis Samples + To begin, let's take a look at `TutorialConfigs/Samples/SampleHandler_Tutorial.yaml`. Each sample has a set of cuts that select events into the sample and reject others. Right now, let's focus on the cut on `TrueNeutrinoEnergy`: ```yaml SelectionCuts: @@ -377,8 +378,8 @@ SelectionCuts: You can also easily change what variable the sample is binned in to get slightly different fit results. For example, we could change `RecoNeutrinoEnergy` to `TrueNeutrinoEnergy` in `TutorialConfigs/Samples/SampleHandler_Tutorial.yaml`: ```yaml Binning: - VarStr : [ "RecoNeutrinoEnergy" ] - VarBins: [[0., 0.5, 1., 1.25, 1.5, 1.75, 2., 2.25, 2.5, 2.75, 3., 3.25, 3.5, 3.75, 4., 5., 6., 10.]] + VarStr : RecoNeutrinoEnergy + BinEdges: [0., 0.5, 1., 1.25, 1.5, 1.75, 2., 2.25, 2.5, 2.75, 3., 3.25, 3.5, 3.75, 4., 5., 6., 10.] Uniform: true ``` You can run the MCMC again using this new configuration (after changing the output file name again!), and then compare all 3 chains using: @@ -388,29 +389,111 @@ You can run the MCMC again using this new configuration (after changing the outp
(Detailed) Uniform vs NonUniform binning -Uniform binning, discussed above creating kind of uniform grid, can be easily scaled like this + +Uniform binning is created from the product of N independent one-dimensional binnings: ```yaml Binning: - VarStr : ["RecoNeutrinoEnergy", "TrueQ2"] - VarBins: [ [0., 0.5, 1., 1.25, 1.5, 1.75, 2., 2.25, 2.5, 2.75, 3., 3.25, 3.5, 3.75, 4., 5., 6., 10.], - [0., 0.5, 1., 1.25, 1.5, 1.75, 2., 5] ] + VarStr : [ "RecoNeutrinoEnergy", "TrueQ2" ] + BinEdges: [ [0., 0.5, 1., 1.25, 1.5, 1.75, 2., 2.25, 2.5, 2.75, 3., 3.25, 3.5, 3.75, 4., 5., 6., 10.], + [0., 0.5, 1., 1.25, 1.5, 1.75, 2., 5] ] Uniform: true ``` -However there is option to use non-unform binning which characterises by having bin sizes vary, -but all bins are axis-aligned hyper-rectangles. +MaCh3 also supports arbitrary hyperrectangular binning in N-dimensional space. +To specify such a binning is more verbose, as the bin extent in each dimension +must be specified for each bin. We recommend to read more [here](https://mach3-software.github.io/MaCh3/classBinningHandler.html). -Example of such binning is given below: +Example of a 2D binning is given below: +```yaml + Binning: + VarStr : ["RecoNeutrinoEnergy", "TrueQ2"] + Bins: [ [[0.0, 0.1], [0.0, 0.1]], + [[0.0, 0.1], [0.1, 0.2]], + [[0.0, 0.1], [0.2, 0.3]], + [[0.0, 0.1], [0.3, 0.4]], #bin 3 + [[0.0, 0.1], [0.4, 0.5]], + [[0.1, 0.3], [0.0, 0.5]], + [[0.3, 0.5], [0.0, 0.5]], + [[0.5, 0.7], [0.0, 0.5]] ] + Uniform: false +``` + +Here, each row corresponds to a bin, the first list element gives low and up edges +of the bin extent in the first dimension, `RecoNeutrinoEnergy` in the example. The +second element gives the extent in the second dimension. So bin 3 from the above +specification, defined by: `[[0.0, 0.1], [0.3, 0.4]]`, corresponds to the intervals +`[0, 0.1)` in `RecoNeutrinoEnergy` and `[0.3, 0.4)` in `TrueQ2`. + +For realistic binnings, the number of bins can grow very large and make modifying +a configuration file unwieldy. You can specify the binning list in another file +and reference it like below: ```yaml +# mybins.yml +erecq2bins: [ [[0.0, 0.1], [0.0, 0.1]], + [[0.0, 0.1], [0.1, 0.2]], + [[0.0, 0.1], [0.2, 0.3]], + [[0.0, 0.1], [0.3, 0.4]], + [[0.0, 0.1], [0.4, 0.5]], + [[0.1, 0.3], [0.0, 0.5]], + [[0.3, 0.5], [0.0, 0.5]], + [[0.5, 0.7], [0.0, 0.5]] ] + +--- +# mysample.yml +# ... Binning: VarStr : ["RecoNeutrinoEnergy", "TrueQ2"] - Bins: [[[0.0, 0.1], [0.0, 0.1]], [[0.0, 0.1], [0.1, 0.2]], [[0.0, 0.1], [0.2, 0.3]], - [[0.0, 0.1], [0.3, 0.4]], [[0.0, 0.1], [0.4, 0.5]], [[0.0, 0.1], [0.5, 0.6]], - [[0.0, 0.1], [0.6, 0.7]], [[0.0, 0.1], [0.7, 0.8]], [[0.0, 0.1], [0.8, 0.9]], - [[0.0, 0.1], [0.9, 1.0]] ] + Bins: { BinFile: mybins.yml, Key: erecq2bins } Uniform: false ``` + +
+ +
+(Detailed) Range-based Binning + +For binnings with many edges, there is an alternate syntax for specifying and concatenating +ranges of binnings. For example, to specify a binning with 10 bins of equal width between +the limits of 0 and 100, you might use the configuration: +```yaml + Binning: + VarStr : RecoNeutrinoEnergy + BinEdges: { linspace: { nb: 10, low: 0, up: 100 } } + Uniform: true +``` + +For 5 logarithmically-spaced bins between 100 and 10000, you might use the configuration: +```yaml + Binning: + VarStr : RecoNeutrinoEnergy + BinEdges: { logspace: { nb: 5, low: 100, up: 10000 } } + Uniform: true +``` + +This syntax can also be mixed with scalar bin edges to define a binnings with +multiple regions of linearly or logarithmically spaced bins in a succinct way: +```yaml + Binning: + VarStr : RecoNeutrinoEnergy + BinEdges: [ -1, + { linspace: { nb: 10, low: 0, up: 100 } }, + { logspace: { nb: 5, low: 100, up: 10000 } } + ] + Uniform: true +``` + +Which will create a binning with 16 bins between -1 and 10000. + +This syntax can also be used when making multi-dimensional binnings: +```yaml + Binning: + VarStr : [ RecoNeutrinoEnergy, TrueQ2 ] + BinEdges: [ [ { linspace: { nb: 10, low: 0, up: 10 } } ], + [ { logspace: { nb: 10, low: 0.001, up: 10 } } ] + ] + Uniform: true +```
### Adding a New Sample From 6031131aa4bbbfed9f277ae9a4422b72c741ef5f Mon Sep 17 00:00:00 2001 From: Luke Pickering Date: Fri, 6 Mar 2026 16:51:59 +0000 Subject: [PATCH 4/8] safe include fmt ranges --- CIValidations/BinningValidations.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CIValidations/BinningValidations.cpp b/CIValidations/BinningValidations.cpp index 676a31f..f18f4bd 100755 --- a/CIValidations/BinningValidations.cpp +++ b/CIValidations/BinningValidations.cpp @@ -2,7 +2,9 @@ #include "Utils/Comparison.h" #include "Samples/BinningHandler.h" +_MaCh3_Safe_Include_Start_ //{ #include "spdlog/fmt/ranges.h" +_MaCh3_Safe_Include_End_ //} void BinningHandlerValidationsNonUniform(std::ostream& outFile) { auto Binning = std::make_unique(); From bc9522eafaf72e000ed9b4bcbbdd38078b87ed3f Mon Sep 17 00:00:00 2001 From: Luke Pickering Date: Fri, 6 Mar 2026 16:55:09 +0000 Subject: [PATCH 5/8] fix key typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e04b9a..1d35fc1 100644 --- a/README.md +++ b/README.md @@ -444,7 +444,7 @@ erecq2bins: [ [[0.0, 0.1], [0.0, 0.1]], # ... Binning: VarStr : ["RecoNeutrinoEnergy", "TrueQ2"] - Bins: { BinFile: mybins.yml, Key: erecq2bins } + Bins: { File: mybins.yml, Key: erecq2bins } Uniform: false ``` From 3a8c4b964ea94724589291564090c522cf9c2874 Mon Sep 17 00:00:00 2001 From: Luke Pickering Date: Mon, 9 Mar 2026 10:05:48 +0000 Subject: [PATCH 6/8] remove fmt ranges. adds binning_parser_tests to CI --- CIValidations/BinningValidations.cpp | 26 ++++++++++++++++---------- CIValidations/MaCh3CLI | 1 + 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/CIValidations/BinningValidations.cpp b/CIValidations/BinningValidations.cpp index f18f4bd..280fe1e 100755 --- a/CIValidations/BinningValidations.cpp +++ b/CIValidations/BinningValidations.cpp @@ -2,10 +2,6 @@ #include "Utils/Comparison.h" #include "Samples/BinningHandler.h" -_MaCh3_Safe_Include_Start_ //{ -#include "spdlog/fmt/ranges.h" -_MaCh3_Safe_Include_End_ //} - void BinningHandlerValidationsNonUniform(std::ostream& outFile) { auto Binning = std::make_unique(); std::string yamlBinning = R"( @@ -173,7 +169,17 @@ Uniform: true YAML::Node Binning_implicit1D = STRINGtoYAML(yamlContent_implicit1D); Binning->SetupSampleBinning(Binning_implicit1D, SingleSample); - outFile << "[Binning_implicit1D]: BinEdges: " << fmt::format("{::.2}",Binning->GetBinEdges(3,0)) << std::endl; + auto fmtvector = [](std::vector const &v) { + std::stringstream ss; + ss << "[ "; + for (auto const &e : v) { + ss << fmt::format("{:g.3} ", e); + } + ss << "]"; + return ss.str(); + }; + + outFile << "[Binning_implicit1D]: BinEdges: " << fmtvector(Binning->GetBinEdges(3,0)) << std::endl; MACH3LOG_INFO(""); std::string yamlContent_implicit1DRange = R"( @@ -185,7 +191,7 @@ Uniform: true YAML::Node Binning_implicit1DRange = STRINGtoYAML(yamlContent_implicit1DRange); Binning->SetupSampleBinning(Binning_implicit1DRange, SingleSample); - outFile << "[Binning_implicit1DRange]: BinEdges: " << fmt::format("{::.2}",Binning->GetBinEdges(4,0)) << std::endl; + outFile << "[Binning_implicit1DRange]: BinEdges: " << fmtvector(Binning->GetBinEdges(4,0)) << std::endl; MACH3LOG_INFO(""); std::string yamlContent_1DRangeRange = R"( @@ -198,7 +204,7 @@ Uniform: true YAML::Node Binning_1DRangeRange = STRINGtoYAML(yamlContent_1DRangeRange); Binning->SetupSampleBinning(Binning_1DRangeRange, SingleSample); - outFile << "[Binning_1DRangeRange]: BinEdges: " << fmt::format("{::.2}",Binning->GetBinEdges(5,0)) << std::endl; + outFile << "[Binning_1DRangeRange]: BinEdges: " << fmtvector(Binning->GetBinEdges(5,0)) << std::endl; MACH3LOG_INFO(""); std::string yamlContent_1DRangeRangeScalar = R"( @@ -211,7 +217,7 @@ Uniform: true YAML::Node Binning_1DRangeRangeScalar = STRINGtoYAML(yamlContent_1DRangeRangeScalar); Binning->SetupSampleBinning(Binning_1DRangeRangeScalar, SingleSample); - outFile << "[Binning_1DRangeRangeScalar]: BinEdges: " << fmt::format("{::.2}",Binning->GetBinEdges(6,0)) << std::endl; + outFile << "[Binning_1DRangeRangeScalar]: BinEdges: " << fmtvector(Binning->GetBinEdges(6,0)) << std::endl; MACH3LOG_INFO(""); std::string yamlContent_2DRangeRange = R"( @@ -224,8 +230,8 @@ Uniform: true YAML::Node Binning_2DRangeRange = STRINGtoYAML(yamlContent_2DRangeRange); Binning->SetupSampleBinning(Binning_2DRangeRange, SingleSample); - outFile << "[Binning_2DRangeRange]: BinEdges[0]: " << fmt::format("{::.2}",Binning->GetBinEdges(7,0)) << std::endl; - outFile << "[Binning_2DRangeRange]: BinEdges[1]: " << fmt::format("{::.2}",Binning->GetBinEdges(7,1)) << std::endl; + outFile << "[Binning_2DRangeRange]: BinEdges[0]: " << fmtvector(Binning->GetBinEdges(7,0)) << std::endl; + outFile << "[Binning_2DRangeRange]: BinEdges[1]: " << fmtvector(Binning->GetBinEdges(7,1)) << std::endl; } diff --git a/CIValidations/MaCh3CLI b/CIValidations/MaCh3CLI index 4483d30..acc2025 100755 --- a/CIValidations/MaCh3CLI +++ b/CIValidations/MaCh3CLI @@ -71,6 +71,7 @@ run_covariance_validations() { ./CIValidations/UnitTests/manager_tests ./CIValidations/UnitTests/histogram_tests ./CIValidations/UnitTests/statistical_tests + ./CIValidations/UnitTests/binning_parser_tests fi ${MaCh3Tutorial_ROOT}/bin/LLHScanTutorial TutorialConfigs/FitterConfig.yaml ${MaCh3_ROOT}/bin/PlotLLH LLH_Test.root -s -g -l "blarb.root" From da82c9f6d4a045b1a8e3b19e1f571f9dd75e7ff7 Mon Sep 17 00:00:00 2001 From: Kamil <45295406+KSkwarczynski@users.noreply.github.com> Date: Mon, 9 Mar 2026 11:36:55 +0000 Subject: [PATCH 7/8] Fix formatting precision in fmtvector lambda --- CIValidations/BinningValidations.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIValidations/BinningValidations.cpp b/CIValidations/BinningValidations.cpp index 280fe1e..5706350 100755 --- a/CIValidations/BinningValidations.cpp +++ b/CIValidations/BinningValidations.cpp @@ -173,7 +173,7 @@ Uniform: true std::stringstream ss; ss << "[ "; for (auto const &e : v) { - ss << fmt::format("{:g.3} ", e); + ss << fmt::format("{:.3g} ", e); } ss << "]"; return ss.str(); From 6212b59a857117454f06117418e6156335afceb1 Mon Sep 17 00:00:00 2001 From: Kamil Skwarczynski Date: Mon, 9 Mar 2026 12:20:28 +0000 Subject: [PATCH 8/8] update Binning CI --- CIValidations/BinningValidations.cpp | 17 ++++++++++------- CIValidations/TestOutputs/BinningOut.txt | 6 +++--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/CIValidations/BinningValidations.cpp b/CIValidations/BinningValidations.cpp index 5706350..21fc4b9 100755 --- a/CIValidations/BinningValidations.cpp +++ b/CIValidations/BinningValidations.cpp @@ -170,13 +170,16 @@ Uniform: true Binning->SetupSampleBinning(Binning_implicit1D, SingleSample); auto fmtvector = [](std::vector const &v) { - std::stringstream ss; - ss << "[ "; - for (auto const &e : v) { - ss << fmt::format("{:.3g} ", e); - } - ss << "]"; - return ss.str(); + std::stringstream ss; + ss << "["; + for (size_t i = 0; i < v.size(); ++i) { + ss << fmt::format("{:.3g}", v[i]); + if (i != v.size() - 1) { + ss << ", "; + } + } + ss << "]"; + return ss.str(); }; outFile << "[Binning_implicit1D]: BinEdges: " << fmtvector(Binning->GetBinEdges(3,0)) << std::endl; diff --git a/CIValidations/TestOutputs/BinningOut.txt b/CIValidations/TestOutputs/BinningOut.txt index 1ca76c3..80082b9 100644 --- a/CIValidations/TestOutputs/BinningOut.txt +++ b/CIValidations/TestOutputs/BinningOut.txt @@ -1004,10 +1004,10 @@ Sample 1, bin: 8, name: Dim0 (0.8, 0.9) Sample 1, bin: 9, name: Dim0 (0.9, 1) [Binning_implicit1D]: BinEdges: [0, 1, 2, 3] [Binning_implicit1DRange]: BinEdges: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] -[Binning_1DRangeRange]: BinEdges: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11] -[Binning_1DRangeRangeScalar]: BinEdges: [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 1e+02] +[Binning_1DRangeRange]: BinEdges: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11] +[Binning_1DRangeRangeScalar]: BinEdges: [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11, 100] [Binning_2DRangeRange]: BinEdges[0]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] -[Binning_2DRangeRange]: BinEdges[1]: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 1e+02] +[Binning_2DRangeRange]: BinEdges[1]: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100] Sample 0, XVar: -0.05, YVar: -0.1, NomXBin: -1, NomYBin: -1, GlobalBin: -1 (Under/Overflow) Sample 0, XVar: -0.05, YVar: 0, NomXBin: -1, NomYBin: -1, GlobalBin: -1 (Under/Overflow) Sample 0, XVar: -0.05, YVar: 0.05, NomXBin: -1, NomYBin: -1, GlobalBin: -1 (Under/Overflow)