8 #include "TDirectory.h"
11 #include "THnSparse.h"
12 #include "TObjString.h"
23 const std::vector<Binning>& bins,
25 : fHist(0), fHistSparse(0), fPOT(0), fLivetime(0),
26 fLabels(labels),
fBins(bins)
36 : fHist(0), fHistSparse(0), fPOT(0), fLivetime(0),
37 fLabels(1, label),
fBins(1, bins)
52 loader.
AddSpectrum(*
this, var, spillcut, cut, shift, wei);
76 loader.
AddSpectrum(*
this, var, spillcut, cut, shift, wei);
97 :
Spectrum(axis.GetLabels(), axis.GetBinnings())
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)
125 const TString className = h->ClassName();
127 if(className ==
"TH1D"){
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)
154 :
Spectrum(label,
"", loader, binsx, varx, binsy, vary, spillcut, cut, shift, wei)
165 :
Spectrum(label,
"", loader, binsx, varx, binsy, vary, spillcut, wei)
178 :
Spectrum(label,
"", loader, binsx, varx, binsy, vary, spillcut, cut, shift, wei)
189 :
Spectrum(label,
"", loader, binsx, varx, binsy, vary, spillcut, 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)
214 const std::string& yLabel,
222 :
Spectrum({xLabel, yLabel}, {binsx, binsy})
224 Var multiDVar =
Var2D(varx, binsx, vary, binsy);
226 loader.AddSpectrum(*
this, multiDVar, spillcut, cut,
shift, wei);
231 const std::string& yLabel,
232 SpectrumLoaderBase&
loader,
233 const Binning& binsx,
const SpillVar& varx,
234 const Binning& binsy,
const SpillVar& vary,
237 : Spectrum({xLabel, yLabel}, {binsx, binsy})
241 loader.AddSpectrum(*
this, multiDVar, spillcut, wei);
246 const std::string& yLabel,
247 SpectrumLoaderBase&
loader,
248 const Binning& binsx,
const MultiVar& varx,
249 const Binning& binsy,
const MultiVar& vary,
252 const SystShifts&
shift,
254 : Spectrum({xLabel, yLabel}, {binsx, binsy})
258 loader.AddSpectrum(*
this, multiDVar, spillcut, cut,
shift, wei);
263 const std::string& yLabel,
264 SpectrumLoaderBase&
loader,
269 : Spectrum({xLabel, yLabel}, {binsx, binsy})
273 loader.AddSpectrum(*
this, multiDVar, spillcut, wei);
278 const Binning& binsx,
const Var& varx,
279 const Binning& binsy,
const Var& vary,
280 const Binning& binsz,
const Var& varz,
283 const SystShifts&
shift,
286 : Spectrum(label,
"",
"", loader, binsx, varx, binsy, vary, binsz, varz, spillcut, cut, shift, wei, sparse)
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,
302 const SystShifts&
shift,
305 : Spectrum({xLabel, yLabel, zLabel}, {binsx, binsy, binsz}, sparse)
307 Var multiDVar =
Var3D(varx, binsx, vary, binsy, varz, binsz);
309 loader.AddSpectrum(*
this, multiDVar, spillcut, cut,
shift, wei);
319 const SystShifts&
shift,
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)
329 assert(xAxis.NDimensions() == 1);
330 assert(yAxis.NDimensions() == 1);
331 assert(zAxis.NDimensions() == 1);
338 static bool once =
true;
341 std::cerr <<
"Spectrum's fHist (" <<
fHist <<
") is associated with a directory (" <<
fHist->GetDirectory() <<
". How did that happen?" << std::endl;
346 { loader->RemoveSpectrum(
this); }
358 fLivetime(rhs.fLivetime),
359 fLabels(rhs.fLabels),
362 DontAddDirectory guard;
364 assert(rhs.fHist || rhs.fHistSparse);
370 fHistSparse = (THnSparseD*)rhs.fHistSparse->Clone();
373 assert( rhs.fLoaderCount.empty() );
381 fLivetime(rhs.fLivetime),
382 fLabels(rhs.fLabels),
385 assert(rhs.fHist || rhs.fHistSparse);
396 assert( rhs.fLoaderCount.empty() );
402 if(
this == &rhs)
return *
this;
404 DontAddDirectory guard;
409 assert(rhs.fHist || rhs.fHistSparse);
417 fHistSparse = (THnSparseD*)rhs.fHistSparse->Clone();
426 assert( fLoaderCount.empty() );
434 if(
this == &rhs)
return *
this;
439 assert(rhs.fHist || rhs.fHistSparse);
452 assert( fLoaderCount.empty() );
460 DontAddDirectory guard;
464 Binning bins1D =
fBins[0];
465 if(
fBins.size() > 1){
467 for(
const Binning& b:
fBins) n *= b.NBins();
472 assert(bins1D.IsSimple());
473 const int nbins = bins1D.NBins();
474 const double xmin = bins1D.Min();
475 const double xmax = bins1D.Max();
477 1, &nbins, &xmin, &xmax);
496 DontAddDirectory guard;
506 if(expotype ==
kPOT){
507 const double pot = exposure;
509 ret->Scale(pot/
fPOT);
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.";
519 <<
"Did you mean to pass kLivetime to ToTH1()?";
524 ret->Scale(pot/1e18);
529 const double livetime = exposure;
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.";
541 <<
"Did you mean to pass kPOT to ToTH1()?";
550 for(
const std::string& l:
fLabels) label += l +
" and ";
551 label.resize(label.size()-5);
552 ret->GetXaxis()->SetTitle(label.c_str());
554 ret->GetYaxis()->SetTitle(
"Events");
557 ret->SetLineColor(col);
558 ret->SetMarkerColor(col);
559 ret->SetLineStyle(style);
565 if(ret->GetEntries() == 0) ret->SetEntries(1);
573 if(fBins.size() != 2){
574 std::cout <<
"Error: This Spectrum does not appear to be 2D." << std::endl;
578 TH2* ret =
ana::ToTH2(*
this, exposure, expotype, fBins[0], fBins[1]);
580 ret->GetXaxis()->SetTitle(fLabels[0].c_str());
581 ret->GetYaxis()->SetTitle(fLabels[1].c_str());
587 if(ret->GetEntries() == 0) ret->SetEntries(1);
595 TH2* xyhist =
ToTH2(exposure, expotype);
596 if(!xyhist)
return nullptr;
598 const int nbinsx = fBins[0].NBins();
599 const int nbinsy = fBins[1].NBins();
602 for(
int i=1; i<=nbinsx; ++i){
604 for(
int j=1; j<=nbinsy; ++j){
605 norm += xyhist->GetBinContent(i, j);
608 if(norm < 0.0000001)
continue;
611 for(
int j=1; j<=nbinsy; ++j){
612 xyhist->SetBinContent(i,j, xyhist->GetBinContent(i, j) *
norm);
618 if(xyhist->GetEntries() == 0) xyhist->SetEntries(1);
626 if(fBins.size() != 3){
627 std::cout <<
"Error: This Spectrum does not appear to be 3D." << std::endl;
631 TH3* ret =
ana::ToTH3(*
this, exposure, expotype,
632 fBins[0], fBins[1], fBins[2]);
634 ret->GetXaxis()->SetTitle(fLabels[0].c_str());
635 ret->GetYaxis()->SetTitle(fLabels[1].c_str());
636 ret->GetZaxis()->SetTitle(fLabels[2].c_str());
642 if(ret->GetEntries() == 0) ret->SetEntries(1);
650 if (force1D)
return this->
ToTH1(exposure, expotype);
651 switch(fBins.size()){
653 return this->
ToTH1(exposure, expotype);
655 return this->
ToTH2(exposure, expotype);
657 return this->
ToTH3(exposure, expotype);
659 std::cout <<
"Error: unable to hande number of dimensions (" << fBins.size() <<
")" << std::endl;
682 for(
int i = 0; i <
fHist->GetNbinsX()+2; ++i){
685 *err = sqrt(*err) * ratio;
690 return fHist->Integral(0, -1) * ratio;
698 if(
fHist->GetEntries() == 0)
fHist->SetEntries(1);
699 return fHist->GetMean();
705 assert( (
fHist ||
fHistSparse) &&
"Somehow both fHist and fHistSparse are null in Spectrum::Fill" );
718 if (!makethrow)
return ret;
723 for(
int i = 0; i < ret.fHist->GetNbinsX()+2; ++i){
724 ret.fHist->SetBinContent(i, rnd.Poisson(ret.fHist->GetBinContent(i)));
728 for(
int i = 0; i < ret.fHistSparse->GetNbins(); ++i)
729 ret.fHistSparse->SetBinContent(i, rnd.Poisson(ret.fHistSparse->GetBinContent(i)));
735 ret.fHist->Sumw2(
false);
748 ret.fHist->Scale(pot/
fPOT);
750 ret.fHistSparse->Scale(pot/
fPOT);
758 ret.fHist->Sumw2(
false);
775 { fLoaderCount.erase(p); }
779 { fLoaderCount.insert(p); }
785 if(rhs.fHist && rhs.fHist->Integral(0, -1) == 0)
return *
this;
788 if(rhs.fPOT == 0 && rhs.fLivetime == 0)
return *
this;
792 if(rhs.fHist)
fHist->Add(rhs.fHist, sign);
793 if(rhs.fHistSparse)
fHistSparse->Add(rhs.fHistSparse, sign);
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;
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;
815 if(
fPOT && rhs.fPOT){
817 if(rhs.fHist)
fHist->Add(rhs.fHist, sign*
fPOT/rhs.fPOT);
818 if(rhs.fHistSparse)
fHistSparse->Add(rhs.fHistSparse, sign*
fPOT/rhs.fPOT);
824 std::cout <<
"Attempting to combine two spectra with incompatible POT / livetime ratio " <<
fPOT <<
" / " <<
fLivetime <<
" vs " << rhs.fPOT <<
" / " << rhs.fLivetime << std::endl;
839 if(rhs.fHist)
fHist->Add(rhs.fHist, sign*
fLivetime/rhs.fLivetime);
842 if(!
fPOT && rhs.fPOT){
853 std::cout <<
"Spectrum::operator+=(). How did we get here? "
855 << rhs.fPOT <<
" " << rhs.fLivetime << std::endl;
890 fHist->Multiply(rhs.fHist);
905 fHist->Divide(rhs.fHist);
920 TDirectory* tmp = gDirectory;
923 TObjString(
"Spectrum").Write(
"type");
927 TH1D hPot(
"",
"", 1, 0, 1);
930 TH1D hLivetime(
"",
"", 1, 0, 1);
932 hLivetime.Write(
"livetime");
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)));
945 DontAddDirectory guard;
947 TObjString* tag = (TObjString*)dir->Get(
"type");
949 assert(tag->GetString() ==
"Spectrum");
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");
957 TH1* hLivetime = (TH1*)dir->Get(
"livetime");
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));
966 TObjString* label = (TObjString*)dir->Get(TString::Format(
"label%d", i));
967 labels.push_back(label ? label->GetString().Data() :
"");
972 if(bins.empty() && labels.empty()){
976 labels.push_back(spect->GetXaxis()->GetTitle());
980 labels.push_back(spectSparse->GetAxis(0)->GetTitle());
984 std::unique_ptr<Spectrum> ret;
986 ret = std::make_unique<Spectrum>(std::unique_ptr<TH1D>(spect), labels, bins, hPot->GetBinContent(1), hLivetime->GetBinContent(1));
989 ret = std::make_unique<Spectrum>((TH1*)0, labels, bins, hPot->GetBinContent(1), hLivetime->GetBinContent(1));
990 ret->fHistSparse = spectSparse;
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.
_HistAxis< Var > HistAxis
Spectrum operator*(const Ratio &rhs) const
Represent the binning of a Spectrum's x-axis.
static std::unique_ptr< Spectrum > LoadFrom(TDirectory *dir)
friend class SpectrumLoaderBase
process_name opflash particleana ie x
static TH1D * Copy(const TH1D *h)
BEGIN_PROLOG could also be cerr
Simple record of shifts applied to systematic parameters.
TH3 * ToTH3(double exposure, EExposureType expotype=kPOT, EBinType bintype=kBinContent) const
Spectrum must be 3D to obtain TH3.
static Binning FromTAxis(const TAxis *ax)
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.
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)
void Fill(double x, double w=1)
process_name opflashCryoW ana
double Integral(double exposure, double *err=0, EExposureType expotype=kPOT) const
Return total number of events scaled to pot.
T sqr(T x)
More efficient square function than pow(x,2)
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.
_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.
Representation of a spectrum in any variable, with associated POT.
process_name pandoraGausCryo1 vertexChargeCryo1 vertexStubCryo1 xmin
std::vector< std::string > fLabels
std::set< SpectrumLoaderBase * > fLoaderCount
This count is maintained by SpectrumLoader, as a sanity check.
_Var< caf::SRSpillProxy > SpillVar
Equivalent of Var acting on caf::SRSpill.
unsigned int NDimensions() const
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
static void Delete(TH1D *&h)
EExposureType
For use as an argument to Spectrum::ToTH1.
_MultiVar< caf::SRSpillProxy > SpillMultiVar
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)
bool AlmostEqual(double a, double b)
_MultiVar< caf::SRSliceProxy > MultiVar
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.
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.
Base class for the various types of spectrum loader.
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)
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
_MultiVar< T > MultiVar2D(const _MultiVar< T > &a, const Binning &binsa, const _MultiVar< T > &b, const Binning &binsb)
Spectrum & operator/=(const Ratio &rhs)
static TH1D * New(const std::string &title, const Binning &bins)
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.
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={})
static std::unique_ptr< Binning > LoadFrom(TDirectory *dir)
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.