13 const std::shared_ptr<OscillationHandler>& OscillatorObj_) :
SampleHandlerBase() {
15 MACH3LOG_INFO(
"-------------------------------------------------------------------");
20 MACH3LOG_ERROR(
"You've passed me a nullptr to a SystematicHandlerGeneric... I need this to setup splines!");
27 if (OscillatorObj_ !=
nullptr) {
28 MACH3LOG_WARN(
"You have passed an Oscillator object through the constructor of a SampleHandlerFD object - this will be used for all oscillation channels");
41 SampleManager = std::make_unique<Manager>(ConfigFileName.c_str());
42 Binning = std::make_unique<BinningHandler>();
61 auto ModeName = Get<std::string>(
SampleManager->raw()[
"MaCh3ModeConfig"], __FILE__ , __LINE__);
62 Modes = std::make_unique<MaCh3Modes>(ModeName);
76 auto EnabledSasmples = Get<std::vector<std::string>>(
SampleManager->raw()[
"Samples"], __FILE__ , __LINE__);
81 for (
int iSample = 0; iSample <
nSamples; iSample++)
83 auto SampleSettings =
SampleManager->raw()[EnabledSasmples[iSample]];
88 for(
int iMode=0; iMode <
Modes->GetNModes(); iMode++ ) {
94 for(
int iMode=0; iMode<
Modes->GetNModes(); iMode++ ) {
95 std::string modeStr =
Modes->GetMaCh3ModeName(iMode);
97 double modeWeight =
SampleManager->raw()[
"NominalWeights"][modeStr].as<
double>();
105 for(
int iMode=0; iMode<
Modes->GetNModes(); iMode++ ) {
106 std::string modeStr =
Modes->GetMaCh3ModeName(iMode);
117 SingleSample.
SampleTitle = Get<std::string>(SampleSettings[
"SampleTitle"], __FILE__ , __LINE__);
119 Binning->SetupSampleBinning(SampleSettings[
"Binning"], SingleSample);
121 auto mtupleprefix = Get<std::string>(SampleSettings[
"InputFiles"][
"mtupleprefix"], __FILE__, __LINE__);
122 auto mtuplesuffix = Get<std::string>(SampleSettings[
"InputFiles"][
"mtuplesuffix"], __FILE__, __LINE__);
123 auto splineprefix = Get<std::string>(SampleSettings[
"InputFiles"][
"splineprefix"], __FILE__, __LINE__);
124 auto splinesuffix = Get<std::string>(SampleSettings[
"InputFiles"][
"splinesuffix"], __FILE__, __LINE__);
126 int NChannels =
static_cast<M3::int_t>(SampleSettings[
"SubSamples"].size());
129 int OscChannelCounter = 0;
130 for (
auto const &osc_channel : SampleSettings[
"SubSamples"]) {
131 std::string MTupleFileName = mtupleprefix+osc_channel[
"mtuplefile"].as<std::string>()+mtuplesuffix;
134 OscInfo.
flavourName = osc_channel[
"Name"].as<std::string>();
135 OscInfo.flavourName_Latex = osc_channel[
"LatexName"].as<std::string>();
136 OscInfo.InitPDG =
static_cast<NuPDG>(osc_channel[
"nutype"].as<
int>());
137 OscInfo.FinalPDG =
static_cast<NuPDG>(osc_channel[
"oscnutype"].as<
int>());
138 OscInfo.ChannelIndex = OscChannelCounter;
140 SingleSample.
OscChannels.push_back(std::move(OscInfo));
145 SingleSample.
mc_files.push_back(MTupleFileName);
146 SingleSample.
spline_files.push_back(splineprefix+osc_channel[
"splinefile"].as<std::string>()+splinesuffix);
150 for (
auto const &SelectionCuts : SampleSettings[
"SelectionCuts"]) {
151 auto TempBoundsVec =
GetBounds(SelectionCuts[
"Bounds"]);
156 MACH3LOG_INFO(
"Adding cut on {} with bounds {} to {}", SelectionCuts[
"KinematicStr"].as<std::string>(), TempBoundsVec[0], TempBoundsVec[1]);
177 MACH3LOG_INFO(
"=============================================");
181 if (OscParams.size() > 0) {
184 MACH3LOG_INFO(
"You have passed an OscillatorBase object through the constructor of a SampleHandlerFD object - this will be used for all oscillation channels");
185 if(
Oscillator->isEqualBinningPerOscChannel() !=
true) {
186 MACH3LOG_ERROR(
"Trying to run shared NuOscillator without EqualBinningPerOscChannel, this will not work");
190 if(OscParams.size() !=
Oscillator->GetOscParamsSize()){
191 MACH3LOG_ERROR(
"SampleHandler {} has {} osc params, while shared NuOsc has {} osc params",
GetName(),
192 OscParams.size(),
Oscillator->GetOscParamsSize());
193 MACH3LOG_ERROR(
"This indicate misconfiguration in your Osc yaml");
201 MACH3LOG_WARN(
"Didn't find any oscillation params, thus will not enable oscillations");
205 MACH3LOG_ERROR(
"Either remove 'NuOsc' field from SampleHandler config or check your model.yaml and include oscillation for sample");
222 MACH3LOG_INFO(
"Finished loading MC for {}, it took {:.2f}s to finish",
GetName(), clock.RealTime());
223 MACH3LOG_INFO(
"=======================================================");
230 MACH3LOG_ERROR(
"Map KinematicParameters or ReversedKinematicParameters hasn't been initialised");
235 const auto& key = pair.first;
236 const auto& value = pair.second;
246 std::vector<std::string> Vars = {
"Mode",
"OscillationChannel"};
247 for(
size_t iVar = 0; iVar < Vars.size(); iVar++) {
251 MACH3LOG_ERROR(
"MaCh3 expected variable: {} not found in KinematicParameters.", Vars[iVar]);
261 #pragma GCC diagnostic push
262 #pragma GCC diagnostic ignored "-Wconversion"
266 int Dimension =
GetNDim(Sample);
271 for (
int xBin = 0; xBin <
Binning->GetNAxisBins(Sample, 0); ++xBin) {
272 const int idx =
Binning->GetGlobalBinSafe(Sample, {xBin});
273 Hist->SetBinContent(xBin + 1, Array[idx]);
275 }
else if (Dimension == 2) {
277 if(
Binning->IsUniform(Sample)) {
278 for (
int yBin = 0; yBin <
Binning->GetNAxisBins(Sample, 1); ++yBin) {
279 for (
int xBin = 0; xBin <
Binning->GetNAxisBins(Sample, 0); ++xBin) {
280 const int idx =
Binning->GetGlobalBinSafe(Sample, {xBin, yBin});
281 Hist->SetBinContent(xBin + 1, yBin + 1, Array[idx]);
285 for (
int iBin = 0; iBin <
Binning->GetNBins(Sample); ++iBin) {
286 const int idx = iBin +
Binning->GetSampleStartBin(Sample);
288 Hist->SetBinContent(iBin + 1, Array[idx]);
292 for (
int iBin = 0; iBin <
Binning->GetNBins(Sample); ++iBin) {
293 const int idx = iBin +
Binning->GetSampleStartBin(Sample);
295 Hist->SetBinContent(iBin + 1, Array[idx]);
299 #pragma GCC diagnostic pop
305 const auto& SampleSelection = Selection[iSample];
306 const int SelectionSize =
static_cast<int>(SampleSelection.size());
307 for (
int iSelection = 0; iSelection < SelectionSize; ++iSelection) {
308 const auto& Cut = SampleSelection[iSelection];
309 const double Val = ReturnKinematicParameter(Cut.ParamToCutOnIt, iEvent);
310 if ((Val < Cut.LowerBound) || (Val >= Cut.UpperBound)) {
320 for (
unsigned int iSelection=0;iSelection < SubEventCuts.size() ;iSelection++) {
322 if (nsubevents != Vec.size()) {
323 MACH3LOG_ERROR(
"Cannot apply kinematic cut on {} as it is of different size to plotting variable");
326 const double Val = Vec[iSubEvent];
327 if ((Val < SubEventCuts[iSelection].LowerBound) || (Val >= SubEventCuts[iSelection].UpperBound)) {
379 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
392 if (totalweight <= 0.){
397 const int GlobalBin =
Binning->FindGlobalBin(MCEvent->NominalSample, MCEvent->KinVar, MCEvent->NomBin);
408 #pragma GCC diagnostic push
409 #pragma GCC diagnostic ignored "-Walloca"
412 void SampleHandlerFD::FillArray_MP() {
431 const auto TotalBins =
Binning->GetNBins();
432 const unsigned int NumberOfEvents =
GetNEvents();
433 #pragma omp parallel for reduction(+:SampleHandlerFD_array[:TotalBins], SampleHandlerFD_array_w2[:TotalBins])
434 for (
unsigned int iEvent = 0; iEvent < NumberOfEvents; ++iEvent) {
450 if (totalweight <= 0.){
455 const int GlobalBin =
Binning->FindGlobalBin(MCEvent->NominalSample, MCEvent->KinVar, MCEvent->NomBin);
467 #pragma GCC diagnostic pop
490 MACH3LOG_ERROR(
"Functional parameter {} already in funcParsNamesVec", fpName);
494 MACH3LOG_ERROR(
"Functional parameter enum {} already registered in funcParsFuncMap", fpEnum);
517 MACH3LOG_ERROR(
"Functional parameter {} not found, did you define it in RegisterFunctionalParameters()?", fp.name);
520 const std::size_t key =
static_cast<std::size_t
>(it->second);
521 MACH3LOG_INFO(
"Adding functional parameter: {} to funcParsMap with key: {}",fp.name, key);
523 const int ikey = it->second;
532 for (std::size_t iEvent = 0; iEvent < static_cast<std::size_t>(
GetNEvents()); ++iEvent) {
534 for (std::vector<FunctionalParameter>::iterator it =
funcParsVec.begin(); it !=
funcParsVec.end(); ++it) {
545 MACH3LOG_TRACE(
"Event {}, missed Kinematic var check for dial {}", iEvent, (*it).name);
548 const std::size_t key =
static_cast<std::size_t
>(
funcParsNamesMap[it->name]);
565 const auto nShifts = shifts.size();
575 for (std::size_t iShift = 0; iShift < nShifts; ++iShift) {
577 (*fp->funcPtr)(fp->valuePtr, iEvent);
586 const int nNorms =
static_cast<int>(MCEvent->norm_pointers.size());
589 #pragma omp simd reduction(*:TotalWeight)
591 for (
int iParam = 0; iParam < nNorms; ++iParam)
593 #pragma GCC diagnostic push
594 #pragma GCC diagnostic ignored "-Wuseless-cast"
595 TotalWeight *=
static_cast<M3::float_t>(*(MCEvent->norm_pointers[iParam]));
596 #pragma GCC diagnostic pop
599 const int TotalWeights =
static_cast<int>(MCEvent->total_weight_pointers.size());
602 #pragma omp simd reduction(*:TotalWeight)
604 for (
int iWeight = 0; iWeight < TotalWeights; ++iWeight) {
605 TotalWeight *= *(MCEvent->total_weight_pointers[iWeight]);
615 std::vector< std::vector< int > > norms_bins(
GetNEvents());
629 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); ++iEvent) {
632 MCSamples[iEvent].norm_pointers.resize(norms_bins[iEvent].size());
633 for(
auto const & norm_bin: norms_bins[iEvent]) {
645 std::vector<int> VerboseCounter(norm_parameters.size(), 0);
647 for(
unsigned int iEvent = 0; iEvent <
GetNEvents(); ++iEvent){
648 std::vector< int > NormBins = {};
658 for (std::vector<NormParameter>::iterator it = norm_parameters.begin(); it != norm_parameters.end(); ++it) {
662 MACH3LOG_TRACE(
"Event {}, missed target check ({}) for dial {}", iEvent, *(
MCSamples[iEvent].Target), (*it).name);
675 if (!FlavourUnoscMatch){
676 MACH3LOG_TRACE(
"Event {}, missed FlavourUnosc check ({}) for dial {}", iEvent,(*
MCSamples[iEvent].nupdgUnosc), (*it).name);
693 MACH3LOG_TRACE(
"Event {}, missed Kinematic var check for dial {}", iEvent, (*it).name);
698 int bin = (*it).index;
700 NormBins.push_back(bin);
701 MACH3LOG_TRACE(
"Event {}, will be affected by dial {}", iEvent, (*it).name);
703 VerboseCounter[std::distance(norm_parameters.begin(), it)]++;
708 norms_bins[iEvent] = NormBins;
711 MACH3LOG_DEBUG(
"┌──────────────────────────────────────────────────────────┐");
712 for (std::size_t i = 0; i < norm_parameters.size(); ++i) {
713 const auto& norm = norm_parameters[i];
714 double eventRatio =
static_cast<double>(VerboseCounter[i]) /
static_cast<double>(
GetNEvents());
716 MACH3LOG_DEBUG(
"│ Param {:<15}, affects {:<8} events ({:>6.2f}%) │",
719 MACH3LOG_DEBUG(
"└──────────────────────────────────────────────────────────┘");
730 for (
int i = 0; i <
Binning->GetNBins(); ++i) {
740 for(
int iSample = 0; iSample <
GetNsamples(); iSample++)
742 int Dimension =
GetNDim(iSample);
747 auto XVec =
Binning->GetBinEdges(iSample, 0);
748 SamDet->DataHist =
new TH1D((
"d" + HistTitle).c_str(), HistTitle.c_str(),
static_cast<int>(XVec.size()-1), XVec.data());
749 SamDet->MCHist =
new TH1D((
"h" + HistTitle).c_str(), HistTitle.c_str(),
static_cast<int>(XVec.size()-1), XVec.data());
750 SamDet->W2Hist =
new TH1D((
"w" + HistTitle).c_str(), HistTitle.c_str(),
static_cast<int>(XVec.size()-1), XVec.data());
753 SamDet->DataHist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
754 SamDet->DataHist->GetYaxis()->SetTitle(
"Events");
755 SamDet->MCHist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
756 SamDet->MCHist->GetYaxis()->SetTitle(
"Events");
757 SamDet->W2Hist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
758 SamDet->W2Hist->GetYaxis()->SetTitle(
"Events");
759 }
else if (Dimension == 2){
760 if(
Binning->IsUniform(iSample)) {
761 auto XVec =
Binning->GetBinEdges(iSample, 0);
762 auto YVec =
Binning->GetBinEdges(iSample, 1);
763 int nX =
static_cast<int>(XVec.size() - 1);
764 int nY =
static_cast<int>(YVec.size() - 1);
766 SamDet->DataHist =
new TH2D((
"d" + HistTitle).c_str(), HistTitle.c_str(), nX, XVec.data(), nY, YVec.data());
767 SamDet->MCHist =
new TH2D((
"h" + HistTitle).c_str(), HistTitle.c_str(), nX, XVec.data(), nY, YVec.data());
768 SamDet->W2Hist =
new TH2D((
"w" + HistTitle).c_str(), HistTitle.c_str(), nX, XVec.data(), nY, YVec.data());
770 auto AddBinsToTH2Poly = [](TH2Poly* hist,
const std::vector<BinInfo>& bins) {
771 for (
const auto& bin : bins) {
772 double xLow = bin.Extent[0][0];
773 double xHigh = bin.Extent[0][1];
774 double yLow = bin.Extent[1][0];
775 double yHigh = bin.Extent[1][1];
777 double x[4] = {xLow, xHigh, xHigh, xLow};
778 double y[4] = {yLow, yLow, yHigh, yHigh};
780 hist->AddBin(4, x, y);
784 SamDet->DataHist =
new TH2Poly();
785 SamDet->DataHist->SetName((
"d" + HistTitle).c_str());
786 SamDet->DataHist->SetTitle(HistTitle.c_str());
788 SamDet->MCHist =
new TH2Poly();
789 SamDet->MCHist->SetName((
"h" + HistTitle).c_str());
790 SamDet->MCHist->SetTitle(HistTitle.c_str());
792 SamDet->W2Hist =
new TH2Poly();
793 SamDet->W2Hist->SetName((
"w" + HistTitle).c_str());
794 SamDet->W2Hist->SetTitle(HistTitle.c_str());
797 AddBinsToTH2Poly(
static_cast<TH2Poly*
>(SamDet->DataHist),
Binning->GetNonUniformBins(iSample));
798 AddBinsToTH2Poly(
static_cast<TH2Poly*
>(SamDet->MCHist),
Binning->GetNonUniformBins(iSample));
799 AddBinsToTH2Poly(
static_cast<TH2Poly*
>(SamDet->W2Hist),
Binning->GetNonUniformBins(iSample));
803 SamDet->DataHist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
804 SamDet->DataHist->GetYaxis()->SetTitle(SamDet->VarStr[1].c_str());
805 SamDet->MCHist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
806 SamDet->MCHist->GetYaxis()->SetTitle(SamDet->VarStr[1].c_str());
807 SamDet->W2Hist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
808 SamDet->W2Hist->GetYaxis()->SetTitle(SamDet->VarStr[1].c_str());
810 int nbins =
Binning->GetNBins(iSample);
811 SamDet->DataHist =
new TH1D((
"d" + HistTitle).c_str(), HistTitle.c_str(), nbins, 0, nbins);
812 SamDet->MCHist =
new TH1D((
"h" + HistTitle).c_str(), HistTitle.c_str(), nbins, 0, nbins);
813 SamDet->W2Hist =
new TH1D((
"w" + HistTitle).c_str(), HistTitle.c_str(), nbins, 0, nbins);
815 for(
int iBin = 0; iBin < nbins; iBin++) {
816 auto BinName =
Binning->GetBinName(iSample, iBin);
817 SamDet->DataHist->GetXaxis()->SetBinLabel(iBin+1, BinName.c_str());
818 SamDet->MCHist->GetXaxis()->SetBinLabel(iBin+1, BinName.c_str());
819 SamDet->W2Hist->GetXaxis()->SetBinLabel(iBin+1, BinName.c_str());
823 SamDet->DataHist->GetYaxis()->SetTitle(
"Events");
824 SamDet->MCHist->GetYaxis()->SetTitle(
"Events");
825 SamDet->W2Hist->GetYaxis()->SetTitle(
"Events");
828 SamDet->DataHist->SetDirectory(
nullptr);
829 SamDet->MCHist->SetDirectory(
nullptr);
830 SamDet->W2Hist->SetDirectory(
nullptr);
841 for (
unsigned int event_i = 0; event_i <
GetNEvents(); event_i++) {
842 int Sample =
MCSamples[event_i].NominalSample;
843 const int dim =
GetNDim(Sample);
847 auto SetNominalBin = [&](
int bin,
int max_bins,
int& out_bin) {
848 if (bin >= 0 && bin < max_bins) {
856 for(
int iDim = 0; iDim < dim; iDim++) {
858 if (std::isnan(*
MCSamples[event_i].KinVar[iDim]) || std::isinf(*
MCSamples[event_i].KinVar[iDim])) {
859 MACH3LOG_ERROR(
"Variable {} for sample {} and dimension {} is ill-defined and equal to {}",
863 const int bin =
Binning->FindNominalBin(Sample, iDim, *
MCSamples[event_i].KinVar[iDim]);
864 int NBins_i =
static_cast<int>(
Binning->GetBinEdges(Sample, iDim).size() - 1);
865 SetNominalBin(bin, NBins_i,
MCSamples[event_i].NomBin[iDim]);
937 MACH3LOG_INFO(
"Adding {}D data histogram: {} with {:.2f} events", Dim, Data->GetTitle(), Data->Integral());
940 SampleDetails[Sample].DataHist =
static_cast<TH1*
>(Data->Clone());
943 MACH3LOG_ERROR(
"SampleHandlerFD_data haven't been initialised yet");
947 auto ChecHistType = [&](
const std::string& Type,
const int Dimen,
const TH1* Hist,
948 const std::string& file,
const int line) {
949 if (std::string(Hist->ClassName()) != Type) {
950 MACH3LOG_ERROR(
"Expected {} for {}D sample, got {}", Type, Dimen, Hist->ClassName());
957 ChecHistType(
"TH1D", Dim,
SampleDetails[Sample].DataHist, __FILE__, __LINE__);
958 for (
int xBin = 0; xBin <
Binning->GetNAxisBins(Sample, 0); ++xBin) {
959 const int idx =
Binning->GetGlobalBinSafe(Sample, {xBin});
964 SampleDetails[Sample].DataHist->GetYaxis()->SetTitle(
"Number of Events");
965 }
else if (Dim == 2) {
966 if(
Binning->IsUniform(Sample)) {
967 ChecHistType(
"TH2D", Dim,
SampleDetails[Sample].DataHist, __FILE__, __LINE__);
968 for (
int yBin = 0; yBin <
Binning->GetNAxisBins(Sample, 1); ++yBin) {
969 for (
int xBin = 0; xBin <
Binning->GetNAxisBins(Sample, 0); ++xBin) {
970 const int idx =
Binning->GetGlobalBinSafe(Sample, {xBin, yBin});
976 ChecHistType(
"TH2Poly", Dim,
SampleDetails[Sample].DataHist, __FILE__, __LINE__);
977 for (
int iBin = 0; iBin <
Binning->GetNBins(Sample); ++iBin) {
978 const int idx = iBin +
Binning->GetSampleStartBin(Sample);
986 SampleDetails[Sample].DataHist->GetZaxis()->SetTitle(
"Number of Events");
988 ChecHistType(
"TH1D", Dim,
SampleDetails[Sample].DataHist, __FILE__, __LINE__);
989 for (
int iBin = 0; iBin <
Binning->GetNBins(Sample); ++iBin) {
990 const int idx = iBin +
Binning->GetSampleStartBin(Sample);
1000 const int Start =
Binning->GetSampleStartBin(Sample);
1001 const int End =
Binning->GetSampleEndBin(Sample);
1002 const int ExpectedSize = End - Start;
1004 if (
static_cast<int>(Data_Array.size()) != ExpectedSize) {
1006 MACH3LOG_ERROR(
"Expected size: {}, received size: {}.", ExpectedSize, Data_Array.size());
1008 MACH3LOG_ERROR(
"This likely indicates a binning or sample slicing bug.");
1012 for (
int idx = Start; idx < End; ++idx) {
1022 auto NuOscillatorConfigFile = Get<std::string>(
SampleManager->raw()[
"NuOsc"][
"NuOscConfigFile"], __FILE__ , __LINE__);
1023 auto EqualBinningPerOscChannel = Get<bool>(
SampleManager->raw()[
"NuOsc"][
"EqualBinningPerOscChannel"], __FILE__ , __LINE__);
1026 if (EqualBinningPerOscChannel) {
1027 if (YAML::LoadFile(NuOscillatorConfigFile)[
"General"][
"CalculationType"].as<std::string>() ==
"Unbinned") {
1028 MACH3LOG_WARN(
"Tried using EqualBinningPerOscChannel while using Unbinned oscillation calculation, changing EqualBinningPerOscChannel to false");
1029 EqualBinningPerOscChannel =
false;
1033 if (OscParams.empty()) {
1035 MACH3LOG_ERROR(
"This likely indicates an error in your oscillation YAML configuration.");
1038 Oscillator = std::make_shared<OscillationHandler>(NuOscillatorConfigFile, EqualBinningPerOscChannel, OscParams,
GetNOscChannels(0));
1040 if(!EqualBinningPerOscChannel) {
1042 for(
int iSample = 1; iSample <
GetNsamples(); iSample++) {
1045 for(
int iSample = 0; iSample <
GetNsamples(); iSample++) {
1046 for(
int iChannel = 0; iChannel <
GetNOscChannels(iSample); iChannel++) {
1047 std::vector<M3::float_t> EnergyArray;
1048 std::vector<M3::float_t> CosineZArray;
1050 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1051 if(
MCSamples[iEvent].NominalSample != iSample)
continue;
1055 if (!
MCSamples[iEvent].isNC && Channel == iChannel) {
1059 std::sort(EnergyArray.begin(),EnergyArray.end());
1064 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1065 if(
MCSamples[iEvent].NominalSample != iSample)
continue;
1069 if (!
MCSamples[iEvent].isNC && Channel == iChannel) {
1073 std::sort(CosineZArray.begin(),CosineZArray.end());
1075 Oscillator->SetOscillatorBinning(iSample, iChannel, EnergyArray, CosineZArray);
1082 auto AddOscPointer = GetFromManager<bool>(
SampleManager->raw()[
"NuOsc"][
"AddOscPointer"],
true, __FILE__ , __LINE__);
1084 if(!AddOscPointer) {
1087 for (
unsigned int iEvent=0;iEvent<
GetNEvents();iEvent++) {
1092 MCSamples[iEvent].total_weight_pointers.push_back(osc_w_pointer);
1115 MACH3LOG_ERROR(
"Something has gone wrong in the mapping between MCSamples.nutype and the enum used within NuOscillator");
1122 const int Sample =
MCSamples[iEvent].NominalSample;
1128 osc_w_pointer =
Oscillator->GetNuOscillatorPointers(Sample, OscIndex, InitFlav, FinalFlav, FLOAT_T(*(
MCSamples[iEvent].rw_etru)), FLOAT_T(*(
MCSamples[iEvent].rw_truecz)));
1131 osc_w_pointer =
Oscillator->GetNuOscillatorPointers(Sample, OscIndex, InitFlav, FinalFlav, FLOAT_T(*(
MCSamples[iEvent].rw_etru)));
1134 return osc_w_pointer;
1162 if (totalweight <= 0.){
1173 bool ThrowCrititcal =
true;
1174 for (
unsigned int j = 0; j <
GetNEvents(); ++j) {
1175 const int SampleIndex =
MCSamples[j].NominalSample;
1178 const int Mode = int(*(
MCSamples[j].mode));
1179 const double Etrue = *(
MCSamples[j].rw_etru);
1180 std::vector< std::vector<int> > EventSplines;
1181 switch(
GetNDim(SampleIndex)) {
1183 EventSplines = BinnedSpline->GetEventSplines(SampleTitle, OscIndex, Mode, Etrue, *(
MCSamples[j].KinVar[0]), 0.);
1186 EventSplines = BinnedSpline->GetEventSplines(SampleTitle, OscIndex, Mode, Etrue, *(
MCSamples[j].KinVar[0]), *(
MCSamples[j].KinVar[1]));
1189 if(ThrowCrititcal) {
1192 ThrowCrititcal =
false;
1194 EventSplines = BinnedSpline->GetEventSplines(SampleTitle, OscIndex, Mode, Etrue, *(
MCSamples[j].KinVar[0]), *(
MCSamples[j].KinVar[1]));
1197 const int NSplines =
static_cast<int>(EventSplines.size());
1198 if(NSplines == 0)
continue;
1199 const int PointersBefore =
static_cast<int>(
MCSamples[j].total_weight_pointers.size());
1200 MCSamples[j].total_weight_pointers.resize(PointersBefore + NSplines);
1202 for(
int spline = 0; spline < NSplines; spline++) {
1204 MCSamples[j].total_weight_pointers[PointersBefore+spline] = BinnedSpline->retPointer(EventSplines[spline][0], EventSplines[spline][1],
1205 EventSplines[spline][2], EventSplines[spline][3],
1206 EventSplines[spline][4], EventSplines[spline][5],
1207 EventSplines[spline][6]);
1212 #ifdef _LOW_MEMORY_STRUCTS_
1213 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); ++iEvent) {
1214 MCSamples[iEvent].total_weight_pointers.push_back(UnbinnedSpline->retPointer(iEvent));
1217 (void) UnbinnedSpline;
1230 const int Start =
Binning->GetSampleStartBin(isample);
1231 const int End =
Binning->GetSampleEndBin(isample);
1233 double negLogL = 0.;
1235 #pragma omp parallel for reduction(+:negLogL)
1237 for (
int idx = Start; idx < End; ++idx)
1252 double negLogL = 0.;
1254 #pragma omp parallel for reduction(+:negLogL)
1256 for (
int idx = 0; idx <
Binning->GetNBins(); ++idx)
1277 for(
int iSample = 0; iSample <
GetNsamples(); iSample++)
1279 std::unique_ptr<TH1> data_hist;
1283 data_hist->GetXaxis()->SetTitle(
GetXBinVarName(iSample).c_str());
1284 data_hist->GetYaxis()->SetTitle(
"Number of Events");
1285 }
else if (
GetNDim(iSample) == 2) {
1286 if(
Binning->IsUniform(iSample)) {
1291 data_hist->GetXaxis()->SetTitle(
GetXBinVarName(iSample).c_str());
1292 data_hist->GetYaxis()->SetTitle(
GetYBinVarName(iSample).c_str());
1293 data_hist->GetZaxis()->SetTitle(
"Number of Events");
1296 int nbins =
Binning->GetNBins(iSample);
1297 for(
int iBin = 0; iBin < nbins; iBin++) {
1298 auto BinName =
Binning->GetBinName(iSample, iBin);
1299 data_hist->GetXaxis()->SetBinLabel(iBin+1, BinName.c_str());
1301 data_hist->GetYaxis()->SetTitle(
"Number of Events");
1309 data_hist->SetTitle((
"data_" +
GetSampleTitle(iSample)).c_str());
1316 bool LoadSplineFile = GetFromManager<bool>(
SampleManager->raw()[
"InputFiles"][
"LoadSplineFile"],
false, __FILE__, __LINE__);
1317 bool PrepSplineFile = GetFromManager<bool>(
SampleManager->raw()[
"InputFiles"][
"PrepSplineFile"],
false, __FILE__, __LINE__);
1318 auto SplineFileName = GetFromManager<std::string>(
SampleManager->raw()[
"InputFiles"][
"SplineFileName"],
1320 if(!LoadSplineFile) {
1321 for(
int iSample = 0; iSample <
GetNsamples(); iSample++) {
1322 std::vector<std::string> spline_filepaths =
SampleDetails[iSample].spline_files;
1325 std::vector<std::string> SplineVarNames = {
"TrueNeutrinoEnergy"};
1328 }
else if (
GetNDim(iSample) == 2) {
1338 BinnedSplines->CountNumberOfLoadedSplines(
false, 1);
1339 BinnedSplines->TransferToMonolith();
1340 if(PrepSplineFile) BinnedSplines->PrepareSplineFile(SplineFileName);
1343 BinnedSplines->LoadSplineFile(SplineFileName);
1350 BinnedSplines->cleanUpMemory();
1352 (void) UnbinnedSpline;
1363 const std::vector<KinematicCut>& ExtraCuts) {
1372 for (
const auto& cut : ExtraCuts) {
1373 selectionToApply[iSample].emplace_back(cut);
1377 Selection = std::move(selectionToApply);
1379 return originalSelection;
1385 int WeightStyle, TAxis* Axis,
const std::vector< KinematicCut >& SubEventSelectionVec) {
1392 TH1D* _h1DVar =
nullptr;;
1394 _h1DVar =
new TH1D(
"",
"",Axis->GetNbins(),Axis->GetXbins()->GetArray());
1397 _h1DVar =
new TH1D(
"",
"",
int(xBinEdges.size())-1, xBinEdges.data());
1399 _h1DVar->GetXaxis()->SetTitle(ProjectionVar_Str.c_str());
1402 Fill1DSubEventHist(iSample, _h1DVar, ProjectionVar_Str, SubEventSelectionVec, WeightStyle);
1408 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1409 const int EventSample =
MCSamples[iEvent].NominalSample;
1410 if(EventSample != iSample)
continue;
1413 if (WeightStyle == 1) {
1417 _h1DVar->Fill(Var, Weight);
1429 const std::vector< KinematicCut >& SubEventSelectionVec,
int WeightStyle) {
1434 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1435 const int EventSample =
MCSamples[iEvent].NominalSample;
1436 if(EventSample != iSample)
continue;
1439 if (WeightStyle == 1) {
1443 size_t nsubevents = Vec.size();
1445 for (
unsigned int iSubEvent = 0; iSubEvent < nsubevents; iSubEvent++) {
1447 double Var = Vec[iSubEvent];
1448 _h1DVar->Fill(Var,Weight);
1457 const std::string& ProjectionVar_StrX,
1458 const std::string& ProjectionVar_StrY,
1459 const std::vector< KinematicCut >& EventSelectionVec,
1460 int WeightStyle, TAxis* AxisX, TAxis* AxisY,
1461 const std::vector< KinematicCut >& SubEventSelectionVec) {
1468 TH2D* _h2DVar =
nullptr;
1469 if (AxisX && AxisY) {
1470 _h2DVar =
new TH2D(
"",
"",AxisX->GetNbins(),AxisX->GetXbins()->GetArray(),AxisY->GetNbins(),AxisY->GetXbins()->GetArray());
1474 _h2DVar =
new TH2D(
"",
"",
int(xBinEdges.size())-1, xBinEdges.data(),
int(yBinEdges.size())-1, yBinEdges.data());
1476 _h2DVar->GetXaxis()->SetTitle(ProjectionVar_StrX.c_str());
1477 _h2DVar->GetYaxis()->SetTitle(ProjectionVar_StrY.c_str());
1480 if (IsSubEventHist)
Fill2DSubEventHist(iSample, _h2DVar, ProjectionVar_StrX, ProjectionVar_StrY, SubEventSelectionVec, WeightStyle);
1487 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1488 const int EventSample =
MCSamples[iEvent].NominalSample;
1489 if(EventSample != iSample)
continue;
1492 if (WeightStyle == 1) {
1497 _h2DVar->Fill(VarX,VarY,Weight);
1509 const std::string& ProjectionVar_StrX,
1510 const std::string& ProjectionVar_StrY,
1511 const std::vector< KinematicCut >& SubEventSelectionVec,
1518 int ProjectionVar_IntX, ProjectionVar_IntY;
1525 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1526 const int EventSample =
MCSamples[iEvent].NominalSample;
1527 if(EventSample != iSample)
continue;
1530 if (WeightStyle == 1) {
1533 std::vector<double> VecX = {}, VecY = {};
1535 size_t nsubevents = 0;
1537 if (IsSubEventVarX && !IsSubEventVarY) {
1540 nsubevents = VecX.size();
1542 else if (!IsSubEventVarX && IsSubEventVarY) {
1545 nsubevents = VecY.size();
1550 if (VecX.size() != VecY.size()) {
1551 MACH3LOG_ERROR(
"Cannot plot {} of size {} against {} of size {}", ProjectionVar_StrX, VecX.size(), ProjectionVar_StrY, VecY.size());
1554 nsubevents = VecX.size();
1557 for (
unsigned int iSubEvent = 0; iSubEvent < nsubevents; iSubEvent++) {
1559 if (IsSubEventVarX) VarX = VecX[iSubEvent];
1560 if (IsSubEventVarY) VarY = VecY[iSubEvent];
1561 _h2DVar->Fill(VarX,VarY,Weight);
1574 MACH3LOG_ERROR(
"Did not recognise Kinematic Parameter type: {}", KinematicParameterStr);
1588 MACH3LOG_ERROR(
"Did not recognise Kinematic Parameter type: {}", KinematicParameter);
1601 MACH3LOG_ERROR(
"Did not recognise Kinematic Vector: {}", KinematicVectorStr);
1615 MACH3LOG_ERROR(
"Did not recognise Kinematic Vector: {}", KinematicVector);
1626 if(
Binning->IsUniform(Sample)) {
1627 for(
int iDim = 0; iDim <
GetNDim(Sample); iDim++) {
1629 return Binning->GetBinEdges(Sample, iDim);
1634 auto MakeBins = [](
int nBins) {
1635 std::vector<double> bins(
nBins + 1);
1636 for (
int i = 0; i <=
nBins; ++i)
1637 bins[i] =
static_cast<double>(i) - 0.5;
1641 if (KinematicParameter ==
"OscillationChannel") {
1643 }
else if (KinematicParameter ==
"Mode") {
1644 return MakeBins(
Modes->GetNModes());
1648 std::vector<double> BinningVect;
1652 BinningVect = Get<std::vector<double>>(BinningConfig[
GetSampleTitle(Sample)][KinematicParameter], __FILE__, __LINE__);
1654 BinningVect = Get<std::vector<double>>(BinningConfig[KinematicParameter], __FILE__, __LINE__);
1658 auto IsIncreasing = [](
const std::vector<double>& vec) {
1659 for (
size_t i = 1; i < vec.size(); ++i) {
1660 if (vec[i] <= vec[i-1]) {
1667 if (!IsIncreasing(BinningVect)) {
1668 MACH3LOG_ERROR(
"Binning for {} is not increasing [{}]", KinematicParameter, fmt::join(BinningVect,
", "));
1682 MACH3LOG_ERROR(
"Attempted to plot kinematic variable {}, but it appears in both KinematicVectors and KinematicParameters", VarStr);
1696 if (kChannelToFill != -1) {
1708 if (kModeToFill != -1) {
1709 if (!(kModeToFill >= 0) && (kModeToFill < Modes->GetNModes())) {
1710 MACH3LOG_ERROR(
"Required mode is not available. kModeToFill should be between 0 and {}",
Modes->GetNModes());
1720 std::vector< KinematicCut > SelectionVec;
1727 SelectionVec.push_back(SelecMode);
1735 SelectionVec.push_back(SelecChannel);
1738 return SelectionVec;
1743 int kModeToFill,
int kChannelToFill,
int WeightStyle, TAxis* Axis) {
1746 return Get1DVarHist(iSample, ProjectionVar_Str, SelectionVec, WeightStyle, Axis);
1751 int kModeToFill,
int kChannelToFill,
int WeightStyle, TAxis* AxisX, TAxis* AxisY) {
1754 return Get2DVarHist(iSample, ProjectionVar_StrX, ProjectionVar_StrY, SelectionVec, WeightStyle, AxisX,AxisY);
1758 constexpr
int space = 14;
1760 bool printToFile=
false;
1761 if (OutputFileName.CompareTo(
"/dev/null")) {printToFile =
true;}
1763 bool printToCSV=
false;
1764 if(OutputCSVFileName.CompareTo(
"/dev/null")) printToCSV=
true;
1766 std::ofstream outfile;
1768 outfile.open(OutputFileName.Data(), std::ios_base::app);
1769 outfile.precision(7);
1772 std::ofstream outcsv;
1774 outcsv.open(OutputCSVFileName, std::ios_base::app);
1775 outcsv.precision(7);
1778 double PDFIntegral = 0.;
1780 std::vector< std::vector< TH1* > > IntegralList;
1781 IntegralList.resize(
Modes->GetNModes());
1783 std::vector<double> ChannelIntegral;
1785 for (
unsigned int i=0;i<ChannelIntegral.size();i++) {ChannelIntegral[i] = 0.;}
1787 for (
int i=0;i<
Modes->GetNModes();i++) {
1795 MACH3LOG_INFO(
"-------------------------------------------------");
1798 outfile <<
"\\begin{table}[ht]" << std::endl;
1799 outfile <<
"\\begin{center}" << std::endl;
1800 outfile <<
"\\caption{Integral breakdown for sample: " <<
GetSampleTitle(iSample) <<
"}" << std::endl;
1801 outfile <<
"\\label{" <<
GetSampleTitle(iSample) <<
"-EventRate}" << std::endl;
1806 outfile <<
"\\begin{tabular}{|l" << nColumns.Data() <<
"}" << std::endl;
1807 outfile <<
"\\hline" << std::endl;
1812 outcsv<<
"Integral Breakdown for sample :"<<
GetSampleTitle(iSample)<<
"\n";
1818 if (printToFile) {outfile << std::setw(space) <<
"Mode:";}
1819 if(printToCSV) {outcsv<<
"Mode,";}
1821 std::string table_headings = fmt::format(
"| {:<8} |",
"Mode");
1822 std::string table_footline =
"------------";
1824 table_headings += fmt::format(
" {:<17} |",
GetFlavourName(iSample, i));
1825 table_footline +=
"--------------------";
1826 if (printToFile) {outfile <<
"&" << std::setw(space) <<
SampleDetails[iSample].OscChannels[i].flavourName_Latex <<
" ";}
1829 if (printToFile) {outfile <<
"&" << std::setw(space) <<
"Total:" <<
"\\\\ \\hline" << std::endl;}
1830 if (printToCSV) {outcsv <<
"Total\n";}
1831 table_headings += fmt::format(
" {:<10} |",
"Total");
1832 table_footline +=
"-------------";
1837 for (
unsigned int i=0;i<IntegralList.size();i++) {
1838 double ModeIntegral = 0;
1839 if (printToFile) {outfile << std::setw(space) <<
Modes->GetMaCh3ModeName(i);}
1840 if(printToCSV) {outcsv <<
Modes->GetMaCh3ModeName(i) <<
",";}
1842 table_headings = fmt::format(
"| {:<8} |",
Modes->GetMaCh3ModeName(i));
1844 for (
unsigned int j=0;j<IntegralList[i].size();j++) {
1845 double Integral = IntegralList[i][j]->Integral();
1847 if (Integral < 1e-100) {Integral=0;}
1849 ModeIntegral += Integral;
1850 ChannelIntegral[j] += Integral;
1851 PDFIntegral += Integral;
1853 if (printToFile) {outfile <<
"&" << std::setw(space) << Form(
"%4.5f",Integral) <<
" ";}
1854 if (printToCSV) {outcsv << Form(
"%4.5f", Integral) <<
",";}
1856 table_headings += fmt::format(
" {:<17.4f} |", Integral);
1858 if (printToFile) {outfile <<
"&" << std::setw(space) << Form(
"%4.5f",ModeIntegral) <<
" \\\\ \\hline" << std::endl;}
1859 if (printToCSV) {outcsv << Form(
"%4.5f", ModeIntegral) <<
"\n";}
1861 table_headings += fmt::format(
" {:<10.4f} |", ModeIntegral);
1866 if (printToFile) {outfile << std::setw(space) <<
"Total:";}
1867 if (printToCSV) {outcsv <<
"Total,";}
1870 table_headings = fmt::format(
"| {:<8} |",
"Total");
1871 for (
unsigned int i=0;i<ChannelIntegral.size();i++) {
1872 if (printToFile) {outfile <<
"&" << std::setw(space) << Form(
"%4.5f",ChannelIntegral[i]) <<
" ";}
1873 if (printToCSV) {outcsv << Form(
"%4.5f", ChannelIntegral[i]) <<
",";}
1874 table_headings += fmt::format(
" {:<17.4f} |", ChannelIntegral[i]);
1876 if (printToFile) {outfile <<
"&" << std::setw(space) << Form(
"%4.5f",PDFIntegral) <<
" \\\\ \\hline" << std::endl;}
1877 if (printToCSV) {outcsv << Form(
"%4.5f", PDFIntegral) <<
"\n\n\n\n";}
1879 table_headings += fmt::format(
" {:<10.4f} |", PDFIntegral);
1884 outfile <<
"\\end{tabular}" << std::endl;
1885 outfile <<
"\\end{center}" << std::endl;
1886 outfile <<
"\\end{table}" << std::endl;
1892 outfile << std::endl;
1901 int Selection1,
int Selection2,
int WeightStyle, TAxis* XAxis) {
1903 std::vector<TH1*> hHistList;
1904 std::string legendEntry;
1910 if (Selection1 == FDPlotType::kModePlot) {
1911 iMax =
Modes->GetNModes();
1913 if (Selection1 == FDPlotType::kOscChannelPlot) {
1917 MACH3LOG_ERROR(
"You've passed me a Selection1 which was not implemented in ReturnHistsBySelection1D. Selection1 and Selection2 are counters for different indexable quantities");
1921 for (
int i=0;i<iMax;i++) {
1922 if (Selection1 == FDPlotType::kModePlot) {
1924 THStackLeg->AddEntry(hHistList[i],(
Modes->GetMaCh3ModeName(i)+Form(
" : (%4.2f)",hHistList[i]->Integral())).c_str(),
"f");
1926 hHistList[i]->SetFillColor(
static_cast<Color_t
>(
Modes->GetMaCh3ModePlotColor(i)));
1927 hHistList[i]->SetLineColor(
static_cast<Color_t
>(
Modes->GetMaCh3ModePlotColor(i)));
1929 if (Selection1 == FDPlotType::kOscChannelPlot) {
1931 THStackLeg->AddEntry(hHistList[i],(
GetFlavourName(iSample, i)+Form(
" | %4.2f",hHistList[i]->Integral())).c_str(),
"f");
1939 const std::string& KinematicProjectionY,
int Selection1,
1940 int Selection2,
int WeightStyle,
1941 TAxis* XAxis, TAxis* YAxis) {
1943 std::vector<TH2*> hHistList;
1946 if (Selection1 == FDPlotType::kModePlot) {
1947 iMax =
Modes->GetNModes();
1949 if (Selection1 == FDPlotType::kOscChannelPlot) {
1953 MACH3LOG_ERROR(
"You've passed me a Selection1 which was not implemented in ReturnHistsBySelection1D. Selection1 and Selection2 are counters for different indexable quantities");
1957 for (
int i=0;i<iMax;i++) {
1958 if (Selection1 == FDPlotType::kModePlot) {
1959 hHistList.push_back(
Get2DVarHistByModeAndChannel(iSample, KinematicProjectionX,KinematicProjectionY,i,Selection2,WeightStyle,XAxis,YAxis));
1961 if (Selection1 == FDPlotType::kOscChannelPlot) {
1962 hHistList.push_back(
Get2DVarHistByModeAndChannel(iSample, KinematicProjectionX,KinematicProjectionY,Selection2,i,WeightStyle,XAxis,YAxis));
1971 int Selection1,
int Selection2,
int WeightStyle, TAxis* XAxis) {
1973 std::vector<TH1*> HistList =
ReturnHistsBySelection1D(iSample, KinematicProjection, Selection1, Selection2, WeightStyle, XAxis);
1974 THStack* StackHist =
new THStack((
GetSampleTitle(iSample)+
"_"+KinematicProjection+
"_Stack").c_str(),
"");
1975 for (
unsigned int i=0;i<HistList.size();i++) {
1976 StackHist->Add(HistList[i]);
1988 return &(OscillationChannels[Channel].ChannelIndex);
2002 const std::string sep_full(71,
'-');
2004 MACH3LOG_INFO(
"{:<40}{:<10}{:<10}{:<10}|",
"Sample",
"Data",
"MC",
"-LLH");
2006 const std::string sep_data(51,
'-');
2011 double sumData = 0.0;
2013 double likelihood = 0.0;
2015 for (
int iSample = 0; iSample <
GetNsamples(); ++iSample) {
2018 double dataIntegral = std::accumulate(DataArray.begin(), DataArray.end(), 0.0);
2019 sumData += dataIntegral;
2021 std::vector<double> MCArray =
GetMCArray(iSample);
2022 double mcIntegral = std::accumulate(MCArray.begin(), MCArray.end(), 0.0);
2023 sumMC += mcIntegral;
2026 MACH3LOG_INFO(
"{:<40}{:<10.2f}{:<10.2f}{:<10.2f}|", name, dataIntegral, mcIntegral, likelihood);
2033 MACH3LOG_INFO(
"{:<40}{:<10.2f}{:<10.2f}{:<10.2f}|",
"Total", sumData, sumMC, likelihood);
2034 const std::string sep_full(71,
'-');
2038 const std::string sep_data(51,
'-');
2047 if(Dimension >
GetNDim(iSample)) {
2057 const int Start =
Binning->GetSampleStartBin(Sample);
2058 const int End =
Binning->GetSampleEndBin(Sample);
2060 return std::vector<double>(array + Start, array + End);
2064 template <
typename ParT>
2067 bool IsSelected =
true;
2068 if (Par.hasKinBounds) {
2069 const auto& kinVars = Par.KinematicVarStr;
2070 const auto& selection = Par.Selection;
2072 for (std::size_t iKinPar = 0; iKinPar < kinVars.size(); ++iKinPar) {
2075 bool passedAnyBound =
false;
2076 const auto& boundsList = selection[iKinPar];
2078 for (
const auto& bounds : boundsList) {
2079 if (kinVal > bounds[0] && kinVal <= bounds[1]) {
2080 passedAnyBound =
true;
2085 if (!passedAnyBound) {
2086 MACH3LOG_TRACE(
"Event {}, missed kinematic check ({}) for dial {}",
2087 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 CleanContainer(T &)
Base case: do nothing for non-pointer types.
std::function< void(const double *, std::size_t)> FuncParFuncType
HH - a shorthand type for funcpar functions.
void CleanVector(T &)
Base case: do nothing for non-vector types.
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.
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.
Custom exception class used throughout MaCh3.
const double * 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.
const std::vector< FunctionalParameter > GetFunctionalParametersFromSampleName(const std::string &SampleName) const
HH Get functional parameters for the relevant SampleName.
std::vector< const double * > GetOscParsFromSampleName(const std::string &SampleName)
Get pointers to Osc params from Sample name.
Even-by-event class calculating response for spline parameters. It is possible to use GPU acceleratio...
Class responsible for handling implementation of samples used in analysis, reweighting and returning ...
std::unique_ptr< MaCh3Modes > Modes
Holds information about used Generator and MaCh3 modes.
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....
unsigned int GetNEvents() const
TestStatistic fTestStatistic
Test statistic tells what kind of likelihood sample is using.
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()
bool MatchCondition(const std::vector< T > &allowedValues, const T &value)
check if event is affected by following conditions, for example pdg, or modes etc
std::vector< FunctionalParameter > funcParsVec
HH - a vector that stores all the FuncPars struct.
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...
virtual void Init()=0
Initialise any variables that your experiment specific SampleHandler needs.
std::vector< double > GetArrayForSample(const int Sample, const double *array) const
Return a sub-array for a given sample.
std::string ReturnStringFromKinematicVector(const int KinematicVariable) const
std::vector< SampleInfo > SampleDetails
Stores info about currently initialised sample.
std::unique_ptr< SplineBase > SplineHandler
Contains all your splines (binned or unbinned) and handles the setup and the returning of weights fro...
std::vector< FunctionalShifter > funcParsMap
HH - a map that relates the funcpar enum to pointer of FuncPars struct HH - Changed to a vector of po...
virtual void CalcWeightFunc(int iEvent)
Calculate weights for function parameters.
virtual void SetupSplines()=0
initialise your splineXX object and then use InitialiseSplineObject to conviently setup everything up
ParameterHandlerGeneric * ParHandler
ETA - All experiments will need an xsec, det and osc cov.
void SetSplinePointers()
Set pointers for each event to appropriate weights, for unbinned based on event number while for binn...
bool FirstTimeW2
KS:Super hacky to update W2 or not.
std::unique_ptr< BinningHandler > Binning
KS: This stores binning information, in future could be come vector to store binning for every used s...
std::unordered_map< std::string, NuPDG > FileToInitPDGMap
double GetLikelihood() const override
DB Multi-threaded GetLikelihood.
void InitialiseSplineObject()
double * SampleHandlerFD_data
DB Array to be filled in AddData.
std::vector< double > ReturnKinematicParameterBinning(const int Sample, const std::string &KinematicParameter) const override
Return the binning used to draw a kinematic parameter.
virtual int SetupExperimentMC()=0
Experiment specific setup, returns the number of events which were loaded.
const std::unordered_map< int, std::string > * ReversedKinematicVectors
void CalcNormsBins(std::vector< NormParameter > &norm_parameters, std::vector< std::vector< int > > &norms_bins)
Check whether a normalisation systematic affects an event or not.
virtual void ResetShifts(const int iEvent)
HH - reset the shifted values to the original values.
std::string ReturnStringFromKinematicParameter(const int KinematicVariable) const
ETA function to generically convert a kinematic type from xsec cov to a string.
void FindNominalBinAndEdges()
std::vector< std::vector< FunctionalShifter * > > funcParsGrid
HH - a grid of vectors of enums for each sample and event.
std::unique_ptr< Manager > SampleManager
The manager object used to read the sample yaml file.
std::vector< TH2 * > ReturnHistsBySelection2D(const int iSample, const std::string &KinematicProjectionX, const std::string &KinematicProjectionY, int Selection1, int Selection2=-1, int WeightStyle=0, TAxis *XAxis=nullptr, TAxis *YAxis=nullptr)
std::unordered_map< std::string, NuPDG > FileToFinalPDGMap
std::vector< double > GetDataArray() const
Return array storing data entries for every bin.
std::unordered_map< int, FuncParFuncType > funcParsFuncMap
HH - a map that relates the funcpar enum to pointer of the actual function.
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
void FillHist(const int Sample, TH1 *Hist, double *Array)
Fill a histogram with the event-level information used in the fit.
void LoadSingleSample(const int iSample, const YAML::Node &Settings)
void SetupNormParameters()
Setup the norm parameters by assigning each event with bin.
std::string GetName() const override
void SetupKinematicMap()
Ensure Kinematic Map is setup and make sure it is initialised correctly.
void PrintIntegral(const int iSample, const TString &OutputName="/dev/null", const int WeightStyle=0, const TString &OutputCSVName="/dev/null")
M3::float_t GetEventWeight(const int iEntry)
virtual void PrepFunctionalParameters()
Update the functional parameter values to the latest proposed values. Needs to be called before every...
std::string GetYBinVarName(const int Sample) const
SampleHandlerFD(std::string ConfigFileName, ParameterHandlerGeneric *xsec_cov, const std::shared_ptr< OscillationHandler > &OscillatorObj_=nullptr)
Constructor.
void Initialise()
Function which does a lot of the lifting regarding the workflow in creating different MC objects.
std::vector< double > GetMCArray() const
Return array storing MC entries for every bin.
int GetNDim(const int Sample) const override
DB Function to differentiate 1D or 2D binning.
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 ...
void AddData(const int Sample, TH1 *Data)
virtual ~SampleHandlerFD()
destructor
std::string GetKinVarName(const int iSample, const int Dimension) const override
Return Kinematic Variable name for specified sample and dimension for example "Reconstructed_Neutrino...
std::string GetFlavourName(const int iSample, const int iChannel) const override
double * SampleHandlerFD_array
DB Array to be filled after reweighting.
TH2 * Get2DVarHistByModeAndChannel(const int iSample, const std::string &ProjectionVar_StrX, const std::string &ProjectionVar_StrY, int kModeToFill=-1, int kChannelToFill=-1, int WeightStyle=0, TAxis *AxisX=nullptr, TAxis *AxisY=nullptr) override
std::vector< std::string > funcParsNamesVec
HH - a vector of string names for each functional parameter.
virtual const double * GetPointerToKinematicParameter(std::string KinematicParamter, int iEvent)=0
std::vector< KinematicCut > BuildModeChannelSelection(const int iSample, const int kModeToFill, const int kChannelToFill) const
virtual void SetupFDMC()=0
Function which translates experiment struct into core struct.
void SaveAdditionalInfo(TDirectory *Dir) override
Store additional info in a chan.
void Fill2DSubEventHist(const int iSample, TH2D *_h2DVar, const std::string &ProjectionVarX, const std::string &ProjectionVarY, const std::vector< KinematicCut > &SubEventSelectionVec={}, int WeightStyle=0)
TH1 * Get1DVarHist(const int iSample, const std::string &ProjectionVar, const std::vector< KinematicCut > &EventSelectionVec={}, int WeightStyle=0, TAxis *Axis=nullptr, const std::vector< KinematicCut > &SubEventSelectionVec={}) override
void PrintRates(const bool DataOnly=false) override
Helper function to print rates for the samples with LLH.
TH1 * GetW2Hist(const int Sample) override
Get W2 histogram.
std::string SampleHandlerName
A unique ID for each sample based on which we can define what systematic should be applied.
TH2 * Get2DVarHist(const int iSample, const std::string &ProjectionVarX, const std::string &ProjectionVarY, const std::vector< KinematicCut > &EventSelectionVec={}, int WeightStyle=0, TAxis *AxisX=nullptr, TAxis *AxisY=nullptr, const std::vector< KinematicCut > &SubEventSelectionVec={}) override
std::string GetXBinVarName(const int Sample) const
const M3::float_t * GetNuOscillatorPointers(const int iEvent) const
std::vector< TH1 * > ReturnHistsBySelection1D(const int iSample, const std::string &KinematicProjection, int Selection1, int Selection2=-1, int WeightStyle=0, TAxis *Axis=nullptr)
void InitialiseNuOscillatorObjects()
including Dan's magic NuOscillator
M3::float_t CalcWeightTotal(const EventInfo *_restrict_ MCEvent) const
Calculate the total weight weight for a given event.
void RegisterIndividualFunctionalParameter(const std::string &fpName, int fpEnum, FuncParFuncType fpFunc)
HH - a helper function for RegisterFunctionalParameter.
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...
void SetBinning()
set the binning for 2D sample used for the likelihood calculation
bool UpdateW2
KS:Super hacky to update W2 or not.
std::shared_ptr< OscillationHandler > Oscillator
Contains oscillator handling calculating oscillation probabilities.
double GetSampleLikelihood(const int isample) const override
Get likelihood for single sample.
int GetNOscChannels(const int iSample) const override
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.
const std::unordered_map< std::string, int > * KinematicParameters
Mapping between string and kinematic enum.
void Fill1DSubEventHist(const int iSample, TH1D *_h1DVar, const std::string &ProjectionVar, const std::vector< KinematicCut > &SubEventSelectionVec={}, int WeightStyle=0)
virtual void RegisterFunctionalParameters()=0
HH - a experiment-specific function where the maps to actual functions are set up.
bool PassesSelection(const ParT &Par, std::size_t iEvent)
void ResetHistograms()
Helper function to reset histograms.
TH1 * GetDataHist(const int Sample) override
Get Data histogram.
virtual double ReturnKinematicParameter(std::string KinematicParamter, int iEvent)=0
Return the value of an associated kinematic parameter for an event.
bool IsSubEventVarString(const std::string &VarStr)
JM Check if a kinematic parameter string corresponds to a subevent-level variable.
std::unordered_map< std::string, double > _modeNomWeightMap
const std::unordered_map< int, std::string > * ReversedKinematicParameters
Mapping between kinematic enum and string.
int ReturnKinematicVectorFromString(const std::string &KinematicStr) const
int GetSampleIndex(const std::string &SampleTitle) const
Get index of sample based on name.
virtual void ApplyShifts(const int iEvent)
ETA - generic function applying shifts.
std::string GetSampleTitle(const int Sample) const override
int ReturnKinematicParameterFromString(const std::string &KinematicStr) const
ETA function to generically convert a string from xsec cov to a kinematic type.
std::vector< EventInfo > MCSamples
Stores information about every MC event.
void SetupNuOscillatorPointers()
THStack * ReturnStackedHistBySelection1D(const int iSample, const std::string &KinematicProjection, int Selection1, int Selection2=-1, int WeightStyle=0, TAxis *Axis=nullptr)
virtual std::vector< double > ReturnKinematicVector(std::string KinematicParameter, int iEvent)
void SetupReweightArrays()
Initialise data, MC and W2 histograms.
virtual void SetupFunctionalParameters()
ETA - a function to setup and pass values to functional parameters where you need to pass a value to ...
void FillArray()
DB Nice new multi-threaded function which calculates the event weights and fills the relevant bins of...
TH1 * GetMCHist(const int Sample) override
Get MC histogram.
double * SampleHandlerFD_array_w2
KS Array used for MC stat.
TLegend * THStackLeg
DB Miscellaneous Variables.
bool IsEventSelected(const int iSample, const int iEvent) _noexcept_
DB Function which determines if an event is selected, where Selection double looks like {{ND280Kinema...
std::unordered_map< std::string, int > funcParsNamesMap
HH - a map that relates the name of the functional parameter to funcpar enum.
TH1 * Get1DVarHistByModeAndChannel(const int iSample, const std::string &ProjectionVar_Str, int kModeToFill=-1, int kChannelToFill=-1, int WeightStyle=0, TAxis *Axis=nullptr) override
virtual void AddAdditionalWeightPointers()=0
DB Function to determine which weights apply to which types of samples.
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.
int PDGToNuOscillatorFlavour(const int NuPdg)
Convert from PDG flavour to NuOscillator type beware that in the case of anti-neutrinos the NuOscilla...
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.
std::string flavourName
Name of osc channel.
KS: Store info about MC sample.
std::vector< OscChannelInfo > OscChannels
Stores info about oscillation channel for a single sample.
std::vector< std::string > mc_files
names of mc files associated associated with this object
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