15 MACH3LOG_INFO(
"-------------------------------------------------------------------");
20 MACH3LOG_WARN(
"You've passed me a nullptr ParameterHandler so I will not use any xsec parameters");
26 if (OscillatorObj_ !=
nullptr) {
27 MACH3LOG_WARN(
"You have passed an Oscillator object through the constructor of a SampleHandlerBase object - this will be used for all oscillation channels");
30 MACH3LOG_CRITICAL(
"You've passed me a nullptr to ParamHandler while non null to Oscillator");
42 SampleManager = std::make_unique<Manager>(ConfigFileName.c_str());
43 Binning = std::make_unique<BinningHandler>();
56 auto ModeName = Get<std::string>(
SampleManager->raw()[
"MaCh3ModeConfig"], __FILE__ , __LINE__);
57 Modes = std::make_unique<MaCh3Modes>(getenv(
"MACH3")+std::string(
"/") + ModeName);
71 auto EnabledSasmples = Get<std::vector<std::string>>(
SampleManager->raw()[
"Samples"], __FILE__ , __LINE__);
76 for (
int iSample = 0; iSample <
nSamples; iSample++)
78 auto SampleSettings =
SampleManager->raw()[EnabledSasmples[iSample]];
83 for(
int iMode=0; iMode <
Modes->GetNModes(); iMode++ ) {
89 for(
int iMode=0; iMode<
Modes->GetNModes(); iMode++ ) {
90 std::string modeStr =
Modes->GetMaCh3ModeName(iMode);
92 double modeWeight =
SampleManager->raw()[
"NominalWeights"][modeStr].as<
double>();
100 for(
int iMode=0; iMode<
Modes->GetNModes(); iMode++ ) {
101 std::string modeStr =
Modes->GetMaCh3ModeName(iMode);
112 SingleSample.
SampleTitle = Get<std::string>(SampleSettings[
"SampleTitle"], __FILE__ , __LINE__);
114 Binning->SetupSampleBinning(SampleSettings[
"Binning"], SingleSample);
116 auto MCFilePrefix = Get<std::string>(SampleSettings[
"InputFiles"][
"mtupleprefix"], __FILE__, __LINE__);
117 auto MCFileSuffix = Get<std::string>(SampleSettings[
"InputFiles"][
"mtuplesuffix"], __FILE__, __LINE__);
118 auto SplinePrefix = Get<std::string>(SampleSettings[
"InputFiles"][
"splineprefix"], __FILE__, __LINE__);
119 auto SplineSuffix = Get<std::string>(SampleSettings[
"InputFiles"][
"splinesuffix"], __FILE__, __LINE__);
121 int NChannels =
static_cast<M3::int_t>(SampleSettings[
"OscChannels"].size());
124 int OscChannelCounter = 0;
125 for (
auto const &osc_channel : SampleSettings[
"OscChannels"]) {
127 OscInfo.
flavourName = Get<std::string>(osc_channel[
"Name"], __FILE__ , __LINE__);
128 OscInfo.
flavourName_Latex = Get<std::string>(osc_channel[
"LatexName"], __FILE__ , __LINE__);
133 for (
const auto& Existing : SingleSample.
OscChannels) {
134 if (Existing.InitPDG == OscInfo.
InitPDG && Existing.FinalPDG == OscInfo.
FinalPDG) {
135 MACH3LOG_ERROR(
"Duplicate oscillation channel detected! InitPDG = {}, FinalPDG = {}"
136 "already defined in channel {} for sample {}",
141 auto MCFileNames = Get<std::vector<std::string>>(osc_channel[
"mtuplefile"], __FILE__ , __LINE__);
142 for(
size_t iFile = 0; iFile < MCFileNames.size(); iFile++){
143 std::string FileName = MCFilePrefix + MCFileNames[iFile] + MCFileSuffix;
144 MCFileNames[iFile] = FileName;
149 SingleSample.
OscChannels.push_back(std::move(OscInfo));
150 SingleSample.
mc_files.push_back(MCFileNames);
151 SingleSample.
spline_files.push_back(SplinePrefix+osc_channel[
"splinefile"].as<std::string>()+SplineSuffix);
155 for (
auto const &SelectionCuts : SampleSettings[
"SelectionCuts"]) {
156 auto TempBoundsVec =
GetBounds(SelectionCuts[
"Bounds"]);
161 MACH3LOG_INFO(
"Adding cut on {} with bounds {} to {}", SelectionCuts[
"KinematicStr"].as<std::string>(), TempBoundsVec[0], TempBoundsVec[1]);
185 MACH3LOG_INFO(
"=============================================");
201 MACH3LOG_INFO(
"Finished loading MC for {}, it took {:.2f}s to finish",
GetName(), clock.RealTime());
204 MACH3LOG_INFO(
"=======================================================");
211 MACH3LOG_ERROR(
"Map KinematicParameters or ReversedKinematicParameters hasn't been initialised");
216 const auto& key = pair.first;
217 const auto& value = pair.second;
227 std::vector<std::string> Vars = {
"Mode",
"OscillationChannel",
"TargetNucleus"};
228 for(
size_t iVar = 0; iVar < Vars.size(); iVar++) {
232 MACH3LOG_ERROR(
"MaCh3 expected variable: {} not found in KinematicParameters.", Vars[iVar]);
242 #pragma GCC diagnostic push
243 #pragma GCC diagnostic ignored "-Wconversion"
247 int Dimension =
GetNDim(Sample);
252 for (
int xBin = 0; xBin <
Binning->GetNAxisBins(Sample, 0); ++xBin) {
253 const int idx =
Binning->GetGlobalBinSafe(Sample, {xBin});
254 Hist->SetBinContent(xBin + 1, Array[idx]);
256 }
else if (Dimension == 2) {
258 if(
Binning->IsUniform(Sample)) {
259 for (
int yBin = 0; yBin <
Binning->GetNAxisBins(Sample, 1); ++yBin) {
260 for (
int xBin = 0; xBin <
Binning->GetNAxisBins(Sample, 0); ++xBin) {
261 const int idx =
Binning->GetGlobalBinSafe(Sample, {xBin, yBin});
262 Hist->SetBinContent(xBin + 1, yBin + 1, Array[idx]);
266 for (
int iBin = 0; iBin <
Binning->GetNBins(Sample); ++iBin) {
267 const int idx = iBin +
Binning->GetSampleStartBin(Sample);
269 Hist->SetBinContent(iBin + 1, Array[idx]);
273 for (
int iBin = 0; iBin <
Binning->GetNBins(Sample); ++iBin) {
274 const int idx = iBin +
Binning->GetSampleStartBin(Sample);
276 Hist->SetBinContent(iBin + 1, Array[idx]);
280 #pragma GCC diagnostic pop
286 const auto& SampleSelection = Selection[iSample];
287 const int SelectionSize =
static_cast<int>(SampleSelection.size());
288 for (
int iSelection = 0; iSelection < SelectionSize; ++iSelection) {
289 const auto& Cut = SampleSelection[iSelection];
290 const double Val = ReturnKinematicParameter(Cut.ParamToCutOnIt, iEvent);
291 if ((Val < Cut.LowerBound) || (Val >= Cut.UpperBound)) {
301 for (
unsigned int iSelection=0;iSelection < SubEventCuts.size() ;iSelection++) {
303 if (nsubevents != Vec.size()) {
304 MACH3LOG_ERROR(
"Cannot apply kinematic cut on {} as it is of different size to plotting variable");
307 const double Val = Vec[iSubEvent];
308 if ((Val < SubEventCuts[iSelection].LowerBound) || (Val >= SubEventCuts[iSelection].UpperBound)) {
360 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
373 if (totalweight <= 0.){
378 const int GlobalBin =
Binning->FindGlobalBin(MCEvent->NominalSample, MCEvent->KinVar, MCEvent->NomBin);
389 #pragma GCC diagnostic push
390 #pragma GCC diagnostic ignored "-Walloca"
412 const auto TotalBins =
Binning->GetNBins();
413 const unsigned int NumberOfEvents =
GetNEvents();
418 #pragma omp parallel for reduction(+:MC_Array_for_reduction[:TotalBins], W2_array_for_reduction[:TotalBins])
419 for (
unsigned int iEvent = 0; iEvent < NumberOfEvents; ++iEvent) {
435 if (totalweight <= 0.){
440 const int GlobalBin =
Binning->FindGlobalBin(MCEvent->NominalSample, MCEvent->KinVar, MCEvent->NomBin);
447 MC_Array_for_reduction[GlobalBin] += totalweight;
448 if (
FirstTimeW2) W2_array_for_reduction[GlobalBin] += totalweight*totalweight;
452 #pragma GCC diagnostic pop
461 const int nBins =
Binning->GetNBins();
475 MACH3LOG_ERROR(
"Functional parameter {} already in funcParsNamesVec", fpName);
479 MACH3LOG_ERROR(
"Functional parameter enum {} already registered in funcParsFuncMap", fpEnum);
503 MACH3LOG_ERROR(
"Functional parameter {} not found, did you define it in RegisterFunctionalParameters()?", fp.name);
506 const std::size_t key =
static_cast<std::size_t
>(it->second);
507 MACH3LOG_INFO(
"Adding functional parameter: {} to funcParsMap with key: {}",fp.name, key);
509 const int ikey = it->second;
518 for (std::size_t iEvent = 0; iEvent < static_cast<std::size_t>(
GetNEvents()); ++iEvent) {
520 for (std::vector<FunctionalParameter>::iterator it =
funcParsVec.begin(); it !=
funcParsVec.end(); ++it) {
525 MACH3LOG_TRACE(
"Event {}, missed Mode check ({}) for dial {}", iEvent, Mode, it->name);
532 MACH3LOG_TRACE(
"Event {}, missed Kinematic var check for dial {}", iEvent, it->name);
535 const std::size_t key =
static_cast<std::size_t
>(
funcParsNamesMap[it->name]);
552 const auto nShifts = shifts.size();
562 for (std::size_t iShift = 0; iShift < nShifts; ++iShift) {
564 (*fp->funcPtr)(fp->valuePtr, iEvent);
575 const int TotalWeights =
static_cast<int>(MCEvent->total_weight_pointers.size());
578 #pragma omp simd reduction(*:TotalWeight)
580 for (
int iWeight = 0; iWeight < TotalWeights; ++iWeight) {
581 TotalWeight *= *(MCEvent->total_weight_pointers[iWeight]);
595 if (OscParams.size() > 0) {
598 MACH3LOG_INFO(
"You have passed an OscillatorBase object through the constructor of a SampleHandlerFD object - this will be used for all oscillation channels");
599 if(
Oscillator->isEqualBinningPerOscChannel() !=
true) {
600 MACH3LOG_ERROR(
"Trying to run shared NuOscillator without EqualBinningPerOscChannel, this will not work");
604 if(OscParams.size() !=
Oscillator->GetOscParamsSize()){
605 MACH3LOG_ERROR(
"SampleHandler {} has {} osc params, while shared NuOsc has {} osc params",
GetName(),
606 OscParams.size(),
Oscillator->GetOscParamsSize());
607 MACH3LOG_ERROR(
"This indicate misconfiguration in your Osc yaml");
615 MACH3LOG_WARN(
"Didn't find any oscillation params, thus will not enable oscillations");
619 MACH3LOG_ERROR(
"Either remove 'NuOsc' field from SampleHandler config or check your model.yaml and include oscillation for sample");
631 std::vector< std::vector< int > > norms_bins(
GetNEvents());
644 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); ++iEvent) {
646 const size_t offset =
MCEvents[iEvent].total_weight_pointers.size();
647 const size_t addSize = norms_bins[iEvent].size();
648 MCEvents[iEvent].total_weight_pointers.resize(offset + addSize);
649 for(
auto const & norm_bin: norms_bins[iEvent]) {
661 std::vector<int> VerboseCounter(norm_parameters.size(), 0);
663 for(
unsigned int iEvent = 0; iEvent <
GetNEvents(); ++iEvent){
664 std::vector< int > NormBins = {};
674 for (std::vector<NormParameter>::iterator it = norm_parameters.begin(); it != norm_parameters.end(); ++it) {
679 MACH3LOG_TRACE(
"Event {}, missed target check ({}) for dial {}", iEvent, Target, it->name);
692 if (!FlavourUnoscMatch){
693 MACH3LOG_TRACE(
"Event {}, missed FlavourUnosc check ({}) for dial {}", iEvent,
MCEvents[iEvent].nupdgUnosc, it->name);
701 MACH3LOG_TRACE(
"Event {}, missed Mode check ({}) for dial {}", iEvent, Mode, it->name);
711 MACH3LOG_TRACE(
"Event {}, missed Kinematic var check for dial {}", iEvent, it->name);
718 NormBins.push_back(bin);
719 MACH3LOG_TRACE(
"Event {}, will be affected by dial {}", iEvent, it->name);
721 VerboseCounter[std::distance(norm_parameters.begin(), it)]++;
726 norms_bins[iEvent] = NormBins;
729 MACH3LOG_DEBUG(
"┌──────────────────────────────────────────────────────────┐");
730 for (std::size_t i = 0; i < norm_parameters.size(); ++i) {
731 const auto& norm = norm_parameters[i];
732 double eventRatio =
static_cast<double>(VerboseCounter[i]) /
static_cast<double>(
GetNEvents());
734 MACH3LOG_DEBUG(
"│ Param {:<15}, affects {:<8} events ({:>6.2f}%) │",
737 MACH3LOG_DEBUG(
"└──────────────────────────────────────────────────────────┘");
752 for(
int iSample = 0; iSample <
GetNSamples(); iSample++)
754 int Dimension =
GetNDim(iSample);
759 auto XVec =
Binning->GetBinEdges(iSample, 0);
760 SamDet->DataHist =
new TH1D((
"d" + HistTitle).c_str(), HistTitle.c_str(),
static_cast<int>(XVec.size()-1), XVec.data());
761 SamDet->MCHist =
new TH1D((
"h" + HistTitle).c_str(), HistTitle.c_str(),
static_cast<int>(XVec.size()-1), XVec.data());
762 SamDet->W2Hist =
new TH1D((
"w" + HistTitle).c_str(), HistTitle.c_str(),
static_cast<int>(XVec.size()-1), XVec.data());
765 SamDet->DataHist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
766 SamDet->DataHist->GetYaxis()->SetTitle(
"Events");
767 SamDet->MCHist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
768 SamDet->MCHist->GetYaxis()->SetTitle(
"Events");
769 SamDet->W2Hist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
770 SamDet->W2Hist->GetYaxis()->SetTitle(
"Events");
771 }
else if (Dimension == 2){
772 if(
Binning->IsUniform(iSample)) {
773 auto XVec =
Binning->GetBinEdges(iSample, 0);
774 auto YVec =
Binning->GetBinEdges(iSample, 1);
775 int nX =
static_cast<int>(XVec.size() - 1);
776 int nY =
static_cast<int>(YVec.size() - 1);
778 SamDet->DataHist =
new TH2D((
"d" + HistTitle).c_str(), HistTitle.c_str(), nX, XVec.data(), nY, YVec.data());
779 SamDet->MCHist =
new TH2D((
"h" + HistTitle).c_str(), HistTitle.c_str(), nX, XVec.data(), nY, YVec.data());
780 SamDet->W2Hist =
new TH2D((
"w" + HistTitle).c_str(), HistTitle.c_str(), nX, XVec.data(), nY, YVec.data());
782 auto AddBinsToTH2Poly = [](TH2Poly* hist,
const std::vector<BinInfo>& bins) {
783 for (
const auto& bin : bins) {
784 double xLow = bin.Extent[0][0];
785 double xHigh = bin.Extent[0][1];
786 double yLow = bin.Extent[1][0];
787 double yHigh = bin.Extent[1][1];
789 double x[4] = {xLow, xHigh, xHigh, xLow};
790 double y[4] = {yLow, yLow, yHigh, yHigh};
792 hist->AddBin(4, x, y);
796 SamDet->DataHist =
new TH2Poly();
797 SamDet->DataHist->SetName((
"d" + HistTitle).c_str());
798 SamDet->DataHist->SetTitle(HistTitle.c_str());
800 SamDet->MCHist =
new TH2Poly();
801 SamDet->MCHist->SetName((
"h" + HistTitle).c_str());
802 SamDet->MCHist->SetTitle(HistTitle.c_str());
804 SamDet->W2Hist =
new TH2Poly();
805 SamDet->W2Hist->SetName((
"w" + HistTitle).c_str());
806 SamDet->W2Hist->SetTitle(HistTitle.c_str());
809 AddBinsToTH2Poly(
static_cast<TH2Poly*
>(SamDet->DataHist),
Binning->GetNonUniformBins(iSample));
810 AddBinsToTH2Poly(
static_cast<TH2Poly*
>(SamDet->MCHist),
Binning->GetNonUniformBins(iSample));
811 AddBinsToTH2Poly(
static_cast<TH2Poly*
>(SamDet->W2Hist),
Binning->GetNonUniformBins(iSample));
815 SamDet->DataHist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
816 SamDet->DataHist->GetYaxis()->SetTitle(SamDet->VarStr[1].c_str());
817 SamDet->MCHist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
818 SamDet->MCHist->GetYaxis()->SetTitle(SamDet->VarStr[1].c_str());
819 SamDet->W2Hist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
820 SamDet->W2Hist->GetYaxis()->SetTitle(SamDet->VarStr[1].c_str());
822 int nbins =
Binning->GetNBins(iSample);
823 SamDet->DataHist =
new TH1D((
"d" + HistTitle).c_str(), HistTitle.c_str(), nbins, 0, nbins);
824 SamDet->MCHist =
new TH1D((
"h" + HistTitle).c_str(), HistTitle.c_str(), nbins, 0, nbins);
825 SamDet->W2Hist =
new TH1D((
"w" + HistTitle).c_str(), HistTitle.c_str(), nbins, 0, nbins);
827 for(
int iBin = 0; iBin < nbins; iBin++) {
828 auto BinName =
Binning->GetBinName(iSample, iBin);
829 SamDet->DataHist->GetXaxis()->SetBinLabel(iBin+1, BinName.c_str());
830 SamDet->MCHist->GetXaxis()->SetBinLabel(iBin+1, BinName.c_str());
831 SamDet->W2Hist->GetXaxis()->SetBinLabel(iBin+1, BinName.c_str());
835 SamDet->DataHist->GetYaxis()->SetTitle(
"Events");
836 SamDet->MCHist->GetYaxis()->SetTitle(
"Events");
837 SamDet->W2Hist->GetYaxis()->SetTitle(
"Events");
840 SamDet->DataHist->SetDirectory(
nullptr);
841 SamDet->MCHist->SetDirectory(
nullptr);
842 SamDet->W2Hist->SetDirectory(
nullptr);
853 for (
unsigned int event_i = 0; event_i <
GetNEvents(); event_i++) {
854 int Sample =
MCEvents[event_i].NominalSample;
855 const int dim =
GetNDim(Sample);
856 MCEvents[event_i].KinVar.resize(dim);
857 MCEvents[event_i].NomBin.resize(dim);
859 auto SetNominalBin = [&](
int bin,
int max_bins,
int& out_bin) {
860 if (bin >= 0 && bin < max_bins) {
868 for(
int iDim = 0; iDim < dim; iDim++) {
870 if (std::isnan(*
MCEvents[event_i].KinVar[iDim]) || std::isinf(*
MCEvents[event_i].KinVar[iDim])) {
871 MACH3LOG_ERROR(
"Variable {} for sample {} and dimension {} is ill-defined and equal to {}",
875 const int bin =
Binning->FindNominalBin(Sample, iDim, *
MCEvents[event_i].KinVar[iDim]);
876 int NBins_i =
static_cast<int>(
Binning->GetBinEdges(Sample, iDim).size() - 1);
877 SetNominalBin(bin, NBins_i,
MCEvents[event_i].NomBin[iDim]);
951 MACH3LOG_INFO(
"Adding {}D data histogram: {} with {:.2f} events", Dim, Data->GetTitle(), Data->Integral());
954 SampleDetails[Sample].DataHist =
static_cast<TH1*
>(Data->Clone());
957 MACH3LOG_ERROR(
"SampleHandler_data haven't been initialised yet");
961 auto ChecHistType = [&](
const std::string& Type,
const int Dimen,
const TH1* Hist,
962 const std::string& file,
const int line) {
963 if (std::string(Hist->ClassName()) != Type) {
964 MACH3LOG_ERROR(
"Expected {} for {}D sample, got {}", Type, Dimen, Hist->ClassName());
971 ChecHistType(
"TH1D", Dim,
SampleDetails[Sample].DataHist, __FILE__, __LINE__);
973 static_cast<TH1D*
>(
SampleDetails[Sample].MCHist), __FILE__, __LINE__);
974 for (
int xBin = 0; xBin <
Binning->GetNAxisBins(Sample, 0); ++xBin) {
975 const int idx =
Binning->GetGlobalBinSafe(Sample, {xBin});
980 SampleDetails[Sample].DataHist->GetYaxis()->SetTitle(
"Number of Events");
981 }
else if (Dim == 2) {
982 if(
Binning->IsUniform(Sample)) {
983 ChecHistType(
"TH2D", Dim,
SampleDetails[Sample].DataHist, __FILE__, __LINE__);
985 static_cast<TH2D*
>(
SampleDetails[Sample].MCHist), __FILE__, __LINE__);
986 for (
int yBin = 0; yBin <
Binning->GetNAxisBins(Sample, 1); ++yBin) {
987 for (
int xBin = 0; xBin <
Binning->GetNAxisBins(Sample, 0); ++xBin) {
988 const int idx =
Binning->GetGlobalBinSafe(Sample, {xBin, yBin});
994 ChecHistType(
"TH2Poly", Dim,
SampleDetails[Sample].DataHist, __FILE__, __LINE__);
996 static_cast<TH2Poly*
>(
SampleDetails[Sample].MCHist), __FILE__, __LINE__);
997 for (
int iBin = 0; iBin <
Binning->GetNBins(Sample); ++iBin) {
998 const int idx = iBin +
Binning->GetSampleStartBin(Sample);
1006 SampleDetails[Sample].DataHist->GetZaxis()->SetTitle(
"Number of Events");
1008 ChecHistType(
"TH1D", Dim,
SampleDetails[Sample].DataHist, __FILE__, __LINE__);
1010 static_cast<TH1D*
>(
SampleDetails[Sample].MCHist), __FILE__, __LINE__);
1011 for (
int iBin = 0; iBin <
Binning->GetNBins(Sample); ++iBin) {
1012 const int idx = iBin +
Binning->GetSampleStartBin(Sample);
1022 const int Start =
Binning->GetSampleStartBin(Sample);
1023 const int End =
Binning->GetSampleEndBin(Sample);
1024 const int ExpectedSize = End - Start;
1026 if (
static_cast<int>(Data_Array.size()) != ExpectedSize) {
1028 MACH3LOG_ERROR(
"Expected size: {}, received size: {}.", ExpectedSize, Data_Array.size());
1030 MACH3LOG_ERROR(
"This likely indicates a binning or sample slicing bug.");
1042 auto NuOscillatorConfigFile = Get<std::string>(
SampleManager->raw()[
"NuOsc"][
"NuOscConfigFile"], __FILE__ , __LINE__);
1043 auto EqualBinningPerOscChannel = Get<bool>(
SampleManager->raw()[
"NuOsc"][
"EqualBinningPerOscChannel"], __FILE__ , __LINE__);
1046 if (EqualBinningPerOscChannel) {
1047 if (YAML::LoadFile(NuOscillatorConfigFile)[
"General"][
"CalculationType"].as<std::string>() ==
"Unbinned") {
1048 MACH3LOG_WARN(
"Tried using EqualBinningPerOscChannel while using Unbinned oscillation calculation, changing EqualBinningPerOscChannel to false");
1049 EqualBinningPerOscChannel =
false;
1053 if (OscParams.empty()) {
1055 MACH3LOG_ERROR(
"This likely indicates an error in your oscillation YAML configuration.");
1058 Oscillator = std::make_shared<OscillationHandler>(NuOscillatorConfigFile, EqualBinningPerOscChannel, OscParams,
GetNOscChannels(0));
1060 if(!EqualBinningPerOscChannel) {
1062 for(
int iSample = 1; iSample <
GetNSamples(); iSample++) {
1065 for(
int iSample = 0; iSample <
GetNSamples(); iSample++) {
1066 for(
int iChannel = 0; iChannel <
GetNOscChannels(iSample); iChannel++) {
1067 std::vector<M3::float_t> EnergyArray;
1068 std::vector<M3::float_t> CosineZArray;
1070 #pragma GCC diagnostic push
1071 #pragma GCC diagnostic ignored "-Wuseless-cast"
1072 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1073 if(
MCEvents[iEvent].NominalSample != iSample)
continue;
1077 if (!
MCEvents[iEvent].isNC && Channel == iChannel) {
1081 std::sort(EnergyArray.begin(),EnergyArray.end());
1086 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1087 if(
MCEvents[iEvent].NominalSample != iSample)
continue;
1091 if (!
MCEvents[iEvent].isNC && Channel == iChannel) {
1095 std::sort(CosineZArray.begin(),CosineZArray.end());
1097 #pragma GCC diagnostic pop
1098 Oscillator->SetOscillatorBinning(iSample, iChannel, EnergyArray, CosineZArray);
1107 auto AddOscPointer = GetFromManager<bool>(
SampleManager->raw()[
"NuOsc"][
"AddOscPointer"],
true, __FILE__ , __LINE__);
1109 if(!AddOscPointer) {
1112 for (
unsigned int iEvent=0;iEvent<
GetNEvents();iEvent++) {
1117 MCEvents[iEvent].total_weight_pointers.push_back(osc_w_pointer);
1140 MACH3LOG_ERROR(
"Something has gone wrong in the mapping between MCEvents.nutype and the enum used within NuOscillator");
1147 const int Sample =
MCEvents[iEvent].NominalSample;
1153 osc_w_pointer =
Oscillator->GetNuOscillatorPointers(Sample, OscIndex, InitFlav, FinalFlav, FLOAT_T(
MCEvents[iEvent].enu_true), FLOAT_T(
MCEvents[iEvent].coszenith_true));
1156 osc_w_pointer =
Oscillator->GetNuOscillatorPointers(Sample, OscIndex, InitFlav, FinalFlav, FLOAT_T(
MCEvents[iEvent].enu_true));
1159 return osc_w_pointer;
1187 if (totalweight <= 0.){
1196 const int SampleIndex =
MCEvents[Event].NominalSample;
1198 bool NoOscChannels =
false;
1200 MACH3LOG_DEBUG(
"Assuming there are no osc channels in {}", __func__);
1201 NoOscChannels =
true;
1206 const double Etrue =
MCEvents[Event].enu_true;
1207 std::vector< std::vector<int> > EventSplines;
1208 switch(
GetNDim(SampleIndex)) {
1210 EventSplines = BinnedSpline->
GetEventSplines(SampleTitle, OscIndex, Mode, Etrue, *(
MCEvents[Event].KinVar[0]), 0.);
1216 if(ThrowCrititcal) {
1219 ThrowCrititcal =
false;
1224 return EventSplines;
1232 bool ThrowCrititcal =
true;
1234 for (
unsigned int j = 0; j <
GetNEvents(); ++j) {
1235 auto EventSplines =
GetSplineBins(j, BinnedSpline, ThrowCrititcal);
1236 const int NSplines =
static_cast<int>(EventSplines.size());
1237 if(NSplines == 0)
continue;
1238 auto& w_pointers =
MCEvents[j].total_weight_pointers;
1239 w_pointers.reserve(w_pointers.size() + NSplines);
1241 for(
int spline = 0; spline < NSplines; spline++) {
1242 int SystIndex = EventSplines[spline][2];
1247 MACH3LOG_TRACE(
"Event {}, missed Kinematic var check for dial {}", j, SplineParsVec[SystIndex].name);
1251 w_pointers.push_back(BinnedSpline->RetPointer(EventSplines[spline][0], EventSplines[spline][1],
1252 EventSplines[spline][2], EventSplines[spline][3],
1253 EventSplines[spline][4], EventSplines[spline][5],
1254 EventSplines[spline][6]));
1256 w_pointers.shrink_to_fit();
1259 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); ++iEvent) {
1260 MCEvents[iEvent].total_weight_pointers.push_back(UnbinnedSpline->RetPointer(iEvent));
1271 const int Start =
Binning->GetSampleStartBin(isample);
1272 const int End =
Binning->GetSampleEndBin(isample);
1274 double negLogL = 0.;
1276 #pragma omp parallel for reduction(+:negLogL)
1278 for (
int idx = Start; idx < End; ++idx)
1293 double negLogL = 0.;
1295 #pragma omp parallel for reduction(+:negLogL)
1297 for (
int idx = 0; idx <
Binning->GetNBins(); ++idx)
1318 for(
int iSample = 0; iSample <
GetNSamples(); iSample++)
1320 std::unique_ptr<TH1> data_hist;
1324 data_hist->GetXaxis()->SetTitle(
GetKinVarName(iSample, 0).c_str());
1325 data_hist->GetYaxis()->SetTitle(
"Number of Events");
1326 }
else if (
GetNDim(iSample) == 2) {
1327 if(
Binning->IsUniform(iSample)) {
1332 data_hist->GetXaxis()->SetTitle(
GetKinVarName(iSample, 0).c_str());
1333 data_hist->GetYaxis()->SetTitle(
GetKinVarName(iSample, 1).c_str());
1334 data_hist->GetZaxis()->SetTitle(
"Number of Events");
1337 int nbins =
Binning->GetNBins(iSample);
1338 for(
int iBin = 0; iBin < nbins; iBin++) {
1339 auto BinName =
Binning->GetBinName(iSample, iBin);
1340 data_hist->GetXaxis()->SetBinLabel(iBin+1, BinName.c_str());
1342 data_hist->GetYaxis()->SetTitle(
"Number of Events");
1350 data_hist->SetTitle((
"data_" +
GetSampleTitle(iSample)).c_str());
1359 bool LoadSplineFile = GetFromManager<bool>(
SampleManager->raw()[
"InputFiles"][
"LoadSplineFile"],
false, __FILE__, __LINE__);
1360 bool PrepSplineFile = GetFromManager<bool>(
SampleManager->raw()[
"InputFiles"][
"PrepSplineFile"],
false, __FILE__, __LINE__);
1361 auto SplineFileName = GetFromManager<std::string>(
SampleManager->raw()[
"InputFiles"][
"SplineFileName"],
1363 if(!LoadSplineFile) {
1364 for(
int iSample = 0; iSample <
GetNSamples(); iSample++) {
1365 std::vector<std::string> spline_filepaths =
SampleDetails[iSample].spline_files;
1368 std::vector<std::string> SplineVarNames = {
"TrueNeutrinoEnergy"};
1371 }
else if (
GetNDim(iSample) == 2) {
1381 BinnedSplines->CountNumberOfLoadedSplines(
false, 1);
1382 BinnedSplines->TransferToMonolith();
1383 if(PrepSplineFile) BinnedSplines->PrepareSplineFile(SplineFileName);
1386 BinnedSplines->LoadSplineFile(SplineFileName);
1393 BinnedSplines->cleanUpMemory();
1395 (void) UnbinnedSpline;
1405 const std::vector<KinematicCut>& ExtraCuts) {
1414 for (
const auto& cut : ExtraCuts) {
1415 selectionToApply[iSample].emplace_back(cut);
1419 Selection = std::move(selectionToApply);
1421 return originalSelection;
1427 const std::vector< KinematicCut >& EventSelectionVec,
1428 const int WeightStyle,
1429 const std::vector< KinematicCut >& SubEventSelectionVec) {
1437 auto _h1DVar = std::make_unique<TH1D>(
"",
"",
int(xBinEdges.size())-1, xBinEdges.data());
1438 _h1DVar->SetDirectory(
nullptr);
1439 _h1DVar->GetXaxis()->SetTitle(ProjectionVar_Str.c_str());
1440 _h1DVar->GetYaxis()->SetTitle(
"Events");
1443 Fill1DSubEventHist(iSample, _h1DVar.get(), ProjectionVar_Str, SubEventSelectionVec, WeightStyle);
1449 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1450 const int EventSample =
MCEvents[iEvent].NominalSample;
1451 if(EventSample != iSample)
continue;
1454 if (WeightStyle == 1) {
1458 _h1DVar->Fill(Var, Weight);
1470 const std::vector< KinematicCut >& SubEventSelectionVec,
const int WeightStyle) {
1475 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1476 const int EventSample =
MCEvents[iEvent].NominalSample;
1477 if(EventSample != iSample)
continue;
1480 if (WeightStyle == 1) {
1484 size_t nsubevents = Vec.size();
1486 for (
unsigned int iSubEvent = 0; iSubEvent < nsubevents; iSubEvent++) {
1488 double Var = Vec[iSubEvent];
1489 _h1DVar->Fill(Var,Weight);
1498 const std::string& ProjectionVar_StrX,
1499 const std::string& ProjectionVar_StrY,
1500 const std::vector< KinematicCut >& EventSelectionVec,
1501 const int WeightStyle,
const std::vector< KinematicCut >& SubEventSelectionVec) {
1509 std::unique_ptr<TH2> _h2DVar;
1512 _h2DVar = std::unique_ptr<TH2>(
static_cast<TH2*
>(
M3::Clone(
GetMCHist(iSample)).release()));
1516 _h2DVar = std::make_unique<TH2D>(
"",
"",
int(xBinEdges.size())-1, xBinEdges.data(),
int(yBinEdges.size())-1, yBinEdges.data());
1518 _h2DVar->SetDirectory(
nullptr);
1519 _h2DVar->GetXaxis()->SetTitle(ProjectionVar_StrX.c_str());
1520 _h2DVar->GetYaxis()->SetTitle(ProjectionVar_StrY.c_str());
1521 _h2DVar->GetZaxis()->SetTitle(
"Events");
1524 if (IsSubEventHist)
Fill2DSubEventHist(iSample, _h2DVar.get(), ProjectionVar_StrX, ProjectionVar_StrY, SubEventSelectionVec, WeightStyle);
1531 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1532 const int EventSample =
MCEvents[iEvent].NominalSample;
1533 if(EventSample != iSample)
continue;
1536 if (WeightStyle == 1) {
1541 _h2DVar->Fill(VarX,VarY,Weight);
1553 const std::string& ProjectionVar_StrX,
1554 const std::string& ProjectionVar_StrY,
1555 const std::vector< KinematicCut >& SubEventSelectionVec,
1561 int ProjectionVar_IntX, ProjectionVar_IntY;
1568 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1569 const int EventSample =
MCEvents[iEvent].NominalSample;
1570 if(EventSample != iSample)
continue;
1573 if (WeightStyle == 1) {
1576 std::vector<double> VecX = {}, VecY = {};
1578 size_t nsubevents = 0;
1580 if (IsSubEventVarX && !IsSubEventVarY) {
1583 nsubevents = VecX.size();
1585 else if (!IsSubEventVarX && IsSubEventVarY) {
1588 nsubevents = VecY.size();
1593 if (VecX.size() != VecY.size()) {
1594 MACH3LOG_ERROR(
"Cannot plot {} of size {} against {} of size {}", ProjectionVar_StrX, VecX.size(), ProjectionVar_StrY, VecY.size());
1597 nsubevents = VecX.size();
1600 for (
unsigned int iSubEvent = 0; iSubEvent < nsubevents; iSubEvent++) {
1602 if (IsSubEventVarX) VarX = VecX[iSubEvent];
1603 if (IsSubEventVarY) VarY = VecY[iSubEvent];
1604 _h2DVar->Fill(VarX,VarY,Weight);
1617 MACH3LOG_ERROR(
"Did not recognise Kinematic Parameter type: {}", KinematicParameterStr);
1631 MACH3LOG_ERROR(
"Did not recognise Kinematic Parameter type: {}", KinematicParameter);
1644 MACH3LOG_ERROR(
"Did not recognise Kinematic Vector: {}", KinematicVectorStr);
1658 MACH3LOG_ERROR(
"Did not recognise Kinematic Vector: {}", KinematicVector);
1669 if(
Binning->IsUniform(Sample)) {
1670 for(
int iDim = 0; iDim <
GetNDim(Sample); iDim++) {
1672 return Binning->GetBinEdges(Sample, iDim);
1677 auto MakeBins = [](
int nBins) {
1678 std::vector<double> bins(nBins + 1);
1679 for (
int i = 0; i <= nBins; ++i)
1680 bins[i] =
static_cast<double>(i) - 0.5;
1684 if (KinematicParameter ==
"OscillationChannel") {
1686 }
else if (KinematicParameter ==
"Mode") {
1687 return MakeBins(
Modes->GetNModes());
1690 std::vector<double> BinningVect;
1694 BinningVect = Get<std::vector<double>>(BinningConfig[
GetSampleTitle(Sample)][KinematicParameter], __FILE__, __LINE__);
1696 BinningVect = Get<std::vector<double>>(BinningConfig[KinematicParameter], __FILE__, __LINE__);
1700 auto IsIncreasing = [](
const std::vector<double>& vec) {
1701 for (
size_t i = 1; i < vec.size(); ++i) {
1702 if (vec[i] <= vec[i-1]) {
1709 if (!IsIncreasing(BinningVect)) {
1710 MACH3LOG_ERROR(
"Binning for {} is not increasing [{}]", KinematicParameter, fmt::join(BinningVect,
", "));
1725 MACH3LOG_ERROR(
"Attempted to plot kinematic variable {}, but it appears in both KinematicVectors and KinematicParameters", VarStr);
1739 if (kChannelToFill != -1) {
1751 if (kModeToFill != -1) {
1752 if (!(kModeToFill >= 0) && (kModeToFill < Modes->GetNModes())) {
1753 MACH3LOG_ERROR(
"Required mode is not available. kModeToFill should be between 0 and {}",
Modes->GetNModes());
1763 std::vector< KinematicCut > SelectionVec;
1770 SelectionVec.push_back(SelecMode);
1778 SelectionVec.push_back(SelecChannel);
1781 return SelectionVec;
1786 const int kModeToFill,
const int kChannelToFill,
const int WeightStyle) {
1789 return Get1DVarHist(iSample, ProjectionVar_Str, SelectionVec, WeightStyle);
1794 const std::string& ProjectionVar_StrY,
const int kModeToFill,
1795 const int kChannelToFill,
const int WeightStyle) {
1798 return Get2DVarHist(iSample, ProjectionVar_StrX, ProjectionVar_StrY, SelectionVec, WeightStyle);
1804 constexpr
int space = 14;
1806 bool printToFile=
false;
1807 if (OutputFileName.CompareTo(
"/dev/null")) {printToFile =
true;}
1809 bool printToCSV=
false;
1810 if(OutputCSVFileName.CompareTo(
"/dev/null")) printToCSV=
true;
1812 std::ofstream outfile;
1814 outfile.open(OutputFileName.Data(), std::ios_base::app);
1815 outfile.precision(7);
1818 std::ofstream outcsv;
1820 outcsv.open(OutputCSVFileName, std::ios_base::app);
1821 outcsv.precision(7);
1824 double PDFIntegral = 0.;
1826 std::vector< std::vector< std::unique_ptr<TH1> > > IntegralList;
1827 IntegralList.resize(
Modes->GetNModes());
1829 std::vector<double> ChannelIntegral;
1831 for (
unsigned int i=0;i<ChannelIntegral.size();i++) {ChannelIntegral[i] = 0.;}
1833 for (
int i=0;i<
Modes->GetNModes();i++) {
1841 MACH3LOG_INFO(
"-------------------------------------------------");
1844 outfile <<
"\\begin{table}[ht]" << std::endl;
1845 outfile <<
"\\begin{center}" << std::endl;
1846 outfile <<
"\\caption{Integral breakdown for sample: " <<
GetSampleTitle(iSample) <<
"}" << std::endl;
1847 outfile <<
"\\label{" <<
GetSampleTitle(iSample) <<
"-EventRate}" << std::endl;
1852 outfile <<
"\\begin{tabular}{|l" << nColumns.Data() <<
"}" << std::endl;
1853 outfile <<
"\\hline" << std::endl;
1858 outcsv<<
"Integral Breakdown for sample :"<<
GetSampleTitle(iSample)<<
"\n";
1864 if (printToFile) {outfile << std::setw(space) <<
"Mode:";}
1865 if(printToCSV) {outcsv<<
"Mode,";}
1867 std::string table_headings = fmt::format(
"| {:<8} |",
"Mode");
1868 std::string table_footline =
"------------";
1870 table_headings += fmt::format(
" {:<17} |",
GetFlavourName(iSample, i));
1871 table_footline +=
"--------------------";
1872 if (printToFile) {outfile <<
"&" << std::setw(space) <<
SampleDetails[iSample].OscChannels[i].flavourName_Latex <<
" ";}
1875 if (printToFile) {outfile <<
"&" << std::setw(space) <<
"Total:" <<
"\\\\ \\hline" << std::endl;}
1876 if (printToCSV) {outcsv <<
"Total\n";}
1877 table_headings += fmt::format(
" {:<10} |",
"Total");
1878 table_footline +=
"-------------";
1883 for (
unsigned int i=0;i<IntegralList.size();i++) {
1884 double ModeIntegral = 0;
1885 if (printToFile) {outfile << std::setw(space) <<
Modes->GetMaCh3ModeName(i);}
1886 if(printToCSV) {outcsv <<
Modes->GetMaCh3ModeName(i) <<
",";}
1888 table_headings = fmt::format(
"| {:<8} |",
Modes->GetMaCh3ModeName(i));
1890 for (
unsigned int j=0;j<IntegralList[i].size();j++) {
1891 double Integral = IntegralList[i][j]->Integral();
1893 if (Integral < 1e-100) {Integral=0;}
1895 ModeIntegral += Integral;
1896 ChannelIntegral[j] += Integral;
1897 PDFIntegral += Integral;
1899 if (printToFile) {outfile <<
"&" << std::setw(space) << Form(
"%4.5f",Integral) <<
" ";}
1900 if (printToCSV) {outcsv << Form(
"%4.5f", Integral) <<
",";}
1902 table_headings += fmt::format(
" {:<17.4f} |", Integral);
1904 if (printToFile) {outfile <<
"&" << std::setw(space) << Form(
"%4.5f",ModeIntegral) <<
" \\\\ \\hline" << std::endl;}
1905 if (printToCSV) {outcsv << Form(
"%4.5f", ModeIntegral) <<
"\n";}
1907 table_headings += fmt::format(
" {:<10.4f} |", ModeIntegral);
1912 if (printToFile) {outfile << std::setw(space) <<
"Total:";}
1913 if (printToCSV) {outcsv <<
"Total,";}
1916 table_headings = fmt::format(
"| {:<8} |",
"Total");
1917 for (
unsigned int i=0;i<ChannelIntegral.size();i++) {
1918 if (printToFile) {outfile <<
"&" << std::setw(space) << Form(
"%4.5f",ChannelIntegral[i]) <<
" ";}
1919 if (printToCSV) {outcsv << Form(
"%4.5f", ChannelIntegral[i]) <<
",";}
1920 table_headings += fmt::format(
" {:<17.4f} |", ChannelIntegral[i]);
1922 if (printToFile) {outfile <<
"&" << std::setw(space) << Form(
"%4.5f",PDFIntegral) <<
" \\\\ \\hline" << std::endl;}
1923 if (printToCSV) {outcsv << Form(
"%4.5f", PDFIntegral) <<
"\n\n\n\n";}
1925 table_headings += fmt::format(
" {:<10.4f} |", PDFIntegral);
1930 outfile <<
"\\end{tabular}" << std::endl;
1931 outfile <<
"\\end{center}" << std::endl;
1932 outfile <<
"\\end{table}" << std::endl;
1938 outfile << std::endl;
1945 const int Selection1,
const int Selection2,
const int WeightStyle) {
1947 std::vector<std::unique_ptr<TH1>> hHistList;
1948 std::string legendEntry;
1954 if (Selection1 == FDPlotType::kModePlot) {
1955 iMax =
Modes->GetNModes();
1957 if (Selection1 == FDPlotType::kOscChannelPlot) {
1961 MACH3LOG_ERROR(
"You've passed me a Selection1 which was not implemented in ReturnHistsBySelection1D. Selection1 and Selection2 are counters for different indexable quantities");
1965 for (
int i=0;i<iMax;i++) {
1966 if (Selection1 == FDPlotType::kModePlot) {
1968 THStackLeg->AddEntry(hHistList[i].get(), (
Modes->GetMaCh3ModeName(i)+Form(
" : (%4.2f)",hHistList[i]->Integral())).c_str(),
"f");
1970 hHistList[i]->SetFillColor(
static_cast<Color_t
>(
Modes->GetMaCh3ModePlotColor(i)));
1971 hHistList[i]->SetLineColor(
static_cast<Color_t
>(
Modes->GetMaCh3ModePlotColor(i)));
1973 if (Selection1 == FDPlotType::kOscChannelPlot) {
1975 THStackLeg->AddEntry(hHistList[i].get(),(
GetFlavourName(iSample, i)+Form(
" | %4.2f",hHistList[i]->Integral())).c_str(),
"f");
1984 const std::string& KinematicProjectionY,
const int Selection1,
1985 const int Selection2,
const int WeightStyle) {
1987 std::vector<std::unique_ptr<TH2>> hHistList;
1990 if (Selection1 == FDPlotType::kModePlot) {
1991 iMax =
Modes->GetNModes();
1993 if (Selection1 == FDPlotType::kOscChannelPlot) {
1997 MACH3LOG_ERROR(
"You've passed me a Selection1 which was not implemented in ReturnHistsBySelection1D. Selection1 and Selection2 are counters for different indexable quantities");
2001 for (
int i=0;i<iMax;i++) {
2002 if (Selection1 == FDPlotType::kModePlot) {
2005 if (Selection1 == FDPlotType::kOscChannelPlot) {
2015 int Selection1,
int Selection2,
int WeightStyle) {
2018 auto StackHist = std::make_unique<THStack>((
GetSampleTitle(iSample)+
"_"+KinematicProjection+
"_Stack").c_str(),
"");
2020 for (
unsigned int i=0;i<HistList.size();i++) {
2021 StackHist->Add(HistList[i].release());
2031 return &(OscillationChannels[Channel].ChannelIndex);
2045 const std::string sep_full(71,
'-');
2047 MACH3LOG_INFO(
"{:<40}{:<10}{:<10}{:<10}|",
"Sample",
"Data",
"MC",
"-LLH");
2049 const std::string sep_data(51,
'-');
2054 double sumData = 0.0;
2056 double likelihood = 0.0;
2058 for (
int iSample = 0; iSample <
GetNSamples(); ++iSample) {
2061 double dataIntegral = std::accumulate(DataArray.begin(), DataArray.end(), 0.0);
2062 sumData += dataIntegral;
2064 std::vector<double> MCArray =
GetMCArray(iSample);
2065 double mcIntegral = std::accumulate(MCArray.begin(), MCArray.end(), 0.0);
2066 sumMC += mcIntegral;
2069 MACH3LOG_INFO(
"{:<40}{:<10.2f}{:<10.2f}{:<10.2f}|", name, dataIntegral, mcIntegral, likelihood);
2076 MACH3LOG_INFO(
"{:<40}{:<10.2f}{:<10.2f}{:<10.2f}|",
"Total", sumData, sumMC, likelihood);
2077 const std::string sep_full(71,
'-');
2081 const std::string sep_data(51,
'-');
2090 if(Dimension >
GetNDim(iSample)) {
2100 const int Start =
Binning->GetSampleStartBin(Sample);
2101 const int End =
Binning->GetSampleEndBin(Sample);
2103 return std::vector<double>(array.begin() + Start, array.begin() + End);
2107 template <
typename ParT>
2110 bool IsSelected =
true;
2111 if (Par.hasKinBounds) {
2112 const auto& kinVars = Par.KinematicVarStr;
2113 const auto& selection = Par.Selection;
2115 for (std::size_t iKinPar = 0; iKinPar < kinVars.size(); ++iKinPar) {
2118 bool passedAnyBound =
false;
2119 const auto& boundsList = selection[iKinPar];
2121 for (
const auto& bounds : boundsList) {
2122 if (kinVal > bounds[0] && kinVal <= bounds[1]) {
2123 passedAnyBound =
true;
2128 if (!passedAnyBound) {
2129 MACH3LOG_TRACE(
"Event {}, missed kinematic check ({}) for dial {}",
2130 iEvent, kinVars[iKinPar], Par.name);
#define _noexcept_
KS: noexcept can help with performance but is terrible for debugging, this is meant to help easy way ...
#define _restrict_
KS: Using restrict limits the effects of pointer aliasing, aiding optimizations. While reading I foun...
int GetOscChannel(const std::vector< OscChannelInfo > &OscChannel, const int InitFlav, const int FinalFlav)
KS: Get Osc Channel Index based on initial and final PDG codes.
Defines the custom exception class used throughout MaCh3.
MaCh3 Logging utilities built on top of SPDLOG.
#define MACH3LOG_CRITICAL
void CleanVector(T &)
Base case: do nothing for non-vector types.
std::function< void(const M3::float_t *, std::size_t)> FuncParFuncType
HH - a shorthand type for funcpar functions.
NuPDG
Enum to track the incoming neutrino species.
TestStatistic
Make an enum of the test statistic that we're using.
TMacro YAMLtoTMacro(const YAML::Node &yaml_node, const std::string &name)
Convert a YAML node to a ROOT TMacro object.
Type GetFromManager(const YAML::Node &node, const Type defval, const std::string File="", const int Line=1)
Get content of config file if node is not found take default value specified.
bool CheckNodeExists(const YAML::Node &node, Args... args)
KS: Wrapper function to call the recursive helper.
#define M3OpenConfig(filename)
Macro to simplify calling LoadYaml with file and line info.
#define GetBounds(filename)
Bin-by-bin class calculating response for spline parameters.
std::vector< std::vector< int > > GetEventSplines(const std::string &SampleTitle, int iOscChan, int EventMode, double Var1Val, double Var2Val, double Var3Val)
Return the splines which affect a given event.
Custom exception class used throughout MaCh3.
const M3::float_t * RetPointer(const int iParam)
DB Pointer return to param position.
std::string GetParFancyName(const int i) const
Get fancy name of the Parameter.
Class responsible for handling of systematic error parameters with different types defined in the con...
const std::vector< NormParameter > GetNormParsFromSampleName(const std::string &SampleName) const
DB Get norm/func parameters depending on given SampleName.
std::vector< const M3::float_t * > GetOscParsFromSampleName(const std::string &SampleName)
Get pointers to Osc params from Sample name.
const std::vector< SplineParameter > GetSplineParsFromSampleName(const std::string &SampleName) const
KS: Grab the Spline parameters for the relevant SampleName.
const std::vector< FunctionalParameter > GetFunctionalParametersFromSampleName(const std::string &SampleName) const
HH Get functional parameters for the relevant SampleName.
std::vector< double > ReturnKinematicVector(const std::string &KinematicParameter, const int iEvent) const
void InitialiseSplineObject()
virtual ~SampleHandlerBase()
destructor
std::string SampleHandlerName
A unique ID for each sample based on which we can define what systematic should be applied.
const std::unordered_map< int, std::string > * ReversedKinematicParameters
Mapping between kinematic enum and string.
std::shared_ptr< OscillationHandler > Oscillator
Contains oscillator handling calculating oscillation probabilities.
int GetNDim(const int Sample) const final
DB Get what dimensionality binning for given sample has.
std::vector< KinematicCut > BuildModeChannelSelection(const int iSample, const int kModeToFill, const int kChannelToFill) const
void SetBinning()
set the binning for 2D sample used for the likelihood calculation
void PrintIntegral(const int iSample, const TString &OutputName="/dev/null", const int WeightStyle=0, const TString &OutputCSVName="/dev/null")
Computes and prints the integral breakdown of all modes and oscillation channels for a given sample.
std::unique_ptr< Manager > SampleManager
The manager object used to read the sample yaml file.
std::string GetKinVarName(const int iSample, const int Dimension) const final
Return Kinematic Variable name for specified sample and dimension for example "Reconstructed_Neutrino...
bool PassesSelection(const ParT &Par, std::size_t iEvent)
std::unordered_map< std::string, int > funcParsNamesMap
HH - a map that relates the name of the functional parameter to funcpar enum.
bool IsSubEventVarString(const std::string &VarStr) const
JM: Check if a kinematic parameter string corresponds to a subevent-level variable.
std::unique_ptr< TH1 > Get1DVarHistByModeAndChannel(const int iSample, const std::string &ProjectionVar_Str, const int kModeToFill=-1, const int kChannelToFill=-1, const int WeightStyle=0) final
void SetupNormParameters()
Setup the norm parameters by assigning each event with bin.
void ReadConfig()
Load information about sample handler and corresponding samples from config file.
const TH1 * GetW2Hist(const int Sample) final
Get W2 histogram.
virtual void FinaliseShifts(const int iEvent)
LP - Optionally calculate derived observables after all shifts have been applied.
void SetupKinematicMap()
Ensure Kinematic Map is setup and make sure it is initialised correctly.
std::vector< std::vector< KinematicCut > > StoredSelection
What gets pulled from config options, these are constant after loading in this is of length 3: 0th in...
virtual void Init()=0
Initialise any variables that your experiment specific SampleHandler needs.
const TH1 * GetDataHist(const int Sample) final
Get Data histogram.
std::string GetFlavourName(const int iSample, const int iChannel) const final
std::unordered_map< std::string, NuPDG > FileToFinalPDGMap
std::vector< double > ReturnKinematicParameterBinning(const int Sample, const std::string &KinematicParameter) const final
Return the binning used to draw a kinematic parameter.
void InitialiseNuOscillatorObjects()
including Dan's magic NuOscillator
const std::unordered_map< std::string, int > * KinematicParameters
Mapping between string and kinematic enum.
std::unordered_map< std::string, double > _modeNomWeightMap
void FillArray_MP()
DB Nice new multi-threaded function which calculates the event weights and fills the relevant bins of...
std::string ReturnStringFromKinematicVector(const int KinematicVariable) const
JM: Convert a kinematic vector integer ID to its corresponding name as a string.
bool IsEventSelected(const int iSample, const int iEvent) _noexcept_
DB Function which determines if an event is selected based on KinematicCut.
void SaveAdditionalInfo(TDirectory *Dir) final
Store additional info in a chan.
virtual void PrepFunctionalParameters()
Update the functional parameter values to the latest proposed values. Needs to be called before every...
std::unordered_map< std::string, NuPDG > FileToInitPDGMap
std::vector< std::string > funcParsNamesVec
HH - a vector of string names for each functional parameter.
void SetSplinePointers()
Set pointers for each event to appropriate weights, for unbinned based on event number while for binn...
SampleHandlerBase(std::string ConfigFileName, ParameterHandlerGeneric *xsec_cov, const std::shared_ptr< OscillationHandler > &OscillatorObj_=nullptr)
Constructor.
std::unique_ptr< BinningHandler > Binning
KS: This stores binning information, in future could be come vector to store binning for every used s...
ParameterHandlerGeneric * ParHandler
ETA - All experiments will need an xsec, det and osc cov.
M3::float_t GetEventWeight(const int iEntry)
Computes the total event weight for a given entry.
bool UpdateW2
KS:Super hacky to update W2 or not.
const std::unordered_map< int, std::string > * ReversedKinematicVectors
std::vector< FunctionalShifter > funcParsMap
HH - a map that relates the funcpar enum to pointer of FuncPars struct HH - Changed to a vector of po...
void Fill1DSubEventHist(const int iSample, TH1D *_h1DVar, const std::string &ProjectionVar, const std::vector< KinematicCut > &SubEventSelectionVec={}, int WeightStyle=0)
virtual void SetupMC()=0
Function which translates experiment struct into core struct.
virtual void InititialiseData()=0
Function responsible for loading data from file or loading from file.
virtual void ApplyShifts(const int iEvent)
ETA - generic function applying shifts.
void Initialise()
Function which does a lot of the lifting regarding the workflow in creating different MC objects.
virtual void SetupSplines()=0
initialise your splineXX object and then use InitialiseSplineObject to conviently setup everything up
double GetSampleLikelihood(const int isample) const override
Get likelihood for single sample.
virtual void ResetShifts(const int iEvent)
HH - reset the shifted values to the original values.
std::vector< std::vector< FunctionalShifter * > > funcParsGrid
HH - a grid of vectors of enums for each sample and event.
void CalcNormsBins(std::vector< NormParameter > &norm_parameters, std::vector< std::vector< int > > &norms_bins)
Check whether a normalisation systematic affects an event or not.
void SetupReweightArrays()
Initialise data, MC and W2 histograms.
std::vector< std::unique_ptr< TH1 > > ReturnHistsBySelection1D(const int iSample, const std::string &KinematicProjection, const int Selection1, const int Selection2=-1, const int WeightStyle=0)
std::vector< std::unique_ptr< TH2 > > ReturnHistsBySelection2D(const int iSample, const std::string &KinematicProjectionX, const std::string &KinematicProjectionY, const int Selection1, const int Selection2=-1, const int WeightStyle=0)
void ResetHistograms()
Helper function to reset histograms.
virtual void AddAdditionalWeightPointers()=0
DB Function to determine which weights apply to which types of samples.
void Fill2DSubEventHist(const int iSample, TH2 *_h2DVar, const std::string &ProjectionVarX, const std::string &ProjectionVarY, const std::vector< KinematicCut > &SubEventSelectionVec={}, int WeightStyle=0)
void FillHist(const int Sample, TH1 *Hist, std::vector< double > &Array)
Fill a histogram with the event-level information used in the fit.
virtual int SetupExperimentMC()=0
Experiment specific setup, returns the number of events which were loaded.
void FindNominalBinAndEdges()
const M3::float_t * GetNuOscillatorPointers(const int iEvent) const
virtual void SetupFunctionalParameters()
ETA - a function to setup and pass values to functional parameters where you need to pass a value to ...
std::string GetName() const final
Get name for Sample Handler.
std::vector< std::vector< KinematicCut > > ApplyTemporarySelection(const int iSample, const std::vector< KinematicCut > &ExtraCuts)
Temporarily extend Selection for a given sample with additional cuts. Returns the original Selection ...
const double * GetPointerToOscChannel(const int iEvent) const
Get pointer to oscillation channel associated with given event. Osc channel is const.
const std::unordered_map< std::string, int > * KinematicVectors
int GetSampleIndex(const std::string &SampleTitle) const
Get index of sample based on name.
std::vector< std::vector< KinematicCut > > Selection
a way to store selection cuts which you may push back in the get1DVar functions most of the time this...
std::vector< std::vector< int > > GetSplineBins(int Event, BinnedSplineHandler *BinnedSpline, bool &ThrowCrititcal) const
Retrieve the spline bin indices associated with a given event.
TLegend * THStackLeg
DB Miscellaneous Variables.
void AddData(const int Sample, TH1 *Data)
void SetupNuOscillatorPointers()
Initialise pointer to oscillation weight to NuOscillator object.
double ReturnKinematicParameter(const std::string &KinematicParameter, int iEvent) const
Return the value of an associated kinematic parameter for an event.
std::unique_ptr< THStack > ReturnStackedHistBySelection1D(const int iSample, const std::string &KinematicProjection, const int Selection1, const int Selection2=-1, const int WeightStyle=0)
std::unordered_map< int, FuncParFuncType > funcParsFuncMap
HH - a map that relates the funcpar enum to pointer of the actual function.
double GetLikelihood() const override
DB Multi-threaded GetLikelihood.
std::vector< EventInfo > MCEvents
Stores information about every MC event.
M3::float_t CalcWeightTotal(const EventInfo *_restrict_ MCEvent) const _noexcept_
Calculate the total weight weight for a given event.
auto GetDataArray() const
Return array storing data entries for every bin.
std::unique_ptr< SplineBase > SplineHandler
Contains all your splines (binned or unbinned) and handles the setup and the returning of weights fro...
std::vector< SampleInfo > SampleDetails
Stores info about currently initialised sample.
int GetNOscChannels(const int iSample) const final
Get number of oscillation channels for a single sample.
std::string GetSampleTitle(const int Sample) const final
Get fancy title for specified samples.
std::unique_ptr< TH2 > Get2DVarHist(const int iSample, const std::string &ProjectionVarX, const std::string &ProjectionVarY, const std::vector< KinematicCut > &EventSelectionVec={}, int WeightStyle=0, const std::vector< KinematicCut > &SubEventSelectionVec={}) final
void LoadSingleSample(const int iSample, const YAML::Node &Settings)
Initialise single sample from config file.
std::vector< double > SampleHandler_data
DB Array to be filled in AddData.
virtual void RegisterFunctionalParameters()=0
HH - a experiment-specific function where the maps to actual functions are set up.
std::vector< double > SampleHandler_array_w2
KS Array used for MC stat.
void PrintRates(const bool DataOnly=false) final
Helper function to print rates for the samples with LLH.
void Reweight() override
main routine modifying MC prediction based on proposed parameter values
std::string ReturnStringFromKinematicParameter(const int KinematicVariable) const
ETA function to generically convert a kinematic type from xsec cov to a string.
std::unique_ptr< TH2 > Get2DVarHistByModeAndChannel(const int iSample, const std::string &ProjectionVar_StrX, const std::string &ProjectionVar_StrY, const int kModeToFill=-1, const int kChannelToFill=-1, const int WeightStyle=0) final
std::unique_ptr< TH1 > Get1DVarHist(const int iSample, const std::string &ProjectionVar, const std::vector< KinematicCut > &EventSelectionVec={}, int WeightStyle=0, const std::vector< KinematicCut > &SubEventSelectionVec={}) final
void SetupOscParameters()
Setup the osc parameters.
int ReturnKinematicParameterFromString(const std::string &KinematicStr) const
ETA function to generically convert a string from xsec cov to a kinematic type.
bool IsSubEventSelected(const std::vector< KinematicCut > &SubEventCuts, const int iEvent, unsigned const int iSubEvent, size_t nsubevents)
JM Function which determines if a subevent is selected.
std::vector< double > GetArrayForSample(const int Sample, std::vector< double > const &array) const
Return a sub-array for a given sample.
void RegisterIndividualFunctionalParameter(const std::string &fpName, int fpEnum, FuncParFuncType fpFunc)
HH - a helper function for RegisterFunctionalParameter.
virtual void CalcWeightFunc(const int iEvent)
Calculate weights for function parameters.
const double * GetPointerToKinematicParameter(const std::string &KinematicParameter, int iEvent) const
std::vector< double > SampleHandler_array
DB Array to be filled after reweighting.
int ReturnKinematicVectorFromString(const std::string &KinematicStr) const
JM: Convert a kinematic vector name to its corresponding integer ID.
std::vector< FunctionalParameter > funcParsVec
HH - a vector that stores all the FuncPars struct.
auto GetMCArray() const
Return array storing MC entries for every bin.
const TH1 * GetMCHist(const int Sample) final
Get MC histogram.
void FillArray()
Function which does the core reweighting, fills the SampleHandlerBase::SampleHandler_array vector wit...
bool FirstTimeW2
KS:Super hacky to update W2 or not.
Class responsible for handling implementation of samples used in analysis, reweighting and returning ...
TestStatistic fTestStatistic
Test statistic tells what kind of likelihood sample is using.
bool MatchCondition(const std::vector< T > &allowedValues, const T &value)
check if event is affected by following conditions, for example pdg, or modes etc
double GetTestStatLLH(const double data, const double mc, const double w2) const
Calculate test statistic for a single bin. Calculation depends on setting of fTestStatistic....
M3::int_t nSamples
Contains how many samples we've got.
unsigned int nEvents
Number of MC events are there.
virtual M3::int_t GetNSamples()
std::unique_ptr< MaCh3Modes > Modes
Holds information about used Generator and MaCh3 modes.
unsigned int GetNEvents() const
Even-by-event class calculating response for spline parameters. It is possible to use GPU acceleratio...
int PDGToNuOscillatorFlavour(const int NuPdg)
Convert from PDG flavour to NuOscillator type beware that in the case of anti-neutrinos the NuOscilla...
std::unique_ptr< ObjectType > Clone(const ObjectType *obj, const std::string &name="")
KS: Creates a copy of a ROOT-like object and wraps it in a smart pointer.
void CheckBinningMatch(const TH1D *Hist1, const TH1D *Hist2, const std::string &File, const int Line)
KS: Helper function check if data and MC binning matches.
constexpr static const double _BAD_DOUBLE_
Default value used for double initialisation.
constexpr static const float_t Unity
constexpr static const float_t Zero
constexpr static const int UnderOverFlowBin
Mark bin which is overflow or underflow in MaCh3 binning.
constexpr static const int _BAD_INT_
Default value used for int initialisation.
Stores info about each MC event used during reweighting routine.
HH - Functional parameters Carrier for whether you want to apply a systematic to an event or not.
KS: Small struct used for applying kinematic cuts.
double UpperBound
Upper bound on which we apply cut.
double LowerBound
Lower bound on which we apply cut.
int ParamToCutOnIt
Index or enum value identifying the kinematic variable to cut on.
KS: Store info about used osc channels.
int InitPDG
PDG of initial flavour.
double ChannelIndex
In case experiment specific would like to have pointer to channel after using GetOscChannel,...
int FinalPDG
PDG of oscillated/final flavour.
std::string flavourName
Name of osc channel.
std::string flavourName_Latex
Fancy channel name (e.g., LaTeX formatted)
KS: Store info about MC sample.
std::vector< OscChannelInfo > OscChannels
Stores info about oscillation channel for a single sample.
std::string SampleTitle
the name of this sample e.g."muon-like"
std::vector< std::string > spline_files
names of spline files associated associated with this object
std::vector< std::vector< std::string > > mc_files
names of mc files associated associated with this object