15 MACH3LOG_INFO(
"-------------------------------------------------------------------");
20 MACH3LOG_WARN(
"You've passed me a nullptr ParameterHandler so I will not use any model parameter");
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>();
57 auto ModeName = Get<std::string>(
SampleManager->raw()[
"MaCh3ModeConfig"], __FILE__ , __LINE__);
58 Modes = std::make_unique<MaCh3Modes>(getenv(
"MACH3")+std::string(
"/") + ModeName);
64 UpdateW2 = GetFromManager<bool>(
SampleManager->raw()[
"LikelihoodOptions"][
"UpdateW2"],
false, __FILE__ , __LINE__);
72 auto EnabledSasmples = Get<std::vector<std::string>>(
SampleManager->raw()[
"Samples"], __FILE__ , __LINE__);
82 for (
int iSample = 0; iSample <
nSamples; iSample++)
84 auto SampleSettings =
SampleManager->raw()[EnabledSasmples[iSample]];
89 for(
int iMode=0; iMode <
Modes->GetNModes(); iMode++ ) {
95 for(
int iMode=0; iMode<
Modes->GetNModes(); iMode++ ) {
96 std::string modeStr =
Modes->GetMaCh3ModeName(iMode);
98 double modeWeight =
SampleManager->raw()[
"NominalWeights"][modeStr].as<
double>();
106 for(
int iMode=0; iMode<
Modes->GetNModes(); iMode++ ) {
107 std::string modeStr =
Modes->GetMaCh3ModeName(iMode);
118 SingleSample.
SampleTitle = Get<std::string>(SampleSettings[
"SampleTitle"], __FILE__ , __LINE__);
120 SingleSample.
SampleName = GetFromManager<std::string>(SampleSettings[
"SampleName"],
GetName(), __FILE__ , __LINE__);
122 Binning->SetupSampleBinning(SampleSettings[
"Binning"], SingleSample);
124 auto MCFilePrefix = Get<std::string>(SampleSettings[
"InputFiles"][
"mtupleprefix"], __FILE__, __LINE__);
125 auto MCFileSuffix = Get<std::string>(SampleSettings[
"InputFiles"][
"mtuplesuffix"], __FILE__, __LINE__);
126 auto SplinePrefix = Get<std::string>(SampleSettings[
"InputFiles"][
"splineprefix"], __FILE__, __LINE__);
127 auto SplineSuffix = Get<std::string>(SampleSettings[
"InputFiles"][
"splinesuffix"], __FILE__, __LINE__);
129 int NChannels =
static_cast<M3::int_t>(SampleSettings[
"OscChannels"].size());
132 YAML::Node OscChannelsConfig;
134 if(SampleSettings[
"OscChannels"].IsScalar()) {
135 auto PredeterminedChannelsName = Get<std::string>(SampleSettings[
"OscChannels"], __FILE__, __LINE__);
137 MACH3LOG_ERROR(
"Trying to use Predetermined OscChannels however such field doesn't exist in config for SampleHandler: {}",
GetName());
140 if(!
SampleManager->raw()[
"OscChannels"][PredeterminedChannelsName]) {
141 MACH3LOG_ERROR(
"I didn't find PredeterminedChannelsName called: {}", PredeterminedChannelsName);
142 MACH3LOG_ERROR(
"However I have PredeterminedChannelsName known as:");
143 for (
const auto& item :
SampleManager->raw()[
"OscChannels"]) {
148 OscChannelsConfig =
SampleManager->raw()[
"OscChannels"][PredeterminedChannelsName];
150 OscChannelsConfig = SampleSettings[
"OscChannels"];
152 int OscChannelCounter = 0;
153 for (
auto const &osc_channel : OscChannelsConfig) {
155 OscInfo.
flavourName = Get<std::string>(osc_channel[
"Name"], __FILE__ , __LINE__);
156 OscInfo.
flavourName_Latex = Get<std::string>(osc_channel[
"LatexName"], __FILE__ , __LINE__);
161 for (
const auto& Existing : SingleSample.
OscChannels) {
162 if (Existing.InitPDG == OscInfo.
InitPDG && Existing.FinalPDG == OscInfo.
FinalPDG) {
163 MACH3LOG_ERROR(
"Duplicate oscillation channel detected! InitPDG = {}, FinalPDG = {}"
164 "already defined in channel {} for sample {}",
169 auto MCFileNames = Get<std::vector<std::string>>(osc_channel[
"mtuplefile"], __FILE__ , __LINE__);
170 for(
size_t iFile = 0; iFile < MCFileNames.size(); iFile++){
171 std::string FileName = MCFilePrefix + MCFileNames[iFile] + MCFileSuffix;
172 MCFileNames[iFile] = FileName;
177 SingleSample.
OscChannels.push_back(std::move(OscInfo));
178 SingleSample.
mc_files.push_back(MCFileNames);
179 SingleSample.
spline_files.push_back(SplinePrefix+osc_channel[
"splinefile"].as<std::string>()+SplineSuffix);
182 for (
auto const &SelectionCuts : SampleSettings[
"SelectionCuts"]) {
183 auto TempBoundsVec =
GetBounds(SelectionCuts[
"Bounds"]);
188 MACH3LOG_INFO(
"Adding cut on {} with bounds {} to {}", SelectionCuts[
"KinematicStr"].as<std::string>(), TempBoundsVec[0], TempBoundsVec[1]);
212 MACH3LOG_INFO(
"=============================================");
228 MACH3LOG_INFO(
"Finished loading MC for {}, it took {:.2f}s to finish",
GetName(), clock.RealTime());
231 MACH3LOG_INFO(
"=======================================================");
239 MACH3LOG_ERROR(
"Map KinematicParameters or ReversedKinematicParameters hasn't been initialised");
244 const auto& key = pair.first;
245 const auto& value = pair.second;
255 std::vector<std::string> Vars = {
"Mode",
"OscillationChannel",
"TargetNucleus"};
256 for(
size_t iVar = 0; iVar < Vars.size(); iVar++) {
260 MACH3LOG_ERROR(
"MaCh3 expected variable: {} not found in KinematicParameters.", Vars[iVar]);
270 #pragma GCC diagnostic push
271 #pragma GCC diagnostic ignored "-Wconversion"
275 int Dimension =
GetNDim(Sample);
280 for (
int xBin = 0; xBin <
Binning->GetNAxisBins(Sample, 0); ++xBin) {
281 const int idx =
Binning->GetGlobalBinSafe(Sample, {xBin});
282 Hist->SetBinContent(xBin + 1, Array[idx]);
284 }
else if (Dimension == 2) {
286 if(
Binning->IsUniform(Sample)) {
287 for (
int yBin = 0; yBin <
Binning->GetNAxisBins(Sample, 1); ++yBin) {
288 for (
int xBin = 0; xBin <
Binning->GetNAxisBins(Sample, 0); ++xBin) {
289 const int idx =
Binning->GetGlobalBinSafe(Sample, {xBin, yBin});
290 Hist->SetBinContent(xBin + 1, yBin + 1, Array[idx]);
294 for (
int iBin = 0; iBin <
Binning->GetNBins(Sample); ++iBin) {
295 const int idx = iBin +
Binning->GetSampleStartBin(Sample);
297 Hist->SetBinContent(iBin + 1, Array[idx]);
301 for (
int iBin = 0; iBin <
Binning->GetNBins(Sample); ++iBin) {
302 const int idx = iBin +
Binning->GetSampleStartBin(Sample);
304 Hist->SetBinContent(iBin + 1, Array[idx]);
308 #pragma GCC diagnostic pop
314 const auto& SampleSelection = Selection[iSample];
315 const int SelectionSize =
static_cast<int>(SampleSelection.size());
316 for (
int iSelection = 0; iSelection < SelectionSize; ++iSelection) {
317 const auto& Cut = SampleSelection[iSelection];
318 const double Val = ReturnKinematicParameter(Cut.ParamToCutOnIt, iEvent);
319 if ((Val < Cut.LowerBound) || (Val >= Cut.UpperBound)) {
329 for (
unsigned int iSelection=0;iSelection < SubEventCuts.size() ;iSelection++) {
331 if (nsubevents != Vec.size()) {
332 MACH3LOG_ERROR(
"Cannot apply kinematic cut on {} as it is of different size to plotting variable");
335 const double Val = Vec[iSubEvent];
336 if ((Val < SubEventCuts[iSelection].LowerBound) || (Val >= SubEventCuts[iSelection].UpperBound)) {
374 #pragma GCC diagnostic push
375 #pragma GCC diagnostic ignored "-Walloca"
396 [[maybe_unused]]
const auto TotalBins =
Binning->GetNBins();
397 const unsigned int NumberOfEvents =
GetNEvents();
402 #pragma omp parallel for reduction(+:MC_Array_for_reduction[:TotalBins], W2_array_for_reduction[:TotalBins])
404 for (
unsigned int iEvent = 0; iEvent < NumberOfEvents; ++iEvent) {
420 if (totalweight <= 0.){
425 const int GlobalBin =
Binning->FindGlobalBin(MCEvent->NominalSample, MCEvent->KinVar, MCEvent->NomBin);
432 MC_Array_for_reduction[GlobalBin] += totalweight;
433 if (
FirstTimeW2) W2_array_for_reduction[GlobalBin] += totalweight*totalweight;
437 #pragma GCC diagnostic pop
445 const int nBins =
Binning->GetNBins();
466 shift.apply(shift.par_vals, iEvent);
477 const int TotalWeights =
static_cast<int>(MCEvent->total_weight_pointers.size());
480 #pragma omp simd reduction(*:TotalWeight)
482 for (
int iWeight = 0; iWeight < TotalWeights; ++iWeight) {
483 TotalWeight *= *(MCEvent->total_weight_pointers[iWeight]);
497 if (OscParams.size() > 0) {
500 MACH3LOG_INFO(
"You have passed an OscillatorBase object through the constructor of a SampleHandlerFD object - this will be used for all oscillation channels");
501 if(
Oscillator->isEqualBinningPerOscChannel() !=
true) {
502 MACH3LOG_ERROR(
"Trying to run shared NuOscillator without EqualBinningPerOscChannel, this will not work");
506 if(OscParams.size() !=
Oscillator->GetOscParamsSize()){
507 MACH3LOG_ERROR(
"SampleHandler {} has {} osc params, while shared NuOsc has {} osc params",
GetName(),
508 OscParams.size(),
Oscillator->GetOscParamsSize());
509 MACH3LOG_ERROR(
"This indicate misconfiguration in your Osc yaml");
517 MACH3LOG_WARN(
"Didn't find any oscillation params, thus will not enable oscillations");
521 MACH3LOG_ERROR(
"Either remove 'NuOsc' field from SampleHandler config or check your model.yaml and include oscillation for sample");
533 std::vector< std::vector< int > > norms_bins(
GetNEvents());
535 std::vector< std::vector<NormParameter>> norm_parameters(
GetNSamples());
537 for (
int iSample = 0; iSample <
GetNSamples(); ++iSample) {
549 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); ++iEvent) {
551 const size_t offset =
MCEvents[iEvent].total_weight_pointers.size();
552 const size_t addSize = norms_bins[iEvent].size();
553 MCEvents[iEvent].total_weight_pointers.resize(offset + addSize);
554 for(
auto const & norm_bin: norms_bins[iEvent]) {
565 for(
unsigned int iEvent = 0; iEvent <
GetNEvents(); ++iEvent){
566 std::vector< int > NormBins = {};
568 const auto SampleId =
MCEvents[iEvent].NominalSample;
569 auto& NormParam = norm_parameters[SampleId];
578 for (std::vector<NormParameter>::iterator it = NormParam.begin(); it != NormParam.end(); ++it) {
583 MACH3LOG_TRACE(
"Event {}, missed target check ({}) for dial {}", iEvent, Target, it->name);
596 if (!FlavourUnoscMatch){
597 MACH3LOG_TRACE(
"Event {}, missed FlavourUnosc check ({}) for dial {}", iEvent,
MCEvents[iEvent].nupdgUnosc, it->name);
605 MACH3LOG_TRACE(
"Event {}, missed Mode check ({}) for dial {}", iEvent, Mode, it->name);
615 MACH3LOG_TRACE(
"Event {}, missed Kinematic var check for dial {}", iEvent, it->name);
622 NormBins.push_back(bin);
623 MACH3LOG_TRACE(
"Event {}, will be affected by dial {}", iEvent, it->name);
626 norms_bins[iEvent] = NormBins;
641 for(
int iSample = 0; iSample <
GetNSamples(); iSample++)
643 int Dimension =
GetNDim(iSample);
648 auto XVec =
Binning->GetBinEdges(iSample, 0);
649 SamDet->DataHist =
new TH1D((
"d" + HistTitle).c_str(), HistTitle.c_str(),
static_cast<int>(XVec.size()-1), XVec.data());
650 SamDet->MCHist =
new TH1D((
"h" + HistTitle).c_str(), HistTitle.c_str(),
static_cast<int>(XVec.size()-1), XVec.data());
651 SamDet->W2Hist =
new TH1D((
"w" + HistTitle).c_str(), HistTitle.c_str(),
static_cast<int>(XVec.size()-1), XVec.data());
654 SamDet->DataHist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
655 SamDet->DataHist->GetYaxis()->SetTitle(
"Events");
656 SamDet->MCHist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
657 SamDet->MCHist->GetYaxis()->SetTitle(
"Events");
658 SamDet->W2Hist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
659 SamDet->W2Hist->GetYaxis()->SetTitle(
"Events");
660 }
else if (Dimension == 2){
661 if(
Binning->IsUniform(iSample)) {
662 auto XVec =
Binning->GetBinEdges(iSample, 0);
663 auto YVec =
Binning->GetBinEdges(iSample, 1);
664 int nX =
static_cast<int>(XVec.size() - 1);
665 int nY =
static_cast<int>(YVec.size() - 1);
667 SamDet->DataHist =
new TH2D((
"d" + HistTitle).c_str(), HistTitle.c_str(), nX, XVec.data(), nY, YVec.data());
668 SamDet->MCHist =
new TH2D((
"h" + HistTitle).c_str(), HistTitle.c_str(), nX, XVec.data(), nY, YVec.data());
669 SamDet->W2Hist =
new TH2D((
"w" + HistTitle).c_str(), HistTitle.c_str(), nX, XVec.data(), nY, YVec.data());
671 auto AddBinsToTH2Poly = [](TH2Poly* hist,
const std::vector<BinInfo>& bins) {
672 for (
const auto& bin : bins) {
673 double xLow = bin.Extent[0][0];
674 double xHigh = bin.Extent[0][1];
675 double yLow = bin.Extent[1][0];
676 double yHigh = bin.Extent[1][1];
678 double x[4] = {xLow, xHigh, xHigh, xLow};
679 double y[4] = {yLow, yLow, yHigh, yHigh};
681 hist->AddBin(4, x, y);
685 SamDet->DataHist =
new TH2Poly();
686 SamDet->DataHist->SetName((
"d" + HistTitle).c_str());
687 SamDet->DataHist->SetTitle(HistTitle.c_str());
689 SamDet->MCHist =
new TH2Poly();
690 SamDet->MCHist->SetName((
"h" + HistTitle).c_str());
691 SamDet->MCHist->SetTitle(HistTitle.c_str());
693 SamDet->W2Hist =
new TH2Poly();
694 SamDet->W2Hist->SetName((
"w" + HistTitle).c_str());
695 SamDet->W2Hist->SetTitle(HistTitle.c_str());
698 AddBinsToTH2Poly(
static_cast<TH2Poly*
>(SamDet->DataHist),
Binning->GetNonUniformBins(iSample));
699 AddBinsToTH2Poly(
static_cast<TH2Poly*
>(SamDet->MCHist),
Binning->GetNonUniformBins(iSample));
700 AddBinsToTH2Poly(
static_cast<TH2Poly*
>(SamDet->W2Hist),
Binning->GetNonUniformBins(iSample));
704 SamDet->DataHist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
705 SamDet->DataHist->GetYaxis()->SetTitle(SamDet->VarStr[1].c_str());
706 SamDet->MCHist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
707 SamDet->MCHist->GetYaxis()->SetTitle(SamDet->VarStr[1].c_str());
708 SamDet->W2Hist->GetXaxis()->SetTitle(SamDet->VarStr[0].c_str());
709 SamDet->W2Hist->GetYaxis()->SetTitle(SamDet->VarStr[1].c_str());
711 int nbins =
Binning->GetNBins(iSample);
712 SamDet->DataHist =
new TH1D((
"d" + HistTitle).c_str(), HistTitle.c_str(), nbins, 0, nbins);
713 SamDet->MCHist =
new TH1D((
"h" + HistTitle).c_str(), HistTitle.c_str(), nbins, 0, nbins);
714 SamDet->W2Hist =
new TH1D((
"w" + HistTitle).c_str(), HistTitle.c_str(), nbins, 0, nbins);
716 for(
int iBin = 0; iBin < nbins; iBin++) {
717 auto BinName =
Binning->GetBinName(iSample, iBin);
718 SamDet->DataHist->GetXaxis()->SetBinLabel(iBin+1, BinName.c_str());
719 SamDet->MCHist->GetXaxis()->SetBinLabel(iBin+1, BinName.c_str());
720 SamDet->W2Hist->GetXaxis()->SetBinLabel(iBin+1, BinName.c_str());
724 SamDet->DataHist->GetYaxis()->SetTitle(
"Events");
725 SamDet->MCHist->GetYaxis()->SetTitle(
"Events");
726 SamDet->W2Hist->GetYaxis()->SetTitle(
"Events");
729 SamDet->DataHist->SetDirectory(
nullptr);
730 SamDet->MCHist->SetDirectory(
nullptr);
731 SamDet->W2Hist->SetDirectory(
nullptr);
742 for (
unsigned int event_i = 0; event_i <
GetNEvents(); event_i++) {
743 int Sample =
MCEvents[event_i].NominalSample;
744 const int dim =
GetNDim(Sample);
745 MCEvents[event_i].KinVar.resize(dim);
746 MCEvents[event_i].NomBin.resize(dim);
748 auto SetNominalBin = [&](
int bin,
int max_bins,
int& out_bin) {
749 if (bin >= 0 && bin < max_bins) {
757 for(
int iDim = 0; iDim < dim; iDim++) {
759 if (std::isnan(*
MCEvents[event_i].KinVar[iDim]) || std::isinf(*
MCEvents[event_i].KinVar[iDim])) {
760 MACH3LOG_ERROR(
"Variable {} for sample {} and dimension {} is ill-defined and equal to {}",
764 const int bin =
Binning->FindNominalBin(Sample, iDim, *
MCEvents[event_i].KinVar[iDim]);
765 int NBins_i =
static_cast<int>(
Binning->GetBinEdges(Sample, iDim).size() - 1);
766 SetNominalBin(bin, NBins_i,
MCEvents[event_i].NomBin[iDim]);
840 MACH3LOG_INFO(
"Adding {}D data histogram: {} with {:.2f} events", Dim, Data->GetTitle(), Data->Integral());
843 SampleDetails[Sample].DataHist =
static_cast<TH1*
>(Data->Clone());
846 MACH3LOG_ERROR(
"SampleHandler_data haven't been initialised yet");
850 auto ChecHistType = [&](
const std::string& Type,
const int Dimen,
const TH1* Hist,
851 const std::string& file,
const int line) {
852 if (std::string(Hist->ClassName()) != Type) {
853 MACH3LOG_ERROR(
"Expected {} for {}D sample, got {}", Type, Dimen, Hist->ClassName());
860 ChecHistType(
"TH1D", Dim,
SampleDetails[Sample].DataHist, __FILE__, __LINE__);
862 static_cast<TH1D*
>(
SampleDetails[Sample].MCHist), __FILE__, __LINE__);
863 for (
int xBin = 0; xBin <
Binning->GetNAxisBins(Sample, 0); ++xBin) {
864 const int idx =
Binning->GetGlobalBinSafe(Sample, {xBin});
869 SampleDetails[Sample].DataHist->GetYaxis()->SetTitle(
"Number of Events");
870 }
else if (Dim == 2) {
871 if(
Binning->IsUniform(Sample)) {
872 ChecHistType(
"TH2D", Dim,
SampleDetails[Sample].DataHist, __FILE__, __LINE__);
874 static_cast<TH2D*
>(
SampleDetails[Sample].MCHist), __FILE__, __LINE__);
875 for (
int yBin = 0; yBin <
Binning->GetNAxisBins(Sample, 1); ++yBin) {
876 for (
int xBin = 0; xBin <
Binning->GetNAxisBins(Sample, 0); ++xBin) {
877 const int idx =
Binning->GetGlobalBinSafe(Sample, {xBin, yBin});
883 ChecHistType(
"TH2Poly", Dim,
SampleDetails[Sample].DataHist, __FILE__, __LINE__);
885 static_cast<TH2Poly*
>(
SampleDetails[Sample].MCHist), __FILE__, __LINE__);
886 for (
int iBin = 0; iBin <
Binning->GetNBins(Sample); ++iBin) {
887 const int idx = iBin +
Binning->GetSampleStartBin(Sample);
895 SampleDetails[Sample].DataHist->GetZaxis()->SetTitle(
"Number of Events");
897 ChecHistType(
"TH1D", Dim,
SampleDetails[Sample].DataHist, __FILE__, __LINE__);
899 static_cast<TH1D*
>(
SampleDetails[Sample].MCHist), __FILE__, __LINE__);
900 for (
int iBin = 0; iBin <
Binning->GetNBins(Sample); ++iBin) {
901 const int idx = iBin +
Binning->GetSampleStartBin(Sample);
911 const int Start =
Binning->GetSampleStartBin(Sample);
912 const int End =
Binning->GetSampleEndBin(Sample);
913 const int ExpectedSize = End - Start;
915 if (
static_cast<int>(Data_Array.size()) != ExpectedSize) {
917 MACH3LOG_ERROR(
"Expected size: {}, received size: {}.", ExpectedSize, Data_Array.size());
919 MACH3LOG_ERROR(
"This likely indicates a binning or sample slicing bug.");
931 auto NuOscillatorConfigFile = Get<std::string>(
SampleManager->raw()[
"NuOsc"][
"NuOscConfigFile"], __FILE__ , __LINE__);
932 auto EqualBinningPerOscChannel = Get<bool>(
SampleManager->raw()[
"NuOsc"][
"EqualBinningPerOscChannel"], __FILE__ , __LINE__);
935 if (EqualBinningPerOscChannel) {
936 if (YAML::LoadFile(NuOscillatorConfigFile)[
"General"][
"CalculationType"].as<std::string>() ==
"Unbinned") {
937 MACH3LOG_WARN(
"Tried using EqualBinningPerOscChannel while using Unbinned oscillation calculation, changing EqualBinningPerOscChannel to false");
938 EqualBinningPerOscChannel =
false;
942 std::vector<OscillationParameter> OscParams{};
943 for (
int iSample = 0; iSample <
GetNSamples(); iSample++) {
946 if (sample_osc_pars.empty()) {
948 MACH3LOG_ERROR(
"This indicates an error in your oscillation YAML configuration.");
951 OscParams = sample_osc_pars;
953 if (sample_osc_pars.size() != OscParams.size()) {
954 MACH3LOG_ERROR(
"SampleHandler/Sample {}/{} has {} osc params while Sample {} has {}",
961 std::vector<const M3::float_t*> OscParamsValues(OscParams.size());
962 std::vector<std::string> NuOscName(OscParams.size());
963 for(
size_t ij = 0; ij < OscParams.size(); ij++){
965 NuOscName[ij] = OscParams[ij].NuOscName;
968 if (EqualBinningPerOscChannel) {
969 Oscillator = std::make_shared<OscillationHandler>(NuOscillatorConfigFile, EqualBinningPerOscChannel, OscParamsValues,
974 std::vector<std::map<std::pair<int, int>, std::vector<M3::float_t>>>
977 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
980 "SampleHandler {} only has {} samples.",
989 #pragma GCC diagnostic push
990 #pragma GCC diagnostic ignored "-Wuseless-cast"
991 channel_energy_array[
MCEvents[iEvent].NominalSample]
992 [std::make_pair(
MCEvents[iEvent].nupdgUnosc,
999 channel_cosz_array[
MCEvents[iEvent].NominalSample]
1000 [std::make_pair(
MCEvents[iEvent].nupdgUnosc,
1004 #pragma GCC diagnostic pop
1007 for (
int iSample = 0; iSample <
GetNSamples(); iSample++) {
1008 if (!channel_energy_array[iSample].size()) {
1014 for (
auto const &[osc_flavs, energies] : channel_energy_array[iSample]) {
1016 for (
size_t i = 0; i <
SampleDetails[iSample].OscChannels.size(); ++i) {
1017 if (osc_flavs.first ==
SampleDetails[iSample].OscChannels[i].InitPDG &&
1018 osc_flavs.second ==
SampleDetails[iSample].OscChannels[i].FinalPDG) {
1027 static const std::map<int, std::pair<std::string, std::string>> spec_defnames = {
1028 {12, {
"nue",
"#nu_{e}"}},
1029 {-12, {
"nueb",
"#bar{#nu}_{e}"}},
1030 {14, {
"numu",
"#nu_{#mu}"}},
1031 {-14, {
"nuemub",
"#bar{#nu}_{#mu}"}},
1032 {16, {
"nutau",
"#nu_{#tau}"}},
1033 {-16, {
"nutaub",
"#bar{#nu}_{#tau}"}},
1037 oci.
InitPDG = osc_flavs.first;
1039 oci.
flavourName = fmt::format(
"{}_x_{}", spec_defnames.at(osc_flavs.first).first,
1040 spec_defnames.at(osc_flavs.second).first);
1042 fmt::format(
"{} #rightarrow {}", spec_defnames.at(osc_flavs.first).second,
1043 spec_defnames.at(osc_flavs.second).second);
1051 Oscillator = std::make_shared<OscillationHandler>(NuOscillatorConfigFile, EqualBinningPerOscChannel, OscParamsValues,
1058 for (
auto &[osc_flavs, energies] : channel_energy_array[iSample]) {
1060 osc_flavs.first, osc_flavs.second);
1062 std::sort(energies.begin(), energies.end());
1063 std::sort(channel_cosz_array[iSample][osc_flavs].begin(),
1064 channel_cosz_array[iSample][osc_flavs].end());
1065 Oscillator->SetOscillatorBinning(iSample, iChannel, energies,
1066 channel_cosz_array[iSample][osc_flavs]);
1075 auto AddOscPointer = GetFromManager<bool>(
SampleManager->raw()[
"NuOsc"][
"AddOscPointer"],
true, __FILE__ , __LINE__);
1077 if(!AddOscPointer) {
1080 for (
unsigned int iEvent=0;iEvent<
GetNEvents();iEvent++) {
1085 MCEvents[iEvent].total_weight_pointers.push_back(osc_w_pointer);
1108 MACH3LOG_ERROR(
"Something has gone wrong in the mapping between MCEvents.nutype and the enum used within NuOscillator");
1115 const int Sample =
MCEvents[iEvent].NominalSample;
1121 osc_w_pointer =
Oscillator->GetNuOscillatorPointers(Sample, OscIndex, InitFlav, FinalFlav, FLOAT_T(
MCEvents[iEvent].enu_true), FLOAT_T(
MCEvents[iEvent].coszenith_true));
1124 osc_w_pointer =
Oscillator->GetNuOscillatorPointers(Sample, OscIndex, InitFlav, FinalFlav, FLOAT_T(
MCEvents[iEvent].enu_true));
1127 return osc_w_pointer;
1155 if (totalweight <= 0.){
1164 const int SampleIndex =
MCEvents[Event].NominalSample;
1166 bool NoOscChannels =
false;
1168 MACH3LOG_DEBUG(
"Assuming there are no osc channels in {}", __func__);
1169 NoOscChannels =
true;
1174 const double Etrue =
MCEvents[Event].enu_true;
1175 std::vector< SplineIndex > EventSplines;
1176 switch(
GetNDim(SampleIndex)) {
1178 EventSplines = BinnedSpline->
GetEventSplines(SampleTitle, OscIndex, Mode, {Etrue, *(
MCEvents[Event].KinVar[0]), 0.});
1184 if(ThrowCrititcal) {
1187 ThrowCrititcal =
false;
1192 return EventSplines;
1200 bool ThrowCrititcal =
true;
1202 std::vector< std::vector<SplineParameter> > SplineParsVec(
GetNSamples());
1203 for (
int iSample = 0; iSample <
GetNSamples(); ++iSample) {
1206 for (
unsigned int j = 0; j <
GetNEvents(); ++j) {
1207 auto EventSplines =
GetSplineBins(j, BinnedSpline, ThrowCrititcal);
1208 const int NSplines =
static_cast<int>(EventSplines.size());
1209 if(NSplines == 0)
continue;
1210 auto& w_pointers =
MCEvents[j].total_weight_pointers;
1211 w_pointers.reserve(w_pointers.size() + NSplines);
1212 const auto SampleId =
MCEvents[j].NominalSample;
1213 for(
int spline = 0; spline < NSplines; spline++) {
1214 int SystIndex = EventSplines[spline].iSyst;
1216 bool IsSelected =
PassesSelection(SplineParsVec[SampleId][SystIndex], j);
1219 MACH3LOG_TRACE(
"Event {}, missed Kinematic var check for dial {}", j, SplineParsVec[SampleId][SystIndex].name);
1223 w_pointers.push_back(BinnedSpline->RetPointer(EventSplines[spline]));
1225 w_pointers.shrink_to_fit();
1228 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); ++iEvent) {
1229 MCEvents[iEvent].total_weight_pointers.push_back(UnbinnedSpline->RetPointer(iEvent));
1240 const int Start =
Binning->GetSampleStartBin(isample);
1241 const int End =
Binning->GetSampleEndBin(isample);
1243 double negLogL = 0.;
1245 #pragma omp parallel for reduction(+:negLogL)
1247 for (
int idx = Start; idx < End; ++idx)
1262 double negLogL = 0.;
1264 #pragma omp parallel for reduction(+:negLogL)
1266 for (
int idx = 0; idx <
Binning->GetNBins(); ++idx)
1287 for(
int iSample = 0; iSample <
GetNSamples(); iSample++)
1289 std::unique_ptr<TH1> data_hist;
1293 data_hist->GetXaxis()->SetTitle(
GetKinVarName(iSample, 0).c_str());
1294 data_hist->GetYaxis()->SetTitle(
"Number of Events");
1295 }
else if (
GetNDim(iSample) == 2) {
1296 if(
Binning->IsUniform(iSample)) {
1301 data_hist->GetXaxis()->SetTitle(
GetKinVarName(iSample, 0).c_str());
1302 data_hist->GetYaxis()->SetTitle(
GetKinVarName(iSample, 1).c_str());
1303 data_hist->GetZaxis()->SetTitle(
"Number of Events");
1306 int nbins =
Binning->GetNBins(iSample);
1307 for(
int iBin = 0; iBin < nbins; iBin++) {
1308 auto BinName =
Binning->GetBinName(iSample, iBin);
1309 data_hist->GetXaxis()->SetBinLabel(iBin+1, BinName.c_str());
1311 data_hist->GetYaxis()->SetTitle(
"Number of Events");
1319 data_hist->SetTitle((
"data_" +
GetSampleTitle(iSample)).c_str());
1328 bool LoadSplineFile = GetFromManager<bool>(
SampleManager->raw()[
"InputFiles"][
"LoadSplineFile"],
false, __FILE__, __LINE__);
1329 bool PrepSplineFile = GetFromManager<bool>(
SampleManager->raw()[
"InputFiles"][
"PrepSplineFile"],
false, __FILE__, __LINE__);
1330 auto SplineFileName = GetFromManager<std::string>(
SampleManager->raw()[
"InputFiles"][
"SplineFileName"],
1332 if(!LoadSplineFile) {
1333 for(
int iSample = 0; iSample <
GetNSamples(); iSample++) {
1334 std::vector<std::string> spline_filepaths =
SampleDetails[iSample].spline_files;
1337 std::vector<std::string> SplineVarNames = {
"TrueNeutrinoEnergy"};
1340 }
else if (
GetNDim(iSample) == 2) {
1350 BinnedSplines->CountNumberOfLoadedSplines(
false, 1);
1351 BinnedSplines->TransferToMonolith();
1352 if(PrepSplineFile) BinnedSplines->PrepareSplineFile(SplineFileName);
1355 BinnedSplines->LoadSplineFile(SplineFileName);
1362 BinnedSplines->CleanUpMemory();
1373 const std::vector<KinematicCut>& ExtraCuts) {
1382 for (
const auto& cut : ExtraCuts) {
1383 selectionToApply[iSample].emplace_back(cut);
1387 Selection = std::move(selectionToApply);
1389 return originalSelection;
1395 const std::vector< KinematicCut >& EventSelectionVec,
1396 const int WeightStyle,
1397 const std::vector< KinematicCut >& SubEventSelectionVec) {
1405 auto _h1DVar = std::make_unique<TH1D>(
"",
"",
int(xBinEdges.size())-1, xBinEdges.data());
1406 _h1DVar->SetDirectory(
nullptr);
1407 _h1DVar->GetXaxis()->SetTitle(ProjectionVar_Str.c_str());
1408 _h1DVar->GetYaxis()->SetTitle(
"Events");
1411 Fill1DSubEventHist(iSample, _h1DVar.get(), ProjectionVar_Str, SubEventSelectionVec, WeightStyle);
1417 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1418 const int EventSample =
MCEvents[iEvent].NominalSample;
1419 if(EventSample != iSample)
continue;
1422 if (WeightStyle == 1) {
1426 _h1DVar->Fill(Var, Weight);
1438 const std::vector< KinematicCut >& SubEventSelectionVec,
const int WeightStyle) {
1443 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1444 const int EventSample =
MCEvents[iEvent].NominalSample;
1445 if(EventSample != iSample)
continue;
1448 if (WeightStyle == 1) {
1452 size_t nsubevents = Vec.size();
1454 for (
unsigned int iSubEvent = 0; iSubEvent < nsubevents; iSubEvent++) {
1456 double Var = Vec[iSubEvent];
1457 _h1DVar->Fill(Var,Weight);
1466 const std::string& ProjectionVar_StrX,
1467 const std::string& ProjectionVar_StrY,
1468 const std::vector< KinematicCut >& EventSelectionVec,
1469 const int WeightStyle,
1470 const std::vector< KinematicCut >& SubEventSelectionVec) {
1478 std::unique_ptr<TH2> _h2DVar;
1481 _h2DVar = std::unique_ptr<TH2>(
static_cast<TH2*
>(
M3::Clone(
GetMCHist(iSample)).release()));
1485 _h2DVar = std::make_unique<TH2D>(
"",
"",
int(xBinEdges.size())-1, xBinEdges.data(),
int(yBinEdges.size())-1, yBinEdges.data());
1487 _h2DVar->SetDirectory(
nullptr);
1488 _h2DVar->GetXaxis()->SetTitle(ProjectionVar_StrX.c_str());
1489 _h2DVar->GetYaxis()->SetTitle(ProjectionVar_StrY.c_str());
1490 _h2DVar->GetZaxis()->SetTitle(
"Events");
1493 if (IsSubEventHist)
Fill2DSubEventHist(iSample, _h2DVar.get(), ProjectionVar_StrX, ProjectionVar_StrY, SubEventSelectionVec, WeightStyle);
1500 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1501 const int EventSample =
MCEvents[iEvent].NominalSample;
1502 if(EventSample != iSample)
continue;
1505 if (WeightStyle == 1) {
1510 _h2DVar->Fill(VarX,VarY,Weight);
1522 const std::string& ProjectionVar_StrX,
1523 const std::string& ProjectionVar_StrY,
1524 const std::vector< KinematicCut >& SubEventSelectionVec,
1530 int ProjectionVar_IntX, ProjectionVar_IntY;
1537 for (
unsigned int iEvent = 0; iEvent <
GetNEvents(); iEvent++) {
1538 const int EventSample =
MCEvents[iEvent].NominalSample;
1539 if(EventSample != iSample)
continue;
1542 if (WeightStyle == 1) {
1545 std::vector<double> VecX = {}, VecY = {};
1547 size_t nsubevents = 0;
1549 if (IsSubEventVarX && !IsSubEventVarY) {
1552 nsubevents = VecX.size();
1554 else if (!IsSubEventVarX && IsSubEventVarY) {
1557 nsubevents = VecY.size();
1562 if (VecX.size() != VecY.size()) {
1563 MACH3LOG_ERROR(
"Cannot plot {} of size {} against {} of size {}", ProjectionVar_StrX, VecX.size(), ProjectionVar_StrY, VecY.size());
1566 nsubevents = VecX.size();
1569 for (
unsigned int iSubEvent = 0; iSubEvent < nsubevents; iSubEvent++) {
1571 if (IsSubEventVarX) VarX = VecX[iSubEvent];
1572 if (IsSubEventVarY) VarY = VecY[iSubEvent];
1573 _h2DVar->Fill(VarX,VarY,Weight);
1586 MACH3LOG_ERROR(
"Did not recognise Kinematic Parameter type: {}", KinematicParameterStr);
1600 MACH3LOG_ERROR(
"Did not recognise Kinematic Parameter type: {}", KinematicParameter);
1613 MACH3LOG_ERROR(
"Did not recognise Kinematic Vector: {}", KinematicVectorStr);
1627 MACH3LOG_ERROR(
"Did not recognise Kinematic Vector: {}", KinematicVector);
1638 if(
Binning->IsUniform(Sample)) {
1639 for(
int iDim = 0; iDim <
GetNDim(Sample); iDim++) {
1641 return Binning->GetBinEdges(Sample, iDim);
1646 auto MakeBins = [](
int nBins) {
1647 std::vector<double> bins(nBins + 1);
1648 for (
int i = 0; i <= nBins; ++i)
1649 bins[i] =
static_cast<double>(i) - 0.5;
1653 if (KinematicParameter ==
"OscillationChannel") {
1655 }
else if (KinematicParameter ==
"Mode") {
1656 return MakeBins(
Modes->GetNModes());
1659 std::vector<double> BinningVect;
1662 bool found_range_specifier =
false;
1670 auto IsIncreasing = [](
const std::vector<double>& vec) {
1671 for (
size_t i = 1; i < vec.size(); ++i) {
1672 if (vec[i] <= vec[i-1]) {
1679 if (!IsIncreasing(BinningVect)) {
1681 if(found_range_specifier){
1682 MACH3LOG_ERROR(
"A bin range specifier was found. Please carefully check the number of square brackets used.");
1697 MACH3LOG_ERROR(
"Attempted to plot kinematic variable {}, but it appears in both KinematicVectors and KinematicParameters", VarStr);
1710 if (kChannelToFill != -1) {
1722 if (kModeToFill != -1) {
1723 if (!(kModeToFill >= 0) && (kModeToFill < Modes->GetNModes())) {
1724 MACH3LOG_ERROR(
"Required mode is not available. kModeToFill should be between 0 and {}",
Modes->GetNModes());
1734 std::vector< KinematicCut > SelectionVec;
1741 SelectionVec.push_back(SelecMode);
1749 SelectionVec.push_back(SelecChannel);
1752 return SelectionVec;
1757 const int kModeToFill,
const int kChannelToFill,
const int WeightStyle) {
1760 return Get1DVarHist(iSample, ProjectionVar_Str, SelectionVec, WeightStyle);
1765 const std::string& ProjectionVar_StrY,
const int kModeToFill,
1766 const int kChannelToFill,
const int WeightStyle) {
1769 return Get2DVarHist(iSample, ProjectionVar_StrX, ProjectionVar_StrY, SelectionVec, WeightStyle);
1775 constexpr
int space = 14;
1777 bool printToFile=
false;
1778 if (OutputFileName.CompareTo(
"/dev/null")) {printToFile =
true;}
1780 bool printToCSV=
false;
1781 if(OutputCSVFileName.CompareTo(
"/dev/null")) printToCSV=
true;
1783 std::ofstream outfile;
1785 outfile.open(OutputFileName.Data(), std::ios_base::app);
1786 outfile.precision(7);
1789 std::ofstream outcsv;
1791 outcsv.open(OutputCSVFileName, std::ios_base::app);
1792 outcsv.precision(7);
1795 double PDFIntegral = 0.;
1797 std::vector< std::vector< std::unique_ptr<TH1> > > IntegralList;
1798 IntegralList.resize(
Modes->GetNModes());
1800 std::vector<double> ChannelIntegral;
1802 for (
unsigned int i=0;i<ChannelIntegral.size();i++) {ChannelIntegral[i] = 0.;}
1804 for (
int i=0;i<
Modes->GetNModes();i++) {
1813 MACH3LOG_INFO(
"-------------------------------------------------");
1816 outfile <<
"\\begin{table}[ht]" << std::endl;
1817 outfile <<
"\\begin{center}" << std::endl;
1818 outfile <<
"\\caption{Integral breakdown for sample: " <<
GetSampleTitle(iSample) <<
"}" << std::endl;
1819 outfile <<
"\\label{" <<
GetSampleTitle(iSample) <<
"-EventRate}" << std::endl;
1824 outfile <<
"\\begin{tabular}{|l" << nColumns.Data() <<
"}" << std::endl;
1825 outfile <<
"\\hline" << std::endl;
1830 outcsv<<
"Integral Breakdown for sample :"<<
GetSampleTitle(iSample)<<
"\n";
1836 if (printToFile) {outfile << std::setw(space) <<
"Mode:";}
1837 if(printToCSV) {outcsv<<
"Mode,";}
1839 std::string table_headings = fmt::format(
"| {:<8} |",
"Mode");
1840 std::string table_footline =
"------------";
1842 table_headings += fmt::format(
" {:<17} |",
GetFlavourName(iSample, i));
1843 table_footline +=
"--------------------";
1844 if (printToFile) {outfile <<
"&" << std::setw(space) <<
SampleDetails[iSample].OscChannels[i].flavourName_Latex <<
" ";}
1847 if (printToFile) {outfile <<
"&" << std::setw(space) <<
"Total:" <<
"\\\\ \\hline" << std::endl;}
1848 if (printToCSV) {outcsv <<
"Total\n";}
1849 table_headings += fmt::format(
" {:<10} |",
"Total");
1850 table_footline +=
"-------------";
1855 for (
unsigned int i=0;i<IntegralList.size();i++) {
1856 double ModeIntegral = 0;
1857 if (printToFile) {outfile << std::setw(space) <<
Modes->GetMaCh3ModeName(i);}
1858 if(printToCSV) {outcsv <<
Modes->GetMaCh3ModeName(i) <<
",";}
1860 table_headings = fmt::format(
"| {:<8} |",
Modes->GetMaCh3ModeName(i));
1862 for (
unsigned int j=0;j<IntegralList[i].size();j++) {
1863 double Integral = IntegralList[i][j]->Integral();
1865 if (Integral < 1e-100) {Integral=0;}
1867 ModeIntegral += Integral;
1868 ChannelIntegral[j] += Integral;
1869 PDFIntegral += Integral;
1871 if (printToFile) {outfile <<
"&" << std::setw(space) << Form(
"%4.5f",Integral) <<
" ";}
1872 if (printToCSV) {outcsv << Form(
"%4.5f", Integral) <<
",";}
1874 table_headings += fmt::format(
" {:<17.4f} |", Integral);
1876 if (printToFile) {outfile <<
"&" << std::setw(space) << Form(
"%4.5f",ModeIntegral) <<
" \\\\ \\hline" << std::endl;}
1877 if (printToCSV) {outcsv << Form(
"%4.5f", ModeIntegral) <<
"\n";}
1879 table_headings += fmt::format(
" {:<10.4f} |", ModeIntegral);
1884 if (printToFile) {outfile << std::setw(space) <<
"Total:";}
1885 if (printToCSV) {outcsv <<
"Total,";}
1888 table_headings = fmt::format(
"| {:<8} |",
"Total");
1889 for (
unsigned int i=0;i<ChannelIntegral.size();i++) {
1890 if (printToFile) {outfile <<
"&" << std::setw(space) << Form(
"%4.5f",ChannelIntegral[i]) <<
" ";}
1891 if (printToCSV) {outcsv << Form(
"%4.5f", ChannelIntegral[i]) <<
",";}
1892 table_headings += fmt::format(
" {:<17.4f} |", ChannelIntegral[i]);
1894 if (printToFile) {outfile <<
"&" << std::setw(space) << Form(
"%4.5f",PDFIntegral) <<
" \\\\ \\hline" << std::endl;}
1895 if (printToCSV) {outcsv << Form(
"%4.5f", PDFIntegral) <<
"\n\n\n\n";}
1897 table_headings += fmt::format(
" {:<10.4f} |", PDFIntegral);
1902 outfile <<
"\\end{tabular}" << std::endl;
1903 outfile <<
"\\end{center}" << std::endl;
1904 outfile <<
"\\end{table}" << std::endl;
1910 outfile << std::endl;
1920 return Modes->GetNModes();
1926 MACH3LOG_ERROR(
"You've passed me a SamplePlotType with value {} which was not implemented.",
static_cast<int>(TypeEnum));
1933 const SamplePlotType Selection1,
const int Selection2,
const int WeightStyle) {
1935 std::vector<std::unique_ptr<TH1>> hHistList;
1936 std::string legendEntry;
1942 for (
int i=0;i<iMax;i++) {
1945 THStackLeg->AddEntry(hHistList[i].get(), (
Modes->GetMaCh3ModeName(i)+Form(
" : (%4.2f)",hHistList[i]->Integral())).c_str(),
"f");
1947 hHistList[i]->SetFillColor(
static_cast<Color_t
>(
Modes->GetMaCh3ModePlotColor(i)));
1948 hHistList[i]->SetLineColor(
static_cast<Color_t
>(
Modes->GetMaCh3ModePlotColor(i)));
1952 THStackLeg->AddEntry(hHistList[i].get(),(
GetFlavourName(iSample, i)+Form(
" | %4.2f",hHistList[i]->Integral())).c_str(),
"f");
1961 const std::string& KinematicProjectionY,
const SamplePlotType Selection1,
1962 const int Selection2,
const int WeightStyle) {
1964 std::vector<std::unique_ptr<TH2>> hHistList;
1967 for (
int i=0;i<iMax;i++) {
1981 const SamplePlotType Selection1,
int Selection2,
int WeightStyle) {
1984 auto StackHist = std::make_unique<THStack>((
GetSampleTitle(iSample)+
"_"+KinematicProjection+
"_Stack").c_str(),
"");
1986 for (
unsigned int i=0;i<HistList.size();i++) {
1987 StackHist->Add(HistList[i].release());
1997 return &(OscillationChannels[Channel].ChannelIndex);
2003 const auto TotalBins =
Binning->GetNBins();
2005 for(
int iBin = 0; iBin < TotalBins; iBin++) {
2014 MACH3LOG_WARN(
"Found in total {} ({:.2f}%) empty bins for SampleHandler: {}",
2015 iCounter, 100.0 *
static_cast<double>(iCounter) / TotalBins,
GetName());
2030 const std::string sep_full(81,
'-');
2032 MACH3LOG_INFO(
"{:<40}{:<15}{:<15}{:<10}|",
"Sample",
"Data",
"MC",
"-LLH");
2034 const std::string sep_data(56,
'-');
2039 double sumData = 0.0;
2041 double likelihood = 0.0;
2043 for (
int iSample = 0; iSample <
GetNSamples(); ++iSample) {
2046 double dataIntegral = std::accumulate(DataArray.begin(), DataArray.end(), 0.0);
2047 sumData += dataIntegral;
2049 std::vector<double> MCArray =
GetMCArray(iSample);
2050 double mcIntegral = std::accumulate(MCArray.begin(), MCArray.end(), 0.0);
2051 sumMC += mcIntegral;
2054 MACH3LOG_INFO(
"{:<40}{:<15.2f}{:<15.2f}{:<10.2f}|", name, dataIntegral, mcIntegral, likelihood);
2061 MACH3LOG_INFO(
"{:<40}{:<15.2f}{:<15.2f}{:<10.2f}|",
"Total", sumData, sumMC, likelihood);
2062 const std::string sep_full(81,
'-');
2066 const std::string sep_data(56,
'-');
2075 if(Dimension >
GetNDim(iSample)) {
2085 const int Start =
Binning->GetSampleStartBin(Sample);
2086 const int End =
Binning->GetSampleEndBin(Sample);
2088 return std::vector<double>(array.begin() + Start, array.begin() + End);
#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...
std::vector< double > BuildBinEdgesFromNode(YAML::Node const &bin_edges_node, bool &found_range_specifier)
Builds a single dimension's bin edges from YAML::Node.
Defines the custom exception class used throughout MaCh3.
MaCh3 Logging utilities built on top of SPDLOG.
#define MACH3LOG_CRITICAL
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.
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)
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< SplineIndex > GetEventSplines(const std::string &SampleTitle, int iOscChan, int EventMode, const std::vector< double > &VarVals)
Return the splines which affect a given event.
Custom exception class used throughout MaCh3.
const M3::float_t * RetPointer(const int iParam) const
DB Pointer return to param position.
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< OscillationParameter > GetOscParsFromSampleName(const std::string &SampleName) const
KS Grab the Osc parameters for the relevant SampleName.
const std::vector< SplineParameter > GetSplineParsFromSampleName(const std::string &SampleName) const
KS: Grab the Spline parameters for the relevant SampleName.
M3::float_t GetEventWeight(const int iEvent)
Computes the total event weight for a given entry.
std::vector< double > ReturnKinematicVector(const std::string &KinematicParameter, const int iEvent) const
void InitialiseSplineObject()
Setup spline handler (both binned or unbinned)
virtual ~SampleHandlerBase()
destructor
std::string SampleHandlerName
Identifier of this Sample Handler, mostly used for fancy printing in FitterBase.
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
Construct vector of kinematic cuts that will be applied, on top of default cuts include stuff like cu...
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)
void ResetHistograms() _noexcept_
Helper function to reset histograms.
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
Build a 1D histogram for a given variable, optionally filtered by mode and channel.
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.
void SetupKinematicMap()
Ensure Kinematic Map is setup and make sure it is initialised correctly.
std::vector< std::vector< KinematicCut > > StoredSelection
DB Vectors to store which kinematic cuts we apply. Gets used in IsEventSelected Read in from sample y...
virtual void Init()=0
Initialise any variables that your experiment specific SampleHandler needs.
const TH1 * GetDataHist(const int Sample) final
Get Data histogram.
SampleHandlerBase(std::string ConfigFileName, ParameterHandlerGeneric *_ParHandler, const std::shared_ptr< OscillationHandler > &OscillatorObj_=nullptr)
Constructor.
std::string GetFlavourName(const int iSample, const int iChannel) const final
Get the flavour name for a given sample and oscillation channel.
std::unordered_map< std::string, NuPDG > FileToFinalPDGMap
Mapping from input file names to final neutrino PDG codes.
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 CheckEmptyBins() const
Loop over bins and checks if there are any which have 0 entries.
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 chain.
std::vector< std::unique_ptr< TH2 > > ReturnHistsBySelection2D(const int iSample, const std::string &KinematicProjectionX, const std::string &KinematicProjectionY, const SamplePlotType Selection1, const int Selection2=-1, const int WeightStyle=0)
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
Mapping from input file names to initial neutrino PDG codes.
void SetSplinePointers()
Set pointers for each event to appropriate weights, for unbinned based on event number while for binn...
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.
bool UpdateW2
KS:Super hacky to update W2 or not.
const std::unordered_map< int, std::string > * ReversedKinematicVectors
std::string GetSampleName(const int iSample) const
Sample name tag used only for getting relevant uncertainties.
void Fill1DSubEventHist(const int iSample, TH1D *_h1DVar, const std::string &ProjectionVar, const std::vector< KinematicCut > &SubEventSelectionVec={}, int WeightStyle=0)
Fill projection histogram by looping over all events, and skipping one which doesn't pass specified c...
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 CalcWeightFunc([[maybe_unused]] const int iEvent)
Calculate weights for function parameters.
unsigned int GetNEvents() const
Return total number of events.
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 conveniently setup everything ...
M3::detail::Functional functional
Helper object for storing/updating information related to functional shift parameters.
virtual void RegisterFunctionalParameters()
HH - a experiment-specific function where the maps to actual functions are set up.
double GetSampleLikelihood(const int iSample) const override
Get likelihood (-logL) for a single sample.
void SetupReweightArrays()
Initialise data, MC and W2 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)
Fill projection histogram by looping over all events, and skipping one which doesn't pass specified c...
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()
Functions which find the nominal bin and bin edges.
const M3::float_t * GetNuOscillatorPointers(const int iEvent) const
Get pointer to NuOscillator weight for a given event.
std::string GetName() const final
Get name for Sample Handler.
virtual void FinaliseShifts([[maybe_unused]] const int iEvent)
LP - Optionally calculate derived observables after all shifts have been applied.
std::vector< SplineIndex > GetSplineBins(int Event, BinnedSplineHandler *BinnedSpline, bool &ThrowCrititcal) const
Retrieve the spline bin indices associated with a given event.
virtual void ResetShifts([[maybe_unused]] const int iEvent)
HH - reset the shifted values to the original values.
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...
TLegend * THStackLeg
DB: Legend associated with stacked histograms produced by this class.
void AddData(const int Sample, TH1 *Data)
DB: Add data for a given sample from a ROOT histogram.
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 SamplePlotType Selection1, const int Selection2=-1, const int WeightStyle=0)
double GetLikelihood() const override
Return likelihood (-LogL) for all samples.
unsigned int nEvents
Number of MC events are there.
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::vector< std::unique_ptr< TH1 > > ReturnHistsBySelection1D(const int iSample, const std::string &KinematicProjection, const SamplePlotType Selection1, const int Selection2=-1, const int WeightStyle=0)
void CalcNormsBins(std::vector< std::vector< NormParameter >> &norm_parameters, std::vector< std::vector< int > > &norms_bins)
Check whether a normalisation systematic affects an event or not.
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
Build a 2D projection of MC events into specified variables.
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.
std::vector< double > SampleHandler_array_w2
KS Array used for MC stat.
int GetRangeForPlotType(const SamplePlotType TypeEnum, const int iSample) const
KS: Return range for plot type, for example number of modes, osc channels etc.
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 param handler 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
Build a 2D histogram for given variables, optionally filtered by mode and channel.
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
Return 1D projection of MC into given 1D variable (doesn't have to be variable used in the fit)
void SetupOscParameters()
Setup the osc parameters.
int ReturnKinematicParameterFromString(const std::string &KinematicStr) const
ETA function to generically convert a string from param handler 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.
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.
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. This assumes that oscillation weights have already been cal...
std::string GetSampleTitle(const int iSample) const final
Get fancy title for specified samples.
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.
virtual M3::int_t GetNSamples()
returns total number of samples
std::unique_ptr< MaCh3Modes > Modes
Holds information about used Generator and MaCh3 modes.
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::string join(const Container &values, std::string_view separator=" ")
Join all values in a container into a single string.
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.
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.
std::vector< Shift > shifts
std::vector< std::vector< int > > event_shifts
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::string SampleName
tag for sample used to easily set by which uncertainties should be affected
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" used for printing
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