diff --git a/CAFAna/.gitignore b/CAFAna/.gitignore index c3934281..295a7ba8 100644 --- a/CAFAna/.gitignore +++ b/CAFAna/.gitignore @@ -7,4 +7,6 @@ cmake/CMakeFiles/ *.root *.pdf *.png +._* +.DS_* support/ diff --git a/CAFAna/Analysis/AnalysisBinnings.cxx b/CAFAna/Analysis/AnalysisBinnings.cxx deleted file mode 100644 index 713bb949..00000000 --- a/CAFAna/Analysis/AnalysisBinnings.cxx +++ /dev/null @@ -1,140 +0,0 @@ -#include "CAFAna/Analysis/AnalysisBinnings.h" -#include "CAFAna/Analysis/AnalysisVersion.h" - -#include "CAFAna/Core/Binning.h" -#include "CAFAna/Vars/Vars.h" - -#include - -using namespace ana; - -AxisBlob GetAxisBlob(std::string const &blob_name) { - - //Should all be statically initialized on first method call to ensure that the vars have been initialized beforehand - // Axes - static HistAxis const axRecoEnuFDnumu("Reco energy (GeV)", kFDRecoBinning, - kRecoE_numu); - static HistAxis const axRecoEnuFDnue("Reco energy (GeV)", kFDRecoBinning, - kRecoE_nue); - static HistAxis const axErecYrecND("Reco energy (GeV)", kNDRecoBinning, - kRecoEnergyND, "y_{rec}", kYBinning, - kRecoYND); - static HistAxis const axRecoEnuFDnumu_v3("Reco energy (GeV)", - kFDRecoBinning, kRecoE_numu); - static HistAxis const axRecoEnuFDnue_v3("Reco energy (GeV)", - kFDRecoV3Binning, kRecoE_nue); - static HistAxis const axErecYrecND_v3("Reco energy (GeV)", - kNDRecoV3Binning, kRecoEnergyND, - "y_{rec}", kYV3Binning, kRecoYND); - static HistAxis const axErecND("Reco energy (GeV)", kNDRecoBinning, - kRecoEnergyND); - - static HistAxis const axErecFD_FromDep("Reco energy (GeV)", kFDRecoBinning, - kRecoE_FromDep); - static HistAxis const axErecYrecND_FromDep( - "Reco energy (GeV)", kNDRecoBinning, kRecoE_FromDep, "y_{rec}", kYBinning, - kRecoY_FromDep); - static HistAxis const axErecYrecNDOA_FromDep( - "Reco energy (GeV)", kNDRecoOABinning, kRecoE_FromDep, "y_{rec}", kYBinning, - kRecoY_FromDep); - static HistAxis const axErecND_FromDep("#it{E}_{#nu}^{Rec.} (GeV)", - kNDRecoBinning, kRecoE_FromDep); - - static HistAxis const axTrueE_unibin("#it{E}_{#nu} (GeV)", kTrueBinning, - kTrueEnergy); - - static HistAxis const axTrueE_unibin_coarse( - "#it{E}_{#nu} (GeV)", kTrueCoarseBinning, kTrueEnergy); - - static HistAxis const axErec_FromDep_unibin("#it{E}_{#nu}^{Rec.} (GeV)", - kTrueBinning, kRecoE_FromDep); - static HistAxis const axErecND_unibin("#it{E}_{#nu}^{Rec.} (GeV)", - kTrueBinning, kRecoEnergyND); - static HistAxis const axRecoEnuFDnumu_unibin("Reco energy (GeV)", - kTrueBinning, kRecoE_numu); - static HistAxis const axRecoEnuFDnue_unibin("Reco energy (GeV)", - kTrueBinning, kRecoE_nue); - - static HistAxis const axErecND_coarsebin( - "Reco energy (GeV)", kRecoCoarseBinning, kRecoEnergyND); - static HistAxis const axRecoEnuFDnumu_coarsebin( - "Reco energy (GeV)", kRecoCoarseBinning, kRecoE_numu); - - static HistAxis const axRecoEnuFDnue_coarsebin( - "Reco energy (GeV)", kRecoCoarseBinning, kRecoE_nue); - - static HistAxis const axErecND_verycoarsebin( - "Reco energy (GeV)", kRecoVeryCoarseBinning, kRecoEnergyND); - static HistAxis const axRecoEnuFDnumu_verycoarsebin( - "Reco energy (GeV)", kRecoVeryCoarseBinning, kRecoE_numu); - - static HistAxis const axRecoEnuFDnue_verycoarsebin( - "Reco energy (GeV)", kRecoVeryCoarseBinning, kRecoE_nue); - - static HistAxis const axErecND_onebin("Reco energy (GeV)", kOneBinBinning, - kRecoEnergyND); - static HistAxis const axRecoEnuFDnumu_onebin("Reco energy (GeV)", kOneBinBinning, - kRecoE_numu); - - static HistAxis const axRecoEnuFDnue_onebin("Reco energy (GeV)", kOneBinBinning, - kRecoE_nue); - - static AxisBlob const default_axes_v4{&axErecYrecND, &axRecoEnuFDnumu, - &axRecoEnuFDnue}; - static AxisBlob const default_axes_v3{&axErecYrecND_v3, &axRecoEnuFDnumu_v3, - &axRecoEnuFDnue_v3}; - static AxisBlob const fake_data_axes{&axErecYrecND_FromDep, &axErecFD_FromDep, - &axErecFD_FromDep}; - - static AxisBlob const Ax1DND_unibin{&axErecND_unibin, &axRecoEnuFDnumu_unibin, - &axRecoEnuFDnue_unibin}; - static AxisBlob const Ax1DND_FromDep_unibin{ - &axErec_FromDep_unibin, &axErec_FromDep_unibin, &axErec_FromDep_unibin}; - - AxisBlob AxToUse = - (GetAnaVersion() == kV4) ? default_axes_v4 : default_axes_v3; - if (blob_name == "1DND") { - AxToUse.NDAx = &axErecND; - } else if (blob_name == "FromDep") { - AxToUse.NDAx = &axErecYrecND_FromDep; - AxToUse.FDAx_numu = &axErecFD_FromDep; - AxToUse.FDAx_nue = &axErecFD_FromDep; - } else if (blob_name == "1DNDFromDep") { - AxToUse.NDAx = &axErecND_FromDep; - AxToUse.FDAx_numu = &axErecFD_FromDep; - AxToUse.FDAx_nue = &axErecFD_FromDep; - } else if (blob_name == "CoarseBin1D") { - AxToUse.NDAx = &axErecND_coarsebin; - AxToUse.FDAx_numu = &axRecoEnuFDnumu_coarsebin; - AxToUse.FDAx_nue = &axRecoEnuFDnue_coarsebin; - } else if (blob_name == "VeryCoarseBin1D") { - AxToUse.NDAx = &axErecND_verycoarsebin; - AxToUse.FDAx_numu = &axRecoEnuFDnumu_verycoarsebin; - AxToUse.FDAx_nue = &axRecoEnuFDnue_verycoarsebin; - } else if (blob_name == "OneBin") { - AxToUse.NDAx = &axErecND_onebin; - AxToUse.FDAx_numu = &axRecoEnuFDnumu_onebin; - AxToUse.FDAx_nue = &axRecoEnuFDnue_onebin; - } else if (blob_name == "ETrue") { - AxToUse.NDAx = &axTrueE_unibin; - AxToUse.FDAx_numu = &axTrueE_unibin; - AxToUse.FDAx_nue = &axTrueE_unibin; - } else if (blob_name == "ETrueCoarse") { - AxToUse.NDAx = &axTrueE_unibin_coarse; - AxToUse.FDAx_numu = &axTrueE_unibin_coarse; - AxToUse.FDAx_nue = &axTrueE_unibin_coarse; - } else if (blob_name == "FakeData") { - AxToUse = fake_data_axes; - } else if (blob_name == "v4") { - AxToUse = default_axes_v4; - } else if (blob_name == "v3") { - AxToUse = default_axes_v3; - } else if (blob_name == "CoarseNue") { - AxToUse.FDAx_nue = &axRecoEnuFDnue_coarsebin; - } else if (blob_name == "VeryCoarseNue") { - AxToUse.FDAx_nue = &axRecoEnuFDnue_verycoarsebin; - } else if (blob_name == "OneBinNue") { - AxToUse.FDAx_nue = &axRecoEnuFDnue_onebin; - } - return AxToUse; -} diff --git a/CAFAna/Analysis/AnalysisBinnings.h b/CAFAna/Analysis/AnalysisBinnings.h deleted file mode 100644 index 5b05d0c6..00000000 --- a/CAFAna/Analysis/AnalysisBinnings.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "CAFAna/Core/HistAxis.h" - -#include - -struct AxisBlob { - ana::HistAxis const *NDAx; - ana::HistAxis const *FDAx_numu; - ana::HistAxis const *FDAx_nue; -}; - -AxisBlob GetAxisBlob(std::string const &); diff --git a/CAFAna/Analysis/AnalysisDialGroups.h b/CAFAna/Analysis/AnalysisDialGroups.h deleted file mode 100644 index 3eedced9..00000000 --- a/CAFAna/Analysis/AnalysisDialGroups.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include -#include - -// Could move this to Systs/AnaSysts.h but it might end up in a loop of dependencies -// Leave this here for now. For now. - -// Define a few groups of systematics: -// nofd_det, nofd_escale, nofd_muon_escale, noxsec_qe, noxsec_res, noxsec_dis, -// noxsec_fsi, noxsec_ratios - -// All detector nuisance parameters -std::vector const nd_det_list = {"RecoNCSyst", "FVNumuND"}; -std::vector const fd_det_list = { - "EnergyScaleFD", "UncorrFDTotSqrt", - "UncorrFDTotInvSqrt", - - "ChargedHadUncorrFD", "UncorrFDHadSqrt", - "UncorrFDHadInvSqrt", "ChargedHadResFD", - - "EScaleMuLArFD", "UncorrFDMuSqrt", - "UncorrFDMuInvSqrt", "MuonResFD", - - "EMUncorrFD", "UncorrFDEMSqrt", - "UncorrFDEMInvSqrt", "EMResFD", - - "NUncorrFD", "UncorrFDNSqrt", - "UncorrFDNInvSqrt", "NResFD", - - "FDRecoNumuSyst", "FDRecoNueSyst", - "FVNumuFD", "FVNueFD"}; - -// FD detector subsets -std::vector const fd_escale_list = { - "EnergyScaleFD", "UncorrFDTotSqrt", "UncorrFDTotInvSqrt", - "ChargedHadUncorrFD", "UncorrFDHadSqrt", "UncorrFDHadInvSqrt", - "EScaleMuLArFD", "UncorrFDMuSqrt", "UncorrFDMuInvSqrt", - "EMUncorrFD", "UncorrFDEMSqrt", "UncorrFDEMInvSqrt", - "NUncorrFD", "UncorrFDNSqrt", "UncorrFDNInvSqrt", -}; -std::vector const fd_muon_escale_list = {"EScaleMuLArFD"}; -std::vector const fd_eres_list = {"ChargedHadResFD", "MuonResFD", - "EMResFD", "NResFD"}; -std::vector const fd_muon_eres_list = {"MuonResFD"}; -std::vector const fd_other_det_list = { - "FDRecoNumuSyst", "FDRecoNueSyst", "FVNumuFD", "FVNueFD"}; -// ~New dials for V4 -std::vector const fd_nonlin_det_list = { - "UncorrFDTotSqrt", "UncorrFDTotInvSqrt", "UncorrFDHadSqrt", - "UncorrFDHadInvSqrt", "UncorrFDMuSqrt", "UncorrFDMuInvSqrt", - "UncorrFDEMSqrt", "UncorrFDEMInvSqrt", "UncorrFDNSqrt", - "UncorrFDNInvSqrt"}; diff --git a/CAFAna/Analysis/AnalysisVars.cxx b/CAFAna/Analysis/AnalysisVars.cxx deleted file mode 100644 index f2ac8aa8..00000000 --- a/CAFAna/Analysis/AnalysisVars.cxx +++ /dev/null @@ -1,46 +0,0 @@ -#include "CAFAna/Analysis/AnalysisVars.h" - -#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" - -using namespace ana; - -// List of vars -// -->FD -Var const kRecoE_nue = SIMPLEVAR(Ev_reco_nue); -Var const kRecoE_numu = SIMPLEVAR(Ev_reco_numu); -Var const kRecoE_FromDep = SIMPLEVAR(eRec_FromDep); -Var const kFDNumuPid = SIMPLEVAR(cvnnumu); -Var const kFDNuePid = SIMPLEVAR(cvnnue); -Var const kMVANUMU = SIMPLEVAR(mvanumu); - -Var const kLepEReco_numu = SIMPLEVAR(RecoLepEnNumu); -Var const kLepEReco_nue = SIMPLEVAR(RecoLepEnNue); - -Var const kHadEReco_numu = SIMPLEVAR(RecoHadEnNumu); -Var const kHadEReco_nue = SIMPLEVAR(RecoHadEnNue); - -Var const kEVisReco_numu = SIMPLEVAR(EVisReco_numu); -Var const kEVisReco_nue = SIMPLEVAR(EVisReco_nue); - -// -->ND -Var const kRecoEnergyND = SIMPLEVAR(Ev_reco); -Var const kRecoYND = (SIMPLEVAR(Ev_reco) - SIMPLEVAR(Elep_reco)) / - SIMPLEVAR(Ev_reco); -Var const kRecoY_FromDep = - (SIMPLEVAR(eRec_FromDep) - SIMPLEVAR(LepE)) / - SIMPLEVAR(eRec_FromDep); - -Var const kNDLepEReco = SIMPLEVAR(Elep_reco); -Var const kNDEVisReco = SIMPLEVAR(EVisReco_ND); - -// -->Common ND & FD -Var const kTrueEnergy = SIMPLEVAR(Ev); -Var const kProxyERec = SIMPLEVAR(eRecProxy); -Var const kEVisTrue = SIMPLEVAR(VisTrue_NDFD); - -Var const kPEReco = SIMPLEVAR(eRecoP); -Var const kPipmEReco = SIMPLEVAR(eRecoPip) + SIMPLEVAR(eRecoPim); -Var const kPi0EReco = SIMPLEVAR(eRecoPi0); - -// CV weighting -Weight const kCVXSecWeights = SIMPLEWEIGHT(total_xsSyst_cv_wgt); // kUnweighted diff --git a/CAFAna/Analysis/AnalysisVars.h b/CAFAna/Analysis/AnalysisVars.h deleted file mode 100644 index 376cf89a..00000000 --- a/CAFAna/Analysis/AnalysisVars.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "CAFAna/Core/Var.h" -#include "CAFAna/Core/Weight.h" - -// List of vars -// -->FD -extern ana::Var const kRecoE_nue; -extern ana::Var const kRecoE_numu; -extern ana::Var const kRecoE_FromDep; -extern ana::Var const kFDNumuPid; -extern ana::Var const kFDNuePid; -extern ana::Var const kMVANUMU; - -extern ana::Var const kLepEReco_numu; -extern ana::Var const kLepEReco_nue; - -extern ana::Var const kHadEReco_numu; -extern ana::Var const kHadEReco_nue; - -extern ana::Var const kEVisReco_numu; -extern ana::Var const kEVisReco_nue; - -// -->ND -extern ana::Var const kRecoEnergyND; -extern ana::Var const kRecoYND; -extern ana::Var const kRecoY_FromDep; - -extern ana::Var const kNDLepEReco; -extern ana::Var const kNDEVisReco; - -// --> Common ND & FD -extern ana::Var const kTrueEnergy; -extern ana::Var const kProxyERec; -extern ana::Var const kEVisTrue; -extern ana::Var const kPEReco; // proton -extern ana::Var const kPipmEReco; // charged pion -extern ana::Var const kPi0EReco; // neutral pion - -// CV weighting -extern ana::Weight const kCVXSecWeights; // kUnweighted diff --git a/CAFAna/Analysis/AnalysisVersion.h b/CAFAna/Analysis/AnalysisVersion.h deleted file mode 100644 index 732fb589..00000000 --- a/CAFAna/Analysis/AnalysisVersion.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -enum AnaVersion { kV3, kV4 }; -inline AnaVersion GetAnaVersion(){ - static AnaVersion AnaV = kV4; - static bool first = true; - if (first && getenv("CAFANA_ANALYSIS_VERSION")) { - int v = atoi(getenv("CAFANA_ANALYSIS_VERSION")); - if (v == 3) { - AnaV = kV3; - } else if (v == 4) { - AnaV = kV4; - } - first = false; - } - - return AnaV; -} \ No newline at end of file diff --git a/CAFAna/Analysis/CMakeLists.txt b/CAFAna/Analysis/CMakeLists.txt index 3dc8b783..10a43742 100644 --- a/CAFAna/Analysis/CMakeLists.txt +++ b/CAFAna/Analysis/CMakeLists.txt @@ -3,26 +3,20 @@ set(Analysis_implementation_files CalcsNuFit.cxx Plots.cxx Resolution.cxx - TDRLoaders.cxx - AnalysisBinnings.cxx - AnalysisVars.cxx - common_fit_definitions.cxx) + SpectrumComponents.cxx +) set(Analysis_header_files Calcs.h CalcsNuFit.h Plots.h Resolution.h - TDRLoaders.h Exposures.h Style.h - AnalysisBinnings.h - AnalysisDialGroups.h - AnalysisVars.h - common_fit_definitions.h - AnalysisVersion.h ExtraHeaders.h - CheckPointHelper.h) + CheckPointHelper.h + SpectrumComponents.h +) add_library(CAFAnaAnalysis SHARED ${Analysis_implementation_files}) target_link_libraries(CAFAnaAnalysis CAFAnaCore CAFAnaFit) @@ -34,6 +28,9 @@ if(DEFINED USE_OPENMP AND USE_OPENMP) target_compile_options(CAFAnaAnalysis BEFORE PUBLIC -DUSE_PREDINTERP_OMP -fopenmp) endif() -install(TARGETS CAFAnaAnalysis +install(TARGETS CAFAnaAnalysis + EXPORT CAFAnaTargets LIBRARY DESTINATION lib/ PUBLIC_HEADER DESTINATION include/CAFAna/Analysis/) + +add_cafana_lib(CAFAnaAnalysis) \ No newline at end of file diff --git a/CAFAna/Analysis/SpectrumComponents.cxx b/CAFAna/Analysis/SpectrumComponents.cxx new file mode 100644 index 00000000..16aac5b1 --- /dev/null +++ b/CAFAna/Analysis/SpectrumComponents.cxx @@ -0,0 +1,246 @@ +#include "CAFAna/Analysis/SpectrumComponents.h" + +#include +#include + +#include "TDirectory.h" +#include "TH1F.h" +#include "TKey.h" +#include "TLegend.h" +#include "TObjString.h" +#include "TParameter.h" +#include "TVirtualPad.h" + +#include "CAFAna/Analysis/Plots.h" +#include "CAFAna/Core/Spectrum.h" + +namespace ana +{ + template + const _Cut _SpectrumComponents::kNoCut = _Cut(NoCut()); + + template + const _Weight _SpectrumComponents::kUnweighted = Unweighted(); + + //------------------------------------------------------------------------- + template + _SpectrumComponents::_SpectrumComponents(const ana::_Cut& baseCut, + const ana::_HistAxis<_Var> &axis, + ana::_IRecordSource &source, + const std::map &categories, + const _Weight &wei) + : + fSel(baseCut), + fTot(source.Weighted(wei)[fSel], axis) + { + if (!categories.empty()) + { + for (const auto & componentPair : categories) + { + fComponentDescr.emplace(componentPair.first, componentPair.second); + fComponentSpecs.emplace(std::piecewise_construct, + std::forward_as_tuple(componentPair.first), + std::forward_as_tuple(source.Weighted(wei)[fSel && componentPair.second.cut], axis)); + } + } + } + + // todo: MultiVarHistAxis is currently disabled in CAFAnaCore + // //------------------------------------------------------------------------- + // SpectrumComponents::SpectrumComponents(const ana::Cut& baseCut, + // const ana::MultiVarHistAxis & axis, + // ana::SpectrumLoaderBase & loader, + // const Weight & wei, + // const std::map& categories) + // : + // fSel(baseCut), + // fTot(loader, axis, fSel, kNoShift, wei) + // { + // if (!categories.empty()) + // { + // for (const auto & componentPair : categories) + // { + // fComponentDescr.emplace(componentPair.first, componentPair.second); + // fComponentSpecs.emplace(std::piecewise_construct, + // std::forward_as_tuple(componentPair.first), + // std::forward_as_tuple(loader, axis, fSel && componentPair.second.cut, kNoShift, wei)); + // } + // } + // } + + //------------------------------------------------------------------------- + template + TLegend* _SpectrumComponents::DrawLegend(double drawThreshold, TLegend * leg) const + { + if (!leg) + leg = AutoPlaceLegend(0.25, 0.18 + 0.04*fComponentDescr.size()); + + double thresh = 0; + if (drawThreshold >= 0 && drawThreshold <= 1.0) + thresh = fTot.Integral(fTot.POT()) * drawThreshold; + else + // this is supposed to be a fraction + assert(drawThreshold <= 1 && "SpectrumComponents::DrawLegend(): legend draw thresholds must be between 0.0 and 1.0"); + for (const auto & mcSpecPair : fComponentDescr) + { + auto spec = fComponentSpecs.at(mcSpecPair.first); + if (spec.Integral(spec.POT()) < thresh) + continue; + + TH1F* comp = new TH1F(); + comp->SetLineColor(kBlack); + comp->SetFillColor(mcSpecPair.second.color); + leg->AddEntry(comp, mcSpecPair.second.blurb.c_str(), "f"); + } + + + leg->SetFillColor(0); + leg->SetFillStyle(0); + + for(const auto& obj:*leg->GetListOfPrimitives()) + { + if(obj->InheritsFrom("TAttFill")){ + ((TAttFill*)obj)->SetFillStyle(0); + } + + } + leg->Draw(); + return leg; + } + + //------------------------------------------------------------------------- + template + void _SpectrumComponents::DrawComponents(bool stacked, EBinType bintype, double POT, bool sameAll) const + { + if (POT == 0) + POT = fComponentSpecs.begin()->second.POT(); + + TH1 * last = nullptr; + std::vector hists; + + // iterate backwards so that they're drawn in the specified order from top to bottom + for (auto it_comp = fComponentSpecs.rbegin(); it_comp != fComponentSpecs.rend(); it_comp++) + { + auto h = it_comp->second.ToTH1(POT, kBlack, kSolid, kPOT, bintype); + if (stacked) + { + if (last) + h->Add(last); + h->SetFillColor(fComponentDescr.at(it_comp->first).color); + h->SetLineWidth(1); + last = h; + } + + hists.push_back(h); + } + bool drawn = false; + for (auto it_hist = hists.rbegin(); it_hist != hists.rend(); it_hist++) + { + std::string opt = "hist"; + if (drawn || sameAll) + opt += " same"; + (*it_hist)->Draw(opt.c_str()); + if (!drawn) + drawn = true; + } + + // if there were fills they will be overlapping the axis ticks + gPad->RedrawAxis(); + } + + //------------------------------------------------------------------------- + template + float _SpectrumComponents::Purity(const std::set& signalCatNames) const + { + double bkgCounts = 0; + double POT = fComponentSpecs.begin()->second.POT(); + for (const auto & mcCatPair : fComponentSpecs) + { + if (signalCatNames.find(mcCatPair.first) != signalCatNames.end()) + continue; + bkgCounts += mcCatPair.second.ToTH1(POT)->GetEntries(); + } + return 1 - bkgCounts / fTot.ToTH1(POT)->GetEntries(); + } + + //------------------------------------------------------------------------- + template + void _SpectrumComponents::SaveTo(TDirectory* dir, const std::string& name) const + { + TDirectory* tmp = gDirectory; + + dir = dir->mkdir(name.c_str()); // switch to subdir + dir->cd(); + + fTot.SaveTo(dir, "Total"); + + TDirectory * allCompsDir = dir->mkdir("Components"); + for (const auto & specPair : fComponentSpecs) + { + TDirectory* compDir = allCompsDir->mkdir(specPair.first.c_str()); + specPair.second.SaveTo(compDir, "spectrum"); + + compDir->cd(); + const auto & comp = fComponentDescr.at(specPair.first); + TObjString blurb(comp.blurb.c_str()); + blurb.Write("blurb"); + + TParameter color; + color.SetVal(comp.color); + color.Write("color"); + } + + dir->Write(); + delete dir; + + tmp->cd(); + } + + //------------------------------------------------------------------------- + template + std::unique_ptr<_SpectrumComponents> _SpectrumComponents::LoadFrom(TDirectory* dir, const std::string& name) + { + dir = dir->GetDirectory(name.c_str()); // switch to subdir + assert(dir); + + Spectrum tot = *Spectrum::LoadFrom(dir, "Total"); + + std::map compDescrs; + std::map compSpecs; + TDirectory * compDir = dynamic_cast(dir->Get("Components")); + for ( TObject * obj : *(compDir->GetListOfKeys()) ) + { + TKey * key = dynamic_cast(obj); + TDirectory * subdir = dynamic_cast(key->ReadObj()); + if (!subdir) + continue; + + compSpecs.emplace(key->GetName(), *(Spectrum::LoadFrom(subdir, "spectrum").release())); + compDescrs.emplace(std::piecewise_construct, + std::forward_as_tuple(key->GetName()), + std::forward_as_tuple(kNoCut, // Cut object won't be re-used anyhow since Spectra are already made? + dynamic_cast(subdir->Get("blurb"))->String().Data(), + dynamic_cast*>(subdir->Get("color"))->GetVal() ) + ); + } + + auto ret = std::make_unique<_SpectrumComponents>( + std::move(tot), + std::move(compDescrs), + std::move(compSpecs) + ); + + delete dir; + + return ret; + } + + //------------------------------------------------------------------------- + // we can add more instantiations if we need to + template class _SpectrumComponents; + template class _SpectrumComponents; + template class _SpectrumComponents; + template class _SpectrumComponents; + + +} diff --git a/CAFAna/Analysis/SpectrumComponents.h b/CAFAna/Analysis/SpectrumComponents.h new file mode 100644 index 00000000..4312cbef --- /dev/null +++ b/CAFAna/Analysis/SpectrumComponents.h @@ -0,0 +1,120 @@ +#pragma once + +#include +#include + +#include "CAFAna/Core/Cut.h" +#include "CAFAna/Core/Spectrum.h" +#include "CAFAna/Core/SpectrumLoader.h" +#include "CAFAna/Core/Var.h" + +class TLegend; + +namespace ana +{ + + template + class _SpectrumComponents + { + // shortcuts + const static _Cut kNoCut; // can't be constexpr because CutBase (an ancestor) has a nontrivial destructor + const static _Weight kUnweighted; // can't be constexpr because VarBase (an ancestor) has a nontrivial destructor + + public: + struct Component + { + Component(const _Cut& cut_, const std::string & blurb_="", int color_=kBlue) + : cut(cut_), blurb(blurb_), color(color_) + {} + + _Cut cut; + std::string blurb; + int color; + }; + + /// \brief \ref SpectrumComponents makes a collection of Spectra differing by a single (often truth) Cut. + /// + /// \param baseCut the selection cut shared between all components + /// \param axis \ref HistAxis shared between all components + /// \param loaderData \ref SpectrumLoader for data + /// \param loaderMC \ref SpectrumLoader for MC + /// \param wei Weight to apply to events + /// \param systs std::vector of ISyst* for drawing plots with syst bands + /// \param bkg \ref Cut object to define background + /// \param mcCategories the various \ref Cut s defining each category + _SpectrumComponents(const ana::_Cut& baseCut, + const ana::_HistAxis<_Var> & axis, + ana::_IRecordSource & source, + const std::map& categories = {}, + const _Weight & wei = kUnweighted); + + // todo: MultiVarHistAxis is currently disabled in CAFAnaCore + // SpectrumComponents(const ana::_Cut& baseCut, + // const ana::_MultiVarHistAxis & axis, + // ana::SpectrumLoaderBase & loader, + // const _Weight & wei = kUnweighted, + // const std::map& categories = {}); + + /// Constructor for use in LoadFrom() + _SpectrumComponents(Spectrum&& tot, + std::map&& compDescrs, + std::map&& compSpecs) + : fSel(kNoCut), + fTot(tot), + fComponentDescr(compDescrs), + fComponentSpecs(compSpecs) + {} + + /// Constructor from copies... + _SpectrumComponents(const Spectrum& tot, + const std::map& compDescrs, + const std::map& compSpecs) + : fSel(kNoCut), + fTot(tot), + fComponentDescr(compDescrs), + fComponentSpecs(compSpecs) + {} + + /// \brief Draw legend on plots + /// \param drawThreshold Only create entries for histograms whose integral is greater than this fraction of the total + TLegend* DrawLegend(double drawThreshold = 0, TLegend * leg = nullptr) const; + + /// \brief Draw MC components distribution + /// + /// \param stack By default components will be shown stacked. Pass false to show them unstacked instead. + /// \param bintype Raw bin contents or bin-width normalized? + /// \param POT Normalize to specific POT? Otherwise use internal Spectrum POT + /// \param sameAll Draw all hists with "same" option? + void DrawComponents(bool stacked=true, EBinType bintype = kBinContent, double POT=0, bool sameAll=true) const; + + /// \brief Purity of the MC selection based on the MC subcategories. + /// + /// \param signalCatNames If any of your subcategories are "signal", pass them here to avoid counting them as background + float Purity(const std::set& signalCatNames={}) const; + + void SaveTo(TDirectory* dir, const std::string& name) const; + static std::unique_ptr<_SpectrumComponents> LoadFrom(TDirectory* dir, const std::string& name); + + const ana::_Cut & Sel() const { return fSel; }; + + Spectrum & Tot() { return fTot; }; + const Spectrum & Tot() const { return fTot; }; + + unsigned int NDimensions() const { return fTot.NDimensions(); } + std::vector GetLabels() const { return fTot.GetLabels(); } + std::vector GetBinnings() const { return fTot.GetBinnings(); } + + const std::map & ComponentDescrs() const { return fComponentDescr; }; + std::map & ComponentDescrs() { return fComponentDescr; }; + const std::map & ComponentSpecs() const { return fComponentSpecs; }; + + private: + ana::_Cut fSel; + Spectrum fTot; + std::map fComponentDescr; + std::map fComponentSpecs; + + }; + + typedef _SpectrumComponents SpectrumComponents; +} diff --git a/CAFAna/Analysis/TDRLoaders.cxx b/CAFAna/Analysis/TDRLoaders.cxx deleted file mode 100644 index 93f7ab35..00000000 --- a/CAFAna/Analysis/TDRLoaders.cxx +++ /dev/null @@ -1,22 +0,0 @@ -#include "CAFAna/Analysis/TDRLoaders.h" - -#include "unistd.h" - -namespace ana -{ - //---------------------------------------------------------------------- - TDRLoaders::TDRLoaders(FluxType flux) - { - // FNAL location - std::string base = "/pnfs/dune/persistent/users/LBL_TDR/CAFs/v4/"; - - const std::string hc = (flux == kFHC) ? "FHC" : "RHC"; - - SetLoaderPath(base+"ND_"+hc+"_CAF.root", caf::kNEARDET, Loaders::kMC, Loaders::kNonSwap); - - SetLoaderPath(base+"FD_"+hc+"_nonswap.root", caf::kFARDET, Loaders::kMC, Loaders::kNonSwap); - SetLoaderPath(base+"FD_"+hc+"_nueswap.root", caf::kFARDET, Loaders::kMC, Loaders::kNueSwap); - - SetLoaderPath(base+"FD_"+hc+"_tauswap.root", caf::kFARDET, Loaders::kMC, Loaders::kNuTauSwap); - } -} diff --git a/CAFAna/Analysis/TDRLoaders.h b/CAFAna/Analysis/TDRLoaders.h deleted file mode 100644 index d96de855..00000000 --- a/CAFAna/Analysis/TDRLoaders.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "CAFAna/Core/Loaders.h" - -namespace ana -{ - /// Standardized filenames for TDR analysis - class TDRLoaders: public Loaders - { - public: - TDRLoaders(FluxType flux); - }; -} diff --git a/CAFAna/Analysis/common_fit_definitions.cxx b/CAFAna/Analysis/common_fit_definitions.cxx deleted file mode 100644 index 6a45b860..00000000 --- a/CAFAna/Analysis/common_fit_definitions.cxx +++ /dev/null @@ -1,1439 +0,0 @@ -#include "CAFAna/Analysis/common_fit_definitions.h" -#include "CAFAna/Analysis/AnalysisVersion.h" - -#include "CAFAna/Analysis/AnalysisBinnings.h" -#include "CAFAna/Analysis/AnalysisVars.h" -#include "CAFAna/Analysis/Calcs.h" -#include "CAFAna/Analysis/CalcsNuFit.h" -#include "CAFAna/Analysis/Exposures.h" -#include "CAFAna/Analysis/Plots.h" - -#include "CAFAna/Core/Binning.h" -#include "CAFAna/Core/LoadFromFile.h" -#include "CAFAna/Core/Loaders.h" -#include "CAFAna/Core/Progress.h" -#include "CAFAna/Core/Spectrum.h" -#include "CAFAna/Core/SpectrumLoader.h" -#include "CAFAna/Core/Var.h" - -#include "CAFAna/Cuts/AnaCuts.h" -#include "CAFAna/Cuts/TruthCuts.h" - -#include "CAFAna/Experiment/MultiExperiment.h" -#include "CAFAna/Experiment/SingleSampleExperiment.h" -#include "CAFAna/Experiment/CovarianceExperiment.h" - -#include "CAFAna/Prediction/PredictionNoExtrap.h" -#include "CAFAna/Prediction/PredictionNoOsc.h" - -#include "CAFAna/Vars/FitVars.h" - -#include "CAFAna/Systs/DUNEFluxSysts.h" -#include "CAFAna/Systs/EnergySysts.h" -#include "CAFAna/Systs/RecoEnergyNDSysts.h" -#include "CAFAna/Systs/FDRecoSysts.h" -#include "CAFAna/Systs/NDRecoSysts.h" -#include "CAFAna/Systs/NuOnESysts.h" -#include "CAFAna/Systs/Systs.h" -#include "CAFAna/Systs/XSecSysts.h" -#include "CAFAna/Systs/CrazyFluxFakeData.h" - -#include "OscLib/IOscCalc.h" -#include "OscLib/OscCalcPMNSOpt.h" -#include "OscLib/OscCalcGeneral.h" - -#include "TFile.h" -#include "TH1.h" -#include "TH2.h" -#include "TMatrixDSym.h" -#include "TSystem.h" -#include "TTree.h" - -#ifdef USE_PREDINTERP_OMP -#include -#endif - -#include -#include - -using namespace ana; - -unsigned gRNGSeed = 0; - -// A smaller APA geometry was used to simmulate the FD due to computational requirements. -// Scale the simulated sample to match the actuall 40 kt detector. -const double pot_fd_FVMassFactor = 40 / 1.13; -// POT for 3.5 years -const double nom_years = 3.5; -const double pot_fd = POT120 * nom_years * pot_fd_FVMassFactor; -const double pot_nd = POT120 * nom_years; -// This is pretty annoying, but the above is for 7 years staged, which is 336 kT / MW yr - -const double nom_exposure = 336.; - -double GetBoundedGausThrow(double min, double max) { - double val = -999; - while (val > max || val < min) - val = gRandom->Gaus(); - return val; -} - -// For ease of penalty terms... -IExperiment *GetPenalty(int hie, int oct, std::string penalty, - std::string asimov_set, bool modConstraint) { - - // First, decide which to use - std::vector penalties = SplitString(penalty, ':'); - bool useTh13 = false; - bool useDmsq32 = false; - bool useTh23 = false; - - for (auto &str : penalties) { - if (str == "th13" || str == "allpen") - useTh13 = true; - if (str == "dmsq32" || str == "allpen") - useDmsq32 = true; - if (str == "th23" || str == "allpen") - useTh23 = true; - } - - Penalizer_GlbLike *ret = - new Penalizer_GlbLike(hie, oct, useTh13, useDmsq32, useTh23, 0); - ret->SetAsimovPoint(asimov_set, modConstraint); - return ret; -} - -std::vector GetOscVars(std::string oscVarString, int hie, - int oct) { - - std::vector osc_vars = SplitString(oscVarString, ':'); - - std::vector rtn_vars; - - for (auto &v : osc_vars) { - if (v == "th13" || v == "alloscvars") { - rtn_vars.push_back(&kFitTheta13); - } - // Deal with bounded dmsq32 - if (v == "dmsq32" || v == "alloscvars") { - if (hie == -1) - rtn_vars.push_back(&kFitDmSq32IHScaled); - else if (hie == 1) - rtn_vars.push_back(&kFitDmSq32NHScaled); - else - rtn_vars.push_back(&kFitDmSq32Scaled); - } - - // Deal with octant boundaries - if (v == "th23" || v == "alloscvars") { - if (oct == -1) - rtn_vars.push_back(&kFitSinSqTheta23LowerOctant); - else if (oct == 1) - rtn_vars.push_back(&kFitSinSqTheta23UpperOctant); - else - rtn_vars.push_back(&kFitSinSqTheta23); - } - if (v == "deltapi" || v == "alloscvars") { - rtn_vars.push_back(&kFitDeltaInPiUnits); - } - - // Add back in the 21 parameters - if (v == "dmsq21" || v == "alloscvars") { - rtn_vars.push_back(&kFitDmSq21Scaled); - } - if (v == "th12" || v == "alloscvars") { - rtn_vars.push_back(&kFitSinSq2Theta12); - } - // Rho rho rho your boat... - if (v == "rho" || v == "alloscvars") { - rtn_vars.push_back(&kFitRho); - } - } - return rtn_vars; -} - -/* - The behaviour of fake data dials is a bit clunky. Instead of the multiple spline - points used for normal dials, they have fixed values for non-zero values of the - dial. So, for some, +/-3, +/-2, +/-1 values of the dial will all give the same - value. Some are set so all negative (positive) values give a -3 (+3) sigma - variation, which is why there's some messing around in the function below. - The spline behaviour is forced (for XSec dials) in XSecSyst::FakeDataDialShift, - which is called only when creating the input CAFs. This is almost certainly not - optimal, but is easy to extend for other dials. - */ -SystShifts GetFakeDataGeneratorSystShift(std::string input) { - - // Default to nominal - SystShifts thisShift = kNoShift; - - if (input.empty() || input == "nominal") - return thisShift; - - // Allow _pos and _neg endings - std::vector split_input = SplitString(input, ':'); - std::vector fake_data_names; - std::vector dial_vals; - - for (auto in_name : split_input){ - std::string name = in_name; - int val = 1; - - if (in_name.compare(in_name.length()-4, 4, "_pos") == 0){ - name = in_name.substr(0, in_name.length()-4); - val = 1; - } else if (in_name.compare(in_name.length()-4, 4, "_neg") == 0){ - name = in_name.substr(0, in_name.length()-4); - val = -1; - } - - // Check nobody did anything dumb... - //assert(IsFakeDataGenerationSyst(name) || //IsCrazyFluxSyst(name) || - // IsNDdetSyst(name) || IsFDdetSyst(name)); // Might also want to do detector bias studies - std::cout << "Fake data shift: " << name << std::endl; - fake_data_names.push_back(name); - dial_vals.push_back(val); - } - - std::vector FDSyst = GetListOfSysts(); - KeepSysts(FDSyst, fake_data_names); - - for (uint i=0; i systlist, - AxisBlob const &axes, - std::vector const &non_swap_file_list, - std::vector const &nue_swap_file_list, - std::vector const &tau_swap_file_list, - int max) { - - bool use_cv_weights = true; - if (getenv("CAFANA_IGNORE_CV_WEIGHT")) { - use_cv_weights = !atoi(getenv("CAFANA_IGNORE_CV_WEIGHT")); - } - - bool use_selection = true; - if (getenv("CAFANA_IGNORE_SELECTION")) { - use_selection = !atoi(getenv("CAFANA_IGNORE_SELECTION")); - } - - // Move to the save directory - saveDir->cd(); - osc::IOscCalcAdjustable *this_calc = NuFitOscCalc(1); - - bool isfhc = - ((sample == kNDFHC) || (sample == kNDFHC_OA) || (sample == kFDFHC)); - - // FD samples - if ((sample == kFDFHC) || (sample == kFDRHC)) { - - Loaders these_loaders; - SpectrumLoader loaderNumu(non_swap_file_list, max); - SpectrumLoader loaderNue(nue_swap_file_list, max); - SpectrumLoader loaderNutau(tau_swap_file_list, max); - - these_loaders.AddLoader(&loaderNumu, caf::kFARDET, Loaders::kMC, - Loaders::kNonSwap); - these_loaders.AddLoader(&loaderNue, caf::kFARDET, Loaders::kMC, - Loaders::kNueSwap); - these_loaders.AddLoader(&loaderNutau, caf::kFARDET, Loaders::kMC, - Loaders::kNuTauSwap); - - NoExtrapPredictionGenerator genFDNumu( - *axes.FDAx_numu, - use_selection ? kPassFD_CVN_NUMU && kIsTrueFV : kIsTrueFV, - use_cv_weights ? kCVXSecWeights : kUnweighted); - NoExtrapPredictionGenerator genFDNue( - *axes.FDAx_nue, - use_selection ? kPassFD_CVN_NUE && kIsTrueFV : kIsTrueFV, - use_cv_weights ? kCVXSecWeights : kUnweighted); - PredictionInterp predInterpFDNumu(systlist, this_calc, genFDNumu, - these_loaders); - PredictionInterp predInterpFDNue(systlist, this_calc, genFDNue, - these_loaders); - these_loaders.Go(); - - std::cout << "Saving " << GetSampleName(sample) << std::endl; - predInterpFDNumu.SaveTo(saveDir, - std::string("fd_interp_numu_") + std::string(isfhc ? "fhc" : "rhc")); - std::cout << "Saving " << GetSampleName(sample) << std::endl; - predInterpFDNue.SaveTo(saveDir, - std::string("fd_interp_nue_") + std::string(isfhc ? "fhc" : "rhc")); - - } else if ((sample == kNDFHC) || (sample == kNDRHC) || - (sample == kNDFHC_OA)) { - - // Now ND - Loaders these_loaders; - SpectrumLoader loaderNumu(non_swap_file_list, max); - these_loaders.AddLoader(&loaderNumu, caf::kNEARDET, Loaders::kMC); - - NoOscPredictionGenerator genNDNumu( - *axes.NDAx, - use_selection - ? (isfhc ? kPassND_FHC_NUMU : kPassND_RHC_NUMU) && kIsTrueFV - : kIsTrueFV, - use_cv_weights ? kCVXSecWeights : kUnweighted); - - PredictionInterp predInterpNDNumu(systlist, this_calc, genNDNumu, - these_loaders); - these_loaders.Go(); - - std::cout << "Saving " << GetSampleName(sample) << std::endl; - predInterpNDNumu.SaveTo(saveDir, - std::string("nd_interp_numu_") + std::string(isfhc ? "fhc" : "rhc")); - } -} - -std::vector const sample_dir_order = { - "fd_interp_numu_fhc", "fd_interp_nue_fhc", "fd_interp_numu_rhc", - "fd_interp_nue_rhc", "nd_interp_numu_fhc", "nd_interp_numu_rhc"}; -std::vector const sample_suffix_order = { - "FD_FHC", "FD_FHC", "FD_RHC", "FD_RHC", "ND_FHC", "ND_RHC"}; - -std::vector> -GetPredictionInterps(std::string fileName, - std::vector systlist) { - - // Make sure the syst registry has been populated with all the systs we could - // want to use - static std::vector systs = GetListOfSysts(); - - // Hackity hackity hack hack - bool fileNameIsStub = (fileName.find(".root") == std::string::npos); - - std::vector> return_list; - - for (size_t s_it = 0; s_it < sample_dir_order.size(); ++s_it) { - std::string state_fname = - fileNameIsStub ? fileName + "_" + sample_suffix_order[s_it] + ".root" - : fileName; - TFile *fin = - TFile::Open(state_fname.c_str(), "READ"); // Allows xrootd streaming - assert(fin && !fin->IsZombie()); - std::cout << "[LOAD]: Retrieving " << sample_dir_order[s_it] << " from " - << state_fname << ":" << sample_dir_order[s_it] << std::endl; - return_list.emplace_back(LoadFrom(fin, sample_dir_order[s_it])); - delete fin; - - std::vector systs_to_remove = - return_list.back()->GetAllSysts(); - std::vector used_syst_names; - for (auto s : systlist) { - used_syst_names.push_back(s->ShortName()); - } - RemoveSysts(systs_to_remove, used_syst_names); - if (systs_to_remove.size()) { - return_list.back()->DiscardSysts(systs_to_remove); - } - } - return return_list; -} - -TH2D *make_corr_from_covar(TH2D *covar) { - - TH2D *corr = (TH2D *)covar->Clone(); - corr->SetNameTitle("corr", "corr"); - - for (int i = 0; i < covar->GetNbinsX(); ++i) { - double istddev = sqrt(covar->GetBinContent(i + 1, i + 1)); - for (int j = 0; j < covar->GetNbinsX(); ++j) { - double jstddev = sqrt(covar->GetBinContent(j + 1, j + 1)); - double new_corr = covar->GetBinContent(i + 1, j + 1) / istddev / jstddev; - corr->SetBinContent(i + 1, j + 1, new_corr); - } - } - return corr; -} - -// Yet another string parser that does far too much. I can't be stopped! -void ParseDataSamples(std::string cmdLineInput, - double &pot_nd_fhc, double &pot_nd_rhc, - double &pot_fd_fhc_nue, double &pot_fd_rhc_nue, - double &pot_fd_fhc_numu, double &pot_fd_rhc_numu) { - - // Did somebody say overextend the command line arguments even further? - // Well okay! - std::vector input_vect = SplitString(cmdLineInput, ':'); - - // Default to 7 years staged. Value is actually in kt MW yr - double exposure = nom_exposure; - if (input_vect.size() > 1) - exposure = stod(input_vect[1]); - std::string input = input_vect[0]; - - // LoWeR cAsE sO i CaN bE sIlLy WiTh InPuTs - std::transform(input.begin(), input.end(), input.begin(), ::tolower); - - // Look for some other magic information - for (auto str : input_vect) { - if (str.find("full") != std::string::npos or - str.find("15year") != std::string::npos) - exposure = 1104; - - if (str.find("nom") != std::string::npos or - str.find("7year") != std::string::npos) - exposure = 336; - - if (str.find("10year") != std::string::npos) - exposure = 624; - } - - double exposure_ratio = exposure / nom_exposure; - - // Now sort out which samples to include - pot_nd_fhc = pot_nd_rhc = 0; - pot_fd_fhc_nue = pot_fd_fhc_numu = 0; - pot_fd_rhc_nue = pot_fd_rhc_numu = 0; - - // Hacky McHackerson is here to stay! - if (input.find("nd") != std::string::npos) { - pot_nd_fhc = pot_nd * exposure_ratio; - pot_nd_rhc = pot_nd * exposure_ratio; - } - if (input.find("fd") != std::string::npos) { - pot_fd_fhc_nue = pot_fd_fhc_numu = pot_fd * exposure_ratio; - pot_fd_rhc_nue = pot_fd_rhc_numu = pot_fd * exposure_ratio; - } - - // Now allow specific subsets - if (input.find("fhc") != std::string::npos) { - pot_nd_rhc = pot_fd_rhc_nue = pot_fd_rhc_numu = 0; - } - - if (input.find("rhc") != std::string::npos) { - pot_nd_fhc = pot_fd_fhc_nue = pot_fd_fhc_numu = 0; - } - - if (input.find("numu") != std::string::npos) { - pot_fd_fhc_nue = pot_fd_rhc_nue = 0; - } - - if (input.find("nue") != std::string::npos) { - pot_fd_fhc_numu = pot_fd_rhc_numu = 0; - } - return; -} - -void ParseThrowInstructions(std::string throwString, bool &stats, bool &fakeOA, - bool &fakeNuis, bool &start, bool ¢ral) { - - std::vector instructions = SplitString(throwString, ':'); - - stats = false; - fakeOA = false; - fakeNuis = false; - start = false; - central = false; - - for (auto &str : instructions) { - - std::transform(str.begin(), str.end(), str.begin(), ::tolower); - - if (str == "stat" || str == "all") - stats = true; - if (str == "fake" || str == "all") - fakeOA = fakeNuis = true; - if (str == "fakeoa" || str == "all") - fakeOA = true; - if (str == "fakenuis" || str == "all") - fakeNuis = true; - if (str == "start" || str == "all") - start = true; - if (str == "central" || str == "all") - central = true; - } - return; -} - -TMatrixD *GetNDCovMat(bool UseV3NDCovMat, bool TwoBeams, bool isFHC){ - - auto AnaV = GetAnaVersion(); - - const std::string detCovPath = - "/pnfs/dune/persistent/users/LBL_TDR/CAFs/v4/"; - -#ifndef DONT_USE_FQ_HARDCODED_SYST_PATHS - std::string covFileName = - detCovPath + ((AnaV == kV3) ? "/Systs/det_sys_cov_v3binning.root" - : "/det_sys_cov.root"); -#else - std::string covFileName = - FindCAFAnaDir() + ((AnaV == kV3) ? "/Systs/det_sys_cov_v3binning.root" - : "/Systs/det_sys_cov.root"); -#endif - - std::string this_beam = "all"; - if(!TwoBeams){ - if(isFHC) this_beam = "fhc"; - else this_beam = "rhc"; - } - - // TDirectory *thisDir = gDirectory->CurrentDirectory(); - TFile covMatFile(covFileName.c_str()); - TString covObjectName = "nd_" + this_beam + "_frac_cov"; - TMatrixD *fake_uncorr = (TMatrixD *)covMatFile.Get(covObjectName); - // TMatrixD *fake_uncorr = (TMatrixD *)covMatFile.Get("nd_all_frac_cov"); - if (!fake_uncorr) { - std::cout << "Could not obtain covariance matrix named " - << covObjectName << " from " << covFileName << std::endl; - abort(); - } - - if(!UseV3NDCovMat){ - return fake_uncorr; - } - else{ - std::cout << "[INFO]: Using v3-like ND covmat treadment." << std::endl; - - TMatrixD *covmx_fhc_only = (TMatrixD *)covMatFile.Get("nd_fhc_frac_cov"); - - assert(fake_uncorr->GetNrows() == 2 * covmx_fhc_only->GetNrows()); - - size_t NRows = fake_uncorr->GetNrows(); - size_t NRows_FHC = covmx_fhc_only->GetNrows(); - - for (size_t row_it = 0; row_it < NRows; ++row_it) { - for (size_t col_it = 0; col_it < NRows; ++col_it) { - - // Could use TMatrix::SetSub but I don't trust TMatrix... - if (((row_it >= NRows_FHC) && (col_it < NRows_FHC)) || - ((row_it < NRows_FHC) && (col_it >= NRows_FHC))) { - (*fake_uncorr)[row_it][col_it] = 0;} - else { - size_t row_fhc_only_it = row_it % NRows_FHC; - size_t col_fhc_only_it = col_it % NRows_FHC; - (*fake_uncorr)[row_it][col_it] = - (*covmx_fhc_only)[row_fhc_only_it][col_fhc_only_it]; - } - } - } - - return fake_uncorr; - } -} - -TMatrixD *MakeCovmat(PredictionInterp const &prediction, - std::vector const &systs, - osc::IOscCalcAdjustable *calc, size_t NToys, - TDirectory *outdir) { - std::vector> ThrownSpectra; - std::vector MeanSpectra; - - SystShifts shift; - - if (outdir) { - outdir->cd(); - std::unique_ptr nominal_spectra( - prediction.PredictSyst(calc, kNoShift).ToTH1(1)); - nominal_spectra->Write("nominal_throw_spectra"); - nominal_spectra->SetDirectory(nullptr); - } - - size_t NBins = std::numeric_limits::max(); - for (size_t t_it = 0; t_it < NToys; ++t_it) { // throws - - shift.ResetToNominal(); - // Throw new param values - for (auto s : systs) { - double v = GetBoundedGausThrow(s->Min(), s->Max()); - shift.SetShift(s, v); - } - - // Make prediction TH1 - std::unique_ptr thrown_spectra( - prediction.PredictSyst(calc, shift).ToTH1(1)); - if (outdir) { - thrown_spectra->Write( - (std::string("thrown_spectra_") + std::to_string(t_it)).c_str()); - } - thrown_spectra->SetDirectory(nullptr); - - if (NBins == std::numeric_limits::max()) { - NBins = thrown_spectra->GetXaxis()->GetNbins(); - - ThrownSpectra = std::vector>( - NToys, std::vector(NBins, 0)); - MeanSpectra = std::vector(NBins, 0); - } - - for (size_t bi_it = 0; bi_it < NBins; ++bi_it) { // spectra bins - double bin_throw = thrown_spectra->GetBinContent(bi_it + 1); - MeanSpectra[bi_it] += bin_throw; - ThrownSpectra[t_it][bi_it] = bin_throw; - } - } - - for (double &bc : MeanSpectra) { - bc /= double(NToys); - } - - // Build covmat - TMatrixD *mat = new TMatrixD(NBins, NBins); - - for (size_t rbi_it = 0; rbi_it < NBins; ++rbi_it) { - for (size_t cbi_it = 0; cbi_it < NBins; ++cbi_it) { - mat->operator()(rbi_it, cbi_it) = 0; - } - } - double nthrow_fact = 1.0 / double(NToys - 1); - - for (size_t t_it = 0; t_it < NToys; ++t_it) { // throws - for (size_t rbi_it = 0; rbi_it < NBins; ++rbi_it) { - for (size_t cbi_it = 0; cbi_it < NBins; ++cbi_it) { - double rdiff = (ThrownSpectra[t_it][rbi_it] / MeanSpectra[rbi_it]) - 1; - double cdiff = (ThrownSpectra[t_it][cbi_it] / MeanSpectra[cbi_it]) - 1; - mat->operator()(rbi_it, cbi_it) += (rdiff * cdiff * nthrow_fact); - } - } - } - return mat; -} - -void SaveTrueOAParams(TDirectory *outDir, osc::IOscCalcAdjustable *calc, - std::string tree_name) { - - outDir->cd(); - double L = calc->GetL(); - double rho = calc->GetRho(); - double dmsq21 = calc->GetDmsq21(); - double dmsq32 = calc->GetDmsq32(); - double th12 = calc->GetTh12(); - double th13 = calc->GetTh13(); - double th23 = calc->GetTh23(); - double ssth23 = sin(calc->GetTh23()) * sin(calc->GetTh23()); - double deltapi = calc->GetdCP() / TMath::Pi(); - - TTree *tree = new TTree(tree_name.c_str(), tree_name.c_str()); - tree->Branch("L", &L); - tree->Branch("rho", &rho); - tree->Branch("dmsq21", &dmsq21); - tree->Branch("dmsq32", &dmsq32); - tree->Branch("th12", &th12); - tree->Branch("th13", &th13); - tree->Branch("th23", &th23); - tree->Branch("ssth23", &ssth23); - tree->Branch("deltapi", &deltapi); - tree->Fill(); - tree->Write(); - return; -} - -void SaveParams(TDirectory *outDir, std::vector systlist) { - outDir->cd(); - std::vector *fParamNames = new std::vector(); - for (auto it : systlist) - fParamNames->push_back(it->ShortName()); - TTree *t = new TTree("meta", "Parameter meta-data"); - t->Branch("fParamNames", &fParamNames); - t->Fill(); - t->Write(); - delete fParamNames; - delete t; -} - -FitTreeBlob::FitTreeBlob(std::string tree_name, std::string meta_tree_name) - : fMeta_filled(false), throw_tree(nullptr), meta_tree(nullptr), fNFills(0) { - - fFakeDataVals = new std::vector(); - fParamNames = new std::vector(); - fPreFitValues = new std::vector(); - fPreFitErrors = new std::vector(); - fPostFitValues = new std::vector(); - fPostFitErrors = new std::vector(); - fCentralValues = new std::vector(); - fEnvVarNames = new std::vector(); - fEnvVarValues = new std::vector(); - fSpectraRNGSeeds = new std::vector(); - - TDirectory *odir = gDirectory; - - if (tree_name.size()) { - - throw_tree = new TTree(tree_name.c_str(), "Fit information"); - throw_tree->SetAutoSave(10); - throw_tree->Branch("chisq", &fChiSq); - throw_tree->Branch("NSeconds", &fNSeconds); - throw_tree->Branch("ResMemUsage", &fResMemUsage); - throw_tree->Branch("VirtMemUsage", &fVirtMemUsage); - throw_tree->Branch("NFCN", &fNFCN); - throw_tree->Branch("EDM", &fEDM); - throw_tree->Branch("IsValid", &fIsValid); - throw_tree->Branch("fFakeDataVals", &fFakeDataVals); - throw_tree->Branch("fPreFitValues", &fPreFitValues); - throw_tree->Branch("fPreFitErrors", &fPreFitErrors); - throw_tree->Branch("fPostFitValues", &fPostFitValues); - throw_tree->Branch("fPostFitErrors", &fPostFitErrors); - throw_tree->Branch("fCentralValues", &fCentralValues); - throw_tree->Branch("LoopRNGSeed", &fLoopRNGSeed); - throw_tree->Branch("JobRNGSeed", &fJobRNGSeed); - throw_tree->Branch("SpectraRNGSeeds", &fSpectraRNGSeeds); - throw_tree->Branch("ProcFitN", &fNFills); - throw_tree->Branch("NOscSeeds", &fNOscSeeds); - - if (meta_tree_name.size()) { - - meta_tree = new TTree(meta_tree_name.c_str(), "Parameter meta-data"); - meta_tree->SetAutoSave(10); - meta_tree->Branch("fParamNames", &fParamNames); - meta_tree->Branch("fEnvVarNames", &fEnvVarNames); - meta_tree->Branch("fEnvVarValues", &fEnvVarValues); - meta_tree->Branch("JobRNGSeed", &fJobRNGSeed); -#ifdef USE_PREDINTERP_OMP - meta_tree->Branch("NMaxThreads", &fNMaxThreads); -#endif - } - } - - if (odir) { - odir->cd(); - } -} - -FitTreeBlob *FitTreeBlob::MakeReader(TTree *t, TTree *m) { - FitTreeBlob *ftb = new FitTreeBlob(); - t->SetBranchAddress("chisq", &ftb->fChiSq); - t->SetBranchAddress("NSeconds", &ftb->fNSeconds); - t->SetBranchAddress("ResMemUsage", &ftb->fResMemUsage); - t->SetBranchAddress("VirtMemUsage", &ftb->fVirtMemUsage); - t->SetBranchAddress("NFCN", &ftb->fNFCN); - t->SetBranchAddress("EDM", &ftb->fEDM); - t->SetBranchAddress("IsValid", &ftb->fIsValid); - t->SetBranchAddress("fFakeDataVals", &ftb->fFakeDataVals); - t->SetBranchAddress("fPreFitValues", &ftb->fPreFitValues); - t->SetBranchAddress("fPreFitErrors", &ftb->fPreFitErrors); - t->SetBranchAddress("fPostFitValues", &ftb->fPostFitValues); - t->SetBranchAddress("fPostFitErrors", &ftb->fPostFitErrors); - t->SetBranchAddress("fCentralValues", &ftb->fCentralValues); - t->SetBranchAddress("LoopRNGSeed", &ftb->fLoopRNGSeed); - t->SetBranchAddress("JobRNGSeed", &ftb->fJobRNGSeed); - t->SetBranchAddress("SpectraRNGSeeds", &ftb->fSpectraRNGSeeds); - t->SetBranchAddress("ProcFitN", &ftb->fNFills); - t->SetBranchAddress("NOscSeeds", &ftb->fNOscSeeds); - - m->SetBranchAddress("fParamNames", &ftb->fParamNames); - m->SetBranchAddress("fEnvVarNames", &ftb->fEnvVarNames); - m->SetBranchAddress("fEnvVarValues", &ftb->fEnvVarValues); - m->SetBranchAddress("JobRNGSeed", &ftb->fJobRNGSeed); -#ifdef USE_PREDINTERP_OMP - m->SetBranchAddress("NMaxThreads", &ftb->fNMaxThreads); -#endif - return ftb; -} -FitTreeBlob::~FitTreeBlob() { - delete fFakeDataVals; - delete fParamNames; - delete fPreFitValues; - delete fPreFitErrors; - delete fPostFitValues; - delete fPostFitErrors; - delete fCentralValues; - delete fEnvVarNames; - delete fEnvVarValues; - delete fSpectraRNGSeeds; -} -void FitTreeBlob::CopyVals(FitTreeBlob const &fb) { - (*fFakeDataVals) = (*fb.fFakeDataVals); - (*fParamNames) = (*fb.fParamNames); - (*fEnvVarNames) = (*fb.fEnvVarNames); - (*fEnvVarValues) = (*fb.fEnvVarValues); - (*fPreFitValues) = (*fb.fPreFitValues); - (*fPreFitErrors) = (*fb.fPreFitErrors); - (*fPostFitValues) = (*fb.fPostFitValues); - (*fPostFitErrors) = (*fb.fPostFitErrors); - (*fCentralValues) = (*fb.fCentralValues); - (*fSpectraRNGSeeds) = (*fb.fSpectraRNGSeeds); - fChiSq = fb.fChiSq; - fNFCN = fb.fNFCN; - fEDM = fb.fEDM; - fIsValid = fb.fIsValid; - fNSeconds = fb.fNSeconds; - fResMemUsage = fb.fResMemUsage; - fVirtMemUsage = fb.fVirtMemUsage; - fLoopRNGSeed = fb.fLoopRNGSeed; - fJobRNGSeed = fb.fJobRNGSeed; - fNFills = fb.fNFills; - fNOscSeeds = fb.fNOscSeeds; -#ifdef USE_PREDINTERP_OMP - fNMaxThreads = fb.fNMaxThreads; -#endif -} -void FitTreeBlob::Fill() { - if (throw_tree) { - throw_tree->Fill(); - } - - if (meta_tree && !fMeta_filled) { - meta_tree->Fill(); - fMeta_filled = true; - } - - fNFills++; -} -void FitTreeBlob::SetDirectory(TDirectory *d) { - if (throw_tree) { - throw_tree->SetDirectory(d); - } - if (meta_tree) { - meta_tree->SetDirectory(d); - } -} -void FitTreeBlob::SetDirectoryClone(TDirectory *d) { - if (!d) { - return; - } - if (throw_tree) { - TTree *clone = throw_tree->CloneTree(); - clone->ResetBranchAddresses(); - clone->SetDirectory(d); - throw_tree->SetDirectory(nullptr); - } - if (meta_tree) { - TTree *clone = meta_tree->CloneTree(); - clone->ResetBranchAddresses(); - clone->SetDirectory(d); - meta_tree->SetDirectory(nullptr); - } -} -void FitTreeBlob::Write() { - if (throw_tree) { - throw_tree->Write(); - } - if (meta_tree) { - meta_tree->Write(); - } -} -void FitTreeBlob::WriteClone() { - if (throw_tree) { - TTree *clone = throw_tree->CloneTree(); - clone->ResetBranchAddresses(); - clone->Write(); - throw_tree->SetDirectory(nullptr); - } - if (meta_tree) { - TTree *clone = meta_tree->CloneTree(); - clone->ResetBranchAddresses(); - clone->Write(); - meta_tree->SetDirectory(nullptr); - } -} - -std::string BuildLogInfoString() { - auto now = std::chrono::system_clock::now(); - std::time_t now_time = std::chrono::system_clock::to_time_t(now); - ProcInfo_t procinfo; - gSystem->GetProcInfo(&procinfo); - MemInfo_t meminfo; - gSystem->GetMemInfo(&meminfo); - - std::stringstream ss(""); - ss << " (ProcResMem: " << (double(procinfo.fMemResident) / 1E6) << " GB) @ " - << std::ctime(&now_time); - - return ss.str(); -} - -Spectrum MockOrAsimov(const Spectrum& s, bool mock, double pot, int seed) -{ - if(mock > 0) return s.MockData(pot, seed); else return s.AsimovData(pot); -} - -std::vector -BuildSpectra(PredictionInterp *predFDNumuFHC, PredictionInterp *predFDNueFHC, - PredictionInterp *predFDNumuRHC, PredictionInterp *predFDNueRHC, - PredictionInterp *predNDNumuFHC, PredictionInterp *predNDNumuRHC, - osc::IOscCalcAdjustable *fakeDataOsc, - SystShifts fakeDataSyst, bool fakeDataStats, double pot_fd_fhc_nue, - double pot_fd_fhc_numu, double pot_fd_rhc_nue, - double pot_fd_rhc_numu, double pot_nd_fhc, double pot_nd_rhc, - std::vector const &Seeds) { - std::vector spectra; - size_t iseed = 0; - - // Ordering of these is important - // kFDNueFHC - if (predFDNueFHC) { - spectra.emplace_back(Seeds[iseed], - std::make_unique(MockOrAsimov(predFDNueFHC->PredictSyst(fakeDataOsc, fakeDataSyst), fakeDataStats, pot_fd_fhc_nue, Seeds[iseed]))); - iseed++; - } - // kFDNumuFHC - if (predFDNumuFHC) { - spectra.emplace_back(Seeds[iseed], - std::make_unique(MockOrAsimov(predFDNumuFHC->PredictSyst(fakeDataOsc, fakeDataSyst), fakeDataStats, pot_fd_fhc_numu, Seeds[iseed]))); - iseed++; - } - // kFDNueRHC - if (predFDNueRHC) { - spectra.emplace_back(Seeds[iseed], - std::make_unique(MockOrAsimov(predFDNueRHC->PredictSyst(fakeDataOsc, fakeDataSyst), fakeDataStats, pot_fd_rhc_nue, Seeds[iseed]))); - iseed++; - } - // kFDNumuRHC - if (predFDNumuRHC) { - spectra.emplace_back(Seeds[iseed], - std::make_unique(MockOrAsimov(predFDNumuRHC->PredictSyst(fakeDataOsc, fakeDataSyst), fakeDataStats, pot_fd_rhc_numu, Seeds[iseed]))); - iseed++; - } - // kNDNumuFHC - if (predNDNumuFHC) { - spectra.emplace_back(Seeds[iseed], - std::make_unique(MockOrAsimov(predNDNumuFHC->PredictSyst(fakeDataOsc, fakeDataSyst), fakeDataStats, pot_nd_fhc, Seeds[iseed]))); - iseed++; - } - // kNDNumuRHC - if (predNDNumuRHC) { - spectra.emplace_back(Seeds[iseed], - std::make_unique(MockOrAsimov(predNDNumuRHC->PredictSyst(fakeDataOsc, fakeDataSyst), fakeDataStats, pot_nd_rhc, Seeds[iseed]))); - iseed++; - } - - return spectra; -} - -double RunFitPoint(std::string stateFileName, std::string sampleString, - osc::IOscCalcAdjustable *fakeDataOsc, - SystShifts fakeDataSyst, bool fakeDataStats, - std::vector oscVars, - std::vector systlist, - osc::IOscCalcAdjustable *fitOsc, SystShifts fitSyst, - ana::SeedList oscSeeds, IExperiment *penaltyTerm, - MinuitFitter::FitOpts fitStrategy, TDirectory *outDir, - FitTreeBlob *PostFitTreeBlob, - std::vector *spectra, SystShifts &bf) { - - assert(systlist.size() + oscVars.size()); - - auto AnaV = GetAnaVersion(); - - bool turbose = false; - if (getenv("CAFANA_FIT_TURBOSE") && - bool(atoi(getenv("CAFANA_FIT_TURBOSE")))) { - turbose = true; - } - -#ifdef USE_PREDINTERP_OMP - size_t maxthreads = omp_get_max_threads(); - if (maxthreads > 4) { - std::cerr << "[INFO]: Cannot run with OMP_NUM_THREADS > 4" << std::endl; - abort(); - } - if (PostFitTreeBlob) { - PostFitTreeBlob->fNMaxThreads = maxthreads; - } -#endif - - // Start by getting the PredictionInterps... better that this is done here - // than elsewhere as they aren't smart enough to know what they are (so the - // order matters) Note that all systs are used to load the PredictionInterps - static bool first_load = true; - static auto start_load = std::chrono::system_clock::now(); - - static bool PI_load = true; - static std::vector syststoload = systlist; - if (PI_load) { - - for (auto &env_str : - {"CAFANA_ANALYSIS_VERSION", "CAFANA_USE_UNCORRNDCOVMAT", - "CAFANA_USE_NDCOVMAT", "CAFANA_IGNORE_CV_WEIGHT", - "CAFANA_IGNORE_SELECTION", "CAFANA_DISABLE_DERIVATIVES", - "CAFANA_DONT_CLAMP_SYSTS", "CAFANA_FIT_TURBOSE", - "CAFANA_FIT_FORCE_HESSE", "CAFANA_PRED_MINMCSTATS", "FIT_PRECISION", - "FIT_TOLERANCE", "SLURM_JOB_ID", "SLURM_PROCID", "SLURM_NODEID", - "SLURM_LOCALID"}) { - if (getenv(env_str)) { - std::cout << "[ENV]: " << env_str << " = " << getenv(env_str) - << std::endl; - if (PostFitTreeBlob) { - PostFitTreeBlob->fEnvVarNames->push_back(env_str); - PostFitTreeBlob->fEnvVarValues->push_back(getenv(env_str)); - } - } - } - - std::vector fdlos = - GetListOfSysts(false, false, false, false, false, false, - true /*add fake data*/, false); - syststoload.insert(syststoload.end(), fdlos.begin(), fdlos.end()); - PI_load = false; - } - - static std::vector> interp_list = - GetPredictionInterps(stateFileName, syststoload); - - static PredictionInterp &predFDNumuFHC = *interp_list[0].release(); - static PredictionInterp &predFDNueFHC = *interp_list[1].release(); - static PredictionInterp &predFDNumuRHC = *interp_list[2].release(); - static PredictionInterp &predFDNueRHC = *interp_list[3].release(); - static PredictionInterp &predNDNumuFHC = *interp_list[4].release(); - static PredictionInterp &predNDNumuRHC = *interp_list[5].release(); - if (first_load) { - static auto end_load = std::chrono::system_clock::now(); - std::cerr << "[LOAD]: Done in " - << std::chrono::duration_cast(end_load - - start_load) - .count() - << " s " << BuildLogInfoString(); - first_load = false; - } - - // String parsing time! - double pot_nd_fhc, pot_nd_rhc, pot_fd_fhc_nue, pot_fd_rhc_nue, - pot_fd_fhc_numu, pot_fd_rhc_numu; - ParseDataSamples(sampleString, pot_nd_fhc, pot_nd_rhc, pot_fd_fhc_nue, - pot_fd_rhc_nue, pot_fd_fhc_numu, pot_fd_rhc_numu); - - // If a directory has been given, a whole mess of stuff will be saved there. - if (outDir) { - outDir->cd(); - } - - // Need to make a fake throw list for later book-keeping - std::vector fFakeDataVals; - for (const IFitVar *v : oscVars) - fFakeDataVals.push_back(v->GetValue(fakeDataOsc)); - for (const ISyst *s : systlist) - fFakeDataVals.push_back(fakeDataSyst.GetShift(s)); - - // One problem with this method is that the experiments are reproduced for - // every single call... Set up the fake data histograms, and save them if - // relevant... This came back to bite me. I need to do multiple fits with the - // same fake data throw, so I need these to persist between calls to this - // function Sadly, the locked down ownership etc means I can't think of a - // better solution to this And the alternative CAFAna is probably just - // copy-pasta-ing this function in all of the scripts that use it... - std::vector LastShredsOfMyDignityAndSanity; - if (!spectra) { - spectra = &LastShredsOfMyDignityAndSanity; - } - - if (!spectra->size()) { - - if (turbose) { - std::cout << "[INFO]: Loading spectra. " << BuildLogInfoString() - << std::endl; - } - - std::vector seeds; - for (size_t i = 0; i < 6; ++i) { - seeds.push_back(gRandom->Integer(std::numeric_limits::max())); - } - - (*spectra) = BuildSpectra(&predFDNumuFHC, &predFDNueFHC, &predFDNumuRHC, - &predFDNueRHC, &predNDNumuFHC, &predNDNumuRHC, - fakeDataOsc, fakeDataSyst, fakeDataStats, - pot_fd_fhc_nue, pot_fd_fhc_numu, pot_fd_rhc_nue, - pot_fd_rhc_numu, pot_nd_fhc, pot_nd_rhc, seeds); - } - - if (turbose) { - std::cout << "[INFO]: Have fit spectra. " << BuildLogInfoString() - << std::endl; - } - if (turbose) { - std::cout << "[INFO]: Setting up experiments. " << BuildLogInfoString() - << std::endl; - } - - // If using the multi sample covariances then they must be added to the - // MultiExperiment - SingleSampleExperiment app_expt_fhc(&predFDNueFHC, - *spectra->at(kFDNueFHC).spect); - app_expt_fhc.SetMaskHist(0.5, (AnaV == kV4) ? 10 : 8); - - SingleSampleExperiment dis_expt_fhc(&predFDNumuFHC, - *spectra->at(kFDNumuFHC).spect); - dis_expt_fhc.SetMaskHist(0.5, (AnaV == kV4) ? 10 : 8); - - SingleSampleExperiment app_expt_rhc(&predFDNueRHC, - *spectra->at(kFDNueRHC).spect); - app_expt_rhc.SetMaskHist(0.5, (AnaV == kV4) ? 10 : 8); - - SingleSampleExperiment dis_expt_rhc(&predFDNumuRHC, - *spectra->at(kFDNumuRHC).spect); - dis_expt_rhc.SetMaskHist(0.5, (AnaV == kV4) ? 10 : 8); - - IExperiment *nd_expt_fhc = 0, *nd_expt_rhc = 0; - CovarianceExperiment* nd_expt_joint = 0; - - bool UseNDCovMat = true; - if (getenv("CAFANA_USE_NDCOVMAT")) { - UseNDCovMat = bool(atoi(getenv("CAFANA_USE_NDCOVMAT"))); - } - - bool UseV3NDCovMat = (AnaV == kV3); - if (getenv("CAFANA_USE_UNCORRNDCOVMAT")) { - UseV3NDCovMat = bool(atoi(getenv("CAFANA_USE_UNCORRNDCOVMAT"))); - } - - // JOINT COVARIANCE CASE HERE. - // The analyses were only performed with both beams when using the covariance matrix. - // So there was no option for joint or no joint matrix case. - - if (UseNDCovMat && (pot_nd_rhc > 0) && (pot_nd_fhc > 0)) { - if (turbose) { - std::cout << "[INFO]: Opening ND covmat file for CovarianceExperiment" << BuildLogInfoString() - << std::endl; - } - - TMatrixD* joint_matrix = GetNDCovMat(UseV3NDCovMat, true, true); - - nd_expt_joint = new CovarianceExperiment({&predNDNumuFHC, &predNDNumuRHC}, - {*spectra->at(kNDNumuFHC).spect, - *spectra->at(kNDNumuRHC).spect}, - joint_matrix, - kCovMxChiSqPreInvert); - - // //// Invert the assignation. Let's see if the old AddCovMatrix to MultiExperiment was messing thing up (?) - // nd_expt_joint = new CovarianceExperiment({&predNDNumuRHC, &predNDNumuFHC}, - // {*spectra->at(kNDNumuRHC).spect, - // *spectra->at(kNDNumuFHC).spect}, - // joint_matrix, - // kCovMxChiSqPreInvert); - nd_expt_joint->SetMaskHist(0, 0.5, (AnaV == kV4) ? 10 : 8, 0, -1); - nd_expt_joint->SetMaskHist(1, 0.5, (AnaV == kV4) ? 10 : 8, 0, -1); - } - else{ - auto e = new SingleSampleExperiment(&predNDNumuFHC, - *spectra->at(kNDNumuFHC).spect); - - e->SetMaskHist(0.5, (AnaV == kV4) ? 10 : 8, 0, -1); - nd_expt_fhc = e; - - e = new SingleSampleExperiment(&predNDNumuRHC, - *spectra->at(kNDNumuRHC).spect); - - e->SetMaskHist(0.5, (AnaV == kV4) ? 10 : 8, 0, -1); - nd_expt_rhc = e; - } - - if (PostFitTreeBlob) { - // Save the seeds used to do the stats throws - (*PostFitTreeBlob->fSpectraRNGSeeds) = std::vector{ - spectra->at(kFDNueFHC).stats_seed, spectra->at(kFDNumuFHC).stats_seed, - spectra->at(kFDNueRHC).stats_seed, spectra->at(kFDNumuRHC).stats_seed, - spectra->at(kNDNumuFHC).stats_seed, spectra->at(kNDNumuRHC).stats_seed}; - } - - if (turbose) { - std::cout << "[INFO]: Have experiments. " << BuildLogInfoString() - << std::endl; - } - - // Save prefit starting distributions - if (outDir) { - - if (turbose) { - std::cout << "[INFO]: Saving prefit info. " << BuildLogInfoString() - << std::endl; - } - - if (pot_fd_fhc_nue > 0) { - TH1 *data_nue_fhc_hist = - spectra->at(kFDNueFHC).spect->ToTHX(pot_fd_fhc_nue); - data_nue_fhc_hist->SetName("data_fd_nue_fhc"); - data_nue_fhc_hist->Write(); - TH1 *pre_fd_nue_fhc = GetMCSystTotal(&predFDNueFHC, fitOsc, fitSyst, - "prefit_fd_nue_fhc", pot_fd_fhc_nue); - pre_fd_nue_fhc->SetTitle( - std::to_string(app_expt_fhc.ChiSq(fitOsc, fitSyst)).c_str()); - pre_fd_nue_fhc->Write(); - } - if (pot_fd_fhc_numu > 0) { - TH1 *data_numu_fhc_hist = - spectra->at(kFDNumuFHC).spect->ToTHX(pot_fd_fhc_numu); - data_numu_fhc_hist->SetName("data_fd_numu_fhc"); - data_numu_fhc_hist->Write(); - TH1 *pre_fd_numu_fhc = - GetMCSystTotal(&predFDNumuFHC, fitOsc, fitSyst, "prefit_fd_numu_fhc", - pot_fd_fhc_numu); - pre_fd_numu_fhc->SetTitle( - std::to_string(dis_expt_fhc.ChiSq(fitOsc, fitSyst)).c_str()); - pre_fd_numu_fhc->Write(); - } - if (pot_fd_rhc_nue > 0) { - TH1 *data_nue_rhc_hist = - spectra->at(kFDNueRHC).spect->ToTHX(pot_fd_rhc_nue); - data_nue_rhc_hist->SetName("data_fd_nue_rhc"); - data_nue_rhc_hist->Write(); - TH1 *pre_fd_nue_rhc = GetMCSystTotal(&predFDNueRHC, fitOsc, fitSyst, - "prefit_fd_nue_rhc", pot_fd_rhc_nue); - pre_fd_nue_rhc->SetTitle( - std::to_string(app_expt_rhc.ChiSq(fitOsc, fitSyst)).c_str()); - pre_fd_nue_rhc->Write(); - } - if (pot_fd_rhc_numu > 0) { - TH1 *data_numu_rhc_hist = - spectra->at(kFDNumuRHC).spect->ToTHX(pot_fd_rhc_numu); - data_numu_rhc_hist->SetName("data_fd_numu_rhc"); - data_numu_rhc_hist->Write(); - TH1 *pre_fd_numu_rhc = - GetMCSystTotal(&predFDNumuRHC, fitOsc, fitSyst, "prefit_fd_numu_rhc", - pot_fd_rhc_numu); - pre_fd_numu_rhc->SetTitle( - std::to_string(dis_expt_rhc.ChiSq(fitOsc, fitSyst)).c_str()); - pre_fd_numu_rhc->Write(); - } - if (pot_nd_fhc > 0) { - TH1 *nd_data_numu_fhc_hist = - spectra->at(kNDNumuFHC).spect->ToTHX(pot_nd_fhc); - TH1 *nd_data_numu_fhc_hist_1D = - spectra->at(kNDNumuFHC).spect->ToTH1(pot_nd_fhc); - nd_data_numu_fhc_hist->SetName("data_nd_numu_fhc"); - nd_data_numu_fhc_hist_1D->SetName("data_nd_numu_fhc_1D"); - nd_data_numu_fhc_hist->Write(); - nd_data_numu_fhc_hist_1D->Write(); - - TH1 *pre_nd_numu_fhc = GetMCSystTotal(&predNDNumuFHC, fitOsc, fitSyst, - "prefit_nd_numu_fhc", pot_nd_fhc); - pre_nd_numu_fhc->SetTitle( - std::to_string(nd_expt_fhc->ChiSq(fitOsc, fitSyst)).c_str()); - pre_nd_numu_fhc->Write(); - TH1 *pre_nd_numu_fhc_1D = - GetMCSystTotal(&predNDNumuFHC, fitOsc, fitSyst, - "prefit_nd_numu_fhc_1D", pot_nd_fhc, true); - pre_nd_numu_fhc_1D->SetTitle( - std::to_string(nd_expt_fhc->ChiSq(fitOsc, fitSyst)).c_str()); - pre_nd_numu_fhc_1D->Write(); - } - if (pot_nd_rhc) { - TH1 *nd_data_numu_rhc_hist = - spectra->at(kNDNumuRHC).spect->ToTHX(pot_nd_rhc); - TH1 *nd_data_numu_rhc_hist_1D = - spectra->at(kNDNumuRHC).spect->ToTH1(pot_nd_rhc); - nd_data_numu_rhc_hist->SetName("data_nd_numu_rhc"); - nd_data_numu_rhc_hist_1D->SetName("data_nd_numu_rhc_1D"); - nd_data_numu_rhc_hist->Write(); - nd_data_numu_rhc_hist_1D->Write(); - - TH1 *pre_nd_numu_rhc = GetMCSystTotal(&predNDNumuRHC, fitOsc, fitSyst, - "prefit_nd_numu_rhc", pot_nd_rhc); - pre_nd_numu_rhc->SetTitle( - std::to_string(nd_expt_rhc->ChiSq(fitOsc, fitSyst)).c_str()); - pre_nd_numu_rhc->Write(); - TH1 *pre_nd_numu_rhc_1D = - GetMCSystTotal(&predNDNumuRHC, fitOsc, fitSyst, - "prefit_nd_numu_rhc_1D", pot_nd_rhc, true); - pre_nd_numu_rhc_1D->SetTitle( - std::to_string(nd_expt_rhc->ChiSq(fitOsc, fitSyst)).c_str()); - pre_nd_numu_rhc_1D->Write(); - } - - if (turbose) { - std::cout << "[INFO]: Done writing prefit " << BuildLogInfoString() - << std::endl; - } - } - - // Now sort out the experiment - MultiExperiment this_expt; - if(nd_expt_joint){ - this_expt.Add(nd_expt_joint); - } - else{ - if (pot_nd_fhc > 0) - this_expt.Add(nd_expt_fhc); - if (pot_nd_rhc > 0) - this_expt.Add(nd_expt_rhc); - } - if (pot_fd_fhc_numu > 0) - this_expt.Add(&dis_expt_fhc); - if (pot_fd_rhc_numu > 0) - this_expt.Add(&dis_expt_rhc); - if (pot_fd_fhc_nue > 0) - this_expt.Add(&app_expt_fhc); - if (pot_fd_rhc_nue > 0) - this_expt.Add(&app_expt_rhc); - - if (turbose) { - std::cout << "[INFO]: Built multi-experiment " << BuildLogInfoString() - << std::endl; - } - - // Add in the penalty... - if (penaltyTerm) { - this_expt.Add(penaltyTerm); - } - - auto start_fit = std::chrono::system_clock::now(); - // Now set up the fit itself - std::cerr << "[INFO]: Beginning fit. " << BuildLogInfoString(); - MinuitFitter this_fit(&this_expt, oscVars, systlist, fitStrategy); - double thischisq = - this_fit.Fit(fitOsc, fitSyst, oscSeeds, {}, MinuitFitter::kVerbose)->EvalMetricVal(); - auto end_fit = std::chrono::system_clock::now(); - std::time_t end_fit_time = std::chrono::system_clock::to_time_t(end_fit); - std::cerr << "[FIT]: Finished fit in " - << std::chrono::duration_cast(end_fit - - start_fit) - .count() - << " s after " << this_fit.GetNFCN() << " iterations " - << BuildLogInfoString(); - - bf = fitSyst; - - // If we have a directory to save to... save some stuff... - if (outDir) { - if (turbose) { - std::cout << "[INFO]: Writing fit tree " << BuildLogInfoString(); - } - std::vector fParamNames = this_fit.GetParamNames(); - std::vector fPreFitValues = this_fit.GetPreFitValues(); - std::vector fPreFitErrors = this_fit.GetPreFitErrors(); - std::vector fPostFitValues = this_fit.GetPostFitValues(); - std::vector fPostFitErrors = this_fit.GetPostFitErrors(); - std::vector fCentralValues = this_fit.GetCentralValues(); - double fNFCN = this_fit.GetNFCN(); - double fEDM = this_fit.GetEDM(); - bool fIsValid = this_fit.GetIsValid(); - - TMatrixDSym covar = this_fit.GetCovariance(); - TH2D hist_covar = TH2D(covar); - hist_covar.SetName("covar"); - TH2D hist_corr = *make_corr_from_covar(&hist_covar); - - if (turbose) { - std::cout << "[INFO]: Writing postfit spectra " << BuildLogInfoString() - << std::endl; - } - - if (pot_fd_fhc_nue) { - TH1 *post_fd_nue_fhc = GetMCSystTotal( - &predFDNueFHC, fitOsc, fitSyst, "postfit_fd_nue_fhc", pot_fd_fhc_nue); - post_fd_nue_fhc->SetTitle( - std::to_string(app_expt_fhc.ChiSq(fitOsc, fitSyst)).c_str()); - post_fd_nue_fhc->Write(); - } - if (pot_fd_fhc_numu) { - TH1 *post_fd_numu_fhc = - GetMCSystTotal(&predFDNumuFHC, fitOsc, fitSyst, "postfit_fd_numu_fhc", - pot_fd_fhc_numu); - post_fd_numu_fhc->SetTitle( - std::to_string(dis_expt_fhc.ChiSq(fitOsc, fitSyst)).c_str()); - post_fd_numu_fhc->Write(); - } - if (pot_fd_rhc_nue) { - TH1 *post_fd_nue_rhc = GetMCSystTotal( - &predFDNueRHC, fitOsc, fitSyst, "postfit_fd_nue_rhc", pot_fd_rhc_nue); - post_fd_nue_rhc->SetTitle( - std::to_string(app_expt_rhc.ChiSq(fitOsc, fitSyst)).c_str()); - post_fd_nue_rhc->Write(); - } - if (pot_fd_rhc_numu) { - TH1 *post_fd_numu_rhc = - GetMCSystTotal(&predFDNumuRHC, fitOsc, fitSyst, "postfit_fd_numu_rhc", - pot_fd_rhc_numu); - post_fd_numu_rhc->SetTitle( - std::to_string(dis_expt_rhc.ChiSq(fitOsc, fitSyst)).c_str()); - post_fd_numu_rhc->Write(); - } - if (pot_nd_fhc) { - TH1 *post_nd_numu_fhc = GetMCSystTotal(&predNDNumuFHC, fitOsc, fitSyst, - "postfit_nd_numu_fhc", pot_nd_fhc); - post_nd_numu_fhc->SetTitle( - std::to_string(nd_expt_fhc->ChiSq(fitOsc, fitSyst)).c_str()); - post_nd_numu_fhc->Write(); - TH1 *post_nd_numu_fhc_1D = - GetMCSystTotal(&predNDNumuFHC, fitOsc, fitSyst, - "postfit_nd_numu_fhc_1D", pot_nd_fhc, true); - post_nd_numu_fhc_1D->SetTitle( - std::to_string(nd_expt_fhc->ChiSq(fitOsc, fitSyst)).c_str()); - post_nd_numu_fhc_1D->Write(); - } - if (pot_nd_rhc) { - TH1 *post_nd_numu_rhc = GetMCSystTotal(&predNDNumuRHC, fitOsc, fitSyst, - "postfit_nd_numu_rhc", pot_nd_rhc); - post_nd_numu_rhc->SetTitle( - std::to_string(nd_expt_rhc->ChiSq(fitOsc, fitSyst)).c_str()); - post_nd_numu_rhc->Write(); - TH1 *post_nd_numu_rhc_1D = - GetMCSystTotal(&predNDNumuRHC, fitOsc, fitSyst, - "postfit_nd_numu_rhc_1D", pot_nd_rhc, true); - post_nd_numu_rhc_1D->SetTitle( - std::to_string(nd_expt_rhc->ChiSq(fitOsc, fitSyst)).c_str()); - post_nd_numu_rhc_1D->Write(); - } - - // Save information - hist_covar.Write(); - hist_corr.Write(); - covar.Write("covar_mat"); - } - - if (PostFitTreeBlob) { - if (turbose) { - std::cout << "[INFO]: Assigning fit tree blob values " - << BuildLogInfoString() << std::endl; - } - (*PostFitTreeBlob->fParamNames) = this_fit.GetParamNames(); - (*PostFitTreeBlob->fPreFitValues) = this_fit.GetPreFitValues(); - (*PostFitTreeBlob->fPreFitErrors) = this_fit.GetPreFitErrors(); - (*PostFitTreeBlob->fPostFitValues) = this_fit.GetPostFitValues(); - (*PostFitTreeBlob->fPostFitErrors) = this_fit.GetPostFitErrors(); - (*PostFitTreeBlob->fCentralValues) = this_fit.GetCentralValues(); - (*PostFitTreeBlob->fFakeDataVals) = fFakeDataVals; - PostFitTreeBlob->fNFCN = this_fit.GetNFCN(); - PostFitTreeBlob->fEDM = this_fit.GetEDM(); - PostFitTreeBlob->fIsValid = this_fit.GetIsValid(); - PostFitTreeBlob->fChiSq = thischisq; - PostFitTreeBlob->fNSeconds = - std::chrono::duration_cast(end_fit - start_fit) - .count(); - PostFitTreeBlob->fNOscSeeds = oscSeeds.size(); - - ProcInfo_t procinfo; - gSystem->GetProcInfo(&procinfo); - PostFitTreeBlob->fResMemUsage = procinfo.fMemResident; - PostFitTreeBlob->fVirtMemUsage = procinfo.fMemVirtual; - } - - if (turbose) { - std::cout << "[INFO]: Finished run fit point." << BuildLogInfoString() - << std::endl; - } - - return thischisq; -} diff --git a/CAFAna/Analysis/common_fit_definitions.h b/CAFAna/Analysis/common_fit_definitions.h deleted file mode 100644 index a24681f0..00000000 --- a/CAFAna/Analysis/common_fit_definitions.h +++ /dev/null @@ -1,181 +0,0 @@ -#pragma once - -#include "CAFAna/Analysis/AnalysisBinnings.h" -#include "CAFAna/Analysis/AnalysisDialGroups.h" - -#include "CAFAna/Core/IFitVar.h" -#include "CAFAna/Core/ISyst.h" -#include "CAFAna/Core/Spectrum.h" -#include "CAFAna/Core/SystShifts.h" - -#include "CAFAna/Experiment/IExperiment.h" - -#include "CAFAna/Fit/Fit.h" -#include "CAFAna/Fit/SeedList.h" - -#include "CAFAna/Prediction/PredictionInterp.h" - -#include "CAFAna/Systs/AnaSysts.h" - -#include "OscLib/IOscCalc.h" - -#include "TDirectory.h" - -// Extra headers not required -#include "CAFAna/Analysis/ExtraHeaders.h" - -#include -#include -#include - -extern unsigned gRNGSeed; - -// Factor to account for simulated LAr mass/expected FV, pot_fd = pot_nd * -// pot_fd_FVMassFactor -extern double const pot_fd_FVMassFactor; -// POT for 3.5 years -extern double const pot_fd; -extern double const pot_nd; - -// This is pretty annoying, but the above is for 7 years staged, which is 336 kT -// MW yr -extern double const nom_exposure; - -double GetBoundedGausThrow(double min, double max); - -// For ease of penalty terms... -ana::IExperiment *GetPenalty(int hie, int oct, std::string penalty, - std::string asimov_set = "0", - bool modConstraint = false); - -std::vector -GetOscVars(std::string oscVarString = "alloscvars", int hie = 0, int oct = 0); - -ana::SystShifts GetFakeDataGeneratorSystShift(std::string input); - -enum SampleType { kFDFHC, kFDRHC, kNDFHC, kNDRHC, kNDNue, kNDFHC_OA, kUnknown }; -std::string GetSampleName(SampleType sample); -SampleType GetSampleType(std::string const &sample); - -void MakePredictionInterp( - TDirectory *saveDir, SampleType sample, - std::vector systlist, AxisBlob const &axes, - std::vector const &non_swap_file_list, - std::vector const &nue_swap_file_list = {}, - std::vector const &tau_swap_file_list = {}, int max = 0); - -std::vector> -GetPredictionInterps(std::string fileName, - std::vector systlist); - -TH2D *make_corr_from_covar(TH2D *covar); - -// Yet another string parser that does far too much. I can't be stopped! -void ParseDataSamples(std::string cmdLineInput, double &pot_nd_fhc, - double &pot_nd_rhc, double &pot_fd_fhc_nue, - double &pot_fd_rhc_nue, double &pot_fd_fhc_numu, - double &pot_fd_rhc_numu); - -void ParseThrowInstructions(std::string throwString, bool &stats, bool &fakeOA, - bool &fakeNuis, bool &start, bool ¢ral); - -TMatrixD *GetNDCovMat(bool UseV3NDCovMat = false, - bool TwoBeams = true, - bool isFHC = true); - -TMatrixD *MakeCovmat(ana::PredictionInterp const &prediction, - std::vector const &systs, - osc::IOscCalcAdjustable *calc, size_t NToys = 1000, - TDirectory *outdir = nullptr); - -void SaveTrueOAParams(TDirectory *outDir, osc::IOscCalcAdjustable *calc, - std::string tree_name = "true_OA"); - -void SaveParams(TDirectory *outDir, std::vector systlist); - -struct FitTreeBlob { - FitTreeBlob(std::string tree_name = "", std::string meta_tree_name = ""); - static FitTreeBlob *MakeReader(TTree *t, TTree *m); - ~FitTreeBlob(); - void CopyVals(FitTreeBlob const &fb); - void Fill(); - void SetDirectory(TDirectory *d); - void SetDirectoryClone(TDirectory *d); - void Write(); - void WriteClone(); - bool fMeta_filled; - TTree *throw_tree; - TTree *meta_tree; - std::vector *fFakeDataVals; - std::vector *fParamNames; - std::vector *fEnvVarNames; - std::vector *fEnvVarValues; - std::vector *fPreFitValues; - std::vector *fPreFitErrors; - std::vector *fPostFitValues; - std::vector *fPostFitErrors; - std::vector *fCentralValues; - double fChiSq; - unsigned fNSeconds; - unsigned fLoopRNGSeed; - unsigned fJobRNGSeed; - std::vector *fSpectraRNGSeeds; - unsigned fNFills; - unsigned fNOscSeeds; - double fResMemUsage; - double fVirtMemUsage; - double fNFCN; - double fEDM; - bool fIsValid; -#ifdef USE_PREDINTERP_OMP - unsigned fNMaxThreads; -#endif -}; - -std::string BuildLogInfoString(); - -struct seeded_spectra { - seeded_spectra(unsigned ss, std::unique_ptr &&ospect) - : stats_seed(ss), spect(std::move(ospect)) {} - unsigned stats_seed; - std::unique_ptr spect; -}; - -enum sample_idxs { - kFDNueFHC = 0, - kFDNumuFHC = 1, - kFDNueRHC = 2, - kFDNumuRHC = 3, - kNDNumuFHC = 4, - kNDNumuRHC = 5 -}; - -// This is so so awful. -std::vector -BuildSpectra(ana::PredictionInterp *predFDNumuFHC = nullptr, - ana::PredictionInterp *predFDNueFHC = nullptr, - ana::PredictionInterp *predFDNumuRHC = nullptr, - ana::PredictionInterp *predFDNueRHC = nullptr, - ana::PredictionInterp *predNDNumuFHC = nullptr, - ana::PredictionInterp *predNDNumuRHC = nullptr, - osc::IOscCalcAdjustable *fakeDataOsc = nullptr, - ana::SystShifts fakeDataSyst = ana::kNoShift, - bool fakeDataStats = false, double pot_fd_fhc_nue = 0, - double pot_fd_fhc_numu = 0, double pot_fd_rhc_nue = 0, - double pot_fd_rhc_numu = 0, double pot_nd_fhc = 0, - double pot_nd_rhc = 0, std::vector const &Seeds = {}); - -double RunFitPoint(std::string stateFileName, std::string sampleString, - osc::IOscCalcAdjustable *fakeDataOsc, - ana::SystShifts fakeDataSyst, bool fakeDataStats, - std::vector oscVars, - std::vector systlist, - osc::IOscCalcAdjustable *fitOsc, - ana::SystShifts fitSyst, - ana::SeedList oscSeeds = ana::SeedList(), - ana::IExperiment *penaltyTerm = nullptr, - ana::MinuitFitter::FitOpts fitStrategy = ana::MinuitFitter::kNormal, - TDirectory *outDir = nullptr, - FitTreeBlob *PostFitTreeBlob = nullptr, - std::vector *spectra = nullptr, - ana::SystShifts &bf = ana::junkShifts); diff --git a/CAFAna/CMakeLists.txt b/CAFAna/CMakeLists.txt index 3f804411..4e5dff55 100644 --- a/CAFAna/CMakeLists.txt +++ b/CAFAna/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required (VERSION 3.14 FATAL_ERROR) find_program(CMAKE_C_COMPILER NAMES $ENV{CC} gcc PATHS ENV PATH NO_DEFAULT_PATH) find_program(CMAKE_CXX_COMPILER NAMES $ENV{CXX} g++ PATHS ENV PATH NO_DEFAULT_PATH) -project(CAFAna) +project(CAFAna VERSION 2.00.00) #Changes default install path to be a subdirectory of the build dir. #Can set build dir at configure time with -DCMAKE_INSTALL_PREFIX=/install/path @@ -81,14 +81,52 @@ include(${CMAKE_SOURCE_DIR}/cmake/FindExternals.cmake) include(${CMAKE_SOURCE_DIR}/cmake/c++CompilerSetup.cmake) ################################################################################ -## CAFAna proper +# we're going to create an interface library that bundles all the CAFAna libs together +# easier if we don't have to know all their names in advance... +macro(add_cafana_lib newlib) + list(APPEND CAFANA_LIBS ${newlib}) + set(CAFANA_LIBS ${CAFANA_LIBS} PARENT_SCOPE) +# message(STATUS " $CAFANA_LIBS now contains: '${CAFANA_LIBS}'") +endmacro() -set(CAFANA_SUBDIRS Analysis Core Cuts Decomp Experiment Extrap Fit Prediction Systs Vars PRISM bin scripts fcl) +################################################################################ +set(CAFANA_SUBDIRS Analysis Core Cuts Experiment Extrap Fit Prediction Systs Utils Vars bin scripts fcl) +if(DEFINED BUILD_PRISM) + set(CAFANA_SUBDIRS ${CAFANA_SUBDIRS} PRISM) +else() + message(WARNING "Not building PRISM. Pass '-DBUILD_PRISM' using '-e BUILD_PRISM' in standalone_configure_and_build.sh to change this.") +endif() foreach(SUBDIR ${CAFANA_SUBDIRS}) + add_subdirectory(${SUBDIR}) endforeach() +# add an 'interface' (= no actual file) library +# that one can import in another CMake project +# to be able to link against all of the CAFAna libs +add_library(All INTERFACE) +message(STATUS "$CAFANA_LIBS contains: '${CAFANA_LIBS}'") +target_link_libraries(All INTERFACE ${CAFANA_LIBS}) +target_include_directories(All INTERFACE + $ + $ +) + +################################################################################ + +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + "${PROJECT_BINARY_DIR}/CAFAnaConfigVersion.cmake" + VERSION ${CMAKE_PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion +) +configure_package_config_file( + "${PROJECT_SOURCE_DIR}/cmake/templates/CAFAnaConfig.cmake.in" + "${PROJECT_BINARY_DIR}/CAFAnaConfig.cmake" + INSTALL_DESTINATION lib/cmake/CAFAna +) + configure_file(cmake/CAFAnaEnv.sh.in ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CAFAnaEnv.sh @ONLY) @@ -112,3 +150,21 @@ install( DESTINATION bin ) + +# install our CMake files so that others can crib them too +file(GLOB cmake_files ${CMAKE_SOURCE_DIR}/cmake/*.cmake) +install( + FILES + ${cmake_files} + DESTINATION + cmake +) + +install(TARGETS All + EXPORT CAFAnaTargets +) + +install(EXPORT CAFAnaTargets NAMESPACE CAFAna:: DESTINATION lib/cmake/CAFAna) +install(FILES "${PROJECT_BINARY_DIR}/CAFAnaConfigVersion.cmake" + "${PROJECT_BINARY_DIR}/CAFAnaConfig.cmake" + DESTINATION lib/cmake/CAFAna) diff --git a/CAFAna/Core/CMakeLists.txt b/CAFAna/Core/CMakeLists.txt index 658c0a75..d9e63214 100644 --- a/CAFAna/Core/CMakeLists.txt +++ b/CAFAna/Core/CMakeLists.txt @@ -1,12 +1,16 @@ set(Core_implementation_files Binning.cxx + Cut.cxx IFitVar.cxx - Instantiations.cxx - FixupRecord.cxx + IRecordSource.cxx ISyst.cxx + Multiverse.cxx Loaders.cxx LoadFromFile.cxx OscCurve.cxx + EnsembleRatio.cxx + EnsembleSpectrum.cxx + EnsembleReweightableSpectrum.cxx OscillatableSpectrum.cxx ProfilerSupport.cxx Registry.cxx @@ -14,29 +18,40 @@ set(Core_implementation_files SpectrumLoaderBase.cxx StanUtils.cxx SystShifts.cxx + TruthMatching.cxx Utilities.cxx + Var.cxx ) set(Core_header_files Binning.h Cut.h FitVarWithPrior.h - FixupRecord.h HistAxis.h IFitVar.h + IRecordSink.h + IRecordSource.h ISyst.h + FitMultiverse.h + Multiverse.h Loaders.h LoadFromFile.h MathUtil.h MultiVar.h OscCalcFwdDeclare.h OscCurve.h + EnsembleRatio.h + EnsembleSpectrum.h + EnsembleReweightableSpectrum.h OscillatableSpectrum.h + Sources.h + Sources.ixx SpectrumLoader.h SpectrumLoaderBase.h StanTypedefs.h StanUtils.h SystShifts.h + TruthMatching.h Utilities.h Var.h Weight.h @@ -63,6 +78,9 @@ if(DEFINED USE_OPENMP AND USE_OPENMP) target_compile_options(CAFAnaCore BEFORE PUBLIC -DUSE_PREDINTERP_OMP -fopenmp) endif() -install(TARGETS CAFAnaCore +install(TARGETS CAFAnaCore + EXPORT CAFAnaTargets LIBRARY DESTINATION lib/ PUBLIC_HEADER DESTINATION include/CAFAna/Core/) + +add_cafana_lib(CAFAnaCore) \ No newline at end of file diff --git a/CAFAna/Core/Cut.cxx b/CAFAna/Core/Cut.cxx new file mode 100644 index 00000000..7c036f0b --- /dev/null +++ b/CAFAna/Core/Cut.cxx @@ -0,0 +1,33 @@ +#include "CAFAna/Core/Cut.h" + +#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" + +#include "CAFAna/Core/TruthMatching.h" + +#include +#include + + +namespace ana +{ + Cut TruthCutToCut(const TruthCut & truthcut) + { + return Cut([=](const caf::SRInteractionProxy * sri) + { + if (sri->truth.size() < 1) + { + std::cerr << "No matched truth for this reco interaction, can't convert Cut to TruthCut\n"; + throw std::runtime_error("Truth is empty"); + } + // todo: FD CAFs apparently aren't filling truthOverlap, but they should be... + if (sri->truthOverlap.size() > 0 && sri->truthOverlap[0] < 0.5) + { + std::cerr << "TruthCutToCut(): best-matched neutrino is < 50% of interaction, can't determine true flavor"; + throw std::runtime_error("No best-matched neutrino"); + } + + return truthcut(MatchedTrueInteraction(sri)); + }); + } + +} \ No newline at end of file diff --git a/CAFAna/Core/Cut.h b/CAFAna/Core/Cut.h index a157614b..c358c411 100644 --- a/CAFAna/Core/Cut.h +++ b/CAFAna/Core/Cut.h @@ -6,8 +6,40 @@ namespace ana { - using Cut = _Cut; + /// \brief Representation of a cut (selection) to be applied to a \ref + /// caf::StandardRecord object + /// + /// A Cut consists of a function, taking a StandardRecord and returning a + /// boolean indicating if that event passes the cut. + /// + /// Cut objects may be combined with the standard boolean operations && || + /// and ! + typedef _Cut InteractionCut; + typedef _Cut Cut; + typedef _Cut TruthCut; + typedef _Cut TruthPartCut; + typedef _Cut NDCut; + + /// \brief Equivalent of \ref Cut acting on \ref caf::StandardRecord. For use in + /// spill-by-spill data quality cuts ???? + typedef _Cut SRCut; + + /// Convert a Cut over a true interaction to one over a reco interaction with associated truth. + Cut TruthCutToCut(const TruthCut & truthcut); + /// The simplest possible cut: pass everything, used as a default - const Cut kNoCut(NoCut{}); + const Cut kNoCut(NoCut{}); + const TruthCut kNoTruthCut(NoCut{}); + const TruthPartCut kNoTruthPartCut(NoCut{}); + const NDCut kNoNDCut(NoCut{}); + const SRCut kNoSRCut(NoCut{}); + + typedef _Cut RecoPartCut; + + const RecoPartCut kNoPartCut(NoCut{}); + +// typedef _Cut RecoPartCut; +// const RecoPartCut kNoPartCut(NoCut{}); + } diff --git a/CAFAna/Core/EnsembleRatio.cxx b/CAFAna/Core/EnsembleRatio.cxx new file mode 100644 index 00000000..fe612261 --- /dev/null +++ b/CAFAna/Core/EnsembleRatio.cxx @@ -0,0 +1,233 @@ +#include "CAFAna/Core/EnsembleRatio.h" + +#include "CAFAna/Core/EnsembleSpectrum.h" + +#include "CAFAna/Core/FitMultiverse.h" +#include "CAFAna/Core/Utilities.h" + +#include "cafanacore/UtilsExt.h" + +#include "TEfficiency.h" +#include "TGraphAsymmErrors.h" + +#include + +namespace ana +{ + //---------------------------------------------------------------------- + EnsembleRatio::EnsembleRatio(const EnsembleSpectrum& num, + const EnsembleSpectrum& denom, + bool purOrEffErrs) + : fMultiverse(&num.GetMultiverse()), + fHist(num.fHist), + fAxis(num.GetLabels(), num.GetBinnings()) + { + CheckMultiverses(denom.GetMultiverse(), __func__); + + fHist.Divide(denom.fHist); + // TODO TODO this should handle livetime too + fHist.Scale(denom.POT()/num.POT()); + + // This is clumsy, but the old histogram operation considered 0/0 = 0, + // which is actually pretty useful (at least PredictionInterp relies on + // this). + for(int i = 0; i < fHist.GetNbinsX()+2; ++i){ + if(denom.fHist.GetBinContent(i) == 0){ + if(num.fHist.GetBinContent(i) == 0){ + fHist.SetBinContent(i, 0); + } + else{ + // Actual infinities break ROOT plotting + fHist.SetBinContent(i, 1e100); + // As in fact do merely very large numbers + // fHist.SetBinContent(i, std::numeric_limits::max()); + } + } + } + + if(purOrEffErrs){ + if(!AlmostEqual(num.POT(), denom.POT())){ + std::cout << "EnsembleRatio: Warning: creating purity or efficiency ratio between two spectra with different POTs" + << "\n " << num.POT() << " vs " << denom.POT() + << "\n That doesn't make much sense" << std::endl; + } + + Eigen::ArrayXd errsqarr(fHist.GetNbinsX()+2); + + const double kOneSigma = .6827; + for(int i = 0; i < fHist.GetNbinsX()+2; ++i){ + const double n = num.fHist.GetBinContent(i); + const double d = denom.fHist.GetBinContent(i); + + // Clopper-Peason is the TEfficiency default and "recommended by the + // PDG". If the user wants something else (for rendering purposes) they + // should use TEfficiency directly. + const double up = TEfficiency::ClopperPearson(n+d, n, kOneSigma, true); + const double dn = TEfficiency::ClopperPearson(n+d, n, kOneSigma, false); + + // Crudely symmetrizes asymmetric errors. The underlying Hist class + // can't cope with that, only really makes sense for plotting. In which + // case the user should do it themselves. + errsqarr[i] = util::sqr((up-dn)/2); + } // end for i + + Eigen::ArrayXd valarr = fHist.GetEigen(); + // Replace fHist with same values but new errors + fHist = Hist::AdoptWithErrors(std::move(valarr), std::move(errsqarr)); + } + } + + //---------------------------------------------------------------------- + unsigned int EnsembleRatio::NUniverses() const + { + return fMultiverse->NUniv(); + } + + //---------------------------------------------------------------------- + Ratio EnsembleRatio::Universe(unsigned int univIdx) const + { + const int nbins = fAxis.GetBins1D().NBins()+2; + + if(fHist.HasStan()){ +#ifdef STAN_ENABLED + return Ratio(std::move(Eigen::ArrayXstan(fHist.GetEigenStan().segment(nbins*univIdx, nbins))), + fAxis.GetLabels(), fAxis.GetBinnings()); +#else + std::cerr << "CAFAna was compiled without Stan support, but received a Stan-enabled histogram! Abort.\n"; + abort(); +#endif + } + else{ + Eigen::ArrayXd arr(fHist.GetEigen().segment(nbins*univIdx, nbins)); + + if(Hist::StatErrorsEnabled()){ + Eigen::ArrayXd errarr(fHist.GetEigenSqErrors().segment(nbins*univIdx, nbins)); + return Ratio(std::move(arr), std::move(errarr), + fAxis.GetLabels(), fAxis.GetBinnings()); + } + else{ + return Ratio(std::move(arr), fAxis.GetLabels(), fAxis.GetBinnings()); + } + } + } + + //---------------------------------------------------------------------- + TGraphAsymmErrors* EnsembleRatio::ErrorBand() const + { + // TODO lots of code duplication with EnsembleSpectrum + + const Eigen::ArrayXd arr = fHist.GetEigen(); + + TGraphAsymmErrors* g = new TGraphAsymmErrors; + + const int nbins = fAxis.GetBins1D().NBins()+2; + const std::vector& edges = fAxis.GetBins1D().Edges(); + + for(int binIdx = 1; binIdx+1 < nbins; ++binIdx){ + const double xnom = (edges[binIdx-1] + edges[binIdx]) / 2; // bin center + const double ynom = arr[binIdx]; + g->SetPoint(binIdx-1, xnom, ynom); + + const double dx = edges[binIdx] - edges[binIdx-1]; + + std::vector ys; + ys.reserve(NUniverses()-1); + for(unsigned int univIdx = 1; univIdx < NUniverses(); ++univIdx) + ys.push_back(arr[univIdx*nbins + binIdx]); + + // 1 sigma + const double y0 = FindQuantile(.5-0.6827/2, ys); + const double y1 = FindQuantile(.5+0.6827/2, ys); + + // It's theoretically possible for the central value to be outside the + // error bands - clamp to zero in that case + g->SetPointError(binIdx-1, dx/2, dx/2, + std::max(ynom-y0, 0.), + std::max(y1-ynom, 0.)); + } // end for binIdx + + return g; + } + + //---------------------------------------------------------------------- + Eigen::MatrixXd EnsembleRatio::CovarianceMatrix() + { + assert (fMultiverse->MultiverseType() == kRandomGas); + + const Eigen::ArrayXd& arr = fHist.GetEigen(); + + const int nbins = fAxis.GetBins1D().NBins()+2; + std::vector histVec; + histVec.reserve(NUniverses()); + + for(unsigned int univIdx = 1; univIdx < NUniverses(); ++univIdx) + histVec.push_back(arr.segment(nbins*univIdx, nbins)); + + return ana::CalcCovMx(histVec);// returns TMatrixD + } + + //---------------------------------------------------------------------- + Eigen::MatrixXd EnsembleRatio::BiasMatrix() + { + assert (fMultiverse->MultiverseType() == kRandomGas); + + const Eigen::ArrayXd& arr = fHist.GetEigen(); + + const int nbins = fAxis.GetBins1D().NBins()+2; + std::vector histVec; + histVec.reserve(NUniverses()); + + for(unsigned int univIdx = 1; univIdx < NUniverses(); ++univIdx) + histVec.push_back(arr.segment(nbins*univIdx, nbins)); + + return ana::CalcBiasMx(arr.segment(0, nbins), histVec); + } + //---------------------------------------------------------------------- + void EnsembleRatio::CheckMultiverses(const FitMultiverse& rhs, + const std::string& func) const + { + if(&rhs == fMultiverse) return; + + std::cout << "EnsembleRatio::" << func << ": attempting to combine two spectra made with different multiverses: " << std::endl; + std::cout << " " << fMultiverse->ShortName() << std::endl; + std::cout << "vs" << std::endl; + std::cout << rhs.ShortName() << std::endl; + abort(); + } + + //---------------------------------------------------------------------- + EnsembleRatio& EnsembleRatio::operator*=(const EnsembleRatio& rhs) + { + CheckMultiverses(rhs.GetMultiverse(), __func__); + + fHist.Multiply(rhs.fHist); + + return *this; + } + + //---------------------------------------------------------------------- + EnsembleRatio EnsembleRatio::operator*(const EnsembleRatio& rhs) const + { + EnsembleRatio ret = *this; + ret *= rhs; + return ret; + } + + //---------------------------------------------------------------------- + EnsembleRatio& EnsembleRatio::operator/=(const EnsembleRatio& rhs) + { + CheckMultiverses(rhs.GetMultiverse(), __func__); + + fHist.Divide(rhs.fHist); + + return *this; + } + + //---------------------------------------------------------------------- + EnsembleRatio EnsembleRatio::operator/(const EnsembleRatio& rhs) const + { + EnsembleRatio ret = *this; + ret /= rhs; + return ret; + } +} \ No newline at end of file diff --git a/CAFAna/Core/EnsembleRatio.h b/CAFAna/Core/EnsembleRatio.h new file mode 100644 index 00000000..e9c9ca34 --- /dev/null +++ b/CAFAna/Core/EnsembleRatio.h @@ -0,0 +1,60 @@ +#pragma once + +#include "cafanacore/Ratio.h" + +#include "TGraphAsymmErrors.h" + +#include + +namespace ana +{ + class EnsembleSpectrum; + class FitMultiverse; + + class EnsembleRatio + { + public: + friend class EnsembleSpectrum; + + EnsembleRatio(const EnsembleSpectrum& num, + const EnsembleSpectrum& denom, + bool purOrEffErrs = false); + + Ratio Nominal() const {return Universe(0);} + unsigned int NUniverses() const; + Ratio Universe(unsigned int i) const; + + const FitMultiverse& GetMultiverse() const {return *fMultiverse;} + + TGraphAsymmErrors* ErrorBand() const; + + /// Wrapper for \ref CalcCovMx + Eigen::MatrixXd CovarianceMatrix(); + + /// Wrapper for \ref CalcBiasMx + Eigen::MatrixXd BiasMatrix(); + + EnsembleRatio& operator*=(const EnsembleRatio& rhs); + EnsembleRatio operator*(const EnsembleRatio& rhs) const; + + EnsembleRatio& operator/=(const EnsembleRatio& rhs); + EnsembleRatio operator/(const EnsembleRatio& rhs) const; + + protected: + friend class EnsembleReweightableSpectrum; + Eigen::ArrayXd GetEigen() const {return fHist.GetEigen();} + + void CheckMultiverses(const FitMultiverse& rhs, + const std::string& func) const; + + const FitMultiverse* fMultiverse; + Hist fHist; + LabelsAndBins fAxis; + }; + + inline EnsembleRatio operator/(const EnsembleSpectrum& lhs, + const EnsembleSpectrum& rhs) + { + return EnsembleRatio(lhs, rhs); + } +} \ No newline at end of file diff --git a/CAFAna/Core/EnsembleReweightableSpectrum.cxx b/CAFAna/Core/EnsembleReweightableSpectrum.cxx new file mode 100644 index 00000000..ee024e56 --- /dev/null +++ b/CAFAna/Core/EnsembleReweightableSpectrum.cxx @@ -0,0 +1,411 @@ +#include "CAFAna/Core/EnsembleReweightableSpectrum.h" + +#include "CAFAna/Core/EnsembleRatio.h" +#include "CAFAna/Core/FitMultiverse.h" + +#include "CAFAna/Core/Binning.h" +#include "CAFAna/Core/Ratio.h" +//#include "CAFAna/Core/Stan.h" + +#include "TDirectory.h" +#include "TH2.h" +#include "TObjString.h" + +#include +#include +#include + +namespace ana +{ + //---------------------------------------------------------------------- + EnsembleReweightableSpectrum:: + EnsembleReweightableSpectrum(IValuePairEnsembleSource& src, + const LabelsAndBins& recoAxis, + const LabelsAndBins& trueAxis) + : EnsembleReweightableSpectrum(src.GetMultiverse(), recoAxis, trueAxis) + { + fMat.resize(trueAxis.GetBins1D().NBins()+2, + (recoAxis.GetBins1D().NBins()+2) * fMultiverse->NUniv()); + + fMat.setZero(); + + src.Register(this); + } + + //---------------------------------------------------------------------- + EnsembleReweightableSpectrum:: + EnsembleReweightableSpectrum(const FitMultiverse* multiverse, + const Eigen::MatrixXd&& mat, + const LabelsAndBins& recoAxis, + const LabelsAndBins& trueAxis, + double pot, double livetime) + : fMultiverse(multiverse), fMat(mat), fPOT(pot), fLivetime(livetime), + fAxisX(recoAxis), fAxisY(trueAxis) + { + } + + //---------------------------------------------------------------------- + EnsembleReweightableSpectrum::~EnsembleReweightableSpectrum() + { + } + // why is copy constructor not working? + //---------------------------------------------------------------------- + //EnsembleReweightableSpectrum::EnsembleReweightableSpectrum(const EnsembleReweightableSpectrum& rhs) + // : fMultiverse(rhs.fMultiverse), + // fMat(rhs.fMat), + // fPOT(rhs.fPOT), + // fLivetime(rhs.fLivetime), + // fAxisX(rhs.fAxisX), + // fAxisY(rhs.fAxisY) + //{ + //} + + //---------------------------------------------------------------------- + EnsembleReweightableSpectrum& EnsembleReweightableSpectrum::operator=(const EnsembleReweightableSpectrum& rhs) + { + if(this == &rhs) return *this; + + fMultiverse = rhs.fMultiverse; + fMat = rhs.fMat; + fPOT = rhs.fPOT; + fLivetime = rhs.fLivetime; + fAxisX = rhs.fAxisX; + fAxisY = rhs.fAxisY; + + return *this; + } + + //---------------------------------------------------------------------- + void EnsembleReweightableSpectrum::FillSingle(double x, double y, double w, int universeId) + { + // Filling a single constituent universe + const int xbin = fAxisX.GetBins1D().FindBin(x); + const int ybin = fAxisY.GetBins1D().FindBin(y); + const unsigned int nbinsx = fAxisX.GetBins1D().NBins()+2; + fMat(ybin, nbinsx * universeId + xbin) += w; + } + + //---------------------------------------------------------------------- + void EnsembleReweightableSpectrum::FillEnsemble(double x, double y, const std::vector& ws) + { + const unsigned int xbin = fAxisX.GetBins1D().FindBin(x); + const unsigned int ybin = fAxisY.GetBins1D().FindBin(y); + const unsigned int nbinsx = fAxisX.GetBins1D().NBins()+2; + + const unsigned int nuniv = fMultiverse->NUniv(); + assert(ws.size() == nuniv); + + for(unsigned int univIdx = 0; univIdx < nuniv; ++univIdx) + fMat(ybin, nbinsx * univIdx + xbin) += ws[univIdx]; + } + + //---------------------------------------------------------------------- + void EnsembleReweightableSpectrum::FillPOT(double pot) + { + fPOT += pot; + } + + //---------------------------------------------------------------------- + void EnsembleReweightableSpectrum::FillLivetime(double livetime) + { + fLivetime += livetime; + } + + //---------------------------------------------------------------------- + unsigned int EnsembleReweightableSpectrum::NUniverses() const + { + return fMultiverse->NUniv(); + } + + //---------------------------------------------------------------------- + ReweightableSpectrum EnsembleReweightableSpectrum::Universe(unsigned int univIdx) const + { + const int nbinsx = fAxisX.GetBins1D().NBins()+2; + const int nbinsy = fAxisY.GetBins1D().NBins()+2; // or fMat.cols() + return ReweightableSpectrum(fMat.block(0, nbinsx*univIdx, nbinsy, nbinsx), + fAxisX, fAxisY, fPOT, fLivetime); + } + + /// Helper for \ref Unweighted + inline Eigen::ArrayXd ProjectionX(const Eigen::MatrixXd& mat) + { + return Eigen::RowVectorXd::Ones(mat.rows()) * mat; + } + + /// Helper for \ref WeightingVariable + inline Eigen::ArrayXd ProjectionY(const Eigen::MatrixXd& mat) + { + return mat * Eigen::VectorXd::Ones(mat.cols()); + } + + //---------------------------------------------------------------------- + EnsembleSpectrum EnsembleReweightableSpectrum::UnWeighted() const + { + return EnsembleSpectrum(fMultiverse, + Hist::Adopt(ProjectionX(fMat)), + fPOT, fLivetime, fAxisX); + } + + //---------------------------------------------------------------------- + EnsembleSpectrum EnsembleReweightableSpectrum::WeightingVariable() const + { + return EnsembleSpectrum(fMultiverse, + Hist::Adopt(ProjectionY(fMat)), + fPOT, fLivetime, fAxisY); + } + + //---------------------------------------------------------------------- + EnsembleSpectrum EnsembleReweightableSpectrum::WeightedBy(const Ratio& ws) const + { + // This version is appropriate for oscillations. We should probably add + // another that takes EnsembleRatio. + + const Eigen::VectorXd& vec = ws.GetEigen(); + + return EnsembleSpectrum(fMultiverse, + Hist::Adopt(Eigen::ArrayXd(vec.transpose() * fMat)), + fPOT, fLivetime, fAxisX); + } + + //---------------------------------------------------------------------- + EnsembleReweightableSpectrum& EnsembleReweightableSpectrum::PlusEqualsHelper(const EnsembleReweightableSpectrum& rhs, int sign, const std::string& func) + { + CheckMultiverses(rhs.GetMultiverse(), func); + + // In this case it would be OK to have no POT/livetime + if(rhs.fMat.sum() == 0) return *this; + + + if((!fPOT && !fLivetime) || (!rhs.fPOT && !rhs.fLivetime)){ + std::cout << "Error: can't sum EnsembleReweightableSpectrum with no POT or livetime." + << fPOT << " " << rhs.fPOT + << std::endl; + // abort(); + return *this; + } + + if(!fLivetime && !rhs.fPOT){ + std::cout << "Error: can't sum EnsembleReweightableSpectrum with POT (" + << fPOT << ") but no livetime and EnsembleReweightableSpectrum with livetime (" + << rhs.fLivetime << " sec) but no POT." << std::endl; + abort(); + } + + if(!fPOT && !rhs.fLivetime){ + std::cout << "Error: can't sum EnsembleReweightableSpectrum with livetime (" + << fLivetime << " sec) but no POT and EnsembleReweightableSpectrum with POT (" + << rhs.fPOT << ") but no livetime." << std::endl; + abort(); + } + + // And now there are still a bunch of good cases to consider + + if(fPOT && rhs.fPOT){ + // Scale by POT when possible + fMat += rhs.fMat * sign*fPOT/rhs.fPOT; + + if(fLivetime && rhs.fLivetime){ + // If POT/livetime ratios match, keep regular lifetime, otherwise zero + // it out. + if(AlmostEqual(fLivetime*rhs.fPOT, rhs.fLivetime*fPOT)) + fLivetime = 0; + } + if(!fLivetime && rhs.fLivetime){ + // If the RHS has a livetime and we don't, copy it in (suitably scaled) + fLivetime = rhs.fLivetime * fPOT/rhs.fPOT; + } + // Otherwise, keep our own livetime (if any) + + return *this; + } + + if(fLivetime && rhs.fLivetime){ + // Scale by livetime, the only thing in common + fMat += rhs.fMat * sign*fLivetime/rhs.fLivetime; + + if(!fPOT && rhs.fPOT){ + // If the RHS has a POT and we don't, copy it in (suitably scaled) + fPOT = rhs.fPOT * fLivetime/rhs.fLivetime; + } + // Otherwise, keep our own POT (if any) + + return *this; + } + + // That should have been all the cases. I definitely want to know what + // happened if it wasn't. + std::cout << "EnsembleReweightableSpectrum::operator+=(). How did we get here? " + << fPOT << " " << fLivetime << " " + << rhs.fPOT << " " << rhs.fLivetime << std::endl; + abort(); + } + + //---------------------------------------------------------------------- + EnsembleReweightableSpectrum& EnsembleReweightableSpectrum::operator+=(const EnsembleReweightableSpectrum& rhs) + { + return PlusEqualsHelper(rhs, +1, __func__); + } + + //---------------------------------------------------------------------- + EnsembleReweightableSpectrum EnsembleReweightableSpectrum::operator+(const EnsembleReweightableSpectrum& rhs) const + { + EnsembleReweightableSpectrum ret = *this; + ret += rhs; + return ret; + } + + //---------------------------------------------------------------------- + EnsembleReweightableSpectrum& EnsembleReweightableSpectrum::operator-=(const EnsembleReweightableSpectrum& rhs) + { + return PlusEqualsHelper(rhs, -1, __func__); + } + + //---------------------------------------------------------------------- + EnsembleReweightableSpectrum EnsembleReweightableSpectrum::operator-(const EnsembleReweightableSpectrum& rhs) const + { + EnsembleReweightableSpectrum ret = *this; + ret -= rhs; + return ret; + } + + //---------------------------------------------------------------------- + void EnsembleReweightableSpectrum::SaveTo(TDirectory* dir, + const std::string& name) const + { + _SaveTo(dir, name, "EnsembleReweightableSpectrum"); + } + + //---------------------------------------------------------------------- + void EnsembleReweightableSpectrum::_SaveTo(TDirectory* dir, + const std::string& name, + const std::string& type) const + { + TDirectory* tmp = gDirectory; + + dir = dir->mkdir(name.c_str()); // switch to sbudir + dir->cd(); + + TObjString(type.c_str()).Write("type"); + + fMultiverse->SaveTo(dir, "multiverse"); + + TH2D* hist = MakeTH2D("hist", "", + Binning::Simple(fMat.cols(), 0, fMat.cols()), + fAxisY.GetBins1D()); + hist->GetXaxis()->SetTitle(fAxisX.GetLabel1D().c_str()); + hist->GetYaxis()->SetTitle(fAxisY.GetLabel1D().c_str()); + for(int i = 0; i < fMat.cols(); ++i){ + for(int j = 0; j < fMat.rows(); ++j){ + hist->SetBinContent(i, j, fMat(j, i)); + } + } + hist->Write("hist"); + + TH1D hPot("", "", 1, 0, 1); + hPot.Fill(.5, fPOT); + hPot.Write("pot"); + TH1D hLivetime("", "", 1, 0, 1); + hLivetime.Fill(.5, fLivetime); + hLivetime.Write("livetime"); + + for(unsigned int i = 0; i < fAxisX.NDimensions(); ++i){ + TObjString(fAxisX.GetLabels()[i].c_str()).Write(TString::Format("label%d", i).Data()); + fAxisX.GetBinnings()[i].SaveTo(dir, TString::Format("bins%d", i).Data()); + } + + for(unsigned int i = 0; i < fAxisY.NDimensions(); ++i){ + TObjString(fAxisY.GetLabels()[i].c_str()).Write(TString::Format("labely%d", i).Data()); + fAxisY.GetBinnings()[i].SaveTo(dir, TString::Format("binsy%d", i).Data()); + } + + dir->Write(); + delete dir; + + delete hist; + + tmp->cd(); + } + + //---------------------------------------------------------------------- + std::unique_ptr EnsembleReweightableSpectrum::LoadFrom(TDirectory* dir, const std::string& name) + { + dir = dir->GetDirectory(name.c_str()); // switch to subdir + assert(dir); + + TObjString* tag = (TObjString*)dir->Get("type"); + assert(tag); + assert(tag->GetString() == "EnsembleReweightableSpectrum"); + delete tag; + + TH2D* spect = (TH2D*)dir->Get("hist"); + assert(spect); + TH1* hPot = (TH1*)dir->Get("pot"); + assert(hPot); + TH1* hLivetime = (TH1*)dir->Get("livetime"); + assert(hLivetime); + + std::vector labels, labelsy; + std::vector bins, binsy; + + for(int i = 0; ; ++i){ + const std::string subname = TString::Format("bins%d", i).Data(); + TDirectory* subdir = dir->GetDirectory(subname.c_str()); + if(!subdir) break; + delete subdir; + bins.push_back(*Binning::LoadFrom(dir, subname.c_str())); + TObjString* label = (TObjString*)dir->Get(TString::Format("label%d", i)); + labels.push_back(label ? label->GetString().Data() : ""); + } + + for(int i = 0; ; ++i){ + const std::string subname = TString::Format("binsy%d", i).Data(); + TDirectory* subdir = dir->GetDirectory(subname.c_str()); + if(!subdir) break; + delete subdir; + binsy.push_back(*Binning::LoadFrom(dir, subname.c_str())); + TObjString* labely = (TObjString*)dir->Get(TString::Format("labely%d", i)); + labelsy.push_back(labely ? labely->GetString().Data() : ""); + } + + // Backwards compatibility + if(labelsy.empty()) labelsy.push_back(spect->GetYaxis()->GetTitle()); + if(binsy.empty()) binsy.push_back(Binning::FromTAxis(spect->GetYaxis())); + + const LabelsAndBins xax(labels, bins); + const LabelsAndBins yax(labelsy, binsy); + + const FitMultiverse* multiverse = FitMultiverse::LoadFrom(dir, "multiverse"); + + // ROOT histogram storage is row-major, but Eigen is column-major by + // default + typedef Eigen::Matrix MatRowMajor; + std::unique_ptr ret(new EnsembleReweightableSpectrum( + multiverse, + Eigen::Map(spect->GetArray(), + yax.GetBins1D().NBins()+2, + (xax.GetBins1D().NBins()+2) * multiverse->NUniv()), + xax, yax, hPot->Integral(0, -1), hLivetime->Integral(0, -1))); + + delete spect; + + delete hPot; + delete hLivetime; + + delete dir; + + return ret; + } + + //---------------------------------------------------------------------- + void EnsembleReweightableSpectrum::CheckMultiverses(const FitMultiverse& rhs, + const std::string& func) const + { + if(&rhs == fMultiverse) return; + + std::cout << "EnsembleReweightableSpectrum::" << func << ": attempting to combine two spectra made with different multiverses: " << std::endl; + std::cout << " " << fMultiverse->ShortName() << std::endl; + std::cout << "vs" << std::endl; + std::cout << rhs.ShortName() << std::endl; + abort(); + } +} \ No newline at end of file diff --git a/CAFAna/Core/EnsembleReweightableSpectrum.h b/CAFAna/Core/EnsembleReweightableSpectrum.h new file mode 100644 index 00000000..f58c4dc7 --- /dev/null +++ b/CAFAna/Core/EnsembleReweightableSpectrum.h @@ -0,0 +1,122 @@ +#pragma once + +#include "CAFAna/Core/EnsembleSpectrum.h" + +#include "cafanacore/ReweightableSpectrum.h" + +#include + +class TDirectory; + +namespace ana +{ + class FitMultiverse; + + template class _Var; + + /// %Spectrum with the value of a second variable, allowing for reweighting + class EnsembleReweightableSpectrum: public IValuePairEnsembleSink + { + public: + EnsembleReweightableSpectrum(IValuePairEnsembleSource& src, + const LabelsAndBins& recoAxis, + const LabelsAndBins& trueAxis); + + template + EnsembleReweightableSpectrum(_IRecordEnsembleSource& src, + const _HistAxis<_Var>& recoAxis, + const _HistAxis<_Var>& trueAxis) + : EnsembleReweightableSpectrum(src.GetVars(recoAxis.GetVar1D(), trueAxis.GetVar1D()), recoAxis, trueAxis) + { + } + + virtual ~EnsembleReweightableSpectrum(); + // why is copy constructor not working? + //EnsembleReweightableSpectrum(const EnsembleReweightableSpectrum& rhs); + EnsembleReweightableSpectrum& operator=(const EnsembleReweightableSpectrum& rhs); + + virtual void FillSingle(double x, double y, double w, int universeId) override; + + virtual void FillEnsemble(double x, double y, const std::vector& ws) override; + + virtual void FillPOT(double pot) override; + virtual void FillLivetime(double livetime) override; + + double POT() const{return fPOT;} + double Livetime() const{return fLivetime;} + + EnsembleSpectrum UnWeighted() const; + + EnsembleSpectrum WeightingVariable() const; + + /// Reco spectrum with truth weights applied + EnsembleSpectrum WeightedBy(const Ratio& weights) const; + +// Not implemented for now + /// Rescale bins so that \ref WeightingVariable will return \a target +// void ReweightToTrueSpectrum(const EnsembleSpectrum& target); + /// Recale bins so that \ref Unweighted will return \a target +// void ReweightToRecoSpectrum(const EnsembleSpectrum& target); + + // Arithmetic operators are as if these are unlike samples, each a + // contribution to one total, not seperate sources of stats for the same + // sample. + EnsembleReweightableSpectrum& operator+=(const EnsembleReweightableSpectrum& rhs); + EnsembleReweightableSpectrum operator+(const EnsembleReweightableSpectrum& rhs) const; + + EnsembleReweightableSpectrum& operator-=(const EnsembleReweightableSpectrum& rhs); + EnsembleReweightableSpectrum operator-(const EnsembleReweightableSpectrum& rhs) const; + + void SaveTo(TDirectory* dir, const std::string& name) const; + + static std::unique_ptr LoadFrom(TDirectory* dir, const std::string& name); + + unsigned int NDimensions() const{return fAxisX.NDimensions();} + + unsigned int NUniverses() const; + ReweightableSpectrum Nominal() const {return Universe(0);} + ReweightableSpectrum Universe(unsigned int univIdx) const; + + // TODO consider naming confusion with Universe() above + const FitMultiverse& GetMultiverse() const {return *fMultiverse;} + + const std::vector& GetLabels() const {return fAxisX.GetLabels();} + const std::vector& GetBinnings() const {return fAxisX.GetBinnings();} + const std::vector& GetTrueBinnings() const {return fAxisY.GetBinnings();} + + protected: + // Derived classes can be trusted take care of their own construction + EnsembleReweightableSpectrum(const FitMultiverse* multiverse, + const LabelsAndBins& axisX, + const LabelsAndBins& axisY) + : fMultiverse(multiverse), + fPOT(0), fLivetime(0), + fAxisX(axisX), fAxisY(axisY) + { + } + + // Helper for LoadFrom + EnsembleReweightableSpectrum(const FitMultiverse* multiverse, + const Eigen::MatrixXd&& mat, + const LabelsAndBins& recoAxis, + const LabelsAndBins& trueAxis, + double pot, double livetime); + + + EnsembleReweightableSpectrum& PlusEqualsHelper(const EnsembleReweightableSpectrum& rhs, int sign, const std::string& func); + + void _SaveTo(TDirectory* dir, + const std::string& name, + const std::string& type) const; + + void CheckMultiverses(const FitMultiverse& rhs, const std::string& func) const; + + const FitMultiverse* fMultiverse; + + Eigen::MatrixXd fMat; + double fPOT; + double fLivetime; + + LabelsAndBins fAxisX, fAxisY; + }; +} \ No newline at end of file diff --git a/CAFAna/Core/EnsembleSpectrum.cxx b/CAFAna/Core/EnsembleSpectrum.cxx new file mode 100644 index 00000000..3dcb6b7f --- /dev/null +++ b/CAFAna/Core/EnsembleSpectrum.cxx @@ -0,0 +1,519 @@ +#include "CAFAna/Core/EnsembleSpectrum.h" + +#include "CAFAna/Core/EnsembleRatio.h" + +#include "CAFAna/Core/FitMultiverse.h" +#include "CAFAna/Core/Utilities.h" + +#include "TDirectory.h" +#include "TGraphAsymmErrors.h" +#include "TH1.h" +#include "TObjString.h" +#include "TPad.h" +#include + +namespace ana +{ + //---------------------------------------------------------------------- + EnsembleSpectrum::EnsembleSpectrum(IValueEnsembleSource& src, + const LabelsAndBins& axis) + : fMultiverse(src.GetMultiverse()), + fHist(Hist::Zero((axis.GetBins1D().NBins()+2) * fMultiverse->NUniv())), + fPOT(0), fLivetime(0), + fAxis(axis) + { + src.Register(this); + } + + //---------------------------------------------------------------------- + EnsembleSpectrum EnsembleSpectrum::MergeSpectra(const std::vector specs, + const FitMultiverse* multiverse) + { + + // we take characteristics from the first spectrum + LabelsAndBins labelsAndBins = LabelsAndBins(specs[0].GetLabels(), specs[0].GetBinnings()); + double pot = specs[0].POT(); + double livetime = specs[0].Livetime(); + int bins = labelsAndBins.GetBins1D().NBins(); + + // are these two extrabins overflow and underflow? + //Eigen::ArrayXd data(bins+2, 1); + // not sure why this one works but not the one above + // we will replace contents here with that of the different spectra + Eigen::ArrayXd data = specs[0].GetEigen().replicate(multiverse->NUniv(), 1); + for ( unsigned int i = 0; iNUniv(); i++){ + // sanity checks + assert(specs[i].ToTH1(pot)->GetNbinsX()==bins && "one of the spectra has different nbins!"); + assert(specs[i].POT() == pot && "one of the spectra has a different POT!"); + assert(specs[i].Livetime() == livetime && "one of the spectra has a different livetime!"); + + // get this universe spectra eigenarray + Eigen::ArrayXd spec = specs[i].GetEigen(); + // copy into new array + for (int b = 0; b <= bins ; b++){ + data[ b + (bins+2)*i ] = spec[b]; + } + } + + return EnsembleSpectrum(multiverse, Hist::Adopt(std::move(data)), specs[0].POT(), specs[0].Livetime(), + LabelsAndBins(specs[0].GetLabels(), specs[0].GetBinnings())); + } + + //---------------------------------------------------------------------- + EnsembleSpectrum EnsembleSpectrum::MergeEnsembles( const std::vector ensembles, + const FitMultiverse* multiverse) + { + + unsigned int nunivs = 0; + for (auto & ensemble : ensembles){ + nunivs += ensemble.NUniverses(); + } + nunivs -= ensembles.size(); // subtract all nominals (number of ensembles), + nunivs += 1; // and add one more (we just need one nom) + + // need something that stitches together the different multiverses + // in the meantime user has to make sure the multiverse provided matches the ensembles given... + assert(multiverse->NUniv() == nunivs && "The FitMultiverse provided does not match the size of EnsembleSpectrum"); + + LabelsAndBins labelsAndBins = LabelsAndBins(ensembles[0].Nominal().GetLabels(), ensembles[0].GetBinnings()); + double pot = ensembles[0].Nominal().POT(); + double livetime = ensembles[0].Nominal().Livetime(); + int bins = labelsAndBins.GetBins1D().NBins(); + + + //we will store data here + Eigen::ArrayXd data = ensembles[0].Nominal().GetEigen().replicate(nunivs, 1); + // first copy the nominal of first ensemble, assuming they are all the same + Eigen::ArrayXd nom = ensembles[0].Nominal().GetEigen(); + for (int b = 0; b <= bins ; b++){ + data[ b ] = nom[b]; + } + + // now the rest of the universes + unsigned int univcount = 1; + for (unsigned int i = 0; iGetNbinsX()==bins && "one of the ensembles has different nbins!"); + assert(ensembles[i].Universe(j).POT() == pot && "one of the ensembles has a different POT!"); + assert(ensembles[i].Universe(j).Livetime() == livetime && "one of the ensembles has a different livetime!"); + + // get this universe spectra eigenarray + Eigen::ArrayXd spec = ensembles[i].Universe(j).GetEigen(); + // copy into new array + for (int b = 0; b <= bins ; b++){ + data[ b + (bins+2)*univcount ] = spec[b]; + } + univcount++; + } + } + + assert(nunivs == univcount && "uh-oh, we miscounted universes"); + + return EnsembleSpectrum(multiverse, Hist::Adopt(std::move(data)), ensembles[0].Nominal().POT(), ensembles[0].Nominal().Livetime(), + LabelsAndBins(ensembles[0].Nominal().GetLabels(), ensembles[0].Nominal().GetBinnings())); + + } + + //---------------------------------------------------------------------- + EnsembleSpectrum EnsembleSpectrum::ReplicatedData(const Spectrum& spec, const FitMultiverse* multiverse) + { + Eigen::ArrayXd data = spec.GetEigen().replicate(multiverse->NUniv(), 1); + + return EnsembleSpectrum(multiverse, Hist::Adopt(std::move(data)), spec.POT(), spec.Livetime(), + LabelsAndBins(spec.GetLabels(), spec.GetBinnings())); + } + + //---------------------------------------------------------------------- + void EnsembleSpectrum::FillSingle(double x, double w, int universeId) + { + // Filling a single constituent universe + const int bin = fAxis.GetBins1D().FindBin(x); + fHist.Fill((fAxis.GetBins1D().NBins()+2) * universeId + bin, w); + } + + //---------------------------------------------------------------------- + void EnsembleSpectrum::FillEnsemble(double x, const std::vector& ws) + { + const unsigned int bin = fAxis.GetBins1D().FindBin(x); + const unsigned int nbins = fAxis.GetBins1D().NBins()+2; + + const unsigned int nuniv = fMultiverse->NUniv(); + assert(ws.size() == nuniv); + + for(unsigned int univIdx = 0; univIdx < nuniv; ++univIdx) + fHist.Fill(nbins * univIdx + bin, ws[univIdx]); + } + + //---------------------------------------------------------------------- + void EnsembleSpectrum::FillPOT(double pot) + { + fPOT += pot; + } + + //---------------------------------------------------------------------- + void EnsembleSpectrum::FillLivetime(double livetime) + { + fLivetime += livetime; + } + + //---------------------------------------------------------------------- + unsigned int EnsembleSpectrum::NUniverses() const + { + return fMultiverse->NUniv(); + } + + //---------------------------------------------------------------------- + Spectrum EnsembleSpectrum::Universe(unsigned int univIdx) const + { + const int nbins = fAxis.GetBins1D().NBins()+2; + if(fHist.HasStan()){ + return Spectrum(Eigen::ArrayXstan(fHist.GetEigenStan().segment(nbins*univIdx, nbins)), + fAxis, fPOT, fLivetime); + } + else{ + return Spectrum(Eigen::ArrayXd(fHist.GetEigen().segment(nbins*univIdx, nbins)), + fAxis, fPOT, fLivetime); + } + } + + //---------------------------------------------------------------------- + TGraphAsymmErrors* EnsembleSpectrum::ErrorBand(double exposure, + EExposureType expotype, + EBinType bintype) const + { + // TODO lots of code duplication with EnsembleRatio + + const Eigen::ArrayXd arr = fHist.GetEigen() * exposure / (expotype == kPOT ? fPOT : fLivetime); + + TGraphAsymmErrors* g = new TGraphAsymmErrors; + + const int nbins = fAxis.GetBins1D().NBins()+2; + const std::vector& edges = fAxis.GetBins1D().Edges(); + + for(int binIdx = 1; binIdx+1 < nbins; ++binIdx){ + const double dx = edges[binIdx] - edges[binIdx-1]; + assert(dx > 0); + + const double xnom = (edges[binIdx-1] + edges[binIdx]) / 2; // bin center + const double ynom = (bintype == kBinDensity) ? arr[binIdx] / dx : arr[binIdx]; + g->SetPoint(binIdx-1, xnom, ynom); + + std::vector ys; + ys.reserve(NUniverses()-1); + for(unsigned int univIdx = 1; univIdx < NUniverses(); ++univIdx) + ys.push_back((bintype == kBinDensity) ? arr[univIdx*nbins + binIdx] / dx : arr[univIdx*nbins + binIdx]); + + // 1 sigma + const double y0 = FindQuantile(.5-0.6827/2, ys); + const double y1 = FindQuantile(.5+0.6827/2, ys); + + // It's theoretically possible for the central value to be outside the + // error bands - clamp to zero in that case + g->SetPointError(binIdx-1, dx/2, dx/2, + std::max(ynom-y0, 0.), + std::max(y1-ynom, 0.)); + } // end for binIdx + + return g; + } + + //---------------------------------------------------------------------- + Eigen::MatrixXd EnsembleSpectrum::CovarianceMatrix(const double exposure, EExposureType expotype) + { + assert (fMultiverse->MultiverseType() == kRandomGas); + + const Eigen::ArrayXd& arr = fHist.GetEigen() * exposure / (expotype == kPOT ? fPOT : fLivetime); + + const int nbins = fAxis.GetBins1D().NBins()+2; + std::vector histVec; + histVec.reserve(NUniverses()); + + for(unsigned int univIdx = 1; univIdx < NUniverses(); ++univIdx) + histVec.push_back(arr.segment(nbins*univIdx, nbins)); + + return ana::CalcCovMx(histVec); + } + + //---------------------------------------------------------------------- + Eigen::MatrixXd EnsembleSpectrum::BiasMatrix(const double exposure, EExposureType expotype) + { + assert (fMultiverse->MultiverseType() == kRandomGas); + + const Eigen::ArrayXd& arr = fHist.GetEigen() * exposure / (expotype == kPOT ? fPOT : fLivetime); + + const int nbins = fAxis.GetBins1D().NBins()+2; + std::vector histVec; + histVec.reserve(NUniverses()); + + for(unsigned int univIdx = 1; univIdx < NUniverses(); ++univIdx) + histVec.push_back(arr.segment(nbins*univIdx, nbins)); + + return ana::CalcBiasMx(arr.segment(0, nbins), histVec); + } + + //---------------------------------------------------------------------- + void EnsembleSpectrum::Scale(double c) + { + fHist.Scale(c); + } + + //---------------------------------------------------------------------- + EnsembleSpectrum& EnsembleSpectrum::PlusEqualsHelper(const EnsembleSpectrum& rhs, int sign, const std::string& func) + { + CheckMultiverses(rhs.GetMultiverse(), func); + + // In this case it would be OK to have no POT/livetime + if(rhs.fHist.Initialized() && rhs.fHist.Integral() == 0) return *this; + + if((!fPOT && !fLivetime) || (!rhs.fPOT && !rhs.fLivetime)){ + std::cout << "Error: can't sum Spectrum with no POT or livetime: " + << fPOT << " " << rhs.fPOT << " " << fLivetime << " " << rhs.fLivetime + << std::endl; + abort(); + } + + if(!fLivetime && !rhs.fPOT){ + std::cout << "Error: can't sum Spectrum with POT (" + << fPOT << ") but no livetime and Spectrum with livetime (" + << rhs.fLivetime << " sec) but no POT." << std::endl; + abort(); + } + + if(!fPOT && !rhs.fLivetime){ + std::cout << "Error: can't sum Spectrum with livetime (" + << fLivetime << " sec) but no POT and Spectrum with POT (" + << rhs.fPOT << ") but no livetime." << std::endl; + abort(); + } + + // And now there are still a bunch of good cases to consider + + if(fPOT && rhs.fPOT){ + // Scale by POT when possible + fHist.Add(rhs.fHist, sign*fPOT/rhs.fPOT); + + if(fLivetime && rhs.fLivetime){ + // If POT/livetime ratios match, keep regular lifetime, otherwise zero + // it out. + if(!AlmostEqual(fLivetime*rhs.fPOT, rhs.fLivetime*fPOT)) + fLivetime = 0; + } + if(!fLivetime && rhs.fLivetime){ + // If the RHS has a livetime and we don't, copy it in (suitably scaled) + fLivetime = rhs.fLivetime * fPOT/rhs.fPOT; + } + // Otherwise, keep our own livetime (if any) + + return *this; + } + + if(fLivetime && rhs.fLivetime){ + // Scale by livetime, the only thing in common + fHist.Add(rhs.fHist, sign*fLivetime/rhs.fLivetime); + + if(!fPOT && rhs.fPOT){ + // If the RHS has a POT and we don't, copy it in (suitably scaled) + fPOT = rhs.fPOT * fLivetime/rhs.fLivetime; + } + // Otherwise, keep our own POT (if any) + + return *this; + } + + // That should have been all the cases. I definitely want to know what + // happened if it wasn't. + std::cout << "EnsembleSpectrum::operator+=(). How did we get here? " + << fPOT << " " << fLivetime << " " + << rhs.fPOT << " " << rhs.fLivetime << std::endl; + abort(); + } + + //---------------------------------------------------------------------- + EnsembleSpectrum& EnsembleSpectrum::operator+=(const EnsembleSpectrum& rhs) + { + return PlusEqualsHelper(rhs, +1, __func__); + } + + //---------------------------------------------------------------------- + EnsembleSpectrum EnsembleSpectrum::operator+(const EnsembleSpectrum& rhs) const + { + EnsembleSpectrum ret = *this; + ret += rhs; + return ret; + } + + //---------------------------------------------------------------------- + EnsembleSpectrum& EnsembleSpectrum::operator-=(const EnsembleSpectrum& rhs) + { + return PlusEqualsHelper(rhs, -1, __func__); + } + + //---------------------------------------------------------------------- + EnsembleSpectrum EnsembleSpectrum::operator-(const EnsembleSpectrum& rhs) const + { + EnsembleSpectrum ret = *this; + ret -= rhs; + return ret; + } + + //---------------------------------------------------------------------- + EnsembleSpectrum& EnsembleSpectrum::operator*=(const EnsembleRatio& rhs) + { + CheckMultiverses(rhs.GetMultiverse(), __func__); + fHist.Multiply(rhs.fHist); + + return *this; + } + + //---------------------------------------------------------------------- + EnsembleSpectrum EnsembleSpectrum::operator*(const EnsembleRatio& rhs) const + { + EnsembleSpectrum ret = *this; + ret *= rhs; + return ret; + } + + //---------------------------------------------------------------------- + EnsembleSpectrum& EnsembleSpectrum::operator/=(const EnsembleRatio& rhs) + { + CheckMultiverses(rhs.GetMultiverse(), __func__); + fHist.Divide(rhs.fHist); + + return *this; + } + + //---------------------------------------------------------------------- + EnsembleSpectrum EnsembleSpectrum::operator/(const EnsembleRatio& rhs) const + { + EnsembleSpectrum ret = *this; + ret /= rhs; + return ret; + } + + //---------------------------------------------------------------------- + void EnsembleSpectrum::SaveTo(TDirectory* dir, const std::string& name) const + { + TDirectory* tmp = gDirectory; + + dir = dir->mkdir(name.c_str()); // switch to subdir + dir->cd(); + + TObjString("EnsembleSpectrum").Write("type"); + + fMultiverse->SaveTo(dir, "multiverse"); + + // TODO potentially version of Write() that doesn't take binning + fHist.Write(Binning::Simple(fHist.GetNbinsX(), 0, fHist.GetNbinsX())); + + TH1D hPot("", "", 1, 0, 1); + hPot.Fill(.5, fPOT); + hPot.Write("pot"); + TH1D hLivetime("", "", 1, 0, 1); + hLivetime.Fill(.5, fLivetime); + hLivetime.Write("livetime"); + + for(unsigned int i = 0; i < NDimensions(); ++i){ + TObjString(GetLabels()[i].c_str()).Write(TString::Format("label%d", i).Data()); + GetBinnings()[i].SaveTo(dir, TString::Format("bins%d", i).Data()); + } + + dir->Write(); + delete dir; + + tmp->cd(); + } + + //---------------------------------------------------------------------- + EnsembleSpectrum::EnsembleSpectrum(const FitMultiverse* multiverse, + const Hist&& hist, + double pot, + double livetime, + const LabelsAndBins& axis) + : fMultiverse(multiverse), fHist(hist), fPOT(pot), fLivetime(livetime), fAxis(axis) + { + } + + //---------------------------------------------------------------------- + std::unique_ptr EnsembleSpectrum::LoadFrom(TDirectory* topdir, const std::string& name) + { + std::unique_ptr dir(topdir->GetDirectory(name.c_str())); // switch to subdir + assert(dir); + + DontAddDirectory guard; + + std::unique_ptr tag((TObjString*)dir->Get("type")); + assert(tag); + assert(tag->GetString() == "EnsembleSpectrum"); + + std::unique_ptr hPot((TH1*)dir->Get("pot")); + assert(hPot); + std::unique_ptr hLivetime((TH1*)dir->Get("livetime")); + assert(hLivetime); + + // TODO LabelsAndBins::LoadFrom() or FromDirectory() + std::vector labels; + std::vector bins; + for(int i = 0; ; ++i){ + const std::string subname = TString::Format("bins%d", i).Data(); + TDirectory* subdir = dir->GetDirectory(subname.c_str()); + if(!subdir) break; + delete subdir; + bins.push_back(*Binning::LoadFrom(dir.get(), subname)); + std::unique_ptr label((TObjString*)dir->Get(TString::Format("label%d", i))); + labels.push_back(label->GetString().Data()); + } + + return std::unique_ptr(new EnsembleSpectrum(FitMultiverse::LoadFrom(dir.get(), "multiverse"), + Hist::FromDirectory(dir.get()), + hPot->GetBinContent(1), + hLivetime->GetBinContent(1), + LabelsAndBins(labels, bins))); + } + + //---------------------------------------------------------------------- + void EnsembleSpectrum::CheckMultiverses(const FitMultiverse& rhs, + const std::string& func) const + { + if(&rhs == fMultiverse) return; + + std::cout << "EnsembleSpectrum::" << func << ": attempting to combine two spectra made with different multiverses: " << std::endl; + std::cout << " " << fMultiverse->ShortName() << std::endl; + std::cout << "vs" << std::endl; + std::cout << rhs.ShortName() << std::endl; + abort(); + } + + //---------------------------------------------------------------------- + void DrawErrorBand(TH1* nom, TGraphAsymmErrors* band, int bandCol, double alpha) + { + if(bandCol == -1) bandCol = nom->GetLineColor()-10; // hopefully a lighter version + + // Check if this pad has already been drawn in + const bool same = gPad && !gPad->GetListOfPrimitives()->IsEmpty(); + + nom->Draw(same ? "hist same" : "hist"); + + band->SetFillColorAlpha(bandCol, alpha); + band->Draw("e2 same"); + + nom->Draw("hist same"); + + // If we are the first spectrum to draw, scale the y-axis appropriately to + // fit the error band as well as the nominal + if(!same){ + double maxY = 0; + // Don't consider underflow or overflow bins when determining maximum + for(int i = 1; i < band->GetN()-1; ++i){ + if(band->GetY()[i] > 1e99) continue; // effectively infinite + maxY = std::max(maxY, band->GetY()[i] + band->GetErrorYhigh(i)); + } + + // Use non-zero lower value so that SetLogy() still works + nom->GetYaxis()->SetRangeUser(1e-10, 1.1 * maxY); + } + + gPad->RedrawAxis(); + } +} \ No newline at end of file diff --git a/CAFAna/Core/EnsembleSpectrum.h b/CAFAna/Core/EnsembleSpectrum.h new file mode 100644 index 00000000..3bfc082d --- /dev/null +++ b/CAFAna/Core/EnsembleSpectrum.h @@ -0,0 +1,141 @@ +#pragma once + +#include "cafanacore/Spectrum.h" + +#include "CAFAna/Core/Cut.h" +#include "CAFAna/Core/HistAxis.h" +#include "CAFAna/Core/IRecordSource.h" +#include "CAFAna/Core/Weight.h" + +#include + +class TGraphAsymmErrors; + +namespace ana +{ + class EnsembleRatio; + class FitMultiverse; + + class EnsembleSpectrum : public IValueEnsembleSink + { + public: + friend class EnsembleRatio; + + /// Construct an ensemble spectrum from a source of values and an axis + /// definition + EnsembleSpectrum(IValueEnsembleSource& src, const LabelsAndBins& axis); + + /// \brief Shorthand construction with a source of records and a HistAxis + /// defining the Var to extract from those records. + template + EnsembleSpectrum(_IRecordEnsembleSource& src, + const _HistAxis<_Var>& axis) + : EnsembleSpectrum(src[axis.GetVar1D()], axis) + { + } + + /// Construct an ensemble spectrum from a set of spectrum which correspond to the given multiverse + static EnsembleSpectrum MergeSpectra(const std::vector specs, const FitMultiverse* multiverse); + + /// Construct an ensemble spectrum merging several ensemble spectrum. + /// user has to make sure the multiverse provided matches the ensembles given + static EnsembleSpectrum MergeEnsembles( const std::vector ensembles, const FitMultiverse* multiverse); + +// // The only valid thing to do with such a spectrum is to assign something +// /// else into it. +// static EnsembleSpectrum Uninitialized(){return EnsembleSpectrum();} +// virtual ~EnsembleSpectrum(); + /// \brief Creates an ensemble spectrum for "data" from an input \ref Spectrum + // which is replicated nUniverse times from the multiverse which it adopts. + // Note that this is a temporary workaround for now + static EnsembleSpectrum ReplicatedData(const Spectrum& spec, const FitMultiverse* multiverse); + + Spectrum Nominal() const {return Universe(0);} + unsigned int NUniverses() const; + Spectrum Universe(unsigned int i) const; + + // TODO consider naming confusion with Universe() above + const FitMultiverse& GetMultiverse() const {return *fMultiverse;} + + double POT() const {return fPOT;} + + double Livetime() const {return fLivetime;} + + /// Result can be painted prettily with \ref DrawErrorBand + TGraphAsymmErrors* ErrorBand(double exposure, + EExposureType expotype = kPOT, + EBinType bintype = kBinContent) const; + + /// Wrapper for \ref CalcCovMx + Eigen::MatrixXd CovarianceMatrix(const double exposure, EExposureType expotype=kPOT); + + /// Wrapper for \ref CalcBiasMx + Eigen::MatrixXd BiasMatrix(const double exposure, EExposureType expotype=kPOT); + + virtual void FillSingle(double x, double w, int universeId) override; + + virtual void FillEnsemble(double x, const std::vector& ws) override; + + virtual void FillPOT(double pot) override; + + /// DO NOT USE UNLESS YOU ARE 110% CERTAIN THERE ISN'T A BETTER WAY! + void OverridePOT(double newpot) {fPOT = newpot;} + + virtual void FillLivetime(double livetime) override; + + void Scale(double c); + + EnsembleSpectrum& operator+=(const EnsembleSpectrum& rhs); + EnsembleSpectrum operator+(const EnsembleSpectrum& rhs) const; + + EnsembleSpectrum& operator-=(const EnsembleSpectrum& rhs); + EnsembleSpectrum operator-(const EnsembleSpectrum& rhs) const; + + EnsembleSpectrum& operator*=(const EnsembleRatio& rhs); + EnsembleSpectrum operator*(const EnsembleRatio& rhs) const; + + EnsembleSpectrum& operator/=(const EnsembleRatio& rhs); + EnsembleSpectrum operator/(const EnsembleRatio& rhs) const; + + void SaveTo(TDirectory* dir, const std::string& name) const; + static std::unique_ptr LoadFrom(TDirectory* dir, + const std::string& name); + + unsigned int NDimensions() const{return fAxis.NDimensions();} + std::vector GetLabels() const {return fAxis.GetLabels();} + std::vector GetBinnings() const {return fAxis.GetBinnings();} + + protected: + friend class EnsembleReweightableSpectrum; + + /// Helper for LoadFrom() + EnsembleSpectrum(const FitMultiverse* multiverse, + const Hist&& hist, + double pot, + double livetime, + const LabelsAndBins& axis); + + void CheckMultiverses(const FitMultiverse& rhs, + const std::string& func) const; + + /// Helper for operator+= and operator-= + EnsembleSpectrum& PlusEqualsHelper(const EnsembleSpectrum& rhs, int sign, + const std::string& func); + + const FitMultiverse* fMultiverse; + + mutable Hist fHist; + mutable double fPOT; + mutable double fLivetime; + mutable LabelsAndBins fAxis; + }; + + // Commutative + inline EnsembleSpectrum operator*(const EnsembleRatio& lhs, const EnsembleSpectrum& rhs){return rhs*lhs;} + inline EnsembleSpectrum operator/(const EnsembleRatio& lhs, const EnsembleSpectrum& rhs){return rhs/lhs;} + + void DrawErrorBand(TH1* nom, + TGraphAsymmErrors* band, + int bandCol = -1, + double alpha = 1); +} \ No newline at end of file diff --git a/CAFAna/Core/EnsembleSpectrumMerger.cxx b/CAFAna/Core/EnsembleSpectrumMerger.cxx new file mode 100644 index 00000000..af3411d2 --- /dev/null +++ b/CAFAna/Core/EnsembleSpectrumMerger.cxx @@ -0,0 +1,65 @@ +#include "CAFAna/Core/EnsembleSpectrum.h" + +#include "CAFAna/Core/EnsembleRatio.h" + +#include "CAFAna/Core/FitMultiverse.h" +#include "CAFAna/Core/Utilities.h" +#include "CAFAna/Core/EnsembleSpectrum.h" +#include "CAFAna/Core/EnsembleSpectrumMerger.h" +#include +#include + + +namespace ana{ + + EnsembleSpectrumMerger::EnsembleSpectrumMerger(std::vector< Spectrum> specs, + const FitMultiverse* multiverse, + const LabelsAndBins& axis) + + EnsembleSpectrum EnsembleSpectrumMerger::GetEnsembleSpectrum + : fMultiverse(multiverse), + fHist(Hist::Zero((axis.GetBins1D().NBins()+2) * fMultiverse->NUniv())), + fPOT(specs[0].POT()), + fLivetime(specs[0].Livetime()), + fAxis(axis) + { + + std::cout<< "how many multiverses? "<< fMultiverse->NUniv()<NUniv());// append here all the spectra + Eigen::ArrayXd data(bins+2, 1); + for ( unsigned int i = 0; iNUniv(); i++){ + // sanity checks + assert(specs[i].ToTH1(pot).GetNbinsX()==bins && "one of the spectra has different nbins!"); + assert(specs[i].POT() == pot && "one of the spectra has a different POT!"); + assert(specs[i].Livetime() == livetime && "one of the spectra has a different livetime!"); + + // get this universe spectra eigenarray + Eigen::ArrayXd spec = specs[i].GetEigen(); + // copy into new array + for (unsigned int b = 0; b <= bins ; b++){ + data[ b + (bins+2)*i ] = spec[b]; + fHist.Fill(b + (bins+2)*i, spec[b]); + } + } + + assert( data.rows() == fHist.GetEigen().rows() && "data and hist are diffesrent size"); + std::cout<<"now moving data\n"; + } + +// //---------------------------------------------------------------------- +// EnsembleSpectrumMerger::~EnsembleSpectrumMerger() +// { +// } + +} \ No newline at end of file diff --git a/CAFAna/Core/EnsembleSpectrumMerger.h b/CAFAna/Core/EnsembleSpectrumMerger.h new file mode 100644 index 00000000..ee0a0970 --- /dev/null +++ b/CAFAna/Core/EnsembleSpectrumMerger.h @@ -0,0 +1,36 @@ + +#pragma once + +#include "cafanacore/Spectrum.h" + +#include "CAFAna/Core/Cut.h" +#include "CAFAna/Core/HistAxis.h" +#include "CAFAna/Core/IRecordSource.h" +#include "CAFAna/Core/Weight.h" +#include "CAFAna/Core/EnsembleSpectrum.h" +#include + +namespace ana{ + + + class EnsembleSpectrumMerger//: public EnsembleSpectrum + { + public: + EnsembleSpectrumMerger(std::vector specs, + const FitMultiverse* multiverse, const LabelsAndBins& axis); + + // virtual ~EnsembleSpectrumMerger(); + + protected: + const FitMultiverse* fMultiverse; + + mutable Hist fHist; + mutable double fPOT; + mutable double fLivetime; + mutable LabelsAndBins fAxis; + //EnsembleSpectrumMerger(){}; + + }; + + +} \ No newline at end of file diff --git a/CAFAna/Core/FitMultiverse.h b/CAFAna/Core/FitMultiverse.h new file mode 100644 index 00000000..cd4db765 --- /dev/null +++ b/CAFAna/Core/FitMultiverse.h @@ -0,0 +1,85 @@ +#pragma once + +#include "CAFAna/Core/IFitSyst.h" + +#include +#include + +class TDirectory; + +namespace ana +{ + template using _Universe = std::unordered_map; + + enum EMultiverseType{kHypercross, kRandomGas}; + + using FitUniverse = _Universe; + + /// \brief Collection of "universes" (SystShifts) + /// + /// Two Multiverses are equivalent if-and-only-if they have the same address + /// + /// Universe zero is always the nominal universe (no systematic shifts) + class FitMultiverse: public INamed + { + public: + // User should not delete these though + virtual ~FitMultiverse() {} + + /// \brief Named constructor. Scan each parameter sequentially + /// + /// \param systs The list of systematic parameters to scan + /// \param nsigma Each parameter will be scanned from -nsigma to +nsigma + static const FitMultiverse& Hypercross(const std::vector& systs, + int nsigma = 3); + + static const unsigned int kTrulyRandom = 123456789; + + /// \brief Named constructor. Throw all parameters as gaussians + /// + /// \param systs The list of systematic parameters to vary + /// \param Nuniv Number of universes to generate + /// \param seed Pseudo-random seed. Pass Multiverse::kTrulyRandom for a + /// real random seed. Beware incompatibility between universes + /// with different seeds. + static const FitMultiverse& RandomGas(const std::vector& systs, + int Nuniv, + unsigned int seed); + + /// Total number of universes, including nominal at index 0 + unsigned int NUniv() const {return fUnivs.size();} + + /// Details of a particular universe + const FitUniverse& GetUniverse(int i) const {return fUnivs[i];} + + // TO DO: a member that returns the systematic shifts used to create this Multiverse + // std::vector GetSysts(){return } + + void SaveTo(TDirectory* dir, const std::string& name) const; + + /// Usually these return unique_ptr, but Multiverses are globally managed + static const FitMultiverse* LoadFrom(TDirectory* dir, const std::string& name); + + /// Enum that specifies the type of multiverse + // remove const? + EMultiverseType MultiverseType() const {return fMultiverseType;}; + + protected: + FitMultiverse(const std::string& shortName, + const std::string& latexName, + const std::vector& univs, + const EMultiverseType multiverseType); + + FitMultiverse(const FitMultiverse&) = delete; + + /// Special move constructor ONLY to help derived _Multiverse classes + FitMultiverse(const FitMultiverse&&); + + std::string Checksum() const; + + std::vector fUnivs; + + EMultiverseType fMultiverseType; + }; + +} \ No newline at end of file diff --git a/CAFAna/Core/FixupRecord.cxx b/CAFAna/Core/FixupRecord.cxx deleted file mode 100644 index cee4e5ec..00000000 --- a/CAFAna/Core/FixupRecord.cxx +++ /dev/null @@ -1,186 +0,0 @@ -#include "CAFAna/Core/FixupRecord.h" - -#include "CAFAna/Core/ModeConversionUtilities.h" -#include "CAFAna/Systs/XSecSystList.h" -#include "CAFAna/Analysis/AnalysisVersion.h" - -#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" - -#include "TTree.h" - -#include -#include - -namespace ana -{ - void FixupRecord(caf::SRProxy* sr, TTree* tr) - { - // Set GENIE_ScatteringMode and eRec_FromDep - if(sr->isFD){ - sr->eRec_FromDep = sr->eDepP + sr->eDepN + sr->eDepPip + - sr->eDepPim + sr->eDepPi0 + - sr->eDepOther + sr->LepE; - - sr->GENIE_ScatteringMode = - ana::GetGENIEModeFromSimbMode(sr->mode); - } - else { - sr->eRec_FromDep = sr->eRecoP + sr->eRecoN + - sr->eRecoPip + sr->eRecoPim + - sr->eRecoPi0 + sr->eRecoOther + - sr->LepE; - sr->GENIE_ScatteringMode = int(sr->mode); // TODO make this work without cast? - } - - // Patch up isFHC which isn't set properly in FD CAFs - if(sr->isFD){ - if(sr->isFHC != 0 && sr->isFHC != 1){ - if(sr->run == 20000001 || sr->run == 20000002 || - sr->run == 20000003) { - sr->isFHC = true; - static bool once = true; - if(once) { - std::cout << "\nPatching up FD file to be considered FHC" - << std::endl; - once = false; - } - } - else if(sr->run == 20000004 || sr->run == 20000005 || - sr->run == 20000006) { - sr->isFHC = false; - static bool once = true; - if(once){ - std::cout << "\nPatching up FD file to be considered RHC" - << std::endl; - once = false; - } - } - else { - std::cout - << "When patching FD CAF with unknown isFHC, saw unknown run " - << sr->run << std::endl; - abort(); - } - } - } - else{ - // ND - if(sr->isFHC == -1){ - // nu-on-e files - sr->isFHC = true; - static bool once = true; - if (once) { - std::cout << "\nPatching up nu-on-e file to be considered FHC" - << std::endl; - once = false; - } - } - else if (sr->isFHC != 0 && sr->isFHC != 1) { - std::cout << "isFHC not set properly in ND file: " << sr->isFHC - << std::endl; - abort(); - } - } - - if(tr->GetNbranches() == 302 || tr->GetNbranches() == 280 /*ndgas*/){ - static bool once = true; - if(once){ - once = false; - std::cout << "Detected TDR-era file. Skipping CV weights, which aren't going to work" << std::endl; - } - return; - } - - // These aren't going to change during the job, so do it once up-front. - static const std::vector& XSSyst_names = GetAllXSecSystNames(); - - // HACK HACK HACK for knobs that aren't in file - static bool hackOnce = true; - static std::vector veto(XSSyst_names.size()); - if(hackOnce){ - hackOnce = false; - for(unsigned int syst_it = 0; syst_it < XSSyst_names.size(); ++syst_it){ - if(ana::GetXSecSystName(syst_it) == "Mnv2p2hGaussEnhancement_NN" || - ana::GetXSecSystName(syst_it) == "Mnv2p2hGaussEnhancement_2p2h" || - ana::GetXSecSystName(syst_it) == "Mnv2p2hGaussEnhancement_1p1h" || - ana::GetXSecSystName(syst_it) == "MissingProtonFakeData" || - ana::GetXSecSystName(syst_it) == "NuWroReweightFakeData" - ) veto[syst_it] = true; - } - } - - // HACK to survive the absence of crazyFlux values in the file - sr->wgt_CrazyFlux = std::vector(7, 1); - - // Reformat the genie systs - sr->total_xsSyst_cv_wgt = 1; - - std::vector XSSyst_cv_tmp(XSSyst_names.size()); - for(unsigned int syst_it = 0; syst_it < XSSyst_names.size(); ++syst_it){ - XSSyst_cv_tmp[syst_it] = 1; - } - - static auto AnaV = GetAnaVersion(); - if(AnaV == kV3){ - for(unsigned int syst_it = 0; syst_it < XSSyst_names.size(); ++syst_it){ - // Do some error checking here - if(std::isnan(sr->cvwgt[syst_it]) || - std::isinf(sr->cvwgt[syst_it]) || - sr->cvwgt[syst_it] == 0){ - std::cout << "Warning: " << XSSyst_names[syst_it] - << " has a bad CV of " << sr->cvwgt[syst_it] - << std::endl; - } - else { - sr->total_xsSyst_cv_wgt *= sr->cvwgt[syst_it]; - } - } - } - else{ - static std::vector alreadyWarned(XSSyst_names.size(), false); - - for(unsigned int syst_it = 0; syst_it < XSSyst_names.size(); ++syst_it){ - // Continuation of the hack from further up - if(veto[syst_it]) continue; - - if(IsDoNotIncludeSyst(syst_it)){ // Multiply CV weight back into - // response splines. - if(std::isnan(sr->cvwgt[syst_it]) || - std::isinf(sr->cvwgt[syst_it]) || - XSSyst_cv_tmp[syst_it] == 0) { - if(!alreadyWarned[syst_it]){ - alreadyWarned[syst_it] = true; - std::cout << "Warning: " << XSSyst_names[syst_it] - << " has a bad CV of " << sr->cvwgt[syst_it] - << " - will only warn once" - << std::endl; - } - } - else{ - const int Nuniv = 7; // HACK HACK HACK sr->xsSyst_wgt[syst_it].size(); - for(int univ_it = 0; univ_it < Nuniv; ++univ_it){ - sr->xsSyst_wgt[syst_it][univ_it] *= sr->cvwgt[syst_it]; - } - } - } - else{ // Include CV weight in the total - // Do some error checking here - if(std::isnan(sr->cvwgt[syst_it]) || - std::isinf(sr->cvwgt[syst_it]) || - sr->cvwgt[syst_it] == 0) { - if(!alreadyWarned[syst_it]){ - alreadyWarned[syst_it] = true; - std::cout << "Warning: " << XSSyst_names[syst_it] - << " has a bad CV of " << sr->cvwgt[syst_it] - << " - will only warn once" - << std::endl; - } - } - else{ - sr->total_xsSyst_cv_wgt *= sr->cvwgt[syst_it]; - } - } - } - } // end version switch - } -} diff --git a/CAFAna/Core/FixupRecord.h b/CAFAna/Core/FixupRecord.h deleted file mode 100644 index b908a2ac..00000000 --- a/CAFAna/Core/FixupRecord.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "duneanaobj/StandardRecord/Proxy/FwdDeclare.h" - -class TTree; - -namespace ana -{ - void FixupRecord(caf::SRProxy* sr, TTree* tr); -} diff --git a/CAFAna/Core/HistAxis.h b/CAFAna/Core/HistAxis.h index c4e81507..168122cf 100644 --- a/CAFAna/Core/HistAxis.h +++ b/CAFAna/Core/HistAxis.h @@ -7,4 +7,9 @@ namespace ana { typedef _HistAxis HistAxis; + typedef _HistAxis SRHistAxis; + typedef _HistAxis TruthHistAxis; + typedef _HistAxis TruthPartHistAxis; + typedef _HistAxis RecoPartHistAxis; + typedef _HistAxis NDHistAxis; } diff --git a/CAFAna/Core/IRecordSink.h b/CAFAna/Core/IRecordSink.h new file mode 100644 index 00000000..d2e0b11f --- /dev/null +++ b/CAFAna/Core/IRecordSink.h @@ -0,0 +1,15 @@ +#pragma once + +#include "cafanacore/IRecordSink.h" +#include "cafanacore/IRecordEnsembleSink.h" + +#include "duneanaobj/StandardRecord/Proxy/FwdDeclare.h" + +namespace ana +{ + using ISRSink = _IRecordSink; + using IInteractionSink = _IRecordSink; + +// using ISpillEnsembleSink = _IRecordEnsembleSink; + using IInteractionEnsembleSink = _IRecordEnsembleSink; +} \ No newline at end of file diff --git a/CAFAna/Core/IRecordSource.cxx b/CAFAna/Core/IRecordSource.cxx new file mode 100644 index 00000000..7d0b250b --- /dev/null +++ b/CAFAna/Core/IRecordSource.cxx @@ -0,0 +1,353 @@ +#include "CAFAna/Core/IRecordSource.h" + +#include "CAFAna/Core/Multiverse.h" + +#include "CAFAna/Core/SystShifts.h" + +#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" + +# include + +namespace ana +{ + + //---------------------------------------------------------------------- + class ShiftedInteractionEnsembleSource: + public PassthroughExposure + { + public: + ShiftedInteractionEnsembleSource(IInteractionSource& src, + const Multiverse& multiverse); + + virtual void HandleRecord(const caf::SRInteractionProxy* ixn, double weight) override; + + virtual const ana::FitMultiverse* GetMultiverse() const override {return fMultiverse;} + + protected: + const ana::FitMultiverse* fMultiverse; + std::vector fShifts; + }; + + //---------------------------------------------------------------------- + ShiftedInteractionEnsembleSource:: + ShiftedInteractionEnsembleSource(IInteractionSource& src, const Multiverse& multiverse) + : fMultiverse(&multiverse) + { + src.Register(this); + + // Turn the universes into concrete SystShifts objects up-front + fShifts.reserve(multiverse.NUniv()); + // This next line is not working... + for(unsigned int i = 0; i < multiverse.NUniv(); ++i) fShifts.emplace_back(multiverse.GetUniverse(i)); + } + + //---------------------------------------------------------------------- + void ShiftedInteractionEnsembleSource::HandleRecord(const caf::SRInteractionProxy* slc, + double weight) + { + if(weight == 0) return; + + std::vector weights(fShifts.size(), weight); + + bool anyShifted = false; + + for(unsigned int univIdx = 0; univIdx < fShifts.size(); ++univIdx){ + // Need to provide a clean slate for each new set of systematic + // shifts to work from. Copying the whole StandardRecord is pretty + // expensive, so modify it in place and revert it afterwards. + + caf::SRProxySystController::BeginTransaction(); + + bool shifted = false; + + // Can special-case nominal to not pay cost of Shift() + if(!fShifts[univIdx].IsNominal()){ + // const_cast is naughty. I hope the fact that we put the record back + // afterwards absolves most sins. + fShifts[univIdx].Shift(const_cast(slc), weights[univIdx]); + // If there were only weighting systs applied then the cached + // nominal values are still valid. + shifted = caf::SRProxySystController::AnyShifted(); + } + + // Interaction was shifted or we are already in the slow path, so we have to + // handle this individually + if((shifted || anyShifted) && weights[univIdx] != 0) + for(IInteractionEnsembleSink* sink: fSinks) + sink->HandleSingleRecord(slc, weights[univIdx], univIdx); + + // Return StandardRecord to its unshifted form ready for the next + // histogram. + caf::SRProxySystController::Rollback(); + + // We entered the slow path for the first time for this universe, have to + // catch up with all the other universes we were hoping to be able to + // handle in the fast path. + if(shifted && !anyShifted){ + anyShifted = true; + + for(unsigned int prevIdx = 0; prevIdx < univIdx; ++prevIdx){ + if(weights[prevIdx] == 0) continue; + + for(IInteractionEnsembleSink* sink: fSinks){ + sink->HandleSingleRecord(slc, weights[prevIdx], prevIdx); + } + } // end for prevIdx + } // end if shifted for the first time + } // end for univIdx + + // Fast path in case none of the records got rewritten, can treat as an + // ensemble with weights. + if(!anyShifted){ + for(IInteractionEnsembleSink* sink: fSinks){ + sink->HandleEnsemble(slc, weights); + } + } + } + + //---------------------------------------------------------------------- + IInteractionEnsembleSource& IInteractionSource:: + Ensemble(const Multiverse& multiverse) + { + return fEnsembleSources.template Get(&multiverse, *this, multiverse); + } + //---------------------------------------------------------------------- + // Truth branch version of ensembles?? + + + //---------------------------------------------------------------------- + + template VectorAdaptor:: + VectorAdaptor(_IRecordSource>& src, + Func_t vecGetter) + : fVecGetter(vecGetter) + { + src.Register(this); + } + + //---------------------------------------------------------------------- + template void VectorAdaptor:: + HandleRecord(const caf::Proxy* rec, double weight) + { + for(const caf::Proxy& to: fVecGetter(rec)) + for(auto& sink: _IRecordSource>::fSinks) + sink->HandleRecord(&to, weight); + } + //---------------------------------------------------------------------- + template EnsembleVectorAdaptor:: + EnsembleVectorAdaptor(_IRecordEnsembleSource>& src, + Func_t vecGetter) + : fSource(&src), fVecGetter(vecGetter) + { + src.Register(this); + } + + //---------------------------------------------------------------------- + template void EnsembleVectorAdaptor:: + HandleSingleRecord(const caf::Proxy* rec, + double weight, + int universeId) + { + for(const caf::Proxy& to: fVecGetter(rec)) + for(auto& sink: _IRecordEnsembleSource>::fSinks) + sink->HandleSingleRecord(&to, weight, universeId); + } + + //---------------------------------------------------------------------- + template void EnsembleVectorAdaptor:: + HandleEnsemble(const caf::Proxy* rec, + const std::vector& weights) + { + for(const caf::Proxy& to: fVecGetter(rec)) + for(auto& sink: _IRecordEnsembleSource>::fSinks) + sink->HandleEnsemble(&to, weights); + } + + //---------------------------------------------------------------------- + //---------------------------------------------------------------------- + + template + const caf::Proxy>& GetRecoParticles(const caf::SRInteractionProxy* ixn) + { + if constexpr (PartType == RecoType::kDLP) + return ixn->part.dlp; + else if constexpr (PartType == RecoType::kPandora) + return ixn->part.pandora; + else if constexpr (PartType == RecoType::kPIDA) + return ixn->part.pida; + else + assert(false && "GetRecoParticles() is currently instrumented only for kDLP, kPandora or kPIDA only"); + //static_assertor RecoType " + std::to_string(PartType)); + } +// template +// const caf::Proxy>& GetTracks(const caf::SRInteractionProxy* ixn); +//{ +// +//} + template + const caf::Proxy> & GetInteractions(const caf::SRProxy* sr) + { + if constexpr(IntType == RecoType::kDLP) + return sr->common.ixn.dlp; + else if constexpr (IntType == RecoType::kPandora) + return sr->common.ixn.pandora; + else + assert(false &&"GetInteractions() is currently instrumented for RecoType kDLP or kPandora only" ); + } + + template + const caf::Proxy> & GetNDLarInteractions(const caf::SRProxy* sr) + { + if constexpr(IntType == RecoType::kDLP) + return sr->nd.lar.dlp; + else if (IntType == RecoType::kPandora) + return sr->nd.lar.pandora; + else + assert(false &&"GetNDLarInteractions() is currently instrumented for RecoType kDLP or kPandora only" ); + } + + const caf::Proxy>& + GetNuTruths(const caf::SRProxy* sr) + { + return sr->mc.nu; + } + + template + const caf::Proxy> & GetNuTruthParticles(const caf::SRTrueInteractionProxy* nu) + { + if constexpr(PartType == TruePType::kPrim) + return nu->prim; + else if (PartType == TruePType::kSec) + return nu->sec; + else if (PartType == TruePType::kPreFSI) + return nu->prefsi; + else + assert(false &&"GetNuTruthParticles() is currently instrumented for TruePType kPrim, kSec or kPreFSI only" ); + } + +// SR to Ixn or SR to TruIxn, only the matched ones? +// +//// // From True interactions to recointeractions +//// // usage: apply cuts on truth branch but get records from common branch +////template +// const caf::Proxy>& GetRecoInteractionsFromTruths(const caf::SRProxy* sr){ +// ///< Interaction ID == 'vertexID' from edep-sim (ND) or GENIE record id (FD) +// //auto nus = sr->mc.nu; +// ///< Indices of SRTrueInteraction(s), if relevant (use this index in SRTruthBranch::nu to get them) +// //auto ixns = sr->common.ixn; +// bool pdgmatch= false; +// // construct a vector of SRInteraction that match the SRTrueIteraction +// std::vector temp = sr->common.ixn.dlp; +// +// //if constexpr(IntType == RecoType::kDLP){ +// for(long unsigned nixn = 0; nixn < sr->common.ixn.dlp.size(); nixn++){ +// int recoid = sr->common.ixn.dlp[nixn].id; +// // find the truth thing.... +// pdgmatch = abs(sr->mc.nu[recoid].pdg ) == 14; +// if (pdgmatch ) temp.emplace_back(sr->common.ixn.dlp[nixn]/*the matched index interaction*/); +// } +// const caf::Proxy> ret = temp; +// return &ret; +// //} +//// else if (IntType == RecoType::kPandora) +//// sr->common.ixn.pandora.id; +//// return sr->common.ixn.pandora; +//// else +// // assert(false &&"GetRecoInteractionsFromTruths() is currently instrumented for RecoType kDLP or kPandora only" ); +// } + + //---------------------------------------------------------------------- + + // Instantiations + template class VectorAdaptor; + + template class VectorAdaptor; + + template class VectorAdaptor; + + template class VectorAdaptor; + + template class VectorAdaptor; + + template class EnsembleVectorAdaptor; + + template class EnsembleVectorAdaptor; + // ----------------------------------------------------------------------- + _IRecordSource::_IRecordSource() + { + // it would be better (lots less boilerplate) to do this in the initializers section, + // but I can't work out why it won't compile when the items are written + // in initializer list format + fParticleCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(RecoType::kDLP), + std::forward_as_tuple(*this, GetRecoParticles)); + fParticleCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(RecoType::kPandora), + std::forward_as_tuple(*this, GetRecoParticles)); + fParticleCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(RecoType::kPIDA), + std::forward_as_tuple(*this, GetRecoParticles)); + } + + // ----------------------------------------------------------------------- + _IRecordSource::_IRecordSource() + { + fInteractionCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(RecoType::kDLP), + std::forward_as_tuple(*this, GetInteractions)); + fInteractionCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(RecoType::kPandora), + std::forward_as_tuple(*this, GetInteractions)); + fNDLarInteractionCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(RecoType::kDLP), + std::forward_as_tuple(*this, GetNDLarInteractions)); + fNDLarInteractionCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(RecoType::kPandora), + std::forward_as_tuple(*this, GetNDLarInteractions)); + } + // ----------------------------------------------------------------------- + _IRecordSource::_IRecordSource() + { + fNuTruthParticleCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(TruePType::kPrim), + std::forward_as_tuple(*this, GetNuTruthParticles)); + fNuTruthParticleCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(TruePType::kSec), + std::forward_as_tuple(*this, GetNuTruthParticles)); + fNuTruthParticleCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(TruePType::kPreFSI), + std::forward_as_tuple(*this, GetNuTruthParticles)); + } + +// ----------------------------------------------------------------------- + _IRecordEnsembleSource::_IRecordEnsembleSource() + { + // it would be better (lots less boilerplate) to do this in the initializers section, + // but I can't work out why it won't compile when the items are written + // in initializer list format + fParticleCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(RecoType::kDLP), + std::forward_as_tuple(*this, GetRecoParticles)); + fParticleCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(RecoType::kPandora), + std::forward_as_tuple(*this, GetRecoParticles)); + fParticleCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(RecoType::kPIDA), + std::forward_as_tuple(*this, GetRecoParticles)); + } +// ----------------------------------------------------------------------- + _IRecordEnsembleSource::_IRecordEnsembleSource() + { + fNuTruthParticleCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(TruePType::kPrim), + std::forward_as_tuple(*this, GetNuTruthParticles)); + fNuTruthParticleCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(TruePType::kSec), + std::forward_as_tuple(*this, GetNuTruthParticles)); + fNuTruthParticleCollections.emplace(std::piecewise_construct, + std::forward_as_tuple(TruePType::kPreFSI), + std::forward_as_tuple(*this, GetNuTruthParticles)); + } + + +} diff --git a/CAFAna/Core/IRecordSource.h b/CAFAna/Core/IRecordSource.h new file mode 100644 index 00000000..205bccfa --- /dev/null +++ b/CAFAna/Core/IRecordSource.h @@ -0,0 +1,222 @@ +#pragma once + +#include "cafanacore/IRecordSource.h" + +#include "CAFAna/Core/IRecordSink.h" + +#include "duneanaobj/StandardRecord/Proxy/FwdDeclare.h" + +namespace ana +{ + class ISyst; + + template class _Multiverse; + // using Multiverse = _Multiverse>; + //using MultiverseTrue = _Multiverse>; + using Multiverse = _Multiverse; + + class SystShifts; + + //---------------------------------------------------------------------- + // Introduce some aliases so we can express ourselves more succinctly + using ISRSource = _IRecordSource; + using IInteractionSource = _IRecordSource; + using INDLarInteractionSource = _IRecordSource; + using IParticleSource = _IRecordSource; + using INuTruthSource = _IRecordSource; + using INuTruthParticleSource = _IRecordSource; + //---------------------------------------------------------------------- + using IInteractionEnsembleSource = _IRecordEnsembleSource; + using ITrueInteractionEnsembleSource = _IRecordEnsembleSource; + using IParticleEnsembleSource = _IRecordEnsembleSource; + using INuTruthParticleEnsembleSource = _IRecordEnsembleSource; + //---------------------------------------------------------------------- + + enum class RecoType { kUnknown, + kDLP, + kPandora, + kPIDA + }; + enum class TruePType{ + kPrim, + kSec, + kPreFSI + }; + + /// Helper class for implementing looping over slices, tracks, etc + template class VectorAdaptor: + public PassthroughExposure<_IRecordSink>, + _IRecordSource>> + { + public: + typedef std::function>&(const caf::Proxy*)> Func_t; + + VectorAdaptor(_IRecordSource>& src, Func_t vecGetter); + virtual void HandleRecord(const caf::Proxy* rec, double weight) override; + protected: + Func_t fVecGetter; + }; + + //---------------------------------------------------------------------- + // Accessors needed by VectorAdaptor + + template + const caf::Proxy>& GetRecoParticles(const caf::SRInteractionProxy* ixn); + +// template +// const caf::Proxy>& GetTracks(const caf::SRInteractionProxy* ixn); +// +// template +// const caf::Proxy>& GetShowers(const caf::SRInteractionProxy* ixn);// or caf::SRProxy* sr? + + template + const caf::Proxy>& GetInteractions(const caf::SRProxy* sr); + + template + const caf::Proxy>& GetNDLarInteractions(const caf::SRProxy* sr); + + const caf::Proxy>& GetNuTruths(const caf::SRProxy* sr); + + template + const caf::Proxy>& GetNuTruthParticles(const caf::SRTrueInteractionProxy* nu); + // template + // const caf::Proxy>& GetRecoInteractionsFromTruths(const caf::SRProxy* sr); + // // usage: apply cuts on truth branch but get records from common branch + //const caf::Proxy>& GetRecoInteractionsFromTruths(const caf::SRProxy* sr); + //---------------------------------------------------------------------- + + template<> class _IRecordSource + : public _IRecordSourceDefaultImpl + { + public: + _IRecordSource(); + + // Weight-based ensembles are still supported + using _IRecordSourceDefaultImpl::Ensemble; + // But also support an ensemble based on SystShifts + IInteractionEnsembleSource& Ensemble(const Multiverse& multiverse); + + IParticleSource& RecoParticles( const RecoType kRType) {return fParticleCollections.at(kRType);} + + protected: + IDDict fEnsembleSources; + + std::unordered_map> fParticleCollections; + + }; + + template<> class _IRecordSource + : public _IRecordSourceDefaultImpl + { + public: + _IRecordSource(); + + //using _IRecordSourceDefaultImpl::Ensemble; + //ITrueInteractionEnsembleSource& Ensemble(const Multiverse& multiverse); + INuTruthParticleSource& TruthParticles(const TruePType kPType) {return fNuTruthParticleCollections.at(kPType);} + + protected: + //IDDict fEnsembleSources; + std::unordered_map> fNuTruthParticleCollections; + + }; + + + //---------------------------------------------------------------------- + // Standard Record sources also provide a source (which loops over the interactions) + template<> class _IRecordSource + : public _IRecordSourceDefaultImpl + { + public: + _IRecordSource(); + + IInteractionSource& Interactions( const RecoType kRType ) {return fInteractionCollections.at(kRType);} + INDLarInteractionSource& NDLarInteractions( const RecoType kRType ) {return fNDLarInteractionCollections.at(kRType);} + INuTruthSource& NuTruths() {return fNuTruths;} + //IInteractionSource& InteractionsTruthFiltered(){return fFilteredInteractions;} + protected: + std::unordered_map> fInteractionCollections; + std::unordered_map> fNDLarInteractionCollections; + VectorAdaptor fNuTruths{*this, GetNuTruths}; + //VectorAdaptor fFilteredInteractions{*this,GetRecoInteractionsFromTruths}; + + }; + + +// // --------------------------------- ******** +// // attempt to connect the nu tree with the reco / common tree +// +// template<> class _IRecordSource +// : public _IRecordSourceDefaultImpl +// { +// public: +// _IRecordSource(); +// +// IInteractionSource& Interactions( const RecoType kRType ) {return fRecoTrueInteractionCollections.at(kRType);} +// +// protected: +// std::unordered_map> fRecoTrueInteractionCollections; +// +// }; +// +// +// + + //---------------------------------------------------------------------- + /// Helper class for implementing looping over interactions, particles, etc + template class EnsembleVectorAdaptor: + public PassthroughExposure<_IRecordEnsembleSink>, + _IRecordEnsembleSource>> + { + public: + using Source_t = _IRecordEnsembleSource>; + using Func_t = std::function>&(const caf::Proxy*)>; + + EnsembleVectorAdaptor(Source_t& src, Func_t vecGetter); + + virtual void HandleSingleRecord(const caf::Proxy* rec, + double weight, + int universeIdx) override; + + virtual void HandleEnsemble(const caf::Proxy* rec, + const std::vector& weight) override; + + virtual const ana::FitMultiverse* GetMultiverse() const {return fSource->GetMultiverse();} + + protected: + const Source_t* fSource; + Func_t fVecGetter; + }; + + //---------------------------------------------------------------------- + // Provide ability to get particle sources from the reco branch + // ensemble source. + + template<> class _IRecordEnsembleSource + : public _IRecordEnsembleSourceDefaultImpl + { + public: + _IRecordEnsembleSource(); + + IParticleEnsembleSource& RecoParticles( const RecoType kRType) {return fParticleCollections.at(kRType);} + + protected: + std::unordered_map> fParticleCollections; + + }; + + // the analogous for truth branch + template<> class _IRecordEnsembleSource + : public _IRecordEnsembleSourceDefaultImpl + { + public: + _IRecordEnsembleSource(); + + INuTruthParticleEnsembleSource& TruthParticles(const TruePType kPType) {return fNuTruthParticleCollections.at(kPType);} + protected: + std::unordered_map> fNuTruthParticleCollections; + }; + + /// Still missing the analogous StandardRecord sources (which loop over interactions) + // SR->Interactions, SR->NDLARInte, SR->TrueInteraction +} diff --git a/CAFAna/Core/ISyst.cxx b/CAFAna/Core/ISyst.cxx index 9450e454..25a64d4a 100644 --- a/CAFAna/Core/ISyst.cxx +++ b/CAFAna/Core/ISyst.cxx @@ -1,32 +1,40 @@ #include "CAFAna/Core/ISyst.h" -#include "CAFAna/Core/Registry.h" +#include "cafanacore/Registry.h" +#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" #include "CAFAna/Core/MathUtil.h" namespace ana { + //---------------------------------------------------------------------- + //template ISyst::ISyst(const std::string& shortName, ISyst::ISyst(const std::string& shortName, const std::string& latexName, - bool applyPenalty, - double min, - double max, - double cv) - : INamed(shortName, latexName), fApplyPenalty(applyPenalty), fMin(min), fMax(max), fCentral(cv) + bool applyPenalty, + double min, + double max, + double cv) + //: _ISyst(shortName, latexName), fApplyPenalty(applyPenalty), fMin(min), fMax(max) + : _ISyst(shortName, latexName), fApplyPenalty(applyPenalty), fMin(min), fMax(max), fCentral(cv) { + //Registry>::Register(this); Registry::Register(this); } //---------------------------------------------------------------------- + //template ISyst::~ISyst() ISyst::~ISyst() { // Normally ISysts should last for the life of the process, but in case one // is deleted it's best not to leave a dangling pointer in Registry. + //Registry>::UnRegister(this); Registry::UnRegister(this); } //---------------------------------------------------------------------- + //template double ISyst::Penalty(double x ) const double ISyst::Penalty(double x) const { if(fApplyPenalty){ diff --git a/CAFAna/Core/ISyst.h b/CAFAna/Core/ISyst.h index 0600b382..2d8ab4b0 100644 --- a/CAFAna/Core/ISyst.h +++ b/CAFAna/Core/ISyst.h @@ -1,8 +1,8 @@ #pragma once -#include "CAFAna/Core/FwdDeclare.h" +#include "cafanacore/ISyst.h" -#include "CAFAna/Core/INamed.h" +#include #include @@ -15,59 +15,50 @@ namespace ana /// /// The Shift() function alters the \ref caf::StandardRecord or the weight /// associated with the event. - class ISyst : public INamed + class ISyst : public _ISyst { - public: - ISyst(const std::string& shortName, - const std::string& latexName, - bool applyPenalty = true, - double min = -3, - double max = +3, - double cv = 0); - ISyst(const ISyst &) = delete; // no copying. - ISyst(ISyst && rhs) = delete; // no moving either. - virtual ~ISyst(); + public: + ISyst(const std::string &shortName, + const std::string &latexName, + bool applyPenalty = true, + double min = -3, + double max = +3, + double cv = 0); - void operator=(const ISyst &) = delete; // still no copying. - void operator=(ISyst &&) = delete; // etc. + ISyst(const ISyst &) = delete; // no copying. + ISyst(ISyst &&rhs) = delete; // no moving either. + virtual ~ISyst(); - virtual double Penalty(double x) const; + void operator=(const ISyst &) = delete; // still no copying. + void operator=(ISyst &&) = delete; // etc. - /// Should a penalty be applied for this shift? - virtual bool ApplyPenalty() const {return fApplyPenalty;} + virtual double Penalty(double x) const; - /// Return the min/max value for this syst - virtual double Min() const{return fMin;} - virtual double Max() const{return fMax;} + /// Should a penalty be applied for this shift? + virtual bool ApplyPenalty() const { return fApplyPenalty; } - /// Set the central value used - virtual void SetCentral(double val) const{fCentral = val;} + /// Return the min/max value for this syst + virtual double Min() const { return fMin; } + virtual double Max() const { return fMax; } - /// Return the central value used - virtual double Central() const{return fCentral;} + /// Set the central value used + virtual void SetCentral(double val) const { fCentral = val; } - /// \brief Perform the systematic shift - /// - /// \param sigma Number of sigma to shift record by - /// \param sr The record to inspect and alter - /// \param weight Scale this weight for reweighting systematics - virtual void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const = 0; + /// Return the central value used + virtual double Central() const { return fCentral; } - /// PredictionInterp normally interpolates between spectra made at - /// +/-1,2,3sigma. For some systematics that's overkill. Override this - /// function to specify different behaviour for this systematic. - virtual int PredInterpMaxNSigma() const - { - return 3; - } + /// PredictionInterp normally interpolates between spectra made at + /// +/-1,2,3sigma. For some systematics that's overkill. Override this + /// function to specify different behaviour for this systematic. + virtual int PredInterpMaxNSigma() const + { + return 3; + } - private: - bool fApplyPenalty; - double fMin; - double fMax; - mutable double fCentral; // I make no apologies for this + private: + bool fApplyPenalty; + double fMin; + double fMax; + mutable double fCentral; // I make no apologies for this }; - } // namespace diff --git a/CAFAna/Core/Instantiations.cxx b/CAFAna/Core/Instantiations.cxx deleted file mode 100644 index da2cc6e8..00000000 --- a/CAFAna/Core/Instantiations.cxx +++ /dev/null @@ -1,80 +0,0 @@ -#include "CAFAna/Core/SpectrumLoaderBase.h" - -#include "CAFAna/Core/SpectrumConstructors.txx" - -namespace ana -{ - template Spectrum::Spectrum(SpectrumLoaderBase& loader, - const HistAxis& axis, - const Cut& cut, - const SystShifts& shift, - const Weight& wei, - Spectrum::ESparse sparse); - - template Spectrum::Spectrum(const std::string& label, - const Binning& bins, - SpectrumLoaderBase& loader, - const Var& var, - const Cut& cut, - const SystShifts& shift, - const Weight& wei, - Spectrum::ESparse sparse); - - template Spectrum::Spectrum(SpectrumLoaderBase& loader, - const HistAxis& xAxis, - const HistAxis& yAxis, - const Cut& cut, - const SystShifts& shift, - const Weight& wei, - ESparse sparse); - - template Spectrum::Spectrum(const std::string& xLabel, - const std::string& yLabel, - SpectrumLoaderBase& loader, - const Binning& binsx, const Var& varx, - const Binning& binsy, const Var& vary, - const Cut& cut, - const SystShifts& shift, - const Weight& wei, - ESparse sparse); - - template Spectrum::Spectrum(SpectrumLoaderBase& loader, - const HistAxis& xAxis, - const HistAxis& yAxis, - const HistAxis& zAxis, - const Cut& cut, - const SystShifts& shift, - const Weight& wei, - ESparse sparse); - - template Spectrum::Spectrum(const std::string& xLabel, - const std::string& yLabel, - const std::string& zLabel, - SpectrumLoaderBase& loader, - const Binning& binsx, const Var& varx, - const Binning& binsy, const Var& vary, - const Binning& binsz, const Var& varz, - const Cut& cut, - const SystShifts& shift, - const Weight& wei, - ESparse sparse); - - template Spectrum::Spectrum(SpectrumLoaderBase& loader, - const _HistAxis& axis, - const Cut& cut, - const SystShifts& shift, - const Weight& wei); -} - -#include "CAFAna/Core/ReweightableSpectrum.h" -#include "CAFAna/Core/ReweightableSpectrumConstructors.txx" - -namespace ana -{ - template ReweightableSpectrum::ReweightableSpectrum(SpectrumLoaderBase& loader, - const HistAxis& recoAxis, - const HistAxis& trueAxis, - const Cut& cut, - const SystShifts& shift, - const Weight& wei); -} diff --git a/CAFAna/Core/LoadFromFile.cxx b/CAFAna/Core/LoadFromFile.cxx index 0a99f3fc..a62c97da 100644 --- a/CAFAna/Core/LoadFromFile.cxx +++ b/CAFAna/Core/LoadFromFile.cxx @@ -86,6 +86,12 @@ namespace ana return std::unique_ptr(ret); } + //---------------------------------------------------------------------- + template<> void SaveTo(const osc::IOscCalcAdjustable& x, TDirectory* dir, const std::string& name) + { + SaveTo(dynamic_cast(x), dir, name); + } + //---------------------------------------------------------------------- template<> void SaveTo(const osc::IOscCalc& x, TDirectory* dir, const std::string& name) { diff --git a/CAFAna/Core/LoadFromFile.h b/CAFAna/Core/LoadFromFile.h index ce41311a..c5ed2f4a 100644 --- a/CAFAna/Core/LoadFromFile.h +++ b/CAFAna/Core/LoadFromFile.h @@ -25,8 +25,6 @@ namespace ana // derived class is actually in the file and hand off to that. The // implementations of these are in the cxx files for the base classes in // question. - class IDecomp; - template<> std::unique_ptr LoadFrom(TDirectory* dir, const std::string& label); class IExtrap; template<> std::unique_ptr LoadFrom(TDirectory* dir, const std::string& label); class IPrediction; @@ -42,6 +40,7 @@ namespace ana // This one is actually implemented in LoadFromFile.cxx to avoid polluting // OscLib with CAFAna conventions. template<> std::unique_ptr LoadFrom(TDirectory* dir, const std::string& label); + template<> std::unique_ptr LoadFrom(TDirectory* dir, const std::string& label); //---------------------------------------------------------------------- // For symmetry @@ -53,6 +52,9 @@ namespace ana // Also in the cxx, to avoid having to put this logic into OscLib template<> void SaveTo(const osc::IOscCalc& x, TDirectory* dir, const std::string& label); + // The general template version gets called rather than the IOscCalc specialization unless we handle it explicitly + template<> void SaveTo(const osc::IOscCalcAdjustable& x, TDirectory* dir, const std::string& label); + //---------------------------------------------------------------------- template std::unique_ptr LoadFromFile(const std::string& fname, const std::string& label) diff --git a/CAFAna/Core/Loaders.cxx b/CAFAna/Core/Loaders.cxx index 468866aa..9faf0318 100644 --- a/CAFAna/Core/Loaders.cxx +++ b/CAFAna/Core/Loaders.cxx @@ -1,128 +1,43 @@ #include "CAFAna/Core/Loaders.h" - -#include "CAFAna/Core/SpectrumLoader.h" -#include "CAFAna/Core/Utilities.h" - -#include -#include +#include "CAFAna/Core/Sources.ixx" namespace ana { - //---------------------------------------------------------------------- - Loaders::Loaders() - { - } - - //---------------------------------------------------------------------- - Loaders::~Loaders() - { - // for(auto it: fLoaders) delete it.second; - } - - //---------------------------------------------------------------------- - void Loaders::SetLoaderPath(const std::string& path, - caf::Det_t det, - DataMC datamc, - SwappingConfig swap) - { - assert(datamc == kMC || swap == kNonSwap); - assert(det == caf::kFARDET || swap == kNonSwap); - - const Key_t key(det, datamc, swap); - - // Clear out the old one if necessary - DisableLoader(det, datamc, swap); - - fLoaderPaths[key] = path; - } - - //---------------------------------------------------------------------- - void Loaders::SetLoaderFiles(const std::vector& files, - caf::Det_t det, - DataMC datamc, - SwappingConfig swap) - { - assert(datamc == kMC || swap == kNonSwap); - assert(det == caf::kFARDET || swap == kNonSwap); - - const Key_t key(det, datamc, swap); - - // Clear out the old one if necessary - DisableLoader(det, datamc, swap); - - fLoaderFiles[key] = files; - } + // instantiate the Sources template with a Loaders type + template class Sources; - //---------------------------------------------------------------------- - void Loaders::AddLoader(SpectrumLoaderBase* file, - caf::Det_t det, - DataMC datamc, - SwappingConfig swap) + // --------------------------------------------------------------------------------- + Loaders::operator InteractionSources&() { - assert(datamc == kMC || swap == kNonSwap); - assert(det == caf::kFARDET || swap == kNonSwap); - - const Key_t key(det, datamc, swap); - - // Clear out the old one if necessary - DisableLoader(det, datamc, swap); - - fLoaders[key] = file; - } - - //---------------------------------------------------------------------- - void Loaders::DisableLoader(caf::Det_t det, - DataMC datamc, - SwappingConfig swap) - { - assert(datamc == kMC || swap == kNonSwap); - assert(det == caf::kFARDET || swap == kNonSwap); - - const Key_t key(det, datamc, swap); - - // Clear out the current one if possible - auto it = fLoaders.find(key); - if(it != fLoaders.end()){ - delete it->second; - fLoaders.erase(it); + if (fRecoIxnType == RecoType::kUnknown) + { + std::cerr << "You must configure a Reco Interaction type when you build your Loaders in order to iterate over Interactions!\n"; + throw std::runtime_error("Reco Interaction type unspecified"); } - fLoaderPaths.erase(key); - fLoaderFiles.erase(key); - } - - //---------------------------------------------------------------------- - SpectrumLoaderBase& Loaders::GetLoader(caf::Det_t det, - DataMC datamc, - SwappingConfig swap) - { - assert(datamc == kMC || swap == kNonSwap); - assert(det == caf::kFARDET || swap == kNonSwap); - - const Key_t key(det, datamc, swap); - - // Look up and return. Use fNull if no loader is set for this config - auto itLoader = fLoaders.find(key); - if(itLoader != fLoaders.end()) return *itLoader->second; - - auto itPath = fLoaderPaths.find(key); - if(itPath != fLoaderPaths.end()){ - fLoaders[key] = new SpectrumLoader(itPath->second); - return *fLoaders[key]; + static std::unique_ptr ret; + if (!ret) + { + for(const ana::DataMC & dmc : enum_range(static_cast(0), ana::DataMC::kNumDataMCs)) + { + for(const caf::Det_t & det : enum_range(static_cast(0), caf::Det_t::kNumDet_ts)) + { + for(const ana::SwappingConfig & swap : enum_range(static_cast(0), ana::SwappingConfig::kNumSwappingConfigs)) + { + if(dmc == DataMC::kData && swap != SwappingConfig::kNonSwap) continue; + ret->AddSource(&GetSource(dmc, det, swap).Interactions(fRecoIxnType), + dmc, det, swap); + } + } + } } - auto itFiles = fLoaderFiles.find(key); - if(itFiles != fLoaderFiles.end()){ - fLoaders[key] = new SpectrumLoader(itFiles->second); - return *fLoaders[key]; - } - - return fNull; - } + return *ret; + } // operator InteractionSources&() - //---------------------------------------------------------------------- void Loaders::Go() { - for(auto it: fLoaders) it.second->Go(); + for (auto it: this->fSourceViews) it.second->Go(); } -} + +} \ No newline at end of file diff --git a/CAFAna/Core/Loaders.h b/CAFAna/Core/Loaders.h index 5b89dc78..ea22c72a 100644 --- a/CAFAna/Core/Loaders.h +++ b/CAFAna/Core/Loaders.h @@ -1,70 +1,37 @@ #pragma once -#include "CAFAna/Core/SpectrumLoaderBase.h" +#include "CAFAna/Core/Sources.h" -namespace caf{ - typedef int Det_t; - const int kNEARDET = 1; - const int kFARDET = 2; +namespace caf +{ + // this needs to start at 0 or the Sources::operator[] thing below won't work. + // similarly, last element needs to be named `kNum[data type]s` + enum class Det_t : unsigned short { kNEARDET = 0, kFARDET, kNumDet_ts }; } -#include - namespace ana { - class SpectrumLoader; - - /// \brief Collection of SpectrumLoaders for many configurations - class Loaders - { - public: - enum DataMC{kData, kMC}; - enum SwappingConfig{kNonSwap, kNueSwap, kNuTauSwap}; - enum FluxType{kFHC, kRHC}; - - /// No loaders initialized. Use \ref SetLoaderPath to configure - Loaders(); - virtual ~Loaders(); - /// Configure loader via wildcard \a path - void SetLoaderPath(const std::string& path, - caf::Det_t det, - DataMC datamc, - SwappingConfig swap = kNonSwap); + using SRSources = Sources; + using InteractionSources = Sources; - /// Configure loader via explicit file list - void SetLoaderFiles(const std::vector& files, - caf::Det_t det, - DataMC datamc, - SwappingConfig swap = kNonSwap); - - void AddLoader(SpectrumLoaderBase*, - caf::Det_t det, - DataMC datamc, - SwappingConfig swap = kNonSwap); - - void DisableLoader(caf::Det_t det, - DataMC datamc, - SwappingConfig swap = kNonSwap); - - /// Retrieve a specific loader - SpectrumLoaderBase& GetLoader(caf::Det_t det, - DataMC datamc, - SwappingConfig swap = kNonSwap); + /// A bundle of SpectrumLoaders that have the same neutrino source configuration (e.g., FHC) but differ over data/MC, detector type, swap, etc. + class Loaders: public Sources + { + public: + Loaders(ana::RecoType ixnType = RecoType::kUnknown) + : fRecoIxnType(ixnType) + {} - /// Call Go() on all the loaders - void Go(); + // todo: relying on a pre-configured Interaction type is probably not the endpoint solution + // (what if ND & FD use different recos? what if I want to compare multiple? etc.) + operator InteractionSources&(); - protected: - typedef std::tuple Key_t; + /// Call Go() on all the loaders + void Go(); - // Hold a list of paths that have been set - std::map fLoaderPaths; - std::map> fLoaderFiles; - // Only reify them when someone actually calls GetLoader() - std::map fLoaders; + private: + ana::RecoType fRecoIxnType; ///< which reco interactions will be passed to spectra? + }; // class Loaders - /// We give this back when a loader isn't set for some configuration - NullLoader fNull; - }; -} // namespace +} // namespace \ No newline at end of file diff --git a/CAFAna/Core/Multiverse.cxx b/CAFAna/Core/Multiverse.cxx new file mode 100644 index 00000000..42bfc1b5 --- /dev/null +++ b/CAFAna/Core/Multiverse.cxx @@ -0,0 +1,316 @@ +#include "CAFAna/Core/Multiverse.h" + +#include "CAFAna/Core/Registry.h" + +#include "TDirectory.h" +#include "TMD5.h" +#include "TObjString.h" + +#include +#include + +namespace ana +{ + // Multiverses live the lifetime of the process, but let's not leak them at + // shutdown + std::vector> gFitMultiverses; + + namespace{ + // This is "group separator" and appears to print as a space. It is + // unlikely to occur in a systematic name by accident, unlike more usual + // separators. + const char kSepChar(29); + const std::string kSep(1, kSepChar); + } + + //---------------------------------------------------------------------- + bool CompareSystsByShortName(const IFitSyst* a, const IFitSyst* b) + { + return a->ShortName() < b->ShortName(); + } + + //---------------------------------------------------------------------- + std::vector SortedSystList(const std::vector systs) + { + std::vector ret = systs; + std::sort(ret.begin(), ret.end(), CompareSystsByShortName); + return ret; + } + + //---------------------------------------------------------------------- + std::vector Tokenize(const std::string& str) + { + std::vector ret; + + size_t i0 = 0; + while(true){ + const size_t i1 = str.find(kSepChar, i0); + ret.push_back(str.substr(i0, i1-i0)); + if(i1 == std::string::npos) return ret; + i0 = i1+1; + } + } + + //---------------------------------------------------------------------- + std::string GetLabelValue(const std::string& str, const std::string& label) + { + if(str.substr(0, label.size()+1) != label+"="){ + std::cout << "FitMultiverse::LoadFrom(): expected '" + << label << "=value' " + << "got '" << str << "'" << std::endl; + abort(); + } + return str.substr(label.size()+1); + } + + //---------------------------------------------------------------------- + std::string ConsumeLabelValue(std::vector& tokens, + const std::string& label) + { + const std::string ret = GetLabelValue(tokens.front(), label); + tokens.erase(tokens.begin()); // effectively pop_front() + return ret; + } + + //---------------------------------------------------------------------- + unsigned int GetLabelIntValue(const std::string& str, const std::string& label) + { + const std::string valuestr = GetLabelValue(str, label); + + unsigned int ret; + size_t pos = -1; + try{ + ret = std::stoi(valuestr, &pos); + } + catch(const std::exception& ex){ + pos = -1; + ret = -1; // silence uninitialized variable warning + } + + if(pos != valuestr.size()){ // need to consume all the string + std::cout << "FitMultiverse::LoadFrom(): failed to parse integer parameter '" << str << "'" << std::endl; + abort(); + } + + return ret; + } + + //---------------------------------------------------------------------- + unsigned int ConsumeLabelIntValue(std::vector& tokens, + const std::string& label) + { + const unsigned int ret = GetLabelIntValue(tokens.front(), label); + tokens.erase(tokens.begin()); // effectively pop_front() + return ret; + } + + //---------------------------------------------------------------------- + std::vector SystNamesToSysts(const std::vector& names) + { + std::vector ret; + ret.reserve(names.size()); + + for(const std::string& name: names){ + ret.push_back(Registry::ShortNameToPtr(name, true)); + //ret.push_back(Registry>::ShortNameToPtr(name, true)); + //ret.push_back(Registry>::ShortNameToPtr(name, true)); + if(!ret.back()){ + std::cout << "FitMultiverse::LoadFrom(): couldn't find any syst with short name '" << name << "'" << std::endl; + abort(); + } + } + + return ret; + } + + //---------------------------------------------------------------------- + FitMultiverse::FitMultiverse(const std::string& shortName, + const std::string& latexName, + const std::vector& univs, + const EMultiverseType multiverseType) + : INamed(shortName, latexName), fUnivs(univs), fMultiverseType(multiverseType) + { + Registry::Register(this); + } + + //---------------------------------------------------------------------- + FitMultiverse::FitMultiverse(const FitMultiverse&& m) + : INamed(m), fUnivs(m.fUnivs), fMultiverseType(m.fMultiverseType) + { + // "leak" the entry in the global list so we don't double-delete it + for(auto& it: gFitMultiverses) if(it.get() == &m) it.release(); + + Registry::UnRegister(&m); + Registry::Register(this); + } + + //---------------------------------------------------------------------- + const FitMultiverse& FitMultiverse:: + Hypercross(const std::vector& systs_unsorted, int nsigma) + { + // Ensure reproducibility + const std::vector systs = SortedSystList(systs_unsorted); + + std::string name = "cross"+kSep+"nsigma="+std::to_string(nsigma); + for(const IFitSyst* s: systs) name += kSep + s->ShortName(); + + // Make sure that requesting the same multiverse multiple times always + // gives back the same object + const FitMultiverse* reg = Registry::ShortNameToPtr(name, true); + if(reg) return *reg; + + const std::string latexName = "Hypercross for #pm"+std::to_string(nsigma)+"#sigma over "+std::to_string(systs.size())+" systematics"; + + + std::vector univs; + univs.reserve(2*nsigma*systs.size()+1); + univs.emplace_back(); // nominal + for(const IFitSyst* s: systs){ + for(int i = -nsigma; i <= +nsigma; ++i){ + if(i == 0) continue; + FitUniverse univ; + univ.emplace(s, i); + univs.push_back(univ); + } + } // end for systs + + gFitMultiverses.emplace_back(new FitMultiverse(name, latexName, univs, kHypercross)); + return *gFitMultiverses.back(); + } + + //---------------------------------------------------------------------- + const FitMultiverse& FitMultiverse:: + RandomGas(const std::vector& systs_unsorted, int Nuniv, + unsigned int seed) + { + // Ensure reproducibility + const std::vector systs = SortedSystList(systs_unsorted); + + if(seed == kTrulyRandom) seed = std::random_device{}(); + + std::string name = "gas"+kSep+"nuniv="+std::to_string(Nuniv)+kSep+"seed="+std::to_string(seed); + for(const IFitSyst* s: systs) name += kSep+s->ShortName(); + + // Make sure that requesting the same multiverse multiple times always + // gives back the same object + const FitMultiverse* reg = Registry::ShortNameToPtr(name, true); + if(reg) return *reg; + + const std::string latexName = "Random multiverse with "+std::to_string(Nuniv)+" universes over "+std::to_string(systs.size())+" systematics"; + + // Use stdlib rather than rely on ROOT's dodgy random numbers + std::mt19937_64 generator(seed); // 64-bit Mersenne twister + std::normal_distribution gaus(0, 1); + + std::vector univs; + univs.reserve(Nuniv+1); + univs.emplace_back(); // nominal + for(int i = 0; i < Nuniv; ++i){ + FitUniverse univ; + for(const IFitSyst* s: systs){ + univ.emplace(s, gaus(generator)); + } + univs.push_back(univ); + } + + gFitMultiverses.emplace_back(new FitMultiverse(name, latexName, univs, kRandomGas)); + return *gFitMultiverses.back(); + } + + // TO DO: a member that creates a new multiverse from a vector of multiverses + // care has to be put in making sure they are compatible + //---------------------------------------------------------------------- + // const FitMultiverse& FitMultiverse::MergeMultiverse( std::vector multiverses ){ + // + // GetUniverse + // + // } + + //---------------------------------------------------------------------- + void FitMultiverse::SaveTo(TDirectory* dir, const std::string& name) const + { + // We could make a whole directory and fill it with a detailed record of + // this object. But this will be saved for every single EnsembleSpectrum, + // so try and make it as minimal as possible. We should be able to encode + // enough information to reconstruct ourselves in a simple string. + + TDirectory* tmp = gDirectory; + + dir->cd(); + TObjString((ShortName()+kSep+"md5="+Checksum()).c_str()).Write(name.c_str()); + + tmp->cd(); + } + + //---------------------------------------------------------------------- + const FitMultiverse* FitMultiverse::LoadFrom(TDirectory* dir, + const std::string& name) + { + TObjString* obj = (TObjString*)dir->Get(name.c_str()); + assert(obj); + const std::string str = obj->GetString().Data(); + + const std::string shortname = str.substr(0, str.rfind(kSep)); + + std::vector tokens = Tokenize(str); + assert(tokens.size() >= 2); // type and checksum at least + + const std::string md5 = GetLabelValue(tokens.back(), "md5"); + tokens.pop_back(); + + // If this multiverse is already known, just give it back directly + const FitMultiverse* ret = Registry::ShortNameToPtr(shortname, true); + + if(!ret){ + // Otherwise we need to construct one + const std::string type = tokens.front(); + tokens.erase(tokens.begin()); // effectively pop_front() + + if(type == "gas"){ + const int nuniv = ConsumeLabelIntValue(tokens, "nuniv"); + const unsigned int seed = ConsumeLabelIntValue(tokens, "seed"); + + ret = &FitMultiverse::RandomGas(SystNamesToSysts(tokens), nuniv, seed); + } + else if(type == "cross"){ + const int nsigma = ConsumeLabelIntValue(tokens, "nsigma"); + + ret = &FitMultiverse::Hypercross(SystNamesToSysts(tokens), nsigma); + } + else{ + std::cout << "Multiverse::LoadFrom(): unknown multiverse type '" + << type << "'" << std::endl; + abort(); + } + } + + if(ret->Checksum() != md5){ + std::cout << "Multiverse::LoadFrom(): checksum mismatch while loading '" << name << "' with content '" << str << "'" << std::endl; + abort(); + } + + return ret; + } + + //---------------------------------------------------------------------- + std::string FitMultiverse::Checksum() const + { + TMD5 md5; + + for(const FitUniverse& univ: fUnivs){ + std::vector keys; + for(auto it: univ) keys.push_back(it.first); + // Ensure reproducibility because the map doesn't guarantee any + // particular ordering + for(const IFitSyst* syst: SortedSystList(keys)){ + md5.Update((unsigned char*)syst->ShortName().c_str(), + syst->ShortName().size()); + const double val = univ.at(syst); + md5.Update((unsigned char*)&val, sizeof(double)); + } // end fo syst + } // end for univ + + md5.Final(); + return md5.AsString(); + } +} \ No newline at end of file diff --git a/CAFAna/Core/Multiverse.h b/CAFAna/Core/Multiverse.h new file mode 100644 index 00000000..4fa20da6 --- /dev/null +++ b/CAFAna/Core/Multiverse.h @@ -0,0 +1,91 @@ +#pragma once + +#include "CAFAna/Core/FitMultiverse.h" + +#include "CAFAna/Core/ISyst.h" + +namespace ana +{ + /// \brief Equivalent to FitMultiverse, but storing experiment-specific + /// systematic type SystT + /// + /// Internal implementation details: we store the systematics as FitSyst* in + /// the base class, but since we know they can only be set by the + /// constructors, which we control, it is safe to cast them back to the + /// derived class on-demand. + template class _Multiverse: public FitMultiverse + { + public: + static_assert(std::is_base_of_v); + + /// See FitMultiverse::Hypercross + static const _Multiverse& Hypercross(const std::vector& systs, + int nsigma = 3) + { + return Cached(FitMultiverse::Hypercross(ConvertSysts(systs), nsigma)); + } + + using FitMultiverse::kTrulyRandom; + + /// See FitMultiverse::RandomGas + static const _Multiverse& RandomGas(const std::vector& systs, + int Nuniv, + unsigned int seed) + { + return Cached(FitMultiverse::RandomGas(ConvertSysts(systs), Nuniv, seed)); + } + + // TO DO: a member that creates a new multiverse from a vector of multiverses + // static const _Multiverse& MergeMultiverse( Multiverse multiverse); + + /// Details of a particular universe + const _Universe& GetUniverse(int i) const + { + // TODO I think this cast is safe because the layout is identical? + return *((const _Universe*)&fUnivs[i]); + //return fUnivs[i]; + } + + protected: + /// Helper constructor for \ref Cached + _Multiverse(const FitMultiverse&& m) : FitMultiverse(std::move(m)) {} + + /// Helper function for named constructors + static std::vector ConvertSysts(const std::vector systs) + { + return {systs.begin(), systs.end()}; + } + + /// \brief We need to retain the property that identically-defined + /// multiverses are the same object (get the same pointers) + /// + /// If there is already a _Multiverse corresponding to \a m return that, + /// otherwise construct one + static const _Multiverse& Cached(const FitMultiverse& m) + { + // These will be deleted by the underlying FitMultiverse, so no need for + // unique_ptr here + static std::unordered_map cache; + if(!cache.count(&m)){ + // We need to create a _Multiverse inheriting from the passed-in + // FitMultiverse. Trouble is, we mustn't create a new FitMultiverse + // with the same definition, so we have to move the input to become the + // base of this new object. This is OK because 1. we only just created + // this FitMultiverse in the named constructor and 2. FitMultiverse + // defines a move constructor for us that takes care of Registry + // registration etc. + cache.emplace(&m, new _Multiverse(std::move(m))); + } + return *cache[&m]; + } + }; + + +// using Universe = _Universe>; +// using Multiverse = _Multiverse>; +// +// using UniverseTrue = _Universe>; +// using MultiverseTrue = _Multiverse>; + using Universe = _Universe; + using Multiverse = _Multiverse; +} diff --git a/CAFAna/Core/OscillatableSpectrum.cxx b/CAFAna/Core/OscillatableSpectrum.cxx index f1ba4b42..4f33dd3b 100644 --- a/CAFAna/Core/OscillatableSpectrum.cxx +++ b/CAFAna/Core/OscillatableSpectrum.cxx @@ -7,7 +7,7 @@ #include "CAFAna/Core/Utilities.h" #include "duneanaobj/StandardRecord/Proxy/SRProxy.h" - +#include "duneanaobj/StandardRecord/SRInteraction.h" #include "OscLib/IOscCalc.h" #include "TDirectory.h" @@ -20,34 +20,27 @@ namespace ana { + namespace{ // Duplicate here because we can't include Vars.h - const Var kTrueE([](const caf::SRProxy* sr) - {return sr->Ev;}); - - //---------------------------------------------------------------------- - OscillatableSpectrum:: - OscillatableSpectrum(const std::string& label, const Binning& bins, - SpectrumLoaderBase& loader, - const Var& var, - const Cut& cut, - const SystShifts& shift, - const Weight& wei) - : ReweightableSpectrum(loader, - HistAxis(label, bins, var), - HistAxis("True Energy (GeV)", kTrueEnergyBins, kTrueE), - cut, shift, wei) - { - } - + // These should be true informations, but I think we only have recoparticle atm + const Var kTrueE([](const caf::SRInteractionProxy* ixn) + { + //assert(sr->mc.nnu == 1); + assert(ixn->truth.size()>0); + /// uuumm what do we + return ixn->Enu.calo; + }); + const Cut kHasNu([](const caf::SRInteractionProxy* ixn) + { + //return sr->truth.index >= 0; + // this should return something at the true level, + //in the meantime just check there's interaction or whatever placeholder cut + return ixn->truth.size()>0;//dlp.size()>0; + }); + } //---------------------------------------------------------------------- - OscillatableSpectrum::OscillatableSpectrum(SpectrumLoaderBase& loader, - const HistAxis& axis, - const Cut& cut, - const SystShifts& shift, - const Weight& wei) - : ReweightableSpectrum(loader, axis, - HistAxis("True Energy (GeV)", kTrueEnergyBins, kTrueE), - cut, shift, wei) + OscillatableSpectrum::OscillatableSpectrum(IInteractionSource& src, const HistAxis& axis) + : ReweightableSpectrum(src[kHasNu], axis, HistAxis("True Energy (GeV)", kTrueEnergyBins, kTrueE)) { } @@ -246,21 +239,18 @@ namespace ana delete dir; - auto ret = std::make_unique(kNullLoader, - HistAxis(labels, bins), - kNoCut); + const HistAxis recoAxis(labels, bins); // ROOT histogram storage is row-major, but Eigen is column-major by // default typedef Eigen::Matrix MatRowMajor; - ret->fMat = Eigen::Map(spect->GetArray(), - ret->fMat.rows(), - ret->fMat.cols()); - delete spect; + auto ret = std::make_unique(Eigen::Map(spect->GetArray(), kTrueEnergyBins.NBins()+2, recoAxis.GetBins1D().NBins()+2), + recoAxis, + hPot->Integral(0, -1), + hLivetime->Integral(0, -1)); - ret->fPOT = hPot->Integral(0, -1); - ret->fLivetime = hLivetime->Integral(0, -1); + delete spect; delete hPot; delete hLivetime; diff --git a/CAFAna/Core/OscillatableSpectrum.h b/CAFAna/Core/OscillatableSpectrum.h index 68a9f6b5..90864265 100644 --- a/CAFAna/Core/OscillatableSpectrum.h +++ b/CAFAna/Core/OscillatableSpectrum.h @@ -1,14 +1,19 @@ #pragma once -#include "CAFAna/Core/ReweightableSpectrum.h" +#include "cafanacore/ReweightableSpectrum.h" +#include "cafanacore/FwdDeclare.h" +#include "cafanacore/Spectrum.h" +#include "cafanacore/ThreadLocal.h" #include "CAFAna/Core/Binning.h" -#include "CAFAna/Core/FwdDeclare.h" +//#include "CAFAna/Core/FwdDeclare.h" #include "CAFAna/Core/OscCalcFwdDeclare.h" -#include "CAFAna/Core/Spectrum.h" +//#include "CAFAna/Core/Spectrum.h" #include "CAFAna/Core/SpectrumLoaderBase.h" #include "CAFAna/Core/StanTypedefs.h" -#include "CAFAna/Core/ThreadLocal.h" +//#include "CAFAna/Core/ThreadLocal.h" + +#include "CAFAna/Core/IRecordSource.h" #include @@ -17,7 +22,7 @@ class TH2; class TH2D; -#include "CAFAna/Core/FwdDeclare.h" +//#include "CAFAna/Core/FwdDeclare.h" namespace ana { @@ -37,23 +42,7 @@ namespace ana class OscillatableSpectrum: public ReweightableSpectrum { public: - friend class SpectrumLoaderBase; - friend class SpectrumLoader; - friend class NullLoader; - - OscillatableSpectrum(const std::string& label, - const Binning& bins, - SpectrumLoaderBase& loader, - const Var& var, - const Cut& cut, - const SystShifts& shift = kNoShift, - const Weight& wei = kUnweighted); - - OscillatableSpectrum(SpectrumLoaderBase& loader, - const HistAxis& axis, - const Cut& cut, - const SystShifts& shift = kNoShift, - const Weight& wei = kUnweighted); + OscillatableSpectrum(ana::IInteractionSource& src, const HistAxis& axis); OscillatableSpectrum(const Eigen::MatrixXd&& mat, const HistAxis& recoAxis, diff --git a/CAFAna/Core/Registry.cxx b/CAFAna/Core/Registry.cxx index 417407b2..27ab60eb 100644 --- a/CAFAna/Core/Registry.cxx +++ b/CAFAna/Core/Registry.cxx @@ -2,10 +2,14 @@ #include "CAFAna/Core/IFitVar.h" #include "CAFAna/Core/ISyst.h" +#include "CAFAna/Core/FitMultiverse.h" namespace ana { // Instantiate the registries we need template class Registry; template class Registry; + //template class Registry< ISyst>; + //template class Registry< ISyst>; + template class Registry; } diff --git a/CAFAna/Core/Sources.h b/CAFAna/Core/Sources.h new file mode 100644 index 00000000..23ab0a5c --- /dev/null +++ b/CAFAna/Core/Sources.h @@ -0,0 +1,102 @@ +#pragma once + +#include "CAFAna/Core/IRecordSource.h" +#include "CAFAna/Core/SpectrumLoader.h" +#include "CAFAna/Utils/EnumIter.h" + +#include + +#include "IRecordSource.h" + +namespace ana +{ + // these need to start at 0 or the Sources::operator[] thing below won't work + // similarly, last element needs to be named `kNum[data type]s` + enum class DataMC : unsigned short { kData = 0, kMC, kNumDataMCs }; + enum class SwappingConfig : unsigned short { kNonSwap = 0, kNueSwap, kNuTauSwap, kIntrinsic, kNumSwappingConfigs }; + enum class FluxType : unsigned short {kFHC = 0, kRHC, kNumFluxTypes }; + + /// \brief Collection of SpectrumLoaders for many configurations + /// + /// \type SrcT the source type + /// \type KeyTypes + template + class Sources + { + public: + /// No sources initialized by default. Use \ref AddSource() to configure one + Sources() = default; + ~Sources() = default; + + /// Hand over ownership of a new source + void AddSource(std::unique_ptr&& src, KeyTypes ... kt); + + /// Add a new non-owned source + void AddSource(SrcT * src, KeyTypes ... kt); + + void DisableSource(KeyTypes ... kt); + + /// Retrieve a specific loader + SrcT& GetSource(KeyTypes ... kt); + + + /// Chain a selector across all the known sources + template auto& operator[](const T& x) + { + using SourceType = std::remove_reference_tsecond)[x])>; + static std::unique_ptr> ret; + + if (!ret) + { + ret = std::make_unique>(); + Expand(*ret, x); + } + + return ret; + } + + protected: + // This is one of two workhorse methods that unroll the parameter pack + // corresponding to the complete set of types in Key_t. + // The typenames used here are: + // S -> the type of the Sources<> object. (Deduced from the function signature.) + // X -> the type of the result of calling operator[] on this Sources object. (Deduced from the function signature.) + // KeyTypesInArgs --> the types of the key args that are being passed along + // (built *up* successively as the types are being unrolled), + // since we need to save these args to pass to the function once we reach bottom. + // These are deduced from the function signature. + // KeyTypesRemain --> all but the last type in this subcollection from the recursive the Key_t unrolling + // LastKeyType --> the last one, peeled off from the previous iteration's parameter pack + // This version of the function will be called recurively + // for all versions of the key type collection + // (as types are progressively stripped out of it), + // *except* for when it has a single type remaining--- + // at which point the other variant will get called. + template + void Expand(S& sources, const X& x, const KeyTypesInArgs & ... prevVals) + { + for (const LastKeyType & t : enum_range(static_cast(0), LastKeyType::LAST_ELEM(T))) + { + Expand(sources, prevVals..., t); + } + } + + // the variant of the unwrapper method that gets called all the way at the bottom, + // when there's only a single arg type left + template + void Expand(S& sources, const X& x, const KeyTypesInArgs & ... vals) + { + for (const LastKeyType & t : enum_range(static_cast(0), LastKeyType::LAST_ELEM(T))) + { + sources.AddSource(this->GetSource(vals...)[x], vals...); + } + } + + + typedef std::tuple Key_t; + + std::map fSourceViews; + std::map> fOwnedSources; + }; + +} \ No newline at end of file diff --git a/CAFAna/Core/Sources.ixx b/CAFAna/Core/Sources.ixx new file mode 100644 index 00000000..722e20c0 --- /dev/null +++ b/CAFAna/Core/Sources.ixx @@ -0,0 +1,59 @@ +#include "CAFAna/Core/Sources.h" + +namespace ana +{ + // ------------------------------------------------------------------------ + template + void Sources::AddSource(std::unique_ptr&& src, KeyTypes ... kt) + { + const Key_t key(kt...); + auto successPair = this->fOwnedSources.try_emplace(std::make_tuple(kt...), std::move(src)); + if (!successPair.second) + { + std::cerr << "Sources::AddSource(): attempt to add source with same key as already existing source! Abort.\n"; + throw std::runtime_error("Duplicate source"); + } + this->AddSource(successPair.first->second.get(), kt...); + } + + // ------------------------------------------------------------------------ + /// Add a new non-owned source + template + void Sources::AddSource(SrcT * src, KeyTypes ... kt) + { + const Key_t key(kt...); + + // we don't own anything here, so we don't need to worry about disabling first, just overwrite + fSourceViews[key] = src; + } + + // ------------------------------------------------------------------------ + template + void Sources::DisableSource(KeyTypes ... kt) + { + const Key_t key(kt...); + fSourceViews.erase(key); // erase() is a no-op if the key doesn't exist + fOwnedSources.erase(key); + } + + // ------------------------------------------------------------------------ + /// Retrieve a specific loader + template + SrcT& Sources::GetSource(KeyTypes ... kt) + { + const Key_t key(kt...); + + // Look up and return. Use kNullLoader if no loader is set for this config + auto itLoader = fSourceViews.find(key); + if(itLoader != fSourceViews.end()) return *itLoader->second; + + if constexpr(std::is_same_v){ + return kNullLoader; + } + else{ + static NullSource null; + return null; + } + } + +} \ No newline at end of file diff --git a/CAFAna/Core/SpectrumLoader.cxx b/CAFAna/Core/SpectrumLoader.cxx index d6bcb115..21eeaedb 100644 --- a/CAFAna/Core/SpectrumLoader.cxx +++ b/CAFAna/Core/SpectrumLoader.cxx @@ -12,9 +12,6 @@ #include "CAFAna/Core/Spectrum.h" #include "CAFAna/Core/Utilities.h" -#include "CAFAna/Systs/XSecSystList.h" -#include "CAFAna/Core/FixupRecord.h" - #include "duneanaobj/StandardRecord/Proxy/SRProxy.h" #include @@ -28,14 +25,14 @@ namespace ana { //---------------------------------------------------------------------- - SpectrumLoader::SpectrumLoader(const std::string& wildcard, int max) - : SpectrumLoaderBase(wildcard), max_entries(max) + SpectrumLoader::SpectrumLoader(const std::string& wildcard, const std::string& pathInFile)//, int max) + : SpectrumLoaderBase(wildcard, pathInFile)//, max_entries(max) { } //---------------------------------------------------------------------- - SpectrumLoader::SpectrumLoader(const std::vector& fnames, int max) - : SpectrumLoaderBase(fnames), max_entries(max) + SpectrumLoader::SpectrumLoader(const std::vector& fnames, const std::string& pathInFile)//, int max) + : SpectrumLoaderBase(fnames, pathInFile)//, max_entries(max) { } @@ -46,30 +43,16 @@ namespace ana #ifdef WITH_SAM //---------------------------------------------------------------------- - SpectrumLoader SpectrumLoader::FromSAMProject(const std::string& proj, + SpectrumLoader* SpectrumLoader::FromSAMProject(const std::string& proj, int fileLimit) { - SpectrumLoader ret; - ret.fWildcard = "project " + proj; - ret.fFileSource = - std::unique_ptr(new SAMProjectSource(proj, fileLimit)); + SpectrumLoader* ret = new SpectrumLoader; + ret->fWildcard = "project "+proj; + ret->fFileSource = std::unique_ptr(new SAMProjectSource(proj, fileLimit)); return ret; } #endif - //---------------------------------------------------------------------- - SpectrumLoader::~SpectrumLoader() - { - } - - struct CompareByID - { - bool operator()(const Cut& a, const Cut& b) const - { - return a.ID() < b.ID(); - } - }; - //---------------------------------------------------------------------- void SpectrumLoader::Go() { @@ -79,16 +62,6 @@ namespace ana } fGone = true; - // Find all the unique cuts - std::set cuts; - for(auto& shiftdef: fHistDefs) - for(auto& cutdef: shiftdef.second) - cuts.insert(cutdef.first); - for(const Cut& cut: cuts) fAllCuts.push_back(cut); - - fLivetimeByCut.resize(fAllCuts.size()); - fPOTByCut.resize(fAllCuts.size()); - const int Nfiles = NFiles(); Progress* prog = 0; @@ -99,12 +72,18 @@ namespace ana while(TFile* f = GetNextFile()){ ++fileIdx; - if(Nfiles >= 0 && !prog){ - std::string sum = TString::Format("Filling %lu spectra", fHistDefs.TotalSize()).Data(); - sum += TString::Format(" from %d files matching '%s'", Nfiles, fWildcard.c_str()).Data(); - prog = new Progress(sum); + // need to find ISpillSink + if(Nfiles >= 0 && !prog){ + unsigned int totsinks = 0; + for(const ISRSink* s: fSinks) totsinks += s->NSinks(); + + if (totsinks < 1) + continue; + + prog = new Progress(TString::Format("Filling %u spectra from %d files matching '%s'", totsinks, Nfiles, fWildcard.c_str()).Data()); } + HandleFile(f, Nfiles == 1 ? prog : 0); if(Nfiles > 1 && prog) prog->SetProgress((fileIdx+1.)/Nfiles); @@ -119,10 +98,23 @@ namespace ana delete prog; } - ReportExposures(); + for(ISRSink* sink: fSinks) sink->RemoveSource(this); + fSinks.clear(); + } - fHistDefs.RemoveLoader(this); - fHistDefs.Clear(); + //---------------------------------------------------------------------- + void SpectrumLoader::PrintGraph(std::ostream& os) const + { + os << "digraph{" << std::endl; + os << "comment = \"Render me with a command like: dot -Tpdf graph.dot > graph.pdf\"" << std::endl << std::endl; + Passthrough::PrintGraph(os); + os << "}"; + } + + //---------------------------------------------------------------------- + void SpectrumLoader::PrintGraph() const + { + PrintGraph(std::cout); } //---------------------------------------------------------------------- @@ -133,202 +125,45 @@ namespace ana // In files with both "caf" and "cafTree", "cafTree" is the correct // version. "caf" is ROOT's temporary save while the file is being produced // and may be incomplete. - TTree* tr = (TTree*)f->Get("cafTree"); - if(!tr) tr = (TTree*)f->Get("caf"); - + auto tr = GetDirectoryFile(f)->Get("cafTree"); assert(tr); - caf::SRProxy sr(tr, ""); + caf::SRProxy sr(tr, "rec"); FloatingExceptionOnNaN fpnan(false); long Nentries = tr->GetEntries(); - if(max_entries != 0 && max_entries < Nentries) - Nentries = max_entries; + //if(max_entries != 0 && max_entries < Nentries) + // Nentries = max_entries; for(long n = 0; n < Nentries; ++n){ tr->LoadTree(n); - FixupRecord(&sr, tr); + // SBN here has fPOT and fNReadouts accounting... + // dont know what to do about that + // at the moment, I left fPOT to be handled in SpectrumLoaderBase same as fPOTFromHist + + // todo: we'll resurrect this if we have to... + //FixupRecord(&sr, tr); - HandleRecord(&sr); + HandleRecord(&sr, 1); - if(prog && n%100 == 0) prog->SetProgress(double(n)/Nentries); + if(prog) prog->SetProgress(double(n)/Nentries); } // end for n } //---------------------------------------------------------------------- - /// Helper for \ref SpectrumLoader::HandleRecord - template class CutVarCache + void SpectrumLoader::StoreExposures() { - public: - CutVarCache() : fCache(U::MaxID()+1) {} - - inline T Get(const U& var, const caf::SRProxy* sr) - { - const unsigned int id = var.ID(); - - if(fCache[id].set) return fCache[id].val; - - const T val = var(sr); - fCache[id].val = val; - fCache[id].set = true; - return val; + if(fabs(fPOT - fPOTFromHist)/std::min(fPOT, fPOTFromHist) > 0.001){ + std::cout << fPOT << " POT from hdr differs from " << fPOTFromHist << " POT from the TotalPOT histogram!" << std::endl; + abort(); } - protected: - // Seems to be faster to do this than [unordered_]map - struct CacheElem{ - T val; bool set; - }; - std::vector fCache; - }; - - //---------------------------------------------------------------------- - void SpectrumLoader::HandleRecord(caf::SRProxy* sr) - { - // Some shifts only adjust the weight, so they're effectively nominal, but - // aren't grouped with the other nominal histograms. Keep track of the - // results for nominals in these caches to speed those systs up. - CutVarCache nomCutCache; - CutVarCache nomWeiCache; - CutVarCache nomVarCache; - - for(auto& shiftdef: fHistDefs){ - const SystShifts& shift = shiftdef.first; - - // Need to provide a clean slate for each new set of systematic shifts to - // work from. Copying the whole StandardRecord is pretty expensive, so - // modify it in place and revert it afterwards. - - // Please do not continue/break out of the shiftdef loop. If this is - // required, let's use a RAII type here. - caf::SRProxySystController::BeginTransaction(); - - double systWeight = 1; - bool shifted = false; - - // Can special-case nominal to not pay cost of Shift() - if(!shift.IsNominal()){ - shift.Shift(sr, systWeight); - // If there were only weighting systs applied then the cached nominal - // values are still valid. - shifted = caf::SRProxySystController::AnyShifted(); - } - - for(auto& cutdef: shiftdef.second){ - const Cut& cut = cutdef.first; - - const bool pass = shifted ? cut(sr) : nomCutCache.Get(cut, sr); - // Cut failed, skip all the histograms that depended on it - if(!pass) continue; - - for(auto& weidef: cutdef.second){ - const Weight& weivar = weidef.first; - - double wei = shifted ? weivar(sr) : nomWeiCache.Get(weivar, sr); - - if(wei < 0){ - std::cerr << "Negative weight " << wei - << " returned from Var"; - std::cerr << std::endl; - abort(); - } - - wei *= systWeight; - if(wei == 0) continue; - - for(auto& vardef: weidef.second){ - if(vardef.first.IsMulti()){ - for(double val: vardef.first.GetMultiVar()(sr)){ - for(Spectrum** s : vardef.second.spects) - if(*s) (*s)->Fill(val, wei); - } - continue; - } - - const Var& var = vardef.first.GetVar(); - - const double val = shifted ? var(sr) : nomVarCache.Get(var, sr); - - if(std::isnan(val) || std::isinf(val)){ - std::cerr << "Warning: Bad value: " << val - << " returned from a Var. The input variable(s) could " - << "be NaN in the CAF, or perhaps your " - << "Var code computed 0/0?"; - std::cout << " Not filling into this histogram for this slice." - << std::endl; - continue; - } - - for(Spectrum** s : vardef.second.spects) - if(*s) (*s)->Fill(val, wei); - - for(auto rv: vardef.second.rwSpects){ - ReweightableSpectrum** rw = rv.first; - if(!*rw) continue; - const double yval = rv.second(sr); - - if(std::isnan(yval) || std::isinf(yval)){ - std::cerr << "Warning: Bad value: " << yval - << " for reweighting Var"; - std::cout << ". Not filling into histogram." << std::endl; - continue; - } - - // TODO: ignoring events with no true neutrino etc - if(yval != 0) - (*rw)->Fill(val, yval, wei); - } // end for rw - } // end for vardef - } // end for weidef - } // end for cutdef - - // Return StandardRecord to its unshifted form ready for the next - // histogram. - caf::SRProxySystController::Rollback(); - } // end for shiftdef - - assert(!caf::SRProxySystController::AnyShifted()); - } - - //---------------------------------------------------------------------- - void SpectrumLoader::ReportExposures() - { - // The POT member variables we use here were filled as part of - // SpectrumLoaderBase::GetNextFile() as we looped through the input files. - - // Let's just assume no-one is using the Cut::POT() function yet, so this - // printout remains relevant... + std::cout << fPOT << " POT over " << fNReadouts << " readouts" << std::endl; - std::cout << fPOT << " POT" << std::endl; - } - - // cafanacore's spectra are expecting a different structure of - // spectrumloader. But we can easily trick it with these. - struct SpectrumSink - { - static void FillPOT(Spectrum* s, double pot){s->fPOT += pot;} - }; - struct ReweightableSpectrumSink - { - static void FillPOT(ReweightableSpectrum* rw, double pot){rw->fPOT += pot;} - }; - - //---------------------------------------------------------------------- - void SpectrumLoader::StoreExposures() { - for(auto& shiftdef: fHistDefs){ - for(auto& cutdef: shiftdef.second){ - for(auto& weidef: cutdef.second){ - for(auto& vardef: weidef.second){ - for(Spectrum** s : vardef.second.spects) - if(*s) SpectrumSink::FillPOT(*s, fPOT); - for(auto rv : vardef.second.rwSpects) - if(*rv.first) ReweightableSpectrumSink::FillPOT(*rv.first, fPOT); - } - } - } - } + FillPOT(fPOT); + FillLivetime(fNReadouts); } } // namespace ana diff --git a/CAFAna/Core/SpectrumLoader.h b/CAFAna/Core/SpectrumLoader.h index 4b22e73b..149431d3 100644 --- a/CAFAna/Core/SpectrumLoader.h +++ b/CAFAna/Core/SpectrumLoader.h @@ -4,9 +4,15 @@ #include +#include "duneanaobj/StandardRecord/Proxy/FwdDeclare.h" + +#include "CAFAna/Core/IRecordSource.h" +#include "CAFAna/Core/IRecordSink.h" + +#include "cafanacore/Passthrough.h" + class TFile; -#include "duneanaobj/StandardRecord/Proxy/FwdDeclare.h" namespace ana { @@ -20,21 +26,27 @@ namespace ana /// need. They will register with this loader. Finally, calling \ref Go will /// cause all the spectra to be filled at once. After this the loader may not /// be used again. - class SpectrumLoader: public SpectrumLoaderBase + class SpectrumLoader: public SpectrumLoaderBase, public Passthrough { public: - SpectrumLoader(const std::string& wildcard, int max = 0); - SpectrumLoader(const std::vector& fnames, int max = 0); + SpectrumLoader(const std::string& wildcard, const std::string& pathInFile="");//, int max = 0); + SpectrumLoader(const std::vector& fnames, const std::string& pathInFile="");//, int max = 0); #ifdef WITH_SAM /// Named constructor for SAM projects - static SpectrumLoader FromSAMProject(const std::string& proj, + static SpectrumLoader *FromSAMProject(const std::string& proj, int fileLimit = -1); #endif - virtual ~SpectrumLoader(); + + virtual ~SpectrumLoader() = default; virtual void Go() override; + virtual void PrintGraph(std::ostream& os) const override; + + // Print to stdout + virtual void PrintGraph() const; + protected: SpectrumLoader(); @@ -48,19 +60,28 @@ namespace ana virtual void HandleFile(TFile* f, Progress* prog = 0); - virtual void HandleRecord(caf::SRProxy* sr); + // This is handed off to + //virtual void HandleRecord(caf::SRProxy* sr); /// Save results of AccumulateExposures into the individual spectra virtual void StoreExposures(); /// Prints POT/livetime info for all spectra - virtual void ReportExposures(); + //virtual void ReportExposures(); - /// All unique cuts contained in fHistDefs - std::vector fAllCuts; - std::vector fLivetimeByCut; ///< Indexing matches fAllCuts - std::vector fPOTByCut; ///< Indexing matches fAllCuts - int max_entries; + // int max_exntries; //this is in sbn, unsure if we need it + }; + + class NullLoader: public SpectrumLoader + { + public: + virtual void Go() override {} }; + static NullLoader kNullLoader; + + // SBN had null spill/slice sources, I guess we need both a StandardRecord and Interaction one? + static NullSource kNullSRSource; + static NullSource kNullInteractionSource; + static NullSource kNullTrueIntSource; } diff --git a/CAFAna/Core/SpectrumLoaderBase.cxx b/CAFAna/Core/SpectrumLoaderBase.cxx index 7b7178ea..80ae903a 100644 --- a/CAFAna/Core/SpectrumLoaderBase.cxx +++ b/CAFAna/Core/SpectrumLoaderBase.cxx @@ -29,89 +29,27 @@ namespace ana { //---------------------------------------------------------------------- - SpectrumLoaderBase::SpectList::~SpectList() - { - // We don't seem to be able to do this - maybe SpectList gets copied? - // Let's just bite the bullet and leak a few pointers. This all works - // completely differently in NOvA CAFAna with refactored SpectrumLoader. - // - // Clean up the memory allocated for the pointers themselves - // for(Spectrum** s: spects) delete *s; - // for(auto rv: rwSpects) delete *rv.first; - } - - // Work around ReweightableSpectrum's friend requirements - struct ReweightableSpectrumSink - { - static void AddLoader(ReweightableSpectrum** rw){(*rw)->AddLoader(rw);} - static void RemoveLoader(ReweightableSpectrum** rw){(*rw)->RemoveLoader(rw);} - }; - //---------------------------------------------------------------------- - void SpectrumLoaderBase::SpectList::RemoveLoader(SpectrumLoaderBase* l) - { - for(Spectrum** s: spects) if(*s) (*s)->RemoveLoader(s); - for(auto rv: rwSpects) if(*rv.first) ReweightableSpectrumSink::RemoveLoader(rv.first); - } - - //---------------------------------------------------------------------- - size_t SpectrumLoaderBase::SpectList::TotalSize() const - { - return spects.size() + rwSpects.size(); - } - - //---------------------------------------------------------------------- - template U& SpectrumLoaderBase::IDMap:: - operator[](const T& key) - { - for(auto& it: fElems){ - if(it.first.ID() == key.ID()) return it.second; - } - fElems.push_back(std::make_pair(key, U())); - return fElems.back().second; - } - - //---------------------------------------------------------------------- - template void SpectrumLoaderBase::IDMap:: - RemoveLoader(SpectrumLoaderBase* l) - { - for(auto& it: fElems) it.second.RemoveLoader(l); - } - - //---------------------------------------------------------------------- - template void SpectrumLoaderBase::IDMap::Clear() - { - fElems.clear(); - } - - //---------------------------------------------------------------------- - template size_t SpectrumLoaderBase::IDMap:: - TotalSize() - { - size_t ret = 0; - for(auto& it: fElems) ret += it.second.TotalSize(); - return ret; - } - - // Start of SpectrumLoaderBase proper - - //---------------------------------------------------------------------- + // adding fPOTFromHist and fNReadouts SpectrumLoaderBase::SpectrumLoaderBase() - : fGone(false), fPOT(0) + : fGone(false), fPOT(0), fPOTFromHist(0), fNReadouts(0) { } //---------------------------------------------------------------------- - SpectrumLoaderBase::SpectrumLoaderBase(const std::string& wildcard) + SpectrumLoaderBase::SpectrumLoaderBase(const std::string& wildcard, const std::string& pathInFile) : SpectrumLoaderBase() { fWildcard = wildcard; + fPathInFile = pathInFile; fFileSource = std::unique_ptr(WildcardOrSAMQuery(wildcard)); } //---------------------------------------------------------------------- - SpectrumLoaderBase::SpectrumLoaderBase(const std::vector& fnames) : SpectrumLoaderBase() + SpectrumLoaderBase::SpectrumLoaderBase(const std::vector& fnames, const std::string& pathInFile) + : SpectrumLoaderBase() { fWildcard = "file list"; + fPathInFile = pathInFile; fFileSource = std::unique_ptr(new FileListSource(fnames)); // Apparently MakePredInterps runs over empty file lists? @@ -121,10 +59,7 @@ namespace ana //---------------------------------------------------------------------- SpectrumLoaderBase::~SpectrumLoaderBase() - { - fHistDefs.RemoveLoader(this); - fHistDefs.Clear(); - } + {} //---------------------------------------------------------------------- IFileSource* SpectrumLoaderBase:: @@ -172,68 +107,6 @@ namespace ana abort(); #endif } - - //---------------------------------------------------------------------- - void SpectrumLoaderBase::AddSpectrum(Spectrum& spect, - const Var& var, - const Cut& cut, - const SystShifts& shift, - const Weight& wei) - { - if(fGone){ - std::cerr << "Error: can't add Spectra after the call to Go()" << std::endl; - abort(); - } - - Spectrum** ps = new Spectrum*; - *ps = &spect; - fHistDefs[shift][cut][wei][var].spects.push_back(ps); - - // Remember we have a Go() pending - spect.AddLoader(ps); - } - - //---------------------------------------------------------------------- - void SpectrumLoaderBase::AddSpectrum(Spectrum& spect, - const MultiVar& var, - const Cut& cut, - const SystShifts& shift, - const Weight& wei) - { - if(fGone){ - std::cerr << "Error: can't add Spectra after the call to Go()" << std::endl; - abort(); - } - - Spectrum** ps = new Spectrum*; - *ps = &spect; - fHistDefs[shift][cut][wei][var].spects.push_back(ps); - - // Remember we have a Go() pending - spect.AddLoader(ps); - } - - //---------------------------------------------------------------------- - void SpectrumLoaderBase::AddReweightableSpectrum(ReweightableSpectrum& spect, - const Var& xvar, - const Var& yvar, - const Cut& cut, - const SystShifts& shift, - const Weight& wei) - { - if(fGone){ - std::cerr << "Error: can't add Spectra after the call to Go()" << std::endl; - abort(); - } - - ReweightableSpectrum** prw = new ReweightableSpectrum*; - *prw = &spect; - fHistDefs[shift][cut][wei][xvar].rwSpects.emplace_back(prw, yvar); - - // Remember we have a Go() pending - ReweightableSpectrumSink::AddLoader(prw); - } - //---------------------------------------------------------------------- int SpectrumLoaderBase::NFiles() const { @@ -250,41 +123,69 @@ namespace ana std::cout << "Bad file (zombie): " << f->GetName() << std::endl; abort(); } +// Im not sure this will still be valid in the source/sink world... TTree* trPot = 0; - if (f->GetListOfKeys()->Contains("meta")) - trPot = (TTree*)f->Get("meta"); + TDirectoryFile * df = GetDirectoryFile(f); + if (df->GetListOfKeys()->Contains("meta")) + trPot = df->Get("meta"); else - trPot = (TTree*)f->Get("pottree"); - assert(trPot); + trPot = df->Get("pottree"); + if (!trPot) + { + std::cerr << "Couldn't find the 'meta' or 'pottree' tree in your CAF file for POT accounting.\n" + << "(Are your TTrees in a subfolder in the file? Pass that as an argument to the SpectrumLoader constructor.)\n" + << "Can't proceed. Abort.\n"; + abort(); + } - double pot; - trPot->SetBranchAddress("pot", &pot); + float pot; //double + trPot->SetBranchAddress("rec.beam.pulsepot", &pot); + //trPot->SetBranchAddress("pot", &pot); for(int n = 0; n < trPot->GetEntries(); ++n){ trPot->GetEntry(n); - fPOT += pot; + //unsure if this shoulf be fPOT or fPOTFromHist + // I think fPOT is accounted for in HandleFile in the SBN version + //fPOT += pot; + fPOTFromHist += pot; + fPOT += pot; } + + // This is from the SBN version... + //TH1* hPOT = (TH1*)f->Get("TotalPOT"); + //assert(hPOT); + //fPOTFromHist += hPOT->Integral(0, -1); + return f; } //---------------------------------------------------------------------- - void NullLoader::Go() + TDirectoryFile *SpectrumLoaderBase::GetDirectoryFile(TFile *f) const { - } + if (fPathInFile.empty()) + return f; - //---------------------------------------------------------------------- - NullLoader::~NullLoader() - { + return f->Get(fPathInFile.c_str()); } - // Apparently the existence of fHistDefs isn't enough and I need to spell - // this out to make sure the function bodies are generated. - template struct SpectrumLoaderBase::IDMap>>>; +// //---------------------------------------------------------------------- +// void NullLoader::Go() +// { +// } +// +// //---------------------------------------------------------------------- +// NullLoader::~NullLoader() +// { +// } +// +// // Apparently the existence of fHistDefs isn't enough and I need to spell +// // this out to make sure the function bodies are generated. +// template struct SpectrumLoaderBase::IDMap>>>; } // namespace diff --git a/CAFAna/Core/SpectrumLoaderBase.h b/CAFAna/Core/SpectrumLoaderBase.h index cf3f5fbf..87869510 100644 --- a/CAFAna/Core/SpectrumLoaderBase.h +++ b/CAFAna/Core/SpectrumLoaderBase.h @@ -14,6 +14,7 @@ #include "CAFAna/Core/Var.h" #include "CAFAna/Core/Weight.h" +class TDirectoryFile; class TFile; class TH1; class TTree; @@ -27,36 +28,14 @@ namespace ana class SpectrumLoaderBase { public: - - friend class ReweightableSpectrum; - friend class NDOscillatableSpectrum; - friend class OscillatableSpectrum; - friend class Spectrum; +// Dow we need these friends?? +// friend class ReweightableSpectrum; +// friend class NDOscillatableSpectrum; +// friend class OscillatableSpectrum; +// friend class Spectrum; virtual ~SpectrumLoaderBase(); - /// For use by the \ref Spectrum constructor - virtual void AddSpectrum(Spectrum& spect, - const Var& var, - const Cut& cut, - const SystShifts& shift, - const Weight& wei = kUnweighted); - - /// For use by the \ref Spectrum constructor - virtual void AddSpectrum(Spectrum& spect, - const MultiVar& var, - const Cut& cut, - const SystShifts& shift, - const Weight& wei = kUnweighted); - - /// For use by the constructors of \ref ReweightableSpectrum subclasses - virtual void AddReweightableSpectrum(ReweightableSpectrum& spect, - const Var& xvar, - const Var& yvar, - const Cut& cut, - const SystShifts& shift, - const Weight& wei); - /// Load all the registered spectra virtual void Go() = 0; @@ -67,9 +46,9 @@ namespace ana /// Component of other constructors SpectrumLoaderBase(); /// Construct from a filename, wildcard, SAM definition, or SAM query - SpectrumLoaderBase(const std::string& wildcard); + SpectrumLoaderBase(const std::string& wildcard, const std::string& pathInFile=""); /// Construct from an explicit list of files - SpectrumLoaderBase(const std::vector& fnames); + SpectrumLoaderBase(const std::vector& fnames, const std::string& pathInFile=""); // Move operations SpectrumLoaderBase(SpectrumLoaderBase&&) = default; @@ -88,120 +67,23 @@ namespace ana /// Forwards to \ref fFileSource but also accumulates POT and livetime TFile* GetNextFile(); + /// the relevant trees inside a CAF may be nested in a subdir. + /// this is a simple utility function to centralize that + TDirectoryFile *GetDirectoryFile(TFile *f) const; + std::string fWildcard; std::unique_ptr fFileSource; + std::string fPathInFile; ///< are the various trees we need in some sub-folder? bool fGone; ///< Has Go() been called? Can't add more histograms after that double fPOT; ///< Accumulated by calls to \ref GetNextFile - /// \brief Helper class for \ref SpectrumLoaderBase - /// - /// List of Spectrum and OscillatableSpectrum, some utility functions - struct SpectList - { - ~SpectList(); - void RemoveLoader(SpectrumLoaderBase* l); - size_t TotalSize() const; - - // Doubled pointers are sadly necessary as we need the locations of the - // nodes to be constant so Spectrum can re-register itself if moved. - std::vector spects; - std::vector> rwSpects; - }; - - /// \brief Helper class for \ref SpectrumLoaderBase - /// - /// Functions like std::map except it should be faster to iterate - /// through the elements (while slower to fill) and it knows to compare Ts - /// via their ID() function. Various methods that forward through to the - /// \ref SpectList at the end of the chain. - template struct IDMap - { - U& operator[](const T& key); - - // Make class iterable. Keep inline for speed - typedef typename std::vector>::iterator it_t; - inline it_t begin(){return fElems.begin();} - inline it_t end(){return fElems.end();} - - void RemoveLoader(SpectrumLoaderBase* l); - void Clear(); - size_t TotalSize(); - protected: - std::vector> fElems; - }; - - class VarOrMultiVar - { - public: - // v could easily be a temporary, have to make a copy - VarOrMultiVar(const Var& v) : fVar(new Var(v)), fMultiVar(0) {} - VarOrMultiVar(const MultiVar& v) : fVar(0), fMultiVar(new MultiVar(v)) {} - ~VarOrMultiVar() {delete fVar; delete fMultiVar;} - - VarOrMultiVar(const VarOrMultiVar& v) - : fVar(v.fVar ? new Var(*v.fVar) : 0), - fMultiVar(v.fMultiVar ? new MultiVar(*v.fMultiVar) : 0) - { - } - - VarOrMultiVar(VarOrMultiVar&& v) - { - fVar = v.fVar; - fMultiVar = v.fMultiVar; - v.fVar = 0; - v.fMultiVar = 0; - } - - bool IsMulti() const {return fMultiVar;} - const Var& GetVar() const {assert(fVar); return *fVar;} - const MultiVar& GetMultiVar() const {assert(fMultiVar); return *fMultiVar;} - - int ID() const {return fVar ? fVar->ID() : fMultiVar->ID();} - - protected: - const Var* fVar; - const MultiVar* fMultiVar; - }; - - /// \brief All the spectra that need to be filled - /// - /// [shift][cut][wei][var] - IDMap>>> fHistDefs; - }; - /// \brief Dummy loader that doesn't load any files - /// - /// Useful when a loader is required for a component you want to ignore - class NullLoader: public SpectrumLoaderBase - { - public: - NullLoader() {} - ~NullLoader(); - - virtual void Go() override; - - void AddSpectrum(Spectrum& spect, - const Var& var, - const Cut& cut, - const SystShifts& shift, - const Weight& wei = kUnweighted) override {} - void AddSpectrum(Spectrum& spect, - const MultiVar& var, - const Cut& cut, - const SystShifts& shift, - const Weight& wei = kUnweighted) override {} - - void AddReweightableSpectrum(ReweightableSpectrum& spect, - const Var& xvar, - const Var& yvar, - const Cut& cut, - const SystShifts& shift, - const Weight& wei) override {} + // new additions + double fPOTFromHist; ///< Accumulated by calls to \ref GetNextFile + // Do we really need this? + int fNReadouts; }; - /// \brief Dummy loader that doesn't load any files - /// - /// Useful when a loader is required for a component you want to ignore - static NullLoader kNullLoader; + } diff --git a/CAFAna/Core/SystShifts.cxx b/CAFAna/Core/SystShifts.cxx index 1f56db23..70c8d5ca 100644 --- a/CAFAna/Core/SystShifts.cxx +++ b/CAFAna/Core/SystShifts.cxx @@ -1,8 +1,9 @@ #include "CAFAna/Core/SystShifts.h" -#include "CAFAna/Core/ISyst.h" -#include "CAFAna/Core/Registry.h" #include "CAFAna/Core/MathUtil.h" + +#include "cafanacore/Registry.h" + #include "CAFAna/Core/Stan.h" #include "CAFAna/Core/StanUtils.h" @@ -14,6 +15,7 @@ #include "TH1D.h" #include "TMath.h" #include "TObjString.h" +#include "TRandom3.h" #include "TString.h" namespace ana @@ -24,15 +26,17 @@ namespace ana const SystShifts kNoShift = SystShifts::Nominal(); //---------------------------------------------------------------------- - SystShifts::SystShifts() : fID(0) {} + SystShifts::SystShifts() : fID(0) + { + } //---------------------------------------------------------------------- - SystShifts::SystShifts(const ISyst *syst, double shift) : fID(fgNextID++) + SystShifts::SystShifts(const ISyst *syst, double shift) + : fID(fgNextID++) { if (shift != 0) fSystsDbl.emplace(syst, Clamp(shift, syst)); } - //---------------------------------------------------------------------- SystShifts::SystShifts(const ISyst* syst, stan::math::var shift) : fID(fgNextID++) @@ -42,7 +46,6 @@ namespace ana // so that when the Stan cache gets invalidated we can still return something usable. fSystsDbl.emplace(syst, Clamp(util::GetValAs(shift), syst)); } - //---------------------------------------------------------------------- SystShifts::SystShifts(const std::map &shifts) : fID(fgNextID++) { @@ -50,7 +53,15 @@ namespace ana if (it.second != 0) fSystsDbl.emplace(it.first, Clamp(it.second, it.first)); } - + //---------------------------------------------------------------------- + SystShifts::SystShifts(const std::unordered_map& shifts) + : fID(fgNextID++) + { + for(auto it: shifts) + if(it.second != 0) //should I be clamping? + fSystsDbl.emplace(it.first, Clamp(it.second, it.first)); + //fSystsDbl.emplace(it.first, it.second); + } //---------------------------------------------------------------------- SystShifts::SystShifts(const std::map& shifts) : fID(fgNextID++) @@ -61,7 +72,13 @@ namespace ana fSystsDbl.emplace(it.first, util::GetValAs(it.second)); } } - + //---------------------------------------------------------------------- + SystShifts SystShifts::RandomThrow(const std::vector& systs) + { + SystShifts ret; + for(const ISyst* s: systs) ret.SetShift(s, gRandom->Gaus(0, 1)); + return ret; + } //---------------------------------------------------------------------- std::unique_ptr SystShifts::Copy() const { @@ -153,7 +170,7 @@ namespace ana stan::math::var SystShifts::LogPrior() const { return log(Prior()); } //---------------------------------------------------------------------- - void SystShifts::Shift(caf::SRProxy *sr, + void SystShifts::Shift(caf::SRInteractionProxy* sr, double &weight) const { // always fSystsDbl here because this is only used in the event loop, not in fitting diff --git a/CAFAna/Core/SystShifts.h b/CAFAna/Core/SystShifts.h index d20134c7..355387ca 100644 --- a/CAFAna/Core/SystShifts.h +++ b/CAFAna/Core/SystShifts.h @@ -1,7 +1,6 @@ #pragma once -#include "CAFAna/Core/FwdDeclare.h" -#include "duneanaobj/StandardRecord/Proxy/FwdDeclare.h" +#include "CAFAna/Core/ISyst.h" #include "CAFAna/Core/StanVar.h" @@ -15,40 +14,44 @@ class TDirectory; namespace ana { - class ISyst; - class Restorer; - /// Simple record of shifts applied to systematic parameters class SystShifts { public: SystShifts(); - SystShifts(const ISyst* syst, double shift); +// SystShifts(const ISyst* syst, double shift); +// SystShifts(const ISyst* syst, double shift); + SystShifts(const ISyst* syst, double shift); +// SystShifts(const ISyst*syst, stan::math::var shift); +// SystShifts(const ISyst*, stan::math::var shift); SystShifts(const ISyst* syst, stan::math::var shift); +// SystShifts(const std::map*, double>& shifts); +// SystShifts(const std::map*, double>& shifts); SystShifts(const std::map& shifts); +// SystShifts(const std::unordered_map*, double>& shifts); +// SystShifts(const std::unordered_map*, double>& shifts); + SystShifts(const std::unordered_map& shifts); +// SystShifts(const std::map*, stan::math::var>& shifts); +// SystShifts(const std::map*, stan::math::var>& shifts); SystShifts(const std::map& shifts); - - virtual ~SystShifts() = default; - - /// SystShifts with the same set of systs should have the same ID - int ID() const {return fID;} + //virtual ~SystShifts() = default; static SystShifts Nominal() {return SystShifts();} - - std::vector ActiveSysts() const; - - /// Allow derived classes to overload so they can copy themselves - /// in case they overload Penalty(). Used in IFitter. - /// Note that you own the copy... - virtual std::unique_ptr Copy() const; + static SystShifts RandomThrow(const std::vector& systs); + //static SystShifts RandomThrow(const std::vector*>& systs); + //static SystShifts RandomThrow(const std::vector*>& systs); bool IsNominal() const {return fSystsDbl.empty(); } // since there's always a 'double' copy of any stan ones too /// shift: 0 = nominal; +-1 = 1sigma shifts etc. Arbitrary shifts allowed /// set force=true to insert a syst even if the shift is 0 + //void SetShift(const ISyst* syst, double shift, bool force=false); + //void SetShift(const ISyst* syst, double shift, bool force=false); + //void SetShift(const ISyst* syst, stan::math::var shift); + //void SetShift(const ISyst* syst, stan::math::var shift); void SetShift(const ISyst* syst, double shift, bool force=false); void SetShift(const ISyst* syst, stan::math::var shift); - + /// Templated so that Stan- and not-stan versions have the same interface. /// If you don't specify anything it'll just give you back the double, /// which is probably what you want anyway. @@ -58,12 +61,30 @@ namespace ana void ResetToNominal(); - bool HasStan(const ISyst* s) const {return fSystsStan.count(s);} - bool HasAnyStan() const {return !fSystsStan.empty();} - /// Penalty term for (frequentist) chi-squared fits double Penalty() const; + + //not sure if this is the right change + //void Shift(caf::SRProxy* sr, + void Shift(caf::SRInteractionProxy* sr, + double& weight) const; + + + /// Brief description of component shifts, for printing to screen + std::string ShortName() const; + /// Long description of component shifts, for plot labels + std::string LatexName() const; + + + /// Allow derived classes to overload so they can copy themselves + /// in case they overload Penalty(). Used in IFitter. + /// Note that you own the copy... + virtual std::unique_ptr Copy() const; + + bool HasStan(const ISyst* s) const {return fSystsStan.count(s);} + bool HasAnyStan() const {return !fSystsStan.empty();} + /// Prior used in Bayesian fitting. Override as needed. /// If it's more efficient to calculate log(prior) /// explicitly, override LogPrior() as well @@ -73,14 +94,10 @@ namespace ana /// override this virtual stan::math::var LogPrior() const; + /// SystShifts with the same set of systs should have the same ID + int ID() const {return fID;} - void Shift(caf::SRProxy* sr, - double& weight) const; - - /// Brief description of component shifts, for printing to screen - std::string ShortName() const; - /// Long description of component shifts, for plot labels - std::string LatexName() const; + std::vector ActiveSysts() const; void SaveTo(TDirectory* dir, const std::string& name) const; static std::unique_ptr LoadFrom(TDirectory* dir, const std::string& name); diff --git a/CAFAna/Core/TruthMatching.cxx b/CAFAna/Core/TruthMatching.cxx new file mode 100644 index 00000000..64688f01 --- /dev/null +++ b/CAFAna/Core/TruthMatching.cxx @@ -0,0 +1,37 @@ +#include "CAFAna/Core/TruthMatching.h" + +#include "duneanaobj/StandardRecord/Navigate.h" +#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" + +namespace ana +{ + const caf::SRTrueInteractionProxy * MatchedTrueInteraction(const caf::SRInteractionProxy * srint, double minOverlap) + { + if (srint->truth.size() < 1) + return nullptr; + + int matchIdx = -1; + + // todo: FD CAFs aren't filling the truthOverlap at the moment, but should be. + // for now, just take the first entry in the match list... + if (srint->truthOverlap.empty()) + matchIdx = srint->truth[0]; + else + { + // would prefer to use std::find_if, but caf::Proxy::iterator doesn't have all the right traits, + // and I'm not in the mood to fix it at the moment + for (std::size_t idx = 0; idx < srint->truthOverlap.size(); ++idx) + { + if (srint->truthOverlap[idx] > minOverlap) + { + matchIdx = idx; + break; + } + } + if (matchIdx < 0) + return nullptr; + } + + return caf::FindInteraction(srint->Ancestor()->mc, matchIdx); + } +} \ No newline at end of file diff --git a/CAFAna/Core/TruthMatching.h b/CAFAna/Core/TruthMatching.h new file mode 100644 index 00000000..0c50986a --- /dev/null +++ b/CAFAna/Core/TruthMatching.h @@ -0,0 +1,22 @@ +#pragma once + +#include "duneanaobj/StandardRecord/Navigate.h" + +namespace caf +{ + class SRInteraction; + using SRInteractionProxy = caf::Proxy; + + class SRTrueInteraction; + using SRTrueInteractionProxy = caf::Proxy; +} + +namespace ana +{ + /// \brief Find the associated true interaction for this reco interaction. + /// + /// \param srint the reco interaction in question + /// \param minOverlap minimum fractional overlap between the reco interaction and a found true interaction + /// \return pointer to the matched true interaction, unless no suitable match was found, in which case, nullptr + const caf::SRTrueInteractionProxy * MatchedTrueInteraction(const caf::SRInteractionProxy * srint, double minOverlap=0.5); +} \ No newline at end of file diff --git a/CAFAna/Core/Utilities.cxx b/CAFAna/Core/Utilities.cxx index 3ef7ddf5..7b0cf1ce 100644 --- a/CAFAna/Core/Utilities.cxx +++ b/CAFAna/Core/Utilities.cxx @@ -60,49 +60,62 @@ namespace ana } //---------------------------------------------------------------------- - std::unique_ptr CalcCovMx(const std::vector & binSets, int firstBin, int lastBin) + // Reduce code duplication between CalcCovMx and CalcBiasMx + Eigen::ArrayXd GetBinMeans(const std::vector& binSets) { - if (binSets.size() < 2) - return std::unique_ptr(nullptr); + const unsigned int nBins(binSets.front().size()); + const unsigned int nUniv(binSets.size()); - if (lastBin < 0) - lastBin = binSets[0]->GetSize() - 1; // indexed from 0 + Eigen::ArrayXd binMeans = Eigen::ArrayXd::Zero(nBins); + for(unsigned int univIdx = 0; univIdx < nUniv; ++univIdx) + binMeans += binSets[univIdx]; - int nBins = lastBin - firstBin + 1; // firstBin and lastBin are inclusive + binMeans *= 1./(nUniv); - std::vector binMeans(nBins); - for( const auto & binSet : binSets ) - { - for ( decltype(lastBin) binIdx = firstBin; binIdx <= lastBin; binIdx++ ) - binMeans[binIdx] += (*binSet)[binIdx]; - } - for (decltype(lastBin) binIdx = firstBin; binIdx <= lastBin; binIdx++) - binMeans[binIdx] /= binSets.size(); + return binMeans; + } + + //---------------------------------------------------------------------- + Eigen::MatrixXd CalcCovMx(const std::vector& binSets) + { + if (binSets.size() < 2) + return Eigen::MatrixXd(0,0); + + const unsigned int nUniv(binSets.size()); + const unsigned int nBins(binSets.front().size()); + const Eigen::ArrayXd binMeans = GetBinMeans(binSets); - auto covmx = std::make_unique(nBins, nBins); + Eigen::MatrixXd covmx = Eigen::MatrixXd::Zero(nBins, nBins); - for( unsigned int hist_idx = 0; hist_idx < binSets.size(); ++hist_idx ) + for(unsigned int univIdx = 0; univIdx < nUniv; ++univIdx) { - // first calculate the weighted sum of squares of the deviations - for( decltype(nBins) i = 0; i < nBins; i++ ) - { - double xi = (*(binSets[hist_idx]))[i]; - for( decltype(nBins) k = i; k < nBins; k++ ) - { - double xk = (*(binSets[hist_idx]))[k]; - (*covmx)[i][k] += (xi - binMeans[i]) * (xk - binMeans[k]); - if (i != k) - (*covmx)[k][i] = (*covmx)[i][k]; // covariance matrices are always symmetric - } - } - } // for (hist_idx) + // Get a column vector of the difference from the mean in each bin + Eigen::MatrixXd errs = (binSets[univIdx] - binMeans).matrix(); + + // Calculate the variance from column * row + covmx += errs * errs.transpose(); + } // for (univIdx) // now divide by N-1 to get sample covariance - (*covmx) *= 1./(binSets.size()-1); + covmx *= 1./(nUniv-1); return covmx; } + //---------------------------------------------------------------------- + Eigen::MatrixXd CalcBiasMx(const Eigen::ArrayXd& nom, const std::vector& binSets) + { + if (binSets.size() < 2) + return Eigen::MatrixXd(0,0); + + const Eigen::ArrayXd binMeans = GetBinMeans(binSets); + + // Get a column vector of the difference from the mean in each bin + Eigen::MatrixXd errs = (nom - binMeans).matrix(); + + // Calculate the variance from column * row + return errs * errs.transpose(); + } //---------------------------------------------------------------------- double LogLikelihood(const TH1* eh, const TH1* oh, bool useOverflow) @@ -165,6 +178,16 @@ namespace ana return ret; } + //---------------------------------------------------------------------- + TH2F * EigenMatrixToTH2(Eigen::MatrixXd m) + { + TH2F* h = new TH2F("", "", m.rows(), 0, m.rows(), m.cols() , 0 , m.cols() ); + for (int x = 0 ; x< m.rows();x++) + for (int y = 0 ; y< m.rows();y++) + h->SetBinContent(x,y,m(x,y)); + + return h; + } //---------------------------------------------------------------------- double Chi2CovMx(const Eigen::ArrayXd& e, const Eigen::ArrayXd& o, const Eigen::MatrixXd& covmxinv) { @@ -682,6 +705,36 @@ namespace ana return ret; } + + //---------------------------------------------------------------------- + double FindQuantile(double frac, std::vector& xs) + { + // This turns out to be a much more fraught issue than you would naively + // expect. This algorithm is equivalent to R-6 here: + // https://en.wikipedia.org/wiki/Quantile#Estimating_quantiles_from_a_sample + + // In principle we could use std::nth_element(). Probably doesn't matter + // much in practice since this is only for plotting. + std::sort(xs.begin(), xs.end()); + + const int N = xs.size(); + // The index we would ideally be sampling at + const double h = frac*(N+1); + // The indices on either side where we have to actually evaluate + const unsigned int h0 = std::floor(h); + const unsigned int h1 = std::ceil(h); + if(h0 == 0) return xs[0]; // Don't underflow indexing + if(h1 > xs.size()) return xs.back(); // Don't overflow indexing + // The values at those indices + const double x0 = xs[h0-1]; // wikipedia is using 1-based indexing + const double x1 = xs[h1-1]; + + if(h0 == h1) return x0; + + // Linear interpolation + return (h1-h)*x0 + (h-h0)*x1; + } + } diff --git a/CAFAna/Core/Utilities.h b/CAFAna/Core/Utilities.h index 4869b977..347c2971 100644 --- a/CAFAna/Core/Utilities.h +++ b/CAFAna/Core/Utilities.h @@ -60,7 +60,21 @@ namespace ana Note TH1D is a child class of TArrayD -- so you can pass a vector of TH1D* to this method. **/ - std::unique_ptr CalcCovMx(const std::vector & binSets, int firstBin=0, int lastBin=-1); + //std::unique_ptr CalcCovMx(const std::vector & binSets, int firstBin=0, int lastBin=-1); + Eigen::MatrixXd CalcCovMx(const std::vector& binSets); + + /** \brief Compute bias from a collection of sets of bin contents. + + \param nom Bins corresponding to the nominal universe from which the bias is calculated + \param binSets Collection of sets of bins from which bias from the nominal is calculated + + \returns Eigen::MatrixXD containing computed bias matrix unless binSets.size() < 2, + in which case an 0*0 matric is returned + **/ + Eigen::MatrixXd CalcBiasMx(const Eigen::ArrayXd& nom, const std::vector& binSets); + + /// Returns a TH2 to visualize matrix easily + // TH2* EigenMatrixToTH2( ) class LLPerBinFracSystErr { @@ -153,6 +167,9 @@ namespace ana TMatrixD TMatrixDFromEigenMatrixXd(const Eigen::MatrixXd& mat); + TH2F * EigenMatrixToTH2(Eigen::MatrixXd m); + + /** \brief Chi-squared calculation using a covariance matrix. \param exp Expected bin counts @@ -262,6 +279,10 @@ namespace ana Eigen::ArrayXd GetMaskArray(const Spectrum& s, double xmin=0, double xmax=-1, double ymin=0, double ymax=-1); + + /// /param frac Quantile to find, eg 0.9 + /// /param xs Values to search in -- this will be sorted + double FindQuantile(double frac, std::vector& xs); } /// \brief Like Ronseal, does exactly what it says on the tin diff --git a/CAFAna/Core/Var.cxx b/CAFAna/Core/Var.cxx new file mode 100644 index 00000000..dbdf9a78 --- /dev/null +++ b/CAFAna/Core/Var.cxx @@ -0,0 +1,33 @@ +#include "CAFAna/Core/Var.h" + +#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" + +#include "CAFAna/Core/TruthMatching.h" + +#include +#include + + +namespace ana +{ + Var TruthVarToVar(const TruthVar & truthvar) + { + return Var([=](const caf::SRInteractionProxy * sri) + { + if (sri->truth.size() < 1) + { + std::cerr << "No matched truth for this reco interaction, can't convert TruthVar to Var\n"; + throw std::runtime_error("Truth is empty"); + } + // todo: FD CAFs apparently aren't filling truthOverlap, but they should be... + if (sri->truthOverlap.size() > 0 && sri->truthOverlap[0] < 0.5) + { + std::cerr << "TruthVarToVar(): best-matched neutrino is < 50% of interaction, can't determine true flavor"; + throw std::runtime_error("No best-matched neutrino"); + } + + return truthvar(MatchedTrueInteraction(sri)); + }); + } + +} \ No newline at end of file diff --git a/CAFAna/Core/Var.h b/CAFAna/Core/Var.h index 5892ebbd..44907a13 100644 --- a/CAFAna/Core/Var.h +++ b/CAFAna/Core/Var.h @@ -11,13 +11,37 @@ namespace ana /// /// A Var consists of a function, taking a StandardRecord and returning the /// value of the variable (which may be some complicated function). - using Var = _Var; + typedef _Var Var; + typedef _Var TruthVar; + typedef _Var TruthPartVar; +//Commented things: I was trying so we could write loader.Interactions()[IntCut].{dlp,pandora}.RecoParticles().{dlp,pandora}[PartiCut] + // typedef _Var Var; + /// \brief Equivalent of \ref Var acting on \ref caf::SRSpill + typedef _Var SRVar; + typedef _Var NDVar; /// \brief For Vars where literally all you need is a single CAF variable /// /// eg Var myVar = SIMPLEVAR(my.var.str); /// NB lack of quotes quotes around my.var.str -#define SIMPLEVAR(CAFNAME) Var([](const caf::SRProxy* sr){return sr->CAFNAME;}) +#define SIMPLEVAR(CAFNAME) Var([](const caf::SRInteractionProxy* sr){return sr->CAFNAME;}) + +#define SIMPLETRUTHVAR(CAFNAME) TruthVar([](const caf::SRTrueInteractionProxy* nu){return nu->CAFNAME;}) + +#define SIMPLENDVAR(CAFNAME) NDVar([](const caf::SRNDLArIntProxy* sr){return sr->CAFNAME;}) + +#define SIMPLESRVAR(CAFNAME) SRVar([](const caf::SRProxy* sr){return sr->CAFNAME;}) + + + inline Var Constant(double v){return Var([v](const caf::SRInteractionProxy*){return v;});} +// inline Var Constant(double v){return Var([v](const caf::SRInteractionBranchProxy*){return v;});} + + typedef _Var RecoPartVar; + +#define SIMPLEPARTVAR(CAFNAME) RecoPartVar([](const caf::SRRecoParticleProxy* sr){return sr->CAFNAME;}) + + /// Convert a Var over a true interaction to one over a reco interaction with associated truth. + Var TruthVarToVar(const TruthVar & truthvar); + - inline Var Constant(double v){return Var([v](const caf::SRProxy*){return v;});} } diff --git a/CAFAna/Core/Weight.h b/CAFAna/Core/Weight.h index 4dd326d2..b45f4579 100644 --- a/CAFAna/Core/Weight.h +++ b/CAFAna/Core/Weight.h @@ -4,11 +4,26 @@ #include "duneanaobj/StandardRecord/Proxy/FwdDeclare.h" +//namespace ana +//{ +// using Weight = _Weight; +// +//#define SIMPLEWEIGHT(CAFNAME) Weight([](const caf::SRProxy* sr){return sr->CAFNAME;}) +// +// const Weight kUnweighted = Unweighted(); +//} + namespace ana { - using Weight = _Weight; + typedef _Weight SRWeight; + + /// \brief Equivalent of \ref Weight acting on \ref caf::SRSpill + typedef _Weight Weight; + typedef _Weight NuTruthWeight; + + /// The simplest possible Weight, always 1. Used as a default weight. + const SRWeight kSRUnweighted = Unweighted(); + const Weight kUnweighted = Unweighted(); -#define SIMPLEWEIGHT(CAFNAME) Weight([](const caf::SRProxy* sr){return sr->CAFNAME;}) - const Weight kUnweighted = Unweighted(); -} +} // namespace \ No newline at end of file diff --git a/CAFAna/Cuts/AnaCuts.cxx b/CAFAna/Cuts/AnaCuts.cxx index ab055654..6fe113ff 100644 --- a/CAFAna/Cuts/AnaCuts.cxx +++ b/CAFAna/Cuts/AnaCuts.cxx @@ -4,6 +4,7 @@ namespace ana { + /* const Cut kPassFD_CVN_NUE( [](const caf::SRProxy* sr) { @@ -41,4 +42,6 @@ const Cut kPassND_RHC_NUMU( // sr->reco_q == +1 && sr->Ehad_veto<30); }); + */ + } diff --git a/CAFAna/Cuts/AnaCuts.h b/CAFAna/Cuts/AnaCuts.h index 3e2fc05e..1791d9bb 100644 --- a/CAFAna/Cuts/AnaCuts.h +++ b/CAFAna/Cuts/AnaCuts.h @@ -4,13 +4,13 @@ namespace ana { - extern const Cut kPassFD_CVN_NUE; - - extern const Cut kPassFD_CVN_NUMU; - - extern const Cut kPassFD_CVN_NUTAU; - - extern const Cut kPassND_FHC_NUMU; - - extern const Cut kPassND_RHC_NUMU; +// extern const Cut kPassFD_CVN_NUE; +// +// extern const Cut kPassFD_CVN_NUMU; +// +// extern const Cut kPassFD_CVN_NUTAU; +// +// extern const Cut kPassND_FHC_NUMU; +// +// extern const Cut kPassND_RHC_NUMU; } diff --git a/CAFAna/Cuts/CMakeLists.txt b/CAFAna/Cuts/CMakeLists.txt index 8b6bd859..264ed531 100644 --- a/CAFAna/Cuts/CMakeLists.txt +++ b/CAFAna/Cuts/CMakeLists.txt @@ -16,6 +16,9 @@ if(DEFINED USE_OPENMP AND USE_OPENMP) target_compile_options(CAFAnaCuts BEFORE PUBLIC -DUSE_PREDINTERP_OMP -fopenmp) endif() -install(TARGETS CAFAnaCuts +install(TARGETS CAFAnaCuts + EXPORT CAFAnaTargets LIBRARY DESTINATION lib/ PUBLIC_HEADER DESTINATION include/CAFAna/Cuts/) + +add_cafana_lib(CAFAnaCuts) \ No newline at end of file diff --git a/CAFAna/Cuts/TruthCuts.cxx b/CAFAna/Cuts/TruthCuts.cxx index d410e2c5..90ef766b 100644 --- a/CAFAna/Cuts/TruthCuts.cxx +++ b/CAFAna/Cuts/TruthCuts.cxx @@ -1,4 +1,81 @@ #include "CAFAna/Cuts/TruthCuts.h" +#include "duneanaobj/StandardRecord/Navigate.h" +#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" +#include +#include +#include "CAFAna/Core/TruthMatching.h" // Just make sure that the cuts get built on a regular basis. Could contain // more complex cut logic in the future. +namespace ana +{ + const TruthCut kIsNC_NT([](const caf::SRTrueInteractionProxy* nu) + { + return !nu->iscc; + }); + const Cut kIsNC = TruthCutToCut(kIsNC_NT); + + const TruthCut kIsNue_NT([](const caf::SRTrueInteractionProxy* nu) + { + return abs(nu->pdg) == 12; + }); + const Cut kIsNue = TruthCutToCut(kIsNue_NT); + + const TruthCut kIsNumu_NT([](const caf::SRTrueInteractionProxy* nu) + { + return abs(nu->pdg) == 14; + }); + const Cut kIsNumu = TruthCutToCut(kIsNumu_NT); + + const TruthCut kIsNutau_NT([](const caf::SRTrueInteractionProxy* nu) + { + return abs(nu->pdg) == 16; + }); + const Cut kIsNutau = TruthCutToCut(kIsNutau_NT); + + + bool CCFlavSel::operator()(const caf::SRTrueInteractionProxy* nu) const + { + return (nu->iscc && + abs(nu->pdg) == fPdg && + abs(nu->pdgorig) == fPdgOrig); + } + + bool CCFlavSel::operator()(const caf::SRInteractionProxy* srint) const + { + if (!kHasNeutrino(srint)) + throw std::runtime_error("CCFlavSel::operator(): no true neutrinos, can't determine true flavor"); + + if (srint->truthOverlap[0] < 0.5) + throw std::runtime_error("CCFlavSel::operator(): best-matched neutrino is < 50% of interaction, can't determine true flavor"); + + return (*this)(MatchedTrueInteraction(srint)); + } + + const Cut kIsNueApp = TruthCutToCut(kIsNueApp_NT); + const Cut kIsNumuCC = TruthCutToCut(kIsNumuCC_NT); + const Cut kIsBeamNue = TruthCutToCut(kIsBeamNue_NT); + const Cut kIsNumuApp = TruthCutToCut(kIsNumuApp_NT); + const Cut kIsTauFromMu = TruthCutToCut(kIsTauFromMu_NT); + const Cut kIsTauFromE = TruthCutToCut(kIsTauFromE_NT); + + + const TruthCut kIsAntiNu_NT([](const caf::SRTrueInteractionProxy* nu) + { + return nu->pdg < 0; + }); + const Cut kIsAntiNu = TruthCutToCut(kIsAntiNu_NT); + + const TruthCut kIsNu_NT([](const caf::SRTrueInteractionProxy* nu) + { + return nu->pdg > 0; + }); + const Cut kIsNu = TruthCutToCut(kIsNu_NT); + + const Cut kHasNeutrino( + [](const caf::SRInteractionProxy* sr) + { return (sr->truth.size() > 0); } + ); + + +} \ No newline at end of file diff --git a/CAFAna/Cuts/TruthCuts.h b/CAFAna/Cuts/TruthCuts.h index 54475ab5..ec95b8c5 100644 --- a/CAFAna/Cuts/TruthCuts.h +++ b/CAFAna/Cuts/TruthCuts.h @@ -1,20 +1,21 @@ #pragma once #include "CAFAna/Core/Cut.h" -#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" + namespace ana { - /// \brief Is this a Neutral %Current event? - /// - /// We use uniform-initializer syntax to concisely pass the list of necessary - /// branches. In this case the selection function is simple enough that we - /// can include it inline as a lambda function. - const Cut kIsNC([](const caf::SRProxy* sr) - { - return !sr->isCC; - }); + extern const TruthCut kIsNC_NT; ///< Is this SRTrueInteraction an NC interaction? + extern const TruthCut kIsNue_NT; ///< Is this SRTrueInteraction a nue CC interaction? + extern const TruthCut kIsNumu_NT; ///< Is this SRTrueInteraction a numu CC interaction? + extern const TruthCut kIsNutau_NT; ///< Is this SRTrueInteraction a nutau CC interaction? + + extern const Cut kIsNC; ///< Adapt kIsNC_NT for (reco) SRInteraction with truth matching + extern const Cut kIsNue; ///< Adapt kIsNue_NT for (reco) SRInteraction with truth matching + extern const Cut kIsNumu; ///< Adapt kIsNumu_NT for (reco) SRInteraction with truth matching + extern const Cut kIsNutau; ///< Adapt kIsNutau_NT for (reco) SRInteraction with truth matching + //---------------------------------------------------------------------- /// Helper for defining true CC event cuts @@ -25,10 +26,9 @@ namespace ana { } - bool operator()(const caf::SRProxy* sr) const - { - return sr->isCC && abs(sr->nuPDGunosc) == fPdgOrig && abs(sr->nuPDG) == fPdg; - } + bool operator()(const caf::SRTrueInteractionProxy* nu) const; + bool operator()(const caf::SRInteractionProxy* nu) const; + protected: int fPdg, fPdgOrig; }; @@ -38,100 +38,37 @@ namespace ana // constants to be easily duplicated. /// Select CC \f$ \nu_\mu\to\nu_e \f$ - const Cut kIsSig (CCFlavSel(12, 14)); + const TruthCut kIsNueApp_NT (CCFlavSel(12, 14)); + extern const Cut kIsNueApp; // defined in .cxx + /// Select CC \f$ \nu_\mu\to\nu_\mu \f$ - const Cut kIsNumuCC (CCFlavSel(14, 14)); + const TruthCut kIsNumuCC_NT (CCFlavSel(14, 14)); + extern const Cut kIsNumuCC; + /// Select CC \f$ \nu_e\to\nu_e \f$ - const Cut kIsBeamNue(CCFlavSel(12, 12)); + const TruthCut kIsBeamNue_NT(CCFlavSel(12, 12)); + extern const Cut kIsBeamNue; + /// Select CC \f$ \nu_e\to\nu_\mu \f$ - const Cut kIsNumuApp(CCFlavSel(14, 12)); + const TruthCut kIsNumuApp_NT(CCFlavSel(14, 12)); + extern const Cut kIsNumuApp; + /// Select CC \f$ \nu_\mu\to\nu_\tau \f$ - const Cut kIsTauFromMu(CCFlavSel(16, 14)); + const TruthCut kIsTauFromMu_NT(CCFlavSel(16, 14)); + extern const Cut kIsTauFromMu; + /// Select CC \f$ \nu_e\to\nu_\tau \f$ - const Cut kIsTauFromE(CCFlavSel(16, 12)); + const TruthCut kIsTauFromE_NT(CCFlavSel(16, 12)); + extern const Cut kIsTauFromE; /// Is this truly an antineutrino? - const Cut kIsAntiNu([](const caf::SRProxy* sr) - { - return sr->nuPDG < 0; - }); - - inline bool IsInFDFV(double pos_x_cm, double pos_y_cm, double pos_z_cm) { - return (abs(pos_x_cm) < 310 && abs(pos_y_cm) < 550 && pos_z_cm > 50 && - pos_z_cm < 1244); - } - - - // Based just on PDG code and not on oscillation channel - const Cut kActuallyIsNumuCC([](const caf::SRProxy *sr) { - return sr->isCC && (sr->nuPDG == 14); - }); - - const Cut kActuallyIsNumubarCC([](const caf::SRProxy *sr) { - return sr->isCC && (sr->nuPDG == -14); - }); - - const Cut kActuallyIsNueCC([](const caf::SRProxy *sr) { - return sr->isCC && (sr->nuPDG == 12); - }); - - const Cut kActuallyIsNuebarCC([](const caf::SRProxy *sr) { - return sr->isCC && (sr->nuPDG == -12); - }); - - inline bool IsInNDFV(double pos_x_cm, double pos_y_cm, double pos_z_cm) { - bool inDeadRegion = false; - for (int i = -3; i <= 3; ++i) { - // 0.5cm cathode in the middle of each module, plus 0.5cm buffer - double cathode_center = i * 102.1; - if (pos_x_cm > cathode_center - 0.75 && pos_x_cm < cathode_center + 0.75) - inDeadRegion = true; - - // 1.6cm dead region between modules (0.5cm module wall and 0.3cm pixel - // plane, x2) don't worry about outer boundary because events are only - // generated in active Ar + insides - double module_boundary = i * 102.1 + 51.05; - if (i <= 2 && pos_x_cm > module_boundary - 1.3 && - pos_x_cm < module_boundary + 1.3) - inDeadRegion = true; - } - for (int i = 1; i <= 4; ++i) { - // module boundaries in z are 1.8cm (0.4cm ArCLight plane + 0.5cm module - // wall, x2) module is 102.1cm wide, but only 101.8cm long due to cathode - // (0.5cm) being absent in length but ArCLight is 0.1cm thicker than pixel - // plane so it's 0.3cm difference positions are off-set by 0.6 because I - // defined 0 to be the upstream edge based on the active volume by - // inspecting a plot, and aparently missed by 3 mm, but whatever add 8mm = - // 2 pad buffer due to worse position resolution in spatial dimension z - // compared to timing direction x so total FV gap will be 1.8 + 2*0.8 - // = 3.4cm - double module_boundary = i * 101.8 - 0.6; - if (pos_z_cm > module_boundary - 1.7 && pos_z_cm < module_boundary + 1.7) - inDeadRegion = true; - } - - return (abs(pos_x_cm) < 200 && abs(pos_y_cm) < 100 && pos_z_cm > 50 && - pos_z_cm < 350 && !inDeadRegion); - } - - inline bool IsInFV(bool IsFD, double pos_x_cm, double pos_y_cm, - double pos_z_cm) { - return IsFD ? IsInFDFV(pos_x_cm, pos_y_cm, pos_z_cm) - : IsInNDFV(pos_x_cm, pos_y_cm, pos_z_cm); - } - - const Cut kIsTrueFV([](const caf::SRProxy* sr) - { - return IsInFV( - sr->isFD, - sr->vtx_x,sr->vtx_y,sr->vtx_z); - }); - - //ETW 11/5/2018 Fiducial cut using MVA variable - //Should use the previous one (kIsTrueFV) for nominal analysis - const Cut kPassFid_MVA([](const caf::SRProxy* sr) - { - return ( sr->mvanumu > -1 ); - }); + extern const TruthCut kIsAntiNu_NT; + extern const Cut kIsAntiNu; + + extern const TruthCut kIsNu_NT; + extern const Cut kIsNu; + + /// Check if MC slice has neutrino information (useful for in-and-out tests) + extern const Cut kHasNeutrino; } // namespace ana diff --git a/CAFAna/Decomp/CMakeLists.txt b/CAFAna/Decomp/CMakeLists.txt deleted file mode 100644 index 4535cb4a..00000000 --- a/CAFAna/Decomp/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -set(Decomp_implementation_files - IDecomp.cxx - NumuDecomp.cxx) - -set(Decomp_header_files - IDecomp.h - NumuDecomp.h) - -add_library(CAFAnaDecomp SHARED ${Decomp_implementation_files}) -target_link_libraries(CAFAnaDecomp CAFAnaCore) - -set_target_properties(CAFAnaDecomp PROPERTIES - PUBLIC_HEADER "${Decomp_header_files}") - -if(DEFINED USE_OPENMP AND USE_OPENMP) - target_compile_options(CAFAnaDecomp BEFORE PUBLIC -DUSE_PREDINTERP_OMP -fopenmp) -endif() - -install(TARGETS CAFAnaDecomp - LIBRARY DESTINATION lib/ - PUBLIC_HEADER DESTINATION include/CAFAna/Decomp/) diff --git a/CAFAna/Decomp/IDecomp.cxx b/CAFAna/Decomp/IDecomp.cxx deleted file mode 100644 index 92f85652..00000000 --- a/CAFAna/Decomp/IDecomp.cxx +++ /dev/null @@ -1,29 +0,0 @@ -#include "CAFAna/Decomp/IDecomp.h" - -#include "CAFAna/Core/LoadFromFile.h" - -#include - -#include "TDirectory.h" -#include "TObjString.h" - -// So we can implement LoadFrom() -#include "CAFAna/Decomp/NumuDecomp.h" - -namespace ana -{ - //---------------------------------------------------------------------- - // Definition to satisfy the declaration in Core/LoadFromFile.h - template<> std::unique_ptr LoadFrom(TDirectory* dir, const std::string& name) - { - TObjString* ptag = (TObjString*)dir->Get((name+"/type").c_str()); - assert(ptag); - - const TString tag = ptag->GetString(); - - if(tag == "NumuDecomp") return NumuDecomp::LoadFrom(dir, name); - - std::cerr << "Unknown Decomp type '" << tag << "'" << std::endl; - abort(); - } -} diff --git a/CAFAna/Decomp/IDecomp.h b/CAFAna/Decomp/IDecomp.h deleted file mode 100644 index e5715e98..00000000 --- a/CAFAna/Decomp/IDecomp.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "CAFAna/Core/Cut.h" -#include "CAFAna/Core/SpectrumLoaderBase.h" -#include "CAFAna/Core/Spectrum.h" - -class TDirectory; - -namespace ana -{ - - /// Standard interface to all decomposition techniques - class IDecomp - { - public: - virtual ~IDecomp() = default; - virtual Spectrum NCComponent() const = 0; - virtual Spectrum NumuComponent() const = 0; - virtual Spectrum AntiNumuComponent() const = 0; - virtual Spectrum NueComponent() const = 0; - virtual Spectrum AntiNueComponent() const = 0; - - virtual void SaveTo(TDirectory* dir, const std::string& name) const = 0; - }; -} diff --git a/CAFAna/Decomp/NumuDecomp.cxx b/CAFAna/Decomp/NumuDecomp.cxx deleted file mode 100644 index 57dd75c9..00000000 --- a/CAFAna/Decomp/NumuDecomp.cxx +++ /dev/null @@ -1,117 +0,0 @@ -#include "CAFAna/Decomp/NumuDecomp.h" - -#include "CAFAna/Cuts/TruthCuts.h" -#include "CAFAna/Core/Ratio.h" - -#include - -#include "TDirectory.h" -#include "TObjString.h" - -namespace ana -{ - //---------------------------------------------------------------------- - NumuDecomp::NumuDecomp(SpectrumLoaderBase& loaderMC, - SpectrumLoaderBase& loaderData, - const std::string& label, - const Binning& bins, - const Var& var, - const Cut& cut, - const SystShifts& shiftMC, - const SystShifts& shiftData, - const Weight& wei) - : NumuDecomp(loaderMC, loaderData, HistAxis(label, bins, var), - cut, shiftMC, shiftData, wei) - { - } - - //---------------------------------------------------------------------- - NumuDecomp::NumuDecomp(SpectrumLoaderBase& loaderMC, - SpectrumLoaderBase& loaderData, - const HistAxis& axis, - const Cut& cut, - const SystShifts& shiftMC, - const SystShifts& shiftData, - const Weight& wei) - : fData (loaderData, axis, cut, shiftData, wei), - fNC (loaderMC, axis, cut && kIsNC, shiftMC, wei), - fNue (loaderMC, axis, cut && kIsBeamNue&&!kIsAntiNu, shiftMC, wei), - fAntiNue (loaderMC, axis, cut && kIsBeamNue&& kIsAntiNu, shiftMC, wei), - fNumu (loaderMC, axis, cut && kIsNumuCC &&!kIsAntiNu, shiftMC, wei), - fAntiNumu(loaderMC, axis, cut && kIsNumuCC && kIsAntiNu, shiftMC, wei), - fNotNumu (loaderMC, axis, cut && !kIsNumuCC, shiftMC, wei) - { - } - - //---------------------------------------------------------------------- - NumuDecomp::NumuDecomp(Loaders& loaders, - const HistAxis& axis, - const Cut& cut, - const SystShifts& shiftMC, - const SystShifts& shiftData, - const Weight& wei) - : NumuDecomp(loaders.GetLoader(caf::kNEARDET, Loaders::kMC), - loaders.GetLoader(caf::kNEARDET, Loaders::kData), - axis, cut, shiftMC, shiftData, wei) - { - } - - //---------------------------------------------------------------------- - Spectrum NumuDecomp::NumuComponent() const - { - // Subtract backgrounds from data using MC, then split into nu/antinu - // components using MC ratio - return (fNumu/(fNumu+fAntiNumu))*(fData-fNotNumu); - } - - //---------------------------------------------------------------------- - Spectrum NumuDecomp::AntiNumuComponent() const - { - return (fAntiNumu/(fNumu+fAntiNumu))*(fData-fNotNumu); - } - - //---------------------------------------------------------------------- - void NumuDecomp::SaveTo(TDirectory* dir, const std::string& name) const - { - TDirectory* tmp = gDirectory; - - dir = dir->mkdir(name.c_str()); // switch to subdir - dir->cd(); - - TObjString("NumuDecomp").Write("type"); - - fNC.SaveTo(dir, "nc_comp"); - fData.SaveTo(dir, "data_comp"); - fNue.SaveTo(dir, "nue_comp"); - fAntiNue.SaveTo(dir, "antinue_comp"); - fNumu.SaveTo(dir, "numu_comp"); - fAntiNumu.SaveTo(dir, "antinumu_comp"); - fNotNumu.SaveTo(dir, "notnumu_comp"); - - dir->Write(); - delete dir; - - tmp->cd(); - } - - //---------------------------------------------------------------------- - std::unique_ptr NumuDecomp::LoadFrom(TDirectory* dir, const std::string& name) - { - dir = dir->GetDirectory(name.c_str()); // switch to subdir - assert(dir); - - std::unique_ptr ret(new NumuDecomp); - - ret->fNC = *Spectrum::LoadFrom(dir, "nc_comp"); - ret->fData = *Spectrum::LoadFrom(dir, "data_comp"); - ret->fNue = *Spectrum::LoadFrom(dir, "nue_comp"); - ret->fAntiNue = *Spectrum::LoadFrom(dir, "antinue_comp"); - ret->fNumu = *Spectrum::LoadFrom(dir, "numu_comp"); - ret->fAntiNumu = *Spectrum::LoadFrom(dir, "antinumu_comp"); - ret->fNotNumu = *Spectrum::LoadFrom(dir, "notnumu_comp"); - - delete dir; - - return ret; - } -} diff --git a/CAFAna/Decomp/NumuDecomp.h b/CAFAna/Decomp/NumuDecomp.h deleted file mode 100644 index 76a4da5f..00000000 --- a/CAFAna/Decomp/NumuDecomp.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include "CAFAna/Decomp/IDecomp.h" - -#include "CAFAna/Core/Loaders.h" - -namespace ana -{ - /// Uses MC for NC and \f$ \nu_e \f$ CC components, assigns remainder of data to \f$ \nu_\mu \f$ CC - class NumuDecomp: public IDecomp - { - public: - NumuDecomp(SpectrumLoaderBase& loaderMC, - SpectrumLoaderBase& loaderData, - const std::string& label, - const Binning& bins, - const Var& var, - const Cut& cut, - const SystShifts& shiftMC = kNoShift, - const SystShifts& shiftData = kNoShift, - const Weight& wei = kUnweighted); - - NumuDecomp(SpectrumLoaderBase& loaderMC, - SpectrumLoaderBase& loaderData, - const HistAxis& axis, - const Cut& cut, - const SystShifts& shiftMC = kNoShift, - const SystShifts& shiftData = kNoShift, - const Weight& wei = kUnweighted); - - NumuDecomp(Loaders& loaders, - const HistAxis& axis, - const Cut& cut, - const SystShifts& shiftMC = kNoShift, - const SystShifts& shiftData = kNoShift, - const Weight& wei = kUnweighted); - - Spectrum NumuComponent() const override; - Spectrum AntiNumuComponent() const override; - Spectrum NCComponent() const override {return fNC;} - Spectrum NueComponent() const override {return fNue;} - Spectrum AntiNueComponent() const override {return fAntiNue;} - - virtual Spectrum MC_NumuComponent() const {return fNumu;} - virtual Spectrum MC_AntiNumuComponent() const {return fAntiNumu;} - virtual Spectrum Data_Component () const {return fData;} - - void SaveTo(TDirectory* dir, const std::string& name) const override; - static std::unique_ptr LoadFrom(TDirectory* dir, const std::string& name); - - protected: - NumuDecomp() - : fData(Spectrum::Uninitialized()), - fNC (Spectrum::Uninitialized()), - fNue (Spectrum::Uninitialized()), - fAntiNue(Spectrum::Uninitialized()), - fNumu(Spectrum::Uninitialized()), - fAntiNumu(Spectrum::Uninitialized()), - fNotNumu(Spectrum::Uninitialized()) - {}; - - Spectrum fData; - - Spectrum fNC; - - Spectrum fNue; - Spectrum fAntiNue; - - Spectrum fNumu; - Spectrum fAntiNumu; - - Spectrum fNotNumu; - }; -} diff --git a/CAFAna/Experiment/CMakeLists.txt b/CAFAna/Experiment/CMakeLists.txt index 37cb5083..8d77383a 100644 --- a/CAFAna/Experiment/CMakeLists.txt +++ b/CAFAna/Experiment/CMakeLists.txt @@ -34,6 +34,9 @@ if(DEFINED USE_OPENMP AND USE_OPENMP) target_compile_options(CAFAnaExperiment BEFORE PUBLIC -DUSE_PREDINTERP_OMP -fopenmp) endif() -install(TARGETS CAFAnaExperiment +install(TARGETS CAFAnaExperiment + EXPORT CAFAnaTargets LIBRARY DESTINATION lib/ PUBLIC_HEADER DESTINATION include/CAFAna/Experiment/) + +add_cafana_lib(CAFAnaExperiment) diff --git a/CAFAna/Extrap/CMakeLists.txt b/CAFAna/Extrap/CMakeLists.txt index c8276dd2..9a6733ba 100644 --- a/CAFAna/Extrap/CMakeLists.txt +++ b/CAFAna/Extrap/CMakeLists.txt @@ -1,14 +1,9 @@ set(Extrap_implementation_files IExtrap.cxx - ModularExtrap.cxx - ModularExtrapComponent.cxx - ModularExtrapComponentPlot.cxx TrivialExtrap.cxx) set(Extrap_header_files IExtrap.h - ModularExtrap.h - ModularExtrapComponent.h TrivialExtrap.h) add_library(CAFAnaExtrap SHARED ${Extrap_implementation_files}) @@ -21,6 +16,9 @@ if(DEFINED USE_OPENMP AND USE_OPENMP) target_compile_options(CAFAnaExtrap BEFORE PUBLIC -DUSE_PREDINTERP_OMP -fopenmp) endif() -install(TARGETS CAFAnaExtrap +install(TARGETS CAFAnaExtrap + EXPORT CAFAnaTargets LIBRARY DESTINATION lib/ PUBLIC_HEADER DESTINATION include/CAFAna/Extrap/) + +add_cafana_lib(CAFAnaExtrap) diff --git a/CAFAna/Extrap/ModularExtrap.cxx b/CAFAna/Extrap/ModularExtrap.cxx deleted file mode 100644 index a95cf47b..00000000 --- a/CAFAna/Extrap/ModularExtrap.cxx +++ /dev/null @@ -1,429 +0,0 @@ -#if 0 -// Currently dead code - -#include "CAFAna/Core/LoadFromFile.h" -#include "CAFAna/Extrap/ModularExtrap.h" -#include "CAFAna/Core/Loaders.h" -#include "CAFAna/Cuts/TruthCuts.h" -#include "TObjString.h" -#include "TDirectory.h" - -namespace ana -{ - - //--------------------------------------------------------------------------- - /* - ModularExtrap ModularExtrap::Nue( - Loaders& loaders, - const IDecomp& nueDecomp, - const IDecomp& numuDecomp, - const HistAxis& axis, - const HistAxis& axisNumuND, - const Cut& fdcut, - const Cut& nueNDcut, - const Cut& numuNDcut, - const SystShifts& shiftMC, - const Weight& weight - ){ - return ModularExtrap::Nue( - loaders.GetLoader( - caf::kNEARDET, Loaders::kMC, Loaders::kNonSwap), - loaders.GetLoader( - caf::kFARDET, Loaders::kMC, Loaders::kFluxSwap), - loaders.GetLoader( - caf::kFARDET, Loaders::kMC, Loaders::kNonSwap), - loaders.GetLoader( - caf::kFARDET, Loaders::kMC, Loaders::kTauSwap), - nueDecomp, - numuDecomp, - axis, - axisNumuND, - fdcut, - nueNDcut, - numuNDcut, - shiftMC, - weight - ); - } - */ - //--------------------------------------------------------------------------- - - ModularExtrap ModularExtrap::Numu( - Loaders& loaders, - const IDecomp& numuDecomp, - const HistAxis& axis, - const Cut& fdcut, - const Cut& ndcut, - const SystShifts& shiftMC, - const Weight& weight - ){ - return ModularExtrap::Numu( - loaders.GetLoader( - caf::kNEARDET, Loaders::kMC, Loaders::kNonSwap), - loaders.GetLoader( - caf::kFARDET, Loaders::kMC, Loaders::kNonSwap), - loaders.GetLoader( - caf::kFARDET, Loaders::kMC, Loaders::kNue), - loaders.GetLoader( - caf::kFARDET, Loaders::kMC, Loaders::kTau), - loaders.GetLoader( - caf::kFARDET, Loaders::kMC, Loaders::kNC), - numuDecomp, - axis, - fdcut, - ndcut, - shiftMC, - weight - ); - } - - //--------------------------------------------------------------------------- - /* - ModularExtrap ModularExtrap::Nue( - SpectrumLoaderBase& nearMC, - SpectrumLoaderBase& farMCswap, - SpectrumLoaderBase& farMCnonswap, - SpectrumLoaderBase& farMCtauswap, - const IDecomp& nueDecomp, - const IDecomp& numuDecomp, - const HistAxis& axis, - const HistAxis& axisNumuND, - const Cut& fdcut, - const Cut& nueNDcut, - const Cut& numuNDcut, - const SystShifts& shiftMC, - const Weight& weight - ){ - - ModularExtrap extrap( - farMCswap, - farMCnonswap, - farMCtauswap, - axis, - fdcut, - shiftMC, - weight - ); - - // mu -> mu ---- - extrap.fMMextrap = std::unique_ptr( - new RecoReweight( - nearMC, axis, fdcut, shiftMC, weight, - "mu -> mu", "#nu_{#mu} #rightarrow #nu_{#mu}", - nueNDcut, nueDecomp, // nue selection in ND - DecompResult::numu, kIsNumuCC && !kIsAntiNu, // numu truth in ND - farMCnonswap, kIsNumuCC && !kIsAntiNu // mu->mu in FD - ) - ); - - // mu -> e ---- - extrap.fMEextrap = std::unique_ptr( - new TruthReweight( - nearMC, axis, axisNumuND, fdcut, shiftMC, weight, - "mu -> e", "#nu_{#mu} #rightarrow #nu_{e}", - numuNDcut, numuDecomp, // numu selection in ND - DecompResult::numu, kIsNumuCC && !kIsAntiNu, // numu truth in ND - farMCswap, kIsSig && !kIsAntiNu // mu->e in FD - ) - ); - extrap.fMEAntiextrap = std::unique_ptr( - new TruthReweight( - nearMC, axis, axisNumuND, fdcut, shiftMC, weight, - "mubar -> ebar", "#bar{#nu}_{#mu} #rightarrow #bar{#nu}_{e}", - numuNDcut, numuDecomp, // numu selection in ND - DecompResult::numubar, kIsNumuCC && kIsAntiNu, // numubar truth in ND - farMCswap, kIsSig && kIsAntiNu // mubar->ebar in FD - ) - ); - - // NC -> NC ---- - extrap.fNCextrap = std::unique_ptr( - new RecoReweight( - nearMC, axis, fdcut, shiftMC, weight, - "NC -> NC", "NC #rightarrow NC", - nueNDcut, nueDecomp, // nue selection in ND - DecompResult::NC, kIsNC, // NC truth in ND - farMCswap, kIsNC, // NC->NC in FD - farMCnonswap, farMCtauswap // extra NC stats - ) - ); - - // e -> e ---- - extrap.fEEextrap = std::unique_ptr( - new RecoReweight( - nearMC, axis, fdcut, shiftMC, weight, - "e -> e", "#nu_{e} #rightarrow #nu_{e}", - nueNDcut, nueDecomp, // nue selection in ND - DecompResult::nue, kIsBeamNue && !kIsAntiNu, // nue truth in ND - farMCnonswap, kIsBeamNue && !kIsAntiNu // e->e in FD - ) - ); - - return extrap; - - } - */ - //--------------------------------------------------------------------------- - - ModularExtrap ModularExtrap::Numu( - SpectrumLoaderBase& nearMC, - SpectrumLoaderBase& farMCnonswap, - SpectrumLoaderBase& farMCnue, - SpectrumLoaderBase& farMCnutau, - SpectrumLoaderBase& farMCnc, - const IDecomp& numuDecomp, - const HistAxis& axis, - const Cut& fdcut, - const Cut& numuNDcut, - const SystShifts& shiftMC, - const Weight& weight - ){ - - ModularExtrap extrap( - farMCnonswap, - farMCnue, - farMCnutau, - farMCnc, - axis, - fdcut, - shiftMC, - weight - ); - - // mu -> mu ---- - extrap.fMMextrap = std::unique_ptr( - new TruthReweight( - nearMC, axis, axis, fdcut, shiftMC, weight, - "mu -> mu", "#nu_{#mu} #rightarrow #nu_{#mu}", - numuNDcut, numuDecomp, // numu selection in ND - DecompResult::numu, kIsNumuCC && !kIsAntiNu, // numu truth in ND - farMCnonswap, kIsNumuCC && !kIsAntiNu // mu->mu in FD - ) - ); - extrap.fMMAntiextrap = std::unique_ptr( - new TruthReweight( - nearMC, axis, axis, fdcut, shiftMC, weight, - "mubar -> mubar", "#bar{#nu}_{#mu} #rightarrow #bar{#nu}_{#mu}", - numuNDcut, numuDecomp, // numu selection in ND - DecompResult::numubar, kIsNumuCC && kIsAntiNu, // numubar truth in ND - farMCnonswap, kIsNumuCC && kIsAntiNu // mubar->mubar in FD - ) - ); - - return extrap; - } - - //--------------------------------------------------------------------------- - - void ModularExtrap::SaveTo(TDirectory* dir) const - { - - TDirectory* tmp = gDirectory; - dir->cd(); - TObjString("ModularExtrap").Write("type"); - - fEEextrap->SaveTo(dir->mkdir("EEextrap")); - fEMextrap->SaveTo(dir->mkdir("EMextrap")); - fMEextrap->SaveTo(dir->mkdir("MEextrap")); - fMMextrap->SaveTo(dir->mkdir("MMextrap")); - fEEAntiextrap->SaveTo(dir->mkdir("EEAntiextrap")); - fEMAntiextrap->SaveTo(dir->mkdir("EMAntiextrap")); - fMEAntiextrap->SaveTo(dir->mkdir("MEAntiextrap")); - fMMAntiextrap->SaveTo(dir->mkdir("MMAntiextrap")); - fMTextrap->SaveTo(dir->mkdir("MTextrap")); - fETextrap->SaveTo(dir->mkdir("ETextrap")); - fMTAntiextrap->SaveTo(dir->mkdir("MTAntiextrap")); - fETAntiextrap->SaveTo(dir->mkdir("ETAntiextrap")); - fNCextrap->SaveTo(dir->mkdir("NCextrap")); - - tmp->cd(); - - } - - //--------------------------------------------------------------------------- - - void ModularExtrap::SavePlotsNue( TDirectory* dir, double potFD ) const - { - TDirectory* tmp = gDirectory; - dir->cd(); - fMEextrap->SavePlots( dir->mkdir("MEextrap"), potFD ); - fMEAntiextrap->SavePlots( dir->mkdir("MEAntiextrap"), potFD ); - fEEextrap->SavePlots( dir->mkdir("EEextrap"), potFD ); - fMMextrap->SavePlots( dir->mkdir("MMextrap"), potFD ); - fNCextrap->SavePlots( dir->mkdir("NCextrap"), potFD ); - tmp->cd(); - } - - //--------------------------------------------------------------------------- - - void ModularExtrap::SavePlotsNumu( TDirectory* dir, double potFD ) const - { - TDirectory* tmp = gDirectory; - dir->cd(); - fMMextrap->SavePlots( dir->mkdir("MMextrap"), potFD ); - fMMAntiextrap->SavePlots( dir->mkdir("MMAntiextrap"), potFD ); - tmp->cd(); - } - - //--------------------------------------------------------------------------- - - std::unique_ptr ModularExtrap::LoadFrom(TDirectory* dir) - { - - std::unique_ptr ret(new ModularExtrap); - - assert(dir->GetDirectory("EEextrap")); - ret->fEEextrap = ana::LoadFrom( - dir->GetDirectory("EEextrap") ); - - assert(dir->GetDirectory("EMextrap")); - ret->fEMextrap = ana::LoadFrom( - dir->GetDirectory("EMextrap") ); - - assert(dir->GetDirectory("MEextrap")); - ret->fMEextrap = ana::LoadFrom( - dir->GetDirectory("MEextrap") ); - - assert(dir->GetDirectory("MMextrap")); - ret->fMMextrap = ana::LoadFrom( - dir->GetDirectory("MMextrap") ); - - assert(dir->GetDirectory("EEAntiextrap")); - ret->fEEAntiextrap = ana::LoadFrom( - dir->GetDirectory("EEAntiextrap") ); - - assert(dir->GetDirectory("EMAntiextrap")); - ret->fEMAntiextrap = ana::LoadFrom( - dir->GetDirectory("EMAntiextrap") ); - - assert(dir->GetDirectory("MEAntiextrap")); - ret->fMEAntiextrap = ana::LoadFrom( - dir->GetDirectory("MEAntiextrap") ); - - assert(dir->GetDirectory("MMAntiextrap")); - ret->fMMAntiextrap = ana::LoadFrom( - dir->GetDirectory("MMAntiextrap") ); - - assert(dir->GetDirectory("NCextrap")); - ret->fNCextrap = ana::LoadFrom( - dir->GetDirectory("NCextrap") ); - - assert(dir->GetDirectory("MTextrap")); - ret->fMTextrap = ana::LoadFrom( - dir->GetDirectory("MTextrap") ); - - assert(dir->GetDirectory("ETextrap")); - ret->fETextrap = ana::LoadFrom( - dir->GetDirectory("ETextrap") ); - - assert(dir->GetDirectory("MTAntiextrap")); - ret->fMTAntiextrap = ana::LoadFrom( - dir->GetDirectory("MTAntiextrap") ); - - assert(dir->GetDirectory("ETAntiextrap")); - ret->fETAntiextrap = ana::LoadFrom( - dir->GetDirectory("ETAntiextrap") ); - - return ret; - - } - - //--------------------------------------------------------------------------- - - ModularExtrap::ModularExtrap( - SpectrumLoaderBase& farMCnonswap, - SpectrumLoaderBase& farMCnue, - SpectrumLoaderBase& farMCnutau, - SpectrumLoaderBase& farMCnc, - const HistAxis& axis, - const Cut& fdcut, - const SystShifts& shiftMC, - const Weight& weight - ) : - - // e -> e ---- - fEEextrap( new NoReweight( - farMCnonswap, axis, fdcut, shiftMC, weight, kIsBeamNue && !kIsAntiNu)), - fEEAntiextrap( new NoReweight( - farMCnonswap, axis, fdcut, shiftMC, weight, kIsBeamNue && kIsAntiNu)), - - // mu -> mu ---- - fMMextrap( new NoReweight( - farMCnonswap, axis, fdcut, shiftMC, weight, kIsNumuCC && !kIsAntiNu)), - fMMAntiextrap( new NoReweight( - farMCnonswap, axis, fdcut, shiftMC, weight, kIsNumuCC && kIsAntiNu)), - - // mu -> e ---- - fMEextrap( new NoReweight( - farMCnue, axis, fdcut, shiftMC, weight, kIsSig && !kIsAntiNu)), - fMEAntiextrap( new NoReweight( - farMCnue, axis, fdcut, shiftMC, weight, kIsSig && kIsAntiNu)), - - // e -> mu ---- - fEMextrap( new NoReweight( - farMCnutau, axis, fdcut, shiftMC, weight, kIsNumuApp && !kIsAntiNu)), - fEMAntiextrap( new NoReweight( - farMCnutau, axis, fdcut, shiftMC, weight, kIsNumuApp && kIsAntiNu)), - - // NC -> NC ---- - fNCextrap( new NoReweight( - farMCnc, axis, fdcut, shiftMC, weight, kIsNC)), - - // mu -> tau ---- - fMTextrap( new NoReweight( - farMCnutau, axis, fdcut, shiftMC, weight, kIsTauFromMu && !kIsAntiNu)), - fMTAntiextrap( new NoReweight( - farMCnutau, axis, fdcut, shiftMC, weight, kIsTauFromMu && kIsAntiNu)), - - // e -> tau ---- - fETextrap( new NoReweight( - farMCnue, axis, fdcut, shiftMC, weight, kIsTauFromE && !kIsAntiNu)), - fETAntiextrap( new NoReweight( - farMCnue, axis, fdcut, shiftMC, weight, kIsTauFromE && kIsAntiNu)) - - {} - - //--------------------------------------------------------------------------- - - OscillatableSpectrum ModularExtrap::NueSurvComponent() - {return fEEextrap->Return();} - - OscillatableSpectrum ModularExtrap::AntiNueSurvComponent() - {return fEEAntiextrap->Return();} - - OscillatableSpectrum ModularExtrap::NumuSurvComponent() - {return fMMextrap->Return();} - - OscillatableSpectrum ModularExtrap::AntiNumuSurvComponent() - {return fMMAntiextrap->Return();} - - OscillatableSpectrum ModularExtrap::NueAppComponent() - {return fMEextrap->Return();} - - OscillatableSpectrum ModularExtrap::AntiNueAppComponent() - {return fMEAntiextrap->Return();} - - OscillatableSpectrum ModularExtrap::NumuAppComponent() - {return fEMextrap->Return();} - - OscillatableSpectrum ModularExtrap::AntiNumuAppComponent() - {return fEMAntiextrap->Return();} - - Spectrum ModularExtrap::NCComponent() - {return fNCextrap->Return().Unoscillated();} - - OscillatableSpectrum ModularExtrap::TauFromMuComponent() - {return fMTextrap->Return();} - - OscillatableSpectrum ModularExtrap::AntiTauFromMuComponent() - {return fMTAntiextrap->Return();} - - OscillatableSpectrum ModularExtrap::TauFromEComponent() - {return fETextrap->Return();} - - OscillatableSpectrum ModularExtrap::AntiTauFromEComponent() - {return fETAntiextrap->Return();} - -} - -#endif diff --git a/CAFAna/Extrap/ModularExtrap.h b/CAFAna/Extrap/ModularExtrap.h deleted file mode 100644 index dcdde528..00000000 --- a/CAFAna/Extrap/ModularExtrap.h +++ /dev/null @@ -1,166 +0,0 @@ -#if 0 -// Currently dead code - -#pragma once - -#include "CAFAna/Core/HistAxis.h" -#include "CAFAna/Extrap/IExtrap.h" -#include "CAFAna/Extrap/ModularExtrapComponent.h" -#include - -class TDirectory; - -namespace ana -{ - - class Loaders; - class SpectrumLoaderBase; - class IDecomp; - class OscillatableSpectrum; - - /// \brief Extrapolate each component using a separate ModularExtrapComponent - /// - /// Only extrapolates one sample. - class ModularExtrap: public IExtrap - { - public: - - // /// Creates a nue-like extraploation. - // /** numuDecomp and numuNDCut are for the signal component (mu->e). - // nueDecomp and nueNDCut are for the backgound components. */ - // static ModularExtrap Nue( - // Loaders& loaders, - // const IDecomp& nueDecomp, - // const IDecomp& numuDecomp, - // const HistAxis& axis, - // const HistAxis& axisNumuND, - // const Cut& fdcut, - // const Cut& nueNDcut, - // const Cut& numuNDcut, - // const SystShifts& shiftMC = kNoShift, - // const Weight& weight = kUnweighted - // ); - - /// Creates a numu-like extrapolation. - static ModularExtrap Numu( - Loaders& loaders, - const IDecomp& numuDecomp, - const HistAxis& axis, - const Cut& fdcut, - const Cut& ndcut, - const SystShifts& shiftMC = kNoShift, - const Weight& weight = kUnweighted - ); - - // /// Creates a nue-like extraploation with individual spectrum loaders. - // /** numuDecomp and numuNDCut are for the signal component (mu->e). - // nueDecomp and nueNDCut are for the backgound components. */ - // static ModularExtrap Nue( - // SpectrumLoaderBase& nearMCLoader, - // SpectrumLoaderBase& farMCswapLoader, - // SpectrumLoaderBase& farMCnonswapLoader, - // SpectrumLoaderBase& farMCtauswapLoader, - // const IDecomp& nueDecomp, - // const IDecomp& numuDecomp, - // const HistAxis& axis, - // const HistAxis& axisNumuND, - // const Cut& fdcut, - // const Cut& nueNDcut, - // const Cut& numuNDcut, - // const SystShifts& shiftMC = kNoShift, - // const Weight& weight = kUnweighted - // ); - - /// Creates a numu-like extrapolation with individual spectrum loaders. - static ModularExtrap Numu( - SpectrumLoaderBase& nearMCLoader, - SpectrumLoaderBase& farMCnonswapLoader, - SpectrumLoaderBase& farMCnueLoader, - SpectrumLoaderBase& farMCnutauLoader, - SpectrumLoaderBase& farMCncLoader, - const IDecomp& numuDecomp, - const HistAxis& axis, - const Cut& fdcut, - const Cut& ndcut, - const SystShifts& shiftMC = kNoShift, - const Weight& weight = kUnweighted - ); - - // Prevent copying because we own objects on the free store. - ModularExtrap(const ModularExtrap&) = delete; - ModularExtrap& operator=(const ModularExtrap&) = delete; - ModularExtrap(ModularExtrap&&) = default; - ModularExtrap& operator=(ModularExtrap&&) = default; - virtual ~ModularExtrap() = default; - - void SaveTo(TDirectory* dir) const override; - void SavePlotsNue( TDirectory* dir, double potFD ) const; - void SavePlotsNumu( TDirectory* dir, double potFD ) const; - static std::unique_ptr LoadFrom(TDirectory* dir); - - // Override abstract methods. - OscillatableSpectrum NueSurvComponent() override; - OscillatableSpectrum AntiNueSurvComponent() override; - OscillatableSpectrum NumuSurvComponent() override; - OscillatableSpectrum AntiNumuSurvComponent() override; - OscillatableSpectrum NueAppComponent() override; - OscillatableSpectrum AntiNueAppComponent() override; - OscillatableSpectrum NumuAppComponent() override; - OscillatableSpectrum AntiNumuAppComponent() override; - OscillatableSpectrum TauFromMuComponent() override; - OscillatableSpectrum AntiTauFromMuComponent() override; - OscillatableSpectrum TauFromEComponent() override; - OscillatableSpectrum AntiTauFromEComponent() override; - Spectrum NCComponent() override; - - std::vector GetModExtrapComponents() const - { - return { - fEEextrap.get(), fEEAntiextrap.get(), - fMMextrap.get(), fMMAntiextrap.get(), - fMEextrap.get(), fMEAntiextrap.get(), - fEMextrap.get(), fEMAntiextrap.get(), - fNCextrap.get(), - fMTextrap.get(), fMTAntiextrap.get(), - fETextrap.get(), fETAntiextrap.get()}; - } - - protected: - - /// Sets up all components to use FD MC--internal use only. - /** Use a named constructor (the static function Nue() or Numu()) to - create a ModularExtrap. This function is protected. */ - ModularExtrap( - SpectrumLoaderBase& farMCnonswapLoader, - SpectrumLoaderBase& farMCnueLoader, - SpectrumLoaderBase& farMCnutauLoader, - SpectrumLoaderBase& farMCncLoader, - const HistAxis& axis, - const Cut& fdcut, - const SystShifts& shiftMC, - const Weight& weight - ); - - std::unique_ptr fEEextrap; - std::unique_ptr fEEAntiextrap; - std::unique_ptr fMMextrap; - std::unique_ptr fMMAntiextrap; - std::unique_ptr fMEextrap; - std::unique_ptr fMEAntiextrap; - std::unique_ptr fEMextrap; - std::unique_ptr fEMAntiextrap; - std::unique_ptr fNCextrap; - std::unique_ptr fMTextrap; - std::unique_ptr fMTAntiextrap; - std::unique_ptr fETextrap; - std::unique_ptr fETAntiextrap; - - private: - - ModularExtrap(){}; - - }; - -} - -#endif diff --git a/CAFAna/Extrap/ModularExtrapComponent.cxx b/CAFAna/Extrap/ModularExtrapComponent.cxx deleted file mode 100644 index dc232389..00000000 --- a/CAFAna/Extrap/ModularExtrapComponent.cxx +++ /dev/null @@ -1,384 +0,0 @@ -#if 0 -// Currently dead code - -#include "CAFAna/Core/LoadFromFile.h" -#include "CAFAna/Extrap/ModularExtrapComponent.h" -#include "CAFAna/Core/SpectrumLoaderBase.h" -#include "CAFAna/Decomp/IDecomp.h" -#include "CAFAna/Core/Ratio.h" -#include "CAFAna/Core/Utilities.h" - -#include "TH1.h" -#include "TDirectory.h" -#include "TObjString.h" - -namespace ana -{ - //--------------------------------------------------------------------------- - // Definition to satisfy declaration in Core/LoadFromFile.h - template<> std::unique_ptr - LoadFrom(TDirectory* dir) - { - TObjString* ptag = (TObjString*)dir->Get("type"); - assert(ptag); - - const TString tag = ptag->GetString(); - - if(tag == "NoReweight") - return NoReweight::LoadFrom(dir); - if(tag == "TruthReweight") - return TruthReweight::LoadFrom(dir); - if(tag == "RecoReweight") - return RecoReweight::LoadFrom(dir); - - std::cerr << "Unknown Component Extrapolation type '" - << tag << "'" << std::endl; - abort(); - } - - //--------------------------------------------------------------------------- - - ModularExtrapComponent::DivByZeroCounter::~DivByZeroCounter() - { - if (fQuiet) - return; - - if (this->fBins.size() == 0) - return; - - std::cerr << "\nWARNING: There were attempted divisions by empty bins (for which a fallback to no reweighting was used)" - << "\n during extrapolation in the following bins (check your MC stats):" - << std::endl; - for (const auto & tuple : this->fBins) - { - std::cerr << " Channel: " << std::get<0>(tuple) - << " Location: " << std::get<1>(tuple) - << " Bin Center: " << std::get<2>(tuple) - << "\n" << std::endl; - } - - } - - //--------------------------------------------------------------------------- - - const OscillatableSpectrum& ModularExtrapComponent::Return() const - { - if (!fEvaluated) - { - fCache = Eval(); - fEvaluated = true; - } - return fCache; - } - - //--------------------------------------------------------------------------- - - Spectrum ModularExtrapComponent::GetDecompResult( - const IDecomp& decomp, - const DecompResult dr - ){ - switch (dr){ - case DecompResult::nue : return decomp.NueComponent(); - case DecompResult::numu : return decomp.NumuComponent(); - case DecompResult::nuebar : return decomp.AntiNueComponent(); - case DecompResult::numubar : return decomp.AntiNumuComponent(); - case DecompResult::NC : return decomp.NCComponent(); - } - assert( 0 && "Bad DecompResult" ); - } - - //--------------------------------------------------------------------------- - - std::string ModularExtrapComponent::DRToString( - const DecompResult dr - ){ - switch (dr){ - case DecompResult::nue : return "Nue"; - case DecompResult::numu : return "Numu"; - case DecompResult::nuebar : return "NueBar"; - case DecompResult::numubar : return "NumuBar"; - case DecompResult::NC : return "NC"; - } - assert( 0 && "Bad DecompResult" ); - } - - //--------------------------------------------------------------------------- - - DecompResult ModularExtrapComponent::StringToDR( - const std::string str - ){ - if (str=="Nue") return DecompResult::nue; - else if (str=="Numu") return DecompResult::numu; - else if (str=="NueBar") return DecompResult::nuebar; - else if (str=="NumuBar") return DecompResult::numubar; - else if (str=="NC") return DecompResult::NC; - else assert( 0 && "Bad DecompResult String" ); - } - - //--------------------------------------------------------------------------- - - Ratio ModularExtrapComponent::FormSmartRatio( - const Spectrum& num, - const Spectrum& denom, - const std::string component, - const std::string location, - const Spectrum& mult - ){ - - DontAddDirectory guard; - - // TODO do this with Eigen or possibly the Ratio class? - std::unique_ptr numh(num.ToTH1(1e20)); - std::unique_ptr denomh(denom.ToTH1(1e20)); - std::unique_ptr multh(mult.ToTH1(1e20)); - - std::unique_ptr ratioh((TH1D*)numh->Clone( UniqueName().c_str() )); - ratioh->Reset(); - - int nbins = numh->GetNbinsX(); - assert( (nbins == denomh->GetNbinsX()) && "Bin Mismatch" ); - assert( (nbins == multh->GetNbinsX()) && "Bin Mismatch" ); - - static DivByZeroCounter counter; - for (int bin(0); bin<=nbins+1; ++bin) - { - if ( denomh->GetBinContent(bin) != 0 ){ - ratioh->SetBinContent( bin, numh->GetBinContent(bin) - / denomh->GetBinContent(bin) ); - } else { - ratioh->SetBinContent( bin, 1. ); - if ( numh->GetBinContent(bin) != 0 - || multh->GetBinContent(bin) != 0 ) - counter.fBins.insert(std::make_tuple(component, location, denomh->GetBinCenter(bin))); - } - } - - return Ratio( ratioh.get() ); - } - - bool ModularExtrapComponent::fQuiet = false; - - //--------------------------------------------------------------------------- - - NoReweight::NoReweight( - SpectrumLoaderBase& loader, - const HistAxis& axis, - const Cut& fdcut, - const SystShifts& shiftMC, - const Weight& weight, - const Cut& flavors ) - : fRecoFD( loader, axis, fdcut && flavors, shiftMC, weight ) - { - } - - OscillatableSpectrum NoReweight::Eval() const - {return fRecoFD;} - - void NoReweight::SaveTo(TDirectory* dir) const - { - TDirectory* tmp = gDirectory; - dir->cd(); - TObjString("NoReweight").Write("type"); - fRecoFD.SaveTo(dir->mkdir("RecoFD")); - tmp->cd(); - } - - std::unique_ptr - NoReweight::LoadFrom(TDirectory* dir) - { - assert(dir->GetDirectory("RecoFD")); - return std::unique_ptr(new NoReweight( - *(OscillatableSpectrum::LoadFrom(dir->GetDirectory("RecoFD")).release()) - )); - } - - //--------------------------------------------------------------------------- - - TruthReweight::TruthReweight( - SpectrumLoaderBase& ndloader, - const HistAxis& axisFD, - const HistAxis& axisND, - const Cut& fdcut, - const SystShifts& shiftMC, - const Weight& weight, - std::string label, - std::string latex, - const Cut& ndcut, - const IDecomp& decomposition, - const DecompResult dr, - const Cut& ndflavor, - SpectrumLoaderBase& fdloader, - const Cut& fdflavors - ) - : fRecoToTrueND(ndloader, axisND, ndcut && ndflavor, shiftMC, weight), - fTrueToRecoFD(fdloader, axisFD, fdcut && fdflavors, shiftMC, weight), - fDecomp(decomposition), - fDecompRes(dr), - fLabel(label), - fLatex(latex) - {} - - OscillatableSpectrum TruthReweight::Eval() const - { - - //Copy to local variables because reweighting is in-place - OscillatableSpectrum recoToTrueND(fRecoToTrueND); - OscillatableSpectrum trueToRecoFD(fTrueToRecoFD); - - //Get ND data from Decomp - Spectrum decompresult(GetDecompResult(fDecomp,fDecompRes)); - - //Compute Data/MC Ratio in reco energy bins to get divide-by-zero warnings - FormSmartRatio( - decompresult, fRecoToTrueND.Unoscillated(), - fLabel, "MC ND Reco", - fRecoToTrueND.Unoscillated() ); - - //ND Reco->True - recoToTrueND.ReweightToRecoSpectrum( decompresult ); - - //Compute Data/MC Ratio in true energy bins - Ratio dataMCtrue = FormSmartRatio( - recoToTrueND.TrueEnergy(), fRecoToTrueND.TrueEnergy(), - fLabel, "MC ND Truth", - fTrueToRecoFD.TrueEnergy() ); - - // Multiply by Data/MC Ratio and add in FD truth information - trueToRecoFD.ReweightToTrueSpectrum( fTrueToRecoFD.TrueEnergy() - * dataMCtrue ); - - return trueToRecoFD; - - } - - void TruthReweight::SaveTo(TDirectory* dir) const - { - TDirectory* tmp = gDirectory; - dir->cd(); - TObjString("TruthReweight").Write("type"); - fRecoToTrueND.SaveTo(dir->mkdir("RecoToTrueND")); - fTrueToRecoFD.SaveTo(dir->mkdir("TrueToRecoFD")); - fDecomp.SaveTo(dir->mkdir("Decomp")); - TObjString(DRToString(fDecompRes).c_str()).Write("DecompRes"); - TObjString(fLabel.c_str()).Write("Label"); - TObjString(fLatex.c_str()).Write("Latex"); - tmp->cd(); - } - - std::unique_ptr - TruthReweight::LoadFrom(TDirectory* dir) - { - - assert(dir->GetDirectory("RecoToTrueND")); - assert(dir->GetDirectory("TrueToRecoFD")); - assert(dir->GetDirectory("Decomp")); - TObjString* dr = (TObjString*)dir->Get("DecompRes"); - assert(dr); - TObjString* label = (TObjString*)dir->Get("Label"); - TObjString* latex = (TObjString*)dir->Get("Latex"); - assert(label); - assert(latex); - - return std::unique_ptr(new TruthReweight( - *(OscillatableSpectrum::LoadFrom(dir->GetDirectory("RecoToTrueND"))), - *(OscillatableSpectrum::LoadFrom(dir->GetDirectory("TrueToRecoFD"))), - *(ana::LoadFrom( - dir->GetDirectory("Decomp")).release()), //leaks! - StringToDR(dr->GetString().Data()), - label->GetString().Data(), - latex->GetString().Data() - )); - - } - - //--------------------------------------------------------------------------- - - RecoReweight::RecoReweight( - SpectrumLoaderBase& ndloader, - const HistAxis& axis, - const Cut& fdcut, - const SystShifts& shiftMC, - const Weight& weight, - std::string label, - std::string latex, - const Cut& ndcut, - const IDecomp& decomposition, - const DecompResult dr, - const Cut& ndflavor, - SpectrumLoaderBase& fdloader, - const Cut& fdflavors - ) - : fRecoND(ndloader, axis, ndcut && ndflavor, shiftMC, weight), - fTrueToRecoFD(fdloader, axis, fdcut && fdflavors, shiftMC, weight), - fDecomp(&decomposition), - fDecompRes(dr), - fLabel(label), - fLatex(latex) - { - } - - OscillatableSpectrum RecoReweight::Eval() const - { - - //Copy to local variable because reweighting is in-place - OscillatableSpectrum result(fTrueToRecoFD); - - //Get ND data from Decomp - Spectrum decompresult(GetDecompResult(*fDecomp,fDecompRes)); - - //Compute Data/MC Ratio - Ratio dataMC = FormSmartRatio( - decompresult, fRecoND, - fLabel, "MC ND Reco", - fTrueToRecoFD.Unoscillated() ); - - // Multiply by Data/MC Ratio and add in FD truth information - result.ReweightToRecoSpectrum( fTrueToRecoFD.Unoscillated() * dataMC ); - - return result; - - } - - void RecoReweight::SaveTo(TDirectory* dir) const - { - TDirectory* tmp = gDirectory; - dir->cd(); - TObjString("RecoReweight").Write("type"); - fRecoND.SaveTo(dir->mkdir("RecoND")); - fTrueToRecoFD.SaveTo(dir->mkdir("TrueToRecoFD")); - fDecomp->SaveTo(dir->mkdir("Decomp")); - TObjString(DRToString(fDecompRes).c_str()).Write("DecompRes"); - TObjString(fLabel.c_str()).Write("Label"); - TObjString(fLatex.c_str()).Write("Latex"); - tmp->cd(); - } - - std::unique_ptr - RecoReweight::LoadFrom(TDirectory* dir) - { - - assert(dir->GetDirectory("RecoND")); - assert(dir->GetDirectory("TrueToRecoFD")); - assert(dir->GetDirectory("Decomp")); - TObjString* dr = (TObjString*)dir->Get("DecompRes"); - assert(dr); - TObjString* label = (TObjString*)dir->Get("Label"); - TObjString* latex = (TObjString*)dir->Get("Latex"); - assert(label); - assert(latex); - - return std::unique_ptr(new RecoReweight( - *(Spectrum::LoadFrom(dir->GetDirectory("RecoND"))), - *(OscillatableSpectrum::LoadFrom(dir->GetDirectory("TrueToRecoFD"))), - *(ana::LoadFrom( - dir->GetDirectory("Decomp")).release()), //leaks! - StringToDR(dr->GetString().Data()), - label->GetString().Data(), - latex->GetString().Data() - )); - - } - -} - -#endif diff --git a/CAFAna/Extrap/ModularExtrapComponent.h b/CAFAna/Extrap/ModularExtrapComponent.h deleted file mode 100644 index ddedcb29..00000000 --- a/CAFAna/Extrap/ModularExtrapComponent.h +++ /dev/null @@ -1,230 +0,0 @@ -#if 0 -// Currently dead code - -#pragma once - -#include "CAFAna/Core/HistAxis.h" -#include "CAFAna/Core/OscillatableSpectrum.h" -#include "CAFAna/Core/Ratio.h" -#include "CAFAna/Core/SpectrumLoaderBase.h" - -class TDirectory; -class TH1; - -namespace ana -{ - - class IDecomp; - - /// Simple way to remember what to ask the decomposition for. - enum class DecompResult {nue, numu, NC, nuebar, numubar}; - - /// Base class for component extrapolation. - class ModularExtrapComponent - { - public: - - ModularExtrapComponent() : fEvaluated(false), fCache(nullptr, {}, {}, 0, 0) {} - virtual ~ModularExtrapComponent() {}; - virtual void SaveTo(TDirectory* dir) const = 0; - virtual void SavePlots(TDirectory* dir, double potFD) const = 0; - static void SetQuiet(bool quiet = true){ fQuiet = quiet; } - - /// Interface so that result of Eval() is called only once and cached. - const OscillatableSpectrum& Return() const; - - virtual const IDecomp* GetDecomp() const = 0; - - protected: - - /// Core extrapolation math. - virtual OscillatableSpectrum Eval() const = 0; - - /// Helper function to pick out single Spectrum from a decomposition. - static Spectrum GetDecompResult(const IDecomp&, DecompResult); - - /// Helper function to turn a DecompResult into a string (for storage). - static std::string DRToString(DecompResult); - - /// Helper function to turn a string into a DecompResult (for loading). - static DecompResult StringToDR(std::string); - - /// Form Ratio, but be aware of zero division. - /** Necessary because root thinks n/0==0, so we lose events when - low stats cause empty bins. If zero division occurs, ratio is set to - 1 and warning is issued. If numerator is 0 and ratio will be - multiplied by 0 later, the warning is suppressed. */ - static Ratio FormSmartRatio( - const Spectrum& num, - const Spectrum& denom, - std::string component, - std::string location, - const Spectrum& mult - ); - - static void ComparisonPlot( - Spectrum mc, - Spectrum notMC, - double pot, - std::string notMCLabel, - int notMCColor, - std::string latex, - std::string title, - std::string saveAs, - bool restrictRange = false - ); - - private: - mutable bool fEvaluated; - mutable OscillatableSpectrum fCache; - static bool fQuiet; - - class DivByZeroCounter - { - public: - DivByZeroCounter(bool quiet = false) - : fQuiet(quiet) - {} - ~DivByZeroCounter(); - - std::set> fBins; - - private: - bool fQuiet; - - }; - - }; - - /// "Extrapolates" component by returning FD Monte Carlo. - class NoReweight: public ModularExtrapComponent - { - - public: - NoReweight( - SpectrumLoaderBase& loader, - const HistAxis& axis, - const Cut& fdcut, - const SystShifts& shiftMC, - const Weight& weight, - const Cut& flavors - ); - OscillatableSpectrum Eval() const override; - void SaveTo(TDirectory* dir) const override; - void SavePlots(TDirectory* dir, double potFD) const override; - static std::unique_ptr LoadFrom(TDirectory* dir); - - const IDecomp* GetDecomp() const override {return 0;} - private: - NoReweight(OscillatableSpectrum recoFD) : fRecoFD(recoFD) {} - - OscillatableSpectrum fRecoFD; - - }; - - /// Extrapolates component using truth-over-truth method. - class TruthReweight: public ModularExtrapComponent - { - - public: - TruthReweight( - SpectrumLoaderBase& ndloader, - const HistAxis& axisFD, - const HistAxis& axisND, - const Cut& fdcut, - const SystShifts& shiftMC, - const Weight& weight, - std::string label, - std::string latex, - const Cut& ndcut, - const IDecomp& decomposition, - const DecompResult dr, - const Cut& ndflavor, - SpectrumLoaderBase& fdloader, - const Cut& fdflavors - ); - OscillatableSpectrum Eval() const override; - void SaveTo(TDirectory* dir) const override; - void SavePlots(TDirectory* dir, double potFD) const override; - static std::unique_ptr LoadFrom(TDirectory* dir); - - const IDecomp* GetDecomp() const override {return &fDecomp;} - private: - TruthReweight( - OscillatableSpectrum recoToTrueND, - OscillatableSpectrum trueToRecoFD, - const IDecomp& decomp, - const DecompResult decompRes, - std::string label, - std::string latex - ) : fRecoToTrueND(recoToTrueND), fTrueToRecoFD(trueToRecoFD), - fDecomp(decomp), fDecompRes(decompRes), - fLabel(label), fLatex(latex) {} - - OscillatableSpectrum fRecoToTrueND; - OscillatableSpectrum fTrueToRecoFD; - const IDecomp& fDecomp; - const DecompResult fDecompRes; - std::string fLabel; - std::string fLatex; - - }; - - /// Extrapolates using reco-over-reco method. - class RecoReweight: public ModularExtrapComponent - { - - public: - RecoReweight( - SpectrumLoaderBase& ndloader, - const HistAxis& axis, - const Cut& fdcut, - const SystShifts& shiftMC, - const Weight& weight, - std::string label, - std::string latex, - const Cut& ndcut, - const IDecomp& decomposition, - const DecompResult dr, - const Cut& ndflavor, - SpectrumLoaderBase& fdloader, - const Cut& fdflavors - ); - OscillatableSpectrum Eval() const override; - void SaveTo(TDirectory* dir) const override; - void SavePlots(TDirectory* dir, double potFD) const override; - static std::unique_ptr LoadFrom(TDirectory* dir); - - /// Uses MC spectra and target MC stats to estimate optimal binning. - TH1* OptimalBinning( double potMCFD, double potMCND ) const; - /// Fits gaussians to FD and ND MC to estimate optimal binning - TH1* OptimalBinningFit( double potMCFD, double potMCND ) const; - static TH1* OptimalBinningHelper( TH1*, TH1* ); - - const IDecomp* GetDecomp() const override {return fDecomp;} - - friend class ModularExtrap; - private: - RecoReweight( - Spectrum recoND, - OscillatableSpectrum trueToRecoFD, - const IDecomp& decomp, - const DecompResult decompRes, - std::string label, - std::string latex - ) : fRecoND(recoND), fTrueToRecoFD(trueToRecoFD), - fDecomp(&decomp), fDecompRes(decompRes), - fLabel(label), fLatex(latex) {} - - Spectrum fRecoND; - OscillatableSpectrum fTrueToRecoFD; - const IDecomp* fDecomp; - const DecompResult fDecompRes; - std::string fLabel; - std::string fLatex; - - }; - -} - -#endif diff --git a/CAFAna/Extrap/ModularExtrapComponentPlot.cxx b/CAFAna/Extrap/ModularExtrapComponentPlot.cxx deleted file mode 100644 index 2e2ba453..00000000 --- a/CAFAna/Extrap/ModularExtrapComponentPlot.cxx +++ /dev/null @@ -1,329 +0,0 @@ -#if 0 -// Currently dead code - -#include "CAFAna/Extrap/ModularExtrapComponent.h" -#include "CAFAna/Core/Ratio.h" -#include "CAFAna/Core/Utilities.h" - -#include "TCanvas.h" -#include "TDirectory.h" -#include "TLegend.h" -#include "TF1.h" -#include "TH1.h" -#include "TH2.h" - -namespace ana -{ - - //--------------------------------------------------------------------------- - - void ModularExtrapComponent::ComparisonPlot( - Spectrum mc, - Spectrum notMC, - double pot, - std::string notMCLabel, - int notMCColor, - std::string latex, - std::string title, - std::string saveAs, - bool restrictRange - ){ - TH1* histMC( mc.ToTH1(pot) ); - TH1* histNotMC( notMC.ToTH1(pot) ); - histMC->SetLineColor( kRed ); - histNotMC->SetLineColor( notMCColor ); - TCanvas c; - histMC->SetMaximum( 1.5 * histMC->GetMaximum() ); - if (restrictRange) histMC->GetXaxis()->SetRangeUser( 0.5, 3.5); - histMC->SetTitle( (latex+" "+title).c_str() ); - histMC->Draw("hist"); - histNotMC->Draw("same"); - TLegend legend( .15, .7, .4, .85 ); - legend.SetTextSize(0.05); - legend.AddEntry( histNotMC, notMCLabel.c_str() ); - legend.AddEntry( histMC, "MC" ); - legend.SetFillStyle(0); - legend.Draw(); - c.Write( saveAs.c_str() ); - delete histMC; - delete histNotMC; - } - - //--------------------------------------------------------------------------- - - void NoReweight::SavePlots(TDirectory* dir, double potFD) const - { - TDirectory* tmp = gDirectory; - dir->cd(); - - TH1* hist( fRecoFD.Unoscillated().ToTH1(potFD) ); - hist->SetLineColor( kRed ); - TCanvas c; - hist->SetMaximum( 1.5 * hist->GetMaximum() ); - hist->SetTitle( "FD Reco Spectrum" ); - hist->Draw("hist"); - c.Write("MC"); - delete hist; - - tmp->cd(); - } - - //--------------------------------------------------------------------------- - - void TruthReweight::SavePlots(TDirectory* dir, double potFD) const - { - TDirectory* tmp = gDirectory; - dir->cd(); - - Spectrum decompresult( GetDecompResult(fDecomp,fDecompRes) ); - double potND( decompresult.POT() ); - - ComparisonPlot( - fRecoToTrueND.Unoscillated(), decompresult, potND, - "Data", kBlack, fLatex, "ND Reco Spectrum", "NDReco" ); - - TH2* histNDrtt( fRecoToTrueND.ToTH2(potND) ); - TCanvas cNDrtt; - histNDrtt->GetYaxis()->SetRangeUser( 0.5, 3.5 ); - histNDrtt->SetTitle( (fLatex+" ND Reco to True Spectrum (MC)").c_str() ); - histNDrtt->Draw("colz"); - cNDrtt.Write("NDRecoToTrue"); - delete histNDrtt; - - OscillatableSpectrum recoToTrueND( fRecoToTrueND ); - recoToTrueND.ReweightToRecoSpectrum( decompresult ); - ComparisonPlot( - fRecoToTrueND.TrueEnergy(), recoToTrueND.TrueEnergy(), potND, - "Reweighted", kBlue, fLatex, "ND True Energy Spectrum", "NDTrue", - true ); - - ComparisonPlot( - fTrueToRecoFD.TrueEnergy(), Return().TrueEnergy(), potFD, - "Extrapolated", kBlue, fLatex, "FD True Energy Spectrum", "FDTrue", - true ); - - TH2* histFDttr( fTrueToRecoFD.ToTH2(potFD) ); - TCanvas cFDttr; - histFDttr->GetYaxis()->SetRangeUser( 0.5, 3.5 ); - histFDttr->SetTitle( (fLatex+" FD True To Reco Spectrum (MC)").c_str() ); - histFDttr->Draw("colz"); - cFDttr.Write("FDTrueToReco"); - delete histFDttr; - - ComparisonPlot( - fTrueToRecoFD.Unoscillated(), Return().Unoscillated(), potFD, - "Extrapolated", kBlue, fLatex, "FD Reco Spectrum", "FDReco" ); - - TH1* histNDDatReco = decompresult.ToTH1(potND); - TH1* histNDRwtTrue = recoToTrueND.TrueEnergy().ToTH1(potND); - TH1* histFDExtTrue = Return().TrueEnergy().ToTH1(potFD); - TH1* histFDExtReco = Return().Unoscillated().ToTH1(potFD); - - TH1* histNDMCReco = fRecoToTrueND.Unoscillated().ToTH1(potND); - TH1* histNDMCTrue = fRecoToTrueND.TrueEnergy().ToTH1(potND); - TH1* histFDMCTrue = fTrueToRecoFD.TrueEnergy().ToTH1(potFD); - TH1* histFDMCReco = fTrueToRecoFD.Unoscillated().ToTH1(potFD); - - histNDDatReco->Write("NDDatReco"); - histNDRwtTrue->Write("NDRwtTrue"); - histFDExtTrue->Write("FDExtTrue"); - histFDExtReco->Write("FDExtReco"); - - histNDMCReco->Write("NDMCReco"); - histNDMCTrue->Write("NDMCTrue"); - histFDMCTrue->Write("FDMCTrue"); - histFDMCReco->Write("FDMCReco"); - - delete histNDDatReco; - delete histNDRwtTrue; - delete histFDExtTrue; - delete histFDExtReco; - - delete histNDMCReco; - delete histNDMCTrue; - delete histFDMCTrue; - delete histFDMCReco; - - tmp->cd(); - } - - //--------------------------------------------------------------------------- - - void RecoReweight::SavePlots(TDirectory* dir, double potFD) const - { - TDirectory* tmp = gDirectory; - dir->cd(); - - Spectrum fdMCReco( fTrueToRecoFD.Unoscillated() ); - Spectrum fdExtReco( Return().Unoscillated() ); - - Spectrum decompresult( GetDecompResult(*fDecomp,fDecompRes) ); - double potND( decompresult.POT() ); - - ComparisonPlot( - fRecoND, decompresult, potND, - "Data", kBlack, fLatex, "ND Reco Spectrum", "ND" ); - - ComparisonPlot( - fdMCReco, fdExtReco, potFD, - "Extrapolated", kBlue, fLatex, "FD Reco Spectrum", "FD" ); - - TH1* histDvMCND( (decompresult/fRecoND).ToTH1() ); - TH1* histEvMCFD( (fdExtReco / fdMCReco).ToTH1() ); - histDvMCND->SetLineColor( kRed ); - histEvMCFD->SetLineColor( kBlue ); - histEvMCFD->SetLineWidth( 4 ); - histEvMCFD->SetLineStyle( 2 ); - TCanvas cDvMC; - histDvMCND->SetMaximum( 1.5 * histDvMCND->GetMaximum() ); - histDvMCND->SetTitle( (fLatex+" Data/MC Ratio").c_str() ); - histDvMCND->GetYaxis()->SetTitle("Ratio"); - histDvMCND->Draw("hist"); - histEvMCFD->Draw("same""hist"); - TLegend legendDvMC( .15, .7, .4, .85 ); - legendDvMC.SetTextSize(0.05); - legendDvMC.AddEntry( histEvMCFD, "FD (Extrapolated)" ); - legendDvMC.AddEntry( histDvMCND, "ND" ); - legendDvMC.SetFillStyle(0); - legendDvMC.Draw(); - cDvMC.Write("DataOverMC"); - delete histDvMCND; - delete histEvMCFD; - - TH1* histFoNMC( (fdMCReco/fRecoND).ToTH1() ); - TH1* histFoNDE( (fdExtReco/decompresult).ToTH1() ); - histFoNMC->SetLineColor( kRed ); - histFoNDE->SetLineColor( kBlue ); - histFoNDE->SetLineWidth( 4 ); - histFoNDE->SetLineStyle( 2 ); - TCanvas cFoN; - histFoNMC->SetMaximum( 1.5 * histFoNMC->GetMaximum() ); - histFoNMC->SetTitle( (fLatex+" Far/Near Ratio").c_str() ); - histFoNMC->GetYaxis()->SetTitle("Ratio"); - histFoNMC->Draw("hist"); - histFoNDE->Draw("same""hist"); - TLegend legendFoN( .15, .7, .4, .85 ); - legendFoN.SetTextSize(0.05); - legendFoN.AddEntry( histFoNDE, "Extrapolation/Data" ); - legendFoN.AddEntry( histFoNMC, "MC" ); - legendFoN.SetFillStyle(0); - legendFoN.Draw(); - cFoN.Write("FarOverNear"); - delete histFoNMC; - delete histFoNDE; - - TH1* histNDDat = decompresult.ToTH1(potND); - TH1* histFDExt = fdExtReco.ToTH1(potFD); - TH1* histNDMC = fRecoND.ToTH1(potND); - TH1* histFDMC = fdMCReco.ToTH1(potFD); - - histNDDat->Write("NDDat"); - histFDExt->Write("FDExt"); - histNDMC->Write("NDMC"); - histFDMC->Write("FDMC"); - - delete histNDDat; - delete histFDExt; - delete histNDMC; - delete histFDMC; - - tmp->cd(); - } - - //--------------------------------------------------------------------------- - - TH1* RecoReweight::OptimalBinning( - double potMCFD, - double potMCND - ) const { - - TH1* fd = fTrueToRecoFD.Unoscillated().ToTH1(potMCFD); - TH1* nd = fRecoND.ToTH1(potMCND); - - TH1* ob = OptimalBinningHelper( fd, nd ); - - delete fd; - delete nd; - - return ob; - - } - - //--------------------------------------------------------------------------- - - TH1* RecoReweight::OptimalBinningFit( - double potMCFD, - double potMCND - ) const { - - TH1* fd = fTrueToRecoFD.Unoscillated().ToTH1(potMCFD); - TH1* nd = fRecoND.ToTH1(potMCND); - - const double lower( fd->GetXaxis()->GetXmin() ); - const double upper( fd->GetXaxis()->GetXmax() ); - - TF1* fdGauss = new TF1( UniqueName().c_str() ,"gaus(0)", lower, upper ); - TF1* ndGauss = new TF1( UniqueName().c_str() ,"gaus(0)", lower, upper ); - - fdGauss->SetParameters( 100., 2., .5 ); - ndGauss->SetParameters( 100., 2., .5 ); - - fd->Fit( fdGauss, "WW" ); - nd->Fit( ndGauss, "WW" ); - - TH1* fdFine = new TH1D(UniqueName().c_str(),"fdFine",100,lower,upper); - TH1* ndFine = new TH1D(UniqueName().c_str(),"ndFine",100,lower,upper); - - fdFine->Eval(fdGauss); - ndFine->Eval(ndGauss); - - const double binScale = fdFine->GetBinWidth(1) / fd->GetBinWidth(1); - - fdFine->Scale(binScale); - ndFine->Scale(binScale); - - TH1* ob(OptimalBinningHelper(fdFine,ndFine)); - - delete fd; - delete nd; - - return ob; - - } - - //--------------------------------------------------------------------------- - - TH1* RecoReweight::OptimalBinningHelper( TH1* fd, TH1* nd) - { - - TH1* ob( (TH1*)fd->Clone() ); - - int nbins = fd->GetNbinsX(); - assert( (nbins == nd->GetNbinsX()) && "Bin Mismatch" ); - - for (int bin(1); bin<=nbins; ++bin) - { - double invdensFD( fd->GetBinWidth(bin) / fd->GetBinContent(bin) ); - double invdensND( nd->GetBinWidth(bin) / nd->GetBinContent(bin) ); - double ratio( fd->GetBinContent(bin) / nd->GetBinContent(bin) ); - double ratioPrev( fd->GetBinContent(bin-1) / nd->GetBinContent(bin-1) ); - double ratioNext( fd->GetBinContent(bin+1) / nd->GetBinContent(bin+1) ); - double deltaRatio( ratioNext - ratioPrev ); - double deltaVar( fd->GetBinCenter(bin+1) - fd->GetBinCenter(bin-1) ); - double invslope( deltaVar / deltaRatio ); - double widthCubed( 6. * ( ratio*ratio * invslope*invslope ) - * ( invdensFD + invdensND ) ); - double optbin( pow(widthCubed, 1./3.) ); - if ( std::isfinite(optbin) ) ob->SetBinContent( bin, optbin ); - else ob->SetBinContent( bin, 0. ); - } - ob->SetBinContent( 0, 0. ); - ob->SetBinContent( nbins+1, 0. ); - - return ob; - - } - -} - -#endif diff --git a/CAFAna/Extrap/TrivialExtrap.cxx b/CAFAna/Extrap/TrivialExtrap.cxx index 37237d25..39b6131e 100644 --- a/CAFAna/Extrap/TrivialExtrap.cxx +++ b/CAFAna/Extrap/TrivialExtrap.cxx @@ -14,87 +14,51 @@ namespace ana REGISTER_LOADFROM("TrivialExtrap", IExtrap, TrivialExtrap); //---------------------------------------------------------------------- - TrivialExtrap::TrivialExtrap(SpectrumLoaderBase& loaderNonswap, - SpectrumLoaderBase& loaderNue, - SpectrumLoaderBase& loaderNuTau, - const HistAxis& axis, - const Cut& cut, - const SystShifts& shift, - const Weight& wei) + TrivialExtrap::TrivialExtrap(IInteractionSource& nonswapSrc, + IInteractionSource& nueSrc, + IInteractionSource& tauSrc, + const HistAxis& axis) : - fNueApp (loaderNue, axis, cut && kIsSig && !kIsAntiNu, shift, wei), - fNueAppAnti (loaderNue, axis, cut && kIsSig && kIsAntiNu, shift, wei), - - fNumuSurv (loaderNonswap, axis, cut && kIsNumuCC && !kIsAntiNu, shift, wei), - fNumuSurvAnti (loaderNonswap, axis, cut && kIsNumuCC && kIsAntiNu, shift, wei), - - fNumuApp (loaderNuTau, axis, cut && kIsNumuApp && !kIsAntiNu, shift, wei), - fNumuAppAnti (loaderNuTau, axis, cut && kIsNumuApp && kIsAntiNu, shift, wei), - - fNueSurv (loaderNonswap, axis, cut && kIsBeamNue && !kIsAntiNu, shift, wei), - fNueSurvAnti (loaderNonswap, axis, cut && kIsBeamNue && kIsAntiNu, shift, wei), - - fTauFromE (loaderNue, axis, cut && kIsTauFromE && !kIsAntiNu, shift, wei), - fTauFromEAnti (loaderNue, axis, cut && kIsTauFromE && kIsAntiNu, shift, wei), - - fTauFromMu (loaderNuTau, axis, cut && kIsTauFromMu && !kIsAntiNu, shift, wei), - fTauFromMuAnti(loaderNuTau, axis, cut && kIsTauFromMu && kIsAntiNu, shift, wei), - - fNCTot (loaderNonswap, axis, cut && kIsNC , shift, wei), - fNC (loaderNonswap, axis, cut && kIsNC && !kIsAntiNu, shift, wei), - fNCAnti (loaderNonswap, axis, cut && kIsNC && kIsAntiNu, shift, wei) + fNueApp (nueSrc [kIsNueApp && !kIsAntiNu], axis), + fNueAppAnti (nueSrc [kIsNueApp && kIsAntiNu], axis), + fNumuSurv (nonswapSrc[kIsNumuCC && !kIsAntiNu], axis), + fNumuSurvAnti (nonswapSrc[kIsNumuCC && kIsAntiNu], axis), + fNumuApp (tauSrc [kIsNumuApp && !kIsAntiNu], axis), + fNumuAppAnti (tauSrc [kIsNumuApp && kIsAntiNu], axis), + fNueSurv (nonswapSrc[kIsBeamNue && !kIsAntiNu], axis), + fNueSurvAnti (nonswapSrc[kIsBeamNue && kIsAntiNu], axis), + fTauFromE (nueSrc [kIsTauFromE && !kIsAntiNu], axis), + fTauFromEAnti (nueSrc [kIsTauFromE && kIsAntiNu], axis), + fTauFromMu (tauSrc [kIsTauFromMu && !kIsAntiNu], axis), + fTauFromMuAnti(tauSrc [kIsTauFromMu && kIsAntiNu], axis), + fNCTot (nonswapSrc[kIsNC ], axis), + fNC (nonswapSrc[kIsNC && !kIsAntiNu], axis), + fNCAnti (nonswapSrc[kIsNC && kIsAntiNu], axis) { // All swapped files are equally valid as a source of NCs. This // approximately doubles/triples our statistics. SpectrumLoader just adds // events and POT for both cases, which is the right thing to do. - loaderNue .AddSpectrum(fNCTot , axis.GetVar1D(), cut && kIsNC , shift, wei); - loaderNue .AddSpectrum(fNC , axis.GetVar1D(), cut && kIsNC && !kIsAntiNu, shift, wei); - loaderNue .AddSpectrum(fNCAnti, axis.GetVar1D(), cut && kIsNC && kIsAntiNu, shift, wei); - loaderNuTau.AddSpectrum(fNCTot , axis.GetVar1D(), cut && kIsNC , shift, wei); - loaderNuTau.AddSpectrum(fNC , axis.GetVar1D(), cut && kIsNC && !kIsAntiNu, shift, wei); - loaderNuTau.AddSpectrum(fNCAnti, axis.GetVar1D(), cut && kIsNC && kIsAntiNu, shift, wei); - } + nueSrc[kIsNC].GetVar(axis.GetVar1D()).Register(&fNCTot); + nueSrc[kIsNC && !kIsAntiNu].GetVar(axis.GetVar1D()).Register(&fNC); + nueSrc[kIsNC && kIsAntiNu].GetVar(axis.GetVar1D()).Register(&fNCAnti); - //---------------------------------------------------------------------- - TrivialExtrap::TrivialExtrap(SpectrumLoaderBase& loaderNonswap, - SpectrumLoaderBase& loaderNue, - SpectrumLoaderBase& loaderNuTau, - std::string label, - const Binning& bins, - const Var& var, - const Cut& cut, - const SystShifts& shift, - const Weight& wei) - : - TrivialExtrap(loaderNonswap, loaderNue, loaderNuTau, - HistAxis(label, bins, var), - cut, shift, wei) - { - } - - //---------------------------------------------------------------------- - TrivialExtrap::TrivialExtrap(Loaders& loaders, - std::string label, - const Binning& bins, - const Var& var, - const Cut& cut, - const SystShifts& shift, - const Weight& wei) - : TrivialExtrap(loaders, HistAxis(label, bins, var), cut, shift, wei) - { + tauSrc[kIsNC].GetVar(axis.GetVar1D()).Register(&fNCTot); + tauSrc[kIsNC && !kIsAntiNu].GetVar(axis.GetVar1D()).Register(&fNC); + tauSrc[kIsNC && kIsAntiNu].GetVar(axis.GetVar1D()).Register(&fNCAnti); } //---------------------------------------------------------------------- TrivialExtrap::TrivialExtrap(Loaders& loaders, const HistAxis& axis, const Cut& cut, + ana::RecoType recoIxnType, const SystShifts& shift, const Weight& wei) - : TrivialExtrap(loaders.GetLoader(caf::kFARDET, Loaders::kMC, Loaders::kNonSwap), - loaders.GetLoader(caf::kFARDET, Loaders::kMC, Loaders::kNueSwap), - loaders.GetLoader(caf::kFARDET, Loaders::kMC, Loaders::kNuTauSwap), - axis, cut, shift, wei) + : TrivialExtrap(loaders.GetSource(DataMC::kMC, caf::Det_t::kFARDET, SwappingConfig::kNonSwap).Interactions(recoIxnType), + loaders.GetSource(DataMC::kMC, caf::Det_t::kFARDET, SwappingConfig::kNueSwap).Interactions(recoIxnType), + loaders.GetSource(DataMC::kMC, caf::Det_t::kFARDET, SwappingConfig::kNuTauSwap).Interactions(recoIxnType), + axis) { } diff --git a/CAFAna/Extrap/TrivialExtrap.h b/CAFAna/Extrap/TrivialExtrap.h index a73c6c49..5941a95f 100644 --- a/CAFAna/Extrap/TrivialExtrap.h +++ b/CAFAna/Extrap/TrivialExtrap.h @@ -2,6 +2,9 @@ #include "CAFAna/Extrap/IExtrap.h" +#include "CAFAna/Core/IRecordSource.h" +#include "CAFAna/Core/Loaders.h" + namespace ana { class Loaders; @@ -10,38 +13,19 @@ namespace ana class TrivialExtrap: public IExtrap { public: - // This is the DUNE constructor - TrivialExtrap(SpectrumLoaderBase& loaderNonswap, - SpectrumLoaderBase& loaderNue, - SpectrumLoaderBase& loaderNuTau, - const HistAxis& axis, - const Cut& cut, - const SystShifts& shift, - const Weight& wei); - - TrivialExtrap(SpectrumLoaderBase& loaderNonswap, - SpectrumLoaderBase& loaderNue, - SpectrumLoaderBase& loaderNuTau, - std::string label, - const Binning& bins, - const Var& var, - const Cut& cut, - const SystShifts& shift, - const Weight& wei); - - TrivialExtrap(Loaders& loaders, - std::string label, - const Binning& bins, - const Var& var, - const Cut& cut, - const SystShifts& shift = kNoShift, - const Weight& wei = kUnweighted); - - TrivialExtrap(Loaders& loaders, - const HistAxis& axis, - const Cut& cut, - const SystShifts& shift = kNoShift, - const Weight& wei = kUnweighted); + TrivialExtrap(IInteractionSource& nonswapSrc, + IInteractionSource& nueSrc, + IInteractionSource& tauSrc, + const HistAxis& axis); + + TrivialExtrap(InteractionSources& srcs, const HistAxis& axis); + + TrivialExtrap(Loaders &loaders, + const HistAxis &axis, + const Cut &cut, + ana::RecoType recoIxnType, + const SystShifts &shift, + const Weight &wei); virtual OscillatableSpectrum NueSurvComponent() override {return fNueSurv;} virtual OscillatableSpectrum AntiNueSurvComponent() override {return fNueSurvAnti;} diff --git a/CAFAna/Fit/CMakeLists.txt b/CAFAna/Fit/CMakeLists.txt index 4cd90ef0..7c4c447e 100644 --- a/CAFAna/Fit/CMakeLists.txt +++ b/CAFAna/Fit/CMakeLists.txt @@ -34,7 +34,7 @@ set(Fit_header_files StanFitter.h) add_library(CAFAnaFit SHARED ${Fit_implementation_files}) -target_link_libraries(CAFAnaFit CAFAnaCore) +target_link_libraries(CAFAnaFit CAFAnaCore OscLib::All) set_target_properties(CAFAnaFit PROPERTIES PUBLIC_HEADER "${Fit_header_files}") @@ -43,6 +43,9 @@ if(DEFINED USE_OPENMP AND USE_OPENMP) target_compile_options(CAFAnaFit BEFORE PUBLIC -DUSE_PREDINTERP_OMP -fopenmp) endif() -install(TARGETS CAFAnaFit +install(TARGETS CAFAnaFit + EXPORT CAFAnaTargets LIBRARY DESTINATION lib/ PUBLIC_HEADER DESTINATION include/CAFAna/Fit/) + +add_cafana_lib(CAFAnaFit) \ No newline at end of file diff --git a/CAFAna/Fit/Fit.cxx b/CAFAna/Fit/Fit.cxx index 4b550154..e2f7bcba 100644 --- a/CAFAna/Fit/Fit.cxx +++ b/CAFAna/Fit/Fit.cxx @@ -1,8 +1,6 @@ #include "CAFAna/Fit/Fit.h" #include "CAFAna/Fit/MinuitFitter.h" -#include "CAFAna/Analysis/common_fit_definitions.h" - #include "CAFAna/Core/IFitVar.h" #include "CAFAna/Core/Progress.h" #include "CAFAna/Core/Utilities.h" diff --git a/CAFAna/Fit/MinuitFitter.cxx b/CAFAna/Fit/MinuitFitter.cxx index 9f25eb1f..24488b55 100644 --- a/CAFAna/Fit/MinuitFitter.cxx +++ b/CAFAna/Fit/MinuitFitter.cxx @@ -1,7 +1,6 @@ #include "CAFAna/Fit/MinuitFitter.h" #include "CAFAna/Fit/GradientDescent.h" -#include "CAFAna/Analysis/common_fit_definitions.h" #include "CAFAna/Core/IFitVar.h" #include "CAFAna/Core/Progress.h" @@ -252,7 +251,6 @@ namespace ana << " s. "; } - std::cout << BuildLogInfoString(); fLastTP = now; } diff --git a/CAFAna/PRISM/PredictionsForPRISM.h b/CAFAna/PRISM/PredictionsForPRISM.h index f3ad88a2..62b08bba 100644 --- a/CAFAna/PRISM/PredictionsForPRISM.h +++ b/CAFAna/PRISM/PredictionsForPRISM.h @@ -70,7 +70,7 @@ class NonSwapNoExtrapPredictionGenerator : public IPredictionGenerator { virtual std::unique_ptr Generate(Loaders &loaders, - const SystShifts &shiftMC = kNoShift) const override { + const ana::RecoType & ixnRecoType, const SystShifts &shiftMC = kNoShift) const override { return std::unique_ptr( new PredictionNonSwapNoExtrap(loaders, fAxis, fCut, shiftMC, fWei)); } @@ -186,7 +186,7 @@ class FDNoOscPredictionGenerator : public IPredictionGenerator { virtual std::unique_ptr Generate(Loaders &loaders, - const SystShifts &shiftMC = kNoShift) const override { + const ana::RecoType & ixnRecoType, const SystShifts &shiftMC = kNoShift) const override { SpectrumLoaderBase &loader_non = loaders.GetLoader(caf::kFARDET, Loaders::kMC, Loaders::kNonSwap); SpectrumLoaderBase &loader_nue = diff --git a/CAFAna/Prediction/CMakeLists.txt b/CAFAna/Prediction/CMakeLists.txt index e0f7ee5a..a35eb47e 100644 --- a/CAFAna/Prediction/CMakeLists.txt +++ b/CAFAna/Prediction/CMakeLists.txt @@ -1,13 +1,11 @@ set(Prediction_implementation_files IPrediction.cxx PredictionExtrap.cxx - PredictionGenerator.cxx - PredictionInterp.cxx + PredictionInterp.cxx PredictionNoExtrap.cxx PredictionNoOsc.cxx PredictionScaleComp.cxx PredictionXSecDiag.cxx - PredictionNuOnE.cxx PredictionInterpKernel.cxx) #PredictionsForPRISM.cxx) @@ -20,12 +18,11 @@ set(Prediction_header_files PredictionNoOsc.h PredictionScaleComp.h PredictionXSecDiag.h - PredictionNuOnE.h PredictionInterpKernel.h) #PredictionsForPRISM.h) add_library(CAFAnaPrediction SHARED ${Prediction_implementation_files}) -target_link_libraries(CAFAnaPrediction CAFAnaExtrap CAFAnaPRISM) +target_link_libraries(CAFAnaPrediction CAFAnaExtrap) # CAFAnaPRISM) set_target_properties(CAFAnaPrediction PROPERTIES PUBLIC_HEADER "${Prediction_header_files}") @@ -34,6 +31,13 @@ if(DEFINED USE_OPENMP AND USE_OPENMP) target_compile_options(CAFAnaPrediction BEFORE PUBLIC -DUSE_PREDINTERP_OMP -fopenmp) endif() -install(TARGETS CAFAnaPrediction +if (NOT DEFINED BUILD_ADHOC_PREDS) + message(WARNING "Not building PredictionScaleComponent and friends. Pass '-DBUILD_ADHOC_PREDS' using '-e BUILD_ADHOC_PREDS' in standalone_configure_and_build.sh to change this.") +endif() + +install(TARGETS CAFAnaPrediction + EXPORT CAFAnaTargets LIBRARY DESTINATION lib/ PUBLIC_HEADER DESTINATION include/CAFAna/Prediction/) + +add_cafana_lib(CAFAnaPrediction) \ No newline at end of file diff --git a/CAFAna/Prediction/PredictionGenerator.cxx b/CAFAna/Prediction/PredictionGenerator.cxx deleted file mode 100644 index 1d42e824..00000000 --- a/CAFAna/Prediction/PredictionGenerator.cxx +++ /dev/null @@ -1,23 +0,0 @@ -#include "CAFAna/Prediction/PredictionGenerator.h" -#include "CAFAna/Prediction/PredictionNoExtrap.h" - -namespace ana -{ - - //-------------------------------------------------------------------------- - - NoExtrapGenerator::NoExtrapGenerator( - const HistAxis axis, - const Cut cut, - const Weight wei - ) : fAxis(axis), fCut(cut), fWei(wei) {} - - std::unique_ptr NoExtrapGenerator::Generate( - Loaders& loaders, - const SystShifts& shiftMC - ) const { - return std::unique_ptr( new PredictionNoExtrap( - loaders, fAxis, fCut, shiftMC, fWei ) ); - } - -} diff --git a/CAFAna/Prediction/PredictionGenerator.h b/CAFAna/Prediction/PredictionGenerator.h index 181f123a..f07635ec 100644 --- a/CAFAna/Prediction/PredictionGenerator.h +++ b/CAFAna/Prediction/PredictionGenerator.h @@ -15,6 +15,7 @@ namespace ana class Loaders; class IPrediction; + enum class RecoType; /** \brief Given loaders and an MC shift, Generate() generates an IPrediction @@ -24,29 +25,7 @@ namespace ana class IPredictionGenerator { public: - virtual std::unique_ptr Generate( - Loaders& loaders, const SystShifts& shiftMC = kNoShift ) const = 0; + virtual std::unique_ptr Generate(Loaders& loaders, const ana::RecoType & ixnRecoType, const SystShifts& shiftMC = kNoShift) const = 0; }; - - //--------------------------------------------------------------------------- - - /// Generates FD-only predictions (no extrapolation) - class NoExtrapGenerator: public IPredictionGenerator - { - public: - NoExtrapGenerator( - const HistAxis axis, - const Cut cut, - const Weight wei = kUnweighted ); - - std::unique_ptr Generate( - Loaders& loaders, - const SystShifts& shiftMC = kNoShift ) const override; - - private: - const HistAxis fAxis; - const Cut fCut; - const Weight fWei; - }; } diff --git a/CAFAna/Prediction/PredictionInterp.cxx b/CAFAna/Prediction/PredictionInterp.cxx index 43a91ca8..097dccb5 100644 --- a/CAFAna/Prediction/PredictionInterp.cxx +++ b/CAFAna/Prediction/PredictionInterp.cxx @@ -41,6 +41,7 @@ namespace ana osc::IOscCalc* osc, const IPredictionGenerator& predGen, Loaders& loaders, + const ana::RecoType & ixnRecoType, const SystShifts& shiftMC, EMode_t mode) : fOscOrigin(osc ? osc->Copy() : 0), @@ -74,13 +75,13 @@ namespace ana for(int sigma: sp.shifts){ SystShifts shiftHere = shiftMC; shiftHere.SetShift(syst, sigma); - sp.preds.emplace_back(predGen.Generate(loaders, shiftHere)); + sp.preds.emplace_back(predGen.Generate(loaders, ixnRecoType, shiftHere)); } fPreds.emplace_back(syst, std::move(sp)); } // end for syst - fPredNom = predGen.Generate(loaders, shiftMC); + fPredNom = predGen.Generate(loaders, ixnRecoType, shiftMC); } //---------------------------------------------------------------------- diff --git a/CAFAna/Prediction/PredictionInterp.h b/CAFAna/Prediction/PredictionInterp.h index da240aa4..09512e56 100644 --- a/CAFAna/Prediction/PredictionInterp.h +++ b/CAFAna/Prediction/PredictionInterp.h @@ -33,6 +33,7 @@ namespace ana /// \param predGen Construct an IPrediction from the following /// information. /// \param loaders The loaders to be passed on to the underlying prediction + /// \param ixnRecoType Which group of reco interactions should be used for making predictions? /// \param shiftMC Underlying shift. Use with care. Mostly for /// PredictionNumuFAHadE. Should not contain any of of /// \a systs @@ -43,6 +44,7 @@ namespace ana osc::IOscCalc* osc, const IPredictionGenerator& predGen, Loaders& loaders, + const ana::RecoType & ixnRecoType, const SystShifts& shiftMC = kNoShift, EMode_t mode = kCombineSigns); diff --git a/CAFAna/Prediction/PredictionNoExtrap.cxx b/CAFAna/Prediction/PredictionNoExtrap.cxx index 16044ccb..c58cbcd5 100644 --- a/CAFAna/Prediction/PredictionNoExtrap.cxx +++ b/CAFAna/Prediction/PredictionNoExtrap.cxx @@ -15,30 +15,11 @@ namespace ana REGISTER_LOADFROM("PredictionNoExtrap", IPrediction, PredictionNoExtrap); //---------------------------------------------------------------------- - PredictionNoExtrap::PredictionNoExtrap(SpectrumLoaderBase& loaderNonswap, - SpectrumLoaderBase& loaderNue, - SpectrumLoaderBase& loaderNuTau, - const std::string& label, - const Binning& bins, - const Var& var, - const Cut& cut, - const SystShifts& shift, - const Weight& wei) - : PredictionExtrap(new TrivialExtrap(loaderNonswap, loaderNue, loaderNuTau, - label, bins, var, cut, shift, wei)) - { - } - - //---------------------------------------------------------------------- - PredictionNoExtrap::PredictionNoExtrap(SpectrumLoaderBase& loaderNonswap, - SpectrumLoaderBase& loaderNue, - SpectrumLoaderBase& loaderNuTau, - const HistAxis& axis, - const Cut& cut, - const SystShifts& shift, - const Weight& wei) - : PredictionExtrap(new TrivialExtrap(loaderNonswap, loaderNue, loaderNuTau, - axis, cut, shift, wei)) + PredictionNoExtrap::PredictionNoExtrap(IInteractionSource& srcNonswap, + IInteractionSource& srcNue, + IInteractionSource& srcNuTau, + const HistAxis& axis) + : PredictionExtrap(new TrivialExtrap(srcNonswap, srcNue, srcNuTau, axis)) { } @@ -47,25 +28,14 @@ namespace ana { } - //---------------------------------------------------------------------- - PredictionNoExtrap::PredictionNoExtrap(Loaders& loaders, - const std::string& label, - const Binning& bins, - const Var& var, - const Cut& cut, - const SystShifts& shift, - const Weight& wei) - : PredictionNoExtrap(loaders, HistAxis(label, bins, var), cut, shift, wei) - { - } - //---------------------------------------------------------------------- PredictionNoExtrap::PredictionNoExtrap(Loaders& loaders, const HistAxis& axis, const Cut& cut, + ana::RecoType recoIxnType, const SystShifts& shift, const Weight& wei) - : PredictionExtrap(new TrivialExtrap(loaders, axis, cut, shift, wei)) + : PredictionExtrap(new TrivialExtrap(loaders, axis, cut, recoIxnType, shift, wei)) { } @@ -109,6 +79,23 @@ namespace ana // We created this in the constructor so it's our responsibility delete fExtrap; } + + + //-------------------------------------------------------------------------- + NoExtrapGenerator::NoExtrapGenerator( + const HistAxis axis, + const Cut cut, + const Weight wei + ) : fAxis(axis), fCut(cut), fWei(wei) {} + + //-------------------------------------------------------------------------- + std::unique_ptr NoExtrapGenerator::Generate( + Loaders& loaders, + const ana::RecoType & ixnRecoType, const SystShifts& shiftMC + ) const { + return std::make_unique(loaders, fAxis, fCut, ixnRecoType, shiftMC, fWei ); + } + } diff --git a/CAFAna/Prediction/PredictionNoExtrap.h b/CAFAna/Prediction/PredictionNoExtrap.h index 66973e77..5a3750a2 100644 --- a/CAFAna/Prediction/PredictionNoExtrap.h +++ b/CAFAna/Prediction/PredictionNoExtrap.h @@ -4,61 +4,53 @@ #include "CAFAna/Prediction/PredictionGenerator.h" -namespace ana { -class Loaders; - -/// Prediction that just uses FD MC, with no extrapolation -class PredictionNoExtrap : public PredictionExtrap { -public: - PredictionNoExtrap(PredictionExtrap *pred); - PredictionNoExtrap(IExtrap *extrap); - - // This is the DUNE constructor - PredictionNoExtrap(SpectrumLoaderBase &loaderNonswap, - SpectrumLoaderBase &loaderNue, - SpectrumLoaderBase &loaderNuTau, const std::string &label, - const Binning &bins, const Var &var, const Cut &cut, - const SystShifts &shift = kNoShift, - const Weight &wei = kUnweighted); - - PredictionNoExtrap(SpectrumLoaderBase &loaderNonswap, - SpectrumLoaderBase &loaderNue, - SpectrumLoaderBase &loaderNuTau, const HistAxis &axis, - const Cut &cut, const SystShifts &shift = kNoShift, - const Weight &wei = kUnweighted); - - PredictionNoExtrap(Loaders &loaders, const std::string &label, - const Binning &bins, const Var &var, const Cut &cut, - const SystShifts &shift = kNoShift, - const Weight &wei = kUnweighted); - - PredictionNoExtrap(Loaders &loaders, const HistAxis &axis, const Cut &cut, - const SystShifts &shift = kNoShift, - const Weight &wei = kUnweighted); - - virtual ~PredictionNoExtrap(); - - static std::unique_ptr LoadFrom(TDirectory *dir, const std::string& name); - virtual void SaveTo(TDirectory *dir, const std::string& name) const override; -}; - -class NoExtrapPredictionGenerator : public IPredictionGenerator { -public: - NoExtrapPredictionGenerator(HistAxis axis, Cut cut, Weight wei = kUnweighted) - : fAxis(axis), fCut(cut), fWei(wei) { - } - - virtual std::unique_ptr - Generate(Loaders &loaders, - const SystShifts &shiftMC = kNoShift) const override { - return std::unique_ptr( - new PredictionNoExtrap(loaders, fAxis, fCut, shiftMC, fWei)); - } - -protected: - HistAxis fAxis; - Cut fCut; - Weight fWei; -}; +#include "CAFAna/Core/IRecordSource.h" + +namespace ana +{ + class Loaders; + + /// Prediction that just uses FD MC, with no extrapolation + class PredictionNoExtrap : public PredictionExtrap + { + public: + PredictionNoExtrap(PredictionExtrap *pred); + PredictionNoExtrap(IExtrap *extrap); + + PredictionNoExtrap(IInteractionSource& loaderNonswap, + IInteractionSource& loaderNue, + IInteractionSource& loaderNuTau, + const HistAxis& axis); + + + PredictionNoExtrap(Loaders& loaders, + const HistAxis &axis, + const Cut &cut, + ana::RecoType recoIxnType, + const SystShifts &shift, + const Weight &wei); + + virtual ~PredictionNoExtrap(); + + static std::unique_ptr LoadFrom(TDirectory *dir, const std::string& name); + virtual void SaveTo(TDirectory *dir, const std::string& name) const override; + }; + + + //--------------------------------------------------------------------------- + + /// Generates FD-only predictions (no extrapolation) + class NoExtrapGenerator: public IPredictionGenerator + { + public: + NoExtrapGenerator(const HistAxis axis, const Cut cut, const Weight wei = kUnweighted ); + + std::unique_ptr Generate(Loaders& loaders, const ana::RecoType & ixnRecoType, const SystShifts& shiftMC = kNoShift) const override; + + private: + const HistAxis fAxis; + const Cut fCut; + const Weight fWei; + }; } // namespace ana diff --git a/CAFAna/Prediction/PredictionNoOsc.cxx b/CAFAna/Prediction/PredictionNoOsc.cxx index 3e8cb5e9..75dda40d 100644 --- a/CAFAna/Prediction/PredictionNoOsc.cxx +++ b/CAFAna/Prediction/PredictionNoOsc.cxx @@ -16,31 +16,15 @@ namespace ana REGISTER_LOADFROM("PredictionNoOsc", IPrediction, PredictionNoOsc); //---------------------------------------------------------------------- - PredictionNoOsc::PredictionNoOsc(SpectrumLoaderBase& loader, - const std::string& label, - const Binning& bins, - const Var& var, - const Cut& cut, - const SystShifts& shift, - const Weight& wei) - : PredictionNoOsc(loader, HistAxis(label, bins, var), cut, shift, wei) - { - } - - //---------------------------------------------------------------------- - PredictionNoOsc::PredictionNoOsc(SpectrumLoaderBase& loader, - const HistAxis& axis, - const Cut& cut, - const SystShifts& shift, - const Weight& wei) - : fSpectrum( loader, axis, cut , shift, wei), - fSpectrumNCTot( loader, axis, cut && kIsNC , shift, wei), - fSpectrumNC( loader, axis, cut && kIsNC && !kIsAntiNu, shift, wei), - fSpectrumNCAnti( loader, axis, cut && kIsNC && kIsAntiNu, shift, wei), - fSpectrumNumu( loader, axis, cut && !kIsNC && kIsNumuCC && !kIsAntiNu, shift, wei), - fSpectrumNumubar(loader, axis, cut && !kIsNC && kIsNumuCC && kIsAntiNu, shift, wei), - fSpectrumNue( loader, axis, cut && !kIsNC && kIsBeamNue && !kIsAntiNu, shift, wei), - fSpectrumNuebar( loader, axis, cut && !kIsNC && kIsBeamNue && kIsAntiNu, shift, wei) + PredictionNoOsc::PredictionNoOsc(IInteractionSource& src, const HistAxis& axis) + : fSpectrum (src, axis), + fSpectrumNCTot (src[ kIsNC], axis), + fSpectrumNC (src[ kIsNC][!kIsAntiNu], axis), + fSpectrumNCAnti(src[ kIsNC][ kIsAntiNu], axis), + fSpectrumNumu (src[!kIsNC][kIsNumuCC ][!kIsAntiNu], axis), + fSpectrumNumubar(src[!kIsNC][kIsNumuCC ][ kIsAntiNu], axis), + fSpectrumNue (src[!kIsNC][kIsBeamNue][!kIsAntiNu], axis), + fSpectrumNuebar (src[!kIsNC][kIsBeamNue][ kIsAntiNu], axis) { } diff --git a/CAFAna/Prediction/PredictionNoOsc.h b/CAFAna/Prediction/PredictionNoOsc.h index 277b6445..d32b5b48 100644 --- a/CAFAna/Prediction/PredictionNoOsc.h +++ b/CAFAna/Prediction/PredictionNoOsc.h @@ -4,19 +4,13 @@ #include "CAFAna/Prediction/PredictionGenerator.h" #include "CAFAna/Core/Loaders.h" +#include "CAFAna/Core/IRecordSource.h" namespace ana { /// Prediction that wraps a simple Spectrum class PredictionNoOsc : public IPrediction { public: - PredictionNoOsc(SpectrumLoaderBase &loader, const HistAxis &axis, - const Cut &cut, const SystShifts &shift = kNoShift, - const Weight &wei = kUnweighted); - - PredictionNoOsc(SpectrumLoaderBase &loader, const std::string &label, - const Binning &bins, const Var &var, const Cut &cut, - const SystShifts &shift = kNoShift, - const Weight &wei = kUnweighted); + PredictionNoOsc(IInteractionSource& src, const HistAxis& axis); static std::unique_ptr LoadFrom(TDirectory *dir, const std::string& name); virtual void SaveTo(TDirectory *dir, const std::string& name) const override; @@ -75,6 +69,7 @@ class PredictionNoOsc : public IPrediction { Spectrum fSpectrumNuebar; }; + /* TODO think about generators class NoOscPredictionGenerator : public IPredictionGenerator { public: NoOscPredictionGenerator(HistAxis axis, Cut cut, Weight wei = kUnweighted) @@ -94,5 +89,6 @@ class NoOscPredictionGenerator : public IPredictionGenerator { Cut fCut; Weight fWei; }; + */ } // namespace ana diff --git a/CAFAna/Prediction/PredictionNuOnE.cxx b/CAFAna/Prediction/PredictionNuOnE.cxx deleted file mode 100644 index 98fdf19a..00000000 --- a/CAFAna/Prediction/PredictionNuOnE.cxx +++ /dev/null @@ -1,128 +0,0 @@ -#include "CAFAna/Prediction/PredictionNuOnE.h" - -#include "CAFAna/Core/LoadFromRegistry.h" - -#include "CAFAna/Cuts/TruthCuts.h" - -#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" - -#include "TDirectory.h" -#include "TObjString.h" - -namespace ana -{ - REGISTER_LOADFROM("PredictionNuOnE", IPrediction, PredictionNuOnE); - - // Simple counting experiment - const HistAxis kNuOnEaxis("Dummy nu-on-e axis", Binning::Simple(1, 0, 2), Constant(1)); - - const Var kThetaReco = SIMPLEVAR(theta_reco); - const Var kElepReco = SIMPLEVAR(Elep_reco); - const Var kEsqTheta = kElepReco * kThetaReco * kThetaReco; - - const Var kEhadVeto = SIMPLEVAR(Ehad_veto); - - // Private communication from Chris M - const Cut kNuOnECut = kEsqTheta < .002 && kElepReco > .5 && kIsTrueFV && kEhadVeto < 20; - - // Account for reduced efficiency of selecting photon shower as backgrounds - // into an analysis looking for electron showers. - const Weight kNCScaleFactor([](const caf::SRProxy* sr){return .1;}); - - // -------------------------------------------------------------------------- - PredictionNuOnE::PredictionNuOnE(SpectrumLoaderBase& sigLoader, - SpectrumLoaderBase& ccBkgLoader, - SpectrumLoaderBase& ncBkgLoader, - const SystShifts& shift, - const Weight& wei) - : fSig ( sigLoader, kNuOnEaxis, kNuOnECut, shift, wei), - fCCBkg(ccBkgLoader, kNuOnEaxis, kNuOnECut, shift, wei), - fNCBkg(ncBkgLoader, kNuOnEaxis, kNuOnECut, shift, wei * kNCScaleFactor) - { - } - - // -------------------------------------------------------------------------- - Spectrum PredictionNuOnE::Predict(osc::IOscCalc*) const - { - return fSig+fCCBkg+fNCBkg; - } - - //---------------------------------------------------------------------- - Spectrum PredictionNuOnE::PredictComponent(osc::IOscCalc* calc, - Flavors::Flavors_t flav, - Current::Current_t curr, - Sign::Sign_t sign) const - { - // Get binning - Spectrum ret = fSig; - ret.Clear(); - - if(curr & Current::kCC){ - if(flav & Flavors::kNuMuToNuMu) ret += fSig; // mostly... - if(flav & Flavors::kNuEToNuE) ret += fCCBkg; - } - - if(curr & Current::kNC){ - assert(flav == Flavors::kAll); - ret += fNCBkg; - } - - return ret; - } - - // -------------------------------------------------------------------------- - void PredictionNuOnE::SaveTo(TDirectory* dir, const std::string& name) const - { - TDirectory* tmp = dir; - - dir = dir->mkdir(name.c_str()); // switch to subdir - dir->cd(); - - TObjString("PredictionNuOnE").Write("type"); - - fSig.SaveTo(dir, "sig"); - fCCBkg.SaveTo(dir, "ccbkg"); - fNCBkg.SaveTo(dir, "ncbkg"); - - dir->Write(); - delete dir; - - tmp->cd(); - } - - //---------------------------------------------------------------------- - std::unique_ptr PredictionNuOnE::LoadFrom(TDirectory* dir, const std::string& name) - { - dir = dir->GetDirectory(name.c_str()); // switch to subdir - assert(dir); - - TObjString* ptag = (TObjString*)dir->Get("type"); - assert(ptag); - assert(ptag->GetString() == "PredictionNuOnE"); - - PredictionNuOnE* ret = new PredictionNuOnE - (*Spectrum::LoadFrom(dir, "sig"), - *Spectrum::LoadFrom(dir, "ccbkg"), - *Spectrum::LoadFrom(dir, "ncbkg")); - - delete dir; - - return std::unique_ptr(ret); - } - - //---------------------------------------------------------------------- - std::unique_ptr PredictionNuOnEGenerator:: - Generate(Loaders& loaders, const SystShifts& shiftMC) const - { - NuOnELoaders* noel = dynamic_cast(&loaders); - if(!noel){ - std::cout << "PredictionNuOnEGenerator must be used in conjunction with NuOnELoaders" << std::endl; - abort(); - } - - return std::unique_ptr - (new PredictionNuOnE(noel->Signal(), noel->CCBkg(), noel->NCBkg(), - shiftMC, fWei)); - } - -} diff --git a/CAFAna/Prediction/PredictionNuOnE.h b/CAFAna/Prediction/PredictionNuOnE.h deleted file mode 100644 index c1a52ead..00000000 --- a/CAFAna/Prediction/PredictionNuOnE.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include "CAFAna/Prediction/IPrediction.h" - -#include "CAFAna/Prediction/PredictionGenerator.h" - -#include "CAFAna/Core/Loaders.h" - -namespace ana -{ - /// Jam the necessary loaders into approximately the expected structure - class NuOnELoaders: public Loaders - { - public: - NuOnELoaders(SpectrumLoaderBase& sig, - SpectrumLoaderBase& ccBkg, - SpectrumLoaderBase& ncBkg) - : fSig(sig), fCCBkg(ccBkg), fNCBkg(ncBkg) - { - } - - SpectrumLoaderBase& Signal() {return fSig;} - SpectrumLoaderBase& CCBkg() {return fCCBkg;} - SpectrumLoaderBase& NCBkg() {return fNCBkg;} - - void Go() {fSig.Go(); fCCBkg.Go(); fNCBkg.Go();} - protected: - SpectrumLoaderBase &fSig, &fCCBkg, &fNCBkg; - }; - - - class PredictionNuOnE: public IPrediction - { - public: - PredictionNuOnE(SpectrumLoaderBase& sigLoader, - SpectrumLoaderBase& ccBkgLoader, - SpectrumLoaderBase& ncBkgLoader, - const SystShifts& shift = kNoShift, - const Weight& wei = kUnweighted); - - PredictionNuOnE(NuOnELoaders& loaders, - const SystShifts& shift = kNoShift, - const Weight& wei = kUnweighted) - : PredictionNuOnE(loaders.Signal(), loaders.CCBkg(), loaders.NCBkg(), - shift, wei) - { - } - - virtual Spectrum Predict(osc::IOscCalc*) const override; - - /// We call signal numu CC and CC bkg nue CC for this function's purposes - virtual Spectrum PredictComponent(osc::IOscCalc* calc, - Flavors::Flavors_t flav, - Current::Current_t curr, - Sign::Sign_t sign) const override; - - virtual void SaveTo(TDirectory* dir, const std::string& name) const override; - static std::unique_ptr LoadFrom(TDirectory* dir, const std::string& name); - - Spectrum Signal() const {return fSig;} - Spectrum CCBkg() const {return fCCBkg;} - Spectrum NCBkg() const {return fNCBkg;} - - protected: - PredictionNuOnE(const Spectrum& sig, const Spectrum& ccbkg, const Spectrum& ncbkg) : fSig(sig), fCCBkg(ccbkg), fNCBkg(ncbkg) {} - - Spectrum fSig, fCCBkg, fNCBkg; - }; - - - class PredictionNuOnEGenerator: public IPredictionGenerator - { - public: - PredictionNuOnEGenerator(Weight wei = kUnweighted) : fWei(wei) - { - } - - virtual std::unique_ptr - Generate(Loaders& loaders, - const SystShifts& shiftMC = kNoShift) const override; - - protected: - Weight fWei; - }; -} diff --git a/CAFAna/Prediction/PredictionScaleComp.cxx b/CAFAna/Prediction/PredictionScaleComp.cxx index b26b509d..060e309d 100644 --- a/CAFAna/Prediction/PredictionScaleComp.cxx +++ b/CAFAna/Prediction/PredictionScaleComp.cxx @@ -1,3 +1,5 @@ +#ifdef BUILD_ADHOC_PREDS // TODO TODO TODO + #include "CAFAna/Prediction/PredictionScaleComp.h" #include "CAFAna/Core/Cut.h" @@ -209,3 +211,5 @@ namespace ana } } + +#endif diff --git a/CAFAna/Prediction/PredictionXSecDiag.cxx b/CAFAna/Prediction/PredictionXSecDiag.cxx index 2cce35ca..9dd2645d 100644 --- a/CAFAna/Prediction/PredictionXSecDiag.cxx +++ b/CAFAna/Prediction/PredictionXSecDiag.cxx @@ -1,3 +1,5 @@ +#ifdef BUILD_ADHOC_PREDS + #include "CAFAna/Prediction/PredictionXSecDiag.h" #include "CAFAna/Core/LoadFromFile.h" @@ -176,3 +178,5 @@ namespace ana } } } + +#endif \ No newline at end of file diff --git a/CAFAna/Prediction/PredictionXSecDiag.h b/CAFAna/Prediction/PredictionXSecDiag.h index 640c0997..5ddd8fde 100644 --- a/CAFAna/Prediction/PredictionXSecDiag.h +++ b/CAFAna/Prediction/PredictionXSecDiag.h @@ -9,7 +9,7 @@ namespace ana class DUNEXSecDiagSyst: public ISyst { public: - virtual void Shift(double, caf::SRProxy*, double&) const + virtual void Shift(double, caf::SRInteractionProxy *, double&) const { assert(0 && "unimplemented"); } diff --git a/CAFAna/README.md b/CAFAna/README.md new file mode 100644 index 00000000..342789d0 --- /dev/null +++ b/CAFAna/README.md @@ -0,0 +1,85 @@ + +# Making your first plots in CAFAna + +This is a simplified guide on how to install and run `CAFAna` to make your first plot . A lot more information can be found in [this tutorial](https://github.com/chenel/dune-nd-lar-reco/blob/main/tute/2021-12-02%20CAFAna-NDLAr-Howto.md) by Jeremy Wolcott. + +Also some information is duplicated from a directory above, but gathered here for your easy access. + +## Setup a container + +As you may know, we are living now in AL9 world, but I don't know how to use spack to build CAFAna. Instead you can setup this standard container provided for us as in https://wiki.dunescience.org/wiki/SL7_to_Alma9_conversion + +``` +/cvmfs/oasis.opensciencegrid.org/mis/apptainer/current/bin/apptainer shell --shell=/bin/bash \ +-B /cvmfs,/exp,/nashome,/pnfs/dune,/opt,/run/user,/etc/hostname,/etc/hosts,/etc/krb5.conf --ipc --pid \ +/cvmfs/singularity.opensciencegrid.org/fermilab/fnal-dev-sl7:latest +``` +The reccommendation is that you use `dunebuild03` instead of a gpvm to build your code. Remove `/pnfs/dune/` when setting up the container, otherwise it will complain. Later on, you can run code and access `pnfs` on a regular gpvm. + +``` +# before anything else, set up UPS +source /cvmfs/dune.opensciencegrid.org/products/dune/setup_dune.sh +``` +Now you can go ahead and install. + +## How to install + +Clone this branch of the repository: +``` +git clone git@github.com:DUNE/lblpwgtools.git +cd lblpwgtools +checkout feature/source-sink-overhaul +``` + +We currently don't have official versions of `cafanacore` ,`duneanaobj`,`osclib`, and `srproxy` , that have truth-reco matching, so we need this extra step to fetch working versions (eventually these should be published): +``` +export PRODUCTS="/exp/dune/app/users/jwolcott/ups:$PRODUCTS" +export PRODUCTS="/exp/dune/app/users/mcasales/ups:$PRODUCTS" +``` + +A helper build script lives in this `CAFAna` subdirectory. You can build and install the code like: + +``` +cd CAFAna +./standalone_configure_and_build.sh -r +``` + +If you are in a DUNE `gpvm` and therefore have `cvmfs` access, you can rely on relevant dependencies from FNAL scisoft by add in the `-u` option: + +``` +./standalone_configure_and_build.sh -r -u -j 4 +``` + +Once CAFAna has been built, to set up the environment you will need to `source /path/to/install/CAFAnaEnv.sh`. If `standalone_configure_and_build.sh` was not passed a `-I` argument, then this will be `/path/to/repo/CAFAna/build/Linux/CAFAnaEnv.sh` by default. + +## Examples + +Once CAFAna is built and the environment setup, proceed to run an example script doing: +``` +cafe tute/demo0b.C +``` +``` +cafe -l 10 tute/demo0b.C +``` +The `-l` option limits the number of files read by the script so you can obtain plots faster. See other options with `cafe --help`. + +The three example scripts in the `tute` directory have the following content: + +### demo0b +Basic distributions in 1D and 2D of variables from the ` SRCommonRecoBranch`. + +### demo1b +More distributions, more manipulations of variables/cuts, now of variables from the `SRTruthBranch`. Also showing how to open/read files. + +### demo0eb +Examples of systematic variations applied to distributions from ` SRCommonRecoBranch` variables. + +## To do's / caveats / wishlist +- Systematic variations are not implemented in truth branches yet +- More realistic examples of systematics +- Note: If you run into issues accessing files, which looks like ```Error in : [FATAL] Auth failed: No protocols left to try```, you probably need to `setup duneutil v09_89_01d01 -q e26:prof` in order to do `setup_fnal_security`. You might need to re-build after doing this. I am working on adding a detailed instruction on this. Remember to source `CAFAnaEnv.sh` after building. +## + +Last updated September 4, 2024, by Maria Martinez-Casales (mcasales@fnal.gov) + + diff --git a/CAFAna/Systs/AnaSysts.cxx b/CAFAna/Systs/AnaSysts.cxx index face8b44..f7bd2c9e 100644 --- a/CAFAna/Systs/AnaSysts.cxx +++ b/CAFAna/Systs/AnaSysts.cxx @@ -1,14 +1,6 @@ -#include "CAFAna/Analysis/AnalysisDialGroups.h" -#include "CAFAna/Analysis/AnalysisVersion.h" - #include "CAFAna/Systs/AnaSysts.h" #include "CAFAna/Systs/CrazyFluxFakeData.h" #include "CAFAna/Systs/DUNEFluxSysts.h" -#include "CAFAna/Systs/EnergySysts.h" -#include "CAFAna/Systs/FDRecoSysts.h" -#include "CAFAna/Systs/RecoEnergyNDSysts.h" -#include "CAFAna/Systs/NDRecoSysts.h" -#include "CAFAna/Systs/NuOnESysts.h" #include "CAFAna/Systs/XSecSysts.h" #include "TFile.h" @@ -18,8 +10,6 @@ #include #include -size_t NFluxParametersToAddToStatefile = 25; - namespace ana { // Because most particle physics is stuck in C++ @@ -67,310 +57,4 @@ namespace ana }), systlist.end()); } - std::vector getDetectorSysts(bool useFD, bool useND, bool useNueOnE) - { - - std::vector systs = {}; - - std::vector fdEScalelist = GetEnergySysts(); - std::vector fdlist = GetFDRecoSysts(); - std::vector ndEScalelist = GetRecoENDSysts(); - std::vector ndlist = GetNDRecoSysts(); - std::vector nuelist = GetNuOnESysts(); - - if (useFD) { - systs.insert(systs.end(), fdEScalelist.begin(), fdEScalelist.end()); - systs.insert(systs.end(), fdlist.begin(), fdlist.end()); - } - if (useND) { - systs.insert(systs.end(), ndEScalelist.begin(), ndEScalelist.end()); - systs.insert(systs.end(), ndlist.begin(), ndlist.end()); - } - if (useND && useNueOnE) { - systs.insert(systs.end(), nuelist.begin(), nuelist.end()); - } - - return systs; - } - - std::vector getReducedXSecSysts(bool fluxXsecPenalties){ - - std::vector systs = GetXSecSysts(GetAllXSecSystNames(), fluxXsecPenalties); - // Always remove these dials - // TO DO: Only add the dials to actually use and avoid the need of RemoveSysts - // Then we won't have to worry about systs addition ordering - RemoveSysts(systs, GetDoNotIncludeSystNames()); - - return systs; - } - - std::vector getFakeDataSysts(bool fluxXsecPenalties){ - - std::vector systs = GetCrazyFluxSysts(); - - std::vector xseclist = GetXSecSysts(GetAllXSecSystNames(), fluxXsecPenalties); - KeepSysts(xseclist, GetFakeDataGenerationSystNames()); - systs.insert(systs.end(), xseclist.begin(), xseclist.end()); - - return systs; - } - - std::vector GetListOfSysts(bool fluxsyst_Nov17, bool xsecsyst, - bool detsyst, bool useND, bool useFD, - bool useNueOnE, bool useFakeDataDials, - bool fluxsyst_CDR, bool fluxsyst_Sept21, - int NFluxSysts, bool removeFDNonFitDials) { - - // This doesn't need to be an argument because I basically never change it: - bool fluxXsecPenalties = true; - - std::vector systlist; - if (fluxsyst_Nov17) { - std::vector fluxsyst_Nov17 = - GetDUNEFluxSysts(NFluxSysts, fluxXsecPenalties, false); - systlist.insert(systlist.end(), fluxsyst_Nov17.begin(), fluxsyst_Nov17.end()); - } - - if (fluxsyst_CDR) { // CHECK: GetDUNEFluxSysts loading nothing when set to true - std::vector fluxsyst_CDR = - GetDUNEFluxSysts(NFluxSysts, fluxXsecPenalties, true); - systlist.insert(systlist.end(), fluxsyst_CDR.begin(), fluxsyst_CDR.end()); - } - - if (fluxsyst_Sept21) { - std::vector fluxsyst_Sept21 = - GetDUNEFluxSysts(NFluxSysts, fluxXsecPenalties, false, true); - systlist.insert(systlist.end(), fluxsyst_Sept21.begin(), fluxsyst_Sept21.end()); - } - - if (detsyst) { - std::vector detsyst = getDetectorSysts(useFD,useND,useNueOnE); - systlist.insert(systlist.end(), detsyst.begin(), detsyst.end()); - } - - if (xsecsyst) { - // This function removes some dials. Don't know why it has to be so - // Those will need to be added again if using fake data. So always add fake data last - std::vector xsecsyst = getReducedXSecSysts(fluxXsecPenalties); - systlist.insert(systlist.end(), xsecsyst.begin(), xsecsyst.end()); - } - - // If using fake data dials (for state generation) add the previously removed systs back in - if (useFakeDataDials) { - std::vector fakedatasyst = getFakeDataSysts(fluxXsecPenalties); - systlist.insert(systlist.end(), fakedatasyst.begin(), fakedatasyst.end()); - } - - return systlist; - } - - std::vector GetListOfSysts(std::string systString, bool useND, - bool useFD, bool useNueOnE) { - - if (systString == "fakedata") { - return GetListOfSysts(false, false, false, false, false, false, - true /*add fake data*/, false, false); - } - - // Now defaults to true! - bool detsyst = true; - bool fluxsyst_Nov17 = (GetAnaVersion() == kV3) ? false : true; - bool fluxsyst_CDR = (GetAnaVersion() == kV3) ? true : false; - bool fluxsyst_Sept21 = true; - bool xsecsyst = true; - bool useFakeData = false; - int NFluxSysts = - (GetAnaVersion() == kV3) ? 10 : NFluxParametersToAddToStatefile; - - // If you find an argument in the form list:name1:name2:name3 etc etc, keep - // only those systematics This is pretty much a magic option to allow single - // parameters... there must be a better way, but for now I'm just going to - // continue to support it - if (systString.find("list") != std::string::npos) { - - // 1) Get a default list with everything - std::vector namedList = - GetListOfSysts(true, true, true, useND, useFD, useNueOnE, - false /*no fake data*/, true /*Get CDR flux systs*/, - true /*Get Sept 21 flux systs*/); - // for (auto & syst : namedList) std::cout << syst->ShortName() << - // std::endl; 2) Interpret the list of short names - std::vector systs = SplitString(systString, ':'); - - // 3) Don't include "list" - systs.erase(systs.begin()); - - // 4) Regret nothing - KeepSysts(namedList, systs); - - // 5) $$$ Profit - return namedList; - } - - // Can't transform anymore, so... BEHAVE YOURSELF - // std::transform(systString.begin(), systString.end(), systString.begin(), - // ::tolower); - - // Do even more horrific things... - std::vector systs = SplitString(systString, ':'); - - // Start off by checking for certain keywords - for (auto syst : systs) { - if (syst == "allsyst") { - xsecsyst = true; - fluxsyst_Nov17 = (GetAnaVersion() == kV3) ? false : true; - fluxsyst_CDR = (GetAnaVersion() == kV3) ? true : false; - fluxsyst_Sept21 = false; - detsyst = true; - } - - if (syst == "nosyst") { - xsecsyst = false; - fluxsyst_Nov17 = false; - fluxsyst_CDR = false; - fluxsyst_Sept21 = false; - detsyst = false; - } - - // Now we're getting a bit funky as these options now conflict. - // But, if you do something stupid, YOU ONLY HAVE YOURSELF TO BLAME - if (syst == "nodet") { - detsyst = false; - fluxsyst_Sept21 = false; // Default to getting the Nov17 flux systs for now - } - if (syst == "noflux") { - fluxsyst_CDR = false; - fluxsyst_Nov17 = false; - fluxsyst_Sept21 = false; - } - if (syst == "cdrflux") { - fluxsyst_CDR = true; - fluxsyst_Nov17 = false; - fluxsyst_Sept21 = false; - } - if (syst == "nov17flux") { - fluxsyst_CDR = false; - fluxsyst_Nov17 = true; - fluxsyst_Sept21 = false; - } - if (syst == "sept21flux") { - fluxsyst_CDR = false; - fluxsyst_Nov17 = false; - fluxsyst_Sept21 = true; - } - if (syst == "fakedata") { - useFakeData = true; - } // LOOK MA, I GOT BRACES! - - if (syst.find("nflux=") == 0) { - auto NFluxSplit = SplitString(syst, '='); - if (NFluxSplit.size() != 2) { - std::cout << "[ERROR]: Found NFlux option, but couldn't parse how many " - "to include, expected to find nflux=<0--" - << NFluxParametersToAddToStatefile << "> but found: \"" - << syst << "\"."; - abort(); - } - - NFluxSysts = atoi(NFluxSplit[1].c_str()); - } - if (syst == "noxsec") { - xsecsyst = false; - fluxsyst_Sept21 = false; // Default to getting the Nov17 flux systs for now - } - } - - // Okay, now get the list, and start from there... - std::vector namedList = - GetListOfSysts(fluxsyst_Nov17, xsecsyst, detsyst, useND, useFD, useNueOnE, - useFakeData, fluxsyst_CDR, fluxsyst_Sept21, NFluxSysts); - - // Now do something REALLY FUNKY. Remove specific dials from the list we - // already have Need to allow single dials, and a few specific groups... - for (auto syst : systs) { - // ignore anything we previously dealt with - if ((syst == "noxsec") || (syst == "nodet") || (syst == "noflux") || - (syst.find("nflux=") == 0)) { - continue; - } - // Now remove some specific groups - // nofd_det, nofd_escale, nofd_muon_escale, noxsec_qe, noxsec_res, - // noxsec_dis, noxsec_fsi, noxsec_ratios - else if (syst == "nofd_det") { - RemoveSysts(namedList, fd_det_list); - } else if (syst == "nofd_escale") { - RemoveSysts(namedList, fd_escale_list); - } else if (syst == "nofd_muon_escale") { - RemoveSysts(namedList, fd_muon_escale_list); - } else if (syst == "nofd_eres") { - RemoveSysts(namedList, fd_eres_list); - } else if (syst == "nofd_muon_eres") { - RemoveSysts(namedList, fd_muon_eres_list); - } else if (syst == "nofd_other_det") { - RemoveSysts(namedList, fd_other_det_list); - } else if (syst == "nofd_nonlin_det") { - RemoveSysts(namedList, fd_nonlin_det_list); - } else if (syst == "noxsec_qe") { - RemoveSysts(namedList, GetXSecSystNames("QELike")); - } else if (syst == "noxsec_res") { - RemoveSysts(namedList, GetXSecSystNames("RES")); - } else if (syst == "noxsec_dis") { - RemoveSysts(namedList, GetXSecSystNames("DIS")); - } else if (syst == "noxsec_fsi") { - RemoveSysts(namedList, GetXSecSystNames("FSI")); - } else if (syst == "noxsec_ratios") { - RemoveSysts(namedList, GetXSecSystNames("Ratios")); - } - // If not, remove as if it's a single parameter instruction - else { - RemoveSysts(namedList, {syst.erase(0, 2)}); - } - } - - if (GetAnaVersion() == kV3) { - RemoveSysts(namedList, - {"UncorrFDTotSqrt", "UncorrFDTotInvSqrt", "UncorrFDHadSqrt", - "UncorrFDHadInvSqrt", "UncorrFDMuSqrt", "UncorrFDMuInvSqrt", - "UncorrFDNSqrt", "UncorrFDNInvSqrt", "UncorrFDEMSqrt", - "UncorrFDEMInvSqrt", "ChargedHadUncorrFD"}); - } - - // Now return the list - return namedList; - } - - std::vector GetListOfSysts(char const *systCString, bool useND, - bool useFD, bool useNueOnE) { - return GetListOfSysts(std::string(systCString), useND, useFD, useNueOnE); - } - - std::vector - OrderListOfSysts(std::vector const &systlist) { - std::vector superorder; - for (auto &s : GetListOfSysts("flux:noxsec:nodet")) { - superorder.emplace_back(s); - } - for (auto &s : GetListOfSysts("cdrflux:noxsec:nodet")) { - superorder.emplace_back(s); - } - for (auto &s : GetListOfSysts("noflux:xsec:nodet")) { - superorder.emplace_back(s); - } - for (auto &s : GetListOfSysts("noflux:noxsec:det")) { - superorder.emplace_back(s); - } - for (auto &s : GetListOfSysts("fakedata")) { - superorder.emplace_back(s); - } - std::vector retlist; - - for (auto s : superorder) { - if (std::find(systlist.begin(), systlist.end(), s) == systlist.end()) { - continue; - } - retlist.emplace_back(s); - } - return retlist; - } - } diff --git a/CAFAna/Systs/AnaSysts.h b/CAFAna/Systs/AnaSysts.h index 244d9bfa..da18e3f7 100644 --- a/CAFAna/Systs/AnaSysts.h +++ b/CAFAna/Systs/AnaSysts.h @@ -1,11 +1,10 @@ #pragma once #include "CAFAna/Core/ISyst.h" -#include "CAFAna/Systs/Systs.h" -class TH1D; +#include -extern size_t NFluxParametersToAddToStatefile; +class TH1D; namespace ana { @@ -18,31 +17,4 @@ namespace ana void RemoveSysts(std::vector &systlist, std::vector const &namesToRemove); - /// Get a vector of all the analysis group systs - std::vector getDetectorSysts(bool useFD=true, bool useND=false, bool useNueOneE=false); - - std::vector getReducedXSecSysts(bool fluxXsecPenalties); - - std::vector getFakeDataSysts(bool fluxXsecPenaltiess); - - std::vector GetListOfSysts(bool fluxsyst_Nov17 = true, bool xsecsyst = true, - bool detsyst = true, bool useND = true, bool useFD = true, - bool useNueOnE = false, bool useFakeDataDials = true, - bool fluxsyst_CDR = true, bool fluxsyst_Sept21 = false, - int NFluxSysts = NFluxParametersToAddToStatefile, - bool removeFDNonFitDials = false); - - std::vector GetListOfSysts(std::string systString, - bool useND = true, - bool useFD = true, - bool useNueOnE = false); - - std::vector GetListOfSysts(char const *systCString, - bool useND = true, - bool useFD = true, - bool useNueOnE = false); - - /// Put a list of systematics in the 'standard' order - std::vector OrderListOfSysts(std::vector const &systlist); - } diff --git a/CAFAna/Systs/CMakeLists.txt b/CAFAna/Systs/CMakeLists.txt index b7b1e64b..dd8f4cd3 100644 --- a/CAFAna/Systs/CMakeLists.txt +++ b/CAFAna/Systs/CMakeLists.txt @@ -1,19 +1,12 @@ set(Systs_implementation_files AnaSysts.cxx DUNEFluxSysts.cxx - RecoEnergyNDSysts.cxx - DUNENDSysts.cxx DUNEXSecSysts.cxx DUNEXSecSystsPCA.cxx - EnergySysts.cxx - FDRecoSysts.cxx XSecSysts.cxx - NDRecoSysts.cxx - NuOnESysts.cxx NuWroReweightFakeData.cxx CrazyFluxFakeData.cxx SystComponentScale.cxx - Systs.cxx UniverseOracle.cxx XSecSystList.cxx OffAxisFluxUncertaintyHelper.cxx @@ -22,17 +15,10 @@ set(Systs_implementation_files set(Systs_header_files AnaSysts.h DUNEFluxSysts.h - RecoEnergyNDSysts.h - DUNENDSysts.h DUNEXSecSysts.h DUNEXSecSystsPCA.h - EnergySysts.h - FDRecoSysts.h XSecSysts.h - NDRecoSysts.h - NuOnESysts.h SystComponentScale.h - Systs.h MissingProtonFakeData.h BDTReweighter.h GeneratorReweight_nuebar_FD_RHC.h @@ -54,7 +40,19 @@ set(Systs_header_files NewOffAxisFluxUncertainty2022Helper.h) add_library(CAFAnaSysts SHARED ${Systs_implementation_files}) -target_link_libraries(CAFAnaSysts CAFAnaExperiment TH2Jagged::All) +target_link_libraries(CAFAnaSysts ${STANDARDRECORD} CAFAnaExperiment TH2Jagged::All) + +if(NOT DEFINED BUILD_FLUX_SYSTS) + message(WARNING "Not building flux systematics code. Include `-DBUILD_FLUX_SYSTS` in the 'extra CMake arguments' passed to `standalone_configure_and_build.sh` to include it.") +endif() + +if(NOT DEFINED BUILD_XSEC_SYSTS) + message(WARNING "Not building xsec systematics code. Include `-DBUILD_XSEC_SYSTS` in the 'extra CMake arguments' passed to `standalone_configure_and_build.sh` to include it.") +endif() + +if(NOT DEFINED BUILD_FDS_SYSTS) + message(WARNING "Not building fake data systematics code. Include `-DBUILD_XSEC_SYSTS` in the 'extra CMake arguments' passed to `standalone_configure_and_build.sh` to include it.") +endif() set_target_properties(CAFAnaSysts PROPERTIES PUBLIC_HEADER "${Systs_header_files}") @@ -63,7 +61,8 @@ if(DEFINED USE_OPENMP AND USE_OPENMP) target_compile_options(CAFAnaSysts BEFORE PUBLIC -DUSE_PREDINTERP_OMP -fopenmp) endif() -install(TARGETS CAFAnaSysts +install(TARGETS CAFAnaSysts + EXPORT CAFAnaTargets LIBRARY DESTINATION lib/ PUBLIC_HEADER DESTINATION include/CAFAna/Systs/) @@ -81,3 +80,5 @@ set(SYST_INPUT_ROOT_FILES ) install(FILES ${SYST_INPUT_ROOT_FILES} DESTINATION Systs) + +add_cafana_lib(CAFAnaSysts) \ No newline at end of file diff --git a/CAFAna/Systs/CrazyFluxFakeData.cxx b/CAFAna/Systs/CrazyFluxFakeData.cxx index 33f17f55..eed7995b 100644 --- a/CAFAna/Systs/CrazyFluxFakeData.cxx +++ b/CAFAna/Systs/CrazyFluxFakeData.cxx @@ -3,6 +3,7 @@ #include "duneanaobj/StandardRecord/Proxy/SRProxy.h" namespace ana { +#ifdef BUILD_FLUX_SYSTS std::vector GetCrazyFluxDialNames(){ static std::vector ret = {"CrazyFlux_FHC", @@ -33,13 +34,13 @@ namespace ana { if (fName == GetCrazyFluxDialNames()[1] && sr->isFHC){ return; } - + // If you get this far, apply a weight // All values in the array except [3], the nominal, should be the same weight *= sr->wgt_CrazyFlux[0]; } - + CrazyFluxDial::CrazyFluxDial(std::string name, bool applyPenalty) : ISyst(name, name, applyPenalty), fName(name) {} @@ -47,7 +48,7 @@ namespace ana { std::vector GetCrazyFluxSysts(std::vector names, bool applyPenalty) { static std::vector ret; - + if (names.empty()) { names = GetCrazyFluxDialNames(); } @@ -60,5 +61,5 @@ namespace ana { return ret; } - +#endif // BUILD_FLUX_SYSTS } diff --git a/CAFAna/Systs/CrazyFluxFakeData.h b/CAFAna/Systs/CrazyFluxFakeData.h index 07f78660..e9f8087c 100644 --- a/CAFAna/Systs/CrazyFluxFakeData.h +++ b/CAFAna/Systs/CrazyFluxFakeData.h @@ -8,22 +8,23 @@ #include namespace ana { +#ifdef BUILD_FLUX_SYSTS class CrazyFluxDial : public ISyst { public: virtual ~CrazyFluxDial(){}; - + void Shift(double sigma, caf::SRProxy *sr, double &weight) const override; - + protected: CrazyFluxDial(std::string name, bool applyPenalty = false); friend std::vector GetCrazyFluxSysts(std::vector, bool); std::string fName; - + }; std::vector GetCrazyFluxDialNames(); @@ -32,5 +33,6 @@ class CrazyFluxDial : public ISyst { std::vector GetCrazyFluxSysts(std::vector names = {}, bool applyPenalty = false); - + +#endif // BUILD_FLUX_SYSTS } // namespace ana diff --git a/CAFAna/Systs/DUNEFluxSysts.cxx b/CAFAna/Systs/DUNEFluxSysts.cxx index e3141ed7..28400207 100644 --- a/CAFAna/Systs/DUNEFluxSysts.cxx +++ b/CAFAna/Systs/DUNEFluxSysts.cxx @@ -22,202 +22,205 @@ static ana::NewOffAxisFluxUncertainty2022Helper const *fNewOffAxisFluxUncertaint #include namespace ana { -const DUNEFluxSystVector kFluxSysts = GetDUNEFluxSysts(30); - -//---------------------------------------------------------------------- -DUNEFluxSyst::~DUNEFluxSyst() { - for (int i : {0, 1}) - for (int j : {0, 1}) - for (int k : {0, 1}) - for (int l : {0, 1}) - delete fScale[i][j][k][l]; -} - -//---------------------------------------------------------------------- -void DUNEFluxSyst::Shift(double sigma, - caf::SRProxy *sr, double &weight) const { - - if (abs(sr->nuPDGunosc) == 16) { - return; - } +#ifdef BUILD_FLUX_SYSTS -#ifdef USE_TH2JAGGED - if (fUseCDR) { - std::cout - << "[ERROR]: Off axis flux uncertainties did not exist for the CDR." - << std::endl; - abort(); + const DUNEFluxSystVector kFluxSysts = GetDUNEFluxSysts(30); + + //---------------------------------------------------------------------- + DUNEFluxSyst::~DUNEFluxSyst() { + for (int i : {0, 1}) + for (int j : {0, 1}) + for (int k : {0, 1}) + for (int l : {0, 1}) + delete fScale[i][j][k][l]; } - bool isSpecHCRun(false); - if (std::abs(sr->SpecialHCRunId) != 293) isSpecHCRun = true; + //---------------------------------------------------------------------- + void DUNEFluxSyst::Shift(double sigma, + caf::SRProxy *sr, double &weight) const { - if (sr->OffAxisFluxBin == -1) { - if (fUseSept21) { - sr->OffAxisFluxBin = ana::NewOffAxisFluxUncertainty2022Helper::Get().GetBin( - sr->nuPDGunosc, sr->Ev, sr->abspos_x * 1E-2, fIdx, !sr->isFD, - sr->isFHC, isSpecHCRun); - } else { - sr->OffAxisFluxBin = ana::OffAxisFluxUncertaintyHelper::Get().GetBin( - sr->nuPDGunosc, sr->Ev, sr->abspos_x * 1E-2, 0, !sr->isFD, - sr->isFHC, isSpecHCRun); - } - } + if (abs(sr->nuPDGunosc) == 16) { + return; + } - if (sr->OffAxisFluxConfig == -1) { - if (fUseSept21) { - sr->OffAxisFluxConfig = - ana::NewOffAxisFluxUncertainty2022Helper::Get().GetNuConfig_checked( + #ifdef USE_TH2JAGGED + if (fUseCDR) { + std::cout + << "[ERROR]: Off axis flux uncertainties did not exist for the CDR." + << std::endl; + abort(); + } + + bool isSpecHCRun(false); + if (std::abs(sr->SpecialHCRunId) != 293) isSpecHCRun = true; + + if (sr->OffAxisFluxBin == -1) { + if (fUseSept21) { + sr->OffAxisFluxBin = ana::NewOffAxisFluxUncertainty2022Helper::Get().GetBin( sr->nuPDGunosc, sr->Ev, sr->abspos_x * 1E-2, fIdx, !sr->isFD, - sr->isFHC, isSpecHCRun); - } else { - sr->OffAxisFluxConfig = - ana::OffAxisFluxUncertaintyHelper::Get().GetNuConfig_checked( + sr->isFHC, isSpecHCRun); + } else { + sr->OffAxisFluxBin = ana::OffAxisFluxUncertaintyHelper::Get().GetBin( sr->nuPDGunosc, sr->Ev, sr->abspos_x * 1E-2, 0, !sr->isFD, sr->isFHC, isSpecHCRun); + } } - } - if (fUseSept21) { - weight = fNewOffAxisFluxUncertainty2022Helper->GetFluxWeight( - fIdx, sigma, sr->abspos_x * 1E-2, sr->OffAxisFluxBin, sr->OffAxisFluxConfig); - } else { - weight = fOffAxisFluxParamHelper->GetFluxWeight( - fIdx, sigma, sr->OffAxisFluxBin, sr->OffAxisFluxConfig); - } -#else - if (!fScale[0][0][0][0]) { - std::string InputFileName; - if (fUseCDR) { - // CDROpt flux - InputFileName = "flux_shifts_CDR.root"; + if (sr->OffAxisFluxConfig == -1) { + if (fUseSept21) { + sr->OffAxisFluxConfig = + ana::NewOffAxisFluxUncertainty2022Helper::Get().GetNuConfig_checked( + sr->nuPDGunosc, sr->Ev, sr->abspos_x * 1E-2, fIdx, !sr->isFD, + sr->isFHC, isSpecHCRun); + } else { + sr->OffAxisFluxConfig = + ana::OffAxisFluxUncertaintyHelper::Get().GetNuConfig_checked( + sr->nuPDGunosc, sr->Ev, sr->abspos_x * 1E-2, 0, !sr->isFD, + sr->isFHC, isSpecHCRun); + } + } + + if (fUseSept21) { + weight = fNewOffAxisFluxUncertainty2022Helper->GetFluxWeight( + fIdx, sigma, sr->abspos_x * 1E-2, sr->OffAxisFluxBin, sr->OffAxisFluxConfig); } else { - // Nov17 opt engineered - InputFileName = "flux_shifts_Nov17.root"; + weight = fOffAxisFluxParamHelper->GetFluxWeight( + fIdx, sigma, sr->OffAxisFluxBin, sr->OffAxisFluxConfig); } + #else + if (!fScale[0][0][0][0]) { + std::string InputFileName; + if (fUseCDR) { + // CDROpt flux + InputFileName = "flux_shifts_CDR.root"; + } else { + // Nov17 opt engineered + InputFileName = "flux_shifts_Nov17.root"; + } - TFile f((FindCAFAnaDir() + "/Systs/" + InputFileName).c_str()); - assert(!f.IsZombie()); - - for (int det : {0, 1}) { - const std::string detStr = (det == 0) ? "ND" : "FD"; - for (int pdg : {0, 1}) { - std::string pdgStr = (pdg == 0) ? "nue" : "numu"; - for (bool anti : {false, true}) { - if (anti) - pdgStr += "bar"; - - for (int hc : {0, 1}) { - const std::string hcStr = (hc == 0) ? "FHC" : "RHC"; - - TH1 *&h = fScale[det][pdg][anti][hc]; - - h = (TH1 *)f.Get(TString::Format("syst%d/%s_%s_%s", fIdx, - detStr.c_str(), pdgStr.c_str(), - hcStr.c_str()) - .Data()); - h = (TH1 *)h->Clone(UniqueName().c_str()); - assert(h); - h->SetDirectory(0); + TFile f((FindCAFAnaDir() + "/Systs/" + InputFileName).c_str()); + assert(!f.IsZombie()); + + for (int det : {0, 1}) { + const std::string detStr = (det == 0) ? "ND" : "FD"; + for (int pdg : {0, 1}) { + std::string pdgStr = (pdg == 0) ? "nue" : "numu"; + for (bool anti : {false, true}) { + if (anti) + pdgStr += "bar"; + + for (int hc : {0, 1}) { + const std::string hcStr = (hc == 0) ? "FHC" : "RHC"; + + TH1 *&h = fScale[det][pdg][anti][hc]; + + h = (TH1 *)f.Get(TString::Format("syst%d/%s_%s_%s", fIdx, + detStr.c_str(), pdgStr.c_str(), + hcStr.c_str()) + .Data()); + h = (TH1 *)h->Clone(UniqueName().c_str()); + assert(h); + h->SetDirectory(0); + } } } } - } - } // end if + } // end if - if (abs(sr->nuPDGunosc) == 16) - return; + if (abs(sr->nuPDGunosc) == 16) + return; - double /*const*/ rel_weight = 1; - double const enu = sr->Ev; + double /*const*/ rel_weight = 1; + double const enu = sr->Ev; - const int det = sr->isFD ? 0 : 1; - const int pdg = (abs(sr->nuPDGunosc) == 12) ? 0 : 1; - const int anti = (sr->nuPDGunosc > 0) ? 0 : 1; - const int hc = sr->isFHC ? 0 : 1; + const int det = sr->isFD ? 0 : 1; + const int pdg = (abs(sr->nuPDGunosc) == 12) ? 0 : 1; + const int anti = (sr->nuPDGunosc > 0) ? 0 : 1; + const int hc = sr->isFHC ? 0 : 1; - TH1 *h = fScale[det][pdg][anti][hc]; - assert(h); + TH1 *h = fScale[det][pdg][anti][hc]; + assert(h); - const int bin = h->FindBin(enu); + const int bin = h->FindBin(enu); - if (bin == 0 || bin == h->GetNbinsX() + 1) { - return; - } - rel_weight = h->GetBinContent(bin); + if (bin == 0 || bin == h->GetNbinsX() + 1) { + return; + } + rel_weight = h->GetBinContent(bin); - weight *= 1 + rel_weight * sigma; -#endif -} - -//---------------------------------------------------------------------- -const DUNEFluxSyst *GetDUNEFluxSyst(unsigned int i, bool applyPenalty, - bool useCDR, bool useSept21) { - // Make sure we always give the same one back - static std::vector cache_CDR; - static std::vector cache_Nov17; - - auto c = useCDR ? &cache_CDR : &cache_Nov17; - if (i >= c->size()) { - c->resize(i + 1); - } - if (!c->at(i)) { - c->at(i) = new DUNEFluxSyst(i, applyPenalty, useCDR, useSept21); + weight *= 1 + rel_weight * sigma; + #endif } - return c->at(i); -} -//---------------------------------------------------------------------- -DUNEFluxSystVector GetDUNEFluxSysts(unsigned int N, bool applyPenalty, - bool useCDR, bool useSept21) { + //---------------------------------------------------------------------- + const DUNEFluxSyst *GetDUNEFluxSyst(unsigned int i, bool applyPenalty, + bool useCDR, bool useSept21) { + // Make sure we always give the same one back + static std::vector cache_CDR; + static std::vector cache_Nov17; -#ifdef USE_TH2JAGGED - if (!fOffAxisFluxParamHelper) { - fOffAxisFluxParamHelper = &ana::OffAxisFluxUncertaintyHelper::Get(); - } - if (!fNewOffAxisFluxUncertainty2022Helper) { - fNewOffAxisFluxUncertainty2022Helper = - &ana::NewOffAxisFluxUncertainty2022Helper::Get(); + auto c = useCDR ? &cache_CDR : &cache_Nov17; + if (i >= c->size()) { + c->resize(i + 1); + } + if (!c->at(i)) { + c->at(i) = new DUNEFluxSyst(i, applyPenalty, useCDR, useSept21); + } + return c->at(i); } -#endif - DUNEFluxSystVector ret; - for (unsigned int i = 0; i < N; ++i) { - ret.push_back(GetDUNEFluxSyst(i, applyPenalty, useCDR, useSept21)); - } - return ret; -} - -SystShifts FilterFluxSystShifts(SystShifts shift) { - SystShifts outs; - std::vector fsysts = - ana::GetDUNEFluxSysts(ana::kFluxSysts.size(), true, false, false); - std::vector fsysts_sept21 = - ana::GetDUNEFluxSysts(ana::kFluxSysts.size(), true, false, true); - fsysts.insert(fsysts.end(), fsysts_sept21.begin(), fsysts_sept21.end()); - - for (auto syst : shift.ActiveSysts()) { - if (std::find(fsysts.begin(), fsysts.end(), syst) != fsysts.end()) { - outs.SetShift(syst, shift.GetShift(syst)); + //---------------------------------------------------------------------- + DUNEFluxSystVector GetDUNEFluxSysts(unsigned int N, bool applyPenalty, + bool useCDR, bool useSept21) { + + #ifdef USE_TH2JAGGED + if (!fOffAxisFluxParamHelper) { + fOffAxisFluxParamHelper = &ana::OffAxisFluxUncertaintyHelper::Get(); } + if (!fNewOffAxisFluxUncertainty2022Helper) { + fNewOffAxisFluxUncertainty2022Helper = + &ana::NewOffAxisFluxUncertainty2022Helper::Get(); + } + #endif + + DUNEFluxSystVector ret; + for (unsigned int i = 0; i < N; ++i) { + ret.push_back(GetDUNEFluxSyst(i, applyPenalty, useCDR, useSept21)); + } + return ret; } - return outs; -} - -size_t GetFluxSystIndex(const ana::ISyst *syst) { - std::vector fsysts = - ana::GetDUNEFluxSysts(ana::kFluxSysts.size(), true, false, false); - std::vector fsysts_sept21 = - ana::GetDUNEFluxSysts(ana::kFluxSysts.size(), true, false, true); - fsysts.insert(fsysts.end(), fsysts_sept21.begin(), fsysts_sept21.end()); - - for (size_t i = 0; i < fsysts.size(); ++i) { - if (fsysts[i] == syst) { - return i; + + SystShifts FilterFluxSystShifts(SystShifts shift) { + SystShifts outs; + std::vector fsysts = + ana::GetDUNEFluxSysts(ana::kFluxSysts.size(), true, false, false); + std::vector fsysts_sept21 = + ana::GetDUNEFluxSysts(ana::kFluxSysts.size(), true, false, true); + fsysts.insert(fsysts.end(), fsysts_sept21.begin(), fsysts_sept21.end()); + + for (auto syst : shift.ActiveSysts()) { + if (std::find(fsysts.begin(), fsysts.end(), syst) != fsysts.end()) { + outs.SetShift(syst, shift.GetShift(syst)); + } } + return outs; } - return kNotValidFluxSyst; -} + size_t GetFluxSystIndex(const ana::ISyst *syst) { + std::vector fsysts = + ana::GetDUNEFluxSysts(ana::kFluxSysts.size(), true, false, false); + std::vector fsysts_sept21 = + ana::GetDUNEFluxSysts(ana::kFluxSysts.size(), true, false, true); + fsysts.insert(fsysts.end(), fsysts_sept21.begin(), fsysts_sept21.end()); + for (size_t i = 0; i < fsysts.size(); ++i) { + if (fsysts[i] == syst) { + return i; + } + } + + return kNotValidFluxSyst; + } + +#endif } // namespace ana diff --git a/CAFAna/Systs/DUNEFluxSysts.h b/CAFAna/Systs/DUNEFluxSysts.h index d67bfd9c..591b3cc2 100644 --- a/CAFAna/Systs/DUNEFluxSysts.h +++ b/CAFAna/Systs/DUNEFluxSysts.h @@ -8,58 +8,61 @@ class TH1; class TH2; namespace ana { -class SystShifts; +#ifdef BUILD_FLUX_SYSTS -class DUNEFluxSyst : public ISyst { -public: - virtual ~DUNEFluxSyst(); + class SystShifts; - virtual void Shift(double sigma, caf::SRProxy *sr, - double &weight) const override; + class DUNEFluxSyst : public ISyst { + public: + virtual ~DUNEFluxSyst(); -protected: - friend const DUNEFluxSyst *GetDUNEFluxSyst(unsigned int, bool, bool, bool); - DUNEFluxSyst(int i, bool applyPenalty, bool useCDR, bool useSept21) - : ISyst(TString::Format("flux_%s_%i", - useCDR ? "CDR" : - (useSept21 ? "Sept21" : "Nov17"), i).Data(), - TString::Format("Flux #%i (%s)", i, - useCDR ? "CDR" : - (useSept21 ? "Sept21" : "Nov17")).Data(), - applyPenalty), - fIdx(i), fScale(), fUseCDR(useCDR), fUseSept21(useSept21) {} + virtual void Shift(double sigma, caf::SRProxy *sr, + double &weight) const override; - int fIdx; + protected: + friend const DUNEFluxSyst *GetDUNEFluxSyst(unsigned int, bool, bool, bool); + DUNEFluxSyst(int i, bool applyPenalty, bool useCDR, bool useSept21) + : ISyst(TString::Format("flux_%s_%i", + useCDR ? "CDR" : + (useSept21 ? "Sept21" : "Nov17"), i).Data(), + TString::Format("Flux #%i (%s)", i, + useCDR ? "CDR" : + (useSept21 ? "Sept21" : "Nov17")).Data(), + applyPenalty), + fIdx(i), fScale(), fUseCDR(useCDR), fUseSept21(useSept21) {} - mutable TH1 *fScale[2][2][2][2]; // ND/FD, numu/nue, bar, FHC/RHC + int fIdx; - bool fUseCDR; - bool fUseSept21; -}; + mutable TH1 *fScale[2][2][2][2]; // ND/FD, numu/nue, bar, FHC/RHC -const DUNEFluxSyst *GetDUNEFluxSyst(unsigned int i, bool applyPenalty = true, - bool useCDR = true, bool useSept21 = false); + bool fUseCDR; + bool fUseSept21; + }; -// Because vector won't automatically convert to vector even when U -// inherits from V. -struct DUNEFluxSystVector : public std::vector { - operator std::vector() { - return std::vector(begin(), end()); - } -}; + const DUNEFluxSyst *GetDUNEFluxSyst(unsigned int i, bool applyPenalty = true, + bool useCDR = true, bool useSept21 = false); -DUNEFluxSystVector GetDUNEFluxSysts(unsigned int N, bool applyPenalty = true, - bool useCDR = true, bool useSept21 = false); + // Because vector won't automatically convert to vector even when U + // inherits from V. + struct DUNEFluxSystVector : public std::vector { + operator std::vector() { + return std::vector(begin(), end()); + } + }; -// instantiate them all at global scope so that they can be found in the -// Registry -extern const DUNEFluxSystVector kFluxSysts; + DUNEFluxSystVector GetDUNEFluxSysts(unsigned int N, bool applyPenalty = true, + bool useCDR = true, bool useSept21 = false); -// Given a SystShifts, extract only those that are flux shifts -SystShifts FilterFluxSystShifts(SystShifts); + // instantiate them all at global scope so that they can be found in the + // Registry + extern const DUNEFluxSystVector kFluxSysts; -// Get the index of a given Flux syst -static const size_t kNotValidFluxSyst = std::numeric_limits::max(); -size_t GetFluxSystIndex(const ana::ISyst *syst); + // Given a SystShifts, extract only those that are flux shifts + SystShifts FilterFluxSystShifts(SystShifts); + // Get the index of a given Flux syst + static const size_t kNotValidFluxSyst = std::numeric_limits::max(); + size_t GetFluxSystIndex(const ana::ISyst *syst); + +#endif } // namespace ana diff --git a/CAFAna/Systs/DUNENDSysts.cxx b/CAFAna/Systs/DUNENDSysts.cxx deleted file mode 100644 index f27d43bb..00000000 --- a/CAFAna/Systs/DUNENDSysts.cxx +++ /dev/null @@ -1,7 +0,0 @@ -#include "CAFAna/Systs/DUNENDSysts.h" - -namespace ana -{ - const DUNENDEvSyst kNDEvSyst; - const DUNENDPIDSyst kNDPIDSyst; -} // namespace diff --git a/CAFAna/Systs/DUNENDSysts.h b/CAFAna/Systs/DUNENDSysts.h deleted file mode 100644 index 56a11ca9..00000000 --- a/CAFAna/Systs/DUNENDSysts.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include "CAFAna/Core/ISyst.h" -#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" -#include "CAFAna/Core/Utilities.h" -#include "math.h" - -namespace ana -{ - class DUNENDEvSyst: public ISyst - { - public: - DUNENDEvSyst() : ISyst("NDEv", "Near Detector reco Ev") {} - - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override - { - double scale = pow( 1. + sr->sigma_Ev_reco, sigma ); - sr->Ev_reco *= scale; - sr->Ev_reco_numu *= scale; - sr->Ev_reco_nue *= scale; - } - }; - - extern const DUNENDEvSyst kNDEvSyst; - - class DUNENDPIDSyst: public ISyst - { - public: - DUNENDPIDSyst() : ISyst("NDPID", "Near Detector lepton PID") {} - - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override - { - bool numu = ( sigma > sr->sigma_numu_pid ); - bool nue = ( sigma > sr->sigma_nue_pid ); - - // theoretically it is possible for both to be true in the same event, though this is highly unlikely. - // in these rare cases, use the one with the smaller sigma - if( numu && nue ) { // very rare - if( sr->sigma_numu_pid < sr->sigma_nue_pid ) nue = false; - else numu = false; - } - - if( numu ) { - sr->numu_pid = 1.; - sr->nue_pid = -1.; - } else if( nue ) { - sr->numu_pid = -1.; - sr->nue_pid = 1.; - } else { // NC event - sr->numu_pid = -1.; - sr->nue_pid = -1.; - } - - } - }; - - extern const DUNENDPIDSyst kNDPIDSyst; -} diff --git a/CAFAna/Systs/DUNEXSecSysts.cxx b/CAFAna/Systs/DUNEXSecSysts.cxx index e903216b..edf3416a 100644 --- a/CAFAna/Systs/DUNEXSecSysts.cxx +++ b/CAFAna/Systs/DUNEXSecSysts.cxx @@ -1,10 +1,10 @@ #include "CAFAna/Systs/DUNEXSecSysts.h" +#include "duneanaobj/StandardRecord/Navigate.h" #include "duneanaobj/StandardRecord/Proxy/SRProxy.h" +#include "CAFAna/Core/TruthMatching.h" #include "CAFAna/Core/Utilities.h" -#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" - #include "CAFAna/Core/MathUtil.h" #include "TFile.h" @@ -98,14 +98,15 @@ namespace ana } //---------------------------------------------------------------------- - EVALORCategory GetVALORCategory(const caf::SRProxy* sr) + EVALORCategory GetVALORCategory(const caf::SRInteractionProxy *sr) { - int lep = sr->LepPDG; - int scat = sr->mode; - const int npiz = sr->nipi0; - const int npic = sr->nipip + sr->nipim; - const float Enu = sr->Ev; - const float Q2 = sr->Q2; + const caf::SRTrueInteractionProxy * srtrueint = MatchedTrueInteraction(sr); + int lep = srtrueint->pdg;// this is probs wrong LepPDG; + int scat = srtrueint->mode;//mode; + const int npiz = srtrueint->npi0;//nipi0; + const int npic = srtrueint->npip+srtrueint->npim;//nipip + sr->nipim; + const float Enu = srtrueint->E;//Ev; + const float Q2 = srtrueint->Q2;//Q2; // These are the FD codes // kUnknownMode = -1 @@ -142,7 +143,7 @@ namespace ana // 14 IMD annihilation // Different conventions ND (weird (new?)) and FD (like NOvA) - if(sr->isFD){ + /*if(sr->isFD){ switch(scat){ case 0: scat = 1; break; // QE -> QE case 1: scat = 4; break; // RES -> RES @@ -161,7 +162,7 @@ namespace ana std::cout << "Unhandled GENIE FD code " << scat << std::endl; abort(); } - } + }*/ // Treat nutaus as if they were numus for now if(lep == -16) lep = -14; diff --git a/CAFAna/Systs/DUNEXSecSysts.h b/CAFAna/Systs/DUNEXSecSysts.h index 71083d02..ae3193f4 100644 --- a/CAFAna/Systs/DUNEXSecSysts.h +++ b/CAFAna/Systs/DUNEXSecSysts.h @@ -51,7 +51,7 @@ namespace ana std::string VALORCategoryName(EVALORCategory c); std::string VALORCategoryLatexName(EVALORCategory c); - EVALORCategory GetVALORCategory(const caf::SRProxy* sr); + EVALORCategory GetVALORCategory(const caf::SRInteractionProxy *sr); const Var kVALORCategory(GetVALORCategory); diff --git a/CAFAna/Systs/DUNEXSecSystsPCA.cxx b/CAFAna/Systs/DUNEXSecSystsPCA.cxx index 3e6c141c..34f75442 100644 --- a/CAFAna/Systs/DUNEXSecSystsPCA.cxx +++ b/CAFAna/Systs/DUNEXSecSystsPCA.cxx @@ -24,7 +24,7 @@ namespace ana //---------------------------------------------------------------------- void DUNEXSecSystPCA::Shift(double sigma, - caf::SRProxy* sr, + caf::SRInteractionProxy* sr, double& weight) const { weight *= 1+fCoeffs[GetVALORCategory(sr)]*sigma; diff --git a/CAFAna/Systs/DUNEXSecSystsPCA.h b/CAFAna/Systs/DUNEXSecSystsPCA.h index 93e21b62..42d85d5a 100644 --- a/CAFAna/Systs/DUNEXSecSystsPCA.h +++ b/CAFAna/Systs/DUNEXSecSystsPCA.h @@ -9,7 +9,7 @@ namespace ana { public: virtual void Shift(double sigma, - caf::SRProxy* sr, + caf::SRInteractionProxy* sr, double& weight) const override; protected: diff --git a/CAFAna/Systs/EnergySysts.cxx b/CAFAna/Systs/EnergySysts.cxx deleted file mode 100644 index 12c77b17..00000000 --- a/CAFAna/Systs/EnergySysts.cxx +++ /dev/null @@ -1,435 +0,0 @@ -#include "CAFAna/Systs/EnergySysts.h" - -namespace ana { - - void EnergyScaleFD::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - double scale = .02 * sigma; - if (sr->isFD) { - if (sr->RecoHadEnNue < 0.) sr->RecoHadEnNue = 0.; - if (sr->Ev_reco_nue < 0.) sr->Ev_reco_nue = 0.; - sr->Ev_reco_numu += scale * sr->RecoHadEnNumu; - sr->Ev_reco_nue += scale * sr->RecoHadEnNue; - sr->EVisReco_numu += scale * sr->HadEVisReco_FD; - sr->EVisReco_nue += scale * sr->HadEVisReco_FD; - sr->RecoHadEnNumu *= 1. + scale; - sr->RecoHadEnNue *= 1. + scale; - sr->HadEVisReco_FD*= 1. + scale; - if ( !(sr->isCC==1 && abs(sr->nuPDG) == 14) ) { - sr->Ev_reco_nue += scale * sr->RecoLepEnNue; - sr->EVisReco_nue += scale * sr->RecoLepEnNue; - sr->RecoLepEnNue *= 1. + scale; - } - } - } - - const EnergyScaleFD kEnergyScaleFD; - - void UncorrFDTotSqrt::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - const double scale = .01 * sigma; - if (sr->isFD) { - if (sr->RecoHadEnNue < 0.) sr->RecoHadEnNue = 0.; - sr->Ev_reco_numu += scale*pow(sr->RecoHadEnNumu, 0.5)*sr->RecoHadEnNumu; - sr->Ev_reco_nue += scale*pow(sr->RecoHadEnNue, 0.5)*sr->RecoHadEnNue; - sr->EVisReco_numu += scale*pow(sr->HadEVisReco_FD, 0.5)*sr->HadEVisReco_FD; - sr->EVisReco_nue += scale*pow(sr->HadEVisReco_FD, 0.5)*sr->HadEVisReco_FD; - sr->RecoHadEnNumu += scale*pow(sr->RecoHadEnNumu, 0.5)*sr->RecoHadEnNumu; - sr->RecoHadEnNue += scale*pow(sr->RecoHadEnNue, 0.5)*sr->RecoHadEnNue; - sr->HadEVisReco_FD+= scale*pow(sr->HadEVisReco_FD, 0.5)*sr->HadEVisReco_FD; - if ( !(sr->isCC==1 && abs(sr->nuPDG) == 14) ) { - sr->Ev_reco_nue += scale*pow(sr->RecoLepEnNue, 0.5)*sr->RecoLepEnNue; - sr->EVisReco_nue += scale*pow(sr->RecoLepEnNue, 0.5)*sr->RecoLepEnNue; - sr->RecoLepEnNue += scale*pow(sr->RecoLepEnNue, 0.5)*sr->RecoLepEnNue; - } - } - } - - const UncorrFDTotSqrt kUncorrFDTotSqrt; - - void UncorrFDTotInvSqrt::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - if (sr->isFD) { - if (sr->RecoHadEnNue < 0.) sr->RecoHadEnNue = 0.; - const double scale = .02 * sigma; - sr->Ev_reco_numu += sr->RecoHadEnNumu*scale*pow(sr->RecoHadEnNumu+0.1, -0.5); - sr->Ev_reco_nue += sr->RecoHadEnNue*scale*pow(sr->RecoHadEnNue+0.1, -0.5); - sr->EVisReco_numu += sr->HadEVisReco_FD*scale*pow(sr->HadEVisReco_FD+0.1, -0.5); - sr->RecoHadEnNumu += sr->RecoHadEnNumu*scale*pow(sr->RecoHadEnNumu+0.1, -0.5); - sr->RecoHadEnNue += sr->RecoHadEnNue*scale*pow(sr->RecoHadEnNue+0.1, -0.5); - sr->HadEVisReco_FD+= sr->HadEVisReco_FD*scale*pow(sr->HadEVisReco_FD+0.1, -0.5); - if ( !(sr->isCC==1 && abs(sr->nuPDG) == 14) ) { - sr->Ev_reco_nue += sr->RecoLepEnNue * scale * pow(sr->RecoLepEnNue+0.1, -0.5); - sr->EVisReco_nue += sr->RecoLepEnNue * scale * pow(sr->RecoLepEnNue+0.1, -0.5); - sr->RecoLepEnNue += sr->RecoLepEnNue * scale * pow(sr->RecoLepEnNue+0.1, -0.5); - } - } - } - - const UncorrFDTotInvSqrt kUncorrFDTotInvSqrt; - - void UncorrFDHadSqrt::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - const double scale = .05 * sigma; - if (sr->isFD) { - if (sr->RecoHadEnNue < 0.) sr->RecoHadEnNue = 0.; - if (sr->eRecoP < 0) sr->eRecoP = 0.; - if (sr->eRecoPim < 0) sr->eRecoPim = 0.; - if (sr->eRecoPip < 0) sr->eRecoPip = 0.; - double sumE = sr->eRecoP + sr->eRecoPip + sr->eRecoPim; - double sumEdep = sr->eDepP + sr->eDepPip + sr->eDepPim; - sr->eRecoP += sr->eRecoP * scale * pow(sumE, 0.5); - sr->eRecoPim += sr->eRecoPim * scale * pow(sumE, 0.5); - sr->eRecoPip += sr->eRecoPip * scale * pow(sumE, 0.5); - sr->Ev_reco_numu += sumE * scale * pow(sumE, 0.5); - sr->Ev_reco_nue += sumE * scale * pow(sumE, 0.5); - sr->EVisReco_numu+= sumEdep * scale * pow(sumEdep, 0.5); - sr->EVisReco_numu+= sumEdep * scale * pow(sumEdep, 0.5); - sr->RecoHadEnNumu += sumE * scale * pow(sumE, 0.5); - sr->RecoHadEnNue += sumE * scale * pow(sumE, 0.5); - sr->HadEVisReco_FD+= sumEdep * scale * pow(sumEdep, 0.5); - } - } - - const UncorrFDHadSqrt kUncorrFDHadSqrt; - - void UncorrFDHadInvSqrt::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - const double scale = .05 * sigma; - if (sr->isFD) { - if (sr->RecoHadEnNue < 0.) sr->RecoHadEnNue = 0.; - if (sr->eRecoP < 0) sr->eRecoP = 0.; - if (sr->eRecoPim < 0) sr->eRecoPim = 0.; - if (sr->eRecoPip < 0) sr->eRecoPip = 0.; - double sumE = sr->eRecoP + sr->eRecoPip + sr->eRecoPim; - double sumEdep = sr->eDepP + sr->eDepPip + sr->eDepPim; - sr->Ev_reco_numu += sumE * scale * pow(sumE+0.1, -0.5); - sr->Ev_reco_nue += sumE * scale * pow(sumE+0.1, -0.5); - sr->EVisReco_numu+= sumEdep * scale * pow(sumEdep+0.1, -0.5); - sr->EVisReco_nue+= sumEdep * scale * pow(sumEdep+0.1, -0.5); - sr->eRecoP += sr->eRecoP * scale * pow(sumE+0.1, -0.5); - sr->eRecoPim += sr->eRecoPim * scale * pow(sumE+0.1, -0.5); - sr->eRecoPip += sr->eRecoPip * scale * pow(sumE+0.1, -0.5); - sr->RecoHadEnNumu += sumE * scale * pow(sumE+0.1, -0.5); - sr->RecoHadEnNue += sumE * scale * pow(sumE+0.1, -0.5); - sr->HadEVisReco_FD+= sumEdep * scale * pow(sumEdep+0.1, -0.5); - } - } - - const UncorrFDHadInvSqrt kUncorrFDHadInvSqrt; - - void UncorrFDMuSqrt::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - if (sr->isFD && sr->isCC==1 && abs(sr->nuPDG)==14) { - const double scale = .005 * sigma; - sr->Ev_reco_numu += sr->RecoLepEnNumu * pow(sr->RecoLepEnNumu, 0.5) * scale; - sr->EVisReco_numu += sr->RecoLepEnNumu * pow(sr->RecoLepEnNumu, 0.5) * scale; - sr->RecoLepEnNumu += sr->RecoLepEnNumu * pow(sr->RecoLepEnNumu, 0.5) * scale; - } - } - - const UncorrFDMuSqrt kUncorrFDMuSqrt; - - void UncorrFDMuInvSqrt::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - if (sr->isFD && sr->isCC==1 && abs(sr->nuPDG)==14) { - const double scale = .02 * sigma; - sr->Ev_reco_numu += sr->RecoLepEnNumu * scale * pow(sr->RecoLepEnNumu+0.1, -0.5); - sr->EVisReco_numu += sr->RecoLepEnNumu * scale * pow(sr->RecoLepEnNumu+0.1, -0.5); - sr->RecoLepEnNumu += sr->RecoLepEnNumu * scale * pow(sr->RecoLepEnNumu+0.1, -0.5); - } - } - - const UncorrFDMuInvSqrt kUncorrFDMuInvSqrt; - - void UncorrFDNSqrt::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - const double scale = .3 * sigma; - if (sr->isFD) { - if (sr->eRecoN < 0.) { sr->eRecoN = 0.; } - sr->Ev_reco_numu += sr->eRecoN * pow(sr->eRecoN, 0.5) * scale; - sr->Ev_reco_nue += sr->eRecoN * pow(sr->eRecoN, 0.5) * scale; - sr->RecoHadEnNumu += sr->eRecoN * pow(sr->eRecoN, 0.5) * scale; - sr->RecoHadEnNue += sr->eRecoN * pow(sr->eRecoN, 0.5) * scale; - } - } - - const UncorrFDNSqrt kUncorrFDNSqrt; - - void UncorrFDNInvSqrt::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - const double scale = .3 * sigma; - if (sr->isFD) { - if (sr->eRecoN < 0.) { sr->eRecoN = 0.; } - sr->Ev_reco_numu += sr->eRecoN * scale * pow(sr->eRecoN+0.1, -0.5); - sr->Ev_reco_nue += sr->eRecoN * scale * pow(sr->eRecoN+0.1, -0.5); - sr->RecoHadEnNumu += sr->eRecoN * scale * pow(sr->eRecoN+0.1, -0.5); - sr->RecoHadEnNue += sr->eRecoN * scale * pow(sr->eRecoN+0.1, -0.5); - } - } - - const UncorrFDNInvSqrt kUncorrFDNInvSqrt; - - void UncorrFDEMSqrt::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - const double scale = .025 * sigma; - if (sr->isFD) { - if (sr->RecoHadEnNue < 0.) sr->RecoHadEnNue = 0.; - if (sr->eRecoPi0 < 0) sr->eRecoPi0 = 0.; - sr->Ev_reco_numu += sr->eRecoPi0 * pow(sr->eRecoPi0, 0.5) * scale; - sr->Ev_reco_nue += sr->eRecoPi0 * pow(sr->eRecoPi0, 0.5) * scale; - sr->EVisReco_numu+= sr->eDepPi0 * pow(sr->eDepPi0, 0.5) * scale; - sr->EVisReco_nue += sr->eDepPi0 * pow(sr->eDepPi0, 0.5) * scale; - sr->RecoHadEnNumu += sr->eRecoPi0 * pow(sr->eRecoPi0, 0.5) * scale; - sr->RecoHadEnNue += sr->eRecoPi0 * pow(sr->eRecoPi0, 0.5) * scale; - sr->HadEVisReco_FD+= sr->eDepPi0 * pow(sr->eDepPi0, 0.5) * scale; - sr->eRecoPi0 += sr->eRecoPi0 * pow(sr->eRecoPi0, 0.5) * scale; - if (sr->eRecoPi0 < 0) sr->eRecoPi0 = 0.; - if (sr->isCC==1 && abs(sr->nuPDG)==12) { - sr->Ev_reco_nue += sr->RecoLepEnNue*pow(sr->RecoLepEnNue, 0.5)*scale; - sr->EVisReco_nue += sr->RecoLepEnNue*pow(sr->RecoLepEnNue, 0.5)*scale; - sr->RecoLepEnNue += sr->RecoLepEnNue*pow(sr->RecoLepEnNue, 0.5)*scale; - } - } - } - - const UncorrFDEMSqrt kUncorrFDEMSqrt; - - - void UncorrFDEMInvSqrt::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - const double scale = .025 * sigma; - if (sr->isFD) { - if (sr->RecoHadEnNue < 0.) sr->RecoHadEnNue = 0.; - if (sr->eRecoPi0 < 0) sr->eRecoPi0 = 0.; - sr->Ev_reco_numu += sr->eRecoPi0 * scale * pow(sr->eRecoPi0+0.1, -0.5); - sr->Ev_reco_nue += sr->eRecoPi0 * scale * pow(sr->eRecoPi0+0.1, -0.5); - sr->EVisReco_numu+= sr->eDepPi0 * scale * pow(sr->eDepPi0+0.1, -0.5); - sr->EVisReco_nue += sr->eDepPi0 * scale * pow(sr->eDepPi0+0.1, -0.5); - sr->RecoHadEnNumu += sr->eRecoPi0 * scale * pow(sr->eRecoPi0+0.1, -0.5); - sr->RecoHadEnNue += sr->eRecoPi0 * scale * pow(sr->eRecoPi0+0.1, -0.5); - sr->HadEVisReco_FD+= sr->eDepPi0 * scale * pow(sr->eDepPi0+0.1, -0.5); - sr->eRecoPi0 += sr->eRecoPi0 * scale * pow(sr->eRecoPi0+0.1, -0.5); - if (sr->isCC==1 && abs(sr->nuPDG)==12) { - sr->Ev_reco_nue += sr->RecoLepEnNue * scale * pow(sr->RecoLepEnNue+0.1, -0.5); - sr->EVisReco_nue += sr->RecoLepEnNue * scale * pow(sr->RecoLepEnNue+0.1, -0.5); - sr->RecoLepEnNue += sr->RecoLepEnNue * scale * pow(sr->RecoLepEnNue+0.1, -0.5); - } - } - } - - const UncorrFDEMInvSqrt kUncorrFDEMInvSqrt; - - void EScaleMuLArFD::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - const double scale = .02 * sigma; - // Checks if FD and select only CC muon neutrino events - if(sr->isFD && abs(sr->nuPDG) == 14 && sr->isCC == 1){ - sr->Ev_reco_numu += sr->RecoLepEnNumu * scale; - sr->EVisReco_numu += sr->RecoLepEnNumu * scale; - sr->RecoLepEnNumu *= 1. + scale; - } - } - - const EScaleMuLArFD kEScaleMuLArFD; - - void ChargedHadUncorrFD::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - const double scale = .05 * sigma; - if(sr->isFD) { - if (sr->RecoHadEnNue < 0.) sr->RecoHadEnNue = 0.; - if (sr->eRecoP < 0) sr->eRecoP = 0.; - if (sr->eRecoPim < 0) sr->eRecoPim = 0.; - if (sr->eRecoPip < 0) sr->eRecoPip = 0.; - const double sumE = sr->eRecoP + sr->eRecoPim + sr->eRecoPip; - const double sumEdep = sr->eDepP + sr->eDepPip + sr->eDepPim; - sr->eRecoP += sr->eRecoP * scale; - sr->eRecoPim += sr->eRecoPim * scale; - sr->eRecoPip += sr->eRecoPip * scale; - sr->Ev_reco_numu += sumE * scale; - sr->Ev_reco_nue += sumE * scale; - sr->EVisReco_numu += sumEdep * scale; - sr->EVisReco_nue += sumEdep * scale; - sr->RecoHadEnNumu += sumE * scale; - sr->RecoHadEnNue += sumE * scale; - sr->HadEVisReco_FD += sumEdep * scale; - } - } - - const ChargedHadUncorrFD kChargedHadUncorrFD; - - void NUncorrFD::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - const double scale = .20 * sigma; - if(sr->isFD) { - if (sr->RecoHadEnNue < 0.) sr->RecoHadEnNue = 0.; - if (sr->eRecoN < 0.) sr->eRecoN = 0.; - sr->Ev_reco_numu += sr->eRecoN * scale; - sr->Ev_reco_nue += sr->eRecoN * scale; - sr->RecoHadEnNumu += sr->eRecoN * scale; - sr->RecoHadEnNue += sr->eRecoN * scale; - sr->eRecoN += sr->eRecoN * scale; - } - } - - const NUncorrFD kNUncorrFD; - - void EMUncorrFD::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - const double scale = 0.025 * sigma; - if (sr->isFD) { - if (sr->RecoHadEnNue < 0.) sr->RecoHadEnNue = 0.; - if (sr->eRecoPi0 < 0.) sr->eRecoPi0 = 0.; - sr->Ev_reco_nue += sr->eRecoPi0 * scale; - sr->Ev_reco_numu += sr->eRecoPi0 * scale; - sr->EVisReco_numu += sr->eDepPi0 * scale; - sr->EVisReco_nue += sr->eDepPi0 * scale; - sr->RecoHadEnNue += sr->eRecoPi0 * scale; - sr->RecoHadEnNumu += sr->eRecoPi0 * scale; - sr->HadEVisReco_FD += sr->eDepPi0 * scale; - sr->eRecoPi0 += sr->eRecoPi0 * scale; - if (sr->isCC && abs(sr->nuPDG) == 12) { - sr->Ev_reco_nue += sr->RecoLepEnNue * scale; - sr->EVisReco_nue += sr->RecoLepEnNue * scale; - sr->RecoLepEnNue += sr->RecoLepEnNue * scale; - } - } - } - - const EMUncorrFD kEMUncorrFD; - - void MuonResFD::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - const double scale = .02*sigma; - // FD charged current numus only - if (sr->isFD && sr->isCC && abs(sr->nuPDG)==14) { - sr->Ev_reco_numu += (sr->LepE - sr->RecoLepEnNumu) * scale; - sr->EVisReco_numu += (sr->LepE - sr->RecoLepEnNumu) * scale; - sr->RecoLepEnNumu += (sr->LepE - sr->RecoLepEnNumu) * scale; - } - } - - const MuonResFD kMuonResFD; - - void EMResFD::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - const double scale = .02*sigma; - if (sr->isFD){ - if (sr->RecoHadEnNue < 0.) sr->RecoHadEnNue = 0.; - if (sr->eRecoPi0 < 0.) sr->eRecoPi0 = 0.; - sr->Ev_reco_nue += (sr->ePi0 - sr->eRecoPi0) * scale; - sr->Ev_reco_numu += (sr->ePi0 - sr->eRecoPi0) * scale; - sr->EVisReco_nue += (sr->ePi0 - sr->eDepPi0) * scale; - sr->EVisReco_numu += (sr->ePi0 - sr->eDepPi0) * scale; - sr->RecoHadEnNumu += (sr->ePi0 - sr->eRecoPi0) * scale; - sr->RecoHadEnNue += (sr->ePi0 - sr->eRecoPi0) * scale; - sr->HadEVisReco_FD+= (sr->ePi0 - sr->eDepPi0) * scale; - sr->eRecoPi0 += (sr->ePi0 - sr->eRecoPi0) * scale; - if (sr->isCC && abs(sr->nuPDG)==12) { - sr->Ev_reco_nue += (sr->LepE - sr->RecoLepEnNue) * scale; - sr->EVisReco_nue += (sr->LepE - sr->RecoLepEnNue) * scale; - sr->RecoLepEnNue += (sr->LepE - sr->RecoLepEnNue) * scale; - } - } - } - - const EMResFD kEMResFD; - - void ChargedHadResFD::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - const double scale = .02*sigma; - if (sr->isFD) { - if (sr->RecoHadEnNue < 0.) sr->RecoHadEnNue = 0.; - if (sr->eRecoP < 0.) sr->eRecoP = 0.; - if (sr->eRecoPip < 0.) sr->eRecoPip = 0.; - if (sr->eRecoPim < 0.) sr->eRecoPim = 0.; - const double trueSum = sr->ePip + sr->ePim + sr->eP; - const double recoSum = sr->eRecoPip + sr->eRecoPim + sr->eRecoP; - const double depSum = sr->eDepP + sr->eDepPip + sr->eDepPim; - sr->Ev_reco_nue += (trueSum - recoSum) * scale; - sr->Ev_reco_numu += (trueSum - recoSum) * scale; - sr->EVisReco_nue += (trueSum - depSum) * scale; - sr->EVisReco_numu += (trueSum - depSum) * scale; - sr->RecoHadEnNue += (trueSum - recoSum) * scale; - sr->RecoHadEnNumu += (trueSum - recoSum) * scale; - sr->HadEVisReco_FD+= (trueSum - depSum) * scale; - } - } - - const ChargedHadResFD kChargedHadResFD; - - void NResFD::Shift(double sigma, - caf::SRProxy* sr, double& weight) const { - - const double scale = .1*sigma; - // FD charged current numus only - if (sr->isFD) { - if (sr->RecoHadEnNue < 0.) sr->RecoHadEnNue = 0.; - if (sr->eRecoN < 0.) sr->eRecoN = 0.; - sr->Ev_reco_nue += (sr->eN - sr->eRecoN) * scale; - sr->Ev_reco_numu += (sr->eN - sr->eRecoN) * scale; - sr->RecoHadEnNue += (sr->eN - sr->eRecoN) * scale; - sr->RecoHadEnNumu += (sr->eN - sr->eRecoN) * scale; - sr->eRecoN += (sr->eN - sr->eRecoN) * scale; - } - } - - const NResFD kNResFD; - - std::vector GetEnergySysts() { - - std::vector vec; - vec.push_back(&kEnergyScaleFD); - vec.push_back(&kUncorrFDTotSqrt);//v4 - vec.push_back(&kUncorrFDTotInvSqrt);//v4 - vec.push_back(&kUncorrFDHadSqrt);//v4 - vec.push_back(&kUncorrFDHadInvSqrt);//v4 - vec.push_back(&kUncorrFDMuSqrt);//v4 - vec.push_back(&kUncorrFDMuInvSqrt);//v4 - vec.push_back(&kUncorrFDNSqrt);//v4 - vec.push_back(&kUncorrFDNInvSqrt);//v4 - vec.push_back(&kUncorrFDEMSqrt);//v4 - vec.push_back(&kUncorrFDEMInvSqrt);//v4 - vec.push_back(&kEScaleMuLArFD); - vec.push_back(&kChargedHadUncorrFD);//v4 - vec.push_back(&kNUncorrFD); - vec.push_back(&kEMUncorrFD); - vec.push_back(&kMuonResFD); - vec.push_back(&kEMResFD); - vec.push_back(&kChargedHadResFD); - vec.push_back(&kNResFD); - - return vec; - } - - std::vector FilterOutFDSysts(std::vector systs) { - std::vector outs; - std::vector fsysts = GetEnergySysts(); - - for (auto syst : systs) { - if (std::find(fsysts.begin(), fsysts.end(), syst) == fsysts.end()) { - outs.emplace_back(syst); - } - } - return outs; - } - -} // namespace ana diff --git a/CAFAna/Systs/EnergySysts.h b/CAFAna/Systs/EnergySysts.h deleted file mode 100644 index e434bc44..00000000 --- a/CAFAna/Systs/EnergySysts.h +++ /dev/null @@ -1,233 +0,0 @@ -#pragma once - -#include "CAFAna/Core/ISyst.h" -#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" -#include "CAFAna/Core/Utilities.h" - -#include "TFile.h" -#include "TH1.h" -#include "TRandom3.h" - -#include - -namespace ana -{ - // FD global energy scale syst - // Don't shift muon energies with this - class EnergyScaleFD: public ISyst { - public: - EnergyScaleFD() : ISyst("EnergyScaleFD", "Global FD Energy Scale Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const EnergyScaleFD kEnergyScaleFD; - - // Total energy scale shape systematics - class UncorrFDTotSqrt: public ISyst { - public: - UncorrFDTotSqrt() : ISyst("UncorrFDTotSqrt", "Uncorrelated FD Sqrt Total Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const UncorrFDTotSqrt kUncorrFDTotSqrt; - - class UncorrFDTotInvSqrt: public ISyst { - public: - UncorrFDTotInvSqrt() : ISyst("UncorrFDTotInvSqrt", "Uncorrelated FD Inverse Sqrt Total Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const UncorrFDTotInvSqrt kUncorrFDTotInvSqrt; - - //------------------------------------------------------------------------------------------------ - - // FD three parameter systematics to match ND ones - // Slope energy scale systematics - // Charged hadrons - class UncorrFDHadSqrt: public ISyst { - public: - UncorrFDHadSqrt() : ISyst("UncorrFDHadSqrt", "Uncorrelated FD Sqrt Hadron Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const UncorrFDHadSqrt kUncorrFDHadSqrt; - - class UncorrFDHadInvSqrt: public ISyst { - public: - UncorrFDHadInvSqrt() : ISyst("UncorrFDHadInvSqrt", "Uncorrelated FD Inv Sqrt Hadron Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const UncorrFDHadInvSqrt kUncorrFDHadInvSqrt; - - //------------------------------------------------------------------------------------ - - // Muons - class UncorrFDMuSqrt: public ISyst { - public: - UncorrFDMuSqrt() : ISyst("UncorrFDMuSqrt", "Uncorrelated FD Sqrt Muon Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const UncorrFDMuSqrt kUncorrFDMuSqrt; - - class UncorrFDMuInvSqrt: public ISyst { - public: - UncorrFDMuInvSqrt() : ISyst("UncorrFDMuInvSqrt", "Uncorrelated FD Inv Sqrt Muon Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const UncorrFDMuInvSqrt kUncorrFDMuInvSqrt; - - //------------------------------------------------------------------------------------ - - //Neutrons - - class UncorrFDNSqrt: public ISyst { - public: - UncorrFDNSqrt() : ISyst("UncorrFDNSqrt", "Uncorrelated FD Sqrt Neutron Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const UncorrFDNSqrt kUncorrFDNSqrt; - - class UncorrFDNInvSqrt: public ISyst { - public: - UncorrFDNInvSqrt() : ISyst("UncorrFDNInvSqrt", "Uncorrelated FD Inv Sqrt Neutron Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const UncorrFDNInvSqrt kUncorrFDNInvSqrt; - - //------------------------------------------------------------------------------------ - - // Electromagnetic - class UncorrFDEMSqrt: public ISyst { - public: - UncorrFDEMSqrt() : ISyst("UncorrFDEMSqrt", "Uncorrelated FD Sqrt EM Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const UncorrFDEMSqrt kUncorrFDEMSqrt; - - class UncorrFDEMInvSqrt: public ISyst { - public: - UncorrFDEMInvSqrt() : ISyst("UncorrFDEMInvSqrt", "Uncorrelated FD Inv Sqrt EM Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const UncorrFDEMInvSqrt kUncorrFDEMInvSqrt; - - // FD muon LAr systematic - // 2% on CC numu events - class EScaleMuLArFD: public ISyst { - public: - EScaleMuLArFD() : ISyst("EScaleMuLArFD", "Muon Energy Scale LAr Far Detector") {} - - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const EScaleMuLArFD kEScaleMuLArFD; - - // 5% uncorrelated FD syst for charged hadrons - class ChargedHadUncorrFD: public ISyst { - public: - ChargedHadUncorrFD() : ISyst("ChargedHadUncorrFD", "Charged Hadron Uncorrelated FD Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const ChargedHadUncorrFD kChargedHadUncorrFD; - - // Neutron energy scale - // 20% on visible energy - class NUncorrFD: public ISyst { - public: - NUncorrFD() : ISyst("NUncorrFD", "Neutron Energy Scale FD") {} - - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const NUncorrFD kNUncorrFD; - - // FD systematic correlated for pi0s and electrons - // 2.5% on reco energy for electrons and pi0s - class EMUncorrFD: public ISyst { - public: - EMUncorrFD() : ISyst("EMUncorrFD", "Electromagnetic shower FD Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const EMUncorrFD kEMUncorrFD; - - //////////////////////////////////////////////////////////////////////////////////////////////// - // Resolution systematics - // Muon energy resolution - class MuonResFD: public ISyst { - public: - MuonResFD() : ISyst("MuonResFD", "Muon Far Detector Resolution Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const MuonResFD kMuonResFD; - - // Electron/pi0 energy resolution - class EMResFD: public ISyst { - public: - EMResFD() : ISyst("EMResFD", "EM shower Far Detector Resolution Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const EMResFD kEMResFD; - - // Charged hadron energy resolution - class ChargedHadResFD: public ISyst { - public: - ChargedHadResFD() : ISyst("ChargedHadResFD", "Charged Hadron Far Detector Resolution Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const ChargedHadResFD kChargedHadResFD; - - // Neutron energy resolution - class NResFD: public ISyst { - public: - NResFD() : ISyst("NResFD", "Neutron Far Detector Resolution Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - - extern const NResFD kNResFD; - -/* - /// why have a structure (yet) if not needed - /// make things simpler - // Vector of energy scale systematics - struct EnergySystVector: public std::vector - { - }; - EnergySystVector GetEnergySysts(); -*/ - - std::vector GetEnergySysts(); - - std::vector FilterOutFDSysts(std::vector systs); -} diff --git a/CAFAna/Systs/FDRecoSysts.cxx b/CAFAna/Systs/FDRecoSysts.cxx deleted file mode 100644 index 168c0d01..00000000 --- a/CAFAna/Systs/FDRecoSysts.cxx +++ /dev/null @@ -1,24 +0,0 @@ -#include "CAFAna/Systs/FDRecoSysts.h" -#include "CAFAna/Core/Utilities.h" - -#include "TH2.h" -#include "TFile.h" - -namespace ana { - - const FDRecoNumuSyst kFDRecoNumuSyst; - const FDRecoNueSyst kFDRecoNueSyst; - const FVNumuFDSyst kFVNumuFDSyst; - const FVNueFDSyst kFVNueFDSyst; - - std::vector GetFDRecoSysts() - { - std::vector vec = {}; - vec.push_back(&kFDRecoNumuSyst); - vec.push_back(&kFDRecoNueSyst); - vec.push_back(&kFVNumuFDSyst); - vec.push_back(&kFVNueFDSyst); - return vec; - } - -} diff --git a/CAFAna/Systs/FDRecoSysts.h b/CAFAna/Systs/FDRecoSysts.h deleted file mode 100644 index 85d044fe..00000000 --- a/CAFAna/Systs/FDRecoSysts.h +++ /dev/null @@ -1,151 +0,0 @@ -// FDRecoSysts.h -// Uses genie and neut file kinematic discrepancies to simulate reconstruction inefficiencies -// Use make_FD_reco_systs.C to make the histograms -#pragma once - -#include "CAFAna/Core/ISyst.h" -#include "CAFAna/Core/Utilities.h" -#include "CAFAna/Cuts/AnaCuts.h" - -#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" - -#include "TFile.h" -#include "TH2.h" - -#include - -namespace ana { - - class FDRecoNumuSyst: public ISyst - { - public: - FDRecoNumuSyst() : ISyst("FDRecoNumuSyst", "Far Detector Numu Reconstruction Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override - { - // Load histograms if they have not been loaded already - if (!hist) { - TFile f((FindCAFAnaDir()+"/Systs/modelComp.root").c_str()); - assert(!f.IsZombie()); - hist = (TH2*)f.Get("hYratio_neutfhc_geniefhc"); - hist->SetDirectory(0); - assert(hist); - } - // Passes FD selection cut - if (sr->isFD && kPassFD_CVN_NUMU(sr)) { - int EBin = hist->GetXaxis()->FindBin(sr->Ev); - int VarBin = hist->GetYaxis()->FindBin(sr->Y); - double w = hist->GetBinContent(EBin, VarBin); - weight *= 1. + sigma * (1. - w) ; - } - } - - protected: - mutable TH2* hist; - }; - - extern const FDRecoNumuSyst kFDRecoNumuSyst; - - // Nue reco syst - class FDRecoNueSyst: public ISyst - { - public: - FDRecoNueSyst() : ISyst("FDRecoNueSyst", "Far Detector Nue Reconstruction Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override - { - // Load histograms if they have not been loaded already - if (!hist) { - TFile f((FindCAFAnaDir()+"/Systs/modelComp.root").c_str()); - assert(!f.IsZombie()); - hist = (TH2*)f.Get("hYratio_neutfhc_geniefhc"); - hist->SetDirectory(0); - assert(hist); - } - // Passes FD nue selection - if (sr->isFD && kPassFD_CVN_NUE(sr)) { - int EBin = hist->GetXaxis()->FindBin(sr->Ev); - int VarBin = hist->GetYaxis()->FindBin(sr->Y); - double w = hist->GetBinContent(EBin, VarBin); - weight *= 1. + sigma * (1. - w) ; - } - } - - protected: - mutable TH2* hist; - }; - - extern const FDRecoNueSyst kFDRecoNueSyst; - - // Fiducial volume normalization for nues - class FVNueFDSyst: public ISyst - { - public: - FVNueFDSyst() : ISyst("FVNueFD", "Far Detector Nue Fiducial Volume") {} - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override - { - const double scale = 1. + 0.01 * sigma; - if (sr->isFD && kPassFD_CVN_NUE(sr)) { - weight *= scale; - } - } - }; - - extern const FVNueFDSyst kFVNueFDSyst; - - // Fiducial volume normalization for numus - class FVNumuFDSyst: public ISyst - { - public: - FVNumuFDSyst() : ISyst("FVNumuFD", "Far Detector Numu Fiducial Volume") {} - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override - { - const double scale = 1. + 0.01 * sigma; - if (sr->isFD && kPassFD_CVN_NUMU(sr)) { - weight *= scale; - } - } - }; - - extern const FVNumuFDSyst kFVNumuFDSyst; - - // Fiducial volume normalization - // Correlated between nues and numus - class FVCorrFDSyst: public ISyst - { - public: - FVCorrFDSyst() : ISyst("FVCorrFD", "Far Detector Correlated Fiducial Volume") {} - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override - { - const double scale = 1. + 0.01 * sigma; - if (sr->isFD && (kPassFD_CVN_NUMU(sr) || kPassFD_CVN_NUMU(sr))) { - weight *= scale; - } - } - }; - - extern const FVCorrFDSyst kFVCorrFDSyst; - - -/* - /// why have a structure (yet) if not needed - /// make things simpler - struct FDRecoSystVector: public std::vector - { - }; - FDRecoSystVector GetFDRecoSysts(); -*/ - - std::vector GetFDRecoSysts(); - -} diff --git a/CAFAna/Systs/MissingProtonFakeData.h b/CAFAna/Systs/MissingProtonFakeData.h index d8aae91e..2cd20b51 100644 --- a/CAFAna/Systs/MissingProtonFakeData.h +++ b/CAFAna/Systs/MissingProtonFakeData.h @@ -14,6 +14,8 @@ #include #include +#ifdef BUILD_FDS_SYSTS + class MissingProtonFakeDataGenerator : public ana::ISyst { public: virtual ~MissingProtonFakeDataGenerator(){}; @@ -39,7 +41,7 @@ class MissingProtonFakeDataGenerator : public ana::ISyst { sr->EVisReco_nue -= EpFrac * sr->eDepP; sr->VisTrue_NDFD -= EpFrac * sr->eP; sr->HadEVisReco_FD -= EpFrac * sr->eDepP; - sr->HadE -= EpFrac * sr->eP; + sr->HadE -= EpFrac * sr->eP; } else { sr->eRec_FromDep -= EpFrac * sr->eRecoP; sr->EVisReco_ND -= EpFrac * sr->eRecoP; @@ -111,3 +113,5 @@ class MissingProtonFakeDataGenerator : public ana::ISyst { } double EpFrac; }; + +#endif // BUILD_FDS_SYSTS \ No newline at end of file diff --git a/CAFAna/Systs/NDRecoSysts.cxx b/CAFAna/Systs/NDRecoSysts.cxx deleted file mode 100644 index 1f48301a..00000000 --- a/CAFAna/Systs/NDRecoSysts.cxx +++ /dev/null @@ -1,101 +0,0 @@ -#include "CAFAna/Systs/NDRecoSysts.h" - -#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" -#include "CAFAna/Core/Utilities.h" - -#include "TFile.h" -#include "TH1.h" -#include "TH2.h" - -#include - -namespace ana -{ - const RecoNCSyst kRecoNCSyst; - const LeptonAccSyst kLeptonAccSyst; - const HadronAccSyst kHadronAccSyst; - const FVNumuNDSyst kFVNumuNDSyst; - - //---------------------------------------------------------------------- - void RecoNCSyst::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const - { - // Is ND - if(!sr->isFD) { - // CC event selection but is NC - /*if((sr->reco_numu || sr->reco_nue) && (sr->muon_contained || sr->muon_tracker) && (sr->reco_q == -1 || sr->reco_q == 1) && sr->Ehad_veto<30 && !sr->isCC) { - weight *= 1 + .2*sigma; - }*/ - if((sr->reco_numu || sr->reco_nue) && (sr->muon_contained || sr->muon_tracker) && sr->Ehad_veto<30 && !sr->isCC) { - weight *= 1 + .2*sigma; - } - } - } - - //---------------------------------------------------------------------- - void LeptonAccSyst::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const - { - // Load hist if it hasn't been loaded already - const double m_mu = 0.105658; - if (!fHist) { - #ifdef USE_FQ_HARDCODED_SYST_PATHS - TFile f("/app/users/marshalc/ND_syst/ND_eff_syst.root", "read"); - #else - TFile f((FindCAFAnaDir()+"/Systs/ND_eff_syst.root").c_str()); - #endif - assert(!f.IsZombie()); - fHist = (TH2*)f.Get("unc"); - fHist->SetDirectory(0); - } - - // Is ND and is a true numu CC event - if (!sr->isFD && sr->isCC && abs(sr->nuPDG) == 14) { - double LepE = sr->LepE; - int bin = fHist->FindBin(sqrt(LepE*LepE - m_mu*m_mu) * cos(sr->LepNuAngle), sqrt(LepE*LepE - m_mu*m_mu) * sin(sr->LepNuAngle)); - double w = fHist->GetBinContent(bin); - weight *= 1. + w*sigma; - } - } - - //---------------------------------------------------------------------- - void HadronAccSyst::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const - { - // Load hist if it hasn't been loaded already - if (!fHist) { - #ifdef USE_FQ_HARDCODED_SYST_PATHS - TFile f("/app/users/marshalc/ND_syst/ND_eff_syst.root", "read"); - #else - TFile f((FindCAFAnaDir()+"/Systs/ND_eff_syst.root").c_str()); - #endif - assert(!f.IsZombie()); - fHist = (TH1*)f.Get("hunc"); - fHist->SetDirectory(0); - } - - // Is ND - if (!sr->isFD) { - double HadE = sr->Ev - sr->LepE; - if (HadE > 5.) { - HadE = 5.; - } - int bin = fHist->FindBin(HadE); - double w = fHist->GetBinContent(bin); - weight *= 1. + w*sigma; - } - } - - //---------------------------------------------------------------------- - std::vector GetNDRecoSysts() - { - std::vector vec; - vec.push_back(&kRecoNCSyst); - vec.push_back(&kFVNumuNDSyst); - return vec; - } - -} diff --git a/CAFAna/Systs/NDRecoSysts.h b/CAFAna/Systs/NDRecoSysts.h deleted file mode 100644 index fc1d20c4..00000000 --- a/CAFAna/Systs/NDRecoSysts.h +++ /dev/null @@ -1,83 +0,0 @@ -// NDRecoSysts.h -// Systematics to simulate reconstruction systematics in the ND -#pragma once - -#include "CAFAna/Core/ISyst.h" -#include "CAFAna/Cuts/AnaCuts.h" - -#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" - -#include - -class TH1; -class TH2; - -namespace ana -{ - /// Take ND events which pass the CC selection cuts but are NC and reweight - /// by 20% - class RecoNCSyst: public ISyst - { - public: - RecoNCSyst() : ISyst("RecoNCSyst", "ND Neutral Current Reconstruction Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - }; - extern const RecoNCSyst kRecoNCSyst; - - /// Systematic designed to mimic effect of lepton acceptance in the ND - class LeptonAccSyst: public ISyst - { - public: - LeptonAccSyst() : ISyst("LeptonAccSyst", "ND Lepton Acceptance Syst"), fHist(0) {} - - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - protected: - mutable TH2* fHist; - }; - extern const LeptonAccSyst kLeptonAccSyst; - - /// Systematic designed to mimic effect of hadron acceptance in the ND - class HadronAccSyst: public ISyst - { - public: - HadronAccSyst() : ISyst("HadronAccSyst", "ND Hadron Acceptance Syst"), fHist(0) {} - - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - protected: - mutable TH1* fHist; - }; - extern const HadronAccSyst kHadronAccSyst; - - // Fiducial volume normalization for numus - class FVNumuNDSyst: public ISyst - { - public: - FVNumuNDSyst() : ISyst("FVNumuND", "Near Detector Numu Fiducial Volume") {} - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override - { - const double scale = 1. + 0.01 * sigma; - if (!sr->isFD && (kPassND_FHC_NUMU(sr) || kPassND_RHC_NUMU(sr))) { - weight *= scale; - } - } - }; - - extern const FVNumuNDSyst kFVNumuNDSyst; - -/* - /// why have a structure (yet) if not needed - /// make things simpler - struct NDRecoSystVector: public std::vector - { - }; - NDRecoSystVector GetNDRecoSysts(); -*/ - - std::vector GetNDRecoSysts(); - -} diff --git a/CAFAna/Systs/NuOnESysts.cxx b/CAFAna/Systs/NuOnESysts.cxx deleted file mode 100644 index 6ee02a60..00000000 --- a/CAFAna/Systs/NuOnESysts.cxx +++ /dev/null @@ -1,17 +0,0 @@ -#include "CAFAna/Systs/NuOnESysts.h" - -namespace ana { - const NuOnECCBkgSyst kNuOnECCBkgSyst; - const NuOnENCBkgSyst kNuOnENCBkgSyst; - const NuOnERecoEffSyst kNuOnERecoEffSyst; - - std::vector GetNuOnESysts() - { - std::vector vec; - vec.push_back(&kNuOnECCBkgSyst); - vec.push_back(&kNuOnENCBkgSyst); - vec.push_back(&kNuOnERecoEffSyst); - return vec; - } - -} diff --git a/CAFAna/Systs/NuOnESysts.h b/CAFAna/Systs/NuOnESysts.h deleted file mode 100644 index d0b2d0b9..00000000 --- a/CAFAna/Systs/NuOnESysts.h +++ /dev/null @@ -1,85 +0,0 @@ -// NuOnESysts.h -// Systematics specific to neutrino-electron scattering samples -#pragma once - -#include "CAFAna/Core/ISyst.h" -#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" -#include "CAFAna/Core/Utilities.h" - -#include - -namespace ana { - - // Expect ~20% shape uncertainty on nu_e CC background to nu+e --> nu+e - class NuOnECCBkgSyst: public ISyst - { - public: - NuOnECCBkgSyst() : ISyst("NuOnECCBkgSyst", "nu_e CC background to nu+e") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override - { - if(!sr->isFD) { // ND only - // apply unc. only to nu_e CC background, not NC gamma background - if( (sr->nuPDG == 12 || sr->nuPDG == -12) && sr->isCC && sr->mode != 7 ) { - // apply it to everything? or just selected? - //double reco_ehad = sr->Ehad_veto; // re-using this variable for "extra energy" cut in nu+e - //double eth2 = sr->Elep_reco * sr->Elep_reco * sr->reco_theta; // E * theta^2 - //if( sr->reco_nue && reco_ehad < 20. && eth2 < 0.002 ) { - weight *= (1 + .2*sigma); // 20% uncertainty on shape (norm is constrained by sideband) - } - } - } - }; - extern const NuOnECCBkgSyst kNuOnECCBkgSyst; - - // Expect ~20% shape uncertainty on nu_e CC background to nu+e --> nu+e - class NuOnENCBkgSyst: public ISyst - { - public: - NuOnENCBkgSyst() : ISyst("NuOnENCBkgSyst", "NC pi0 background to nu+e") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override - { - if(!sr->isFD) { // ND only - // apply unc. only to NC gamma background (and not nu-on-e) - if( !sr->isCC && sr->mode != 7) { - // apply it to everything? or just selected? - //double reco_ehad = sr->Ehad_veto; // re-using this variable for "extra energy" cut in nu+e - //double eth2 = sr->Elep_reco * sr->Elep_reco * sr->reco_theta; // E * theta^2 - //if( sr->reco_nue && reco_ehad < 20. && eth2 < 0.002 ) { - weight *= (1 + .1*sigma); // 10% uncertainty on shape (norm is constrained by sideband) - } - } - } - }; - extern const NuOnENCBkgSyst kNuOnENCBkgSyst; - - // Signal reconstruction efficiency systematic - class NuOnERecoEffSyst: public ISyst - { - public: - NuOnERecoEffSyst() : ISyst("NuOnERecoEffSyst", "nu+e signal reconstruction") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override - { - if(!sr->isFD) { // ND only - if( sr->mode == 7 ) { - weight *= (1 + 0.01*sigma); // 1% uncertainty on reco eff - } - } - } - }; - extern const NuOnERecoEffSyst kNuOnERecoEffSyst; - -/* - /// why have a structure (yet) if not needed - /// make things simpler - struct NuOnESystVector: public std::vector - { - }; - NuOnESystVector GetNuOnESysts(); -*/ - - std::vector GetNuOnESysts(); - -} diff --git a/CAFAna/Systs/NuWroReweightFakeData.cxx b/CAFAna/Systs/NuWroReweightFakeData.cxx index 9b3feef5..3a11cc1a 100644 --- a/CAFAna/Systs/NuWroReweightFakeData.cxx +++ b/CAFAna/Systs/NuWroReweightFakeData.cxx @@ -14,6 +14,8 @@ #include #include +#ifdef BUILD_FDS_SYSTS + NuWroReweightFakeDataGenerator::NuWroReweightFakeDataGenerator() : ana::ISyst("NuWroReweightFakeDataGenerator", "NuWroReweightFakeDataGenerator", false, 0, 1) @@ -38,10 +40,10 @@ void NuWroReweightFakeDataGenerator::Shift(double sigma, caf::SRProxy* sr, double& weight) const { - if(!sr->isCC) return; // only reweight CC's + if(!sr->mc.nu[0].iscc /*isCC*/) return; // only reweight CC's // To be on the safe side. BDT does not know about taus. - if(abs(sr->nuPDG) == 16) return; + if(abs(sr->mc.nu[0].pdg /*nuPDG*/) == 16) return; // Reweighting only applied up to 8 GeV if(sr->Ev > 8.) return; @@ -148,3 +150,5 @@ void NuWroReweightFakeDataGenerator::Shift(double sigma, } } + +#endif // BUILD_FDS_SYSTS \ No newline at end of file diff --git a/CAFAna/Systs/NuWroReweightFakeData.h b/CAFAna/Systs/NuWroReweightFakeData.h index 3fcf17c7..fbddfecc 100644 --- a/CAFAna/Systs/NuWroReweightFakeData.h +++ b/CAFAna/Systs/NuWroReweightFakeData.h @@ -9,6 +9,8 @@ #include +#ifdef BUILD_FDS_SYSTS + class NuWroReweightFakeDataGenerator : public ana::ISyst { public: NuWroReweightFakeDataGenerator(); @@ -22,3 +24,5 @@ class NuWroReweightFakeDataGenerator : public ana::ISyst { std::vector bdt_reweighters; }; + +#endif // BUILD_FDS_SYSTS \ No newline at end of file diff --git a/CAFAna/Systs/RecoEnergyNDSysts.cxx b/CAFAna/Systs/RecoEnergyNDSysts.cxx deleted file mode 100644 index cb52776a..00000000 --- a/CAFAna/Systs/RecoEnergyNDSysts.cxx +++ /dev/null @@ -1,355 +0,0 @@ -#include "CAFAna/Systs/RecoEnergyNDSysts.h" - -#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" - -namespace ana { - - void RecoEnergyScaleND::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const { - - const double scale = 0.02 * sigma; - if (!sr->isFD) { - // To match FD: - // Whether NC or CC, Numu or Nue, we want to shift total "reconstructed neutrino energy" - // by the "reconstructed hadronic energy". - sr->EVisReco_ND += (sr->EVisReco_ND - sr->Elep_reco) * scale; - // Also shift the hadronic energy variable, if we don't do this then shifted - // plots of the reconstructed hadronic energy will not be different to nominal. - sr->HadEVisReco_ND *= 1. + scale; - // If it isn't Numu-CC, also shift the "reconstructed neutrino energy" by the - // "reconstructed leptonic energy". - // Also shift the reconstructed leptonic energy itself. - if (!(sr->isCC && abs(sr->nuPDG) == 14)) { - sr->EVisReco_ND += sr->Elep_reco * scale; - sr->Elep_reco *= 1. + scale; - } - } - } - - const RecoEnergyScaleND kRecoEnergyScaleND; - - void RecoEnergySqrtND::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const { - - const double scale = 0.01 * sigma; - if (!sr->isFD) { - // To match LBL TDR: - // Whether NC or CC, Numu or Nue, we want to shift total "reconstructed neutrino energy" - // by the "reconstructed hadronic energy". - sr->EVisReco_ND += (sr->EVisReco_ND - sr->Elep_reco) * scale * - pow((sr->EVisReco_ND - sr->Elep_reco), 0.5); - // Also shift the hadronic energy variable, if we don't do this then shifted - // plots of the reconstructed hadronic energy will not be different to nominal. - sr->HadEVisReco_ND += sr->HadEVisReco_ND * scale * pow(sr->HadEVisReco_ND, 0.5); - // If it isn't Numu-CC, also shift the "reconstructed neutrino energy" by the - // "reconstructed leptonic energy". - // Also shift the reconstructed leptonic energy itself. - if (!(sr->isCC && abs(sr->nuPDG) == 14)) { - sr->EVisReco_ND += sr->Elep_reco * scale * pow(sr->Elep_reco, 0.5); - sr->Elep_reco += sr->Elep_reco * scale * pow(sr->Elep_reco, 0.5); - } - } - } - - const RecoEnergySqrtND kRecoEnergySqrtND; - - void RecoEnergyInvSqrtND::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const { - - const double scale = 0.02 * sigma; - if (!sr->isFD) { - // To match LBL TDR: - // Whether NC or CC, Numu or Nue, we want to shift total "reconstructed neutrino energy" - // by the "reconstructed hadronic energy". - sr->EVisReco_ND += (sr->EVisReco_ND - sr->Elep_reco) * scale * - pow((sr->EVisReco_ND - sr->Elep_reco+0.1), -0.5); - // Also shift the hadronic energy variable, if we don't do this then shifted - // plots of the reconstructed hadronic energy will not be different to nominal. - sr->HadEVisReco_ND += sr->HadEVisReco_ND * scale * pow(sr->HadEVisReco_ND+0.1, -0.5); - // If it isn't Numu-CC, also shift the "reconstructed neutrino energy" by the - // "reconstructed leptonic energy". - // Also shift the reconstructed leptonic energy itself. - if (!(sr->isCC && abs(sr->nuPDG) == 14)) { - sr->EVisReco_ND += sr->Elep_reco * scale * pow(sr->Elep_reco+0.1, -0.5); - sr->Elep_reco += sr->Elep_reco * scale * pow(sr->Elep_reco+0.1, -0.5); - } - } - } - - const RecoEnergyInvSqrtND kRecoEnergyInvSqrtND; - - - void EMRecoUncorrND::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const { - - const double scale = 0.025 * sigma; - if (!sr->isFD) { // in the ND - sr->eRecoPi0 += sr->eRecoPi0 * scale; - sr->EVisReco_ND += sr->eRecoPi0 * scale; - if (sr->isCC && abs(sr->nuPDG) == 12) { - sr->Elep_reco += sr->Elep_reco * scale; - sr->EVisReco_ND += sr->Elep_reco * scale; - } - } - } - - const EMRecoUncorrND kEMRecoUncorrND; - - void EMRecoUncorrSqrtND::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const { - - const double scale = 0.025 * sigma; - if (!sr->isFD) { // in the ND - sr->eRecoPi0 += sr->eRecoPi0 * scale * pow(sr->eRecoPi0, 0.5); - sr->EVisReco_ND += sr->eRecoPi0 * scale * pow(sr->eRecoPi0, 0.5); - if (sr->isCC && abs(sr->nuPDG) == 12) { - sr->Elep_reco += sr->Elep_reco * scale * pow(sr->Elep_reco, 0.5); - sr->EVisReco_ND += sr->Elep_reco * scale * pow(sr->Elep_reco, 0.5); - } - } - } - - const EMRecoUncorrSqrtND kEMRecoUncorrSqrtND; - - void EMRecoUncorrInvSqrtND::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const { - - const double scale = 0.025 * sigma; - if (!sr->isFD) { // in the ND - sr->eRecoPi0 += sr->eRecoPi0 * scale * pow(sr->eRecoPi0+0.1, -0.5); - sr->EVisReco_ND += sr->eRecoPi0 * scale * pow(sr->eRecoPi0+0.1, -0.5); - if (sr->isCC && abs(sr->nuPDG) == 12) { - sr->Elep_reco += sr->Elep_reco * scale * pow(sr->Elep_reco+0.1, -0.5); - sr->EVisReco_ND += sr->Elep_reco * scale * pow(sr->Elep_reco+0.1, -0.5); - } - } - } - - const EMRecoUncorrInvSqrtND kEMRecoUncorrInvSqrtND; - - void ChargedHadRecoUncorrND::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const { - - const double scale = 0.05 * sigma; - if (!sr->isFD) { // in the ND - if (sr->eRecoP < 0) sr->eRecoP = 0.; - if (sr->eRecoPim < 0) sr->eRecoPim = 0.; - if (sr->eRecoPip < 0) sr->eRecoPip = 0.; - const double sumE = sr->eRecoP + sr->eRecoPim + sr->eRecoPip; - sr->eRecoPip += sr->eRecoPip * scale; - sr->eRecoPim += sr->eRecoPim * scale; - sr->eRecoP += sr->eRecoP * scale; - sr->EVisReco_ND += sumE * scale; - sr->HadEVisReco_ND += sumE * scale; - } - } - - const ChargedHadRecoUncorrND kChargedHadRecoUncorrND; - - void ChargedHadRecoUncorrSqrtND::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const { - - const double scale = 0.05 * sigma; - if (!sr->isFD) { // in the ND - if (sr->eRecoP < 0) sr->eRecoP = 0.; - if (sr->eRecoPim < 0) sr->eRecoPim = 0.; - if (sr->eRecoPip < 0) sr->eRecoPip = 0.; - const double sumE = sr->eRecoPip + sr->eRecoPim + sr->eRecoP; - sr->eRecoPip += sr->eRecoPip * scale * pow(sr->eRecoPip, 0.5); - sr->eRecoPim += sr->eRecoPim * scale * pow(sr->eRecoPim, 0.5); - sr->eRecoP += sr->eRecoP * scale * pow(sr->eRecoP, 0.5); - sr->EVisReco_ND += sumE * scale * pow(sumE, 0.5); - sr->HadEVisReco_ND += sumE * scale * pow(sumE, 0.5); - } - } - - const ChargedHadRecoUncorrSqrtND kChargedHadRecoUncorrSqrtND; - - void ChargedHadRecoUncorrInvSqrtND::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const { - - const double scale = 0.05 * sigma; - if (!sr->isFD) { // in the ND - if (sr->eRecoP < 0) sr->eRecoP = 0.; - if (sr->eRecoPim < 0) sr->eRecoPim = 0.; - if (sr->eRecoPip < 0) sr->eRecoPip = 0.; - const double sumE = sr->eRecoPip + sr->eRecoPim + sr->eRecoP; - sr->eRecoPip += sr->eRecoPip * scale * pow(sr->eRecoPip+0.1, -0.5); - sr->eRecoPim += sr->eRecoPim * scale * pow(sr->eRecoPim+0.1, -0.5); - sr->eRecoP += sr->eRecoP * scale * pow(sr->eRecoP+0.1, -0.5); - sr->EVisReco_ND += sumE * scale * pow(sumE+0.1, -0.5); - sr->HadEVisReco_ND += sumE * scale * pow(sumE+0.1, -0.5); - } - } - - const ChargedHadRecoUncorrInvSqrtND kChargedHadRecoUncorrInvSqrtND; - - void ERecoScaleMuLArND::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const { - - // Different EScale uncertainty for reconstruction by range or in - // GAr tracker - double var(0); - if (sr->muon_contained) var = 0.02; - else if (sr->muon_tracker) var = 0.01; - else var = 0.02; // selection requires muon to be inLAr or GAr so never get here - const double scale = var * sigma; - if (!sr->isFD) { // in the ND - if (sr->isCC && abs(sr->nuPDG) == 14) { - sr->Elep_reco += sr->Elep_reco * scale; - sr->EVisReco_ND += sr->Elep_reco * scale; - } - } - } - - const ERecoScaleMuLArND kERecoScaleMuLArND; - - void ERecoScaleMuLArSqrtND::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const { - - double var(0); - if (sr->muon_contained) var = 0.02; - else if (sr->muon_tracker) var = 0.01; - else var = 0.02; // selection requires muon to be inLAr or GAr so never get here - const double scale = var * sigma; // is 0.005 in FD - if (!sr->isFD) { // in the ND - if (sr->isCC && abs(sr->nuPDG) == 14) { - sr->Elep_reco += sr->Elep_reco * scale * pow(sr->Elep_reco, 0.5); - sr->EVisReco_ND += sr->Elep_reco * scale * pow(sr->Elep_reco, 0.5); - } - } - } - - const ERecoScaleMuLArSqrtND kERecoScaleMuLArSqrtND; - - void ERecoScaleMuLArInvSqrtND::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const { - - double var(0); - if (sr->muon_contained) var = 0.02; - else if (sr->muon_tracker) var = 0.01; - else var = 0.02; // selection requires muon to be inLAr or GAr so never get here - const double scale = var * sigma; - if (!sr->isFD) { // in the ND - if (sr->isCC && abs(sr->nuPDG) == 14) { - sr->Elep_reco += sr->Elep_reco * scale * pow(sr->Elep_reco+0.1, -0.5); - sr->EVisReco_ND += sr->Elep_reco * scale * pow(sr->Elep_reco+0.1, -0.5); - } - } - } - - const ERecoScaleMuLArInvSqrtND kERecoScaleMuLArInvSqrtND; - - // Resolution Syst - - void MuonRecoResND::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const { - - const double scale = 0.02 * sigma; - if (!sr->isFD) { // in the ND - sr->Elep_reco += (sr->LepE - sr->Elep_reco) * scale; - sr->EVisReco_ND += (sr->LepE - sr->Elep_reco) * scale; - } - } - - const MuonRecoResND kMuonRecoResND; - - void EMRecoResND::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const { - - const double scale = .02*sigma; - if (!sr->isFD){ - sr->EVisReco_ND += (sr->ePi0 - sr->eRecoPi0) * scale; - sr->eRecoPi0 += (sr->ePi0 - sr->eRecoPi0) * scale; - if (sr->isCC && abs(sr->nuPDG)==12) { - sr->EVisReco_ND += (sr->LepE - sr->Elep_reco) * scale; - sr->Elep_reco += (sr->LepE - sr->Elep_reco) * scale; - } - } - } - - const EMRecoResND kEMRecoResND; - - - void ChargedHadRecoResND::Shift(double sigma, - caf::SRProxy* sr, - double& weight) const { - - const double scale = .02*sigma; - if (!sr->isFD) { - if (sr->eRecoP < 0.) sr->eRecoP = 0.; - if (sr->eRecoPip < 0.) sr->eRecoPip = 0.; - if (sr->eRecoPim < 0.) sr->eRecoPim = 0.; - const double trueSum = sr->ePip + sr->ePim + sr->eP; - const double recoSum = sr->eRecoPip + sr->eRecoPim + sr->eRecoP; - sr->eRecoPip += (sr->ePip - sr->eRecoPip) * scale; - sr->eRecoPim += (sr->ePim - sr->eRecoPim) * scale; - sr->eRecoP += (sr->eP - sr->eRecoP) * scale; - sr->EVisReco_ND += (trueSum - recoSum) * scale; - sr->HadEVisReco_ND += (trueSum - recoSum) * scale; - } - } - - const ChargedHadRecoResND kChargedHadRecoResND; - - RecoEnergyNDSystVector GetRecoENDSysts() { - - RecoEnergyNDSystVector vec; - vec.push_back(&kRecoEnergyScaleND); - vec.push_back(&kRecoEnergySqrtND); - vec.push_back(&kRecoEnergyInvSqrtND); - vec.push_back(&kEMRecoUncorrND); - vec.push_back(&kEMRecoUncorrSqrtND); - vec.push_back(&kEMRecoUncorrInvSqrtND); - vec.push_back(&kChargedHadRecoUncorrND); - vec.push_back(&kChargedHadRecoUncorrSqrtND); - vec.push_back(&kChargedHadRecoUncorrInvSqrtND); - vec.push_back(&kERecoScaleMuLArND); - vec.push_back(&kERecoScaleMuLArSqrtND); - vec.push_back(&kERecoScaleMuLArInvSqrtND); - vec.push_back(&kMuonRecoResND); - vec.push_back(&kEMRecoResND); - vec.push_back(&kChargedHadRecoResND); - - return vec; - } - - bool IsNDdetRecoSyst(std::string name) { - - std::vector syst_names; - for (const auto &syst : GetRecoENDSysts()) { - syst_names.emplace_back(syst->ShortName()); - } - - return (std::find(syst_names.begin(), - syst_names.end(), name) != - syst_names.end()); - } - - std::vector FilterOutNDSysts(std::vector systs) { - std::vector outs; - std::vector fsysts = GetRecoENDSysts(); - - for (auto syst : systs) { - if (std::find(fsysts.begin(), fsysts.end(), syst) == fsysts.end()) { - outs.emplace_back(syst); - } - } - return outs; - } -} - diff --git a/CAFAna/Systs/RecoEnergyNDSysts.h b/CAFAna/Systs/RecoEnergyNDSysts.h deleted file mode 100644 index 8ac7bf4a..00000000 --- a/CAFAna/Systs/RecoEnergyNDSysts.h +++ /dev/null @@ -1,248 +0,0 @@ -#pragma once - -#include "CAFAna/Core/ISyst.h" -#include "CAFAna/Core/Utilities.h" -#include "CAFAna/Cuts/AnaCuts.h" - -#include "duneanaobj/StandardRecord/Proxy/FwdDeclare.h" - -#include "TFile.h" -#include "TH1.h" -#include "TRandom3.h" - -#include -#include -#include -#include - -// Implement ND energy scale uncertainties on truth information -// for use in eRecProxy -// LepE, eP, ePip, ePim, ePi0, eother -class TH1; -class TH2; - -namespace ana -{ - class SystShifts; - - class RecoEnergyScaleND : public ISyst { - public: - RecoEnergyScaleND() : ISyst("RecoEnergyScaleND", "Global Reco Energy Scale ND Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override; - - }; - - extern const RecoEnergyScaleND kRecoEnergyScaleND; - - // Total energy scale syst varying with sqrt of the energy - class RecoEnergySqrtND: public ISyst { - public: - RecoEnergySqrtND() : ISyst("RecoEnergySqrtND", "Sqrt Reco Energy Scale ND Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override; - - }; - - extern const RecoEnergySqrtND kRecoEnergySqrtND; - - // Total energy scale syst varying with inverse sqrt of the energy - class RecoEnergyInvSqrtND: public ISyst { - public: - RecoEnergyInvSqrtND() : ISyst("RecoEnergyInvSqrtND", "Inv Sqrt Total Energy Scale ND Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override; - - }; - - extern const RecoEnergyInvSqrtND kRecoEnergyInvSqrtND; - - //------------------------------------------------------------------------------ - // Electromagnetic - - // Systematic for pi0s and electrons - // 2.5% on true energy of electrons and pi0s - class EMRecoUncorrND : public ISyst { - public: - EMRecoUncorrND() : ISyst("EMRecoUncorrND", "EM Shower Uncorrelated ND Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override; - - }; - - extern const EMRecoUncorrND kEMRecoUncorrND; - - // 2.5% systematic on EM energy for sqrt parameter - // - class EMRecoUncorrSqrtND : public ISyst { - public: - EMRecoUncorrSqrtND() : ISyst("EMRecoUncorrSqrtND", "EM Shower Uncorrelated ND Syst Sqrt") {} - - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override; - - }; - - extern const EMRecoUncorrSqrtND kEMRecoUncorrSqrtND; - - // 2.5% syst on EM energy for inv sqrt param - // - class EMRecoUncorrInvSqrtND : public ISyst { - public: - EMRecoUncorrInvSqrtND() : ISyst("EMRecoUncorrInvSqrtND", "EM Shower Uncorrelated ND Syst Inv Sqrt") {} - - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override; - - }; - - extern const EMRecoUncorrInvSqrtND kEMRecoUncorrInvSqrtND; - - //--------------------------------------------------------------------- - // Charged Hadrons - - // Systematic for charged hadrons: p, pi+, pi- - // 5% on true energy of charged pions and protons - class ChargedHadRecoUncorrND : public ISyst { - public: - ChargedHadRecoUncorrND() : ISyst("ChargedHadRecoUncorrND", "Charged Hadron Uncorrelated ND Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override; - - }; - - extern const ChargedHadRecoUncorrND kChargedHadRecoUncorrND; - - // 5% syst for charged hadrons sqrt param - // - class ChargedHadRecoUncorrSqrtND : public ISyst { - public: - ChargedHadRecoUncorrSqrtND() : ISyst("ChargedHadRecoUncorrSqrtND", "Charged Had Uncorrelated Sqrt ND Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override; - - }; - - extern const ChargedHadRecoUncorrSqrtND kChargedHadRecoUncorrSqrtND; - - // 5% syst for charged hadrons inv sqrt param - // - class ChargedHadRecoUncorrInvSqrtND : public ISyst { - public: - ChargedHadRecoUncorrInvSqrtND() : ISyst("ChargedHadRecoUncorrInvSqrtND", "Charged Had Uncorrelated Inv Sqrt ND Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override; - - }; - - extern const ChargedHadRecoUncorrInvSqrtND kChargedHadRecoUncorrInvSqrtND; - - //------------------------------------------------------------------- - // Muons - - // Systematic for Muon - // 2% on true energy of muon from CC numu event - class ERecoScaleMuLArND : public ISyst { - public: - ERecoScaleMuLArND() : ISyst("ERecoScaleMuLArND", "Muon Energy Scale ND Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override; - - }; - - extern const ERecoScaleMuLArND kERecoScaleMuLArND; - - // true energy of muon from CC numu event - // Sqrt param 2% for LArTPC - class ERecoScaleMuLArSqrtND : public ISyst { - public: - ERecoScaleMuLArSqrtND() : ISyst("ERecoScaleMuLArSqrtND", "Muon E Scale Sqrt ND Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override; - - }; - - extern const ERecoScaleMuLArSqrtND kERecoScaleMuLArSqrtND; - - // 2% on true energy of muon from CC numu event - // Inv Sqrt param - class ERecoScaleMuLArInvSqrtND : public ISyst { - public: - ERecoScaleMuLArInvSqrtND() : ISyst("ERecoScaleMuLArInvSqrtND", "Muon E Scale Inv Sqrt ND Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override; - - }; - - extern const ERecoScaleMuLArInvSqrtND kERecoScaleMuLArInvSqrtND; - - //--------------------------------------------------------------------------------- - - // Resolution systematics for Muon - class MuonRecoResND : public ISyst { - public: - MuonRecoResND() : ISyst("MuonRecoResND", "Muon Near Detector Resolution") {} - - void Shift(double sigma, - caf::SRProxy* sr, - double& weight) const override; - - }; - - extern const MuonRecoResND kMuonRecoResND; - - // Electron/pi0 energy resolution - class EMRecoResND: public ISyst - { - public: - EMRecoResND() : ISyst("EMRecoResND", "EM shower Near Detector Resolution Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - - }; - - extern const EMRecoResND kEMRecoResND; - - // Charged hadron energy resolution - class ChargedHadRecoResND: public ISyst - { - public: - ChargedHadRecoResND() : ISyst("ChargedHadRecoResND", "Charged Hadron Near Detector Resolution Syst") {} - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override; - - }; - - extern const ChargedHadRecoResND kChargedHadRecoResND; - - //--------------------------------------------------------------------------------- - - // Vector of the reco energy scale systematics - struct RecoEnergyNDSystVector : public std::vector {}; - - RecoEnergyNDSystVector GetRecoENDSysts(); - - bool IsNDdetRecoSyst(std::string); - - std::vector FilterOutNDSysts(std::vector systs); - -} diff --git a/CAFAna/Systs/SystComponentScale.cxx b/CAFAna/Systs/SystComponentScale.cxx index 1254b801..24b1bfa7 100644 --- a/CAFAna/Systs/SystComponentScale.cxx +++ b/CAFAna/Systs/SystComponentScale.cxx @@ -16,7 +16,7 @@ namespace ana //---------------------------------------------------------------------- void SystComponentScale::Shift(double sigma, - caf::SRProxy* sr, + caf::SRInteractionProxy* sr, double& weight) const { if(!fCut(sr)) return; diff --git a/CAFAna/Systs/SystComponentScale.h b/CAFAna/Systs/SystComponentScale.h index efec21bc..e267332e 100644 --- a/CAFAna/Systs/SystComponentScale.h +++ b/CAFAna/Systs/SystComponentScale.h @@ -35,7 +35,7 @@ namespace ana const Cut& GetCut() const {return fCut;} void Shift(double sigma, - caf::SRProxy* sr, + caf::SRInteractionProxy* sr, double& weight) const override; // Some derived classes might have a back-channel allowing them to diff --git a/CAFAna/Systs/Systs.cxx b/CAFAna/Systs/Systs.cxx deleted file mode 100644 index 1fcbdb1a..00000000 --- a/CAFAna/Systs/Systs.cxx +++ /dev/null @@ -1,15 +0,0 @@ -#include "CAFAna/Systs/Systs.h" - -namespace ana -{ - const NumuFHCSyst kNumuFHCSyst; - const NumuRHCSyst kNumuRHCSyst; - const NueFHCSyst kNueFHCSyst; - const NueRHCSyst kNueRHCSyst; - const NCDisSyst kNCDisSyst; - const NCAppSyst kNCAppSyst; - const NutauSyst kNutauSyst; - const NueBeamFHCSyst kNueBeamFHCSyst; - const NueBeamRHCSyst kNueBeamRHCSyst; -} - diff --git a/CAFAna/Systs/Systs.h b/CAFAna/Systs/Systs.h deleted file mode 100644 index 47e88f15..00000000 --- a/CAFAna/Systs/Systs.h +++ /dev/null @@ -1,154 +0,0 @@ -#pragma once - -#include "CAFAna/Core/ISyst.h" -#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" -#include "CAFAna/Core/Utilities.h" - -#include "TFile.h" -#include "TH1.h" -#include "TRandom3.h" - -namespace ana -{ - ///ETW Rework of Normalization Systematics - - //Signal normalization - - /// 5% normalization syst for numu signal - class NumuFHCSyst: public ISyst - { - public: - NumuFHCSyst() : ISyst("numufhcnorm", "Numu FHC Norm Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override - { - if(sr->isCC && abs(sr->nuPDG)==14 && sr->run==20000001) weight *= 1 + .05*sigma; - } - }; - - extern const NumuFHCSyst kNumuFHCSyst; - - /// 5% normalization syst for numubar - class NumuRHCSyst: public ISyst - { - public: - NumuRHCSyst() : ISyst("numurhcnorm", "Numu RHC Norm Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override - { - if(sr->isCC && abs(sr->nuPDG)==14 && sr->run==20000004) weight *= 1 + .05*sigma; - } - }; - - extern const NumuRHCSyst kNumuRHCSyst; - - /// 2% normalization syst for nue - class NueFHCSyst: public ISyst - { - public: - NueFHCSyst() : ISyst("nuefhcnorm", "Nue FHC Norm Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override - { - if(sr->isCC && abs(sr->nuPDG)==12 && sr->run==20000002) weight *= 1 + .02*sigma; - } - }; - - extern const NueFHCSyst kNueFHCSyst; - - /// 2% normalization syst for nuebar - class NueRHCSyst: public ISyst - { - public: - NueRHCSyst() : ISyst("nuerhcnorm", "Nue RHC Norm Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override - { - if(sr->isCC && abs(sr->nuPDG)==12 && sr->run==20000005) weight *= 1 + .02*sigma; - } - }; - - extern const NueRHCSyst kNueRHCSyst; - - //Background normalization following CDR - - /// 10% normalization syst for NC on disappearance analysis (uncorrelated to NC on appearance analysis) - class NCDisSyst: public ISyst - { - public: - NCDisSyst() : ISyst("NCDis", "NC Dis Norm Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override - { - if(!sr->isCC && sr->cvnnumu > 0.5 && sr->cvnnue < 0.5) weight *= 1 + .1*sigma; - } - }; - - extern const NCDisSyst kNCDisSyst; - - /// 5% normalization syst for NC on nue analysis, correlated with numu-CC background - class NCAppSyst: public ISyst - { - public: - NCAppSyst() : ISyst("NCApp", "NC App Norm Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override - { - if((!sr->isCC && sr->cvnnue > 0.5 && sr->cvnnumu < 0.5) || (sr->isCC && abs(sr->nuPDG)==14)) weight *= 1 + .05*sigma; - } - }; - - extern const NCAppSyst kNCAppSyst; - - /// 20% normalization syst for nutau - correlated for app/dis and fhc/rhc - class NutauSyst: public ISyst - { - public: - NutauSyst() : ISyst("nutau", "nutau Norm Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override - { - if(sr->isCC && abs(sr->nuPDG)==16) weight *= 1 + .2*sigma; - } - }; - - extern const NutauSyst kNutauSyst; - - /// 5% normalization syst for beam nues - uncorrelated in fhc/rhc - class NueBeamFHCSyst: public ISyst - { - public: - NueBeamFHCSyst() : ISyst("nuebeamfhc", "Nue Beam FHC Norm Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override - { - if(sr->isCC && abs(sr->nuPDG) == 12 && abs(sr->nuPDGunosc) == 12 && sr->run<20000004) weight *= 1 + .05*sigma; - } - }; - - extern const NueBeamFHCSyst kNueBeamFHCSyst; - - /// 5% normalization syst for beam nues - class NueBeamRHCSyst: public ISyst - { - public: - NueBeamRHCSyst() : ISyst("nuebeamrhc", "Nue Beam RHC Norm Syst") {} - - void Shift(double sigma, - caf::SRProxy* sr, double& weight) const override - { - if(sr->isCC && abs(sr->nuPDG) == 12 && abs(sr->nuPDGunosc) == 12 && !(sr->run<20000004)) weight *= 1 + .05*sigma; - } - }; - - extern const NueBeamRHCSyst kNueBeamRHCSyst; - -} diff --git a/CAFAna/Systs/XSecSystList.cxx b/CAFAna/Systs/XSecSystList.cxx index a678f123..fbbd2422 100644 --- a/CAFAna/Systs/XSecSystList.cxx +++ b/CAFAna/Systs/XSecSystList.cxx @@ -7,150 +7,153 @@ #include namespace ana { -const std::vector kAllXsecSysts = GetXSecSysts(); +#ifdef BUILD_XSEC_SYSTS -///\\\///\\\///\\\/// Get a specific list -std::vector GetXSecSystNames(std::string const &inputCategg) { + const std::vector kAllXsecSysts = GetXSecSysts(); - if (inputCategg == "All") { - return GetFitSystNames(); - } + ///\\\///\\\///\\\/// Get a specific list + std::vector GetXSecSystNames(std::string const &inputCategg) { - std::vector XSecSystNames; - XSecCategg thisCategg = kNahMate; - if (inputCategg == "QELike") - thisCategg = kQELike; - if (inputCategg == "RES") - thisCategg = kRES; - if (inputCategg == "DIS") - thisCategg = kDIS; - if (inputCategg == "FSI") - thisCategg = kFSI; - if (inputCategg == "Ratios") - thisCategg = kRatios; - if (inputCategg == "NC") - thisCategg = kNC; - if (inputCategg == "Other") - thisCategg = kOther; - - static auto XSecDials = GetAllXSecDials(); - for (auto const &s : XSecDials) { - if (s.IsFitSyst != kFitSyst) { - continue; + if (inputCategg == "All") { + return GetFitSystNames(); } - if (s.Categg == thisCategg) { - XSecSystNames.push_back(s.Name); - } // Just for you Luke ;p - } - return XSecSystNames; -} - -/// All dials used as freedoms in standard fits -std::vector const &GetFitSystNames() { - static std::vector XSecSystNames; - static bool first = true; - if (first) { - first = false; - for (auto const &s : GetAllXSecDials()) { - if (s.IsFitSyst == kFitSyst) { - XSecSystNames.push_back(s.Name); + std::vector XSecSystNames; + XSecCategg thisCategg = kNahMate; + if (inputCategg == "QELike") + thisCategg = kQELike; + if (inputCategg == "RES") + thisCategg = kRES; + if (inputCategg == "DIS") + thisCategg = kDIS; + if (inputCategg == "FSI") + thisCategg = kFSI; + if (inputCategg == "Ratios") + thisCategg = kRatios; + if (inputCategg == "NC") + thisCategg = kNC; + if (inputCategg == "Other") + thisCategg = kOther; + + static auto XSecDials = GetAllXSecDials(); + for (auto const &s : XSecDials) { + if (s.IsFitSyst != kFitSyst) { + continue; } + if (s.Categg == thisCategg) { + XSecSystNames.push_back(s.Name); + } // Just for you Luke ;p } + + return XSecSystNames; } - return XSecSystNames; -} - -/// Dials which have an extrapolated response outside of 0->1 -std::vector const &GetExtrapolateOffToOnSystNames() { - static std::vector XSecSystNames; - static bool first = true; - if (first) { - first = false; - for (auto const &s : GetAllXSecDials()) { - if (s.IsExtrapolateOffToOnSyst == kExtrapolated) { - XSecSystNames.push_back(s.Name); + /// All dials used as freedoms in standard fits + std::vector const &GetFitSystNames() { + static std::vector XSecSystNames; + static bool first = true; + if (first) { + first = false; + for (auto const &s : GetAllXSecDials()) { + if (s.IsFitSyst == kFitSyst) { + XSecSystNames.push_back(s.Name); + } } } + + return XSecSystNames; } - return XSecSystNames; -} -/// Dials used to generate fake data sets when set to 1, should not be fit. -std::vector const &GetFakeDataGenerationSystNames() { - static std::vector XSecSystNames; - static bool first = true; - if (first) { - first = false; - for (auto const &s : GetAllXSecDials()) { - if (s.IsFitSyst == kUsedAsFakeData) { - XSecSystNames.push_back(s.Name); + /// Dials which have an extrapolated response outside of 0->1 + std::vector const &GetExtrapolateOffToOnSystNames() { + static std::vector XSecSystNames; + static bool first = true; + if (first) { + first = false; + for (auto const &s : GetAllXSecDials()) { + if (s.IsExtrapolateOffToOnSyst == kExtrapolated) { + XSecSystNames.push_back(s.Name); + } } } - } - return XSecSystNames; -} + return XSecSystNames; + } + /// Dials used to generate fake data sets when set to 1, should not be fit. + std::vector const &GetFakeDataGenerationSystNames() { + static std::vector XSecSystNames; + static bool first = true; + if (first) { + first = false; + for (auto const &s : GetAllXSecDials()) { + if (s.IsFitSyst == kUsedAsFakeData) { + XSecSystNames.push_back(s.Name); + } + } + } -int GetXSecSystIndex(std::string const &name) { - static auto XSecDials = GetAllXSecDials(); + return XSecSystNames; + } - static std::map cache; - if (!cache.count(name)) { - int found = -1; - for (size_t it = 0; it < XSecDials.size(); ++it) { - if (XSecDials[it].Name == name) { - found = it; - break; + int GetXSecSystIndex(std::string const &name) { + static auto XSecDials = GetAllXSecDials(); + + static std::map cache; + if (!cache.count(name)) { + int found = -1; + for (size_t it = 0; it < XSecDials.size(); ++it) { + if (XSecDials[it].Name == name) { + found = it; + break; + } } + assert(found > -1); + cache[name] = found; + } + return cache[name]; + } + + /// Convenience method for checking if a dial is + bool IsExtrapolateOffToOnSyst(std::string const &name) { + static std::unordered_map cache; + if (!cache.count(name)) { + cache[name] = SystNameIsInList(name, GetExtrapolateOffToOnSystNames()); } - assert(found > -1); - cache[name] = found; + return cache[name]; } - return cache[name]; -} - -/// Convenience method for checking if a dial is -bool IsExtrapolateOffToOnSyst(std::string const &name) { - static std::unordered_map cache; - if (!cache.count(name)) { - cache[name] = SystNameIsInList(name, GetExtrapolateOffToOnSystNames()); + bool IsExtrapolateOffToOnSyst(int index) { + static std::unordered_map cache; + if (!cache.count(index)) { + cache[index] = IsExtrapolateOffToOnSyst(GetXSecSystName(index)); + } + return cache[index]; } - return cache[name]; -} -bool IsExtrapolateOffToOnSyst(int index) { - static std::unordered_map cache; - if (!cache.count(index)) { - cache[index] = IsExtrapolateOffToOnSyst(GetXSecSystName(index)); + + bool IsFakeDataGenerationSyst(std::string const &name) { + static std::unordered_map cache; + if (!cache.count(name)) { + cache[name] = SystNameIsInList(name, GetFakeDataGenerationSystNames()); + } + return cache[name]; + } + bool IsFakeDataGenerationSyst(int index) { + static std::unordered_map cache; + if (!cache.count(index)) { + cache[index] = IsFakeDataGenerationSyst(GetXSecSystName(index)); + } + return cache[index]; } - return cache[index]; -} -bool IsFakeDataGenerationSyst(std::string const &name) { - static std::unordered_map cache; - if (!cache.count(name)) { - cache[name] = SystNameIsInList(name, GetFakeDataGenerationSystNames()); + std::pair GetXSecSystLimits(int index) { + static auto XSecDials = GetAllXSecDials(); + assert((index >= 0) && (index < int(XSecDials.size()))); + return XSecDials[index].FitLimits; } - return cache[name]; -} -bool IsFakeDataGenerationSyst(int index) { - static std::unordered_map cache; - if (!cache.count(index)) { - cache[index] = IsFakeDataGenerationSyst(GetXSecSystName(index)); + std::pair GetXSecSystLimits(const std::string &name) { + return GetXSecSystLimits(GetXSecSystIndex(name)); } - return cache[index]; -} - -std::pair GetXSecSystLimits(int index) { - static auto XSecDials = GetAllXSecDials(); - assert((index >= 0) && (index < int(XSecDials.size()))); - return XSecDials[index].FitLimits; -} -std::pair GetXSecSystLimits(const std::string &name) { - return GetXSecSystLimits(GetXSecSystIndex(name)); -} -double GetXSecSystMax(int index) { return GetXSecSystLimits(index).second; } -double GetXSecSystMin(int index) { return GetXSecSystLimits(index).first; } + double GetXSecSystMax(int index) { return GetXSecSystLimits(index).second; } + double GetXSecSystMin(int index) { return GetXSecSystLimits(index).first; } +#endif } // namespace ana diff --git a/CAFAna/Systs/XSecSystList.h b/CAFAna/Systs/XSecSystList.h index d881a6fc..ab7a34e2 100644 --- a/CAFAna/Systs/XSecSystList.h +++ b/CAFAna/Systs/XSecSystList.h @@ -1,7 +1,5 @@ #pragma once -#include "CAFAna/Analysis/AnalysisVersion.h" - #include #include #include @@ -9,299 +7,302 @@ #include namespace ana { -class ISyst; - -enum FitSyst { - kFitSyst, - kRemovedOverconstraint, - kRemovedOddResponse, - kRemovedOther, - kUsedAsFakeData -}; - -enum XSecCategg { kQELike, kRES, kDIS, kFSI, kRatios, kNC, kOther, kNahMate }; - -enum ExtrapolatedSyst { kExtrapolated, kContinuous }; - -static std::pair const kStandardRange{-3, 3}; -static std::pair const kFakeDataRange{0, 1}; - -struct XSecDialDescriptor { - std::string Name; - FitSyst IsFitSyst; - ExtrapolatedSyst IsExtrapolateOffToOnSyst; - std::pair FitLimits; - XSecCategg Categg; -}; - -/// All dial names that should go into a state file -inline std::vector const &GetAllXSecDials() { - static std::vector XSecSystDials; - static bool first = true; - if (first) { - - first = false; - XSecSystDials = { - {"MaCCQE", kFitSyst, kContinuous, kStandardRange, kQELike}, - {"VecFFCCQEshape", kFitSyst, kExtrapolated, kStandardRange, kQELike}, - {"MaNCEL", kUsedAsFakeData, kContinuous, kStandardRange, kNC}, - {"EtaNCEL", kRemovedOverconstraint, kContinuous, kStandardRange, kNC}, - {"MaCCRES", kFitSyst, kContinuous, kStandardRange, kRES}, - {"MvCCRES", kFitSyst, kContinuous, kStandardRange, kRES}, - {"MaNCRES", kFitSyst, kContinuous, kStandardRange, kNC}, - {"MvNCRES", kFitSyst, kContinuous, kStandardRange, kNC}, - {"RDecBR1gamma", kRemovedOverconstraint, kContinuous, {-2, 3}, kRES}, - {"RDecBR1eta", kRemovedOverconstraint, kContinuous, {-2, 3}, kRES}, - {"Theta_Delta2Npi", kFitSyst, kExtrapolated, kStandardRange, kDIS}, - {"AhtBY", kFitSyst, kContinuous, kStandardRange, kDIS}, - {"BhtBY", kFitSyst, kContinuous, kStandardRange, kDIS}, - {"CV1uBY", kFitSyst, kContinuous, kStandardRange, kDIS}, - {"CV2uBY", kFitSyst, kContinuous, kStandardRange, kDIS}, - {"FormZone", kUsedAsFakeData, kContinuous, {-2, 2}, kFSI}, - {"MFP_pi", kUsedAsFakeData, kContinuous, {-2, 2}, kFSI}, - {"FrCEx_pi", kFitSyst, kContinuous, {-2, 2}, kFSI}, - {"FrElas_pi", kFitSyst, kContinuous, {-2, 2}, kFSI}, - {"FrInel_pi", kFitSyst, kContinuous, {-2, 2}, kFSI}, - {"FrAbs_pi", kFitSyst, kContinuous, {-2, 2}, kFSI}, - {"FrPiProd_pi", kFitSyst, kContinuous, {-2, 2}, kFSI}, - {"MFP_N", kUsedAsFakeData, kContinuous, {-2, 2}, kFSI}, - {"FrCEx_N", kFitSyst, kContinuous, {-2, 2}, kFSI}, - {"FrElas_N", kFitSyst, kContinuous, {-2, 2}, kFSI}, - {"FrInel_N", kFitSyst, kContinuous, {-2, 2}, kFSI}, - {"FrAbs_N", kFitSyst, kContinuous, {-2, 2}, kFSI}, - {"FrPiProd_N", kFitSyst, kContinuous, {-2, 2}, kFSI}, - {"CCQEPauliSupViaKF", kFitSyst, kExtrapolated, kStandardRange, kQELike}, - // Must be here to fill branch in SpectrumLoader but shouldn't be used - // as the dials below separate out the responses into multiple fake data - // sets. - {"Mnv2p2hGaussEnhancement", - kRemovedOther, - kContinuous, - {0, 0}, - kQELike}, - {"Mnv2p2hGaussEnhancement_NN", kUsedAsFakeData, kContinuous, - kFakeDataRange, kQELike}, - {"Mnv2p2hGaussEnhancement_2p2h", kUsedAsFakeData, kContinuous, - kFakeDataRange, kQELike}, - {"Mnv2p2hGaussEnhancement_1p1h", kUsedAsFakeData, kContinuous, - kFakeDataRange, kQELike}, - {"MKSPP_ReWeight", kUsedAsFakeData, kContinuous, kFakeDataRange, kRES}, - {"E2p2h_A_nu", kFitSyst, kExtrapolated, kStandardRange, kQELike}, - {"E2p2h_B_nu", kFitSyst, kExtrapolated, kStandardRange, kQELike}, - {"E2p2h_A_nubar", kFitSyst, kExtrapolated, kStandardRange, kQELike}, - {"E2p2h_B_nubar", kFitSyst, kExtrapolated, kStandardRange, kQELike}, - {"NR_nu_n_CC_2Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, - {"NR_nu_n_CC_3Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, - {"NR_nu_p_CC_2Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, - {"NR_nu_p_CC_3Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, - {"NR_nu_np_CC_1Pi", kFitSyst, kContinuous, kStandardRange, kDIS}, - {"NR_nu_n_NC_1Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, - {"NR_nu_n_NC_2Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, - {"NR_nu_n_NC_3Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, - {"NR_nu_p_NC_1Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, - {"NR_nu_p_NC_2Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, - {"NR_nu_p_NC_3Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, - {"NR_nubar_n_CC_1Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, - {"NR_nubar_n_CC_2Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, - {"NR_nubar_n_CC_3Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, - {"NR_nubar_p_CC_1Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, - {"NR_nubar_p_CC_2Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, - {"NR_nubar_p_CC_3Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, - {"NR_nubar_n_NC_1Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, - {"NR_nubar_n_NC_2Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, - {"NR_nubar_n_NC_3Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, - {"NR_nubar_p_NC_1Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, - {"NR_nubar_p_NC_2Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, - {"NR_nubar_p_NC_3Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, - {"BeRPA_A", kFitSyst, kContinuous, kStandardRange, kQELike}, - {"BeRPA_B", kFitSyst, kContinuous, kStandardRange, kQELike}, - {"BeRPA_D", kFitSyst, kContinuous, kStandardRange, kQELike}, - {"BeRPA_E", kUsedAsFakeData, kContinuous, kStandardRange, kQELike}, - {"C12ToAr40_2p2hScaling_nu", kFitSyst, kExtrapolated, kStandardRange, - kQELike}, - {"C12ToAr40_2p2hScaling_nubar", kFitSyst, kExtrapolated, kStandardRange, - kQELike}, - {"nuenuebar_xsec_ratio", kFitSyst, kExtrapolated, kStandardRange, - kRatios}, - {"nuenumu_xsec_ratio", kFitSyst, kExtrapolated, kStandardRange, - kRatios}, - {"SPPLowQ2Suppression", kUsedAsFakeData, kContinuous, kFakeDataRange, - kRES}, - {"FSILikeEAvailSmearing", kUsedAsFakeData, kContinuous, kFakeDataRange, - kFSI}, - {"MissingProtonFakeData", kUsedAsFakeData, kContinuous, kFakeDataRange, - kOther}, - {"NuWroReweightFakeData", kUsedAsFakeData, kContinuous, kFakeDataRange, - kOther}}; - - static auto AnaV = GetAnaVersion(); - if (AnaV == kV3) { - std::string dial_name; - auto sel = [&](XSecDialDescriptor const &d) -> bool { - return d.Name == dial_name; - }; - - dial_name = "Mnv2p2hGaussEnhancement"; - auto mnv_dial = - std::find_if(XSecSystDials.begin(), XSecSystDials.end(), sel); - mnv_dial->IsFitSyst = kFitSyst; - mnv_dial->IsExtrapolateOffToOnSyst = kExtrapolated; - mnv_dial->FitLimits = kStandardRange; - - dial_name = "Mnv2p2hGaussEnhancement_NN"; - auto mnv_dial_NN = - std::find_if(XSecSystDials.begin(), XSecSystDials.end(), sel); - mnv_dial_NN->IsFitSyst = kRemovedOther; - mnv_dial_NN->FitLimits = {0, 0}; - - dial_name = "Mnv2p2hGaussEnhancement_2p2h"; - auto mnv_dial_2p2h = - std::find_if(XSecSystDials.begin(), XSecSystDials.end(), sel); - mnv_dial_2p2h->IsFitSyst = kRemovedOther; - mnv_dial_2p2h->FitLimits = {0, 0}; - - dial_name = "Mnv2p2hGaussEnhancement_1p1h"; - auto mnv_dial_1p1h = - std::find_if(XSecSystDials.begin(), XSecSystDials.end(), sel); - mnv_dial_1p1h->IsFitSyst = kRemovedOther; - mnv_dial_1p1h->FitLimits = {0, 0}; - - dial_name = "MKSPP_ReWeight"; - auto mk_dial = - std::find_if(XSecSystDials.begin(), XSecSystDials.end(), sel); - mk_dial->IsFitSyst = kFitSyst; - mk_dial->IsExtrapolateOffToOnSyst = kExtrapolated; - mk_dial->FitLimits = kStandardRange; - - dial_name = "SPPLowQ2Suppression"; - auto spplowq2 = - std::find_if(XSecSystDials.begin(), XSecSystDials.end(), sel); - spplowq2->IsFitSyst = kFitSyst; - spplowq2->IsExtrapolateOffToOnSyst = kExtrapolated; - spplowq2->FitLimits = kStandardRange; - - dial_name = "FSILikeEAvailSmearing"; - auto fslilikesmear = - std::find_if(XSecSystDials.begin(), XSecSystDials.end(), sel); - fslilikesmear->IsFitSyst = kFitSyst; - fslilikesmear->IsExtrapolateOffToOnSyst = kExtrapolated; - fslilikesmear->FitLimits = kStandardRange; - } - } +#ifdef BUILD_XSEC_SYSTS + + class ISyst; + + enum FitSyst { + kFitSyst, + kRemovedOverconstraint, + kRemovedOddResponse, + kRemovedOther, + kUsedAsFakeData + }; + + enum XSecCategg { kQELike, kRES, kDIS, kFSI, kRatios, kNC, kOther, kNahMate }; - return XSecSystDials; -} - -/// All dial names that should go into a state file -inline std::vector const &GetAllXSecSystNames() { - static std::vector XSecSystNames; - static bool first = true; - if (first) { - first = false; - for (auto const &s : GetAllXSecDials()) { - XSecSystNames.push_back(s.Name); + enum ExtrapolatedSyst { kExtrapolated, kContinuous }; + + static std::pair const kStandardRange{-3, 3}; + static std::pair const kFakeDataRange{0, 1}; + + struct XSecDialDescriptor { + std::string Name; + FitSyst IsFitSyst; + ExtrapolatedSyst IsExtrapolateOffToOnSyst; + std::pair FitLimits; + XSecCategg Categg; + }; + + /// All dial names that should go into a state file + inline std::vector const &GetAllXSecDials() { + static std::vector XSecSystDials; + static bool first = true; + if (first) { + + first = false; + XSecSystDials = { + {"MaCCQE", kFitSyst, kContinuous, kStandardRange, kQELike}, + {"VecFFCCQEshape", kFitSyst, kExtrapolated, kStandardRange, kQELike}, + {"MaNCEL", kUsedAsFakeData, kContinuous, kStandardRange, kNC}, + {"EtaNCEL", kRemovedOverconstraint, kContinuous, kStandardRange, kNC}, + {"MaCCRES", kFitSyst, kContinuous, kStandardRange, kRES}, + {"MvCCRES", kFitSyst, kContinuous, kStandardRange, kRES}, + {"MaNCRES", kFitSyst, kContinuous, kStandardRange, kNC}, + {"MvNCRES", kFitSyst, kContinuous, kStandardRange, kNC}, + {"RDecBR1gamma", kRemovedOverconstraint, kContinuous, {-2, 3}, kRES}, + {"RDecBR1eta", kRemovedOverconstraint, kContinuous, {-2, 3}, kRES}, + {"Theta_Delta2Npi", kFitSyst, kExtrapolated, kStandardRange, kDIS}, + {"AhtBY", kFitSyst, kContinuous, kStandardRange, kDIS}, + {"BhtBY", kFitSyst, kContinuous, kStandardRange, kDIS}, + {"CV1uBY", kFitSyst, kContinuous, kStandardRange, kDIS}, + {"CV2uBY", kFitSyst, kContinuous, kStandardRange, kDIS}, + {"FormZone", kUsedAsFakeData, kContinuous, {-2, 2}, kFSI}, + {"MFP_pi", kUsedAsFakeData, kContinuous, {-2, 2}, kFSI}, + {"FrCEx_pi", kFitSyst, kContinuous, {-2, 2}, kFSI}, + {"FrElas_pi", kFitSyst, kContinuous, {-2, 2}, kFSI}, + {"FrInel_pi", kFitSyst, kContinuous, {-2, 2}, kFSI}, + {"FrAbs_pi", kFitSyst, kContinuous, {-2, 2}, kFSI}, + {"FrPiProd_pi", kFitSyst, kContinuous, {-2, 2}, kFSI}, + {"MFP_N", kUsedAsFakeData, kContinuous, {-2, 2}, kFSI}, + {"FrCEx_N", kFitSyst, kContinuous, {-2, 2}, kFSI}, + {"FrElas_N", kFitSyst, kContinuous, {-2, 2}, kFSI}, + {"FrInel_N", kFitSyst, kContinuous, {-2, 2}, kFSI}, + {"FrAbs_N", kFitSyst, kContinuous, {-2, 2}, kFSI}, + {"FrPiProd_N", kFitSyst, kContinuous, {-2, 2}, kFSI}, + {"CCQEPauliSupViaKF", kFitSyst, kExtrapolated, kStandardRange, kQELike}, + // Must be here to fill branch in SpectrumLoader but shouldn't be used + // as the dials below separate out the responses into multiple fake data + // sets. + {"Mnv2p2hGaussEnhancement", + kRemovedOther, + kContinuous, + {0, 0}, + kQELike}, + {"Mnv2p2hGaussEnhancement_NN", kUsedAsFakeData, kContinuous, + kFakeDataRange, kQELike}, + {"Mnv2p2hGaussEnhancement_2p2h", kUsedAsFakeData, kContinuous, + kFakeDataRange, kQELike}, + {"Mnv2p2hGaussEnhancement_1p1h", kUsedAsFakeData, kContinuous, + kFakeDataRange, kQELike}, + {"MKSPP_ReWeight", kUsedAsFakeData, kContinuous, kFakeDataRange, kRES}, + {"E2p2h_A_nu", kFitSyst, kExtrapolated, kStandardRange, kQELike}, + {"E2p2h_B_nu", kFitSyst, kExtrapolated, kStandardRange, kQELike}, + {"E2p2h_A_nubar", kFitSyst, kExtrapolated, kStandardRange, kQELike}, + {"E2p2h_B_nubar", kFitSyst, kExtrapolated, kStandardRange, kQELike}, + {"NR_nu_n_CC_2Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, + {"NR_nu_n_CC_3Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, + {"NR_nu_p_CC_2Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, + {"NR_nu_p_CC_3Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, + {"NR_nu_np_CC_1Pi", kFitSyst, kContinuous, kStandardRange, kDIS}, + {"NR_nu_n_NC_1Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, + {"NR_nu_n_NC_2Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, + {"NR_nu_n_NC_3Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, + {"NR_nu_p_NC_1Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, + {"NR_nu_p_NC_2Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, + {"NR_nu_p_NC_3Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, + {"NR_nubar_n_CC_1Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, + {"NR_nubar_n_CC_2Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, + {"NR_nubar_n_CC_3Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, + {"NR_nubar_p_CC_1Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, + {"NR_nubar_p_CC_2Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, + {"NR_nubar_p_CC_3Pi", kFitSyst, kContinuous, {-2, 3}, kDIS}, + {"NR_nubar_n_NC_1Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, + {"NR_nubar_n_NC_2Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, + {"NR_nubar_n_NC_3Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, + {"NR_nubar_p_NC_1Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, + {"NR_nubar_p_NC_2Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, + {"NR_nubar_p_NC_3Pi", kFitSyst, kContinuous, {-2, 3}, kNC}, + {"BeRPA_A", kFitSyst, kContinuous, kStandardRange, kQELike}, + {"BeRPA_B", kFitSyst, kContinuous, kStandardRange, kQELike}, + {"BeRPA_D", kFitSyst, kContinuous, kStandardRange, kQELike}, + {"BeRPA_E", kUsedAsFakeData, kContinuous, kStandardRange, kQELike}, + {"C12ToAr40_2p2hScaling_nu", kFitSyst, kExtrapolated, kStandardRange, + kQELike}, + {"C12ToAr40_2p2hScaling_nubar", kFitSyst, kExtrapolated, kStandardRange, + kQELike}, + {"nuenuebar_xsec_ratio", kFitSyst, kExtrapolated, kStandardRange, + kRatios}, + {"nuenumu_xsec_ratio", kFitSyst, kExtrapolated, kStandardRange, + kRatios}, + {"SPPLowQ2Suppression", kUsedAsFakeData, kContinuous, kFakeDataRange, + kRES}, + {"FSILikeEAvailSmearing", kUsedAsFakeData, kContinuous, kFakeDataRange, + kFSI}, + {"MissingProtonFakeData", kUsedAsFakeData, kContinuous, kFakeDataRange, + kOther}, + {"NuWroReweightFakeData", kUsedAsFakeData, kContinuous, kFakeDataRange, + kOther}}; + + static auto AnaV = GetAnaVersion(); + if (AnaV == kV3) { + std::string dial_name; + auto sel = [&](XSecDialDescriptor const &d) -> bool { + return d.Name == dial_name; + }; + + dial_name = "Mnv2p2hGaussEnhancement"; + auto mnv_dial = + std::find_if(XSecSystDials.begin(), XSecSystDials.end(), sel); + mnv_dial->IsFitSyst = kFitSyst; + mnv_dial->IsExtrapolateOffToOnSyst = kExtrapolated; + mnv_dial->FitLimits = kStandardRange; + + dial_name = "Mnv2p2hGaussEnhancement_NN"; + auto mnv_dial_NN = + std::find_if(XSecSystDials.begin(), XSecSystDials.end(), sel); + mnv_dial_NN->IsFitSyst = kRemovedOther; + mnv_dial_NN->FitLimits = {0, 0}; + + dial_name = "Mnv2p2hGaussEnhancement_2p2h"; + auto mnv_dial_2p2h = + std::find_if(XSecSystDials.begin(), XSecSystDials.end(), sel); + mnv_dial_2p2h->IsFitSyst = kRemovedOther; + mnv_dial_2p2h->FitLimits = {0, 0}; + + dial_name = "Mnv2p2hGaussEnhancement_1p1h"; + auto mnv_dial_1p1h = + std::find_if(XSecSystDials.begin(), XSecSystDials.end(), sel); + mnv_dial_1p1h->IsFitSyst = kRemovedOther; + mnv_dial_1p1h->FitLimits = {0, 0}; + + dial_name = "MKSPP_ReWeight"; + auto mk_dial = + std::find_if(XSecSystDials.begin(), XSecSystDials.end(), sel); + mk_dial->IsFitSyst = kFitSyst; + mk_dial->IsExtrapolateOffToOnSyst = kExtrapolated; + mk_dial->FitLimits = kStandardRange; + + dial_name = "SPPLowQ2Suppression"; + auto spplowq2 = + std::find_if(XSecSystDials.begin(), XSecSystDials.end(), sel); + spplowq2->IsFitSyst = kFitSyst; + spplowq2->IsExtrapolateOffToOnSyst = kExtrapolated; + spplowq2->FitLimits = kStandardRange; + + dial_name = "FSILikeEAvailSmearing"; + auto fslilikesmear = + std::find_if(XSecSystDials.begin(), XSecSystDials.end(), sel); + fslilikesmear->IsFitSyst = kFitSyst; + fslilikesmear->IsExtrapolateOffToOnSyst = kExtrapolated; + fslilikesmear->FitLimits = kStandardRange; + } } + + return XSecSystDials; } - return XSecSystNames; -} -/// Return a specific category of XSEC systs -std::vector -GetXSecSystNames(std::string const &inputCategg = "All"); -/// All dials used as freedoms in standard fits -std::vector const &GetFitSystNames(); -/// Dials which should not be used as freedoms (CV weights if they exist removed -/// in SpectrumLoader) -inline std::vector const &GetDoNotIncludeSystNames() { - static std::vector XSecSystNames; - static bool first = true; - if (first) { - first = false; - for (auto const &s : GetAllXSecDials()) { - if (s.IsFitSyst != kFitSyst) { + /// All dial names that should go into a state file + inline std::vector const &GetAllXSecSystNames() { + static std::vector XSecSystNames; + static bool first = true; + if (first) { + first = false; + for (auto const &s : GetAllXSecDials()) { XSecSystNames.push_back(s.Name); } } + + return XSecSystNames; } + /// Return a specific category of XSEC systs + std::vector + GetXSecSystNames(std::string const &inputCategg = "All"); + /// All dials used as freedoms in standard fits + std::vector const &GetFitSystNames(); + /// Dials which should not be used as freedoms (CV weights if they exist removed + /// in SpectrumLoader) + inline std::vector const &GetDoNotIncludeSystNames() { + static std::vector XSecSystNames; + static bool first = true; + if (first) { + first = false; + for (auto const &s : GetAllXSecDials()) { + if (s.IsFitSyst != kFitSyst) { + XSecSystNames.push_back(s.Name); + } + } + } - return XSecSystNames; -} -/// Dials which have an extrapolated response outside of 0->1 -std::vector const &GetExtrapolateOffToOnSystNames(); -/// Dials used to generate fake data sets when set to 1, should not be fit. -std::vector const &GetFakeDataGenerationSystNames(); - -int GetXSecSystIndex(std::string const &name); -inline std::string GetXSecSystName(int index) { - static auto XSecDials = GetAllXSecDials(); - assert((index >= 0) && (index < int(XSecDials.size()))); - return XSecDials[index].Name; -} - -/// Check if a dial name is in a list -inline bool SystNameIsInList(std::string const &name, - std::vector const &listOfNames) { - return (std::find(listOfNames.begin(), listOfNames.end(), name) != - listOfNames.end()); -} - -/// Convenience method for checking if a dial name is -bool IsExtrapolateOffToOnSyst(std::string const &); -bool IsExtrapolateOffToOnSyst(int); - -inline bool IsDoNotIncludeSyst(std::string const &name) { - static std::map cache; - if (!cache.count(name)) { - cache[name] = SystNameIsInList(name, GetDoNotIncludeSystNames()); + return XSecSystNames; } - return cache[name]; -} - -inline bool IsDoNotIncludeSyst(unsigned int index) -{ - // This function is very hot from FixupRecord(), and since we know all the - // indices are small, this arrangement is more efficient than using any sort - // of map. - - enum class Tristate{ - kUnknown = 0, // must be zero so it's the default - kTrue, - kFalse - }; + /// Dials which have an extrapolated response outside of 0->1 + std::vector const &GetExtrapolateOffToOnSystNames(); + /// Dials used to generate fake data sets when set to 1, should not be fit. + std::vector const &GetFakeDataGenerationSystNames(); + + int GetXSecSystIndex(std::string const &name); + inline std::string GetXSecSystName(int index) { + static auto XSecDials = GetAllXSecDials(); + assert((index >= 0) && (index < int(XSecDials.size()))); + return XSecDials[index].Name; + } + + /// Check if a dial name is in a list + inline bool SystNameIsInList(std::string const &name, + std::vector const &listOfNames) { + return (std::find(listOfNames.begin(), listOfNames.end(), name) != + listOfNames.end()); + } + + /// Convenience method for checking if a dial name is + bool IsExtrapolateOffToOnSyst(std::string const &); + bool IsExtrapolateOffToOnSyst(int); - static std::vector cache; - // Common case - if(index < cache.size() && cache[index] != Tristate::kUnknown){ - return cache[index] == Tristate::kTrue; + inline bool IsDoNotIncludeSyst(std::string const &name) { + static std::map cache; + if (!cache.count(name)) { + cache[name] = SystNameIsInList(name, GetDoNotIncludeSystNames()); + } + return cache[name]; } - // Otherwise, we have to look up the answer - const bool ret = IsDoNotIncludeSyst(GetXSecSystName(index)); + inline bool IsDoNotIncludeSyst(unsigned int index) + { + // This function is very hot from FixupRecord(), and since we know all the + // indices are small, this arrangement is more efficient than using any sort + // of map. + + enum class Tristate{ + kUnknown = 0, // must be zero so it's the default + kTrue, + kFalse + }; + + static std::vector cache; + // Common case + if(index < cache.size() && cache[index] != Tristate::kUnknown){ + return cache[index] == Tristate::kTrue; + } + + // Otherwise, we have to look up the answer + const bool ret = IsDoNotIncludeSyst(GetXSecSystName(index)); - // And store it in the cache for next time - if(cache.size() <= index){cache.resize(index+1);} - cache[index] = ret ? Tristate::kTrue : Tristate::kFalse; + // And store it in the cache for next time + if(cache.size() <= index){cache.resize(index+1);} + cache[index] = ret ? Tristate::kTrue : Tristate::kFalse; - return ret; + return ret; - // Old, straightforward code: - /* - static std::map cache; - if (!cache.count(index)) { - cache[index] = IsDoNotIncludeSyst(GetXSecSystName(index)); + // Old, straightforward code: + /* + static std::map cache; + if (!cache.count(index)) { + cache[index] = IsDoNotIncludeSyst(GetXSecSystName(index)); + } + return cache[index]; + */ } - return cache[index]; - */ -} -bool IsFakeDataGenerationSyst(std::string const &); -bool IsFakeDataGenerationSyst(int); + bool IsFakeDataGenerationSyst(std::string const &); + bool IsFakeDataGenerationSyst(int); -std::pair GetXSecSystLimits(const std::string &name); -double GetXSecSystMax(int index); -double GetXSecSystMin(int index); + std::pair GetXSecSystLimits(const std::string &name); + double GetXSecSystMax(int index); + double GetXSecSystMin(int index); -// actually instantiate them so that the Registry knows about them -extern const std::vector kAllXsecSysts; + // actually instantiate them so that the Registry knows about them + extern const std::vector kAllXsecSysts; +#endif } // namespace ana diff --git a/CAFAna/Systs/XSecSysts.cxx b/CAFAna/Systs/XSecSysts.cxx index c4db83ba..d4e5aa0e 100644 --- a/CAFAna/Systs/XSecSysts.cxx +++ b/CAFAna/Systs/XSecSysts.cxx @@ -7,165 +7,165 @@ #include "duneanaobj/StandardRecord/Proxy/SRProxy.h" namespace ana { +#ifdef BUILD_XSEC_SYSTS + + MissingProtonFakeDataGenerator mpfd; + NuWroReweightFakeDataGenerator nuwrofd; + + void XSecSyst::FakeDataDialShift(double sigma, + caf::SRProxy *sr, + double &weight) const { + + // First time hook up known fake data dial IDs, logic then in switch + // statement. + // Why is it like this?! + static int Mnv2p2hGaussEnhancement_id = 0; + static int Mnv2p2hGaussEnhancement_NN_id = 0; + static int Mnv2p2hGaussEnhancement_2p2h_id = 0; + static int Mnv2p2hGaussEnhancement_1p1h_id = 0; + static int MKSPP_ReWeight_id = 0; + static int SPPLowQ2Suppression_id = 0; + static int FSILikeEAvailSmearing_id = 0; + static int MissingProtonFakeData_id = 0; + static int NuWroReweightFakeData_id = 0; + static int BeRPA_E_id = 0; + static int FormZone_id = 0; + static int MFP_pi_id = 0; + static int MFP_N_id = 0; + static int MaNCEL_id = 0; + + static bool first = true; + if (first) { + first = false; + Mnv2p2hGaussEnhancement_id = GetXSecSystIndex("Mnv2p2hGaussEnhancement"); + Mnv2p2hGaussEnhancement_NN_id = + GetXSecSystIndex("Mnv2p2hGaussEnhancement_NN"); + Mnv2p2hGaussEnhancement_2p2h_id = + GetXSecSystIndex("Mnv2p2hGaussEnhancement_2p2h"); + Mnv2p2hGaussEnhancement_1p1h_id = + GetXSecSystIndex("Mnv2p2hGaussEnhancement_1p1h"); + MKSPP_ReWeight_id = GetXSecSystIndex("MKSPP_ReWeight"); + SPPLowQ2Suppression_id = GetXSecSystIndex("SPPLowQ2Suppression"); + FSILikeEAvailSmearing_id = GetXSecSystIndex("FSILikeEAvailSmearing"); + MissingProtonFakeData_id = GetXSecSystIndex("MissingProtonFakeData"); + NuWroReweightFakeData_id = GetXSecSystIndex("NuWroReweightFakeData"); + BeRPA_E_id = GetXSecSystIndex("BeRPA_E"); + FormZone_id = GetXSecSystIndex("FormZone"); + MFP_pi_id = GetXSecSystIndex("MFP_pi"); + MFP_N_id = GetXSecSystIndex("MFP_N"); + MaNCEL_id = GetXSecSystIndex("MaNCEL"); + } -MissingProtonFakeDataGenerator mpfd; -NuWroReweightFakeDataGenerator nuwrofd; - -void XSecSyst::FakeDataDialShift(double sigma, - caf::SRProxy *sr, - double &weight) const { - - // First time hook up known fake data dial IDs, logic then in switch - // statement. - // Why is it like this?! - static int Mnv2p2hGaussEnhancement_id = 0; - static int Mnv2p2hGaussEnhancement_NN_id = 0; - static int Mnv2p2hGaussEnhancement_2p2h_id = 0; - static int Mnv2p2hGaussEnhancement_1p1h_id = 0; - static int MKSPP_ReWeight_id = 0; - static int SPPLowQ2Suppression_id = 0; - static int FSILikeEAvailSmearing_id = 0; - static int MissingProtonFakeData_id = 0; - static int NuWroReweightFakeData_id = 0; - static int BeRPA_E_id = 0; - static int FormZone_id = 0; - static int MFP_pi_id = 0; - static int MFP_N_id = 0; - static int MaNCEL_id = 0; - - static bool first = true; - if (first) { - first = false; - Mnv2p2hGaussEnhancement_id = GetXSecSystIndex("Mnv2p2hGaussEnhancement"); - Mnv2p2hGaussEnhancement_NN_id = - GetXSecSystIndex("Mnv2p2hGaussEnhancement_NN"); - Mnv2p2hGaussEnhancement_2p2h_id = - GetXSecSystIndex("Mnv2p2hGaussEnhancement_2p2h"); - Mnv2p2hGaussEnhancement_1p1h_id = - GetXSecSystIndex("Mnv2p2hGaussEnhancement_1p1h"); - MKSPP_ReWeight_id = GetXSecSystIndex("MKSPP_ReWeight"); - SPPLowQ2Suppression_id = GetXSecSystIndex("SPPLowQ2Suppression"); - FSILikeEAvailSmearing_id = GetXSecSystIndex("FSILikeEAvailSmearing"); - MissingProtonFakeData_id = GetXSecSystIndex("MissingProtonFakeData"); - NuWroReweightFakeData_id = GetXSecSystIndex("NuWroReweightFakeData"); - BeRPA_E_id = GetXSecSystIndex("BeRPA_E"); - FormZone_id = GetXSecSystIndex("FormZone"); - MFP_pi_id = GetXSecSystIndex("MFP_pi"); - MFP_N_id = GetXSecSystIndex("MFP_N"); - MaNCEL_id = GetXSecSystIndex("MaNCEL"); + // This is a bit hacky, but for fake data dials which have discrete +/- values, try the +/-3 sigma values + int posneg_spline_point = 6; + if (sigma < 0) posneg_spline_point = 0; + + // Do something special with the Mnv stuff + if (fID == Mnv2p2hGaussEnhancement_NN_id) { + weight *= sr->xsSyst_wgt[Mnv2p2hGaussEnhancement_id][4]; + } else if (fID == Mnv2p2hGaussEnhancement_2p2h_id) { + weight *= sr->xsSyst_wgt[Mnv2p2hGaussEnhancement_id][3]; + } else if (fID == Mnv2p2hGaussEnhancement_1p1h_id) { + weight *= sr->xsSyst_wgt[Mnv2p2hGaussEnhancement_id][2]; + } else if (fID == MKSPP_ReWeight_id) { + weight *= sr->xsSyst_wgt[MKSPP_ReWeight_id][2]; + } else if (fID == SPPLowQ2Suppression_id) { + weight *= sr->xsSyst_wgt[SPPLowQ2Suppression_id][2]; + } else if (fID == FSILikeEAvailSmearing_id) { + weight *= sr->xsSyst_wgt[FSILikeEAvailSmearing_id][2]; + } else if (fID == MissingProtonFakeData_id) { + mpfd.Shift(sigma, sr, weight); + } else if (fID == NuWroReweightFakeData_id) { + nuwrofd.Shift(sigma, sr, weight); + } else if (fID == BeRPA_E_id) { + weight *= sr->xsSyst_wgt[BeRPA_E_id][posneg_spline_point]; + } else if (fID == FormZone_id) { + weight *= sr->xsSyst_wgt[FormZone_id][posneg_spline_point]; + } else if (fID == MFP_pi_id) { + weight *= sr->xsSyst_wgt[MFP_pi_id][posneg_spline_point]; + } else if (fID == MFP_N_id) { + weight *= sr->xsSyst_wgt[MFP_N_id][posneg_spline_point]; + } else if (fID == MaNCEL_id) { + weight *= sr->xsSyst_wgt[MaNCEL_id][posneg_spline_point]; + } } - // This is a bit hacky, but for fake data dials which have discrete +/- values, try the +/-3 sigma values - int posneg_spline_point = 6; - if (sigma < 0) posneg_spline_point = 0; - - // Do something special with the Mnv stuff - if (fID == Mnv2p2hGaussEnhancement_NN_id) { - weight *= sr->xsSyst_wgt[Mnv2p2hGaussEnhancement_id][4]; - } else if (fID == Mnv2p2hGaussEnhancement_2p2h_id) { - weight *= sr->xsSyst_wgt[Mnv2p2hGaussEnhancement_id][3]; - } else if (fID == Mnv2p2hGaussEnhancement_1p1h_id) { - weight *= sr->xsSyst_wgt[Mnv2p2hGaussEnhancement_id][2]; - } else if (fID == MKSPP_ReWeight_id) { - weight *= sr->xsSyst_wgt[MKSPP_ReWeight_id][2]; - } else if (fID == SPPLowQ2Suppression_id) { - weight *= sr->xsSyst_wgt[SPPLowQ2Suppression_id][2]; - } else if (fID == FSILikeEAvailSmearing_id) { - weight *= sr->xsSyst_wgt[FSILikeEAvailSmearing_id][2]; - } else if (fID == MissingProtonFakeData_id) { - mpfd.Shift(sigma, sr, weight); - } else if (fID == NuWroReweightFakeData_id) { - nuwrofd.Shift(sigma, sr, weight); - } else if (fID == BeRPA_E_id) { - weight *= sr->xsSyst_wgt[BeRPA_E_id][posneg_spline_point]; - } else if (fID == FormZone_id) { - weight *= sr->xsSyst_wgt[FormZone_id][posneg_spline_point]; - } else if (fID == MFP_pi_id) { - weight *= sr->xsSyst_wgt[MFP_pi_id][posneg_spline_point]; - } else if (fID == MFP_N_id) { - weight *= sr->xsSyst_wgt[MFP_N_id][posneg_spline_point]; - } else if (fID == MaNCEL_id) { - weight *= sr->xsSyst_wgt[MaNCEL_id][posneg_spline_point]; - } -} + void XSecSyst::Shift(double sigma,caf::SRProxy *sr, + double &weight) const { + // No xs weights in this event, skip reweighting it + if (sr->xsSyst_wgt.empty()) { + return; + } + if (sr->xsSyst_wgt[0].empty()) { + return; + } + if (fabs(sigma) < 1E-5) { + return; + } -void XSecSyst::Shift(double sigma,caf::SRProxy *sr, - double &weight) const { - // No xs weights in this event, skip reweighting it - if (sr->xsSyst_wgt.empty()) { - return; - } - if (sr->xsSyst_wgt[0].empty()) { - return; - } - if (fabs(sigma) < 1E-5) { - return; - } + if (IsFakeDataGenerationSyst( + fID)) { // Separate out hard coded logic for fake data dials. + FakeDataDialShift(sigma, sr, weight); + return; + } - if (IsFakeDataGenerationSyst( - fID)) { // Separate out hard coded logic for fake data dials. - FakeDataDialShift(sigma, sr, weight); - return; - } + assert(std::abs(sigma) <= 3 && + "XSecs responses only valid up to +/-3 sigma!"); - assert(std::abs(sigma) <= 3 && - "XSecs responses only valid up to +/-3 sigma!"); + bool IsExtrapolatedSyst = IsExtrapolateOffToOnSyst(fID); - bool IsExtrapolatedSyst = IsExtrapolateOffToOnSyst(fID); + // How far apart are the points + const double spacing = 1; - // How far apart are the points - const double spacing = 1; + // Get the top and bottom values in the array + int low_index = std::floor(sigma / spacing) + 3; + int high_index = std::ceil(sigma / spacing) + 3; - // Get the top and bottom values in the array - int low_index = std::floor(sigma / spacing) + 3; - int high_index = std::ceil(sigma / spacing) + 3; + double fact = 1; + if (IsExtrapolatedSyst) { - double fact = 1; - if (IsExtrapolatedSyst) { + // double diff = sigma / spacing; - // double diff = sigma / spacing; + double weight_at_cv = 1; + double weight_at_one_sig = sr->xsSyst_wgt[fID][4]; - double weight_at_cv = 1; - double weight_at_one_sig = sr->xsSyst_wgt[fID][4]; + double dx = 1; + double dy = weight_at_one_sig - weight_at_cv; - double dx = 1; - double dy = weight_at_one_sig - weight_at_cv; + // y = m*x + c + fact = (dy / dx) * sigma + weight_at_cv; - // y = m*x + c - fact = (dy / dx) * sigma + weight_at_cv; + } else { + double diff = (sigma - double(low_index)) / spacing; - } else { - double diff = (sigma - double(low_index)) / spacing; + double low_weight = sr->xsSyst_wgt[fID][low_index]; + double high_weight = sr->xsSyst_wgt[fID][high_index]; - double low_weight = sr->xsSyst_wgt[fID][low_index]; - double high_weight = sr->xsSyst_wgt[fID][high_index]; + fact = low_weight + (high_weight - low_weight) * diff; + } - fact = low_weight + (high_weight - low_weight) * diff; + fact = std::min(fact, 10.); + weight *= fact; } - fact = std::min(fact, 10.); - weight *= fact; -} - -XSecSyst::XSecSyst(int syst_id, bool applyPenalty) - : ISyst(GetXSecSystName(syst_id), GetXSecSystName(syst_id), applyPenalty, - GetXSecSystMin(syst_id), GetXSecSystMax(syst_id)), - fID(syst_id) {} + XSecSyst::XSecSyst(int syst_id, bool applyPenalty) + : ISyst(GetXSecSystName(syst_id), GetXSecSystName(syst_id), applyPenalty, + GetXSecSystMin(syst_id), GetXSecSystMax(syst_id)), + fID(syst_id) {} -std::vector GetXSecSysts(std::vector names, - bool applyPenalty) { - static std::vector ret; + std::vector GetXSecSysts(std::vector names, + bool applyPenalty) { + static std::vector ret; - if (names.empty()) { - names = GetAllXSecSystNames(); - } - - if (ret.empty()) { - for (auto &it : names) { - ret.push_back(new XSecSyst(GetXSecSystIndex(it), applyPenalty)); + if (names.empty()) { + names = GetAllXSecSystNames(); } - } - return ret; -} + if (ret.empty()) { + for (auto &it : names) { + ret.push_back(new XSecSyst(GetXSecSystIndex(it), applyPenalty)); + } + } + return ret; +#endif } // namespace ana diff --git a/CAFAna/Systs/XSecSysts.h b/CAFAna/Systs/XSecSysts.h index bcc7beb0..a27b4778 100644 --- a/CAFAna/Systs/XSecSysts.h +++ b/CAFAna/Systs/XSecSysts.h @@ -10,26 +10,28 @@ #include namespace ana { +#ifdef BUILD_XSEC_SYSTS -class XSecSyst : public ISyst { -public: - virtual ~XSecSyst(){}; + class XSecSyst : public ISyst { + public: + virtual ~XSecSyst(){}; - void FakeDataDialShift(double sigma, - caf::SRProxy *sr, double &weight) const; + void FakeDataDialShift(double sigma, + caf::SRProxy *sr, double &weight) const; - void Shift(double sigma, caf::SRProxy *sr, - double &weight) const override; + void Shift(double sigma, caf::SRProxy *sr, + double &weight) const override; -protected: - XSecSyst(int syst_id, bool applyPenalty = true); + protected: + XSecSyst(int syst_id, bool applyPenalty = true); - friend std::vector GetXSecSysts(std::vector, bool); + friend std::vector GetXSecSysts(std::vector, bool); - int fID; -}; + int fID; + }; -std::vector -GetXSecSysts(std::vector names = {}, bool applyPenalty = true); + std::vector + GetXSecSysts(std::vector names = {}, bool applyPenalty = true); +#endif } // namespace ana diff --git a/CAFAna/Utils/CMakeLists.txt b/CAFAna/Utils/CMakeLists.txt new file mode 100644 index 00000000..0f93c887 --- /dev/null +++ b/CAFAna/Utils/CMakeLists.txt @@ -0,0 +1,6 @@ +set(Utils_header_files + EnumIter.h) + + +install( FILES ${Utils_header_files} + DESTINATION include/CAFAna/Utils/) diff --git a/CAFAna/Utils/EnumIter.h b/CAFAna/Utils/EnumIter.h new file mode 100644 index 00000000..40de3250 --- /dev/null +++ b/CAFAna/Utils/EnumIter.h @@ -0,0 +1,48 @@ +#pragma once + +// this file's contents borrowed from https://medium.com/@ryan_forrester_/c-enum-iteration-comprehensive-guide-647a30f0f2ca + +#include +#include + +namespace ana +{ + template + constexpr auto to_underlying(E e) noexcept + { + return static_cast>(e); + } + + template + class EnumIterator + { + private: + int value; + + public: + explicit EnumIterator(int v) : value(v) {} + E operator*() const { return static_cast(value); } + EnumIterator& operator++() { ++value; return *this; } + bool operator!=(const EnumIterator& other) const { return value != other.value; } + }; + + template + class EnumRange + { + private: + int begin_value, end_value; + + public: + EnumRange(E begin, E end) : begin_value(to_underlying(begin)), end_value(to_underlying(end)) {} + EnumIterator begin() const { return EnumIterator(begin_value); } + EnumIterator end() const { return EnumIterator(end_value + 1); } + }; + + template + EnumRange enum_range(E begin, E end) + { + return EnumRange(begin, end); + } + +#define LAST_ELEM(E) kNumEs +} \ No newline at end of file diff --git a/CAFAna/Vars/CMakeLists.txt b/CAFAna/Vars/CMakeLists.txt index c7ef3575..6ce51542 100644 --- a/CAFAna/Vars/CMakeLists.txt +++ b/CAFAna/Vars/CMakeLists.txt @@ -18,6 +18,9 @@ if(DEFINED USE_OPENMP AND USE_OPENMP) target_compile_options(CAFAnaVars BEFORE PUBLIC -DUSE_PREDINTERP_OMP -fopenmp) endif() -install(TARGETS CAFAnaVars +install(TARGETS CAFAnaVars + EXPORT CAFAnaTargets LIBRARY DESTINATION lib/ PUBLIC_HEADER DESTINATION include/CAFAna/Vars/) + +add_cafana_lib(CAFAnaVars) \ No newline at end of file diff --git a/CAFAna/Vars/DUNENeutNuWROReweight.cxx b/CAFAna/Vars/DUNENeutNuWROReweight.cxx index 9abbc022..ecba056c 100644 --- a/CAFAna/Vars/DUNENeutNuWROReweight.cxx +++ b/CAFAna/Vars/DUNENeutNuWROReweight.cxx @@ -17,14 +17,14 @@ namespace ana } //---------------------------------------------------------------------- - double DUNENeutNuWROReweight::operator()(const caf::SRProxy* sr) + double DUNENeutNuWROReweight::operator()(const caf::SRTrueInteractionProxy* nu) { if(!fHistNu && !fHist2DNu) LoadHists(); - const double x = sr->Ev; + const double x = nu->E; if(x < 0) return 1; // How? - const bool anti = (sr->nuPDG < 0); + const bool anti = ( nu->pdg<0);//(sr->nuPDG < 0); if(fVars == kEnu){ TH1* h = (anti ? fHistAnu : fHistNu); @@ -35,7 +35,7 @@ namespace ana } else{ TH2* h = (anti ? fHist2DAnu : fHist2DNu); - const double y = (fVars == kEnuQ2) ? sr->Q2 : sr->W; + const double y = (fVars == kEnuQ2) ? nu->Q2 : nu->W;//sr->Q2 : sr->W; if(x > h->GetXaxis()->GetXmax()) return 1; // overflow bin if(y < 0) return 1; // underflow bin if(y > h->GetYaxis()->GetXmax()) return 1; // overflow bin diff --git a/CAFAna/Vars/DUNENeutNuWROReweight.h b/CAFAna/Vars/DUNENeutNuWROReweight.h index 49c04f5c..85df4cb5 100644 --- a/CAFAna/Vars/DUNENeutNuWROReweight.h +++ b/CAFAna/Vars/DUNENeutNuWROReweight.h @@ -8,6 +8,8 @@ class TH2; namespace ana { + class SRTrueInteractionProxy; + class DUNENeutNuWROReweight { public: @@ -33,7 +35,7 @@ namespace ana ~DUNENeutNuWROReweight(); - double operator()(const caf::SRProxy* sr); + double operator()(const caf::SRTrueInteractionProxy* nu); protected: void LoadHists(); @@ -49,11 +51,11 @@ namespace ana const std::string kNeutNuWROReweightFname = "/dune/data/users/marshalc/NEUT_GENIE_ratio.root"; - const Weight kReweightEnuToNeut(DUNENeutNuWROReweight(kNeutNuWROReweightFname, DUNENeutNuWROReweight::kNeut, DUNENeutNuWROReweight::kEnu)); - const Weight kReweightEnuQ2ToNeut(DUNENeutNuWROReweight(kNeutNuWROReweightFname, DUNENeutNuWROReweight::kNeut, DUNENeutNuWROReweight::kEnuQ2)); - const Weight kReweightEnuWToNeut(DUNENeutNuWROReweight(kNeutNuWROReweightFname, DUNENeutNuWROReweight::kNeut, DUNENeutNuWROReweight::kEnuW)); + const NuTruthWeight kReweightEnuToNeut(DUNENeutNuWROReweight(kNeutNuWROReweightFname, DUNENeutNuWROReweight::kNeut, DUNENeutNuWROReweight::kEnu)); + const NuTruthWeight kReweightEnuQ2ToNeut(DUNENeutNuWROReweight(kNeutNuWROReweightFname, DUNENeutNuWROReweight::kNeut, DUNENeutNuWROReweight::kEnuQ2)); + const NuTruthWeight kReweightEnuWToNeut(DUNENeutNuWROReweight(kNeutNuWROReweightFname, DUNENeutNuWROReweight::kNeut, DUNENeutNuWROReweight::kEnuW)); - const Weight kReweightEnuToNuWRO(DUNENeutNuWROReweight(kNeutNuWROReweightFname, DUNENeutNuWROReweight::kNuWRO, DUNENeutNuWROReweight::kEnu)); - const Weight kReweightEnuQ2ToNuWRO(DUNENeutNuWROReweight(kNeutNuWROReweightFname, DUNENeutNuWROReweight::kNuWRO, DUNENeutNuWROReweight::kEnuQ2)); - const Weight kReweightEnuWToNuWRO(DUNENeutNuWROReweight(kNeutNuWROReweightFname, DUNENeutNuWROReweight::kNuWRO, DUNENeutNuWROReweight::kEnuW)); + const NuTruthWeight kReweightEnuToNuWRO(DUNENeutNuWROReweight(kNeutNuWROReweightFname, DUNENeutNuWROReweight::kNuWRO, DUNENeutNuWROReweight::kEnu)); + const NuTruthWeight kReweightEnuQ2ToNuWRO(DUNENeutNuWROReweight(kNeutNuWROReweightFname, DUNENeutNuWROReweight::kNuWRO, DUNENeutNuWROReweight::kEnuQ2)); + const NuTruthWeight kReweightEnuWToNuWRO(DUNENeutNuWROReweight(kNeutNuWROReweightFname, DUNENeutNuWROReweight::kNuWRO, DUNENeutNuWROReweight::kEnuW)); } diff --git a/CAFAna/Vars/Vars.cxx b/CAFAna/Vars/Vars.cxx index afd5056e..81fdfd5f 100644 --- a/CAFAna/Vars/Vars.cxx +++ b/CAFAna/Vars/Vars.cxx @@ -11,21 +11,6 @@ namespace ana { - // -->FD - const Var kRecoE_nue = SIMPLEVAR(Ev_reco_nue); - const Var kRecoE_numu = SIMPLEVAR(Ev_reco_numu); - const Var kRecoE_FromDep = SIMPLEVAR(eRec_FromDep); - const Var kFDNumuPid = SIMPLEVAR(cvnnumu); - const Var kFDNuePid = SIMPLEVAR(cvnnue); - const Var kMVANUMU = SIMPLEVAR(mvanumu); - - // -->ND - const Var kRecoEnergyND = SIMPLEVAR(Ev_reco); - const Var kRecoYND = (SIMPLEVAR(Ev_reco) - SIMPLEVAR(Elep_reco)) / SIMPLEVAR(Ev_reco); - const Var kRecoY_FromDep = (SIMPLEVAR(eRec_FromDep) - SIMPLEVAR(LepE)) / SIMPLEVAR(eRec_FromDep); - const Var kTrueEnergy = SIMPLEVAR(Ev); - - // CV weighting - const Weight kCVXSecWeights = SIMPLEWEIGHT(total_xsSyst_cv_wgt); // kUnweighted - + const Var kRecoEnu = SIMPLEVAR(Enu.lep_calo); + const TruthVar kTrueEnu = SIMPLETRUTHVAR(E); } diff --git a/CAFAna/Vars/Vars.h b/CAFAna/Vars/Vars.h index 97e45206..c2f62f71 100644 --- a/CAFAna/Vars/Vars.h +++ b/CAFAna/Vars/Vars.h @@ -1,6 +1,8 @@ -/// Eventually split this in {Nue,Numu}Vars.{cxx,h} +// Eventually maybe we split this into truth-only TruthVars.{cxx,h}, etc. #pragma once +#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" + #include "CAFAna/Core/Utilities.h" #include "CAFAna/Core/Var.h" #include "CAFAna/Core/Weight.h" @@ -10,21 +12,16 @@ namespace ana { -extern const Var kRecoE_nue; -extern const Var kRecoE_numu; -extern const Var kRecoE_FromDep; -extern const Var kFDNumuPid; -extern const Var kFDNuePid; -extern const Var kMVANUMU; - -// -->ND -extern const Var kRecoEnergyND; -extern const Var kRecoYND; -extern const Var kRecoY_FromDep; - -extern const Var kTrueEnergy; - -// CV weighting -extern const Weight kCVXSecWeights; // kUnweighted + // simple examples + extern const Var kRecoEnu; + extern const TruthVar kTrueEnu; + + // useful truth-only variables + inline const TruthVar kTrueVtxX_NT = SIMPLETRUTHVAR(vtx.x); + inline const TruthVar kTrueVtxY_NT = SIMPLETRUTHVAR(vtx.y); + inline const TruthVar kTrueVtxZ_NT = SIMPLETRUTHVAR(vtx.z); + inline const Var kTrueVtxX = TruthVarToVar(kTrueVtxX_NT); + inline const Var kTrueVtxY = TruthVarToVar(kTrueVtxY_NT); + inline const Var kTrueVtxZ = TruthVarToVar(kTrueVtxZ_NT); } // namespace diff --git a/CAFAna/cafe b/CAFAna/cafe index 8a669540..9bb98677 100755 --- a/CAFAna/cafe +++ b/CAFAna/cafe @@ -147,11 +147,13 @@ if __name__ == '__main__': os.environ['DUNEANAOBJ_INC'], os.environ['ROOTSYS']+'/include', os.environ['SRPROXY_INC'], + os.environ['BOOST_INC'], os.environ['STAN_INC'], os.environ['STAN_MATH_INC'], os.environ['EIGEN_INC'], os.environ['SUNDIALS_INC'], os.environ['OSCLIB_INC'], + os.environ['BOOST_INC'], os.environ['TBB_INC']] @@ -231,14 +233,15 @@ int main(int argc, char** argv) libs = ['Minuit2', 'TMVA', 'EG', 'duneanaobj_StandardRecord', 'duneanaobj_StandardRecordProxy', 'OscLib', 'CAFAnaCoreExt', - 'CAFAnaCore', 'CAFAnaVars', 'CAFAnaCuts', - 'CAFAnaExperiment', 'CAFAnaSysts', 'CAFAnaDecomp', 'CAFAnaExtrap', - 'CAFAnaPrediction', 'CAFAnaFit', 'CAFAnaAnalysis', + 'CAFAnaCore', + #'CAFAnaVars', 'CAFAnaCuts', + #'CAFAnaExperiment', 'CAFAnaSysts', 'CAFAnaExtrap', + #'CAFAnaPrediction', 'CAFAnaFit', 'CAFAnaAnalysis', 'boost_filesystem', 'boost_system'] print('Compiling macro...') incs = ' '.join(['-I '+p for p in path]) - compile_cmd = 'g++ -c -g '+d.name+'/'+fname+'.cxx -o '+d.name+'/'+fname+'.o' + ' -pthread -std=c++17 -m64 -UNDEBUG -fdiagnostics-color=auto -DDONT_USE_FQ_HARDCODED_SYST_PATHS=1 -UNDEBUG -DTBB_INTERFACE_NEW -DCAFANACORE_SPECTRUMLOADERBASE '+incs + compile_cmd = 'g++ -c -g '+d.name+'/'+fname+'.cxx -o '+d.name+'/'+fname+'.o' + ' -pthread -std=c++17 -m64 -UNDEBUG -fdiagnostics-color=auto -DDONT_USE_FQ_HARDCODED_SYST_PATHS=1 -UNDEBUG -DTBB_INTERFACE_NEW '+incs # print(compile_cmd) ret = subprocess.run(compile_cmd, shell=True).returncode if ret != 0: sys.exit(ret) diff --git a/CAFAna/cmake/FindCAFAnaCore.cmake b/CAFAna/cmake/FindCAFAnaCore.cmake index cfda0b9a..e257d283 100644 --- a/CAFAna/cmake/FindCAFAnaCore.cmake +++ b/CAFAna/cmake/FindCAFAnaCore.cmake @@ -27,7 +27,7 @@ find_path(CAFAnaCoreSAM PATHS ${CAFANACORE_INC} NO_DEFAULT_PATH) -SET(CAFAnaCore_CompileOptions "-DCAFANACORE_SPECTRUMLOADERBASE") +SET(CAFAnaCore_CompileOptions) if(NOT "${CAFAnaCoreSAM}x" STREQUAL "CAFAnaCoreSAM-NOTFOUNDx") if(DEFINED ENV{IFDHC_INC}) diff --git a/CAFAna/cmake/c++CompilerSetup.cmake b/CAFAna/cmake/c++CompilerSetup.cmake index 0a3502d1..ea80590f 100644 --- a/CAFAna/cmake/c++CompilerSetup.cmake +++ b/CAFAna/cmake/c++CompilerSetup.cmake @@ -20,3 +20,5 @@ add_compile_options(-Wno-unused "-D__FILENAME__=\"$(subst ${CMAKE_SOURCE_DIR}/,, # We probably don't need these but they exist in the source # add_compile_options(-DUSE_FQ_HARDCODED_SYST_PATHS) # add_compile_options(-DUSE_SRT_CONTEXT) + +add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=1) diff --git a/CAFAna/cmake/templates/CAFAnaConfig.cmake.in b/CAFAna/cmake/templates/CAFAnaConfig.cmake.in new file mode 100644 index 00000000..48728122 --- /dev/null +++ b/CAFAna/cmake/templates/CAFAnaConfig.cmake.in @@ -0,0 +1,4 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/CAFAnaTargets.cmake") +check_required_components("@PROJECT_NAME@") \ No newline at end of file diff --git a/CAFAna/cmake/ups_env_setup.sh b/CAFAna/cmake/ups_env_setup.sh index 5866535b..12b126b6 100644 --- a/CAFAna/cmake/ups_env_setup.sh +++ b/CAFAna/cmake/ups_env_setup.sh @@ -2,21 +2,31 @@ source /cvmfs/dune.opensciencegrid.org/products/dune/setup_dune.sh +# temporary until we get updated builds of all the dependent products +export PRODUCTS="/exp/dune/app/users/jwolcott/ups:$PRODUCTS" + if [ -z "${UPS_SHELL}" ]; then echo "[ERROR]: Is UPS set up?" exit 1 fi -setup root v6_22_08d -q e20:prof:p392 || exit 1 + +setup root v6_28_12 -q e20:p3915:prof || exit 1 setup boost v1_75_0 -q e20:prof || exit 1 setup cmake v3_22_2 || exit 1 setup jobsub_client || exit 1 -setup eigen v3_3_9a || exit 1 -setup stan v2_26_1 -q e20:prof || exit 1 -setup osclib v00.21 -q e20:prof:n311:stan || exit 1 -setup cafanacore v02.00 -q e20:prof:n311 || exit 1 -setup duneanaobj v02_02_00 -qe20:prof || exit 1 setup fhiclcpp v4_15_03 -q e20:prof || exit 1 # for prism +setup eigen v3_4_0 || exit 1 +setup stan v2_26_1 -q e20:prof || exit 1 + +# these will need to be updated as soon as we have official builds for them +setup osclib testing -q e20:prof:stanfree || exit 1 +setup cafanacore testing -q e20:prof || exit 1 +setup duneanaobj vtesting -q e20:debug || exit 1 + + + # To get setup_fnal_security which helps reading files over xrootd #setup duneutil v09_53_00d02 -q e20:prof +#setup duneutil v09_89_01d01 -q e26:prof echo "Finished ups setup." diff --git a/CAFAna/scripts/CMakeLists.txt b/CAFAna/scripts/CMakeLists.txt index b4dc71be..718c2acd 100644 --- a/CAFAna/scripts/CMakeLists.txt +++ b/CAFAna/scripts/CMakeLists.txt @@ -11,19 +11,8 @@ set(scripts_to_install spec_variations.C ) +# 2025-02-25 JW: the scripts are left as legacy examples as to what one might want to do, but they won't build any more set(scripts_to_build - asimov_joint - make_toy_throws - make_toy_throws_fixed_seed - MakePredInterps - fit_covar - make_all_throws - make_all_throws_fixed_seed - make_1dconstraint_plots - make_spectra_constraint_plots - llh_scans - spec_joint - sample_throws ) if(DEFINED USE_OPENMP AND USE_OPENMP) LIST(APPEND scripts_to_build pred_thread_test fit_thread_test) diff --git a/CAFAna/standalone_configure_and_build.sh b/CAFAna/standalone_configure_and_build.sh index 64d36408..21c9c5c7 100755 --- a/CAFAna/standalone_configure_and_build.sh +++ b/CAFAna/standalone_configure_and_build.sh @@ -27,6 +27,7 @@ CMAKE_BUILD_TYPE=RelWithDebInfo BUILD_DIR="build" INSTALL_DIR="" USE_OMP="0" +EXTRA_CMAKE_ARGS="" while [[ ${#} -gt 0 ]]; do @@ -43,6 +44,16 @@ while [[ ${#} -gt 0 ]]; do shift ;; + -e|--extra-arg) + if [[ ${#} -lt 2 ]]; then + echo "[ERROR]: ${1} expected a value." + exit 1 + fi + echo "[OPT]: will pass '${2}' to CMake." + EXTRA_CMAKE_ARGS="$EXTRA_CMAKE_ARGS $2" + shift + ;; + -f|--force-remove) FORCE_REMOVE="1" @@ -103,6 +114,7 @@ while [[ ${#} -gt 0 ]]; do echo -e "\t-f|--force-remove : Remove previous build directory if it exists." echo -e "\t-r|--release : Compile with CMAKE_BUILD_TYPE=Release" echo -e "\t--db : Compile with CMAKE_BUILD_TYPE=Debug" + echo -e "\t-e|--extra-arg : Add the following as an extra argument to the CMake invocation" echo -e "\t--use-gperftools : Compile libunwind and gperftools" echo -e "\t-u|--use-UPS : Try and use ups to set up required packages, " echo -e "\t rather than assuming they exist on the local system." @@ -133,22 +145,28 @@ fi SCRIPT_EXE_DIR=$(pwd) +TOP_SOURCE_DIR="$( cd $(dirname $0); pwd)" +SUPPORT_DIR=$INSTALL_DIR/support + mkdir "$BUILD_DIR" cd "$BUILD_DIR" BUILD_DIR=$(pwd) -mkdir -p ../support +mkdir -p $SUPPORT_DIR + +echo "\$CAFANACORE_INC = $CAFANACORE_INC" if [ "${USE_UPS}" = "1" ]; then - source ../cmake/ups_env_setup.sh - source ../support_software.sh $(abspath ../support) USING_UPS + source ${TOP_SOURCE_DIR}/cmake/ups_env_setup.sh + source ${TOP_SOURCE_DIR}/support_software.sh $(abspath $SUPPORT_DIR) USING_UPS cd "$BUILD_DIR" - cmake ../ -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -DBUILD_ENV_SCRIPTS="$(abspath ../cmake/ups_env_setup.sh);$(abspath ../support/support_software_env.sh)" + cmake ${TOP_SOURCE_DIR} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} ${EXTRA_CMAKE_ARGS} \ + -DBUILD_ENV_SCRIPTS="$(abspath ${TOP_SOURCE_DIR}/cmake/ups_env_setup.sh);$(abspath $SUPPORT_DIR/support_software_env.sh)" else - source ../support_software.sh $(abspath ../support) BUILD_UPS_REPLACEMENT_SOFTWARE + source ${TOP_SOURCE_DIR}/support_software.sh $(abspath $SUPPORT_DIR) BUILD_UPS_REPLACEMENT_SOFTWARE cd "$BUILD_DIR" - cmake ../ -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ - -DBUILD_ENV_SCRIPTS=$(abspath ../support/support_software_env.sh) + cmake ${TOP_SOURCE_DIR} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} ${EXTRA_CMAKE_ARGS} \ + -DBUILD_ENV_SCRIPTS=$(abspath $SUPPORT_DIR/support_software_env.sh) fi +echo "Building in and installing from $PWD:" make install -j ${CORES} diff --git a/CAFAna/tute/TestAncestry.C b/CAFAna/tute/TestAncestry.C new file mode 100644 index 00000000..d482bc60 --- /dev/null +++ b/CAFAna/tute/TestAncestry.C @@ -0,0 +1,130 @@ +#include + +#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" +#include "duneanaobj/StandardRecord/Navigate.h" +#include "duneanaobj/StandardRecord/SREnums.h" + +#include "CAFAna/Core/SpectrumLoader.h" +#include "CAFAna/Core/Spectrum.h" +#include "CAFAna/Core/Binning.h" +#include "CAFAna/Core/Var.h" +#include "CAFAna/Core/Cut.h" +#include "CAFAna/Core/HistAxis.h" + +#include "TCanvas.h" +#include "TH1.h" +#include "TLegend.h" + +using namespace ana; + + +const RecoPartVar kMatchedTruePartE([](const caf::SRRecoParticleProxy * part) -> float +{ + if (part->truth.empty()) + return -999.; + + // Ancestor() returns the closest ancestor in the SR hierarchy with the template type. + // Once we have the top-level object, we then can connect its + const caf::SRProxy * top = part->Ancestor(); + return caf::FindParticle(top->mc, part->truth[0])->p.E; +}); + +// reco particles whose best-match particle is a true muon +const RecoPartCut kMatchedToTrueMuon([](const caf::SRRecoParticleProxy * part) -> float +{ + if (part->truth.empty()) + return false; + + const caf::SRProxy * top = part->Ancestor(); + return std::abs(caf::FindParticle(top->mc, part->truth[0])->pdg) == 13; +}); + +// Select reco particles that have a pdg of muon +const RecoPartCut kIsMuon([](const caf::SRRecoParticleProxy* sr) + { + return abs(sr->pdg) == 13 ; + }); + +const Var kMatchedTrueInteractionEnergy([](const caf::SRInteractionProxy * ixn) -> float +{ + if (ixn->truth.empty()) + return -999.; + + // Ancestor() returns the closest ancestor in the SR hierarchy with the template type. + // Once we have the top-level object, we then can connect its + const caf::SRProxy * top = ixn->Ancestor(); + // should be a number... + return caf::FindInteraction(top->mc, ixn->truth[0])->E; + +}); + +// cut on true interaction mode as defined in StandardRecord/SREnums.h +const Cut kMatchedToTrueRES([](const caf::SRInteractionProxy * ixn) +{ + if (ixn->truth.empty()) + return false; + + const caf::SRProxy * top = ixn->Ancestor(); + return caf::FindInteraction(top->mc, ixn->truth[0])->mode == caf::ScatteringMode::kRes; +}); + +void TestAncestry() +{ + + const std::string fname = "/pnfs/dune/persistent/users/abooth/nd-production/MicroProdN1p2/output/run-cafmaker/MicroProdN1p2_NDLAr_1E18_RHC.caf.nu/CAF.flat/0000000/0000000/MicroProdN1p2_NDLAr_1E18_RHC.caf.nu.00000*"; + //"/exp/dune/data/users/noeroy/mywork/MiniRun5_Fixed_truth/MiniRun5_1E19_RHC.caf/CAF.flat/0000000/*.flat.root"; + + // Source of events + SpectrumLoader loader(fname); + + // Define axes for the spectra we'll make + const RecoPartHistAxis axEnergy("Best-matched true particle energy (GeV)", Binning::Simple(50, 0, 5), kMatchedTruePartE); + + Spectrum sEnergyMatched(loader.Interactions(RecoType::kDLP).RecoParticles(RecoType::kDLP)[kIsMuon], axEnergy); + Spectrum sEnergyMatchedTrueMu(loader.Interactions(RecoType::kDLP).RecoParticles(RecoType::kDLP)[kIsMuon && kMatchedToTrueMuon], axEnergy); + + const HistAxis axNuEnergy("True matched neutrino energy (GeV", Binning::Simple(50, 0, 20), kMatchedTrueInteractionEnergy); + Spectrum sNuEnergyMatched(loader.Interactions(RecoType::kDLP), axNuEnergy); + Spectrum sNuEnergyMatchedTrue(loader.Interactions(RecoType::kDLP)[kMatchedToTrueRES], axNuEnergy); + + // ~~~~**** -.-.-.-.-.-.-.-.-.-.-.- *****~~~~ + // Fill in the spectrum + loader.Go(); + + const double pot = sEnergyMatched.POT(); + //1e17; + + TCanvas c; + TLegend leg(0.6, 0.6, 0.9, 0.9); + leg.SetFillStyle(0); + leg.SetBorderSize(0); + + auto h1 = sEnergyMatched.ToTH1(pot); + h1->Draw("hist"); + leg.AddEntry(h1, "All reco muons"); + + auto h2 = sEnergyMatchedTrueMu.ToTH1(pot, kRed); + h2->Draw("hist same"); + leg.AddEntry(h2, "+ matched to true muons"); + + leg.Draw(); + + c.SaveAs("recoMu_matchedTrueE.png"); + + + TCanvas c2; + TLegend leg2(0.6, 0.6, 0.9, 0.9); + leg2.SetFillStyle(0); + leg2.SetBorderSize(0); + + auto h3 = sNuEnergyMatched.ToTH1(pot); + h3->Draw("hist"); + leg2.AddEntry(h3, "All neutrino ixn"); + + auto h4 = sNuEnergyMatchedTrue.ToTH1(pot, kRed); + h4->Draw("hist same"); + leg2.AddEntry(h2, "+ matched to RES"); + leg2.Draw(); + + c2.SaveAs("TrueE_matchedRES.png"); +} diff --git a/CAFAna/tute/demo0b.C b/CAFAna/tute/demo0b.C new file mode 100644 index 00000000..85ba9091 --- /dev/null +++ b/CAFAna/tute/demo0b.C @@ -0,0 +1,228 @@ + +#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" + +#include "CAFAna/Core/SpectrumLoader.h" +#include "CAFAna/Core/Spectrum.h" +#include "CAFAna/Core/Binning.h" +#include "CAFAna/Core/Var.h" +#include "CAFAna/Core/Cut.h" +#include "CAFAna/Core/HistAxis.h" + +#include "TCanvas.h" +#include "TH1.h" +#include "TH2.h" +#include "TPad.h" +#include "TLegend.h" +#include +using namespace ana; + +// Make a few basic spectra from the cafs +// Reconstructed +// - One with Interaction Level vars/cuts +// - One with particle-level vars/cuts +// Truth +// - True interaction Level Vars/Cuts +// - True particles Level Vars/Cuts + + +void demo0b( std::string option = "flat") +{ + + std::string fname; + if(option=="caf") fname = "/exp/dune/data/users/skumara/Datafiles_2x2/CAF_rootfiles/MR5_beta2a_flash/test_flash.root"; + + if (option=="flat") fname = "/exp/dune/data/users/noeroy/mywork/MiniRun5_Fixed_truth/MiniRun5_1E19_RHC.caf/CAF.flat/0000000/*.flat.root"; + + + // Source of events + SpectrumLoader loader(fname); + + ///////////////////////////////////////////////////////////////// + // Reco-Particles (SRRecoParticleProxy) level vars and cuts + const RecoPartVar kRecoParticleEnergy = SIMPLEPARTVAR(E); + // Define axes for the spectra we'll make + const RecoPartHistAxis axEnergy("Muon energy (GeV)", Binning::Simple(50, 0, 1), kRecoParticleEnergy); + // Select particles that have a pdg of muon, + const RecoPartCut kIsMuon([](const caf::SRRecoParticleProxy* sr) + { + return abs(sr->pdg) == 13 ; + }); + + ///////////////////////////////////////////////////////////////// + // Interaction level (SRInteractionProxy) Simple vars + const Var kVtxX = SIMPLEVAR(vtx.x); + // we can also write vars with additional logic/operations + const Var kVtxZ([](const caf::SRInteractionProxy* sr) + { + double z = sr-> vtx.z;//-1300; + // you could do more operations here + return z; + }); + + // Histaxis with interaction level variables + // Note you can setup a 2D axis, you can directly write simple vars here + const HistAxis vtxPosition( "x(cm)", Binning::Simple(70,-70,70), kVtxX, + "z(cm)", Binning::Simple(70,-70,70), SIMPLEVAR(vtx.z)); //or kVtxZ + + // A simple selection cut at the level of vertices: i.e. containment + const Cut kContainedVertex([](const caf::SRInteractionProxy* sr) + { + double x = sr->vtx.x; + double y = sr->vtx.y; + double z = sr->vtx.z; + bool cont = abs(x)<50 && + abs(x)>10 && + abs(y)<50 && + abs(z)>10 && + abs(z)<50 ; + return cont; + }); + + + ///////////////////////////////////////////////////////////////// + // ~~~~**** now actually make some histograms *****~~~~ + // we use kNoCut at interactions level, meaning no selection on vertices, then with containment + // You can select RecoType::kDLP,kPandora at vtx/interaction level and kPIDA as well for particles + Spectrum sEnergyMuon( loader.Interactions(RecoType::kDLP)[kNoCut].RecoParticles( RecoType::kDLP)[kIsMuon], axEnergy); + Spectrum sEnergyMuonCont( loader.Interactions(RecoType::kDLP)[kContainedVertex].RecoParticles(RecoType::kDLP)[kIsMuon], axEnergy); + // Interaction level vars + Spectrum sVtxPositionAll( loader.Interactions(RecoType::kDLP)[kNoCut], vtxPosition); + Spectrum sVtxPositionCont(loader.Interactions(RecoType::kDLP)[kContainedVertex], vtxPosition); + + // You need the histaxis to match the Cut level (i.e: the next one will not work becausePosition is an SRInteraction entry + // but your spectrumLoader points to entries from SRRecoParticle + // Spectrum sVtxPositionCont(loader.Interactions(RecoType::kDLP)[kContainedVertex].RecoParticles(RecoType::kDLP)[kIsMuon], vtxPosition); + + ///////////////////////////////////////////////////////////////// + + const TruthVar kTrueId([](const caf::SRTrueInteractionProxy* nu){return nu->id;}); + + // lets try a reco histaxis wuth truth selection ... + const TruthCut kIsTrueNuMu ([](const caf::SRTrueInteractionProxy* nu){ + int pdg = nu->pdg; + return pdg==14; + }); + + const TruthCut kTruthContainedVertex ([](const caf::SRTrueInteractionProxy* nu){ + double x = nu->vtx.x; + double y = nu->vtx.y; + double z = nu->vtx.z; + bool cont = abs(x)<50 && + abs(x)>10 && + abs(y)<50 && + abs(z)>10 && + abs(z)<50 ; + return cont; + }); + + // This can be used for prefsi, primary or secondary particles. See spectrum constructor later. + const TruthPartVar kTruePartPDG([](const caf::SRTrueParticleProxy* part){ + int pdg = part->pdg; + // recast in a different way + //(1) muon + if ( abs(pdg)==13) return 1.; + //(2) electron + if ( abs(pdg)==11) return 2.; + //(3) proton + if ( pdg==2212) return 3.; + // (4) neutron + if ( pdg==2112) return 4.; + // (5) pi + + if ( pdg==211) return 5.; + // (6) pi - + if ( pdg==-211) return 6.; + // (7) pi0 + if ( pdg==111) return 7.; + // (8) photon + if (pdg==22) return 8.; + // (9) Any K0S, K0L K0 or K+/- + if (abs(pdg)==321 || pdg== 311|| pdg== 310|| pdg== 130) return 9.; + else{ + //std::cout< PDGlabels = {"#mu", "e","p","n","#pi^{+}","#pi^{-}","#pi^{0}","#gamma","K","other"}; + + const TruthHistAxis myHistTruthAxisPDG("true pdg", Binning::Simple(100, 0, 100), SIMPLETRUTHVAR(pdg)); + const TruthPartHistAxis myHistTruthPartAxisPDG("true particles pdg", Binning::Simple(10, 1, 11), kTruePartPDG); + + ///////////////////////////////////////////////////////////////// + // ~~~~**** now make some more histograms *****~~~~ + // this kind of an ugly plot + Spectrum PDGTrue(loader.NuTruths(), myHistTruthAxisPDG); + Spectrum sTrueNumuPDGtest(loader.NuTruths()[kIsTrueNuMu], myHistTruthAxisPDG); + + Spectrum PDGTruePrims(loader.NuTruths().TruthParticles(TruePType::kPrim)[kNoTruthPartCut], myHistTruthPartAxisPDG); + Spectrum PDGTrueSecs(loader.NuTruths()[kNoTruthCut].TruthParticles(TruePType::kSec)[kNoTruthPartCut], myHistTruthPartAxisPDG); + Spectrum PDGTruePreFSI(loader.NuTruths()[kNoTruthCut].TruthParticles(TruePType::kPreFSI)[kNoTruthPartCut], myHistTruthPartAxisPDG); + + Spectrum sTrueVtxPositionAll( loader.NuTruths(), + TruthHistAxis("Truth x(cm)", Binning::Simple(70,-70,70), SIMPLETRUTHVAR(vtx.x), + "Truth z(cm)", Binning::Simple(70,-70,70), SIMPLETRUTHVAR(vtx.z))); + Spectrum sTrueVtxPositionCont(loader.NuTruths()[kTruthContainedVertex], + TruthHistAxis("Truth x(cm)", Binning::Simple(70,-70,70), SIMPLETRUTHVAR(vtx.x), + "Truth z(cm)", Binning::Simple(70,-70,70), SIMPLETRUTHVAR(vtx.z))); + + Spectrum sTrueNumuEnergy( loader.NuTruths(), TruthHistAxis("True neutrino energy [GeV]", Binning::Simple(50,0,10),SIMPLETRUTHVAR(E)) ); + + ///////////////////////////////////////////////////////////////// + + // Fill in the spectra + loader.Go(); + + std::cout<< "Spectrum sTrueNumuPDGtest has"<< sTrueNumuPDGtest.ToTH1(sTrueNumuPDGtest.POT())->GetNbinsX() << "bins, and the axis "<< sTrueNumuPDGtest.GetBinnings()[0].NBins()<< " NBins\n"; + std::cout<< "eigen has size: "<< sTrueNumuPDGtest.GetEigen().rows() << "," << sTrueNumuPDGtest.GetEigen().cols()<Draw("hist"); + TH1 *emuCont=sEnergyMuonCont.ToTH1(pot,kMagenta+2); emuCont->Draw("hist same"); + auto *lege = new TLegend(.55,.5,.88,.88); + lege->AddEntry(emu, "All #mu energy","L"); + lege->AddEntry(emuCont, "Cont. #mu energy","L"); + lege->Draw(); + gPad->SaveAs(("demo0_sEnergyMuon"+option+".pdf").c_str()); + + new TCanvas; + PDGTrue.ToTH1(pot,kBlue)->Draw("hist same"); + sTrueNumuPDGtest.ToTH1(pot,kRed, kDashed)->Draw("hist same"); + + new TCanvas; + // you can also retrieve the TH1 * object and manipulate as usual in root + TH1* prims = PDGTruePrims.ToTH1(pot,kRed); + for (unsigned int i = 0; iGetXaxis()->SetBinLabel(i+1,PDGlabels[i].c_str()); + prims->SetTitle("True particles ID"); + prims->Draw("hist"); + TH1* secs = PDGTrueSecs.ToTH1(pot,kBlue); secs->Draw("hist same"); + TH1 *prefsi= PDGTruePreFSI.ToTH1(pot,kGreen+2); prefsi->Draw("hist same"); + auto *leg = new TLegend(.55,.7,.88,.88); + leg->AddEntry(prims, "Primaries","L"); + leg->AddEntry(secs, "Secondaries","L"); + leg->AddEntry(prefsi, "Pre-FSI","L"); + leg->SetFillStyle(0); + leg->Draw(); + gPad->SaveAs(("demo0_PDGprims_"+option+".pdf").c_str()); + + new TCanvas; + sTrueNumuEnergy.ToTH1(sTrueNumuEnergy.POT())->Draw("hist"); + + new TCanvas; + sVtxPositionAll.ToTH2(pot)->Draw("colz"); + gPad->SaveAs(("demo0_vtxPosAll_"+option+".pdf").c_str()); + new TCanvas; + sVtxPositionCont.ToTH2(pot)->Draw("colz"); + gPad->SaveAs(("demo0_vtxPosCont_"+option+".pdf").c_str()); + + + new TCanvas; + sTrueVtxPositionAll.ToTH2(sTrueVtxPositionAll.POT())->Draw("colz"); + gPad->SaveAs(("demo0_TruevtxPosAll_"+option+".pdf").c_str()); + new TCanvas; + sTrueVtxPositionCont.ToTH2(sTrueVtxPositionCont.POT())->Draw("colz"); + gPad->SaveAs(("demo0_TruevtxPosCont_"+option+".pdf").c_str()); + +} diff --git a/CAFAna/tute/demo0eb.C b/CAFAna/tute/demo0eb.C new file mode 100644 index 00000000..dd55de96 --- /dev/null +++ b/CAFAna/tute/demo0eb.C @@ -0,0 +1,434 @@ + +#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" + +#include "CAFAna/Core/SpectrumLoader.h" +#include "CAFAna/Core/Spectrum.h" +#include "CAFAna/Core/Binning.h" +#include "CAFAna/Core/EnsembleSpectrum.h" +#include "CAFAna/Core/EnsembleRatio.h" +#include "CAFAna/Core/LoadFromFile.h" +#include "CAFAna/Core/Multiverse.h" +#include "CAFAna/Core/Var.h" +#include "CAFAna/Core/Cut.h" +#include "CAFAna/Core/HistAxis.h" +#include "CAFAna/Core/ISyst.h" +#include "CAFAna/Core/Utilities.h" + +#include "TFile.h" +#include "TCanvas.h" +#include "TH1.h" +#include "TH2.h" +#include "TPad.h" +#include "TColor.h" +#include + +using namespace ana; + +// Setup a dummy systematic that shifts Particle (Muon) Enegy by a +/- percent + + class EnergyScaleMu: public ISyst { + public: + EnergyScaleMu() : ISyst("EnergyScaleMu", "Muon Energy Scale Syst") {} + void Shift(double sigma, + caf::SRInteractionProxy* ixn, double& weight) const override; + }; + void EnergyScaleMu::Shift(double sigma, + caf::SRInteractionProxy* ixn, double& weight) const { + double scale = .05 * sigma; + + // loop through particles and change record to shift energy + for (int i=0; ipart.ndlp; i++){ + if ( abs(ixn->part.dlp[i].pdg)==13) { + ixn->part.dlp[i].E *= 1. + scale; + } + } + } + + const EnergyScaleMu kEnergyScaleMu; + + +//// A second dummy syst to have a multiverse with multiple systs +// A reweight systematic... multiply times [x] all events that pass [ some ] criteria + class MuonRwgtSyst : public ISyst + { + public : + MuonRwgtSyst(double scale, const std::string shortName, const std::string latexName) + : ISyst( shortName , latexName ), fScale(scale) {} + + void Shift( double sigma, caf::SRInteractionProxy* ixn, double& weight ) const override; + + private: + double fScale; + + }; + void MuonRwgtSyst::Shift( double sigma, caf::SRInteractionProxy* ixn, double& weight ) const + { + bool hasMuon = false; + // loop through particles see if theres a muon + for (int i=0; ipart.ndlp; i++){ + if ( abs(ixn->part.dlp[i].pdg)==13) { + hasMuon= true; + } + } + if (hasMuon){ + weight = 1 + sigma * fScale; + //std::cout<< " Found a Muon, wgt = "< +//{ +//public: +// MECScaleSyst(double scale, const std::string shortName, const std::string latexName) +// : ISyst(shortName, latexName), fScale(scale) {} +// +// void Shift( double sigma, caf::SRTrueInteractionProxy* ixn, double& weight) const override; +// +// private: +// double fScale; +//}; +//void MECScaleSyst::Shift(double sigma, caf::SRTrueInteractionProxy* ixn, double& weight) const +//{ +// if (ixn->mode == ScatteringMode::kMEC) +// weight = 1 + sigma * fScale; +// else +// weight=1; +//} +//const MECScaleSyst kMECScaleSyst(0.10, "MECScaleSyst", "MEC scale systematic"); +// Var that takes energy of the most energetic muon in interaction +const Var kEnergyInteractionMu([](const caf::SRInteractionProxy* ixn) + { + double e = -5.; + + int numMuons = 0; + for (int i=0; ipart.ndlp; i++){ + // check if muon + //std::cout<< "we are in particle "<< i<part.dlp[i].pdg)==13) { + numMuons ++; + //this muons energy + double tempE = ixn->part.dlp[i].E; + //std::cout<< "found muon # "<< numMuons<< ", idx "<1 ){ + // check which one has more energy + if (tempE>e) + e=tempE; // store if this muon has more energy + }else{ e = tempE;} + } + + } + return e; + }); + +// Var that sums up Energy of all tracks +// Var that takes energy of the most energetic muon in interaction +const Var kEnergyInteractionAll([](const caf::SRInteractionProxy* ixn) + { + double e = 0.; + for (int i=0; ipart.ndlp; i++){ + double tempE = ixn->part.dlp[i].E; + e = e + tempE; + }// in the weird case interaction had nothing?? + //if (e == 0) return -5.; + return e; + }); +// Var that takes energy of the most energetic muon in interaction +const Var kEnergyInteractionButMu([](const caf::SRInteractionProxy* ixn) + { + return kEnergyInteractionAll(ixn) - kEnergyInteractionMu(ixn); + }); + + + // A simple selection cut at the level of vertices: i.e. containment + const Cut kContainment([](const caf::SRInteractionProxy* ixn) + { + + double x = ixn->vtx.x; + double y = ixn->vtx.y; + double z = ixn->vtx.z; + bool cont = abs(x)<50 && + abs(x)>10 && + abs(y+310)<50 && + abs(z-1300)>10 && + abs(z-1300)<50 ; + return cont; + }); + +// Has only one muon + const Cut kHas1RecoMuon([](const caf::SRInteractionProxy* ixn) + { + int nMuons= 0; + for (int i=0; ipart.ndlp; i++){ + if ( abs(ixn->part.dlp[i].pdg)==13) { + nMuons++; + } + } + return (nMuons==1); + }); + + const RecoPartVar kRecoParticleEnergy = SIMPLEPARTVAR(E); + // Select particles that have a pdg of muon + const RecoPartCut kIsMuon([](const caf::SRRecoParticleProxy* sr) + { + return abs(sr->pdg) == 13 ; + }); + + +// Make a basic ensemble spectrum? +// based on https://github.com/SBNSoftware/sbnana/blob/feature/ext_cafanacore/sbnana/CAFAna/test/test_ensemble.C +void demo0eb() +{ + + // test multiverse + std::vector systs; //,systs2; + systs.push_back(&kEnergyScaleMu); + systs.push_back(&kMuonRwgtSyst); + //systs.push_back(&kDummyRwgtSyst); + + + // Two methods of generatig multiverse + // 100 Random values grom a gaussian distribution + // using the specific seed = 42 + const Multiverse& gas = Multiverse::RandomGas(systs, 100, 42); + // scans from -n to n sigma shifts, we'll do only the 1 sigma + const Multiverse& cross = Multiverse::Hypercross(systs,1); + + + + std::cout << gas.LatexName() << std::endl << gas.ShortName() << std::endl; + std::cout << cross.LatexName() << std::endl << cross.ShortName() << std::endl; + + std::cout << "gas has "<< gas.NUniv() << "universes from NUniv()\n"; + std::cout << "cross has "<< cross.NUniv() << "universes from NUniv()\n"; + // we can save our multiverses to file + TFile fout("test_multiverse.root", "RECREATE"); + gas.SaveTo(&fout, "gas"); + cross.SaveTo(&fout, "cross"); + fout.Close(); + + // and then retrieve multiverses from file + TFile fin("test_multiverse.root"); + const FitMultiverse& gas2 = *Multiverse::LoadFrom(&fin, "gas"); + const FitMultiverse& cross2 = *Multiverse::LoadFrom(&fin, "cross"); + +// you can print out exactly what are the values of each multiverse. +/* for (int i = 0; i< gas2.NUniv(); i++){ + for (const auto & [ key, value ] : gas2.GetUniverse(i)) { + std::cout << key->ShortName() << ": " << value << std::endl; + } + } +*/ + // you can print the hypercross universe to see what is going on + for (int i = 0; i< cross.NUniv(); i++){ + for (const auto & [ key, value ] : cross.GetUniverse(i)) { + std::cout << key->ShortName() << ": " << value << std::endl; + } + } + fin.Close(); + //----------------------------------------------------------------------// + // now make ensemble spectra + + const Binning binsEnergy = Binning::Simple(10, 0, 1); + + const HistAxis axMuEnergy("Muon energy (GeV)", binsEnergy, kEnergyInteractionMu); + const HistAxis axEnergy("Interaction energy (GeV)", binsEnergy, kEnergyInteractionAll); + const HistAxis axNoMuEnergy("non-muon energy (GeV)", binsEnergy,kEnergyInteractionButMu); + + const RecoPartHistAxis axRecoPartEnergy("Reco Particle Energy", binsEnergy, kRecoParticleEnergy); + + //std::vector weis; + //weis.reserve(101); + //weis.push_back(kUnweighted); // nominal + // TO DO: generate multiverse weights + //for(int i = 0; i < 99; ++i) weis.push_back(GetUniverseWeight("multisim_Genie", i)); + + const std::string fname = "/exp/dune/data/users/noeroy/mywork/MiniRun5_Fixed_truth/MiniRun5_1E19_RHC.caf/CAF.flat/0000000/*.flat.root"; + + // Source of events + SpectrumLoader loader(fname); + // This is another key line // dont know what is the 2nd [cut] applied to... + //EnsembleSpectrum sMuonEnsembleGauss(loader.Interactions(RecoType::kDLP).Ensemble(weis)[kContainment][kIsNumuCC], axEnergy); + // weis is a vector of weights that come from GetUniverseWeight + + // or whatever multiverse object, in this case randomly generated gaussian shifts + EnsembleSpectrum sMuonEnsembleGauss(loader.Interactions(RecoType::kDLP).Ensemble(gas)[kHas1RecoMuon], axMuEnergy); + EnsembleSpectrum sMuonEnsembleX(loader.Interactions(RecoType::kDLP).Ensemble(cross)[kHas1RecoMuon], axMuEnergy); + // Another way to access the same information from the reco particles branch + EnsembleSpectrum sMuonEnsemblePartX(loader.Interactions(RecoType::kDLP).Ensemble(cross)[kHas1RecoMuon].RecoParticles(RecoType::kDLP)[kIsMuon], axRecoPartEnergy); + // Doing the same for other particles to verify our systematic is working as expected + EnsembleSpectrum sOtherEnsemblePartX(loader.Interactions(RecoType::kDLP).Ensemble(cross)[kHas1RecoMuon].RecoParticles(RecoType::kDLP)[!kIsMuon], axRecoPartEnergy); + + + // The same but for a different variable + EnsembleSpectrum sAllEnsembleX(loader.Interactions(RecoType::kDLP).Ensemble(cross)[kHas1RecoMuon], axEnergy); + EnsembleSpectrum sNoMuEnsembleX(loader.Interactions(RecoType::kDLP).Ensemble(cross)[kHas1RecoMuon], axNoMuEnergy); + + + // some true distributions of MEC things + //EnsembleSpectrum sAllMECEnsemble(loader.NuTruths().Ensemble(crossMEC)[kIsMEC], axTrueEnergy); + //EnsembleSpectrum sAllnonMECEnsemble(loader.NuTruths().Ensemble(crossMEC)[!kIsMEC], axTrueEnergy); + + loader.Go(); + + const double pot = sMuonEnsembleGauss.POT();// 3.5 * 1.47e21 * 40/1.13; + + + //----------- save to file + TFile fout2("multiverse_ensemble_test.root", "RECREATE"); + sMuonEnsembleGauss.SaveTo(&fout2, "sMuonEnsembleGauss"); + sMuonEnsembleX.SaveTo(&fout2, "sMuonEnsembleX"); + fout2.Close(); + + + //----------- Display things in canvases for the gaussian random multiverse + // exercise load from file as well + + TFile fin2("multiverse_ensemble_test.root"); + EnsembleSpectrum sMuonEnsembleGaussFile= *EnsembleSpectrum::LoadFrom(&fin2, "sMuonEnsembleGauss"); + EnsembleSpectrum sMuonEnsembleXFile= *EnsembleSpectrum::LoadFrom(&fin2, "sMuonEnsembleX"); + + + new TCanvas; + TH1 * hsMuonEnsembleGauss = sMuonEnsembleGaussFile.Nominal().ToTH1(pot, kRed); + hsMuonEnsembleGauss->Draw("hist"); + + // a vector to store ratios to nominal + std::vector hratios; + for(unsigned int i = 0; i < sMuonEnsembleGaussFile.NUniverses(); ++i){ + hratios.push_back(sMuonEnsembleGaussFile.Universe(i).ToTH1(pot, kRed-10)); + + sMuonEnsembleGaussFile.Universe(i).ToTH1(pot, kRed-10)->Draw("hist same"); + + hratios.back()->Divide(hsMuonEnsembleGauss); + } + hsMuonEnsembleGauss->Draw("hist same"); + gPad->SaveAs("multiverse_gauss.pdf"); + + hratios[0]->SetMinimum(.6); + hratios[0]->SetMaximum(1.4); + new TCanvas; + for (unsigned int i = 0; i < sMuonEnsembleGaussFile.NUniverses(); ++i) + hratios[i]->Draw("hist same"); + gPad->SaveAs("multiverse_gauss_ratios.pdf"); + + new TCanvas; + // Error band summing in quadrature + TGraphAsymmErrors* eBand =sMuonEnsembleGaussFile.ErrorBand(pot); + DrawErrorBand(hsMuonEnsembleGauss, eBand); + + gPad->SaveAs("multiverse_ErrorBand.pdf"); + + + // Grab covariance matrix + Eigen::MatrixXd m= sMuonEnsembleGaussFile.CovarianceMatrix(pot); + std::cout << "The matrix m is of size " << m.rows() << "x" << m.cols() << std::endl; + // convert to th2 for drawing + TH2F* hCov = EigenMatrixToTH2(m); + new TCanvas; + hCov->Draw("colz"); + gPad->SaveAs("cov_mx.pdf"); + + // grab bias matrix + Eigen::MatrixXd mb= sMuonEnsembleGaussFile.BiasMatrix(pot); + TH2F* hBias = EigenMatrixToTH2(mb); + new TCanvas; + hBias->Draw("colz"); + gPad->SaveAs("bias_mx.pdf"); + + // ------- More canvases for the hypercross univ + new TCanvas; + TH1 * hsMuonEnsembleX = sMuonEnsembleXFile.Nominal().ToTH1(pot, kBlue); + hsMuonEnsembleX->SetMaximum(1.3*hsMuonEnsembleX->GetMaximum()); + hsMuonEnsembleX->Draw("hist"); + // a vector to store ratios to nominal + std::vector hratiosx; + std::cout<< "cross has "<Draw("hist same"); + hratiosx.push_back(sMuonEnsembleXFile.Universe(i).ToTH1(pot, color,kDashed)); + hratiosx.back()->Divide(hsMuonEnsembleX); + + } + hsMuonEnsembleX->Draw("hist same"); + gPad->SaveAs("multiverse_x_.pdf"); + + hratiosx[0]->SetMinimum(.6); + hratiosx[0]->SetMaximum(1.4); + new TCanvas; + for (unsigned int i = 0; i < sMuonEnsembleXFile.NUniverses(); ++i) + hratiosx[i]->Draw("hist same"); + gPad->SaveAs("multiverse_x_ratios.pdf"); + // we dont get covariance out of this one + + new TCanvas; + + TH1 * hsMuonEnsembleX2 = sMuonEnsemblePartX.Nominal().ToTH1(pot, kGreen+2); + TH1 * hsNoMuonEnsembleX2 = sOtherEnsemblePartX.Nominal().ToTH1(pot, kPink); + + + hsMuonEnsembleX2->SetMaximum(1.3*hsMuonEnsembleX2->GetMaximum()); + hsMuonEnsembleX2->Draw("hist"); + hsNoMuonEnsembleX2->Draw("hist same"); + for(unsigned int i = 0; i < sMuonEnsemblePartX.NUniverses(); ++i){ + // using different colors per systematic + Color_t color = kGreen+2; + Color_t color2 =kBlack ; + if (i==0){ color = kGreen+2; color2 =kBlack;} + if (i== 1 || i==2) {color = kViolet +1; color2 =kAzure+2;} + if (i==3 || i==4) {color = kPink; color2=kTeal-7;} + + sMuonEnsemblePartX.Universe(i).ToTH1(pot, color,kDashed)->Draw("hist same"); + sOtherEnsemblePartX.Universe(i).ToTH1(pot, color2,kDashed)->Draw("hist same"); + + } + +/* + // repeat for other variable + new TCanvas; + TH1 * hsAllEnsembleX = sAllEnsembleX.Nominal().ToTH1(pot, kBlue); + TH1 * hsNoMuEnsembleX = sNoMuEnsembleX.Nominal().ToTH1(pot, kGreen+2); + hsAllEnsembleX->Draw("hist"); + hsNoMuEnsembleX->Draw("hist same"); + // a vector to store ratios to nominal + std::vector hratiosxAll, hratiosxNoMu; + std::cout<< "cross has "<Draw("hist same"); + sNoMuEnsembleX.Universe(i).ToTH1(pot, color2, kDashed)->Draw("hist same"); + hratiosxAll.push_back(sAllEnsembleX.Universe(i).ToTH1(pot, color,kDashed)); + hratiosxAll.back()->Divide(hsAllEnsembleX); + hratiosxNoMu.push_back(sNoMuEnsembleX.Universe(i).ToTH1(pot, color2,kDashed)); + hratiosxNoMu.back()->Divide(hsNoMuEnsembleX); + } + hsAllEnsembleX->Draw("hist same"); + //gPad->SaveAs("multiverse_x_all.pdf"); + gPad->SaveAs("multiverse_x_all2.pdf"); + + hratiosxAll[0]->SetMinimum(.6); + hratiosxAll[0]->SetMaximum(1.4); + new TCanvas; + for (unsigned int i = 0; i < sAllEnsembleX.NUniverses(); ++i){ + hratiosxAll[i]->Draw("hist same"); + hratiosxNoMu[i]->Draw("hist same"); + } +// gPad->SaveAs("multiverse_x_ratios_all.pdf"); + gPad->SaveAs("multiverse_x_ratios_all2.pdf"); +*/ +} diff --git a/CAFAna/tute/demo1b.C b/CAFAna/tute/demo1b.C new file mode 100644 index 00000000..3f927c92 --- /dev/null +++ b/CAFAna/tute/demo1b.C @@ -0,0 +1,317 @@ +// Make a simple spectrum plot +// cafe demo0.C + +#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" + +#include "CAFAna/Core/SpectrumLoader.h" +#include "CAFAna/Core/Spectrum.h" +#include "CAFAna/Core/Binning.h" +#include "CAFAna/Core/Var.h" +#include "CAFAna/Core/Cut.h" +#include "CAFAna/Core/HistAxis.h" + +//#include "CAFAna/Cuts/TruthCuts.h" + +#include "TCanvas.h" +#include "TH1.h" +#include "TH2.h" +#include "TPad.h" +#include "TVector3.h" + +using namespace ana; + +const auto beam_dir = TVector3(0.0, -0.05836, 1.0); + + + + +// Mesonless analysis cuts + // From https://indico.fnal.gov/event/61771/contributions/277573/attachments/172154/ + //Require 1 muon (either +/-), 0 pions, and N protons as primary particles (no cuts on photons or electrons tagged as primaries) + //No requirement on the muon entering/exiting MINERvA + //No fiducial volume cuts, No containment cuts +const Cut kMesonlessSelection([](const caf::SRInteractionProxy* sr) + { + int num_muons = 0; + int num_prtns = 0; + int num_pions = 0; + int num_phtns = 0; + int num_elecs = 0; + // loop over particles and count each type + for (const auto & part : sr->part.dlp ){ + if(part.primary == false) + continue; + if( abs(part.pdg) == 13) + num_muons++; + if(part.pdg == 211) + num_pions++; + if(part.pdg == 2212) + num_prtns++; + if(part.pdg == 22) + num_phtns++; + if(part.pdg == 11) + num_elecs++; + } + return ( num_muons==1 && num_pions<1 && num_prtns>0 ); + }); + +const RecoPartCut kContainedPart([](const caf::SRRecoParticleProxy* part){return part->contained;}); + +TVector3 RecoPartDir(const caf::SRRecoParticleProxy* part){ + + TVector3 ret = TVector3(part->end.x, part->end.y, part->end.z) - + TVector3(part->start.x,part->start.y,part->start.z); + return ret; +} + +const RecoPartCut kPartLenCut([](const caf::SRRecoParticleProxy* part) + { + auto len=-5.; + // prevent showers to be accounted + if (part->E_method != caf::PartEMethod::kCalorimetry) len = RecoPartDir(part).Mag(); + return len>2; + }); + +const RecoPartVar kPartLen([](const caf::SRRecoParticleProxy* part) + { + auto len=-5.; + // prevent trying to calculate shw lenght, as they have infinity end-point + if (part->E_method != caf::PartEMethod::kCalorimetry) len = RecoPartDir(part).Mag(); + return len; + }); + +// A generic selection on the pdg of the particle + const RecoPartCut kPartCut(int PDG){ + const RecoPartCut kIsPDG([PDG](const caf::SRRecoParticleProxy* part) + { + return abs(part->pdg) == PDG ; + }); + return kIsPDG; + } +// vars + +const RecoPartVar kPartAngle([](const caf::SRRecoParticleProxy* part) + { + //auto dir = TVector3(part->end.x, part->end.y, part->end.z) - + // TVector3(part->start.x,part->start.y,part->start.z); + auto angle = RecoPartDir(part).Angle(beam_dir) * 180.0 / TMath::Pi(); + //auto angle = TVector3(part->p.x,part->p.y,part->p.z).Angle(beam_dir) * 180.0 / TMath::Pi(); + return angle; + }); + // momentum +const RecoPartVar kPartMomentum([](const caf::SRRecoParticleProxy* part) + { + float p = std::sqrt( (part->p.x * part->p.x) + (part->p.y * part->p.y) + (part->p.z * part->p.z)); + return p; + }); + + +// Using E_method to count tracks/showers, because there's currently no implementation to combine +// entreis from SRNDLarIntProxy and SRInteractionProxy +const Var kNumberOfTracks([](const caf::SRInteractionProxy* ixn) + { + double num_tracks=0; + + for (int j=0; jpart.ndlp; j++){ + if ( ixn->part.dlp[j].E_method == caf::PartEMethod::kRange || + ixn->part.dlp[j].E_method == caf::PartEMethod::kMCS ) + num_tracks++; + + } + return num_tracks; + }); +// +const Var kNumberOfShowers([](const caf::SRInteractionProxy* ixn) + { + double num_shw=0; + for (int j=0; jpart.ndlp; j++){ + if ( ixn->part.dlp[j].E_method == caf::PartEMethod::kCalorimetry) + num_shw++; + + } + return num_shw; + }); + +const Var kNumberOfTrkShw([](const caf::SRInteractionProxy* ixn) + { + return ixn->part.ndlp; + }); + + + +void demo1b() +{ + // Environment variables and wildcards work. As do SAM datasets. + const std::string fname = "/exp/dune/data/users/noeroy/prod/MiniRun5_1E19_RHC/MiniRun5_1E19_RHC.caf.beta1/CAF/0000000/*.root"; + //"/pnfs/dune/persistent/users/mkramer/productions/MiniRun4.5_1E19_RHC/CAF_beta3/CAF/0000000/MiniRun4.5_1E19_RHC.caf.0000*"; + //"/dune/data/users/skumara/Datafiles_2x2/CAF_rootfiles/Picorun4.2/flat/PicoRun4.2_1E17_RHC.flow.0000*"; + /// "/dune/data/users/skumara/Datafiles_2x2/CAF_rootfiles/minirun4/notruth/outputCAF_notruth_*"; + // "/dune/data/users/skumara/Datafiles_2x2/CAF_rootfiles/Picorun4.2/PicoRun4.2_1E17_RHC.flow*"; +// "/dune/data/users/skumara/Datafiles_2x2/CAF_rootfiles/Picorun4.1/PicoRun4.1_1E17_RHC.flow*"; + + + // Source of events + SpectrumLoader loader(fname); + + // We will also use two different Vars. For such simple ones we can use this + // Variables at the level of Particles + const RecoPartVar kRecoParticleEnergy = SIMPLEPARTVAR(E); + const RecoPartVar kRecoParticlePDG = SIMPLEPARTVAR(pdg); + + // Define axes for the spectra we'll make + const RecoPartHistAxis axEnergy("Muon energy (GeV)", Binning::Simple(50, 0, 1), kRecoParticleEnergy); + const RecoPartHistAxis axPDG("PDG of reco particle", Binning::Simple(14, 0, 14), kRecoParticlePDG); + + +// Select particles that have a pdg of muon + const RecoPartCut kIsMuon([](const caf::SRRecoParticleProxy* sr) + { + return abs(sr->pdg) == 13 ; + }); + +// A simple selection cut at the level of vertices: i.e. containment +const Cut kContainment([](const caf::SRInteractionProxy* ixn) + { + double x = ixn->vtx.x; + double y = ixn->vtx.y; + double z = ixn->vtx.z; + bool cont = abs(x)<50 && + abs(x)>10 && + abs(y)<50 && + abs(z)>10 && + abs(z)<50 ; + return cont; + }); + + +const Cut kShwCut([](const caf::SRInteractionProxy* ixn) + { + //Vertex must have more than one shower and 0 tracks. + return !(kNumberOfShowers(ixn)==1 && kNumberOfTracks(ixn)==0 ) ; + }); + + + + //2D histaxis with interaction level variables + const HistAxis vtxPosition( "x(cm)", Binning::Simple(60,-60,60), SIMPLEVAR(vtx.x), + "z(cm)", Binning::Simple(60,-60,60), SIMPLEVAR(vtx.z)); + +// Multiplicity of all particles reconstructed from selected vertices + // tracks + // showers + const HistAxis trackMult("Number of particles", Binning::Simple(20,0,20), kNumberOfTracks); + const HistAxis shwMult("Number of particles", Binning::Simple(20,0,20), kNumberOfShowers); + const HistAxis trkshwMult("Number of particles", Binning::Simple(20,0,20), kNumberOfTrkShw); + + // - Track length of all reconstructed tracks binned in 1 cm bins. + const RecoPartHistAxis trkLen("Track length (cm)", Binning::Simple(100,0,100),kPartLen); + + +// ~~~~**** where the magic happens *****~~~~ + // we use kNoCut at interactions level, meaning no selection on vertices + Spectrum sEnergyMuon(loader.Interactions(RecoType::kDLP).RecoParticles(RecoType::kDLP)[kIsMuon], axEnergy); + Spectrum sEnergyMuonContX(loader.Interactions(RecoType::kDLP)[kContainment].RecoParticles(RecoType::kDLP)[kIsMuon], axEnergy); + Spectrum sEnergyElectron(loader.Interactions(RecoType::kDLP).RecoParticles(RecoType::kDLP)[kPartCut(11)], axEnergy); + + Spectrum sVtxPositionAll(loader.Interactions(RecoType::kDLP), vtxPosition); + Spectrum sVtxPositionCont(loader.Interactions(RecoType::kDLP)[kContainment], vtxPosition); +// +//// This wont work with a cut because the information of number of tracks +//// is in a different branch than the vtx position information + Spectrum sTrackMultContained( loader.Interactions(RecoType::kDLP)[kContainment && kShwCut], trackMult); + Spectrum sShowerMultContained(loader.Interactions(RecoType::kDLP)[kContainment && kShwCut], shwMult); + Spectrum sAllMultContained( loader.Interactions(RecoType::kDLP)[kContainment && kShwCut], trkshwMult); + + Spectrum sTrackLen(loader.Interactions(RecoType::kDLP)[kContainment && kShwCut].RecoParticles(RecoType::kDLP)[kNoPartCut], trkLen); + +////// Mesonless analysis plots +// /// Mesonless analysis axes +// const RecoPartHistAxis axPartMomentum("Momentum (GeV)", Binning::Simple(50, 0.0, 1.0), kPartMomentum); +// const RecoPartHistAxis axPartAngle("angle(deg)",Binning::Simple(60, 0.0, 180),kPartAngle); +// //Candidate = primary protons in selected interactions +// // All +// Spectrum CandidateProtonMomentum(loader.Interactions(RecoType::kDLP)[kMesonlessSelection].RecoParticles(RecoType::kDLP)[kPartCut(2212)],axPartMomentum ); +// Spectrum AllProtonMomentum(loader.Interactions(RecoType::kDLP)[kNoCut].RecoParticles(RecoType::kDLP)[kPartCut(2212)],axPartMomentum ); +// +// Spectrum CandidateProtonMomentumCont(loader.Interactions(RecoType::kDLP)[kMesonlessSelection].RecoParticles(RecoType::kDLP)[kPartCut(2212)&&kContainedPart&&kPartLenCut],axPartMomentum ); +// Spectrum AllProtonMomentumCont( loader.Interactions(RecoType::kDLP)[kNoCut].RecoParticles(RecoType::kDLP)[kPartCut(2212)&&kContainedPart&&kPartLenCut],axPartMomentum ); +// +// +// Spectrum CandidateProtonAngle(loader.Interactions(RecoType::kDLP)[kMesonlessSelection].RecoParticles(RecoType::kDLP)[kPartCut(2212)],axPartAngle ); +// Spectrum AllProtonAngle(loader.Interactions(RecoType::kDLP)[kNoCut].RecoParticles(RecoType::kDLP)[kPartCut(2212)],axPartAngle ); +// +// Spectrum CandidateProtonAngleCont(loader.Interactions(RecoType::kDLP)[kMesonlessSelection].RecoParticles(RecoType::kDLP)[kPartCut(2212)&&kContainedPart&&kPartLenCut],axPartAngle ); +// Spectrum AllProtonAngleCont( loader.Interactions(RecoType::kDLP)[kNoCut].RecoParticles(RecoType::kDLP)[kPartCut(2212)&&kContainedPart&&kPartLenCut],axPartAngle ); +// + +// ~~~~**** -.-.-.-.-.-.-.-.-.-.-.- *****~~~~ + // Fill in the spectrum + loader.Go(); + + // We are forcing the pot value because cafs dont have this information yet + const double pot = 1e17; + + sEnergyMuon.OverridePOT(pot); + sEnergyMuonContX.OverridePOT(pot); + sEnergyElectron.OverridePOT(pot); + + sVtxPositionAll.OverridePOT(pot); + sVtxPositionCont.OverridePOT(pot); + + sTrackMultContained.OverridePOT(pot); + sShowerMultContained.OverridePOT(pot); + sAllMultContained.OverridePOT(pot); + + sTrackLen.OverridePOT(pot); +// CandidateProtonMomentum.OverridePOT(pot); +// CandidateProtonMomentumCont.OverridePOT(pot); +// AllProtonMomentum.OverridePOT(pot); +// AllProtonMomentumCont.OverridePOT(pot); +// +// CandidateProtonAngle.OverridePOT(pot); +// CandidateProtonAngleCont.OverridePOT(pot); +// AllProtonAngle.OverridePOT(pot); +// AllProtonAngleCont.OverridePOT(pot); + //ta da! + sEnergyMuon.ToTH1(pot)->Draw("hist"); + sEnergyMuonContX.ToTH1(pot,kMagenta+2)->Draw("hist same"); + sEnergyElectron.ToTH1(pot,kGreen+1)->Draw("hist same"); + + new TCanvas; + sVtxPositionAll.ToTH2(pot)->Draw("colz"); + gPad->SaveAs("demo1b_AllVtxPosition.pdf"); + new TCanvas; + sVtxPositionCont.ToTH2(pot)->Draw("colz"); + gPad->SaveAs("demo1b_ContainedVtxPosition.pdf"); + + new TCanvas; + sTrackMultContained.ToTH1(pot,kBlue,kDashed)->Draw("hist same"); + sAllMultContained.ToTH1(pot,kRed,kDotted)->Draw("hist same"); +// sShowerMultContained.ToTH1(pot,kRed,kDotted)->Draw("hist same"); + gPad->SaveAs("demo1b_ContainedMultiplicity.pdf"); + + new TCanvas; + sTrackLen.ToTH1(pot,kRed,kDotted)->Draw("hist same"); + gPad->SaveAs("demo1b_ContainedTrackLen.pdf"); +// +// new TCanvas; +// CandidateProtonMomentum.ToTH1(pot)->Draw("hist"); +// CandidateProtonMomentumCont.ToTH1(pot,kRed)->Draw("hist same"); +// gPad->SaveAs("demo1b_mesonless_CandidateProtonMomentum.pdf"); +// +// new TCanvas; +// AllProtonMomentum.ToTH1(pot)->Draw("hist"); +// AllProtonMomentumCont.ToTH1(pot,kRed)->Draw("hist same"); +// gPad->SaveAs("demo1b_All_CandidateProtonMomentum.pdf"); +// +// new TCanvas; +// CandidateProtonAngle.ToTH1(pot)->Draw("hist"); +// CandidateProtonAngleCont.ToTH1(pot,kRed)->Draw("hist same"); +// gPad->SaveAs("demo1b_mesonless_CandidateProtonAngle.pdf"); +// +// new TCanvas; +// AllProtonAngle.ToTH1(pot)->Draw("hist"); +// AllProtonAngleCont.ToTH1(pot,kRed)->Draw("hist same"); +// gPad->SaveAs("demo1b_All_CandidateProtonAngle.pdf"); + +} diff --git a/CAFAna/tute/demo2eb.C b/CAFAna/tute/demo2eb.C new file mode 100644 index 00000000..1defa243 --- /dev/null +++ b/CAFAna/tute/demo2eb.C @@ -0,0 +1,219 @@ + +#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" + +#include "CAFAna/Core/SpectrumLoader.h" +#include "CAFAna/Core/Spectrum.h" +#include "CAFAna/Core/Binning.h" +#include "CAFAna/Core/EnsembleSpectrum.h" +#include "CAFAna/Core/EnsembleRatio.h" +#include "CAFAna/Core/LoadFromFile.h" +#include "CAFAna/Core/Multiverse.h" +#include "CAFAna/Core/Var.h" +#include "CAFAna/Core/Cut.h" +#include "CAFAna/Core/HistAxis.h" +#include "CAFAna/Core/ISyst.h" +#include "demo0eb.C" + +#include "TFile.h" +#include "TCanvas.h" +#include "TH1.h" +#include "TH2.h" +#include "TPad.h" +#include "TColor.h" +#include + +using namespace ana; + + + + class DummySyst: public ISyst + { + public: + DummySyst(const std::string& shortName, const std::string& longName) + :ISyst(shortName, longName) {} + virtual void Shift(double, caf::SRInteractionProxy*, double&) const {} + }; + + + // declare a particular systematic and names + // varied the ionization potential (W_ion) parameter in larnd-sim to +/-3 sigma + // (to 25.1 and 22.7 eV respectively) from its nominal value (23.6 eV). + extern const DummySyst kWIonSyst("WIon", "Ionization Potential"); + extern const DummySyst kDummyNominalSyst("Nominal","Nominal"); + + std::vector GetDummyShifts(const ISyst* s) + { + // do for each different file syst, some may be one-sided, etc... + // not sure if should label it as +/- 1 or 3.. anyways it is easily changed + if (s == &kWIonSyst ) return {-1,0,1}; + else return {0}; + }; + +struct ShiftedSpec +{ + Spectrum spec; + SystShifts shift; +}; + + +// Script to make a basic ensemble spectrum +// Based on file systematics +// So fill up a nominal +// Fill Plus and minus 1 sigma versions +// This is a cross systematic type I guess +// Instantiate a dummy systematic to construct Multiverse +// Get a wrapper that merges various spectra into a simgle ensemble spectrum thing... + +void demo2eb() +{ + + + + // test multiverse + std::vector systs; //,systs2; + systs.push_back(& ); + + + // scans from -n to n sigma shifts, we'll do only the 1 sigma + const Multiverse& cross = Multiverse::Hypercross(systs,1); + + std::cout << cross.LatexName() << std::endl << cross.ShortName() << std::endl; + + // we can save our multiverses to file + TFile fout("test_multiverse.root", "RECREATE"); + cross.SaveTo(&fout, "cross"); + fout.Close(); + + // and then retrieve multiverses from file + TFile fin("test_multiverse.root"); + const FitMultiverse& cross2 = *Multiverse::LoadFrom(&fin, "cross"); + + + // you can print the hypercross universe to see what is going on + for (int i = 0; i< cross.NUniv(); i++){ + for (const auto & [ key, value ] : cross.GetUniverse(i)) { + std::cout << key->ShortName() << ": " << value << std::endl; + } + } + fin.Close(); + //----------------------------------------------------------------------// + // now make ensemble spectra + + const Binning binsEnergy = Binning::Simple(10, 0, 1); + + const HistAxis axMuEnergy("Muon energy (GeV)", binsEnergy, kEnergyInteractionMu); + const HistAxis axEnergy("Interaction energy (GeV)", binsEnergy, kEnergyInteractionAll); + const HistAxis axNoMuEnergy("non-muon energy (GeV)", binsEnergy,kEnergyInteractionButMu); + + const RecoPartHistAxis axRecoPartEnergy("Reco Particle Energy", binsEnergy, kRecoParticleEnergy); + + + //const std::string fname_nom = "/exp/dune/data/users/mcasales/test_cafs/MiniRun5_1E19_RHC.caf.0001013.CAF.root"; + // also beta2a + const std::string fname_nom = "/exp/dune/data/users/noeroy/mywork/MiniRun5_Fixed_truth/MiniRun5_1E19_RHC.caf/CAF.flat/0000000/*.flat.root"; +//"/exp/dune/data/users/noeroy/prod/MiniRun5_1E19_RHC/MiniRun5_1E19_RHC.caf.beta1/CAF/0000000/MiniRun5_1E19_RHC.caf.0000*"; + const std::string fname_up = "/pnfs/dune/persistent/users/cuddandr/2x2_production/MiniRun5_Systematics_W_ION_22.7/MiniRun5_Systematics_W_ION_22.7.caf/CAF/0000000/MiniRun5_Systematics_W_ION_22.7.caf.*"; + const std::string fname_down = "/pnfs/dune/persistent/users/cuddandr/2x2_production/MiniRun5_Systematics_W_ION_25.1/MiniRun5_Systematics_W_ION_25.1.caf/CAF/0000000/MiniRun5_Systematics_W_ION_25.1.caf.*"; + + // Source of events + SpectrumLoader loader_nom(fname_nom); + SpectrumLoader loader_up(fname_up); + SpectrumLoader loader_down(fname_down); + + // Fill various spectra with these... + Spectrum sEnergyMatchedTrueMu_nom(loader_nom.Interactions(RecoType::kDLP)[kHas1RecoMuon], axMuEnergy); + Spectrum sEnergyMatchedTrueMu_up(loader_up.Interactions(RecoType::kDLP)[kHas1RecoMuon], axMuEnergy); + Spectrum sEnergyMatchedTrueMu_down(loader_down.Interactions(RecoType::kDLP)[kHas1RecoMuon], axMuEnergy); + +// Spectrum sEnergyMatchedTrueMu_nom(loader_nom.Interactions(RecoType::kDLP).RecoParticles(RecoType::kDLP)[kIsMuon && kMatchedToTrueMuon], axEnergy); +// Spectrum sEnergyMatchedTrueMu_up(loader_up.Interactions(RecoType::kDLP).RecoParticles(RecoType::kDLP)[kIsMuon && kMatchedToTrueMuon], axEnergy); +// Spectrum sEnergyMatchedTrueMu_down(loader_down.Interactions(RecoType::kDLP).RecoParticles(RecoType::kDLP)[kIsMuon && kMatchedToTrueMuon], axEnergy); + + loader_nom.Go(); + loader_up.Go(); + loader_down.Go(); + + // Save the three spectra to file + TFile fout2("multiverse_ensemble_spec.root", "RECREATE"); + sEnergyMatchedTrueMu_nom.SaveTo(&fout2, "sEnergyMatchedTrueMu_nom"); + sEnergyMatchedTrueMu_up.SaveTo(&fout2, "sEnergyMatchedTrueMu_up"); + sEnergyMatchedTrueMu_down.SaveTo(&fout2, "sEnergyMatchedTrueMu_down"); + cross.SaveTo(&fout2, "cross"); + fout2.Close(); + + TFile * fIn = new TFile("multiverse_ensemble_spec.root"); + std::vector specs= {}; + // make sure to place nominal first... + specs.push_back(*Spectrum::LoadFrom(fIn, "sEnergyMatchedTrueMu_nom").release() ); + // then -1 shift + specs.push_back(*Spectrum::LoadFrom(fIn, "sEnergyMatchedTrueMu_down").release()); + // then +1 shift + specs.push_back(*Spectrum::LoadFrom(fIn, "sEnergyMatchedTrueMu_up").release() ); + + + // get from file + const FitMultiverse& cross22 = *Multiverse::LoadFrom(fIn, "cross"); + + EnsembleSpectrum sEnergyMatchedWIon = EnsembleSpectrum::MergeSpectra(specs, &cross22);//, axMuEnergy ); + + + TFile fout3("multiverse_ensemble_spec_2.root", "RECREATE"); + sEnergyMatchedWIon.SaveTo(&fout3, "sEnergyMatchedWIon"); + fout3.Close(); + + // Read spectra from file + TFile fin2("multiverse_ensemble_spec_2.root"); + + EnsembleSpectrum sEnergyMatchedWIon2 =*EnsembleSpectrum::LoadFrom(&fin2, "sEnergyMatchedWIon"); + + // ------- More canvases for the hypercross univ + double pot = sEnergyMatchedTrueMu_nom.POT(); + new TCanvas; + TH1 * hsMuonEnsembleX = sEnergyMatchedWIon2.Nominal().ToTH1(pot, kBlue); + hsMuonEnsembleX->SetMaximum(1.3*hsMuonEnsembleX->GetMaximum()); + hsMuonEnsembleX->Draw("hist"); + // a vector to store ratios to nominal + std::vector hratiosx; + std::cout<< "cross has "<Draw("hist same"); + hratiosx.push_back(sEnergyMatchedWIon2.Universe(i).ToTH1(pot, color,kDashed)); + hratiosx.back()->Divide(hsMuonEnsembleX); + + } + hsMuonEnsembleX->Draw("hist same"); + gPad->SaveAs("spec_ensemble_test.pdf"); + + hratiosx[0]->SetMinimum(.6); + hratiosx[0]->SetMaximum(1.4); + new TCanvas; + for (unsigned int i = 0; i < sEnergyMatchedWIon2.NUniverses(); ++i) + hratiosx[i]->Draw("hist same"); + gPad->SaveAs("spec_ensemble_test_ratios.pdf"); + + + new TCanvas; + // Grab covariance matrix + Eigen::MatrixXd m= sEnergyMatchedWIon2.CovarianceMatrix(pot); + std::cout << "The matrix m is of size " << m.rows() << "x" << m.cols() << std::endl; + // convert to th2 for drawing + TH2F* hCov = EigenMatrixToTH2(m); + new TCanvas; + hCov->Draw("colz"); + gPad->SaveAs("cov_mx_ion.pdf"); + + /// Drawing the spectra directly + new TCanvas; + TH1 * hsMuonEnsembleX2 = sEnergyMatchedTrueMu_nom.ToTH1(pot, kBlack); + hsMuonEnsembleX2->SetMaximum(1.3*hsMuonEnsembleX2->GetMaximum()); + hsMuonEnsembleX2->Draw("hist"); + sEnergyMatchedTrueMu_up.ToTH1(pot, kBlue)->Draw("hist same");; + sEnergyMatchedTrueMu_down.ToTH1(pot, kPink)->Draw("hist same");; + +} diff --git a/CAFAna/tute/demoPions.C b/CAFAna/tute/demoPions.C new file mode 100644 index 00000000..0a3814e9 --- /dev/null +++ b/CAFAna/tute/demoPions.C @@ -0,0 +1,165 @@ +#include + +#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" +#include "duneanaobj/StandardRecord/Navigate.h" + +#include "CAFAna/Core/SpectrumLoader.h" +#include "CAFAna/Core/Spectrum.h" +#include "CAFAna/Core/Binning.h" +#include "CAFAna/Core/Var.h" +#include "CAFAna/Core/Cut.h" +#include "CAFAna/Core/HistAxis.h" + +#include "TCanvas.h" +#include "TH1.h" +#include "TLegend.h" + +using namespace ana; + + +const RecoPartVar kMatchedTruePartE([](const caf::SRRecoParticleProxy * part) -> float +{ + if (part->truth.empty()) + return -999.; + + // Ancestor() returns the closest ancestor in the SR hierarchy with the template type. + // Once we have the top-level object, we then can connect its + const caf::SRProxy * top = part->Ancestor(); + return caf::FindParticle(top->mc, part->truth[0])->p.E; +}); + +const RecoPartVar kMatchedTruePartPDG([](const caf::SRRecoParticleProxy * part) -> int +{ + if (part->truth.empty()) + return -999; + + // Ancestor() returns the closest ancestor in the SR hierarchy with the template type. + // Once we have the top-level object, we then can connect its + const caf::SRProxy * top = part->Ancestor(); + int pdg = caf::FindParticle(top->mc, part->truth[0])->pdg; + // recast in a different way for easier visualization + //(1) muon + if ( abs(pdg)==13) return 1.; + //(2) electron + if ( abs(pdg)==11) return 2.; + //(3) proton + if ( pdg==2212) return 3.; + // (4) neutron + if ( pdg==2112) return 4.; + // (5) pi + + if ( pdg==211) return 5.; + // (6) pi - + if ( pdg==-211) return 6.; + // (7) pi0 + if ( pdg==111) return 7.; + // (8) photon + if (pdg==22) return 8.; + // (9) Any K0S, K0L K0 or K+/- + if (abs(pdg)==321 || pdg== 311|| pdg== 310|| pdg== 130) return 9.; + else return 10.; +}); +std::vector PDGlabels = {"#mu", "e","p","n","#pi^{+}","#pi^{-}","#pi^{0}","#gamma","K","other"}; + +// reco particles whose best-match particle is a true pion +const RecoPartCut kMatchedToTruePion([](const caf::SRRecoParticleProxy * part) -> float +{ + if (part->truth.empty()) + return false; + + const caf::SRProxy * top = part->Ancestor(); + return std::abs(caf::FindParticle(top->mc, part->truth[0])->pdg) == 211; +}); + +// Select reco particles that have a pdg of muon +const RecoPartCut kIsPion([](const caf::SRRecoParticleProxy* sr) + { + return abs(sr->pdg) == 211 ; + }); + + +// some truth variables +const TruthPartVar kPrimEnergy([](const caf::SRTrueParticleProxy * part) -> float +{ + float ret = -999.; + ret = part->p.E; + return ret; + +}); + +const TruthCut kIsTrueNuMu ([](const caf::SRTrueInteractionProxy* nu){ + int pdg = abs(nu->pdg); + return pdg==14; + }); + +const TruthPartCut kIsPionPrim([](const caf::SRTrueParticleProxy * part){ + int pdg = abs(part->pdg); + return pdg==211; +}); + + +void demoPions() +{ + + const std::string fname = "/exp/dune/data/users/noeroy/mywork/MiniRun5_Fixed_truth/MiniRun5_1E19_RHC.caf/CAF.flat/0000000/*.flat.root"; + + // Source of events + SpectrumLoader loader(fname); + + // Define axes for the spectra we'll make + const RecoPartHistAxis axEnergy("Best-matched true particle energy (GeV)", Binning::Simple(50, 0, 5), kMatchedTruePartE); + const TruthPartHistAxis axTrueEnergy("true pion primary energy (GeV)", Binning::Simple(50,0,5), kPrimEnergy); + const RecoPartHistAxis myHistTruthPartAxisPDG("true particles pdg", Binning::Simple(10, 1, 11), kMatchedTruePartPDG); + + // Reconstructed energy of best matched pions + Spectrum sEnergyMatched(loader.Interactions(RecoType::kDLP).RecoParticles(RecoType::kDLP)[kIsPion], axEnergy); + Spectrum sEnergyMatchedTrueMu(loader.Interactions(RecoType::kDLP).RecoParticles(RecoType::kDLP)[kIsPion && kMatchedToTruePion], axEnergy); + // We want to see what else is there (pdg of the rest identified pions) + Spectrum sNonMatchedPionPDG(loader.Interactions(RecoType::kDLP).RecoParticles(RecoType::kDLP)[kIsPion && !kMatchedToTruePion], myHistTruthPartAxisPDG); + + // True energy of pions... + Spectrum sEnergyTruthPions(loader.NuTruths()[kIsTrueNuMu].TruthParticles(TruePType::kPrim)[kIsPionPrim], axTrueEnergy); + + // ~~~~**** -.-.-.-.-.-.-.-.-.-.-.- *****~~~~ + // Fill in the spectrum + loader.Go(); + + // We are forcing the pot value because cafs dont have this information yet + const double pot = 1e17; + + //sEnergyMatched.OverridePOT(pot); + //sEnergyMatchedTrueMu.OverridePOT(pot); + + TCanvas c; + TLegend leg(0.6, 0.6, 0.9, 0.9); + leg.SetFillStyle(0); + leg.SetBorderSize(0); + + auto h1 = sEnergyMatched.ToTH1(pot); + h1->Draw("hist"); + leg.AddEntry(h1, "All reco pions"); + + auto h2 = sEnergyMatchedTrueMu.ToTH1(pot, kRed); + auto h3 = sEnergyTruthPions.ToTH1(pot, kBlue); + h2->Draw("hist same"); + // h3->Draw("hist same"); + leg.AddEntry(h2, "+ matched to true pions"); + //leg.AddEntry(h3, "all true pions energy"); + leg.Draw(); + c.SaveAs("recoPion_matchedTrueE.png"); + + + + new TCanvas; + h3->Draw("hist") ; + gPad->SaveAs("truePion_TrueE.png"); + + + auto h4 = sNonMatchedPionPDG.ToTH1(pot); + for (unsigned int i = 0; iGetXaxis()->SetBinLabel(i+1,PDGlabels[i].c_str()); + h4->GetXaxis()->SetTitle("non-matched reco pions true pdg"); + new TCanvas; + h4->Draw("hist"); + gPad->SaveAs("nonTruePions_PDG.png"); + +} diff --git a/CAFAna/tute/demo_systs.C b/CAFAna/tute/demo_systs.C new file mode 100644 index 00000000..db8a55f3 --- /dev/null +++ b/CAFAna/tute/demo_systs.C @@ -0,0 +1,235 @@ + +#include "duneanaobj/StandardRecord/Proxy/SRProxy.h" +#include "duneanaobj/StandardRecord/Navigate.h" +#include "duneanaobj/StandardRecord/SREnums.h" +#include "CAFAna/Core/SpectrumLoader.h" +#include "CAFAna/Core/Spectrum.h" +#include "CAFAna/Core/Binning.h" +#include "CAFAna/Core/EnsembleSpectrum.h" +#include "CAFAna/Core/EnsembleRatio.h" +#include "CAFAna/Core/LoadFromFile.h" +#include "CAFAna/Core/Multiverse.h" +#include "CAFAna/Core/Var.h" +#include "CAFAna/Core/Cut.h" +#include "CAFAna/Core/HistAxis.h" +#include "CAFAna/Core/ISyst.h" +#include "CAFAna/Core/Utilities.h" +#include "demo0eb.C" + +#include "TFile.h" +#include "TCanvas.h" +#include "TH1.h" +#include "TH2.h" +#include "TPad.h" +#include "TColor.h" +#include + +using namespace ana; + + + +void demo_systs() +{ + + + std::vector systs; + systs.push_back(&kWIonSyst); + std::vector systs2; + systs2.push_back(&kEnergyScaleTrueMu); + systs2.push_back(&kMECScaleSyst); + + // scans from -n to n sigma shifts, we'll do only the 1 sigma + const Multiverse& cross = Multiverse::Hypercross(systs,1); + const Multiverse& cross_rwgt = Multiverse::Hypercross(systs2,1); + + // we can save our multiverses to file + TFile fout("test_multiverse.root", "RECREATE"); + cross.SaveTo(&fout, "cross"); + cross_rwgt.SaveTo(&fout, "cross_rwgt"); + fout.Close(); + + // and then retrieve multiverses from file + TFile fin("test_multiverse.root"); + const FitMultiverse& cross2 = *Multiverse::LoadFrom(&fin, "cross"); + const FitMultiverse& cross_rwgt2 = *Multiverse::LoadFrom(&fin, "cross_rwgt"); + + + // you can print the hypercross universe to see what is going on + std::cout << cross.LatexName() << ", "<< cross.ShortName() << std::endl; + for (int i = 0; i< cross.NUniv(); i++){ + for (const auto & [ key, value ] : cross.GetUniverse(i)) { + std::cout << key->ShortName() << ": " << value << std::endl; + } + } + std::cout << cross_rwgt.LatexName() << ", "<< cross_rwgt.ShortName() << std::endl; + for (int i = 0; i< cross_rwgt.NUniv(); i++){ + for (const auto & [ key, value ] : cross_rwgt.GetUniverse(i)) { + std::cout << key->ShortName() << ": " << value << std::endl; + } + } + + fin.Close(); + //----------------------------------------------------------------------// + // now make ensemble spectra + + const Binning binsEnergy = Binning::Simple(10, 0, 1); + + const HistAxis axMuEnergy("Muon energy (GeV)", binsEnergy, kEnergyInteractionMu); + + //const std::string fname_nom = "/exp/dune/data/users/mcasales/test_cafs/MiniRun5_1E19_RHC.caf.0001013.CAF.root"; + // also beta2a + + // const std::string fname_nom = "/exp/dune/data/users/noeroy/mywork/MiniRun5_Fixed_truth/MiniRun5_1E19_RHC.caf/CAF.flat/0000000/*.flat.root"; + const std::string fname_nom = "/exp/dune/data/users/noeroy/prod/MiniRun5_1E19_RHC/MiniRun5_1E19_RHC.caf.beta1/CAF.flat/0000000/MiniRun5_1E19_RHC.caf.*"; + const std::string fname_up = "/pnfs/dune/persistent/users/cuddandr/2x2_production/MiniRun5_Systematics_W_ION_22.7/MiniRun5_Systematics_W_ION_22.7.caf/CAF.flat/0000000/MiniRun5_Systematics_W_ION_22.7.caf.*"; + const std::string fname_down = "/pnfs/dune/persistent/users/cuddandr/2x2_production/MiniRun5_Systematics_W_ION_25.1/MiniRun5_Systematics_W_ION_25.1.caf/CAF.flat/0000000/MiniRun5_Systematics_W_ION_25.1.caf.*"; + + // Source of events + SpectrumLoader loader_nom(fname_nom); + SpectrumLoader loader_up(fname_up); + SpectrumLoader loader_down(fname_down); + + // Fill various spectra with these... + Spectrum sEnergyMatchedTrueMu_nom(loader_nom.Interactions(RecoType::kDLP)[kHas1RecoMuon], axMuEnergy); + Spectrum sEnergyMatchedTrueMu_up(loader_up.Interactions(RecoType::kDLP)[kHas1RecoMuon], axMuEnergy); + Spectrum sEnergyMatchedTrueMu_down(loader_down.Interactions(RecoType::kDLP)[kHas1RecoMuon], axMuEnergy); + + // other ensemble with two reweight systematics + EnsembleSpectrum sMuonEnegyEnsemble(loader_nom.Interactions(RecoType::kDLP).Ensemble(cross_rwgt)[kHas1RecoMuon], axMuEnergy ); + + loader_nom.Go(); + loader_up.Go(); + loader_down.Go(); + + // Save the three spectra to file + TFile fout2("multiverse_ensemble_spec.root", "RECREATE"); + sEnergyMatchedTrueMu_nom.SaveTo(&fout2, "sEnergyMatchedTrueMu_nom"); + sEnergyMatchedTrueMu_up.SaveTo(&fout2, "sEnergyMatchedTrueMu_up"); + sEnergyMatchedTrueMu_down.SaveTo(&fout2, "sEnergyMatchedTrueMu_down"); + sMuonEnegyEnsemble.SaveTo( &fout2, "sMuonEnegyEnsemble"); + + cross.SaveTo(&fout2, "cross"); + cross_rwgt.SaveTo(&fout2, "cross_rwgt"); + fout2.Close(); + + TFile * fIn = new TFile("multiverse_ensemble_spec.root"); + std::vector specs= {}; + // make sure to place nominal first,then -1 shift, then +1 shift + specs.push_back(*Spectrum::LoadFrom(fIn, "sEnergyMatchedTrueMu_nom").release() ); + specs.push_back(*Spectrum::LoadFrom(fIn, "sEnergyMatchedTrueMu_down").release()); + specs.push_back(*Spectrum::LoadFrom(fIn, "sEnergyMatchedTrueMu_up").release() ); + + // get from file + const FitMultiverse& cross22 = *Multiverse::LoadFrom(fIn, "cross"); + + EnsembleSpectrum sEnergyMatchedWIon = EnsembleSpectrum::MergeSpectra(specs, &cross22);//, axMuEnergy ); + +//---------------------------------------------------------------------- + // These lines dont crash but I dont know if they are working properly + const FitMultiverse& crossCombined = Multiverse::Hypercross({&kWIonSyst, &kEnergyScaleTrueMu, &kMECScaleSyst},1); + std::cout<< "sMuonEnegyEnsemble has "<< sMuonEnegyEnsemble.NUniverses()<< "sEnergyMatchedWIon has "<< sEnergyMatchedWIon.NUniverses()<< + " and crossCombined has "<< crossCombined.NUniv() <SetMaximum(1.3*hsMuonEnsembleX->GetMaximum()); + hsMuonEnsembleX->Draw("hist"); + + // you can draw the individual spectra for each universe + // in this case our spectra from different files + std::cout<< "\ncross has "<Draw("hist same"); + //sEnergyMatchedIonandEnergyScale2.Universe(i).ToTH1(pot, color+1,kDotted)->Draw("hist same"); + } + gPad->SaveAs("spec_ensemble_test.pdf"); + + + // or draw as TGraph + new TCanvas; + // Error band summing in quadrature + TGraphAsymmErrors* eBand =sEnergyMatchedWIon2.ErrorBand(pot); + DrawErrorBand(hsMuonEnsembleX, eBand); + gPad->SaveAs("spec_ensemble_test_ErrorBand.pdf"); + + // Draw covariance matrix + new TCanvas; + Eigen::MatrixXd m= sEnergyMatchedWIon2.CovarianceMatrix(pot); + std::cout << "The matrix m is of size " << m.rows() << "x" << m.cols() << std::endl; + // convert to th2 for drawing + TH2F* hCov = EigenMatrixToTH2(m); + new TCanvas; + hCov->Draw("colz"); + gPad->SaveAs("cov_mx_ion.pdf"); + + + /// Drawing the spectra directly + new TCanvas; + TH1 * hsMuonEnsembleX2 = sEnergyMatchedTrueMu_nom.ToTH1(pot, kBlue); + hsMuonEnsembleX2->SetMaximum(1.3*hsMuonEnsembleX2->GetMaximum()); + hsMuonEnsembleX2->Draw("hist"); + sEnergyMatchedTrueMu_up.ToTH1(pot, kPink)->Draw("hist same");; + sEnergyMatchedTrueMu_down.ToTH1(pot, kViolet+1)->Draw("hist same");; + gPad->SaveAs("specs_non-ensemble_test.png"); + + // check differences + new TCanvas; + TH1* hdiffNom = sEnergyMatchedTrueMu_nom.ToTH1(pot, kBlue); + hdiffNom->Divide( sEnergyMatchedWIon2.Universe(0).ToTH1(pot)); + TH1* hdiffUp = sEnergyMatchedTrueMu_up.ToTH1(pot, kPink); + hdiffUp->Divide( sEnergyMatchedWIon2.Universe(2).ToTH1(pot)); + TH1* hdiffDown =sEnergyMatchedTrueMu_down.ToTH1(pot, kViolet+1); + hdiffDown->Divide( sEnergyMatchedWIon2.Universe(1).ToTH1(pot)); + hdiffNom->SetMaximum(1.5); hdiffNom->SetMinimum(.5); + hdiffNom->Draw("hist"); + hdiffUp->Draw("hist same"); + hdiffDown->Draw("hist same"); + gPad->SaveAs("specs_ensembe_diff.png"); + + new TCanvas; + EnsembleSpectrum sMuonEnegyEnsemble2 =*EnsembleSpectrum::LoadFrom(&fin2, "sMuonEnegyEnsemble"); + for(unsigned int i = 0; i < sMuonEnegyEnsemble2.NUniverses(); ++i){ + // using different colors per shift + Color_t color = kBlue; + if (i==0) color = kBlue; + if (i== 1 ) color = kViolet +1; + if (i==2 ) color = kPink; + sMuonEnegyEnsemble2.Universe(i).ToTH1(pot, color,kDashed)->Draw("hist same"); + } + gPad->SaveAs("rwgt_ensemble_test.png"); + + new TCanvas; + // Grab covariance matrix + Eigen::MatrixXd m2= sMuonEnegyEnsemble2.CovarianceMatrix(pot); + std::cout << "The matrix m is of size " << m2.rows() << "x" << m2.cols() << std::endl; + // convert to th2 for drawing + TH2F* hCov2 = EigenMatrixToTH2(m2); + + new TCanvas; + hCov2->Draw("colz"); + gPad->SaveAs("cov_mx_rwgt.pdf"); + + +}