MaCh3  2.5.0
Reference Guide
HistogramUtils.cpp
Go to the documentation of this file.
2 
4 // ROOT include
5 #include "TList.h"
6 #include "TObjArray.h"
7 #include "TObjString.h"
8 #include "TRandom3.h"
10 
11 // **************************************************
12 //KS: ROOT changes something with binning when moving from ROOT 5 to ROOT 6. If you open ROOT5 produced file with ROOT6 you will be missing 9 last bins
13 // However if you use ROOT6 and have ROOT6 file exactly the same code will work. Something have changed with how TH2Poly bins are stored in TFile
14 void CheckTH2PolyFileVersion(TFile *file) {
15 // **************************************************
16  int FileROOTVersion = file->GetVersion();
17  int MainFileROOTVersion = FileROOTVersion;
18 
19  // Remove last digit from number
20  // till only one digit is left
21  while (MainFileROOTVersion >= 10)
22  MainFileROOTVersion /= 10;
23 
24  std::string SystemROOTVersion = std::string(ROOT_RELEASE);
25  int MainSystemROOTVersion = SystemROOTVersion.at(0) - '0';
26 
27  if(MainFileROOTVersion != MainSystemROOTVersion)
28  {
29  MACH3LOG_ERROR("File was produced with: {} ROOT version", FileROOTVersion);
30  MACH3LOG_ERROR("Found: {} ROOT version in the system", SystemROOTVersion);
31  MACH3LOG_ERROR("For some documentation please visit me");
32  throw MaCh3Exception(__FILE__, __LINE__);
33  }
34 }
35 
36 // **************************************************
37 //WP: Helper function for calculating unbinned Integral of TH2Poly i.e including overflow
38 double OverflowIntegral(TH2Poly* poly) {
39 // **************************************************
40  double overflow = 0.;
41  //TH2Polys have 9 overflow bins
42  for(int iOverflow = -1; iOverflow > -10; iOverflow--)
43  {
44  overflow += poly->GetBinContent(iOverflow);
45  }
46  double IntegralUn = NoOverflowIntegral(poly) + overflow;
47 
48  return IntegralUn;
49 } // end function
50 
51 // **************************************************
52 //WP: Helper function for calculating binned Integral of TH2Poly i.e not including overflow
53 double NoOverflowIntegral(TH2Poly* poly) {
54 // **************************************************
55  double integral = 0.;
56  for(int i = 1; i < poly->GetNumberOfBins()+1; i++)
57  {
58  integral += poly->GetBinContent(i);
59  }
60 
61  return integral;
62 } // end function
63 
64 // **************************************************
65 //WP: Helper function for projecting TH2Poly onto the X axis
66 TH1D* PolyProjectionX(TObject* poly, std::string TempName, const std::vector<double>& xbins, const bool computeErrors) {
67 // **************************************************
68  TH1D* hProjX = new TH1D((TempName+"_x").c_str(),(TempName+"_x").c_str(), int(xbins.size()-1), &xbins[0]);
69 
70  //KS: Temp Histogram to store error, use double as this is thread safe
71  std::vector<double> hProjX_Error(hProjX->GetXaxis()->GetNbins() + 1, 0.0);
72  double xlow, xup, frac = 0.;
73 
74  //loop over bins in the poly
75  for (int i = 0; i < static_cast<TH2Poly*>(poly)->GetNumberOfBins(); i++)
76  {
77  //get bin and its edges
78  TH2PolyBin* bin = static_cast<TH2PolyBin*>(static_cast<TH2Poly*>(poly)->GetBins()->At(i));
79  xlow = bin->GetXMin();
80  xup = bin->GetXMax();
81 
82  //Loop over projected bins, find fraction of poly bin in each
83  for(int dx = 0; dx < int(xbins.size()); dx++)
84  {
85  if(xbins[dx+1] <= xlow || xbins[dx] >= xup)
86  {
87  frac = 0;
88  }
89  else if(xbins[dx] <= xlow && xbins[dx+1] >= xup)
90  {
91  frac = 1;
92  }
93  else if(xbins[dx] <= xlow && xbins[dx+1] <= xup)
94  {
95  frac = (xbins[dx+1]-xlow)/(xup-xlow);
96  }
97  else if(xbins[dx] >= xlow && xbins[dx+1] >= xup)
98  {
99  frac = (xup-xbins[dx])/(xup-xlow);
100  }
101  else if(xbins[dx] >= xlow && xbins[dx+1] <= xup)
102  {
103  frac = (xbins[dx+1]-xbins[dx])/(xup-xlow);
104  }
105  else
106  {
107  frac = 0;
108  }
109  hProjX->SetBinContent(dx+1,hProjX->GetBinContent(dx+1)+frac*bin->GetContent());
110  //KS: Follow ROOT implementation and sum up the variance
111  if(computeErrors)
112  {
113  //KS: TH2PolyBin doesn't have GetError so we have to use TH2Poly,
114  //but numbering of GetBinError is different than GetBins...
115  const double Temp_Err = frac*static_cast<TH2Poly*>(poly)->GetBinError(i+1)*frac*static_cast<TH2Poly*>(poly)->GetBinError(i+1);
116  hProjX_Error[dx+1] += Temp_Err;
117  }
118  }
119  }
120  //KS: The error is sqrt(summed variance)) https://root.cern.ch/doc/master/TH2_8cxx_source.html#l02266
121  if(computeErrors)
122  {
123  for (int i = 1; i <= hProjX->GetXaxis()->GetNbins(); ++i)
124  {
125  const double Error = std::sqrt(hProjX_Error[i]);
126  hProjX->SetBinError(i, Error);
127  }
128  }
129  return hProjX;
130 } // end project poly X function
131 
132 // **************************************************
133 //WP: Helper function for projecting TH2Poly onto the Y axis
134 TH1D* PolyProjectionY(TObject* poly, std::string TempName, const std::vector<double>& ybins, const bool computeErrors) {
135 // **************************************************
136  TH1D* hProjY = new TH1D((TempName+"_y").c_str(),(TempName+"_y").c_str(),int(ybins.size()-1),&ybins[0]);
137  //KS: Temp Histogram to store error, use double as this is thread safe
138  std::vector<double> hProjY_Error(hProjY->GetXaxis()->GetNbins() + 1, 0.0);
139  double ylow, yup, frac = 0.;
140 
141  //loop over bins in the poly
142  for (int i = 0; i < static_cast<TH2Poly*>(poly)->GetNumberOfBins(); i++)
143  {
144  //get bin and its edges
145  TH2PolyBin* bin = static_cast<TH2PolyBin*>(static_cast<TH2Poly*>(poly)->GetBins()->At(i));
146  ylow = bin->GetYMin();
147  yup = bin->GetYMax();
148 
149  //Loop over projected bins, find fraction of poly bin in each
150  for(int dy = 0; dy < int(ybins.size()); dy++)
151  {
152  if(ybins[dy+1]<=ylow || ybins[dy] >= yup)
153  {
154  frac = 0;
155  }
156  else if(ybins[dy] <= ylow && ybins[dy+1] >= yup)
157  {
158  frac = 1;
159  }
160  else if(ybins[dy] <= ylow && ybins[dy+1] <= yup)
161  {
162  frac = (ybins[dy+1]-ylow)/(yup-ylow);
163  }
164  else if(ybins[dy] >= ylow && ybins[dy+1] >= yup)
165  {
166  frac = (yup-ybins[dy])/(yup-ylow);
167  }
168  else if(ybins[dy] >= ylow && ybins[dy+1] <= yup)
169  {
170  frac = (ybins[dy+1]-ybins[dy])/(yup-ylow);
171  }
172  else
173  {
174  frac = 0;
175  }
176  hProjY->SetBinContent(dy+1,hProjY->GetBinContent(dy+1)+frac*bin->GetContent());
177  //KS: Follow ROOT implementation and sum up the variance
178  if(computeErrors)
179  {
180  //KS: TH2PolyBin doesn't have GetError so we have to use TH2Poly,
181  //but numbering of GetBinError is different than GetBins...
182  const double Temp_Err = frac*static_cast<TH2Poly*>(poly)->GetBinError(i+1)*frac*static_cast<TH2Poly*>(poly)->GetBinError(i+1);
183  hProjY_Error[dy+1] += Temp_Err;
184  }
185  }
186  }
187  //KS: The error is sqrt(summed variance)) https://root.cern.ch/doc/master/TH2_8cxx_source.html#l02266
188  if(computeErrors)
189  {
190  for (int i = 1; i <= hProjY->GetXaxis()->GetNbins(); ++i)
191  {
192  const double Error = std::sqrt(hProjY_Error[i]);
193  hProjY->SetBinError(i, Error);
194  }
195  }
196  return hProjY;
197 } // end project poly Y function
198 
199 // ****************
200 //WP: Normalise a th2poly
201 TH2Poly* NormalisePoly(TH2Poly *Histogram) {
202 // ****************
203  TH2Poly* HistCopy = static_cast<TH2Poly*>(Histogram->Clone());
204  double IntegralWidth = PolyIntegralWidth(HistCopy);
205  HistCopy = PolyScaleWidth(HistCopy, IntegralWidth);
206  std::string title = std::string(HistCopy->GetName())+"_norm";
207  HistCopy->SetNameTitle(title.c_str(), title.c_str());
208 
209  return HistCopy;
210 }
211 
212 // ****************
213 // Normalise a TH2Poly
214 void NormaliseTH2Poly(TH2Poly* Histogram){
215 // ****************
216  const double Integral = NoOverflowIntegral(Histogram);
217  for(int j = 1; j < Histogram->GetNumberOfBins()+1; j++)
218  {
219  Histogram->SetBinContent(j, Histogram->GetBinContent(j)/Integral);
220  }
221 }
222 
223 // ****************
224 // Make a ratio histogram
225 template<class HistType>
226 HistType* RatioHists(HistType *NumHist, HistType *DenomHist) {
227 // ****************
228  HistType *NumCopy = static_cast<HistType*>(NumHist->Clone());
229  std::string title = std::string(DenomHist->GetName()) + "_ratio";
230  NumCopy->SetNameTitle(title.c_str(), title.c_str());
231  NumCopy->Divide(DenomHist);
232 
233  return NumCopy;
234 }
235 
236 // ****************
237 // Make a ratio th2poly
238 TH2Poly* RatioPolys(TH2Poly *NumHist, TH2Poly *DenomHist) {
239 // ****************
240  TH2Poly *NumCopy = static_cast<TH2Poly*>(NumHist->Clone());
241  std::string title = std::string(DenomHist->GetName()) + "_ratio";
242  NumCopy->SetNameTitle(title.c_str(), title.c_str());
243 
244  for(int i = 1; i < NumCopy->GetNumberOfBins()+1; ++i) {
245  NumCopy->SetBinContent(i,NumHist->GetBinContent(i)/DenomHist->GetBinContent(i));
246  }
247  return NumCopy;
248 }
249 
250 // ****************
251 TH2D* ConvertTH2PolyToTH2D(TH2Poly *poly, TH2D *h2dhist) {
252 // ****************
253  double xlow, xup, ylow, yup;
254  std::string HistTempName = poly->GetName();
255 
256  HistTempName += "_";
257  //make the th2d
258  TH2D *hist = static_cast<TH2D*>(h2dhist->Clone());
259  hist->SetNameTitle(HistTempName.c_str(), HistTempName.c_str());
260 
261  for(int ix = 0; ix < hist->GetNbinsX() + 2; ix++) {
262  for(int iy = 0; iy < hist->GetNbinsY() + 2; iy++) {
263  hist->SetBinContent(ix, iy, 0);
264  }
265  }
266  //Loop over poly bins, find the corresponding th2d and setbincontent!
267  for(int i = 0; i< poly->GetNumberOfBins(); i++){
268  TH2PolyBin & polybin = static_cast<TH2PolyBin &>(*poly->GetBins()->At(i));
269  xlow = polybin.GetXMin();
270  xup = polybin.GetXMax();
271  ylow = polybin.GetYMin();
272  yup = polybin.GetYMax();
273  int xbin, ybin;
274 
275  xbin = hist->GetXaxis()->FindBin(xlow+(xup-xlow)/2);
276  ybin = hist->GetYaxis()->FindBin(ylow+(yup-ylow)/2);
277 
278  MACH3LOG_TRACE("Poly bin {}, xlow: {}, xup: {}, ylow: {}, yup: {}. Finding bin for ({}, {}). Found Bin ({}, {}) with content {}. But Poly content: {}",
279  i, xlow, xup, ylow, yup, (xlow + (xup - xlow) / 2), (ylow + (yup - ylow) / 2), xbin, ybin, polybin.GetContent(), poly->GetBinContent(i));
280  hist->SetBinContent(xbin, ybin, polybin.GetContent());
281  }
282  return hist;
283 }
284 // ****************
285 TH2Poly* ConvertTH2DtoTH2Poly(TH2D* hist) {
286 // ****************
287  // Make the x axis from the momentum of lepton
288  TAxis* xaxis = hist->GetXaxis();
289  // Make the y axis from the cos theta of lepton
290  TAxis* yaxis = hist->GetYaxis();
291 
292  TString histname = hist->GetName();
293  // Convert TH2D binning to TH2Poly
294  TH2Poly* poly = new TH2Poly();
295  poly->SetName(histname);
296  poly->SetTitle(histname);
297 
298  // Copy axis titles
299  poly->GetXaxis()->SetTitle(xaxis->GetTitle());
300  poly->GetYaxis()->SetTitle(yaxis->GetTitle());
301 
302  double xmax, xmin, ymax, ymin;
303  for (int iy = 1; iy <= yaxis->GetNbins(); iy++) {
304  ymax = yaxis->GetBinUpEdge(iy);
305  ymin = yaxis->GetBinLowEdge(iy);
306  for (int ix = 1; ix <= xaxis->GetNbins(); ix++) {
307  xmax = xaxis->GetBinUpEdge(ix);
308  xmin = xaxis->GetBinLowEdge(ix);
309  double binofx[] = {xmin, xmax, xmax, xmin};
310  double binofy[] = {ymin, ymin, ymax, ymax};
311  poly->AddBin(4, binofx, binofy);
312  }
313  }
314 
315  for (int iy = 1; iy <= yaxis->GetNbins(); iy++) {
316  ymax = yaxis->GetBinUpEdge(iy);
317  ymin = yaxis->GetBinLowEdge(iy);
318  for (int ix = 1; ix <= xaxis->GetNbins(); ix++) {
319  xmax = xaxis->GetBinUpEdge(ix);
320  xmin = xaxis->GetBinLowEdge(ix);
321 
322  // Get the content of the corresponding bin in TH2D and set it in TH2Poly
323  int bin = hist->GetBin(ix, iy);
324  double content = hist->GetBinContent(bin);
325  poly->SetBinContent(poly->FindBin((xmin + xmax) / 2, (ymin + ymax) / 2), content);
326  }
327  }
328 
329  return poly;
330 }
331 
332 // ****************
333 //WP: Scale a TH2Poly and divide by bin width
334 TH2Poly* PolyScaleWidth(TH2Poly *Histogram, double scale) {
335 // ****************
336  TH2Poly* HistCopy = static_cast<TH2Poly*>(Histogram->Clone());
337  double xlow, xup, ylow, yup, area;
338 
339  for(int i = 1; i < HistCopy->GetNumberOfBins()+1; i++)
340  {
341  TH2PolyBin* bin = static_cast<TH2PolyBin*>(Histogram->GetBins()->At(i - 1));
342  xlow = bin->GetXMin();
343  xup = bin->GetXMax();
344  ylow = bin->GetYMin();
345  yup = bin->GetYMax();
346  area = (xup-xlow)*(yup-ylow);
347  HistCopy->SetBinContent(i, Histogram->GetBinContent(i)/(area*scale));
348  }
349  return HistCopy;
350 }
351 
352 // ****************
353 //WP: Integral of TH2Poly multiplied by bin width
354 double PolyIntegralWidth(TH2Poly *Histogram) {
355 // ****************
356  double integral = 0;
357  double xlow, xup, ylow, yup, area;
358 
359  for(int i = 1; i < Histogram->GetNumberOfBins()+1; i++)
360  {
361  TH2PolyBin* bin = static_cast<TH2PolyBin*>(Histogram->GetBins()->At(i - 1));
362  xlow = bin->GetXMin();
363  xup = bin->GetXMax();
364  ylow = bin->GetYMin();
365  yup = bin->GetYMax();
366  area = (xup-xlow)*(yup-ylow);
367  integral += Histogram->GetBinContent(i)*area;
368  }
369  return integral;
370 }
371 
372 // *********************
373 TH2Poly* MakePolyHist(const std::string& name, const std::vector<double>& BinArray_x, const std::vector<double>& BinArray_y) {
374 // *********************
375  TH2Poly* poly = new TH2Poly();
376  poly->SetName(name.c_str());
377  poly->SetTitle(name.c_str());
378  double xmax, xmin, ymax, ymin;
379  for(unsigned int iy = 0; iy < BinArray_y.size()-1; iy++)
380  {
381  ymax = BinArray_y[iy+1];
382  ymin = BinArray_y[iy];
383  for(unsigned int ix = 0; ix < BinArray_x.size()-1; ix++)
384  {
385  xmax = BinArray_x[ix+1];
386  xmin = BinArray_x[ix];
387  double binofx[] = {xmin, xmax, xmax, xmin};
388  double binofy[] = {ymin, ymin, ymax, ymax};
389  poly->AddBin(4,binofx,binofy);
390  }
391  }
392  return poly;
393 }
394 
395 // *********************
396 //KS: Remove fitted TF1 from hist to make comparison easier
397 void RemoveFitter(TH1D* hist, const std::string& name) {
398 // *********************
399  TList *listOfFunctions = hist->GetListOfFunctions();
400  TF1 *fitter = dynamic_cast<TF1*>(listOfFunctions->FindObject(name.c_str()));
401 
402  listOfFunctions->Remove(fitter);
403  delete fitter;
404 }
405 
406 // ****************
407 // Make Poisson Fluctuation of TH1D hist
408 void MakeFluctuatedHistogramStandard(TH1D *FluctHist, TH1D* PolyHist, TRandom3* rand){
409 // ****************
410  // Make the Poisson fluctuated hist
411  FluctHist->Reset("");
412  FluctHist->Fill(0.0, 0.0);
413 
414  for (int i = 1; i <= PolyHist->GetXaxis()->GetNbins(); ++i)
415  {
416  // Get the posterior predictive bin content
417  const double MeanContent = PolyHist->GetBinContent(i);
418  // Get a Poisson fluctuation of the content
419  const double Random = rand->PoissonD(MeanContent);
420  // Set the fluctuated histogram content to the Poisson variation of the posterior predictive histogram
421  FluctHist->SetBinContent(i,Random);
422  }
423 }
424 
425 // ****************
426 // Make Poisson Fluctuation of TH2Poly hist
427 void MakeFluctuatedHistogramStandard(TH2Poly *FluctHist, TH2Poly* PolyHist, TRandom3* rand) {
428 // ****************
429  // Make the Poisson fluctuated hist
430  FluctHist->Reset("");
431  FluctHist->Fill(0.0, 0.0, 0.0);
432 
433  for (int i = 1; i < FluctHist->GetNumberOfBins()+1; ++i)
434  {
435  // Get the posterior predictive bin content
436  const double MeanContent = PolyHist->GetBinContent(i);
437  // Get a Poisson fluctuation of the content
438  const double Random = rand->PoissonD(MeanContent);
439  // Set the fluctuated histogram content to the Poisson variation of the posterior predictive histogram
440  FluctHist->SetBinContent(i,Random);
441  }
442 }
443 
444 // ****************
445 // Make Poisson Fluctuation of TH2D hist
446 void MakeFluctuatedHistogramStandard(TH2D* FluctHist, TH2D* Hist, TRandom3* rand) {
447 // ****************
448  // Reset the histogram
449  FluctHist->Reset("");
450  FluctHist->Fill(0.0, 0.0, 0.0);
451 
452  // Loop over all bins
453  const int nBinsX = Hist->GetXaxis()->GetNbins();
454  const int nBinsY = Hist->GetYaxis()->GetNbins();
455  for (int ix = 1; ix <= nBinsX; ++ix) {
456  for (int iy = 1; iy <= nBinsY; ++iy) {
457  // Get the original bin content
458  const double MeanContent = Hist->GetBinContent(ix, iy);
459  // Generate Poisson fluctuation
460  const double Random = rand->PoissonD(MeanContent);
461  // Set the Random content
462  FluctHist->SetBinContent(ix, iy, Random);
463  }
464  }
465 }
466 
467 // ****************
468 // Make Poisson Fluctuation of TH1D hist
469 void MakeFluctuatedHistogramAlternative(TH1D* FluctHist, TH1D* PolyHist, TRandom3* rand){
470 // ****************
471  // Make the Poisson fluctuated hist
472  FluctHist->Reset("");
473  FluctHist->Fill(0.0, 0.0);
474 
475  const double evrate = PolyHist->Integral();
476  #pragma GCC diagnostic push
477  #pragma GCC diagnostic ignored "-Wconversion"
478  const int num = rand->Poisson(evrate);
479  #pragma GCC diagnostic pop
480  int count = 0;
481  while(count < num)
482  {
483  const double candidate = PolyHist->GetRandom();
484  FluctHist->Fill(candidate);
485  count++;
486  }
487 }
488 
489 // ****************
490 // Make Poisson Fluctuation of TH1D hist
491 void MakeFluctuatedHistogramAlternative(TH2D* FluctHist, TH2D* PolyHist, TRandom3* rand) {
492 // ****************
493  FluctHist->Reset();
494  FluctHist->Fill(0.0, 0.0, 0.0);
495 
496  const double evrate = PolyHist->Integral();
497  #pragma GCC diagnostic push
498  #pragma GCC diagnostic ignored "-Wconversion"
499  const int num = rand->Poisson(evrate);
500  #pragma GCC diagnostic pop
501 
502  double x, y;
503  for (int count = 0; count < num; ++count) {
504  PolyHist->GetRandom2(x, y);
505  FluctHist->Fill(x, y);
506  }
507 }
508 // ****************
509 //KS: ROOT developers were too lazy do develop getRanom2 for TH2Poly, this implementation is based on:
510 // https://root.cern.ch/doc/master/classTH2.html#a883f419e1f6899f9c4255b458d2afe2e
511 int GetRandomPoly2(const TH2Poly* PolyHist, TRandom3* rand) {
512 // ****************
513  const int nbins = PolyHist->GetNumberOfBins();
514  const double r1 = rand->Rndm();
515 
516  double* fIntegral = new double[nbins+2];
517  fIntegral[0] = 0.0;
518 
519  //KS: This is custom version of ComputeIntegral, once again ROOT was lazy :(
520  for (int i = 1; i < nbins+1; ++i)
521  {
522  fIntegral[i] = 0.0;
523  const double content = PolyHist->GetBinContent(i);
524  fIntegral[i] += fIntegral[i - 1] + content;
525  }
526  for (Int_t bin = 1; bin < nbins+1; ++bin) fIntegral[bin] /= fIntegral[nbins];
527  fIntegral[nbins+1] = PolyHist->GetEntries();
528 
529  //KS: We just return one rather then X and Y, this way we can use SetBinContent rather than Fill, which is faster
530  int iBin = int(TMath::BinarySearch(nbins, fIntegral, r1));
531  //KS: Have to increment because TH2Poly has stupid offset arghh
532  iBin += 1;
533 
534  delete[] fIntegral;
535  return iBin;
536 }
537 
538 // ****************
539 // Make Poisson fluctuation of TH2Poly hist
540 void MakeFluctuatedHistogramAlternative(TH2Poly *FluctHist, TH2Poly* PolyHist, TRandom3* rand){
541 // ****************
542  // Make the Poisson fluctuated hist
543  FluctHist->Reset("");
544  FluctHist->Fill(0.0, 0.0, 0.0);
545 
546  const double evrate = NoOverflowIntegral(PolyHist);
547  #pragma GCC diagnostic push
548  #pragma GCC diagnostic ignored "-Wconversion"
549  const int num = rand->Poisson(evrate);
550  #pragma GCC diagnostic pop
551  int count = 0;
552  while(count < num)
553  {
554  const int iBin = GetRandomPoly2(PolyHist, rand);
555  FluctHist->SetBinContent(iBin, FluctHist->GetBinContent(iBin) + 1);
556  count++;
557  }
558 }
559 
560 // ****************
561 //Fast and thread safe fill of violin histogram, it assumes both histograms have the same binning
562 void FastViolinFill(TH2D* violin, TH1D* hist_1d){
563 // ****************
564  for (int x = 0; x < violin->GetXaxis()->GetNbins(); ++x)
565  {
566  const int y = violin->GetYaxis()->FindBin(hist_1d->GetBinContent(x+1));
567  violin->SetBinContent(x+1, y, violin->GetBinContent(x+1, y)+1);
568  }
569 }
570 
571 
572 // ****************
573 //DB Get the Cherenkov momentum threshold in MeV
574 double returnCherenkovThresholdMomentum(const int PDG) {
575 // ****************
576  constexpr double refractiveIndex = 1.334; //DB From https://github.com/fiTQun/fiTQun/blob/646cf9c8ba3d4f7400bcbbde029d5ca15513a3bf/fiTQun_shared.cc#L757
577  double mass = M3::Utils::GetMassFromPDG(PDG)*1e3;
578  double momentumThreshold = mass/sqrt(refractiveIndex*refractiveIndex-1.);
579  return momentumThreshold;
580 }
581 
582 // **************************************************************************
583 // Recalculate Q^2 after Eb shift. Takes in shifted lepton momentum, lepton angle, and true neutrino energy
584 double CalculateQ2(double PLep, double PUpd, double EnuTrue, double InitialQ2){
585 // ***************************************************************************
586  constexpr double MLep = 0.10565837;
587  constexpr double MLep2 = MLep * MLep;
588 
589  // Calculate muon energy
590  double ELep = sqrt((MLep2)+(PLep*PLep));
591 
592  double CosTh = (2*EnuTrue*ELep - MLep2 - InitialQ2)/(2*EnuTrue*PLep);
593 
594  ELep = sqrt((MLep2)+(PUpd*PUpd));
595 
596  // Calculate the new Q2
597  double Q2Upd = -(MLep2) + 2.0*EnuTrue*(ELep - PUpd*CosTh);
598 
599  return Q2Upd - InitialQ2;
600 }
601 
602 // **************************************************************************
603 // Recalculate Enu after Eb shift. Takes in shifted lepton momentum, lepton angle, and binding energy change, and if nu/anu
604 double CalculateEnu(double PLep, double costh, double Eb, bool neutrino){
605 // ***************************************************************************
606  double mNeff = 0.93956536 - Eb / 1000.;
607  double mNoth = 0.93827203;
608 
609  if (!neutrino) {
610  mNeff = 0.93827203 - Eb / 1000.;
611  mNoth = 0.93956536;
612  }
614  constexpr double mLep = 0.10565837;
615  constexpr double mLep2 = mLep * mLep;
616 
617  const double eLep = sqrt(PLep * PLep + mLep2);
618  double Enu = (2 * mNeff * eLep - mLep2 + mNoth * mNoth - mNeff * mNeff) /(2 * (mNeff - eLep + PLep * costh));
619 
620  return Enu;
621 }
622 
623 // ***********************************************
624 std::unique_ptr<TH1D> MakeSummaryFromSpectra(const TH2D* Spectra,
625  const std::string& name) {
626 // ***********************************************
627  const int nBinsX = Spectra->GetNbinsX();
628  // Reuse the exact x binning
629  std::vector<double> edges(nBinsX + 1);
630  for (int i = 0; i < nBinsX; ++i) {
631  edges[i] = Spectra->GetXaxis()->GetBinLowEdge(i+1);
632  }
633  edges[nBinsX] = Spectra->GetXaxis()->GetBinUpEdge(nBinsX);
634 
635  auto h1 = std::make_unique<TH1D>(name.c_str(), name.c_str(), nBinsX, edges.data());
636  h1->SetDirectory(nullptr);
637  h1->Sumw2(true);
638 
639  // ---- Loop X bins and extract Y distribution
640  for (int ix = 1; ix <= nBinsX; ++ix) {
641  // Project THIS x-bin onto Y
642  std::unique_ptr<TH1D> slice(Spectra->ProjectionY(Form("_py_%d", ix), ix, ix));
643  slice->SetDirectory(nullptr);
644  if (slice->GetEntries() == 0) {
645  h1->SetBinContent(ix, 0.0);
646  h1->SetBinError(ix, 0.0);
647  continue;
648  }
649 
650  const double mean = slice->GetMean();
651  const double rms = slice->GetRMS();
652 
653  h1->SetBinContent(ix, mean);
654  h1->SetBinError(ix, rms);
655  }
656 
657  h1->GetXaxis()->SetTitle(Spectra->GetXaxis()->GetTitle());
658  h1->GetYaxis()->SetTitle("Events");
659 
660  return h1;
661 }
662 
663 namespace M3 {
664 // **************************************************************************
665 TFile* Open(const std::string& Name, const std::string& Type, const std::string& File, const int Line) {
666 // **************************************************************************
667  TFile* OutFile = new TFile(Name.c_str(), Type.c_str());
668 
669  // Check if the file is successfully opened and usable
670  if (OutFile->IsZombie()) {
671  MACH3LOG_ERROR("Failed to open file: {}", Name);
672  std::string lowerType = Type;
673  std::transform(lowerType.begin(), lowerType.end(), lowerType.begin(), ::tolower);
674  if (lowerType == "recreate") {
675  MACH3LOG_ERROR("Check if directory exist");
676  }
677  delete OutFile;
678  throw MaCh3Exception(File, Line);
679  }
680  return OutFile;
681 }
682 
683 // ***************************************************************************
684 void ScaleHistogram(TH1* Sample_Hist, const double scale) {
685 // ***************************************************************************
686  for (int j = 0; j <= Sample_Hist->GetNbinsX(); ++j)
687  {
688  double num = Sample_Hist->GetBinContent(j);
689  double numErr = Sample_Hist->GetBinError(j);
690  double den = Sample_Hist->GetBinWidth(j);
691  double value = 0.;
692  double valueErr = 0.;
693  if (den != 0)
694  {
695  value = num/(den/scale);
696  valueErr = numErr/(den/scale);
697  Sample_Hist->SetBinContent(j,value);
698  Sample_Hist->SetBinError(j,valueErr);
699  }
700  }
701 }
702 // ***************************************************************************
703 //KS: Helper function check if data and MC binning matches
704 void CheckBinningMatch(const TH1D* Hist1, const TH1D* Hist2, const std::string& File, const int Line) {
705 // ***************************************************************************
706  if (Hist1->GetNbinsX() != Hist2->GetNbinsX()) {
707  MACH3LOG_ERROR("Number of bins does not match for TH1D: {} vs {}", Hist1->GetNbinsX(), Hist2->GetNbinsX());
708  throw MaCh3Exception(File, Line);
709  }
710  for (int i = 1; i <= Hist1->GetNbinsX(); ++i) {
711  if (std::fabs(Hist1->GetXaxis()->GetBinLowEdge(i) - Hist2->GetXaxis()->GetBinLowEdge(i)) > 0.001 ||
712  std::fabs(Hist1->GetXaxis()->GetBinUpEdge(i) - Hist2->GetXaxis()->GetBinUpEdge(i)) > 0.001) {
713  MACH3LOG_ERROR("Bin edges do not match for TH1D at bin {}", i);
714  throw MaCh3Exception(File, Line);
715  }
716  }
717 }
718 // ***************************************************************************
719 //KS: Helper function check if data and MC binning matches
720 void CheckBinningMatch(const TH2D* Hist1, const TH2D* Hist2, const std::string& File, const int Line) {
721 // ***************************************************************************
722  if (Hist1->GetNbinsX() != Hist2->GetNbinsX() || Hist1->GetNbinsY() != Hist2->GetNbinsY()) {
723  MACH3LOG_ERROR("Number of bins does not match for TH2D");
724  throw MaCh3Exception(File, Line);
725  }
726 
727  for (int i = 1; i <= Hist1->GetNbinsX(); ++i) {
728  if (std::fabs(Hist1->GetXaxis()->GetBinLowEdge(i) - Hist2->GetXaxis()->GetBinLowEdge(i)) > 0.001 ||
729  std::fabs(Hist1->GetXaxis()->GetBinUpEdge(i) - Hist2->GetXaxis()->GetBinUpEdge(i)) > 0.001) {
730  MACH3LOG_ERROR("X bin edges do not match for TH2D at bin {}", i);
731  throw MaCh3Exception(File, Line);
732  }
733  }
734  for (int j = 1; j <= Hist1->GetNbinsY(); ++j) {
735  if (std::fabs(Hist1->GetYaxis()->GetBinLowEdge(j) - Hist2->GetYaxis()->GetBinLowEdge(j)) > 0.001 ||
736  std::fabs(Hist1->GetYaxis()->GetBinUpEdge(j) - Hist2->GetYaxis()->GetBinUpEdge(j)) > 0.001) {
737  MACH3LOG_ERROR("Y bin edges do not match for TH2D at bin {}", j);
738  throw MaCh3Exception(File, Line);
739  }
740  }
741 }
742 
743 // ***************************************************************************
744 //KS: Helper function check if data and MC binning matches
745 void CheckBinningMatch(TH2Poly* Hist1, TH2Poly* Hist2, const std::string& File, const int Line) {
746 // ***************************************************************************
747  int NBins1 = Hist1->GetNumberOfBins();
748  int NBins2 = Hist2->GetNumberOfBins();
749  if (NBins1 != NBins2) {
750  MACH3LOG_ERROR("Number of bins does not match for TH2Poly: {} vs {}", NBins1, NBins2);
751  throw MaCh3Exception(File, Line);
752  }
753  for (int j = 1; j <= NBins1; j++)
754  {
755  //KS: There is weird offset between bin content and GetBins so this is correct, in spite of looking funny
756  TH2PolyBin* polybin1 = static_cast<TH2PolyBin*>(Hist1->GetBins()->At(j - 1));
757  TH2PolyBin* polybin2 = static_cast<TH2PolyBin*>(Hist2->GetBins()->At(j - 1));
758 
759  if( std::fabs(polybin2->GetXMin() - polybin1->GetXMin()) > 0.001 ||
760  std::fabs(polybin2->GetXMax() - polybin1->GetXMax()) > 0.001 ||
761  std::fabs(polybin2->GetYMin() - polybin1->GetYMin()) > 0.001 ||
762  std::fabs(polybin2->GetYMax() - polybin1->GetYMax()) > 0.001 )
763  {
764  MACH3LOG_ERROR("Binning doesn't match", Hist1->GetTitle());
765  MACH3LOG_ERROR("data x min {} x max {} y min {} y max {}", polybin2->GetXMin(), polybin2->GetXMax(), polybin2->GetYMin(), polybin2->GetYMax());
766  MACH3LOG_ERROR("mc x min {} x max {} y min {} y max {}", polybin1->GetXMin(), polybin1->GetXMax(), polybin1->GetYMin(), polybin1->GetYMax());
767  throw MaCh3Exception(File , Line );
768  }
769  }
770 }
771 
772 // ***************************************************************************
773 //KS: Convert TH2Poly into yaml config accepted by MaCh3
774 YAML::Node PolyToYaml(TH2Poly* Hist, const std::string& YamlName, const std::string& File, const int Line) {
775 // ***************************************************************************
776  if (!Hist) {
777  MACH3LOG_ERROR("Null TH2Poly pointer");
778  throw MaCh3Exception(File, Line);
779  }
780 
781  YAML::Node bins(YAML::NodeType::Sequence);
782  bins.SetStyle(YAML::EmitterStyle::Flow);
783  const int NBins = Hist->GetNumberOfBins();
784 
785  for (int j = 1; j <= NBins; j++)
786  {
787  TH2PolyBin* polybin = static_cast<TH2PolyBin*>(Hist->GetBins()->At(j - 1));
788 
789  double xmin = polybin->GetXMin();
790  double xmax = polybin->GetXMax();
791  double ymin = polybin->GetYMin();
792  double ymax = polybin->GetYMax();
793 
794  YAML::Node xNode(YAML::NodeType::Sequence);
795  xNode.SetStyle(YAML::EmitterStyle::Flow);
796  xNode.push_back(xmin);
797  xNode.push_back(xmax);
798 
799  YAML::Node yNode(YAML::NodeType::Sequence);
800  yNode.SetStyle(YAML::EmitterStyle::Flow);
801  yNode.push_back(ymin);
802  yNode.push_back(ymax);
803 
804  YAML::Node bin(YAML::NodeType::Sequence);
805  bin.SetStyle(YAML::EmitterStyle::Flow);
806  bin.push_back(xNode);
807  bin.push_back(yNode);
808 
809  bins.push_back(bin);
810  }
811 
812  YAML::Node result;
813  result[YamlName] = bins;
814 
815  return result;
816 }
817 
818 } //end M3 namespace
#define _MaCh3_Safe_Include_Start_
KS: Avoiding warning checking for headers.
Definition: Core.h:126
#define _MaCh3_Safe_Include_End_
KS: Restore warning checking after including external headers.
Definition: Core.h:141
void MakeFluctuatedHistogramAlternative(TH1D *FluctHist, TH1D *PolyHist, TRandom3 *rand)
Make Poisson fluctuation of TH1D hist using slow method which is only for cross-check.
TH2D * ConvertTH2PolyToTH2D(TH2Poly *poly, TH2D *h2dhist)
KS: Convert TH2D to TH2Poly.
void NormaliseTH2Poly(TH2Poly *Histogram)
Helper to Normalise histograms.
double returnCherenkovThresholdMomentum(const int PDG)
DB Get the Cherenkov momentum threshold in MeV.
double OverflowIntegral(TH2Poly *poly)
WP: Helper function for calculating unbinned Integral of TH2Poly i.e including overflow.
void MakeFluctuatedHistogramStandard(TH1D *FluctHist, TH1D *PolyHist, TRandom3 *rand)
Make Poisson fluctuation of TH1D hist using default fast method.
TH1D * PolyProjectionX(TObject *poly, std::string TempName, const std::vector< double > &xbins, const bool computeErrors)
WP: Poly Projectors.
int GetRandomPoly2(const TH2Poly *PolyHist, TRandom3 *rand)
KS: ROOT developers were too lazy do develop getRanom2 for TH2Poly, this implementation is based on l...
void FastViolinFill(TH2D *violin, TH1D *hist_1d)
KS: Fill Violin histogram with entry from a toy.
TH2Poly * NormalisePoly(TH2Poly *Histogram)
WP: Helper to Normalise histograms.
HistType * RatioHists(HistType *NumHist, HistType *DenomHist)
Helper to make ratio histograms.
TH2Poly * RatioPolys(TH2Poly *NumHist, TH2Poly *DenomHist)
Helper to make ratio of TH2Polys.
TH2Poly * PolyScaleWidth(TH2Poly *Histogram, double scale)
WP: Helper to scale th2poly analogous to th2d scale with option "width".
TH1D * PolyProjectionY(TObject *poly, std::string TempName, const std::vector< double > &ybins, const bool computeErrors)
WP: Poly Projectors.
void RemoveFitter(TH1D *hist, const std::string &name)
KS: Remove fitted TF1 from hist to make comparison easier.
double CalculateEnu(double PLep, double costh, double Eb, bool neutrino)
Recalculate Enu after Eb shift. Takes in shifted lepton momentum, lepton angle, and binding energy ch...
double PolyIntegralWidth(TH2Poly *Histogram)
WP: Helper to calc integral of th2poly analogous to th2d integra; with option "width".
_MaCh3_Safe_Include_Start_ _MaCh3_Safe_Include_End_ void CheckTH2PolyFileVersion(TFile *file)
KS: ROOT changes something with binning when moving from ROOT 5 to ROOT 6. If you open ROOT5 produced...
double NoOverflowIntegral(TH2Poly *poly)
WP: Helper function for calculating binned Integral of TH2Poly i.e not including overflow.
TH2Poly * ConvertTH2DtoTH2Poly(TH2D *hist)
KS: Convert TH2Poly to TH2D.
TH2Poly * MakePolyHist(const std::string &name, const std::vector< double > &BinArray_x, const std::vector< double > &BinArray_y)
WP: Helper function to create TH2Poly histogram with uniform binning.
std::unique_ptr< TH1D > MakeSummaryFromSpectra(const TH2D *Spectra, const std::string &name)
Build a 1D posterior-predictive summary from a violin spectrum.
double CalculateQ2(double PLep, double PUpd, double EnuTrue, double InitialQ2)
Recalculate Q^2 after Eb shift. Takes in shifted lepton momentum, lepton angle, and true neutrino ene...
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:37
#define MACH3LOG_TRACE
Definition: MaCh3Logger.h:33
Custom exception class used throughout MaCh3.
double GetMassFromPDG(const int PDG)
Return mass for given PDG.
Main namespace for MaCh3 software.
void CheckBinningMatch(const TH1D *Hist1, const TH1D *Hist2, const std::string &File, const int Line)
KS: Helper function check if data and MC binning matches.
void ScaleHistogram(TH1 *Sample_Hist, const double scale)
Scale histogram to get divided by bin width.
TFile * Open(const std::string &Name, const std::string &Type, const std::string &File, const int Line)
Opens a ROOT file with the given name and mode.
YAML::Node PolyToYaml(TH2Poly *Hist, const std::string &YamlName, const std::string &File, const int Line)
KS: Convert TH2Poly into yaml config accepted by MaCh3.