All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Spectrum.cxx
Go to the documentation of this file.
2 
7 
8 #include "TDirectory.h"
9 #include "TH2.h"
10 #include "TH3.h"
11 #include "THnSparse.h"
12 #include "TObjString.h"
13 #include "TRandom3.h"
14 
15 #include <cassert>
16 #include <iostream>
17 
18 namespace ana
19 {
20  //----------------------------------------------------------------------
21  // The one constructor to rule them all. (Almost) everyone forwards here
22  Spectrum::Spectrum(const std::vector<std::string>& labels,
23  const std::vector<Binning>& bins,
24  ESparse sparse)
25  : fHist(0), fHistSparse(0), fPOT(0), fLivetime(0),
26  fLabels(labels), fBins(bins)
27  {
28  ConstructHistogram(sparse);
29  }
30 
31  //----------------------------------------------------------------------
32  // Or here...
33  Spectrum::Spectrum(const std::string& label,
34  const Binning& bins,
35  ESparse sparse)
36  : fHist(0), fHistSparse(0), fPOT(0), fLivetime(0),
37  fLabels(1, label), fBins(1, bins)
38  {
39  ConstructHistogram(sparse);
40  }
41 
42  //----------------------------------------------------------------------
43  Spectrum::Spectrum(const std::string& label, const Binning& bins,
45  const Var& var,
46  const SpillCut& spillcut,
47  const Cut& cut,
48  const SystShifts& shift,
49  const Var& wei)
50  : Spectrum(label, bins)
51  {
52  loader.AddSpectrum(*this, var, spillcut, cut, shift, wei);
53  }
54 
55  //----------------------------------------------------------------------
56  Spectrum::Spectrum(const std::string& label, const Binning& bins,
58  const SpillVar& var,
59  const SpillCut& cut,
60  const SpillVar& wei)
61  : Spectrum(label, bins)
62  {
63  loader.AddSpectrum(*this, var, cut, wei);
64  }
65 
66  //----------------------------------------------------------------------
67  Spectrum::Spectrum(const std::string& label, const Binning& bins,
69  const MultiVar& var,
70  const SpillCut& spillcut,
71  const Cut& cut,
72  const SystShifts& shift,
73  const Var& wei)
74  : Spectrum(label, bins)
75  {
76  loader.AddSpectrum(*this, var, spillcut, cut, shift, wei);
77  }
78 
79  //----------------------------------------------------------------------
80  Spectrum::Spectrum(const std::string& label, const Binning& bins,
82  const SpillMultiVar& var,
83  const SpillCut& cut,
84  const SpillVar& wei)
85  : Spectrum(label, bins)
86  {
87  loader.AddSpectrum(*this, var, cut, wei);
88  }
89 
90  //----------------------------------------------------------------------
92  const HistAxis& axis,
93  const SpillCut& spillcut,
94  const Cut& cut,
95  const SystShifts& shift,
96  const Var& wei)
97  : Spectrum(axis.GetLabels(), axis.GetBinnings())
98  {
99  loader.AddSpectrum(*this, axis.GetMultiDVar(), spillcut, cut, shift, wei);
100  }
101 
102  //----------------------------------------------------------------------
103  Spectrum::Spectrum(const std::string& label, double pot, double livetime,
104  const Binning& bins)
105  : Spectrum(label, bins)
106  {
107  fPOT = pot;
108  fLivetime = livetime;
109  }
110 
111  //----------------------------------------------------------------------
113  const std::vector<std::string>& labels,
114  const std::vector<Binning>& bins,
115  double pot, double livetime)
116  : fHist(0), fHistSparse(0), fPOT(pot), fLivetime(livetime), fLabels(labels), fBins(bins)
117  {
118  if(!h){
119  fHist = 0;
120  return;
121  }
122 
123  DontAddDirectory guard;
124 
125  const TString className = h->ClassName();
126 
127  if(className == "TH1D"){
128  // Shortcut if types match
129  fHist = HistCache::Copy((TH1D*)h);
130  }
131  else{
132  fHist = HistCache::New("", h->GetXaxis());
133  fHist->Add(h);
134  }
135  }
136 
137  //----------------------------------------------------------------------
138  Spectrum::Spectrum(std::unique_ptr<TH1D> h,
139  const std::vector<std::string>& labels,
140  const std::vector<Binning>& bins,
141  double pot, double livetime)
142  : fHist(h.release()), fHistSparse(0), fPOT(pot), fLivetime(livetime), fLabels(labels), fBins(bins)
143  {
144  }
145 
146  //----------------------------------------------------------------------
147  Spectrum::Spectrum(const std::string& label, SpectrumLoaderBase& loader,
148  const Binning& binsx, const Var& varx,
149  const Binning& binsy, const Var& vary,
150  const SpillCut& spillcut,
151  const Cut& cut,
152  const SystShifts& shift,
153  const Var& wei)
154  : Spectrum(label, "", loader, binsx, varx, binsy, vary, spillcut, cut, shift, wei)
155  {
156  // TODO do we want this variant when there's one with a labelY just below?
157  }
158 
159  //----------------------------------------------------------------------
160  Spectrum::Spectrum(const std::string& label, SpectrumLoaderBase& loader,
161  const Binning& binsx, const SpillVar& varx,
162  const Binning& binsy, const SpillVar& vary,
163  const SpillCut& spillcut,
164  const SpillVar& wei)
165  : Spectrum(label, "", loader, binsx, varx, binsy, vary, spillcut, wei)
166  {
167  // TODO do we want this variant when there's one with a labelY just below?
168  }
169 
170  //----------------------------------------------------------------------
171  Spectrum::Spectrum(const std::string& label, SpectrumLoaderBase& loader,
172  const Binning& binsx, const MultiVar& varx,
173  const Binning& binsy, const MultiVar& vary,
174  const SpillCut& spillcut,
175  const Cut& cut,
176  const SystShifts& shift,
177  const Var& wei)
178  : Spectrum(label, "", loader, binsx, varx, binsy, vary, spillcut, cut, shift, wei)
179  {
180  // TODO do we want this variant when there's one with a labelY just below?
181  }
182 
183  //----------------------------------------------------------------------
184  Spectrum::Spectrum(const std::string& label, SpectrumLoaderBase& loader,
185  const Binning& binsx, const SpillMultiVar& varx,
186  const Binning& binsy, const SpillMultiVar& vary,
187  const SpillCut& spillcut,
188  const SpillVar& wei)
189  : Spectrum(label, "", loader, binsx, varx, binsy, vary, spillcut, wei)
190  {
191  // TODO do we want this variant when there's one with a labelY just below?
192  }
193 
194  //----------------------------------------------------------------------
196  const HistAxis& xAxis,
197  const HistAxis& yAxis,
198  const SpillCut& spillcut,
199  const Cut& cut,
200  const SystShifts& shift,
201  const Var& wei)
202  : Spectrum(xAxis.GetLabels()[0], loader,
203  xAxis.GetBinnings()[0], xAxis.GetVars()[0],
204  yAxis.GetBinnings()[0], yAxis.GetVars()[0],
205  spillcut, cut, shift, wei)
206  {
207  // TODO - do we want to keep this variant around?
208  assert(xAxis.NDimensions() == 1);
209  assert(yAxis.NDimensions() == 1);
210  }
211 
212  //----------------------------------------------------------------------
213  Spectrum::Spectrum(const std::string& xLabel,
214  const std::string& yLabel,
216  const Binning& binsx, const Var& varx,
217  const Binning& binsy, const Var& vary,
218  const SpillCut& spillcut,
219  const Cut& cut,
220  const SystShifts& shift,
221  const Var& wei)
222  : Spectrum({xLabel, yLabel}, {binsx, binsy})
223  {
224  Var multiDVar = Var2D(varx, binsx, vary, binsy);
225 
226  loader.AddSpectrum(*this, multiDVar, spillcut, cut, shift, wei);
227  }
228 
229  //----------------------------------------------------------------------
230  Spectrum::Spectrum(const std::string& xLabel,
231  const std::string& yLabel,
232  SpectrumLoaderBase& loader,
233  const Binning& binsx, const SpillVar& varx,
234  const Binning& binsy, const SpillVar& vary,
235  const SpillCut& spillcut,
236  const SpillVar& wei)
237  : Spectrum({xLabel, yLabel}, {binsx, binsy})
238  {
239  SpillVar multiDVar = Var2D(varx, binsx, vary, binsy);
240 
241  loader.AddSpectrum(*this, multiDVar, spillcut, wei);
242  }
243 
244  //----------------------------------------------------------------------
245  Spectrum::Spectrum(const std::string& xLabel,
246  const std::string& yLabel,
247  SpectrumLoaderBase& loader,
248  const Binning& binsx, const MultiVar& varx,
249  const Binning& binsy, const MultiVar& vary,
250  const SpillCut& spillcut,
251  const Cut& cut,
252  const SystShifts& shift,
253  const Var& wei)
254  : Spectrum({xLabel, yLabel}, {binsx, binsy})
255  {
256  MultiVar multiDVar = MultiVar2D(varx, binsx, vary, binsy);
257 
258  loader.AddSpectrum(*this, multiDVar, spillcut, cut, shift, wei);
259  }
260 
261  //----------------------------------------------------------------------
262  Spectrum::Spectrum(const std::string& xLabel,
263  const std::string& yLabel,
264  SpectrumLoaderBase& loader,
265  const Binning& binsx, const SpillMultiVar& varx,
266  const Binning& binsy, const SpillMultiVar& vary,
267  const SpillCut& spillcut,
268  const SpillVar& wei)
269  : Spectrum({xLabel, yLabel}, {binsx, binsy})
270  {
271  SpillMultiVar multiDVar = MultiVar2D(varx, binsx, vary, binsy);
272 
273  loader.AddSpectrum(*this, multiDVar, spillcut, wei);
274  }
275 
276  //----------------------------------------------------------------------
277  Spectrum::Spectrum(const std::string& label, SpectrumLoaderBase& loader,
278  const Binning& binsx, const Var& varx,
279  const Binning& binsy, const Var& vary,
280  const Binning& binsz, const Var& varz,
281  const SpillCut& spillcut,
282  const Cut& cut,
283  const SystShifts& shift,
284  const Var& wei,
285  ESparse sparse)
286  : Spectrum(label, "", "", loader, binsx, varx, binsy, vary, binsz, varz, spillcut, cut, shift, wei, sparse)
287  {
288  // TODO do we want this variant when there's one with a labelY and labelZ
289  // just below?
290  }
291 
292  //----------------------------------------------------------------------
293  Spectrum::Spectrum(const std::string& xLabel,
294  const std::string& yLabel,
295  const std::string& zLabel,
296  SpectrumLoaderBase& loader,
297  const Binning& binsx, const Var& varx,
298  const Binning& binsy, const Var& vary,
299  const Binning& binsz, const Var& varz,
300  const SpillCut& spillcut,
301  const Cut& cut,
302  const SystShifts& shift,
303  const Var& wei,
304  ESparse sparse)
305  : Spectrum({xLabel, yLabel, zLabel}, {binsx, binsy, binsz}, sparse)
306  {
307  Var multiDVar = Var3D(varx, binsx, vary, binsy, varz, binsz);
308 
309  loader.AddSpectrum(*this, multiDVar, spillcut, cut, shift, wei);
310  }
311 
312  //----------------------------------------------------------------------
313  Spectrum::Spectrum(SpectrumLoaderBase& loader,
314  const HistAxis& xAxis,
315  const HistAxis& yAxis,
316  const HistAxis& zAxis,
317  const SpillCut& spillcut,
318  const Cut& cut,
319  const SystShifts& shift,
320  const Var& wei,
321  ESparse sparse)
322  : Spectrum(xAxis.GetLabels()[0], loader,
323  xAxis.GetBinnings()[0], xAxis.GetVars()[0],
324  yAxis.GetBinnings()[0], yAxis.GetVars()[0],
325  zAxis.GetBinnings()[0], zAxis.GetVars()[0],
326  spillcut, cut, shift, wei, sparse)
327  {
328  // TODO - do we want to keep this variant around?
329  assert(xAxis.NDimensions() == 1);
330  assert(yAxis.NDimensions() == 1);
331  assert(zAxis.NDimensions() == 1);
332  }
333 
334  //----------------------------------------------------------------------
336  {
337  if(fHist && fHist->GetDirectory()){
338  static bool once = true;
339  if(once){
340  once = false;
341  std::cerr << "Spectrum's fHist (" << fHist << ") is associated with a directory (" << fHist->GetDirectory() << ". How did that happen?" << std::endl;
342  }
343  }
344 
345  for (SpectrumLoaderBase* loader : fLoaderCount)
346  { loader->RemoveSpectrum(this); }
347 
349 
350  delete fHistSparse;
351  }
352 
353  //----------------------------------------------------------------------
354  Spectrum::Spectrum(const Spectrum& rhs):
355  fHist(0),
356  fHistSparse(0),
357  fPOT(rhs.fPOT),
358  fLivetime(rhs.fLivetime),
359  fLabels(rhs.fLabels),
360  fBins(rhs.fBins)
361  {
362  DontAddDirectory guard;
363 
364  assert(rhs.fHist || rhs.fHistSparse);
365  if(rhs.fHist)
366  fHist = HistCache::Copy(rhs.fHist);
367  if(rhs.fHistSparse){
368  // Doesn't exist?
369  // fHistSparse = new THnSparseD(*rhs.fHistSparse);
370  fHistSparse = (THnSparseD*)rhs.fHistSparse->Clone();
371  }
372 
373  assert( rhs.fLoaderCount.empty() ); // Copying with pending loads is unexpected
374  }
375 
376  //----------------------------------------------------------------------
377  Spectrum::Spectrum(Spectrum&& rhs):
378  fHist(0),
379  fHistSparse(0),
380  fPOT(rhs.fPOT),
381  fLivetime(rhs.fLivetime),
382  fLabels(rhs.fLabels),
383  fBins(rhs.fBins)
384  {
385  assert(rhs.fHist || rhs.fHistSparse);
386 
387  if(rhs.fHist){
388  fHist = rhs.fHist;
389  rhs.fHist = 0;
390  }
391  if(rhs.fHistSparse){
392  fHistSparse = rhs.fHistSparse;
393  rhs.fHistSparse = 0;
394  }
395 
396  assert( rhs.fLoaderCount.empty() ); // Copying with pending loads is unexpected
397  }
398 
399  //----------------------------------------------------------------------
400  Spectrum& Spectrum::operator=(const Spectrum& rhs)
401  {
402  if(this == &rhs) return *this;
403 
404  DontAddDirectory guard;
405 
407  delete fHistSparse;
408 
409  assert(rhs.fHist || rhs.fHistSparse);
410 
411  if(rhs.fHist){
412  fHist = HistCache::Copy(rhs.fHist);
413  fHistSparse = 0;
414  }
415 
416  if(rhs.fHistSparse){
417  fHistSparse = (THnSparseD*)rhs.fHistSparse->Clone();
418  fHist = 0;
419  }
420 
421  fPOT = rhs.fPOT;
422  fLivetime = rhs.fLivetime;
423  fLabels = rhs.fLabels;
424  fBins = rhs.fBins;
425 
426  assert( fLoaderCount.empty() ); // Copying with pending loads is unexpected
427 
428  return *this;
429  }
430 
431  //----------------------------------------------------------------------
432  Spectrum& Spectrum::operator=(Spectrum&& rhs)
433  {
434  if(this == &rhs) return *this;
435 
437  delete fHistSparse;
438 
439  assert(rhs.fHist || rhs.fHistSparse);
440 
441  fHist = rhs.fHist;
442  fHistSparse = rhs.fHistSparse;
443 
444  fPOT = rhs.fPOT;
445  fLivetime = rhs.fLivetime;
446  fLabels = rhs.fLabels;
447  fBins = rhs.fBins;
448 
449  rhs.fHist = 0;
450  rhs.fHistSparse = 0;
451 
452  assert( fLoaderCount.empty() ); // Copying with pending loads is unexpected
453 
454  return *this;
455  }
456 
457  //----------------------------------------------------------------------
458  void Spectrum::ConstructHistogram(ESparse sparse)
459  {
460  DontAddDirectory guard;
461 
462  assert(!fHist && !fHistSparse);
463 
464  Binning bins1D = fBins[0];
465  if(fBins.size() > 1){
466  int n = 1;
467  for(const Binning& b: fBins) n *= b.NBins();
468  bins1D = Binning::Simple(n, 0, n);
469  }
470 
471  if(sparse){
472  assert(bins1D.IsSimple());
473  const int nbins = bins1D.NBins();
474  const double xmin = bins1D.Min();
475  const double xmax = bins1D.Max();
476  fHistSparse = new THnSparseD(UniqueName().c_str(), UniqueName().c_str(),
477  1, &nbins, &xmin, &xmax);
478 
479  // Ensure errors get accumulated properly
480  fHistSparse->Sumw2();
481  }
482  else{
483  fHist = HistCache::New("", bins1D);
484 
485  // Ensure errors get accumulated properly
486  fHist->Sumw2();
487  }
488  }
489 
490  //----------------------------------------------------------------------
491  TH1D* Spectrum::ToTH1(double exposure, Color_t col, Style_t style,
492  EExposureType expotype,
493  EBinType bintype) const
494  {
495  // Could have a file temporarily open
496  DontAddDirectory guard;
497 
498  TH1D* ret = 0;
499  if(fHist){
500  ret = HistCache::Copy(fHist);
501  }
502  else{
503  ret = fHistSparse->Projection(0);
504  }
505 
506  if(expotype == kPOT){
507  const double pot = exposure;
508  if(fPOT){
509  ret->Scale(pot/fPOT);
510  }
511  else{
512  // Allow zero POT if there are also zero events
513  if(ret->Integral() > 0){
514  std::cout << "Error: Spectrum with " << ret->Integral()
515  << " entries has zero POT, no way to scale to "
516  << exposure << " POT.";
517  if(fLivetime > 0){
518  std::cout << " Spectrum has " << fLivetime << " seconds livetime. "
519  << "Did you mean to pass kLivetime to ToTH1()?";
520  }
521  std::cout << std::endl;
522  // abort();
523  // fPOT = 1e18;
524  ret->Scale(pot/1e18); //hack while we add spill tree
525  }
526  }
527  }
528  if(expotype == kLivetime){
529  const double livetime = exposure;
530  if(fLivetime){
531  ret->Scale(livetime/fLivetime);
532  }
533  else{
534  // Allow zero exposure if there are also zero events
535  if(ret->Integral() > 0){
536  std::cout << "Error: Spectrum with " << ret->Integral()
537  << " entries has zero livetime, no way to scale to "
538  << livetime << " seconds.";
539  if(fPOT > 0){
540  std::cout << " Spectrum has " << fPOT << " POT. "
541  << "Did you mean to pass kPOT to ToTH1()?";
542  }
543  std::cout << std::endl;
544  abort();
545  }
546  }
547  }
548 
549  std::string label;
550  for(const std::string& l: fLabels) label += l + " and ";
551  label.resize(label.size()-5); // drop the last "and"
552  ret->GetXaxis()->SetTitle(label.c_str());
553 
554  ret->GetYaxis()->SetTitle("Events");
555 
556 
557  ret->SetLineColor(col);
558  ret->SetMarkerColor(col);
559  ret->SetLineStyle(style);
560 
561  if(bintype == kBinDensity) ret->Scale(1, "width");
562 
563  // Allow GetMean() and friends to work even if this histogram never had any
564  // explicit Fill() calls made.
565  if(ret->GetEntries() == 0) ret->SetEntries(1);
566 
567  return ret;
568  }
569 
570  //----------------------------------------------------------------------
571  TH2* Spectrum::ToTH2(double exposure, EExposureType expotype, EBinType bintype) const
572  {
573  if(fBins.size() != 2){
574  std::cout << "Error: This Spectrum does not appear to be 2D." << std::endl;
575  abort();
576  }
577 
578  TH2* ret = ana::ToTH2(*this, exposure, expotype, fBins[0], fBins[1]);
579 
580  ret->GetXaxis()->SetTitle(fLabels[0].c_str());
581  ret->GetYaxis()->SetTitle(fLabels[1].c_str());
582 
583  if(bintype == kBinDensity) ret->Scale(1, "width");
584 
585  // Allow GetMean() and friends to work even if this histogram never had any
586  // explicit Fill() calls made.
587  if(ret->GetEntries() == 0) ret->SetEntries(1);
588 
589  return ret;
590  }
591 
592  //----------------------------------------------------------------------
593  TH2* Spectrum::ToTH2NormX(double exposure, EExposureType expotype) const
594  {
595  TH2* xyhist = ToTH2(exposure, expotype);
596  if(!xyhist) return nullptr;
597 
598  const int nbinsx = fBins[0].NBins();
599  const int nbinsy = fBins[1].NBins();
600 
601  // Normalize 2D histogram to X-axis spectrum
602  for(int i=1; i<=nbinsx; ++i){
603  double norm = 0.0;
604  for(int j=1; j<=nbinsy; ++j){
605  norm += xyhist->GetBinContent(i, j);
606  }
607  /// If no entries in the column, skip normalization
608  if(norm < 0.0000001) continue;
609 
610  norm = 1.0 / norm;
611  for(int j=1; j<=nbinsy; ++j){
612  xyhist->SetBinContent(i,j, xyhist->GetBinContent(i, j) * norm);
613  }
614  }
615 
616  // Allow GetMean() and friends to work even if this histogram never had any
617  // explicit Fill() calls made.
618  if(xyhist->GetEntries() == 0) xyhist->SetEntries(1);
619 
620  return xyhist;
621  }
622 
623  //----------------------------------------------------------------------
624  TH3* Spectrum::ToTH3(double exposure, EExposureType expotype, EBinType bintype) const
625  {
626  if(fBins.size() != 3){
627  std::cout << "Error: This Spectrum does not appear to be 3D." << std::endl;
628  abort();
629  }
630 
631  TH3* ret = ana::ToTH3(*this, exposure, expotype,
632  fBins[0], fBins[1], fBins[2]);
633 
634  ret->GetXaxis()->SetTitle(fLabels[0].c_str());
635  ret->GetYaxis()->SetTitle(fLabels[1].c_str());
636  ret->GetZaxis()->SetTitle(fLabels[2].c_str());
637 
638  if(bintype == kBinDensity) ret->Scale(1, "width");
639 
640  // Allow GetMean() and friends to work even if this histogram never had any
641  // explicit Fill() calls made.
642  if(ret->GetEntries() == 0) ret->SetEntries(1);
643 
644  return ret;
645  }
646 
647  //----------------------------------------------------------------------
648  TH1* Spectrum::ToTHX(double exposure, bool force1D, EExposureType expotype) const
649  {
650  if (force1D) return this->ToTH1(exposure, expotype);
651  switch(fBins.size()){
652  case 1:
653  return this->ToTH1(exposure, expotype);
654  case 2:
655  return this->ToTH2(exposure, expotype);
656  case 3:
657  return this->ToTH3(exposure, expotype);
658  default:
659  std::cout << "Error: unable to hande number of dimensions (" << fBins.size() << ")" << std::endl;
660  abort();
661  }
662 
663  return NULL;
664  }
665 
666 
667  //----------------------------------------------------------------------
668  void Spectrum::Scale(double c)
669  {
670  fHist->Scale(c);
671  }
672 
673  //----------------------------------------------------------------------
674  double Spectrum::Integral(double exposure, double* err,
675  EExposureType expotype) const
676  {
677  const double ratio = (expotype == kPOT) ? exposure/fPOT : exposure/fLivetime;
678 
679  if(err){
680  *err = 0;
681 
682  for(int i = 0; i < fHist->GetNbinsX()+2; ++i){
683  *err += util::sqr(fHist->GetBinError(i));
684  }
685  *err = sqrt(*err) * ratio;
686  }
687 
688  // TODO how to integrate fHistSparse?
689 
690  return fHist->Integral(0, -1) * ratio;
691  }
692 
693  //----------------------------------------------------------------------
694  double Spectrum::Mean() const
695  {
696  // Allow GetMean() to work even if this histogram never had any explicit
697  // Fill() calls made.
698  if(fHist->GetEntries() == 0) fHist->SetEntries(1);
699  return fHist->GetMean();
700  }
701 
702  //----------------------------------------------------------------------
703  void Spectrum::Fill(double x, double w)
704  {
705  assert( (fHist || fHistSparse) && "Somehow both fHist and fHistSparse are null in Spectrum::Fill" );
706 
707  if(fHist)
708  fHist->Fill(x, w);
709  else if (fHistSparse)
710  fHistSparse->Fill(&x, w);
711  }
712 
713  //----------------------------------------------------------------------
714  Spectrum Spectrum::MockData(double pot, bool makethrow, int seed) const
715  {
716  Spectrum ret = FakeData(pot);
717 
718  if (!makethrow) return ret;
719 
720  TRandom3 rnd(seed); // zero seeds randomly
721 
722  if(ret.fHist){
723  for(int i = 0; i < ret.fHist->GetNbinsX()+2; ++i){
724  ret.fHist->SetBinContent(i, rnd.Poisson(ret.fHist->GetBinContent(i)));
725  }
726  }
727  if(ret.fHistSparse){
728  for(int i = 0; i < ret.fHistSparse->GetNbins(); ++i)
729  ret.fHistSparse->SetBinContent(i, rnd.Poisson(ret.fHistSparse->GetBinContent(i)));
730  }
731 
732  // Drop old errors, which are based on the MC statistics, and create new
733  // ones that are based on the prediction for the data
734  if(ret.fHist){
735  ret.fHist->Sumw2(false);
736  ret.fHist->Sumw2();
737  }
738 
739  return ret;
740  }
741 
742  //----------------------------------------------------------------------
743  Spectrum Spectrum::FakeData(double pot) const
744  {
745  Spectrum ret = *this;
746  if(fPOT > 0){
747  if(ret.fHist)
748  ret.fHist->Scale(pot/fPOT);
749  if(ret.fHistSparse)
750  ret.fHistSparse->Scale(pot/fPOT);
751  }
752  if(fLivetime > 0) ret.fLivetime *= pot/fPOT;
753  ret.fPOT = pot;
754 
755  // Drop old errors, which are based on the MC statistics, and create new
756  // ones that are based on the prediction for the data
757  if(ret.fHist){
758  ret.fHist->Sumw2(false);
759  ret.fHist->Sumw2();
760  }
761 
762  return ret;
763  }
764 
765  //----------------------------------------------------------------------
766  void Spectrum::Clear()
767  {
768  fPOT = fLivetime = 0;
769  if(fHist) fHist->Reset();
770  if(fHistSparse) fHistSparse->Reset();
771  }
772 
773  //----------------------------------------------------------------------
774  void Spectrum::RemoveLoader(SpectrumLoaderBase* p)
775  { fLoaderCount.erase(p); }
776 
777  //----------------------------------------------------------------------
778  void Spectrum::AddLoader(SpectrumLoaderBase* p)
779  { fLoaderCount.insert(p); }
780 
781  //----------------------------------------------------------------------
782  Spectrum& Spectrum::PlusEqualsHelper(const Spectrum& rhs, int sign)
783  {
784  // In this case it would be OK to have no POT/livetime
785  if(rhs.fHist && rhs.fHist->Integral(0, -1) == 0) return *this;
786 
787  // Empty RHS -> do nothing
788  if(rhs.fPOT == 0 && rhs.fLivetime == 0) return *this;
789 
790  // Empty LHS -> copy RHS (possibly with sign flip)
791  if(fPOT == 0 && fLivetime == 0){
792  if(rhs.fHist) fHist->Add(rhs.fHist, sign);
793  if(rhs.fHistSparse) fHistSparse->Add(rhs.fHistSparse, sign);
794  fPOT = rhs.fPOT;
795  fLivetime = rhs.fLivetime;
796  return *this;
797  }
798 
799  if(!fLivetime && !rhs.fPOT){
800  std::cout << "Error: can't sum Spectrum with POT ("
801  << fPOT << ") but no livetime and Spectrum with livetime ("
802  << rhs.fLivetime << " sec) but no POT." << std::endl;
803  abort();
804  }
805 
806  if(!fPOT && !rhs.fLivetime){
807  std::cout << "Error: can't sum Spectrum with livetime ("
808  << fLivetime << " sec) but no POT and Spectrum with POT ("
809  << rhs.fPOT << ") but no livetime." << std::endl;
810  abort();
811  }
812 
813  // And now there are still a bunch of good cases to consider
814 
815  if(fPOT && rhs.fPOT){
816  // Scale by POT when possible
817  if(rhs.fHist) fHist->Add(rhs.fHist, sign*fPOT/rhs.fPOT);
818  if(rhs.fHistSparse) fHistSparse->Add(rhs.fHistSparse, sign*fPOT/rhs.fPOT);
819 
820  if(fLivetime && rhs.fLivetime){
821  // If POT/livetime ratios match, keep regular lifetime, otherwise zero
822  // it out.
823  if(!AlmostEqual(fLivetime*rhs.fPOT, rhs.fLivetime*fPOT)){
824  std::cout << "Attempting to combine two spectra with incompatible POT / livetime ratio " << fPOT << " / " << fLivetime << " vs " << rhs.fPOT << " / " << rhs.fLivetime << std::endl;
825  abort();
826  }
827  }
828  if(!fLivetime && rhs.fLivetime){
829  // If the RHS has a livetime and we don't, copy it in (suitably scaled)
830  fLivetime = rhs.fLivetime * fPOT/rhs.fPOT;
831  }
832  // Otherwise, keep our own livetime (if any)
833 
834  return *this;
835  }
836 
837  if(fLivetime && rhs.fLivetime){
838  // Scale by livetime, the only thing in common
839  if(rhs.fHist) fHist->Add(rhs.fHist, sign*fLivetime/rhs.fLivetime);
840  if(rhs.fHistSparse) fHistSparse->Add(rhs.fHistSparse, sign*fLivetime/rhs.fLivetime);
841 
842  if(!fPOT && rhs.fPOT){
843  // If the RHS has a POT and we don't, copy it in (suitably scaled)
844  fPOT = rhs.fPOT * fLivetime/rhs.fLivetime;
845  }
846  // Otherwise, keep our own POT (if any)
847 
848  return *this;
849  }
850 
851  // That should have been all the cases. I definitely want to know what
852  // happened if it wasn't.
853  std::cout << "Spectrum::operator+=(). How did we get here? "
854  << fPOT << " " << fLivetime << " "
855  << rhs.fPOT << " " << rhs.fLivetime << std::endl;
856  abort();
857  }
858 
859  //----------------------------------------------------------------------
860  Spectrum& Spectrum::operator+=(const Spectrum& rhs)
861  {
862  return PlusEqualsHelper(rhs, +1);
863  }
864 
865  //----------------------------------------------------------------------
866  Spectrum Spectrum::operator+(const Spectrum& rhs) const
867  {
868  Spectrum ret = *this;
869  ret += rhs;
870  return ret;
871  }
872 
873  //----------------------------------------------------------------------
874  Spectrum& Spectrum::operator-=(const Spectrum& rhs)
875  {
876  return PlusEqualsHelper(rhs, -1);
877  }
878 
879  //----------------------------------------------------------------------
880  Spectrum Spectrum::operator-(const Spectrum& rhs) const
881  {
882  Spectrum ret = *this;
883  ret -= rhs;
884  return ret;
885  }
886 
887  //----------------------------------------------------------------------
888  Spectrum& Spectrum::operator*=(const Ratio& rhs)
889  {
890  fHist->Multiply(rhs.fHist);
891  return *this;
892  }
893 
894  //----------------------------------------------------------------------
895  Spectrum Spectrum::operator*(const Ratio& rhs) const
896  {
897  Spectrum ret = *this;
898  ret *= rhs;
899  return ret;
900  }
901 
902  //----------------------------------------------------------------------
903  Spectrum& Spectrum::operator/=(const Ratio& rhs)
904  {
905  fHist->Divide(rhs.fHist);
906  return *this;
907  }
908 
909  //----------------------------------------------------------------------
910  Spectrum Spectrum::operator/(const Ratio& rhs) const
911  {
912  Spectrum ret = *this;
913  ret /= rhs;
914  return ret;
915  }
916 
917  //----------------------------------------------------------------------
918  void Spectrum::SaveTo(TDirectory* dir) const
919  {
920  TDirectory* tmp = gDirectory;
921  dir->cd();
922 
923  TObjString("Spectrum").Write("type");
924 
925  if(fHist) fHist->Write("hist");
926  if(fHistSparse) fHistSparse->Write("hist_sparse");
927  TH1D hPot("", "", 1, 0, 1);
928  hPot.Fill(.5, fPOT);
929  hPot.Write("pot");
930  TH1D hLivetime("", "", 1, 0, 1);
931  hLivetime.Fill(.5, fLivetime);
932  hLivetime.Write("livetime");
933 
934  for(unsigned int i = 0; i < fBins.size(); ++i){
935  TObjString(fLabels[i].c_str()).Write(TString::Format("label%d", i).Data());
936  fBins[i].SaveTo(dir->mkdir(TString::Format("bins%d", i)));
937  }
938 
939  tmp->cd();
940  }
941 
942  //----------------------------------------------------------------------
943  std::unique_ptr<Spectrum> Spectrum::LoadFrom(TDirectory* dir)
944  {
945  DontAddDirectory guard;
946 
947  TObjString* tag = (TObjString*)dir->Get("type");
948  assert(tag);
949  assert(tag->GetString() == "Spectrum");
950  delete tag;
951 
952  TH1D* spect = (TH1D*)dir->Get("hist");
953  THnSparseD* spectSparse = (THnSparseD*)dir->Get("hist_sparse");
954  assert(spect || spectSparse);
955  TH1* hPot = (TH1*)dir->Get("pot");
956  assert(hPot);
957  TH1* hLivetime = (TH1*)dir->Get("livetime");
958  assert(hLivetime);
959 
960  std::vector<std::string> labels;
961  std::vector<Binning> bins;
962  for(int i = 0; ; ++i){
963  TDirectory* subdir = dir->GetDirectory(TString::Format("bins%d", i));
964  if(!subdir) break;
965  bins.push_back(*Binning::LoadFrom(subdir));
966  TObjString* label = (TObjString*)dir->Get(TString::Format("label%d", i));
967  labels.push_back(label ? label->GetString().Data() : "");
968  delete subdir;
969  delete label;
970  }
971 
972  if(bins.empty() && labels.empty()){
973  // Must be an old file. Make an attempt at backwards compatibility.
974  if(spect){
975  bins.push_back(Binning::FromTAxis(spect->GetXaxis()));
976  labels.push_back(spect->GetXaxis()->GetTitle());
977  }
978  else{
979  bins.push_back(Binning::FromTAxis(spectSparse->GetAxis(0)));
980  labels.push_back(spectSparse->GetAxis(0)->GetTitle());
981  }
982  }
983 
984  std::unique_ptr<Spectrum> ret;
985  if(spect){
986  ret = std::make_unique<Spectrum>(std::unique_ptr<TH1D>(spect), labels, bins, hPot->GetBinContent(1), hLivetime->GetBinContent(1));
987  }
988  else{
989  ret = std::make_unique<Spectrum>((TH1*)0, labels, bins, hPot->GetBinContent(1), hLivetime->GetBinContent(1));
990  ret->fHistSparse = spectSparse;
991  }
992 
993  delete hPot;
994  delete hLivetime;
995 
996  return ret;
997  }
998 }
Spectrum & operator-=(const Spectrum &rhs)
TH1D * ToTH1(double exposure, Color_t col=kBlack, Style_t style=kSolid, EExposureType expotype=kPOT, EBinType bintype=kBinContent) const
Histogram made from this Spectrum, scaled to some exposure.
* labels
_HistAxis< Var > HistAxis
Definition: HistAxis.h:62
Spectrum operator*(const Ratio &rhs) const
Represent the binning of a Spectrum&#39;s x-axis.
Definition: Binning.h:18
static std::unique_ptr< Spectrum > LoadFrom(TDirectory *dir)
friend class SpectrumLoaderBase
Definition: Spectrum.h:33
process_name opflash particleana ie x
static TH1D * Copy(const TH1D *h)
Definition: HistCache.cxx:76
BEGIN_PROLOG could also be cerr
tuple loader
Definition: demo.py:7
Simple record of shifts applied to systematic parameters.
Definition: SystShifts.h:16
TH3 * ToTH3(double exposure, EExposureType expotype=kPOT, EBinType bintype=kBinContent) const
Spectrum must be 3D to obtain TH3.
static Binning FromTAxis(const TAxis *ax)
Definition: Binning.cxx:122
EResult err(const char *call)
_Var< T > Var2D(const _Var< T > &a, const Binning &binsa, const _Var< T > &b, const Binning &binsb)
Variable formed from two input variables.
Definition: Var.cxx:109
pdgs p
Definition: selectors.fcl:22
Divide bin contents by bin widths.
Spectrum & PlusEqualsHelper(const Spectrum &rhs, int sign)
Helper for operator+= and operator-=.
TH2 * ToTH2NormX(double exposure, EExposureType expotype=kPOT) const
Spectrum must be 2D to obtain TH2. Normalized to X axis.
void AddLoader(SpectrumLoaderBase *)
void ConstructHistogram(ESparse sparse=kDense)
double fPOT
Definition: Spectrum.h:342
void Fill(double x, double w=1)
def style
Definition: util.py:237
process_name opflashCryoW ana
double Integral(double exposure, double *err=0, EExposureType expotype=kPOT) const
Return total number of events scaled to pot.
shift
Definition: fcl_checks.sh:26
T sqr(T x)
More efficient square function than pow(x,2)
Definition: MathUtil.h:23
Spectrum & operator=(const Spectrum &rhs)
void Scale(double c)
Multiply this spectrum by a constant c.
_Var< caf::SRSliceProxy > Var
Representation of a variable to be retrieved from a caf::StandardRecord object.
Definition: Var.h:73
_Var< T > Var3D(const _Var< T > &a, const Binning &binsa, const _Var< T > &b, const Binning &binsb, const _Var< T > &c, const Binning &binsc)
This is just like a Var2D, but useful for 3D Spectra.
Definition: Var.cxx:133
Representation of a spectrum in any variable, with associated POT.
Definition: Spectrum.h:30
process_name pandoraGausCryo1 vertexChargeCryo1 vertexStubCryo1 xmin
while getopts h
std::vector< std::string > fLabels
Definition: Spectrum.h:348
std::set< SpectrumLoaderBase * > fLoaderCount
This count is maintained by SpectrumLoader, as a sanity check.
Definition: Spectrum.h:346
_Var< caf::SRSpillProxy > SpillVar
Equivalent of Var acting on caf::SRSpill.
Definition: Var.h:76
unsigned int NDimensions() const
Definition: HistAxis.h:46
Spectrum FakeData(double pot) const
Fake data is a MC spectrum scaled to the POT expected in the data.
Spectrum operator/(const Ratio &rhs) const
_Cut< caf::SRSliceProxy > Cut
Definition: Cut.h:95
static void Delete(TH1D *&h)
Definition: HistCache.cxx:92
EExposureType
For use as an argument to Spectrum::ToTH1.
_MultiVar< caf::SRSpillProxy > SpillMultiVar
Definition: MultiVar.h:49
TH1 * ToTHX(double exposure, bool force1D=false, EExposureType expotype=kPOT) const
Function decides what is the appropriate projection based on fBins, and does that.
Spectrum & operator+=(const Spectrum &rhs)
double fLivetime
Definition: Spectrum.h:343
unsigned int seed
bool AlmostEqual(double a, double b)
TH1D * fHist
Definition: Spectrum.h:340
_MultiVar< caf::SRSliceProxy > MultiVar
Definition: MultiVar.h:48
fBins({binsX, binsY})
virtual void AddSpectrum(Spectrum &spect, const Var &var, const SpillCut &spillcut, const Cut &cut, const SystShifts &shift, const Var &wei=kUnweighted)
For use by the Spectrum constructor.
void RemoveLoader(SpectrumLoaderBase *)
_Cut< caf::SRSpillProxy > SpillCut
Equivalent of Cut acting on caf::SRSpill. For use in spill-by-spill data quality cuts.
Definition: Cut.h:99
THnSparseD * fHistSparse
Definition: Spectrum.h:341
TH2 * ToTH2(const Spectrum &s, double exposure, ana::EExposureType expotype, const Binning &binsx, const Binning &binsy, ana::EBinType bintype)
auto norm(Vector const &v)
Return norm of the specified vector.
tuple dir
Definition: dropbox.py:28
Base class for the various types of spectrum loader.
T GetMultiDVar() const
Definition: HistAxis.cxx:66
int sign(double val)
Definition: UtilFunc.cxx:104
Spectrum(const std::string &label, const Binning &bins, SpectrumLoaderBase &loader, const Var &var, const SpillCut &spillcut, const Cut &cut, const SystShifts &shift=kNoShift, const Var &wei=kUnweighted)
Definition: Spectrum.cxx:43
Spectrum operator+(const Spectrum &rhs) const
TH2 * ToTH2(double exposure, EExposureType expotype=kPOT, EBinType bintype=kBinContent) const
Spectrum must be 2D to obtain TH2.
std::vector< Binning > fBins
Definition: Spectrum.h:349
_MultiVar< T > MultiVar2D(const _MultiVar< T > &a, const Binning &binsa, const _MultiVar< T > &b, const Binning &binsb)
Definition: MultiVar.cxx:69
Spectrum & operator/=(const Ratio &rhs)
static TH1D * New(const std::string &title, const Binning &bins)
Definition: HistCache.cxx:21
Spectrum MockData(double pot, bool makethrow=true, int seed=0) const
Mock data is FakeData with Poisson fluctuations applied.
Prevent histograms being added to the current directory.
virtual ~Spectrum()
TH3 * ToTH3(const Spectrum &s, double exposure, ana::EExposureType expotype, const Binning &binsx, const Binning &binsy, const Binning &binsz, ana::EBinType bintype)
static Binning Simple(int n, double lo, double hi, const std::vector< std::string > &labels={})
Definition: Binning.cxx:38
static std::unique_ptr< Binning > LoadFrom(TDirectory *dir)
Definition: Binning.cxx:229
Spectrum operator-(const Spectrum &rhs) const
std::string UniqueName()
Return a different string each time, for creating histograms.
BEGIN_PROLOG could also be cout
Spectrum & operator*=(const Ratio &rhs)
void SaveTo(TDirectory *dir) const
double Mean() const
Return mean of 1D histogram.