8 #include "TDirectory.h"
11 #include "TObjString.h"
18 #include "OscLib/IOscCalc.h"
35 : fOscOrigin(osc ? osc->Copy() : 0),
36 fBinning(0, {}, {}, 0, 0),
39 for(
const ISyst* syst: systs){
41 sp.systName = syst->ShortName();
43 for(
int x = -syst->PredInterpMaxNSigma();
x <= +syst->PredInterpMaxNSigma(); ++
x){
44 sp.shifts.push_back(
x);
47 for(
int sigma: sp.shifts){
50 sp.preds.push_back(predGen.Generate(loaders, shiftHere).release());
53 fPreds.emplace(syst, sp);
56 fPredNom = predGen.Generate(loaders, shiftMC);
72 const std::vector<std::unique_ptr<TH1>>& ratios)
const
74 assert(shifts.size() == ratios.size());
76 std::vector<std::vector<Coeffs>> ret;
78 const int binMax = ratios[0]->GetNbinsX();
81 if(ratios.size() == 2){
82 for(
int binIdx = 0; binIdx < binMax+2; ++binIdx){
84 const double y1 = ratios[0]->GetBinContent(binIdx);
85 const double y2 = ratios[1]->GetBinContent(binIdx);
86 ret.back().emplace_back(0, 0, y2-y1, y1);
91 for(
int binIdx = 0; binIdx < binMax+2; ++binIdx){
106 const double y1 = ratios[0]->GetBinContent(binIdx);
107 const double y2 = ratios[1]->GetBinContent(binIdx);
108 const double y3 = ratios[2]->GetBinContent(binIdx);
109 const double v[3] = {y1, y2, (y3-y1)/2};
110 const double m[9] = { 1, -1, 1,
113 const TVectorD res = TMatrixD(3, 3, m) * TVectorD(3, v);
114 ret.back().emplace_back(0, res(0), res(1), res(2));
118 for(
unsigned int shiftIdx = 1; shiftIdx < ratios.size()-2; ++shiftIdx){
119 const double y0 = ratios[shiftIdx-1]->GetBinContent(binIdx);
120 const double y1 = ratios[shiftIdx ]->GetBinContent(binIdx);
121 const double y2 = ratios[shiftIdx+1]->GetBinContent(binIdx);
122 const double y3 = ratios[shiftIdx+2]->GetBinContent(binIdx);
124 const double v[4] = {y1, y2, (y2-y0)/2, (y3-y1)/2};
125 const double m[16] = { 2, -2, 1, 1,
129 const TVectorD res = TMatrixD(4, 4, m) * TVectorD(4, v);
130 ret.back().emplace_back(res(0), res(1), res(2), res(3));
134 const int N = ratios.size()-3;
135 const double y0 = ratios[
N ]->GetBinContent(binIdx);
136 const double y1 = ratios[N+1]->GetBinContent(binIdx);
137 const double y2 = ratios[N+2]->GetBinContent(binIdx);
138 const double v[3] = {y1, y2, (y2-y0)/2};
139 const double m[9] = {-1, 1, -1,
142 const TVectorD res = TMatrixD(3, 3, m) * TVectorD(3, v);
143 ret.back().emplace_back(0, res(0), res(1), res(2));
148 for(
unsigned int i = 0; i < shifts.size()-1; ++i){
149 const double newStride = shifts[i+1]-shifts[i];
150 assert((stride < 0 || fabs(stride-newStride) < 1
e-3) &&
151 "Variably-spaced syst templates are unsupported");
156 for(std::vector<Coeffs>& cs: ret)
168 const std::vector<IPrediction*>& preds,
172 const std::string& shortName)
const
175 for(
unsigned int i = 0; i < shifts.size(); ++i){
176 if(shifts[i] == 0) pNom = preds[i];
186 std::vector<std::unique_ptr<TH1>> ratios;
193 std::unique_ptr<TH1>&
r = ratios.back();
194 for(
int i = 0; i < r->GetNbinsX()+2; ++i){
195 const double y = r->GetBinContent(i);
197 std::cout <<
"PredictionInterp: WARNING, ratio in bin "
199 <<
" for '" << shortName <<
"'. Ignoring." << std::endl;
200 r->SetBinContent(i, 1);
232 else if(!
fPreds.empty() && !
fPreds.begin()->second.fits.empty())
return;
255 for(
auto& it:
fPreds) it.second.fits.clear();
270 return fPredNom->PredictComponent(calc, flav, curr, sign);
302 const unsigned int N = h->GetNbinsX()+2;
303 std::vector<double> corr(N,1.0);
306 const ISyst* syst = it.first;
316 shiftBin = std::max(0, shiftBin);
317 shiftBin = std::min(shiftBin, sp.
nCoeffs-1);
324 for(
unsigned int n = 0;
n <
N; ++
n){
331 corr[
n] *= f.
a*x_cube + f.
b*x_sqr + f.
c*x + f.
d;
335 double* arr = h->GetArray();
336 for(
unsigned int n = 0;
n <
N; ++
n){
337 arr[
n] *= std::max(corr[
n], 0.);
361 const bool canCache = (hash != 0);
363 const Key_t key = {flav, curr, sign};
371 if(canCache && it !=
fNomCache.end() && it->second.hash == *hash){
384 it->second = {*hash, nom};
407 std::cerr <<
"This PredictionInterp is not set up to handle the requested systematic: " << syst->ShortName() << std::endl;
413 const TMD5* hash = calc ? calc->GetParamsHash() : 0;
438 TDirectory* tmp = gDirectory;
441 TObjString(
"PredictionInterp").Write(
"type");
444 fPredNom->SaveTo(dir->mkdir(
"pred_nom"));
450 for(
unsigned int i = 0; i < sp.
shifts.size(); ++i){
452 std::cout <<
"Can't save a PredictionInterp after MinimizeMemory()" << std::endl;
455 sp.
preds[i]->SaveTo(dir->mkdir(TString::Format(
"pred_%s_%+d",
464 TH1F hSystNames(
"syst_names",
";Syst names", fPreds.size(), 0, fPreds.size());
466 for(
auto it: fPreds){
467 hSystNames.GetXaxis()->SetBinLabel(binIdx++, it.second.systName.c_str());
469 hSystNames.Write(
"syst_names");
473 split_sign.Write(
"split_sign");
481 TObjString* tag = (TObjString*)dir->Get(
"type");
483 assert(tag->GetString() ==
"PredictionInterp" ||
484 tag->GetString() ==
"PredictionInterp2");
488 LoadFromBody(dir, ret.get());
490 TObjString* split_sign = (TObjString*)dir->Get(
"split_sign");
492 ret->fSplitBySign = (split_sign && split_sign->String() ==
"yes");
499 std::vector<const ISyst*> veto)
503 TH1* hSystNames = (TH1*)dir->Get(
"syst_names");
505 for(
int systIdx = 0; systIdx < hSystNames->GetNbinsX(); ++systIdx){
507 sp.systName = hSystNames->GetXaxis()->GetBinLabel(systIdx+1);
511 if(std::find(veto.begin(), veto.end(), syst) != veto.end())
continue;
514 TDirectory* preddir = dir->GetDirectory(TString::Format(
"pred_%s_%+d", sp.systName.c_str(),
shift).
Data());
515 if(!preddir)
continue;
519 sp.shifts.push_back(
shift);
520 sp.preds.push_back(pred);
523 ret->
fPreds.emplace(syst, sp);
527 ret->
fOscOrigin = ana::LoadFrom<osc::IOscCalc>(dir->GetDirectory(
"osc_origin")).release();
535 std::set<IPrediction*> todel;
537 std::vector<IPrediction*>& preds = it.second.preds;
538 for(
unsigned int i = 0; i < preds.size(); ++i){
540 todel.insert(preds[i]);
566 auto it =
fPreds.find(syst);
568 std::cout <<
"PredictionInterp::DebugPlots(): "
569 << syst->
ShortName() <<
" not found" << std::endl;
573 std::unique_ptr<TH1> nom(
fPredNom->PredictComponent(calc, flav, curr, sign).ToTH1(18e20));
574 const int nbins = nom->GetNbinsX();
576 std::vector<TGraph*> curves(nbins);
577 std::vector<TGraph*> points(nbins);
579 for(
int i = 0; i <= 80; ++i){
580 const double x = .1*i-4;
586 curves[
bin] =
new TGraph;
587 points[
bin] =
new TGraph;
590 const double ratio = h->GetBinContent(
bin+1)/nom->GetBinContent(
bin+1);
592 if(!std::isnan(ratio)) curves[
bin]->SetPoint(curves[
bin]->GetN(), x, ratio);
593 else curves[
bin]->SetPoint(curves[
bin]->GetN(), x, 1);
600 for(
unsigned int shiftIdx = 0; shiftIdx < it->second.shifts.size(); ++shiftIdx){
601 if(it->second.shifts[shiftIdx] == 0) pNom = it->second.preds[shiftIdx];
606 for(
unsigned int shiftIdx = 0; shiftIdx < it->second.shifts.size(); ++shiftIdx){
607 if(!it->second.preds[shiftIdx])
continue;
608 std::unique_ptr<TH1>
h(it->second.preds[shiftIdx]->PredictComponent(calc, flav, curr, sign).ToTH1(18e20));
611 const double ratio =
h->GetBinContent(
bin+1)/hnom->GetBinContent(
bin+1);
612 if(!std::isnan(ratio)) points[
bin]->SetPoint(points[
bin]->GetN(), it->second.shifts[shiftIdx], ratio);
613 else points[
bin]->SetPoint(points[
bin]->GetN(), it->second.shifts[shiftIdx], 1);
618 int nx = int(sqrt(nbins));
619 int ny = int(sqrt(nbins));
620 if(nx*ny < nbins) ++nx;
621 if(nx*ny < nbins) ++ny;
623 TCanvas* c =
new TCanvas;
629 TString::Format(
"%s %g < %s < %g;Shift;Ratio",
630 it->second.systName.c_str(),
631 nom->GetXaxis()->GetBinLowEdge(
bin+1),
632 nom->GetXaxis()->GetTitle(),
633 nom->GetXaxis()->GetBinUpEdge(
bin+1)),
634 100, -4, +4, 100, .5, 1.5))->Draw();
635 curves[
bin]->Draw(
"l same");
636 points[
bin]->SetMarkerStyle(kFullDotMedium);
637 points[
bin]->Draw(
"p same");
645 const std::string& savePattern,
650 const bool save = !savePattern.empty();
651 const bool multiFile = savePattern.find(
"%s") != std::string::npos;
653 if(save && !multiFile){
655 gPad->Print((savePattern+
"[").c_str());
659 DebugPlot(it.first, calc, flav, curr, sign);
663 gPad->Print(TString::Format(savePattern.c_str(), it.second.systName.c_str()).
Data());
666 gPad->Print(savePattern.c_str());
671 if(save && !multiFile){
672 gPad->Print((savePattern+
"]").c_str());
685 std::unique_ptr<TH1> nom(
fPredNom->PredictComponent(calc, flav, curr, sign).ToTH1(18e20));
686 const int nbins = nom->GetNbinsX();
688 TH2* h2 =
new TH2F(
"", (syst->
LatexName()+
";;#sigma").c_str(),
689 nbins, nom->GetXaxis()->GetXmin(), nom->GetXaxis()->GetXmax(),
691 h2->GetXaxis()->SetTitle(nom->GetXaxis()->GetTitle());
693 for(
int i = 1; i <= 80; ++i){
694 const double y = h2->GetYaxis()->GetBinCenter(i);
699 const double ratio = h->GetBinContent(
bin+1)/nom->GetBinContent(
bin+1);
701 if(!isnan(ratio) && !isinf(ratio))
702 h2->Fill(h2->GetXaxis()->GetBinCenter(
bin),
y, ratio);
713 const std::string& savePattern,
718 const bool save = !savePattern.empty();
719 const bool multiFile = savePattern.find(
"%s") != std::string::npos;
721 if(save && !multiFile){
723 gPad->Print((savePattern+
"[").c_str());
732 gPad->Print(TString::Format(savePattern.c_str(), it.second.systName.c_str()).
Data());
735 gPad->Print(savePattern.c_str());
740 if(save && !multiFile){
741 gPad->Print((savePattern+
"]").c_str());
virtual Spectrum PredictComponent(osc::IOscCalc *calc, Flavors::Flavors_t flav, Current::Current_t curr, Sign::Sign_t sign) const override
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.
Implements systematic errors by interpolation between shifted templates.
void SetShift(const ISyst *syst, double shift)
Shifts are 0=nominal, -1,+1 = 1 sigma shifts.
virtual Spectrum PredictSyst(osc::IOscCalc *calc, const SystShifts &shift) const override
std::string systName
What systematic we're interpolating.
process_name opflash particleana ie x
BEGIN_PROLOG could also be cerr
Simple record of shifts applied to systematic parameters.
void OverridePOT(double newpot)
DO NOT USE UNLESS YOU ARE 110% CERTAIN THERE ISN'T A BETTER WAY!
Collection of SpectrumLoaders for many configurations.
std::vector< std::vector< std::vector< Coeffs > > > fitsNubar
Will be filled if signs are separated, otherwise not.
virtual void SaveTo(TDirectory *dir) const override
void SetOscSeed(osc::IOscCalc *oscSeed)
std::vector< std::vector< Coeffs > > FitRatios(const std::vector< double > &shifts, const std::vector< std::unique_ptr< TH1 >> &ratios) const
Find coefficients describing this set of shifts.
process_name opflashCryoW ana
T cube(T x)
More efficient cube function than pow(x,3)
void DebugPlotsColz(osc::IOscCalc *calc, const std::string &savePattern="", Flavors::Flavors_t flav=Flavors::kAll, Current::Current_t curr=Current::kBoth, Sign::Sign_t sign=Sign::kBoth) const
T sqr(T x)
More efficient square function than pow(x,2)
Encapsulate code to systematically shift a caf::StandardRecord.
virtual std::string ShortName() const final
The name printed out to the screen.
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
fSplitBySign(mode==kSplitBySign)
Representation of a spectrum in any variable, with associated POT.
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
std::unique_ptr< IPrediction > fPredNom
The nominal prediction.
std::map< Key_t, Val_t > fNomCache
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Charged-current interactions.
Interactions of both types.
process_name opflash particleana ie ie y
virtual ~PredictionInterp()
std::vector< double > shifts
Shift values sampled.
std::vector< IPrediction * > preds
double GetShift(const ISyst *syst) const
Spectrum fBinning
Dummy spectrum to provide binning.
void DebugPlots(osc::IOscCalc *calc, const std::string &savePattern="", Flavors::Flavors_t flav=Flavors::kAll, Current::Current_t curr=Current::kBoth, Sign::Sign_t sign=Sign::kBoth) const
Represent the ratio between two spectra.
static std::unique_ptr< PredictionInterp > LoadFrom(TDirectory *dir)
static const ISyst * ShortNameToSyst(const std::string &s, bool allowFail=false)
void DebugPlotColz(const ISyst *syst, osc::IOscCalc *calc, Flavors::Flavors_t flav=Flavors::kAll, Current::Current_t curr=Current::kBoth, Sign::Sign_t sign=Sign::kBoth) const
std::unique_ptr< IPrediction > LoadFrom< IPrediction >(TDirectory *dir)
then echo File list $list not found else cat $list while read file do echo $file sed s
process_name largeant stream1 can override from command line with o or output physics producers generator N
Neutral-current interactions.
virtual Spectrum PredictComponent(osc::IOscCalc *calc, Flavors::Flavors_t flav, Current::Current_t curr, Sign::Sign_t sign) const =0
Both neutrinos and antineutrinos.
Standard interface to all prediction techniques.
std::vector< const ISyst * > ActiveSysts() const
void DebugPlot(const ISyst *syst, osc::IOscCalc *calc, Flavors::Flavors_t flav=Flavors::kAll, Current::Current_t curr=Current::kBoth, Sign::Sign_t sign=Sign::kBoth) const
void InitFitsHelper(ShiftedPreds &sp, std::vector< std::vector< std::vector< Coeffs >>> &fits, Sign::Sign_t sign) const
virtual std::string LatexName() const final
The name used on plots (ROOT's TLatex syntax)
Given loaders and an MC shift, Generate() generates an IPrediction.
std::vector< std::string > GetLabels() const
std::unordered_map< const ISyst *, ShiftedPreds > fPreds
osc::IOscCalc * fOscOrigin
The oscillation values we assume when evaluating the coefficients.
All neutrinos, any flavor.
Prevent histograms being added to the current directory.
std::vector< std::vector< Coeffs > > FitComponent(const std::vector< double > &shifts, const std::vector< IPrediction * > &preds, Flavors::Flavors_t flav, Current::Current_t curr, Sign::Sign_t sign, const std::string &shortName) const
Find coefficients describing the ratios from this component.
virtual Spectrum PredictComponentSyst(osc::IOscCalc *calc, const SystShifts &shift, Flavors::Flavors_t flav, Current::Current_t curr, Sign::Sign_t sign) const override
double Livetime() const
Seconds. For informational purposes only. No calculations use this.
virtual Spectrum Predict(osc::IOscCalc *calc) const override
Spectrum ShiftedComponent(osc::IOscCalc *calc, const TMD5 *hash, const SystShifts &shift, Flavors::Flavors_t flav, Current::Current_t curr, Sign::Sign_t sign, CoeffsType type) const
Helper for PredictComponentSyst.
std::string UniqueName()
Return a different string each time, for creating histograms.
void SaveTo(const osc::IOscCalc &x, TDirectory *dir)
Spectrum ShiftSpectrum(const Spectrum &s, CoeffsType type, bool nubar, const SystShifts &shift) const
BEGIN_PROLOG could also be cout
std::vector< Binning > GetBinnings() const
std::vector< std::vector< std::vector< Coeffs > > > fits
Indices: [type][histogram bin][shift bin].