5 #include "TStopwatch.h"
7 #include "TGraphAsymmErrors.h"
10 #pragma GCC diagnostic ignored "-Wuseless-cast"
19 random = std::make_unique<TRandom3>(Get<int>(
fitMan->
raw()[
"General"][
"Seed"], __FILE__, __LINE__));
26 clock = std::make_unique<TStopwatch>();
27 stepClock = std::make_unique<TStopwatch>();
30 debug = GetFromManager<bool>(
fitMan->
raw()[
"General"][
"Debug"],
false, __FILE__ , __LINE__);
33 auto outfile = Get<std::string>(
fitMan->
raw()[
"General"][
"OutputFile"], __FILE__ , __LINE__);
36 auto_save = Get<int>(
fitMan->
raw()[
"General"][
"MCMC"][
"AutoSave"], __FILE__ , __LINE__);
42 outTree =
new TTree(
"posteriors",
"Posterior_Distributions");
58 if (debug) debugFile.open((outfile+
".log").c_str());
62 fTestLikelihood = GetFromManager<bool>(
fitMan->
raw()[
"General"][
"Fitter"][
"FitTestLikelihood"],
false, __FILE__ , __LINE__);
83 TDirectory* MaCh3Version =
outputFile->mkdir(
"MaCh3Engine");
86 if (std::getenv(
"MaCh3_ROOT") ==
nullptr) {
92 if (std::getenv(
"MACH3") ==
nullptr) {
97 std::string header_path = std::string(std::getenv(
"MACH3"));
98 header_path +=
"/version.h";
99 FILE* file = fopen(header_path.c_str(),
"r");
102 header_path = std::string(std::getenv(
"MaCh3_ROOT"));
103 header_path +=
"/version.h";
109 TMacro versionHeader(
"version_header",
"version_header");
110 versionHeader.ReadFile(header_path.c_str());
111 versionHeader.Write();
119 Engine.Write(
GetName().c_str());
121 MaCh3Version->Write();
133 for(
unsigned int i = 0; i <
systematics.size(); ++i)
136 for(
unsigned int i = 0; i <
samples.size(); ++i) {
138 for(
int iSam = 0; iSam <
samples[i]->GetNSamples(); ++iSam) {
139 MACH3LOG_INFO(
" {}: Sample name: {}, with {} osc channels",iSam ,
samples[i]->GetSampleTitle(iSam),
samples[i]->GetNOscChannels(iSam));
164 bool SaveProposal = GetFromManager<bool>(
fitMan->
raw()[
"General"][
"SaveProposal"],
false, __FILE__ , __LINE__);
166 if(SaveProposal)
MACH3LOG_INFO(
"Will save in the chain proposal parameters and LogL");
169 cov->SetBranches(*
outTree, SaveProposal);
183 for (
size_t i = 0; i <
samples.size(); ++i) {
184 std::stringstream oss, oss2;
185 oss <<
"LogL_sample_" << i;
186 oss2 << oss.str() <<
"/D";
191 std::stringstream oss, oss2;
192 oss <<
"LogL_systematic_" <<
systematics[i]->GetName();
193 oss2 << oss.str() <<
"/D";
205 MACH3LOG_INFO(
"-------------------- Starting MCMC --------------------");
208 debugFile <<
"----- Starting MCMC -----" << std::endl;
223 for (
size_t i = 0; i <
samples.size(); ++i) {
224 samples[i]->CleanMemoryBeforeFit();
236 int originalErrorLevel = gErrorIgnoreLevel;
237 gErrorIgnoreLevel = kFatal;
247 debugFile <<
"\n\n" <<
step <<
" steps took " <<
clock->RealTime() <<
" seconds to complete. (" <<
clock->RealTime() /
step <<
"s / step).\n" <<
accCount<<
" steps were accepted." << std::endl;
255 gErrorIgnoreLevel = originalErrorLevel;
263 for (
const auto &s :
samples) {
264 for (
int iExisting = 0; iExisting < s->GetNSamples(); ++iExisting) {
265 for (
int iNew = 0; iNew < sample->
GetNSamples(); ++iNew) {
266 if (s->GetSampleTitle(iExisting) == sample->
GetSampleTitle(iNew)) {
268 "Duplicate sample title '{}' in handler {} detected: "
270 sample->
GetName(), s->GetName());
277 for (
const auto &s :
samples) {
278 if (s->GetName() == sample->
GetName()) {
302 for (
int iPar = 0; iPar <
systematics[s]->GetNumParams(); ++iPar)
307 MACH3LOG_ERROR(
"ParameterHandler {} has param '{}' which already exists in in {}, with name {}",
313 MACH3LOG_ERROR(
"ParameterHandler {} has param '{}' which already exists in {}, with name {}",
331 CorrMatrix->Write((cov->
GetName() + std::string(
"_Corr")).c_str());
349 TFile *infile =
M3::Open(FitName,
"READ", __FILE__, __LINE__);
350 TTree *posts = infile->Get<TTree>(
"posteriors");
351 unsigned int step_val = 0;
353 posts->SetBranchAddress(
"step",&step_val);
354 posts->SetBranchAddress(
"LogL",&log_val);
358 TDirectory* CovarianceFolder = infile->Get<TDirectory>(
"CovarianceFolder");
360 std::string ConfigName =
"Config_" +
systematics[s]->GetName();
361 TMacro *ConfigCov = CovarianceFolder->Get<TMacro>(ConfigName.c_str());
363 if (ConfigCov !=
nullptr) {
367 YAML::Node ConfigCurrent =
systematics[s]->GetConfig();
371 MACH3LOG_ERROR(
"Yaml configs in previous chain (from path {}) and current one are different", FitName);
377 CovarianceFolder->Close();
378 delete CovarianceFolder;
380 std::vector<double> branch_vals;
381 std::vector<std::string> branch_name;
382 systematics[s]->MatchMaCh3OutputBranches(posts, branch_vals, branch_name);
383 posts->GetEntry(posts->GetEntries()-1);
392 for (
int i = 0; i <
systematics[s]->GetNumParams(); ++i) {
393 posts->SetBranchAddress(
systematics[s]->GetParName(i).c_str(),
nullptr);
413 if (
fitMan ==
nullptr)
return;
416 if (GetFromManager<bool>(
fitMan->
raw()[
"General"][
"ProcessMCMC"],
false, __FILE__ , __LINE__)){
422 TVectorD *Central =
nullptr;
423 TVectorD *Errors =
nullptr;
424 TVectorD *Central_Gauss =
nullptr;
425 TVectorD *Errors_Gauss =
nullptr;
426 TVectorD *Peaks =
nullptr;
429 Processor.
GetPostfit(Central, Errors, Central_Gauss, Errors_Gauss, Peaks);
433 TMatrixDSym *Covariance =
nullptr;
434 TMatrixDSym *Correlation =
nullptr;
444 MACH3LOG_INFO(
"Opening output again to update with means..");
445 outputFile =
new TFile(Get<std::string>(
fitMan->
raw()[
"General"][
"OutputFile"], __FILE__, __LINE__).c_str(),
"UPDATE");
447 Central->Write(
"PDF_Means");
448 Errors->Write(
"PDF_Errors");
449 Central_Gauss->Write(
"Gauss_Means");
450 Errors_Gauss->Write(
"Errors_Gauss");
451 Covariance->Write(
"Covariance");
452 Correlation->Write(
"Correlation");
464 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs)
466 TStopwatch clockRace;
468 for(
int Lap = 0; Lap < NLaps; ++Lap) {
472 MACH3LOG_INFO(
"It took {:.4f} s to reweights {} times sample: {}", clockRace.RealTime(), NLaps,
samples[ivs]->GetName());
473 MACH3LOG_INFO(
"On average {:.6f}", clockRace.RealTime()/NLaps);
476 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs)
478 TStopwatch clockRace;
480 for(
int Lap = 0; Lap < NLaps; ++Lap) {
484 MACH3LOG_INFO(
"It took {:.4f} s to calculate GetLikelihood {} times sample: {}", clockRace.RealTime(), NLaps,
samples[ivs]->GetName());
485 MACH3LOG_INFO(
"On average {:.6f}", clockRace.RealTime()/NLaps);
488 std::vector<std::vector<double>> StepsValuesBefore(
systematics.size());
490 StepsValuesBefore[s] =
systematics[s]->GetProposed();
493 TStopwatch clockRace;
495 for(
int Lap = 0; Lap < NLaps; ++Lap) {
499 MACH3LOG_INFO(
"It took {:.4f} s to propose step {} times cov: {}", clockRace.RealTime(), NLaps,
systematics[s]->GetName());
500 MACH3LOG_INFO(
"On average {:.6f}", clockRace.RealTime()/NLaps);
503 systematics[s]->SetParameters(StepsValuesBefore[s]);
507 TStopwatch clockRace;
509 for(
int Lap = 0; Lap < NLaps; ++Lap) {
513 MACH3LOG_INFO(
"It took {:.4f} s to calculate get likelihood {} times cov: {}", clockRace.RealTime(), NLaps,
systematics[s]->GetName());
514 MACH3LOG_INFO(
"On average {:.6f}", clockRace.RealTime()/NLaps);
522 bool isScanRanges =
false;
524 if(
fitMan->
raw()[
"LLHScan"][
"ScanRanges"]){
525 YAML::Node scanRangesList =
fitMan->
raw()[
"LLHScan"][
"ScanRanges"];
526 for (
auto it = scanRangesList.begin(); it != scanRangesList.end(); ++it) {
527 std::string itname = it->first.as<std::string>();
528 std::vector<double> itrange = it->second.as<std::vector<double>>();
530 scanRanges[itname] = itrange;
534 MACH3LOG_INFO(
"There are no user-defined parameter ranges, so I'll use default param bounds for LLH Scans");
543 for(
unsigned int is = 0; is < SkipVector.size(); ++is)
545 if(ParamName.substr(0, SkipVector[is].length()) == SkipVector[is])
557 double& lower,
double& upper,
const int n_points,
const std::string& suffix)
const {
560 std::map<std::string, std::vector<double>> scanRanges;
563 double nSigma = GetFromManager<int>(
fitMan->
raw()[
"LLHScan"][
"LLHScanSigma"], 1., __FILE__, __LINE__);
564 bool IsPCA = cov->
IsPCA();
568 if (IsPCA) name +=
"_PCA";
577 if (std::abs(CentralValue - prior) > 1e-10) {
578 MACH3LOG_INFO(
"For {} scanning around value {} rather than prior {}", name, CentralValue, prior);
601 auto it = scanRanges.find(name);
602 if (it != scanRanges.end() && it->second.size() == 2) {
603 lower = it->second[0];
604 upper = it->second[1];
605 MACH3LOG_INFO(
"Found matching param name for setting specified range for {}", name);
606 MACH3LOG_INFO(
"Range for {} = [{:.2f}, {:.2f}]", name, lower, upper);
614 MACH3LOG_INFO(
"Scanning {} {} with {} steps, from [{:.2f} , {:.2f}], CV = {:.2f}", suffix, name, n_points, lower, upper, CentralValue);
627 bool PlotLLHScanBySample = GetFromManager<bool>(
fitMan->
raw()[
"LLHScan"][
"LLHScanBySample"],
false, __FILE__ , __LINE__);
628 auto SkipVector = GetFromManager<std::vector<std::string>>(
fitMan->
raw()[
"LLHScan"][
"LLHScanSkipVector"], {}, __FILE__ , __LINE__);
632 std::vector<TDirectory *> Cov_LLH(
systematics.size());
633 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc )
635 std::string NameTemp =
systematics[ivc]->GetName();
636 NameTemp = NameTemp.substr(0, NameTemp.find(
"_cov")) +
"_LLH";
637 Cov_LLH[ivc] =
outputFile->mkdir(NameTemp.c_str());
640 std::vector<TDirectory *> SampleClass_LLH(
samples.size());
641 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
643 std::string NameTemp =
samples[ivs]->GetName();
644 SampleClass_LLH[ivs] =
outputFile->mkdir(NameTemp.c_str());
647 TDirectory *Sample_LLH =
outputFile->mkdir(
"Sample_LLH");
648 TDirectory *Total_LLH =
outputFile->mkdir(
"Total_LLH");
650 std::vector<TDirectory *>SampleSplit_LLH;
651 if(PlotLLHScanBySample)
654 int SampleIterator = 0;
655 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
657 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is )
659 SampleSplit_LLH[SampleIterator] =
outputFile->mkdir((
samples[ivs]->GetSampleTitle(is)+
"_LLH").c_str());
665 const int n_points = GetFromManager<int>(
fitMan->
raw()[
"LLHScan"][
"LLHScanPoints"], 100, __FILE__ , __LINE__);
668 const int countwidth = int(
double(n_points)/
double(5));
675 int npars = cov->GetNumParams();
676 bool IsPCA = cov->IsPCA();
677 if (IsPCA) npars = cov->GetNParameters();
678 for (
int i = 0; i < npars; ++i)
681 std::string name = cov->GetParFancyName(i);
682 if (IsPCA) name +=
"_PCA";
686 double CentralValue, lower, upper;
689 auto hScan = std::make_unique<TH1D>((name +
"_full").c_str(), (name +
"_full").c_str(), n_points, lower, upper);
690 hScan->SetTitle((std::string(
"2LLH_full, ") + name +
";" + name +
"; -2(ln L_{sample} + ln L_{xsec+flux} + ln L_{det})").c_str());
691 hScan->SetDirectory(
nullptr);
693 auto hScanSam = std::make_unique<TH1D>((name +
"_sam").c_str(), (name +
"_sam").c_str(), n_points, lower, upper);
694 hScanSam->SetTitle((std::string(
"2LLH_sam, ") + name +
";" + name +
"; -2(ln L_{sample})").c_str());
695 hScanSam->SetDirectory(
nullptr);
697 std::vector<std::unique_ptr<TH1D>> hScanSample(
samples.size());
698 std::vector<double> nSamLLH(
samples.size(), 0.0);
699 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
701 std::string NameTemp =
samples[ivs]->GetName();
702 hScanSample[ivs] = std::make_unique<TH1D>((name+
"_"+NameTemp).c_str(), (name+
"_" + NameTemp).c_str(), n_points, lower, upper);
703 hScanSample[ivs]->SetDirectory(
nullptr);
704 hScanSample[ivs]->SetTitle((
"2LLH_" + NameTemp +
", " + name +
";" + name +
"; -2(ln L_{" + NameTemp +
"})").c_str());
707 std::vector<std::unique_ptr<TH1D>> hScanCov(
systematics.size());
708 std::vector<double> nCovLLH(
systematics.size(), 0.0);
709 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc )
711 std::string NameTemp =
systematics[ivc]->GetName();
712 NameTemp = NameTemp.substr(0, NameTemp.find(
"_cov"));
713 hScanCov[ivc] = std::make_unique<TH1D>((name +
"_" + NameTemp).c_str(), (name +
"_" + NameTemp).c_str(), n_points, lower, upper);
714 hScanCov[ivc]->SetDirectory(
nullptr);
715 hScanCov[ivc]->SetTitle((
"2LLH_" + NameTemp +
", " + name +
";" + name +
"; -2(ln L_{" + NameTemp +
"})").c_str());
718 std::vector<std::unique_ptr<TH1D>> hScanSamSplit;
719 std::vector<double> sampleSplitllh;
720 if(PlotLLHScanBySample)
722 int SampleIterator = 0;
725 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
727 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is )
729 auto histName = name +
samples[ivs]->GetSampleTitle(is);
730 auto histTitle = std::string(
"2LLH_sam, ") + name +
";" + name +
"; -2(ln L_{sample})";
731 hScanSamSplit[SampleIterator] = std::make_unique<TH1D>(histName.c_str(), histTitle.c_str(), n_points, lower, upper);
732 hScanSamSplit[SampleIterator]->SetDirectory(
nullptr);
739 for (
int j = 0; j < n_points; ++j)
741 if (j % countwidth == 0)
746 cov->GetPCAHandler()->SetParPropPCA(i, hScan->GetBinCenter(j+1));
749 cov->SetParProp(i, hScan->GetBinCenter(j+1));
753 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs ){
757 double totalllh = 0.;
760 double samplellh = 0.;
762 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs ) {
763 nSamLLH[ivs] =
samples[ivs]->GetLikelihood();
764 samplellh += nSamLLH[ivs];
767 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc ) {
769 totalllh += nCovLLH[ivc];
772 totalllh += samplellh;
774 if(PlotLLHScanBySample)
776 int SampleIterator = 0;
777 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
779 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is)
781 sampleSplitllh[SampleIterator] =
samples[ivs]->GetSampleLikelihood(is);
787 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs ) {
788 hScanSample[ivs]->SetBinContent(j+1, 2*nSamLLH[ivs]);
790 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc ) {
791 hScanCov[ivc]->SetBinContent(j+1, 2*nCovLLH[ivc]);
794 hScanSam->SetBinContent(j+1, 2*samplellh);
795 hScan->SetBinContent(j+1, 2*totalllh);
797 if(PlotLLHScanBySample)
799 int SampleIterator = 0;
800 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
802 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is)
804 hScanSamSplit[SampleIterator]->SetBinContent(j+1, 2*sampleSplitllh[SampleIterator]);
810 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc )
813 hScanCov[ivc]->Write();
816 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
818 SampleClass_LLH[ivs]->cd();
819 hScanSample[ivs]->Write();
826 if(PlotLLHScanBySample)
828 int SampleIterator = 0;
829 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
831 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is)
833 SampleSplit_LLH[SampleIterator]->cd();
834 hScanSamSplit[SampleIterator]->Write();
842 cov->GetPCAHandler()->SetParPropPCA(i, CentralValue);
844 cov->SetParProp(i, CentralValue);
849 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc )
851 Cov_LLH[ivc]->Write();
855 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
857 SampleClass_LLH[ivs]->Write();
858 delete SampleClass_LLH[ivs];
867 if(PlotLLHScanBySample)
869 int SampleIterator = 0;
870 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
872 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is )
874 SampleSplit_LLH[SampleIterator]->Write();
875 delete SampleSplit_LLH[SampleIterator];
886 TFile* outputFileLLH =
nullptr;
887 bool ownsfile =
false;
888 if(outputFileName !=
""){
889 outputFileLLH =
M3::Open(outputFileName,
"READ", __FILE__, __LINE__);
894 TDirectory *Sample_LLH = outputFileLLH->Get<TDirectory>(
"Sample_LLH");
897 if(!Sample_LLH || Sample_LLH->IsZombie())
899 MACH3LOG_WARN(
"Couldn't find Sample_LLH, it looks like LLH scan wasn't run, will do this now");
901 Sample_LLH = outputFileLLH->Get<TDirectory>(
"Sample_LLH");
906 const int npars = cov->GetNumParams();
907 std::vector<double> StepScale(npars);
908 for (
int i = 0; i < npars; ++i)
910 std::string name = cov->GetParFancyName(i);
911 StepScale[i] = cov->GetIndivStepScale(i);
912 TH1D* LLHScan = Sample_LLH->Get<TH1D>((name+
"_sam").c_str());
913 if(LLHScan ==
nullptr)
915 MACH3LOG_WARN(
"Couldn't find LLH scan, for {}, skipping", name);
918 const double LLH_val = std::max(LLHScan->GetBinContent(1), LLHScan->GetBinContent(LLHScan->GetNbinsX()));
920 if(LLH_val < 0.001)
continue;
925 const double Var = 1.;
926 const double approxSigma = std::abs(Var)/std::sqrt(LLH_val);
927 const double GlobalScale = cov->GetGlobalStepScale();
929 const double TargetStep = approxSigma * 2.38 / std::sqrt(npars);
931 const double NewStepScale = TargetStep / GlobalScale;
933 StepScale[i] = NewStepScale;
935 MACH3LOG_DEBUG(
"Target Step Size (before accounting for global step size): {}", TargetStep);
938 cov->SetIndivStepScale(StepScale);
939 cov->SaveUpdatedMatrixConfig();
941 if(ownsfile && outputFileLLH !=
nullptr)
delete outputFileLLH;
953 TDirectory *Sample_2DLLH =
outputFile->mkdir(
"Sample_2DLLH");
954 auto SkipVector = GetFromManager<std::vector<std::string>>(
fitMan->
raw()[
"LLHScan"][
"LLHScanSkipVector"], {}, __FILE__ , __LINE__);;
957 const int n_points = GetFromManager<int>(
fitMan->
raw()[
"LLHScan"][
"2DLLHScanPoints"], 20, __FILE__ , __LINE__);
959 const int countwidth = int(
double(n_points)/
double(5));
966 int npars = cov->GetNumParams();
967 bool IsPCA = cov->IsPCA();
968 if (IsPCA) npars = cov->GetNParameters();
970 for (
int i = 0; i < npars; ++i)
972 std::string name_x = cov->GetParFancyName(i);
973 if (IsPCA) name_x +=
"_PCA";
975 double central_x, lower_x, upper_x;
981 for (
int j = 0; j < i; ++j)
983 std::string name_y = cov->GetParFancyName(j);
984 if (IsPCA) name_y +=
"_PCA";
989 double central_y, lower_y, upper_y;
992 auto hScanSam = std::make_unique<TH2D>((name_x +
"_" + name_y +
"_sam").c_str(), (name_x +
"_" + name_y +
"_sam").c_str(),
993 n_points, lower_x, upper_x, n_points, lower_y, upper_y);
994 hScanSam->SetDirectory(
nullptr);
995 hScanSam->GetXaxis()->SetTitle(name_x.c_str());
996 hScanSam->GetYaxis()->SetTitle(name_y.c_str());
997 hScanSam->GetZaxis()->SetTitle(
"2LLH_sam");
1000 for (
int x = 0; x < n_points; ++x)
1002 if (x % countwidth == 0)
1005 for (
int y = 0; y < n_points; ++y)
1009 cov->GetPCAHandler()->SetParPropPCA(i, hScanSam->GetXaxis()->GetBinCenter(x+1));
1010 cov->GetPCAHandler()->SetParPropPCA(j, hScanSam->GetYaxis()->GetBinCenter(y+1));
1013 cov->SetParProp(i, hScanSam->GetXaxis()->GetBinCenter(x+1));
1014 cov->SetParProp(j, hScanSam->GetYaxis()->GetBinCenter(y+1));
1017 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs) {
1022 double samplellh = 0;
1023 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs) {
1024 samplellh +=
samples[ivs]->GetLikelihood();
1026 hScanSam->SetBinContent(x+1, y+1, 2*samplellh);
1034 cov->GetPCAHandler()->SetParPropPCA(i, central_x);
1035 cov->GetPCAHandler()->SetParPropPCA(j, central_y);
1037 cov->SetParProp(i, central_x);
1038 cov->SetParProp(j, central_y);
1043 Sample_2DLLH->Write();
1044 delete Sample_2DLLH;
1057 bool PlotLLHScanBySample = GetFromManager<bool>(
fitMan->
raw()[
"LLHScan"][
"LLHScanBySample"],
false, __FILE__ , __LINE__);
1058 auto ParamsOfInterest = GetFromManager<std::vector<std::string>>(
fitMan->
raw()[
"LLHScan"][
"LLHParameters"], {}, __FILE__, __LINE__);
1060 if(ParamsOfInterest.empty()) {
1061 MACH3LOG_WARN(
"There were no LLH parameters of interest specified to run the LLHMap! LLHMap will not run at all ...");
1067 std::vector<std::tuple<std::string, ParameterHandlerBase*, int>> ParamsCovIDs;
1068 for(
auto& p : ParamsOfInterest) {
1071 for(
int c = 0; c < cov->GetNumParams(); ++c) {
1072 if(cov->GetParName(c) == p || cov->GetParFancyName(c) == p) {
1074 for(
auto& pc : ParamsCovIDs) {
1075 if(std::get<1>(pc) == cov && std::get<2>(pc) == c)
1077 MACH3LOG_WARN(
"Parameter {} as {}({}) listed multiple times for LLHMap, omitting and using only once!", p, cov->GetName(), c);
1084 ParamsCovIDs.push_back(std::make_tuple(p, cov, c));
1094 MACH3LOG_INFO(
"Parameter {} found in {} at an index {}.", p, std::get<1>(ParamsCovIDs.back())->GetName(), std::get<2>(ParamsCovIDs.back()));
1096 MACH3LOG_WARN(
"Parameter {} not found in any of the systematic covariance objects. Will not scan over this one!", p);
1100 std::map<std::string, std::pair<int, std::pair<double, double>>> ParamsRanges;
1102 MACH3LOG_INFO(
"======================================================================================");
1103 MACH3LOG_INFO(
"Performing a general multi-dimensional LogL map scan over following parameters ranges:");
1104 MACH3LOG_INFO(
"======================================================================================");
1105 unsigned long TotalPoints = 1;
1107 double nSigma = GetFromManager<int>(
fitMan->
raw()[
"LLHScan"][
"LLHScanSigma"], 1., __FILE__, __LINE__);
1112 for(
auto& p : ParamsCovIDs) {
1114 std::string name = std::get<0>(p);
1115 int i = std::get<2>(p);
1118 ParamsRanges[name].first = GetFromManager<int>(
fitMan->
raw()[
"LLHScan"][
"LLHScanPoints"], 20, __FILE__, __LINE__);
1120 ParamsRanges[name].first = GetFromManager<int>(
fitMan->
raw()[
"LLHScan"][
"ScanPoints"][name], ParamsRanges[name].first, __FILE__, __LINE__);
1125 bool IsPCA = cov->
IsPCA();
1133 if (std::abs(CentralValue - prior) > 1e-10) {
1134 MACH3LOG_INFO(
"For {} scanning around value {} rather than prior {}", name, CentralValue, prior);
1152 ParamsRanges[name].second = {lower,upper};
1155 ParamsRanges[name].second = GetFromManager<std::pair<double,double>>(
fitMan->
raw()[
"LLHScan"][
"ScanRanges"][name], ParamsRanges[name].second, __FILE__, __LINE__);
1157 MACH3LOG_INFO(
"{} from {:.4f} to {:.4f} with a {:.5f} step ({} points total)",
1158 name, ParamsRanges[name].second.first, ParamsRanges[name].second.second,
1159 (ParamsRanges[name].second.second - ParamsRanges[name].second.first)/(ParamsRanges[name].first - 1.),
1160 ParamsRanges[name].first);
1162 TotalPoints *= ParamsRanges[name].first;
1166 MACH3LOG_INFO(
"In total, looping over {} points, from {} parameters. Estimates for run time:", TotalPoints, ParamsCovIDs.size());
1167 MACH3LOG_INFO(
" 1 s per point = {} hours",
double(TotalPoints)/3600.);
1168 MACH3LOG_INFO(
" 0.1 s per point = {} hours",
double(TotalPoints)/36000.);
1169 MACH3LOG_INFO(
"0.01 s per point = {} hours",
double(TotalPoints)/360000.);
1170 MACH3LOG_INFO(
"==================================================================================");
1172 const int countwidth = int(
double(TotalPoints)/
double(20));
1175 auto LLHMap =
new TTree(
"llhmap",
"LLH Map");
1178 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc )
1180 std::string NameTemp =
systematics[ivc]->GetName();
1181 NameTemp = NameTemp.substr(0, NameTemp.find(
"_cov")) +
"_LLH";
1182 LLHMap->Branch(NameTemp.c_str(), &CovLogL[ivc]);
1185 std::vector<double> SampleClassLogL(
samples.size());
1186 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
1188 std::string NameTemp =
samples[ivs]->GetName()+
"_LLH";
1189 LLHMap->Branch(NameTemp.c_str(), &SampleClassLogL[ivs]);
1192 double SampleLogL, TotalLogL;
1193 LLHMap->Branch(
"Sample_LLH", &SampleLogL);
1194 LLHMap->Branch(
"Total_LLH", &TotalLogL);
1196 std::vector<double>SampleSplitLogL;
1197 if(PlotLLHScanBySample)
1200 int SampleIterator = 0;
1201 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
1203 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is )
1205 std::string NameTemp =
samples[ivs]->GetSampleTitle(is)+
"_LLH";
1206 LLHMap->Branch(NameTemp.c_str(), &SampleSplitLogL[SampleIterator]);
1212 std::vector<double> ParamsValues(ParamsCovIDs.size());
1213 for(
unsigned int i=0; i < ParamsCovIDs.size(); ++i)
1214 LLHMap->Branch(std::get<0>(ParamsCovIDs[i]).c_str(), &ParamsValues[i]);
1218 std::vector<unsigned long> idx(ParamsCovIDs.size(), 0);
1221 for(
unsigned long sp = 0; sp < TotalPoints; ++sp)
1224 for(
unsigned int n = 0; n < ParamsCovIDs.size(); ++n)
1227 std::string name = std::get<0>(ParamsCovIDs[n]);
1228 int points = ParamsRanges[name].first;
1229 double low = ParamsRanges[name].second.first;
1230 double high = ParamsRanges[name].second.second;
1233 unsigned long dev = 1;
1234 for(
unsigned int m = 0; m <= n; ++m)
1235 dev *= ParamsRanges[std::get<0>(ParamsCovIDs[m])].first;
1239 idx[n] = idx[n] / ( dev / points );
1242 ParamsValues[n] = low + (high-low) *
double(idx[n])/double(points-1);
1247 int i = std::get<2>(ParamsCovIDs[n]);
1259 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs)
1262 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs)
1264 SampleClassLogL[ivs] = 2.*
samples[ivs]->GetLikelihood();
1265 SampleLogL += SampleClassLogL[ivs];
1267 TotalLogL += SampleLogL;
1270 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc )
1272 CovLogL[ivc] = 2.*
systematics[ivc]->GetLikelihood();
1273 TotalLogL += CovLogL[ivc];
1276 if(PlotLLHScanBySample)
1278 int SampleIterator = 0;
1279 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
1281 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is)
1283 SampleSplitLogL[SampleIterator] = 2.*
samples[ivs]->GetSampleLikelihood(is);
1291 if (sp % countwidth == 0)
1303 if(!
fitMan->
raw()[
"SigmaVar"][
"CustomRange"])
return;
1305 auto Config =
fitMan->
raw()[
"SigmaVar"][
"CustomRange"];
1307 const auto sigmaStr = std::to_string(
static_cast<int>(std::round(sigma)));
1309 if (Config[ParName] && Config[ParName][sigmaStr]) {
1310 ParamShiftValue = Config[ParName][sigmaStr].as<
double>();
1311 MACH3LOG_INFO(
" ::: setting custom range from config ::: {} -> {}", ParName, ParamShiftValue);
1320 hist->SetTitle(baseName.c_str());
1322 TString className = hist->ClassName();
1325 if (className.Contains(
"TH1")) {
1326 hist->GetYaxis()->SetTitle(
"Events");
1327 }
else if (className.Contains(
"TH2")) {
1328 hist->GetZaxis()->SetTitle(
"Events");
1330 hist->Write(baseName.c_str());
1336 const std::string& suffix,
1338 const bool by_channel,
1339 const std::vector<TDirectory*>& SampleDir) {
1342 for (
int iSample = 0; iSample < sample->
GetNSamples(); ++iSample) {
1343 SampleDir[iSample]->cd();
1345 for(
int iDim1 = 0; iDim1 < sample->
GetNDim(iSample); iDim1++) {
1346 std::string ProjectionName = sample->
GetKinVarName(iSample, iDim1);
1347 std::string ProjectionSuffix =
"_1DProj" + std::to_string(iDim1);
1351 for (
int iMode = 0; iMode < modes->
GetNModes(); ++iMode) {
1358 for (
int iChan = 0; iChan < sample->
GetNOscChannels(iSample); ++iChan) {
1364 if (by_mode && by_channel) {
1365 for (
int iMode = 0; iMode < modes->
GetNModes(); ++iMode) {
1366 for (
int iChan = 0; iChan < sample->
GetNOscChannels(iSample); ++iChan) {
1373 if (!by_mode && !by_channel) {
1374 auto hist = sample->
Get1DVarHist(iSample, ProjectionName);
1377 for (
int iDim2 = iDim1 + 1; iDim2 < sample->
GetNDim(iSample); ++iDim2) {
1379 std::string XVarName = sample->
GetKinVarName(iSample, iDim1);
1380 std::string YVarName = sample->
GetKinVarName(iSample, iDim2);
1383 auto hist2D = sample->
Get2DVarHist(iSample, XVarName, YVarName);
1386 std::string suffix2D =
"_2DProj_" + std::to_string(iDim1) +
"_vs_" + std::to_string(iDim2) + suffix;
1400 bool plot_by_mode = GetFromManager<bool>(
fitMan->
raw()[
"SigmaVar"][
"PlotByMode"],
false);
1401 bool plot_by_channel = GetFromManager<bool>(
fitMan->
raw()[
"SigmaVar"][
"PlotByChannel"],
false);
1402 auto SkipVector = GetFromManager<std::vector<std::string>>(
fitMan->
raw()[
"SigmaVar"][
"SkipVector"], {}, __FILE__ , __LINE__);
1404 if (plot_by_mode)
MACH3LOG_INFO(
"Plotting by sample and mode");
1405 if (plot_by_channel)
MACH3LOG_INFO(
"Plotting by sample and channel");
1406 if (!plot_by_mode && !plot_by_channel)
MACH3LOG_INFO(
"Plotting by sample only");
1407 if (plot_by_mode && plot_by_channel)
MACH3LOG_INFO(
"Plotting by sample, mode and channel");
1409 auto SigmaArray = GetFromManager<std::vector<double>>(
fitMan->
raw()[
"SigmaVar"][
"SigmaArray"], {-3, -1, 0, 1, 3}, __FILE__ , __LINE__);
1410 if (std::find(SigmaArray.begin(), SigmaArray.end(), 0.0) == SigmaArray.end()) {
1411 MACH3LOG_ERROR(
":: SigmaArray does not contain 0! Current contents: {} ::", fmt::join(SigmaArray,
", "));
1415 TDirectory* SigmaDir =
outputFile->mkdir(
"SigmaVar");
1420 for(
int i = 0; i <
systematics[s]->GetNumParams(); i++)
1422 std::string ParName =
systematics[s]->GetParFancyName(i);
1428 TDirectory* ParamDir = SigmaDir->mkdir(ParName.c_str());
1431 const double ParamCentralValue =
systematics[s]->GetParProp(i);
1432 const double Prior =
systematics[s]->GetParInit(i);
1433 const double ParamLower =
systematics[s]->GetLowerBound(i);
1434 const double ParamUpper =
systematics[s]->GetUpperBound(i);
1436 if (std::abs(ParamCentralValue - Prior) > 1e-10) {
1437 MACH3LOG_INFO(
"For {} scanning around value {} rather than prior {}", ParName, ParamCentralValue, Prior);
1440 for(
unsigned int iSample = 0; iSample <
samples.size(); ++iSample)
1442 auto* MaCh3Sample =
samples[iSample];
1443 std::vector<TDirectory*> SampleDir(MaCh3Sample->GetNSamples());
1444 for (
int SampleIndex = 0; SampleIndex < MaCh3Sample->GetNSamples(); ++SampleIndex) {
1445 SampleDir[SampleIndex] = ParamDir->mkdir(MaCh3Sample->GetSampleTitle(SampleIndex).c_str());
1448 for (
size_t j = 0; j < SigmaArray.size(); ++j) {
1449 double sigma = SigmaArray[j];
1451 double ParamShiftValue = ParamCentralValue + sigma * std::sqrt((*
systematics[s]->GetCovMatrix())(i,i));
1452 ParamShiftValue = std::max(std::min(ParamShiftValue, ParamUpper), ParamLower);
1457 MACH3LOG_INFO(
" - set to {:<5.2f} ({:<2} sigma shift)", ParamShiftValue, sigma);
1460 std::ostringstream valStream;
1461 valStream << std::fixed << std::setprecision(2) << ParamShiftValue;
1462 std::string valueStr = valStream.str();
1464 std::ostringstream sigmaStream;
1465 sigmaStream << std::fixed << std::setprecision(2) << std::abs(sigma);
1466 std::string sigmaStr = sigmaStream.str();
1470 suffix =
"_" + ParName +
"_nom_val_" + valueStr;
1472 std::string sign = (sigma > 0) ?
"p" :
"n";
1473 suffix =
"_" + ParName +
"_sig_" + sign + sigmaStr +
"_val_" + valueStr;
1477 MaCh3Sample->Reweight();
1481 for (
int subSampleIndex = 0; subSampleIndex < MaCh3Sample->GetNSamples(); ++subSampleIndex) {
1482 SampleDir[subSampleIndex]->Close();
1483 delete SampleDir[subSampleIndex];
1489 MACH3LOG_INFO(
" - set back to CV {:<5.2f}", ParamCentralValue);
#define _MaCh3_Safe_Include_Start_
KS: Avoiding warning checking for headers.
#define _MaCh3_Safe_Include_End_
void WriteHistogramsByMode(SampleHandlerInterface *sample, const std::string &suffix, const bool by_mode, const bool by_channel, const std::vector< TDirectory * > &SampleDir)
Generic histogram writer - should make main code more palatable.
void WriteHistograms(TH1 *hist, const std::string &baseName)
Helper to write histograms.
#define MACH3LOG_CRITICAL
std::vector< TString > BranchNames
TMacro YAMLtoTMacro(const YAML::Node &yaml_node, const std::string &name)
Convert a YAML node to a ROOT TMacro object.
YAML::Node TMacroToYAML(const TMacro ¯o)
KS: Convert a ROOT TMacro object to a YAML node.
bool compareYAMLNodes(const YAML::Node &node1, const YAML::Node &node2, bool Mute=false)
Compare if yaml nodes are identical.
bool CheckNodeExists(const YAML::Node &node, Args... args)
KS: Wrapper function to call the recursive helper.
void RunLLHScan()
Perform a 1D likelihood scan.
FitterBase(Manager *const fitMan)
Constructor.
void AddSystObj(ParameterHandlerBase *cov)
This function adds a Covariance object to the analysis framework. The Covariance object will be utili...
std::string GetName() const
Get name of class.
std::unique_ptr< TRandom3 > random
Random number.
double logLProp
proposed likelihood
bool CheckSkipParameter(const std::vector< std::string > &SkipVector, const std::string &ParamName) const
KS: Check whether we want to skip parameter using skip vector.
void ProcessMCMC()
Process MCMC output.
int accCount
counts accepted steps
bool OutputPrepared
Checks if output prepared not repeat some operations.
void SaveOutput()
Save output and close files.
TFile * outputFile
Output.
void SaveSettings()
Save the settings that the MCMC was run with.
unsigned int step
current state
void PrepareOutput()
Prepare the output file.
bool SettingsSaved
Checks if setting saved not repeat some operations.
double accProb
current acceptance prob
virtual void StartFromPreviousFit(const std::string &FitName)
Allow to start from previous fit/chain.
bool FileSaved
Checks if file saved not repeat some operations.
std::string AlgorithmName
Name of fitting algorithm that is being used.
std::vector< double > sample_llh
store the llh breakdowns
void RunSigmaVar()
Perform a 1D/2D sigma var for all samples.
std::vector< SampleHandlerInterface * > samples
Sample holder.
void GetParameterScanRange(const ParameterHandlerBase *cov, const int i, double &CentralValue, double &lower, double &upper, const int n_points, const std::string &suffix="") const
Helper function to get parameter scan range, central value.
double stepTime
Time of single step.
std::unique_ptr< TStopwatch > clock
tells global time how long fit took
Manager * fitMan
The manager for configuration handling.
unsigned int stepStart
step start, by default 0 if we start from previous chain then it will be different
bool GetScanRange(std::map< std::string, std::vector< double >> &scanRanges) const
YSP: Set up a mapping to store parameters with user-specified ranges, suggested by D....
std::unique_ptr< TStopwatch > stepClock
tells how long single step/fit iteration took
TDirectory * CovFolder
Output cov folder.
void CustomRange(const std::string &ParName, const double sigma, double &ParamShiftValue) const
For comparison with other fitting frameworks (like P-Theta) we usually have to apply different parame...
TDirectory * SampleFolder
Output sample folder.
void DragRace(const int NLaps=100)
Calculates the required time for each sample or covariance object in a drag race simulation....
void Run2DLLHScan()
Perform a 2D likelihood scan.
unsigned int TotalNSamples
Total number of samples used, single SampleHandler can store more than one analysis sample!
double logLCurr
current likelihood
void RunLLHMap()
Perform a general multi-dimensional likelihood scan.
std::vector< double > syst_llh
systematic llh breakdowns
int auto_save
auto save every N steps
bool fTestLikelihood
Necessary for some fitting algorithms like PSO.
void GetStepScaleBasedOnLLHScan(const std::string &filename="")
LLH scan is good first estimate of step scale.
virtual ~FitterBase()
Destructor for the FitterBase class.
TTree * outTree
Output tree with posteriors.
void SanitiseInputs()
Remove obsolete memory and make other checks before fit starts.
void AddSampleHandler(SampleHandlerInterface *sample)
This function adds a sample PDF object to the analysis framework. The sample PDF object will be utili...
std::vector< ParameterHandlerBase * > systematics
Systematic holder.
Class responsible for processing MCMC chains, performing diagnostics, generating plots,...
const std::vector< TString > & GetBranchNames() const
Get the vector of branch names from root file.
void Initialise()
Scan chain, what parameters we have and load information from covariance matrices.
void GetPostfit(TVectorD *&Central, TVectorD *&Errors, TVectorD *&Central_Gauss, TVectorD *&Errors_Gauss, TVectorD *&Peaks)
Get the post-fit results (arithmetic and Gaussian)
void DrawCovariance()
Draw the post-fit covariances.
void DrawPostfit()
Draw the post-fit comparisons.
void GetCovariance(TMatrixDSym *&Cov, TMatrixDSym *&Corr)
Get the post-fit covariances and correlations.
Custom exception class used throughout MaCh3.
KS: Class describing MaCh3 modes used in the analysis, it is being initialised from config.
int GetNModes() const
KS: Get number of modes, keep in mind actual number is +1 greater due to unknown category.
std::string GetMaCh3ModeName(const int Index) const
KS: Get normal name of mode, if mode not known you will get UNKNOWN_BAD.
The manager class is responsible for managing configurations and settings.
YAML::Node const & raw() const
Return config.
void SaveSettings(TFile *const OutputFile) const
Add manager useful information's to TFile, in most cases to Fitter.
double GetParPropPCA(const int i) const
Get current parameter value using PCA.
void SetParPropPCA(const int i, const double value)
Set proposed value for parameter in PCA base.
double GetPreFitValuePCA(const int i) const
Get current parameter value using PCA.
const TVectorD GetEigenValues() const
Get eigen values for all parameters, if you want for decomposed only parameters use GetEigenValuesMas...
Base class responsible for handling of systematic error parameters. Capable of using PCA or using ada...
int GetNumParams() const
Get total number of parameters.
TH2D * GetCorrelationMatrix() const
KS: Convert covariance matrix to correlation matrix and return TH2D which can be used for fancy plott...
std::string GetParName(const int i) const
Get name of parameter.
void SetParProp(const int i, const double val)
Set proposed parameter value.
double GetUpperBound(const int i) const
Get upper parameter bound in which it is physically valid.
TMatrixDSym * GetCovMatrix() const
Return covariance matrix.
std::string GetParFancyName(const int i) const
Get fancy name of the Parameter.
PCAHandler * GetPCAHandler() const
Get pointer for PCAHandler.
double GetLowerBound(const int i) const
Get lower parameter bound in which it is physically valid.
bool IsPCA() const
is PCA, can use to query e.g. LLH scans
std::string GetName() const
Get name of covariance.
M3::float_t GetParProp(const int i) const
Get proposed parameter value.
double GetParInit(const int i) const
Get prior parameter value.
double GetDiagonalError(const int i) const
Get diagonal error for ith parameter.
YAML::Node GetConfig() const
Getter to return a copy of the YAML node.
Class responsible for handling implementation of samples used in analysis, reweighting and returning ...
virtual 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)=0
Build a 1D histogram for a given variable, optionally filtered by mode and channel.
virtual std::string GetName() const =0
Get name for Sample Handler.
virtual void SaveAdditionalInfo(TDirectory *Dir)
Store additional info in a chain.
virtual 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={})=0
Return 1D projection of MC into given 1D variable (doesn't have to be variable used in the fit)
virtual std::string GetFlavourName(const int iSample, const int iChannel) const =0
Get the flavour name for a given sample and oscillation channel.
MaCh3Modes * GetMaCh3Modes() const
Return pointer to MaCh3 modes.
virtual int GetNOscChannels(const int iSample) const =0
Get number of oscillation channels for a single sample.
virtual M3::int_t GetNSamples()
returns total number of samples
virtual std::string GetSampleTitle(const int iSample) const =0
Get fancy title for specified samples.
virtual std::string GetKinVarName(const int iSample, const int Dimension) const =0
Return Kinematic Variable name for specified sample and dimension for example "Reconstructed_Neutrino...
virtual std::unique_ptr< TH2 > Get2DVarHist(const int iSample, const std::string &ProjectionVarX, const std::string &ProjectionVarY, const std::vector< KinematicCut > &EventSelectionVec={}, const int WeightStyle=0, const std::vector< KinematicCut > &SubEventSelectionVec={})=0
Build a 2D projection of MC events into specified variables.
virtual int GetNDim(const int Sample) const =0
DB Get what dimensionality binning for given sample has.
int getValue(const std::string &Type)
CW: Get info like RAM.
void PrintProgressBar(const Long64_t Done, const Long64_t All)
KS: Simply print progress bar.
constexpr static const double _LARGE_LOGL_
Large Likelihood is used it parameter go out of physical boundary, this indicates in MCMC that such s...
TFile * Open(const std::string &Name, const std::string &Type, const std::string &File, const int Line)
Opens a ROOT file with the given name and mode.
int GetNThreads()
number of threads which we need for example for TRandom3