MaCh3  2.2.3
Reference Guide
SampleStructs.h
Go to the documentation of this file.
1 #pragma once
2 
3 // C++ includes
4 #include <set>
5 #include <list>
6 #include <unordered_map>
7 
8 // MaCh3 includes
10 #include "Manager/MaCh3Logger.h"
11 #include "Manager/Core.h"
12 
14 // ROOT include
15 #include "TSpline.h"
16 #include "TObjString.h"
17 #include "TFile.h"
18 #include "TF1.h"
19 #include "TH2Poly.h"
20 #include "TH1.h"
21 // NuOscillator includes
22 #include "Constants/OscillatorConstants.h"
24 
32 
33 
34 // *******************
36 constexpr unsigned int str2int(const char* str, const int h = 0) {
37 // *******************
38  return !str[h] ? 5381 : (str2int(str, h+1) * 33) ^ str[h];
39 }
40 
41 
42 // *****************
44 enum TargetMat {
45 // *****************
46  kTarget_H = 1,
47  kTarget_C = 12,
48  kTarget_N = 14,
49  kTarget_O = 16,
50  kTarget_Al = 27,
51  kTarget_Ar = 40,
52  kTarget_Ti = 48,
53  kTarget_Fe = 56,
54  kTarget_Pb = 207
55 };
56 
57 // *****************
59 inline std::string TargetMat_ToString(const TargetMat i) {
60 // *****************
61  std::string name;
62 
63  switch(i) {
64  case kTarget_H:
65  name = "Hydrogen";
66  break;
67  case kTarget_C:
68  name = "Carbon";
69  break;
70  case kTarget_N:
71  name = "Nitrogen";
72  break;
73  case kTarget_O:
74  name = "Oxygen";
75  break;
76  case kTarget_Al:
77  name = "Aluminium";
78  break;
79  case kTarget_Ar:
80  name = "Argon";
81  break;
82  case kTarget_Ti:
83  name = "Titanium";
84  break;
85  case kTarget_Fe:
86  name = "Iron";
87  break;
88  case kTarget_Pb:
89  name = "Lead";
90  break;
91  default:
92  name = "TargetMat_Undefined";
93  break;
94  }
95 
96  return name;
97 }
98 
99 // *****************
101 enum NuPDG {
102 // *****************
103  kNue = 12,
104  kNumu = 14,
105  kNutau = 16,
106  kNueBar = -12,
107  kNumuBar = -14,
108  kNutauBar = -16
109 };
110 
119 };
120 
121 // **************************************************
123 inline std::string TestStatistic_ToString(const TestStatistic TestStat) {
124 // **************************************************
125  std::string name = "";
126 
127  switch(TestStat) {
129  name = "Poisson";
130  break;
132  name = "Barlow-Beeston";
133  break;
135  name = "IceCube";
136  break;
138  name = "Pearson";
139  break;
141  name = "Dembinski-Abdelmotteleb";
142  break;
144  MACH3LOG_ERROR("kNTestStatistics is not a valid TestStatistic!");
145  throw MaCh3Exception(__FILE__, __LINE__);
146  default:
147  MACH3LOG_ERROR("UNKNOWN LIKELIHOOD SPECIFIED!");
148  MACH3LOG_ERROR("You gave test-statistic {}", static_cast<int>(TestStat));
149  throw MaCh3Exception(__FILE__ , __LINE__ );
150  }
151  return name;
152 }
153 
154 // ***************************
156 struct KinematicCut {
157 // ***************************
164 };
165 
166 
167 // ***************************
170 // ***************************
179 };
180 
181 // ***************************
184 // ***************************
186  std::vector<double> XBinEdges;
188  std::vector<double> YBinEdges;
189 
199  std::vector<BinShiftLookup> xBinLookup;
200 
205  int GetBin(const int xBin, const int yBin) const {
206  return static_cast<int>(yBin * nXBins + xBin);
207  }
208 
214  int GetBinSafe(const int xBin, const int yBin) const {
215  if (xBin < 0 || yBin < 0 || static_cast<size_t>(xBin) >= nXBins || static_cast<size_t>(yBin) >= nYBins) {
216  MACH3LOG_ERROR("GetBinSafe: Bin indices out of range: xBin={}, yBin={}, max xBin={}, max yBin={}",
217  xBin, yBin, nXBins - 1, nYBins - 1);
218  throw MaCh3Exception(__FILE__, __LINE__);
219  }
220  return GetBin(xBin, yBin);
221  }
222 
226  int GetBinGlobal(const int xBin, const int yBin) const {
227  return static_cast<int>(GlobalOffset + GetBin(xBin, yBin));
228  }
229 
231  int FindXBin(const double XVar, const int NomXBin) const {
232  // KS: Get reference to avoid repeated indexing and help with performance
233  const auto& xBin = xBinLookup[NomXBin];
234 
235  //DB Check to see if momentum shift has moved bins
236  //DB - First , check to see if the event is outside of the binning range and skip event if it is
237  if (XVar < XBinEdges[0] || XVar >= XBinEdges[nXBins]) {
238  return -1;
239  }
240  //DB - Second, check to see if the event is still in the nominal bin
241  else if (XVar < xBin.upper_binedge && XVar >= xBin.lower_binedge) {
242  return NomXBin;
243  }
244  //DB - Thirdly, check the adjacent bins first as Eb+CC+EScale shifts aren't likely to move an Erec more than 1bin width
245  //Shifted down one bin from the event bin at nominal
246  else if (XVar < xBin.lower_binedge && XVar >= xBin.lower_lower_binedge) {
247  return NomXBin-1;
248  }
249  //Shifted up one bin from the event bin at nominal
250  else if (XVar < xBin.upper_upper_binedge && XVar >= xBin.upper_binedge) {
251  return NomXBin+1;
252  }
253  //DB - If we end up in this loop, the event has been shifted outside of its nominal bin, but is still within the allowed binning range
254  else {
255  // KS: Perform binary search to find correct bin. We already checked if isn't outside of bounds
256  return static_cast<int>(std::distance(XBinEdges.begin(), std::upper_bound(XBinEdges.begin(), XBinEdges.end(), XVar)) - 1);
257  }
258  }
259 
264  void InitialiseLookUpSingleDimension(std::vector<BinShiftLookup>& BinLookup, const std::vector<double>& BinEdges, const size_t TotBins) {
265  BinLookup.resize(TotBins);
266  //Set rw_pdf_bin and upper_binedge and lower_binedge for each skmc_base
267  for(size_t bin_i = 0; bin_i < TotBins; bin_i++){
268  double low_lower_edge = M3::_DEFAULT_RETURN_VAL_;
269  double low_edge = BinEdges[bin_i];
270  double upper_edge = BinEdges[bin_i+1];
271  double upper_upper_edge = M3::_DEFAULT_RETURN_VAL_;
272 
273  if (bin_i == 0) {
274  low_lower_edge = BinEdges[0];
275  } else {
276  low_lower_edge = BinEdges[bin_i-1];
277  }
278 
279  if (bin_i + 2 < TotBins) {
280  upper_upper_edge = BinEdges[bin_i + 2];
281  } else if (bin_i + 1 < TotBins) {
282  upper_upper_edge = BinEdges[bin_i + 1];
283  }
284 
285  BinLookup[bin_i].lower_binedge = low_edge;
286  BinLookup[bin_i].upper_binedge = upper_edge;
287  BinLookup[bin_i].lower_lower_binedge = low_lower_edge;
288  BinLookup[bin_i].upper_upper_binedge = upper_upper_edge;
289  }
290  }
291 
297  }
298 };
299 
304 inline int GetSampleFromGlobalBin(const std::vector<SampleBinningInfo>& BinningInfo, const size_t GlobalBin) {
305  for (size_t iSample = 0; iSample < BinningInfo.size(); ++iSample) {
306  const SampleBinningInfo& info = BinningInfo[iSample];
307  if (GlobalBin >= info.GlobalOffset && GlobalBin < info.GlobalOffset + info.nBins) {
308  return static_cast<int>(iSample);
309  }
310  }
311 
312  MACH3LOG_ERROR("Couldn't find sample corresponding to bin {}", GlobalBin);
313  throw MaCh3Exception(__FILE__, __LINE__);
314 
315  // GlobalBin is out of range for all samples
316  return M3::_BAD_INT_;
317 }
318 
321 inline void SetGlobalBinNumbers(std::vector<SampleBinningInfo>& BinningInfo) {
322  if (BinningInfo.empty()) {
323  MACH3LOG_ERROR("No binning samples provided.");
324  throw MaCh3Exception(__FILE__, __LINE__);
325  }
326 
327  size_t GlobalOffsetCounter = 0;
328  for(size_t iSample = 0; iSample < BinningInfo.size(); iSample++){
329  BinningInfo[iSample].GlobalOffset = GlobalOffsetCounter;
330  GlobalOffsetCounter += BinningInfo[iSample].nBins;
331  }
332 }
333 
334 // ***************************
335 // A handy namespace for variables extraction
336 namespace MaCh3Utils {
337 // ***************************
338  // *****************************
344  inline double GetMassFromPDG(const int PDG) {
345  // *****************************
346  switch (abs(PDG)) {
347  // Leptons
348  case 11: return 0.00051099895; // e
349  case 13: return 0.1056583755; // mu
350  case 15: return 1.77693; // tau
351  // Neutrinos
352  case 12:
353  case 14:
354  case 16:
355  return 0.;
356  // Photon
357  case 22: return 0.;
358  // Mesons
359  case 211: return 0.13957039; // pi_+/-
360  case 111: return 0.1349768; // pi_0
361  case 221: return 0.547862; // eta
362  case 311: // K_0
363  case 130: // K_0_L
364  case 310: // K_0_S
365  return 0.497611;
366  case 321: return 0.493677; // K_+/-
367  // Baryons
368  case 2112: return 0.939565; // n
369  case 2212: return 0.938272; // p
370  case 3122: return 1.115683; // lambda
371  case 3222: return 1.118937; // sig_+
372  case 3112: return 1.197449; // sig_-
373  case 3212: return 1.192642; // sig_0
374  // Nuclei
375  case 1000050110: return 10.255103; // Boron-11
376  case 1000060120: return 11.177929; // Carbon-12
377  case 1000070140: return 13.043781; // Nitrogen-14
378  case 1000080160: return 14.899169; // Oxygen-16
379  case 1000090190: return 17.696901; // Fluorine-19
380  case 1000110230: return 21.414835; // Sodium-23
381  case 1000130270: return 25.133144; // Aluminum-27
382  case 1000140280: return 26.060342; // Silicon-28
383  case 1000190390: return 36.294463; // Potassium-39
384  case 1000180400: return 37.224724; // Argon-40
385  case 1000220480: return 44.663224; // Titanium-48
386  case 1000300640: return 59.549619; // Zinc-64
387  default:
388  MACH3LOG_ERROR("Haven't got a saved mass for PDG: {}", PDG);
389  MACH3LOG_ERROR("Please implement me!");
390  throw MaCh3Exception(__FILE__, __LINE__);
391  } // End switch
392  MACH3LOG_ERROR("Warning, didn't catch a saved mass");
393  return 0;
394  }
395  // ***************************
396 
397  // ***************************
401  inline int PDGToNuOscillatorFlavour(const int NuPdg){
402  int NuOscillatorFlavour = M3::_BAD_INT_;
403  switch(std::abs(NuPdg)){
404  case NuPDG::kNue:
405  NuOscillatorFlavour = NuOscillator::kElectron;
406  break;
407  case NuPDG::kNumu:
408  NuOscillatorFlavour = NuOscillator::kMuon;
409  break;
410  case NuPDG::kNutau:
411  NuOscillatorFlavour = NuOscillator::kTau;
412  break;
413  default:
414  MACH3LOG_ERROR("Unknown Neutrino PDG {}, cannot convert to NuOscillator type", NuPdg);
415  break;
416  }
417 
418  //This is very cheeky but if the PDG is negative then multiply the PDG by -1
419  // This is consistent with the treatment that NuOscillator expects as enums only
420  // exist for the generic matter flavour and not the anti-matter version
421  if(NuPdg < 0){NuOscillatorFlavour *= -1;}
422 
423  return NuOscillatorFlavour;
424  }
425  // ***************************
426 
427  // ***************************
429  inline std::string FormatDouble(const double value, const int precision) {
430  // ***************************
431  std::ostringstream oss;
432  oss << std::fixed << std::setprecision(precision) << value;
433  return oss.str();
434  }
435 
436 } // end MaCh3Utils namespace
#define _MaCh3_Safe_Include_Start_
KS: Avoiding warning checking for headers.
Definition: Core.h:109
#define _MaCh3_Safe_Include_End_
KS: Restore warning checking after including external headers.
Definition: Core.h:120
KS: Based on this https://github.com/gabime/spdlog/blob/a2b4262090fd3f005c2315dcb5be2f0f1774a005/incl...
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:27
NuPDG
Enum to track the incoming neutrino species.
@ kNutauBar
@ kNutau
@ kNumuBar
@ kNueBar
@ kNue
@ kNumu
std::string TestStatistic_ToString(const TestStatistic TestStat)
Convert a LLH type to a string.
std::string TargetMat_ToString(const TargetMat i)
Converted the Target Mat to a string.
Definition: SampleStructs.h:59
TargetMat
Enum to track the target material.
Definition: SampleStructs.h:44
@ kTarget_Fe
Iron (Atomic number 26)
Definition: SampleStructs.h:53
@ kTarget_C
Carbon 12 (Atomic number 6)
Definition: SampleStructs.h:47
@ kTarget_Al
Aluminum (Atomic number 13)
Definition: SampleStructs.h:50
@ kTarget_H
Hydrogen (Atomic number 1)
Definition: SampleStructs.h:46
@ kTarget_Ti
Titanium (Atomic number 22)
Definition: SampleStructs.h:52
@ kTarget_Ar
Argon (Atomic number 18)
Definition: SampleStructs.h:51
@ kTarget_N
Nitrogen (Atomic number 7)
Definition: SampleStructs.h:48
@ kTarget_Pb
Lead (Atomic number 82)
Definition: SampleStructs.h:54
@ kTarget_O
Oxygen 16 (Atomic number 8)
Definition: SampleStructs.h:49
void SetGlobalBinNumbers(std::vector< SampleBinningInfo > &BinningInfo)
Sets the GlobalOffset for each SampleBinningInfo to enable linearization of multiple 2D binning sampl...
int GetSampleFromGlobalBin(const std::vector< SampleBinningInfo > &BinningInfo, const size_t GlobalBin)
Get the sample index corresponding to a global bin number.
TestStatistic
Make an enum of the test statistic that we're using.
@ kNTestStatistics
Number of test statistics.
@ kPearson
Standard Pearson likelihood .
@ kBarlowBeeston
Barlow-Beeston () following Conway approximation ()
@ kIceCube
Based on .
@ kDembinskiAbdelmotteleb
Based on .
@ kPoisson
Standard Poisson likelihood .
constexpr unsigned int str2int(const char *str, const int h=0)
KS: This is mad way of converting string to int. Why? To be able to use string with switch.
Definition: SampleStructs.h:36
Custom exception class for MaCh3 errors.
constexpr static const double _BAD_DOUBLE_
Default value used for double initialisation.
Definition: Core.h:46
constexpr static const int _BAD_INT_
Default value used for int initialisation.
Definition: Core.h:48
constexpr static const double _DEFAULT_RETURN_VAL_
Definition: Core.h:49
double GetMassFromPDG(const int PDG)
Return mass for given PDG.
std::string FormatDouble(const double value, const int precision)
Convert double into string for precision, useful for playing with yaml if you don't want to have in c...
int PDGToNuOscillatorFlavour(const int NuPdg)
Convert from PDG flavour to NuOscillator type beware that in the case of anti-neutrinos the NuOscilla...
KS: Store bin lookups allowing to quickly find bin after migration.
double lower_lower_binedge
lower to check if Eb has moved the erec bin
double upper_upper_binedge
upper to check if Eb has moved the erec bin
double lower_binedge
lower to check if Eb has moved the erec bin
double upper_binedge
upper to check if Eb has moved the erec bin
KS: Small struct used for applying kinematic cuts.
double UpperBound
Upper bound on which we apply cut.
double LowerBound
Lower bound on which we apply cut.
int ParamToCutOnIt
Index or enum value identifying the kinematic variable to cut on.
KS: Small struct storying info about used binning.
int GetBin(const int xBin, const int yBin) const
Get linear bin index from 2D bin indices.
void InitialiseBinMigrationLookUp()
Initialise special lookup arrays allowing to more efficiently perform bin-migration These arrays stor...
std::vector< double > YBinEdges
Vector to hold y-axis bin-edges.
int GetBinGlobal(const int xBin, const int yBin) const
Calculates the global bin number for a given 2D bin, accounting for multiple binning samples.
std::vector< BinShiftLookup > xBinLookup
Bin lookups for X axis only.
size_t nXBins
Number of X axis bins in the histogram used for likelihood calculation.
size_t nYBins
Number of Y axis bins in the histogram used for likelihood calculation.
void InitialiseLookUpSingleDimension(std::vector< BinShiftLookup > &BinLookup, const std::vector< double > &BinEdges, const size_t TotBins)
Initializes lookup arrays for efficient bin migration in a single dimension.
int GetBinSafe(const int xBin, const int yBin) const
Get linear bin index from 2D bin indices with additional checks.
size_t GlobalOffset
If you have binning for multiple samples and trying to define 1D vector let's.
std::vector< double > XBinEdges
Vector to hold x-axis bin-edges.
size_t nBins
Number of total bins.
int FindXBin(const double XVar, const int NomXBin) const
DB Find the relevant bin in the PDF for each event.