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 title: {}, 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");
352 posts->SetBranchAddress(
"LogL",&log_val);
356 TDirectory* CovarianceFolder = infile->Get<TDirectory>(
"CovarianceFolder");
358 std::string ConfigName =
"Config_" +
systematics[s]->GetName();
359 TMacro *ConfigCov = CovarianceFolder->Get<TMacro>(ConfigName.c_str());
361 if (ConfigCov !=
nullptr) {
365 YAML::Node ConfigCurrent =
systematics[s]->GetConfig();
369 MACH3LOG_ERROR(
"Yaml configs in previous chain (from path {}) and current one are different", FitName);
375 CovarianceFolder->Close();
376 delete CovarianceFolder;
378 std::vector<double> branch_vals;
379 std::vector<std::string> branch_name;
380 systematics[s]->MatchMaCh3OutputBranches(posts, branch_vals, branch_name);
381 posts->GetEntry(posts->GetEntries()-1);
390 for (
int i = 0; i <
systematics[s]->GetNumParams(); ++i) {
391 posts->SetBranchAddress(
systematics[s]->GetParName(i).c_str(),
nullptr);
406 if (
fitMan ==
nullptr)
return;
409 if (GetFromManager<bool>(
fitMan->
raw()[
"General"][
"ProcessMCMC"],
false, __FILE__ , __LINE__)){
415 TVectorD *Central =
nullptr;
416 TVectorD *Errors =
nullptr;
417 TVectorD *Central_Gauss =
nullptr;
418 TVectorD *Errors_Gauss =
nullptr;
419 TVectorD *Peaks =
nullptr;
422 Processor.
GetPostfit(Central, Errors, Central_Gauss, Errors_Gauss, Peaks);
426 TMatrixDSym *Covariance =
nullptr;
427 TMatrixDSym *Correlation =
nullptr;
437 MACH3LOG_INFO(
"Opening output again to update with means..");
438 outputFile =
new TFile(Get<std::string>(
fitMan->
raw()[
"General"][
"OutputFile"], __FILE__, __LINE__).c_str(),
"UPDATE");
440 Central->Write(
"PDF_Means");
441 Errors->Write(
"PDF_Errors");
442 Central_Gauss->Write(
"Gauss_Means");
443 Errors_Gauss->Write(
"Errors_Gauss");
444 Covariance->Write(
"Covariance");
445 Correlation->Write(
"Correlation");
457 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs)
459 TStopwatch clockRace;
461 for(
int Lap = 0; Lap < NLaps; ++Lap) {
465 MACH3LOG_INFO(
"It took {:.4f} s to reweights {} times sample: {}", clockRace.RealTime(), NLaps,
samples[ivs]->GetName());
466 MACH3LOG_INFO(
"On average {:.6f}", clockRace.RealTime()/NLaps);
469 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs)
471 TStopwatch clockRace;
473 for(
int Lap = 0; Lap < NLaps; ++Lap) {
477 MACH3LOG_INFO(
"It took {:.4f} s to calculate GetLikelihood {} times sample: {}", clockRace.RealTime(), NLaps,
samples[ivs]->GetName());
478 MACH3LOG_INFO(
"On average {:.6f}", clockRace.RealTime()/NLaps);
481 std::vector<std::vector<double>> StepsValuesBefore(
systematics.size());
483 StepsValuesBefore[s] =
systematics[s]->GetProposed();
486 TStopwatch clockRace;
488 for(
int Lap = 0; Lap < NLaps; ++Lap) {
492 MACH3LOG_INFO(
"It took {:.4f} s to propose step {} times cov: {}", clockRace.RealTime(), NLaps,
systematics[s]->GetName());
493 MACH3LOG_INFO(
"On average {:.6f}", clockRace.RealTime()/NLaps);
496 systematics[s]->SetParameters(StepsValuesBefore[s]);
500 TStopwatch clockRace;
502 for(
int Lap = 0; Lap < NLaps; ++Lap) {
506 MACH3LOG_INFO(
"It took {:.4f} s to calculate get likelihood {} times cov: {}", clockRace.RealTime(), NLaps,
systematics[s]->GetName());
507 MACH3LOG_INFO(
"On average {:.6f}", clockRace.RealTime()/NLaps);
515 bool isScanRanges =
false;
517 if(
fitMan->
raw()[
"LLHScan"][
"ScanRanges"]){
518 YAML::Node scanRangesList =
fitMan->
raw()[
"LLHScan"][
"ScanRanges"];
519 for (
auto it = scanRangesList.begin(); it != scanRangesList.end(); ++it) {
520 std::string itname = it->first.as<std::string>();
521 std::vector<double> itrange = it->second.as<std::vector<double>>();
523 scanRanges[itname] = itrange;
527 MACH3LOG_INFO(
"There are no user-defined parameter ranges, so I'll use default param bounds for LLH Scans");
541 double& lower,
double& upper,
const int n_points,
const std::string& suffix)
const {
544 std::map<std::string, std::vector<double>> scanRanges;
547 double nSigma = GetFromManager<int>(
fitMan->
raw()[
"LLHScan"][
"LLHScanSigma"], 1., __FILE__, __LINE__);
548 bool IsPCA = cov->
IsPCA();
552 if (IsPCA) name +=
"_PCA";
561 if (std::abs(CentralValue - prior) > 1e-10) {
562 MACH3LOG_INFO(
"For {} scanning around value {} rather than prior {}", name, CentralValue, prior);
585 auto it = scanRanges.find(name);
586 if (it != scanRanges.end() && it->second.size() == 2) {
587 lower = it->second[0];
588 upper = it->second[1];
589 MACH3LOG_INFO(
"Found matching param name for setting specified range for {}", name);
590 MACH3LOG_INFO(
"Range for {} = [{:.2f}, {:.2f}]", name, lower, upper);
598 MACH3LOG_INFO(
"Scanning {} {} with {} steps, from [{:.2f} , {:.2f}], CV = {:.2f}", suffix, name, n_points, lower, upper, CentralValue);
611 bool PlotLLHScanBySample = GetFromManager<bool>(
fitMan->
raw()[
"LLHScan"][
"LLHScanBySample"],
false, __FILE__ , __LINE__);
612 auto SkipVector = GetFromManager<std::vector<std::string>>(
fitMan->
raw()[
"LLHScan"][
"LLHScanSkipVector"], {}, __FILE__ , __LINE__);
616 std::vector<TDirectory *> Cov_LLH(
systematics.size());
617 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc )
619 std::string NameTemp =
systematics[ivc]->GetName();
620 NameTemp = NameTemp.substr(0, NameTemp.find(
"_cov")) +
"_LLH";
621 Cov_LLH[ivc] =
outputFile->mkdir(NameTemp.c_str());
624 std::vector<TDirectory *> SampleClass_LLH(
samples.size());
625 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
627 std::string NameTemp =
samples[ivs]->GetName();
628 SampleClass_LLH[ivs] =
outputFile->mkdir(NameTemp.c_str());
631 TDirectory *Sample_LLH =
outputFile->mkdir(
"Sample_LLH");
632 TDirectory *Total_LLH =
outputFile->mkdir(
"Total_LLH");
634 std::vector<TDirectory *>SampleSplit_LLH;
635 if(PlotLLHScanBySample)
638 int SampleIterator = 0;
639 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
641 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is )
643 SampleSplit_LLH[SampleIterator] =
outputFile->mkdir((
samples[ivs]->GetSampleTitle(is)+
"_LLH").c_str());
649 const int n_points = GetFromManager<int>(
fitMan->
raw()[
"LLHScan"][
"LLHScanPoints"], 100, __FILE__ , __LINE__);
652 const int countwidth = int(
double(n_points)/
double(5));
659 int npars = cov->GetNumParams();
660 bool IsPCA = cov->IsPCA();
661 if (IsPCA) npars = cov->GetNParameters();
662 for (
int i = 0; i < npars; ++i)
665 std::string name = cov->GetParFancyName(i);
666 if (IsPCA) name +=
"_PCA";
670 double CentralValue, lower, upper;
673 auto hScan = std::make_unique<TH1D>((name +
"_full").c_str(), (name +
"_full").c_str(), n_points, lower, upper);
674 hScan->SetTitle((std::string(
"2LLH_full, ") + name +
";" + name +
"; -2(ln L_{sample} + ln L_{xsec+flux} + ln L_{det})").c_str());
675 hScan->SetDirectory(
nullptr);
677 auto hScanSam = std::make_unique<TH1D>((name +
"_sam").c_str(), (name +
"_sam").c_str(), n_points, lower, upper);
678 hScanSam->SetTitle((std::string(
"2LLH_sam, ") + name +
";" + name +
"; -2(ln L_{sample})").c_str());
679 hScanSam->SetDirectory(
nullptr);
681 std::vector<std::unique_ptr<TH1D>> hScanSample(
samples.size());
682 std::vector<double> nSamLLH(
samples.size(), 0.0);
683 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
685 std::string NameTemp =
samples[ivs]->GetName();
686 hScanSample[ivs] = std::make_unique<TH1D>((name+
"_"+NameTemp).c_str(), (name+
"_" + NameTemp).c_str(), n_points, lower, upper);
687 hScanSample[ivs]->SetDirectory(
nullptr);
688 hScanSample[ivs]->SetTitle((
"2LLH_" + NameTemp +
", " + name +
";" + name +
"; -2(ln L_{" + NameTemp +
"})").c_str());
691 std::vector<std::unique_ptr<TH1D>> hScanCov(
systematics.size());
692 std::vector<double> nCovLLH(
systematics.size(), 0.0);
693 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc )
695 std::string NameTemp =
systematics[ivc]->GetName();
696 NameTemp = NameTemp.substr(0, NameTemp.find(
"_cov"));
697 hScanCov[ivc] = std::make_unique<TH1D>((name +
"_" + NameTemp).c_str(), (name +
"_" + NameTemp).c_str(), n_points, lower, upper);
698 hScanCov[ivc]->SetDirectory(
nullptr);
699 hScanCov[ivc]->SetTitle((
"2LLH_" + NameTemp +
", " + name +
";" + name +
"; -2(ln L_{" + NameTemp +
"})").c_str());
702 std::vector<std::unique_ptr<TH1D>> hScanSamSplit;
703 std::vector<double> sampleSplitllh;
704 if(PlotLLHScanBySample)
706 int SampleIterator = 0;
709 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
711 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is )
713 auto histName = name +
samples[ivs]->GetSampleTitle(is);
714 auto histTitle = std::string(
"2LLH_sam, ") + name +
";" + name +
"; -2(ln L_{sample})";
715 hScanSamSplit[SampleIterator] = std::make_unique<TH1D>(histName.c_str(), histTitle.c_str(), n_points, lower, upper);
716 hScanSamSplit[SampleIterator]->SetDirectory(
nullptr);
723 for (
int j = 0; j < n_points; ++j)
725 if (j % countwidth == 0)
730 cov->GetPCAHandler()->SetParPropPCA(i, hScan->GetBinCenter(j+1));
733 cov->SetParProp(i, hScan->GetBinCenter(j+1));
737 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs ){
741 double totalllh = 0.;
744 double samplellh = 0.;
746 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs ) {
747 nSamLLH[ivs] =
samples[ivs]->GetLikelihood();
748 samplellh += nSamLLH[ivs];
751 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc ) {
753 totalllh += nCovLLH[ivc];
756 totalllh += samplellh;
758 if(PlotLLHScanBySample)
760 int SampleIterator = 0;
761 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
763 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is)
765 sampleSplitllh[SampleIterator] =
samples[ivs]->GetSampleLikelihood(is);
771 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs ) {
772 hScanSample[ivs]->SetBinContent(j+1, 2*nSamLLH[ivs]);
774 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc ) {
775 hScanCov[ivc]->SetBinContent(j+1, 2*nCovLLH[ivc]);
778 hScanSam->SetBinContent(j+1, 2*samplellh);
779 hScan->SetBinContent(j+1, 2*totalllh);
781 if(PlotLLHScanBySample)
783 int SampleIterator = 0;
784 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
786 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is)
788 hScanSamSplit[SampleIterator]->SetBinContent(j+1, 2*sampleSplitllh[SampleIterator]);
794 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc )
797 hScanCov[ivc]->Write();
800 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
802 SampleClass_LLH[ivs]->cd();
803 hScanSample[ivs]->Write();
810 if(PlotLLHScanBySample)
812 int SampleIterator = 0;
813 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
815 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is)
817 SampleSplit_LLH[SampleIterator]->cd();
818 hScanSamSplit[SampleIterator]->Write();
826 cov->GetPCAHandler()->SetParPropPCA(i, CentralValue);
828 cov->SetParProp(i, CentralValue);
833 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc )
835 Cov_LLH[ivc]->Write();
839 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
841 SampleClass_LLH[ivs]->Write();
842 delete SampleClass_LLH[ivs];
851 if(PlotLLHScanBySample)
853 int SampleIterator = 0;
854 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
856 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is )
858 SampleSplit_LLH[SampleIterator]->Write();
859 delete SampleSplit_LLH[SampleIterator];
870 TFile* outputFileLLH =
nullptr;
871 bool ownsfile =
false;
872 if(outputFileName !=
""){
873 outputFileLLH =
M3::Open(outputFileName,
"READ", __FILE__, __LINE__);
878 TDirectory *Sample_LLH = outputFileLLH->Get<TDirectory>(
"Sample_LLH");
881 if(!Sample_LLH || Sample_LLH->IsZombie())
883 MACH3LOG_WARN(
"Couldn't find Sample_LLH, it looks like LLH scan wasn't run, will do this now");
885 Sample_LLH = outputFileLLH->Get<TDirectory>(
"Sample_LLH");
890 const int npars = cov->GetNumParams();
891 std::vector<double> StepScale(npars);
892 for (
int i = 0; i < npars; ++i)
894 std::string name = cov->GetParFancyName(i);
895 StepScale[i] = cov->GetIndivStepScale(i);
896 TH1D* LLHScan = Sample_LLH->Get<TH1D>((name+
"_sam").c_str());
897 if(LLHScan ==
nullptr)
899 MACH3LOG_WARN(
"Couldn't find LLH scan, for {}, skipping", name);
902 const double LLH_val = std::max(LLHScan->GetBinContent(1), LLHScan->GetBinContent(LLHScan->GetNbinsX()));
904 if(LLH_val < 0.001)
continue;
909 const double Var = 1.;
910 const double approxSigma = std::abs(Var)/std::sqrt(LLH_val);
911 const double GlobalScale = cov->GetGlobalStepScale();
913 const double TargetStep = approxSigma * 2.38 / std::sqrt(npars);
915 const double NewStepScale = TargetStep / GlobalScale;
917 StepScale[i] = NewStepScale;
919 MACH3LOG_DEBUG(
"Target Step Size (before accounting for global step size): {}", TargetStep);
922 cov->SetIndivStepScale(StepScale);
923 cov->SaveUpdatedMatrixConfig();
925 if(ownsfile && outputFileLLH !=
nullptr)
delete outputFileLLH;
937 TDirectory *Sample_2DLLH =
outputFile->mkdir(
"Sample_2DLLH");
938 auto SkipVector = GetFromManager<std::vector<std::string>>(
fitMan->
raw()[
"LLHScan"][
"LLHScanSkipVector"], {}, __FILE__ , __LINE__);;
941 const int n_points = GetFromManager<int>(
fitMan->
raw()[
"LLHScan"][
"2DLLHScanPoints"], 20, __FILE__ , __LINE__);
943 const int countwidth = int(
double(n_points)/
double(5));
950 int npars = cov->GetNumParams();
951 bool IsPCA = cov->IsPCA();
952 if (IsPCA) npars = cov->GetNParameters();
954 for (
int i = 0; i < npars; ++i)
956 std::string name_x = cov->GetParFancyName(i);
957 if (IsPCA) name_x +=
"_PCA";
959 double central_x, lower_x, upper_x;
965 for (
int j = 0; j < i; ++j)
967 std::string name_y = cov->GetParFancyName(j);
968 if (IsPCA) name_y +=
"_PCA";
973 double central_y, lower_y, upper_y;
976 auto hScanSam = std::make_unique<TH2D>((name_x +
"_" + name_y +
"_sam").c_str(), (name_x +
"_" + name_y +
"_sam").c_str(),
977 n_points, lower_x, upper_x, n_points, lower_y, upper_y);
978 hScanSam->SetDirectory(
nullptr);
979 hScanSam->GetXaxis()->SetTitle(name_x.c_str());
980 hScanSam->GetYaxis()->SetTitle(name_y.c_str());
981 hScanSam->GetZaxis()->SetTitle(
"2LLH_sam");
984 for (
int x = 0; x < n_points; ++x)
986 if (x % countwidth == 0)
989 for (
int y = 0; y < n_points; ++y)
993 cov->GetPCAHandler()->SetParPropPCA(i, hScanSam->GetXaxis()->GetBinCenter(x+1));
994 cov->GetPCAHandler()->SetParPropPCA(j, hScanSam->GetYaxis()->GetBinCenter(y+1));
997 cov->SetParProp(i, hScanSam->GetXaxis()->GetBinCenter(x+1));
998 cov->SetParProp(j, hScanSam->GetYaxis()->GetBinCenter(y+1));
1001 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs) {
1006 double samplellh = 0;
1007 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs) {
1008 samplellh +=
samples[ivs]->GetLikelihood();
1010 hScanSam->SetBinContent(x+1, y+1, 2*samplellh);
1018 cov->GetPCAHandler()->SetParPropPCA(i, central_x);
1019 cov->GetPCAHandler()->SetParPropPCA(j, central_y);
1021 cov->SetParProp(i, central_x);
1022 cov->SetParProp(j, central_y);
1027 Sample_2DLLH->Write();
1028 delete Sample_2DLLH;
1041 bool PlotLLHScanBySample = GetFromManager<bool>(
fitMan->
raw()[
"LLHScan"][
"LLHScanBySample"],
false, __FILE__ , __LINE__);
1042 auto ParamsOfInterest = GetFromManager<std::vector<std::string>>(
fitMan->
raw()[
"LLHScan"][
"LLHParameters"], {}, __FILE__, __LINE__);
1044 if(ParamsOfInterest.empty()) {
1045 MACH3LOG_WARN(
"There were no LLH parameters of interest specified to run the LLHMap! LLHMap will not run at all ...");
1051 std::vector<std::tuple<std::string, ParameterHandlerBase*, int>> ParamsCovIDs;
1052 for(
auto& p : ParamsOfInterest) {
1055 for(
int c = 0; c < cov->GetNumParams(); ++c) {
1056 if(cov->GetParName(c) == p || cov->GetParFancyName(c) == p) {
1058 for(
auto& pc : ParamsCovIDs) {
1059 if(std::get<1>(pc) == cov && std::get<2>(pc) == c)
1061 MACH3LOG_WARN(
"Parameter {} as {}({}) listed multiple times for LLHMap, omitting and using only once!", p, cov->GetName(), c);
1068 ParamsCovIDs.push_back(std::make_tuple(p, cov, c));
1078 MACH3LOG_INFO(
"Parameter {} found in {} at an index {}.", p, std::get<1>(ParamsCovIDs.back())->GetName(), std::get<2>(ParamsCovIDs.back()));
1080 MACH3LOG_WARN(
"Parameter {} not found in any of the systematic covariance objects. Will not scan over this one!", p);
1084 std::map<std::string, std::pair<int, std::pair<double, double>>> ParamsRanges;
1086 MACH3LOG_INFO(
"======================================================================================");
1087 MACH3LOG_INFO(
"Performing a general multi-dimensional LogL map scan over following parameters ranges:");
1088 MACH3LOG_INFO(
"======================================================================================");
1089 unsigned long TotalPoints = 1;
1091 double nSigma = GetFromManager<int>(
fitMan->
raw()[
"LLHScan"][
"LLHScanSigma"], 1., __FILE__, __LINE__);
1096 for(
auto& p : ParamsCovIDs) {
1098 std::string name = std::get<0>(p);
1099 int i = std::get<2>(p);
1102 ParamsRanges[name].first = GetFromManager<int>(
fitMan->
raw()[
"LLHScan"][
"LLHScanPoints"], 20, __FILE__, __LINE__);
1104 ParamsRanges[name].first = GetFromManager<int>(
fitMan->
raw()[
"LLHScan"][
"ScanPoints"][name], ParamsRanges[name].first, __FILE__, __LINE__);
1109 bool IsPCA = cov->
IsPCA();
1117 if (std::abs(CentralValue - prior) > 1e-10) {
1118 MACH3LOG_INFO(
"For {} scanning around value {} rather than prior {}", name, CentralValue, prior);
1136 ParamsRanges[name].second = {lower,upper};
1139 ParamsRanges[name].second = GetFromManager<std::pair<double,double>>(
fitMan->
raw()[
"LLHScan"][
"ScanRanges"][name], ParamsRanges[name].second, __FILE__, __LINE__);
1141 MACH3LOG_INFO(
"{} from {:.4f} (lower bin edge) to {:.4f} (upper bin edge) with a {:.5f} step ({} points total)",
1142 name, ParamsRanges[name].second.first, ParamsRanges[name].second.second,
1143 (ParamsRanges[name].second.second - ParamsRanges[name].second.first)/(ParamsRanges[name].first),
1144 ParamsRanges[name].first);
1146 TotalPoints *= ParamsRanges[name].first;
1150 MACH3LOG_INFO(
"In total, looping over {} points, from {} parameters. Estimates for run time:", TotalPoints, ParamsCovIDs.size());
1151 MACH3LOG_INFO(
" 1 s per point = {} hours",
double(TotalPoints)/3600.);
1152 MACH3LOG_INFO(
" 0.1 s per point = {} hours",
double(TotalPoints)/36000.);
1153 MACH3LOG_INFO(
"0.01 s per point = {} hours",
double(TotalPoints)/360000.);
1154 MACH3LOG_INFO(
"==================================================================================");
1156 const int countwidth = int(
double(TotalPoints)/
double(20));
1159 auto LLHMap =
new TTree(
"llhmap",
"LLH Map");
1162 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc )
1164 std::string NameTemp =
systematics[ivc]->GetName();
1165 NameTemp = NameTemp.substr(0, NameTemp.find(
"_cov")) +
"_LLH";
1166 LLHMap->Branch(NameTemp.c_str(), &CovLogL[ivc]);
1169 std::vector<double> SampleClassLogL(
samples.size());
1170 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
1172 std::string NameTemp =
samples[ivs]->GetName()+
"_LLH";
1173 LLHMap->Branch(NameTemp.c_str(), &SampleClassLogL[ivs]);
1176 double SampleLogL, TotalLogL;
1177 LLHMap->Branch(
"Sample_LLH", &SampleLogL);
1178 LLHMap->Branch(
"Total_LLH", &TotalLogL);
1180 std::vector<double>SampleSplitLogL;
1181 if(PlotLLHScanBySample)
1184 int SampleIterator = 0;
1185 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
1187 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is )
1189 std::string NameTemp =
samples[ivs]->GetSampleTitle(is)+
"_LLH";
1190 LLHMap->Branch(NameTemp.c_str(), &SampleSplitLogL[SampleIterator]);
1196 std::vector<double> ParamsValues(ParamsCovIDs.size());
1197 for(
unsigned int i=0; i < ParamsCovIDs.size(); ++i)
1198 LLHMap->Branch(std::get<0>(ParamsCovIDs[i]).c_str(), &ParamsValues[i]);
1202 std::vector<unsigned long> idx(ParamsCovIDs.size(), 0);
1205 for(
unsigned long sp = 0; sp < TotalPoints; ++sp)
1208 for(
unsigned int n = 0; n < ParamsCovIDs.size(); ++n)
1211 std::string name = std::get<0>(ParamsCovIDs[n]);
1212 int points = ParamsRanges[name].first;
1213 double low = ParamsRanges[name].second.first;
1214 double high = ParamsRanges[name].second.second;
1217 unsigned long dev = 1;
1218 for(
unsigned int m = 0; m <= n; ++m)
1219 dev *= ParamsRanges[std::get<0>(ParamsCovIDs[m])].first;
1223 idx[n] = idx[n] / ( dev / points );
1226 ParamsValues[n] = low + (2 * double(idx[n]) + 1) * (high-low) / (2 * double(points));
1231 int i = std::get<2>(ParamsCovIDs[n]);
1243 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs)
1246 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs)
1248 SampleClassLogL[ivs] = 2.*
samples[ivs]->GetLikelihood();
1249 SampleLogL += SampleClassLogL[ivs];
1251 TotalLogL += SampleLogL;
1254 for(
unsigned int ivc = 0; ivc <
systematics.size(); ++ivc )
1256 CovLogL[ivc] = 2.*
systematics[ivc]->GetLikelihood();
1257 TotalLogL += CovLogL[ivc];
1260 if(PlotLLHScanBySample)
1262 int SampleIterator = 0;
1263 for(
unsigned int ivs = 0; ivs <
samples.size(); ++ivs )
1265 for(
int is = 0; is <
samples[ivs]->GetNSamples(); ++is)
1267 SampleSplitLogL[SampleIterator] = 2.*
samples[ivs]->GetSampleLikelihood(is);
1275 if (sp % countwidth == 0)
1287 if(!
fitMan->
raw()[
"SigmaVar"][
"CustomRange"])
return;
1289 auto Config =
fitMan->
raw()[
"SigmaVar"][
"CustomRange"];
1291 const auto sigmaStr = std::to_string(
static_cast<int>(std::round(sigma)));
1293 if (Config[ParName] && Config[ParName][sigmaStr]) {
1294 ParamShiftValue = Config[ParName][sigmaStr].as<
double>();
1295 MACH3LOG_INFO(
" ::: setting custom range from config ::: {} -> {}", ParName, ParamShiftValue);
1304 hist->SetTitle(baseName.c_str());
1306 TString className = hist->ClassName();
1309 if (className.Contains(
"TH1")) {
1310 hist->GetYaxis()->SetTitle(
"Events");
1311 }
else if (className.Contains(
"TH2")) {
1312 hist->GetZaxis()->SetTitle(
"Events");
1314 hist->Write(baseName.c_str());
1320 const std::string& suffix,
1322 const bool by_channel,
1323 const std::vector<TDirectory*>& SampleDir) {
1326 for (
int iSample = 0; iSample < sample->
GetNSamples(); ++iSample) {
1327 SampleDir[iSample]->cd();
1329 for(
int iDim1 = 0; iDim1 < sample->
GetNDim(iSample); iDim1++) {
1330 std::string ProjectionName = sample->
GetKinVarName(iSample, iDim1);
1331 std::string ProjectionSuffix =
"_1DProj" + std::to_string(iDim1);
1335 for (
int iMode = 0; iMode < modes->
GetNModes(); ++iMode) {
1342 for (
int iChan = 0; iChan < sample->
GetNOscChannels(iSample); ++iChan) {
1348 if (by_mode && by_channel) {
1349 for (
int iMode = 0; iMode < modes->
GetNModes(); ++iMode) {
1350 for (
int iChan = 0; iChan < sample->
GetNOscChannels(iSample); ++iChan) {
1357 if (!by_mode && !by_channel) {
1358 auto hist = sample->
Get1DVarHist(iSample, ProjectionName);
1361 for (
int iDim2 = iDim1 + 1; iDim2 < sample->
GetNDim(iSample); ++iDim2) {
1363 std::string XVarName = sample->
GetKinVarName(iSample, iDim1);
1364 std::string YVarName = sample->
GetKinVarName(iSample, iDim2);
1367 auto hist2D = sample->
Get2DVarHist(iSample, XVarName, YVarName);
1370 std::string suffix2D =
"_2DProj_" + std::to_string(iDim1) +
"_vs_" + std::to_string(iDim2) + suffix;
1384 bool plot_by_mode = GetFromManager<bool>(
fitMan->
raw()[
"SigmaVar"][
"PlotByMode"],
false, __FILE__ , __LINE__);
1385 bool plot_by_channel = GetFromManager<bool>(
fitMan->
raw()[
"SigmaVar"][
"PlotByChannel"],
false, __FILE__ , __LINE__);
1386 auto SkipVector = GetFromManager<std::vector<std::string>>(
fitMan->
raw()[
"SigmaVar"][
"SkipVector"], {}, __FILE__ , __LINE__);
1388 if (plot_by_mode)
MACH3LOG_INFO(
"Plotting by sample and mode");
1389 if (plot_by_channel)
MACH3LOG_INFO(
"Plotting by sample and channel");
1390 if (!plot_by_mode && !plot_by_channel)
MACH3LOG_INFO(
"Plotting by sample only");
1391 if (plot_by_mode && plot_by_channel)
MACH3LOG_INFO(
"Plotting by sample, mode and channel");
1393 auto SigmaArray = GetFromManager<std::vector<double>>(
fitMan->
raw()[
"SigmaVar"][
"SigmaArray"], {-3, -1, 0, 1, 3}, __FILE__ , __LINE__);
1394 if (std::find(SigmaArray.begin(), SigmaArray.end(), 0.0) == SigmaArray.end()) {
1395 MACH3LOG_ERROR(
":: SigmaArray does not contain 0! Current contents: {} ::", fmt::join(SigmaArray,
", "));
1399 TDirectory* SigmaDir =
outputFile->mkdir(
"SigmaVar");
1404 for(
int i = 0; i <
systematics[s]->GetNumParams(); i++)
1406 std::string ParName =
systematics[s]->GetParFancyName(i);
1412 TDirectory* ParamDir = SigmaDir->mkdir(ParName.c_str());
1415 const double ParamCentralValue =
systematics[s]->GetParProp(i);
1416 const double Prior =
systematics[s]->GetParPreFit(i);
1417 const double ParamLower =
systematics[s]->GetLowerBound(i);
1418 const double ParamUpper =
systematics[s]->GetUpperBound(i);
1420 if (std::abs(ParamCentralValue - Prior) > 1e-10) {
1421 MACH3LOG_INFO(
"For {} scanning around value {} rather than prior {}", ParName, ParamCentralValue, Prior);
1424 for(
unsigned int iSample = 0; iSample <
samples.size(); ++iSample)
1426 auto* MaCh3Sample =
samples[iSample];
1427 std::vector<TDirectory*> SampleDir(MaCh3Sample->GetNSamples());
1428 for (
int SampleIndex = 0; SampleIndex < MaCh3Sample->GetNSamples(); ++SampleIndex) {
1429 SampleDir[SampleIndex] = ParamDir->mkdir(MaCh3Sample->GetSampleTitle(SampleIndex).c_str());
1432 for (
size_t j = 0; j < SigmaArray.size(); ++j) {
1433 double sigma = SigmaArray[j];
1435 double ParamShiftValue = ParamCentralValue + sigma * std::sqrt((*
systematics[s]->GetCovMatrix())(i,i));
1436 ParamShiftValue = std::max(std::min(ParamShiftValue, ParamUpper), ParamLower);
1441 MACH3LOG_INFO(
" - set to {:<5.2f} ({:<2} sigma shift)", ParamShiftValue, sigma);
1444 std::ostringstream valStream;
1445 valStream << std::fixed << std::setprecision(2) << ParamShiftValue;
1446 std::string valueStr = valStream.str();
1448 std::ostringstream sigmaStream;
1449 sigmaStream << std::fixed << std::setprecision(2) << std::abs(sigma);
1450 std::string sigmaStr = sigmaStream.str();
1454 suffix =
"_" + ParName +
"_nom_val_" + valueStr;
1456 std::string sign = (sigma > 0) ?
"p" :
"n";
1457 suffix =
"_" + ParName +
"_sig_" + sign + sigmaStr +
"_val_" + valueStr;
1461 MaCh3Sample->Reweight();
1465 for (
int subSampleIndex = 0; subSampleIndex < MaCh3Sample->GetNSamples(); ++subSampleIndex) {
1466 SampleDir[subSampleIndex]->Close();
1467 delete SampleDir[subSampleIndex];
1473 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 for handling systematic uncertainty parameters.
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.
double GetParPreFit(const int i) const
Get prior parameter value.
M3::float_t GetParProp(const int i) const
Get proposed 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 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.
virtual void SaveAdditionalInfo([[maybe_unused]] TDirectory *Dir)
Store additional info in a chain.
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
bool CaseInsensitiveMatchAny(std::string Text, const std::vector< std::string > &Patterns)
Matches a string against a simple wildcard Pattern using regex. Is not case sensitive.