37 bool &found_range_specifier) {
39 if (bin_edges_node.IsMap()) {
40 found_range_specifier =
true;
41 return std::vector<std::vector<double>>{
44 }
else if (bin_edges_node.IsSequence()) {
45 if (!bin_edges_node.size()) {
48 MACH3LOG_ERROR(
"When parsing binning, found an empty sequence:\n{}",
52 auto const &first_el = bin_edges_node[0];
53 if (first_el.IsScalar() || first_el.IsMap()) {
54 return std::vector<std::vector<double>>{
59 std::vector<std::vector<double>> dims;
60 for (
auto const &dim_node : bin_edges_node) {
68 "When parsing binning, expected to find a YAML map or sequence, "
84 SingleSample.
VarStr = (Settings[
"VarStr"] && Settings[
"VarStr"].IsScalar())
85 ? std::vector<std::string>{Get<std::string>(
86 Settings[
"VarStr"], __FILE__, __LINE__)}
87 : Get<std::vector<std::string>>(Settings[
"VarStr"],
92 bool Uniform = Get<bool>(Settings[
"Uniform"], __FILE__ , __LINE__);
93 bool found_range_specifier =
false;
94 if(Uniform ==
false) {
95 if(Settings[
"Bins"].IsSequence()) {
96 SingleBinning.
InitNonUniform(
Get<std::vector<std::vector<std::vector<double>>>>(Settings[
"Bins"], __FILE__, __LINE__));
97 }
else if(Settings[
"Bins"].IsMap()){
99 auto file = Get<std::string>(Settings[
"Bins"][
"File"], __FILE__, __LINE__);
101 auto key = Get<std::string>(Settings[
"Bins"][
"Key"], __FILE__, __LINE__);
103 SingleBinning.
InitNonUniform(
Get<std::vector<std::vector<std::vector<double>>>>(binfile[key], __FILE__, __LINE__));
105 std::stringstream ss;
106 ss << Settings[
"Bins"];
108 "When parsing binning, expected to find a YAML map or sequence, "
114 YAML::Node
const & bin_edges_node = Settings[
"BinEdges"] ? Settings[
"BinEdges"] : Settings[
"VarBins"];
116 MACH3LOG_ERROR(
"When setting up Uniform sample binning, didn't find expected key: BinEdges (or VarBins for backward compatibility).");
122 MACH3LOG_ERROR(
"Number of variables ({}) does not match number of bin edge sets ({}) in sample config '{}'",
124 if(found_range_specifier){
125 std::stringstream ss;
126 ss << (Settings[
"BinEdges"] ? Settings[
"BinEdges"] : Settings[
"VarBins"]);
131 Please carefully check the number of square brackets used, a 2D binning
132 comprised of just 2 range specifiers must explicitly include the axis
135 BinEdges: [ [ {{linspace: {{nb:10, low:0, up: 10}}}} ], [ {{linspace: {{nb:5, low:10, up: 100}}}} ] ]
149 const std::vector<const double*>& KinVar,
150 const std::vector<int>& NomBin)
const {
153 const int Dim =
static_cast<int>(KinVar.size());
157 for(
int i = 0; i < Dim; ++i) {
158 const double Var = *KinVar[i];
159 const int Bin = Binning.FindBin(i, Var, NomBin[i]);
163 GlobalBin += Bin * Binning.Strides[i];
166 if(Binning.Uniform) {
167 GlobalBin +=
static_cast<int>(Binning.GlobalOffset);
170 const auto&
_restrict_ BinMapping = Binning.BinGridMapping[GlobalBin];
171 const size_t nNonUniBins = BinMapping.size();
172 for(
size_t iBin = 0; iBin < nNonUniBins; iBin++) {
173 const int BinNumber = BinMapping[iBin];
174 const auto&
_restrict_ NonUniBin = Binning.Bins[BinNumber];
175 if(NonUniBin.IsEventInside(KinVar)){
176 return BinNumber + Binning.GlobalOffset;
179 MACH3LOG_DEBUG(
"Didn't find any bin so returning UnderOverFlowBin");
187 const double Var)
const {
191 const auto& edges = info.
BinEdges[iDim];
194 if (Var < edges.front() || Var >= edges.back()) {
197 return static_cast<int>(std::distance(edges.begin(), std::upper_bound(edges.begin(), edges.end(), Var)) - 1);
203 const int GlobalBin =
SampleBinning[Sample].GetBinSafe(Bins);
226 return static_cast<int>(
SampleBinning[Sample+1].GlobalOffset);
239 int GlobalOffsetCounter = 0;
240 for(
size_t iSample = 0; iSample <
SampleBinning.size(); iSample++){
253 if(!Binning.Uniform) {
254 MACH3LOG_ERROR(
"When using Non-Uniform binning for sample {} please use One bin instead of Axis bins", iSample);
267 if (SampleBin < 0 || SampleBin >=
static_cast<int>(Binning.nBins)) {
268 MACH3LOG_ERROR(
"Requested bin {} is out of range for sample {}", SampleBin, iSample);
273 if(Binning.Uniform) {
274 int Dim =
static_cast<int>(Binning.Strides.size());
275 std::vector<int> Bins(Dim, 0);
276 int Remaining = SampleBin;
289 for (
int i = 0; i < Dim; ++i) {
290 const int nBinsDim =
static_cast<int>(Binning.BinEdges[i].size()) - 1;
291 Bins[i] = Remaining % nBinsDim;
292 Remaining /= nBinsDim;
295 for (
int i = 0; i < Dim; ++i) {
296 if (i > 0) BinName +=
", ";
297 const double min = Binning.BinEdges[i].at(Bins[i]);
298 const double max = Binning.BinEdges[i].at(Bins[i] + 1);
299 BinName += fmt::format(
"Dim{} ({:g}, {:g})", i, min, max);
302 const BinInfo& bin = Binning.Bins[SampleBin];
303 const int Dim =
static_cast<int>(bin.
Extent.size());
305 for (
int i = 0; i < Dim; ++i) {
306 if (i > 0) BinName +=
", ";
307 const double min = bin.
Extent[i][0];
308 const double max = bin.
Extent[i][1];
309 BinName += fmt::format(
"Dim{} ({:g}, {:g})", i, min, max);
334 if(!Binning.Uniform) {
335 MACH3LOG_ERROR(
"When using Non-Uniform binning for sample {} please use global bin instead of {}", iSample, __func__);
338 return static_cast<int>(Binning.AxisNBins.at(iDim));
346 return Binning.Uniform;
353 if(!Binning.Uniform) {
356 MACH3LOG_ERROR(
"{} for sample {} will not work becasue binnin is unfiorm", __func__, iSample);
std::vector< std::vector< double > > 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...
std::vector< double > BuildBinEdgesFromNode(YAML::Node const &bin_edges_node, bool &found_range_specifier)
Builds a single dimension's bin edges from YAML::Node.
std::vector< double > BinRangeToBinEdges(YAML::Node const &bin_range)
Converts a range (linspace/logspace) to a std::vector<double>
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 GetSampleIndex(const int GlobalBin) const
Returns sample index based on global bin.
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" used for printing