12 YAML::Node bin_range_specifier;
13 if (bin_range[
"linspace"]) {
14 bin_range_specifier = bin_range[
"linspace"];
15 }
else if (bin_range[
"logspace"]) {
17 bin_range_specifier = bin_range[
"logspace"];
21 MACH3LOG_ERROR(
"When parsing binning, expected bin range specifier with "
22 "key linspace or logspace, but found,\n{}",
27 auto nb = Get<int>(bin_range_specifier[
"nb"], __FILE__, __LINE__);
28 auto low = Get<double>(bin_range_specifier[
"low"], __FILE__, __LINE__);
29 auto up = Get<double>(bin_range_specifier[
"up"], __FILE__, __LINE__);
31 std::vector<double> edges(nb + 1, low);
39 double bw = (up - low) / nb;
40 for (
int i = 0; i < (nb - 1); ++i) {
41 edges[i + 1] = edges[i] + bw;
44 double llow = std::log10(low);
45 double lup = std::log10(up);
46 double lbw = (lup - llow) / nb;
47 for (
int i = 0; i < (nb - 1); ++i) {
48 edges[i + 1] = std::pow(10, llow + (i + 1) * lbw);
64 bool &found_range_specifier) {
66 if (bin_edges_node.IsMap()) {
67 found_range_specifier =
true;
70 std::vector<double> edges_builder;
71 if (!bin_edges_node.IsSequence()) {
75 "When parsing binning, expected to find a YAML map or sequence, "
80 for (
auto const &it : bin_edges_node) {
82 edges_builder.push_back(it.as<
double>());
83 }
else if (it.IsMap()) {
84 found_range_specifier =
true;
86 std::copy(range_edges.begin(), range_edges.end(),
87 std::back_inserter(edges_builder));
92 "When parsing binning, expected elements in outer sequence to all be "
93 "either scalars or maps, but found:\n{}",
100 std::vector<double> edges;
101 for (
size_t eb_it = 0; eb_it < edges_builder.size(); ++eb_it) {
103 if (edges_builder[eb_it] == edges.back()) {
105 }
else if (edges_builder[eb_it] < edges.back()) {
106 std::stringstream ss;
108 for(
auto const & e : edges_builder){
109 ss << fmt::format(
"{:.3g} ", e);
113 "When parsing binning, found edges that were not monotonically "
114 "increasing, problem bin at index: {}:\n{}",
119 edges.push_back(edges_builder[eb_it]);
154 bool &found_range_specifier) {
156 if (bin_edges_node.IsMap()) {
157 found_range_specifier =
true;
158 return std::vector<std::vector<double>>{
161 }
else if (bin_edges_node.IsSequence()) {
162 if (!bin_edges_node.size()) {
163 std::stringstream ss;
164 ss << bin_edges_node;
165 MACH3LOG_ERROR(
"When parsing binning, found an empty sequence:\n{}",
169 auto const &first_el = bin_edges_node[0];
170 if (first_el.IsScalar() || first_el.IsMap()) {
171 return std::vector<std::vector<double>>{
176 std::vector<std::vector<double>> dims;
177 for (
auto const &dim_node : bin_edges_node) {
182 std::stringstream ss;
183 ss << bin_edges_node;
185 "When parsing binning, expected to find a YAML map or sequence, "
201 SingleSample.
VarStr = (Settings[
"VarStr"] && Settings[
"VarStr"].IsScalar())
202 ? std::vector<std::string>{Get<std::string>(
203 Settings[
"VarStr"], __FILE__, __LINE__)}
204 : Get<std::vector<std::string>>(Settings[
"VarStr"],
209 bool Uniform = Get<bool>(Settings[
"Uniform"], __FILE__ , __LINE__);
210 bool found_range_specifier =
false;
211 if(Uniform ==
false) {
212 if(Settings[
"Bins"].IsSequence()) {
213 SingleBinning.
InitNonUniform(
Get<std::vector<std::vector<std::vector<double>>>>(Settings[
"Bins"], __FILE__, __LINE__));
214 }
else if(Settings[
"Bins"].IsMap()){
216 auto file = Get<std::string>(Settings[
"Bins"][
"File"], __FILE__, __LINE__);
218 auto key = Get<std::string>(Settings[
"Bins"][
"Key"], __FILE__, __LINE__);
220 SingleBinning.
InitNonUniform(
Get<std::vector<std::vector<std::vector<double>>>>(binfile[key], __FILE__, __LINE__));
222 std::stringstream ss;
223 ss << Settings[
"Bins"];
225 "When parsing binning, expected to find a YAML map or sequence, "
231 YAML::Node
const & bin_edges_node = Settings[
"BinEdges"] ? Settings[
"BinEdges"] : Settings[
"VarBins"];
233 MACH3LOG_ERROR(
"When setting up Uniform sample binning, didn't find expected key: BinEdges (or VarBins for backward compatibility).");
239 MACH3LOG_ERROR(
"Number of variables ({}) does not match number of bin edge sets ({}) in sample config '{}'",
241 if(found_range_specifier){
242 std::stringstream ss;
243 ss << (Settings[
"BinEdges"] ? Settings[
"BinEdges"] : Settings[
"VarBins"]);
248 Please carefully check the number of square brackets used, a 2D binning
249 comprised of just 2 range specifiers must explicitly include the axis
252 BinEdges: [ [ {{linspace: {{nb:10, low:0, up: 10}}}} ], [ {{linspace: {{nb:5, low:10, up: 100}}}} ] ]
266 const std::vector<const double*>& KinVar,
267 const std::vector<int>& NomBin)
const {
270 const int Dim =
static_cast<int>(KinVar.size());
274 for(
int i = 0; i < Dim; ++i) {
275 const double Var = *KinVar[i];
276 const int Bin = Binning.FindBin(i, Var, NomBin[i]);
280 GlobalBin += Bin * Binning.Strides[i];
283 if(Binning.Uniform) {
284 GlobalBin +=
static_cast<int>(Binning.GlobalOffset);
287 const auto&
_restrict_ BinMapping = Binning.BinGridMapping[GlobalBin];
288 const size_t nNonUniBins = BinMapping.size();
289 for(
size_t iBin = 0; iBin < nNonUniBins; iBin++) {
290 const int BinNumber = BinMapping[iBin];
291 const auto&
_restrict_ NonUniBin = Binning.Bins[BinNumber];
292 if(NonUniBin.IsEventInside(KinVar)){
293 return BinNumber + Binning.GlobalOffset;
296 MACH3LOG_DEBUG(
"Didn't find any bin so returning UnderOverFlowBin");
304 const double Var)
const {
308 const auto& edges = info.
BinEdges[iDim];
311 if (Var < edges.front() || Var >= edges.back()) {
314 return static_cast<int>(std::distance(edges.begin(), std::upper_bound(edges.begin(), edges.end(), Var)) - 1);
320 const int GlobalBin =
SampleBinning[Sample].GetBinSafe(Bins);
343 return static_cast<int>(
SampleBinning[Sample+1].GlobalOffset);
356 int GlobalOffsetCounter = 0;
357 for(
size_t iSample = 0; iSample <
SampleBinning.size(); iSample++){
370 if(!Binning.Uniform) {
371 MACH3LOG_ERROR(
"When using Non-Uniform binning for sample {} please use One bin instead of Axis bins", iSample);
384 if (SampleBin < 0 || SampleBin >=
static_cast<int>(Binning.nBins)) {
385 MACH3LOG_ERROR(
"Requested bin {} is out of range for sample {}", SampleBin, iSample);
390 if(Binning.Uniform) {
391 int Dim =
static_cast<int>(Binning.Strides.size());
392 std::vector<int> Bins(Dim, 0);
393 int Remaining = SampleBin;
406 for (
int i = 0; i < Dim; ++i) {
407 const int nBinsDim =
static_cast<int>(Binning.BinEdges[i].size()) - 1;
408 Bins[i] = Remaining % nBinsDim;
409 Remaining /= nBinsDim;
412 for (
int i = 0; i < Dim; ++i) {
413 if (i > 0) BinName +=
", ";
414 const double min = Binning.BinEdges[i].at(Bins[i]);
415 const double max = Binning.BinEdges[i].at(Bins[i] + 1);
416 BinName += fmt::format(
"Dim{} ({:g}, {:g})", i, min, max);
419 const BinInfo& bin = Binning.Bins[SampleBin];
420 const int Dim =
static_cast<int>(bin.
Extent.size());
422 for (
int i = 0; i < Dim; ++i) {
423 if (i > 0) BinName +=
", ";
424 const double min = bin.
Extent[i][0];
425 const double max = bin.
Extent[i][1];
426 BinName += fmt::format(
"Dim{} ({:g}, {:g})", i, min, max);
444 if(!Binning.Uniform) {
445 MACH3LOG_ERROR(
"When using Non-Uniform binning for sample {} please use global bin instead of {}", iSample, __func__);
448 return static_cast<int>(Binning.AxisNBins.at(iDim));
456 return Binning.Uniform;
463 if(!Binning.Uniform) {
466 MACH3LOG_ERROR(
"{} for sample {} will not work becasue binnin is unfiorm", __func__, iSample);
auto BinRangeToBinEdges(YAML::Node const &bin_range)
auto BuildBinEdgesFromNode(YAML::Node const &bin_edges_node, bool &found_range_specifier)
Builds a single dimension's bin edges from YAML::Node.
auto UniformBinEdgeConfigParser(YAML::Node const &bin_edges_node, bool &found_range_specifier)
Parses YAML node describing multidim uniform binning.
#define _restrict_
KS: Using restrict limits the effects of pointer aliasing, aiding optimizations. While reading I foun...
int GetSampleFromGlobalBin(const std::vector< SampleBinningInfo > &BinningInfo, const int GlobalBin)
Get the sample index corresponding to a global bin number.
int GetLocalBinFromGlobalBin(const std::vector< SampleBinningInfo > &BinningInfo, const int GlobalBin)
Get the local (sample) bin index from a global bin number.
YAML::Node LoadYamlConfig(const std::string &filename, const std::string &File, const int Line)
Open YAML file.
Type Get(const YAML::Node &node, const std::string File, const int Line)
Get content of config file.
const std::vector< BinInfo > GetNonUniformBins(const int iSample) const
Return NonUnifomr bins to for example check extent etc.
void SetGlobalBinNumbers()
Sets the GlobalOffset for each SampleBinningInfo to enable linearization of multiple 2D binning sampl...
int GetSampleStartBin(const int iSample) const
Get bin number corresponding to where given sample starts.
BinningHandler()
Constructor.
std::vector< SampleBinningInfo > SampleBinning
Binning info for individual sample.
int FindGlobalBin(const int iSample, const std::vector< const double * > &KinVar, const std::vector< int > &NomBin) const
Find Global bin including.
void SetupSampleBinning(const YAML::Node &Settings, SampleInfo &SingleSample)
Function to setup the binning of your sample histograms and the underlying arrays that get handled in...
int GetBinSafe(const int iSample, const std::vector< int > &Bins) const
Get gloabl bin based on sample, and dimension of each sample without any safety checks.
int GetNBins() const
Get total number of bins over all samples/kinematic bins etc.
std::string GetBinName(const int GlobalBin) const
Get fancy name for a given bin, to help match it with global properties.
int FindNominalBin(const int iSample, const int iDim, const double Var) const
Find the nominal bin for a given variable in a given sample and dimension.
int GetGlobalBinSafe(const int iSample, const std::vector< int > &Bins) const
Get gloabl bin based on sample, and dimension of each sample with additional checks.
bool IsUniform(const int iSample) const
Tells whether given sample is using unform binning.
int GetSampleEndBin(const int iSample) const
Get bin number corresponding to where given sample ends.
int TotalNumberOfBins
Total number of bins.
int GetNAxisBins(const int iSample, const int iDim) const
Get Number of N-axis bins for a given sample.
Custom exception class used throughout MaCh3.
constexpr static const int UnderOverFlowBin
Mark bin which is overflow or underflow in MaCh3 binning.
void AddPath(std::string &FilePath)
Prepends the MACH3 environment path to FilePath if it is not already present.
KS: This hold bin extents in N-Dimensions allowing to check if Bin falls into.
std::vector< std::array< double, 2 > > Extent
KS: Struct storing all information required for sample binning.
void InitUniform(const std::vector< std::vector< double >> &InputEdges)
Initialise Uniform Binning.
void InitNonUniform(const std::vector< std::vector< std::vector< double >>> &InputBins)
Initialise Non-Uniform Binning.
std::vector< std::vector< double > > BinEdges
Vector to hold N-axis bin-edges.
KS: Store info about MC sample.
int nDimensions
Keep track of the dimensions of the sample binning.
std::vector< std::string > VarStr
the strings associated with the variables used for the binning e.g. "RecoNeutrinoEnergy"
std::string SampleTitle
the name of this sample e.g."muon-like"