MaCh3  2.2.3
Reference Guide
Functions | Variables
ProcessMCMC.cpp File Reference

Main exectable responsible for different types of MCMC processing like drawing posteriors, triangle plots etc. Actual implantation of methods is in MCMCProcessor. More...

#include "Fitters/OscProcessor.h"
#include "Manager/Manager.h"
Include dependency graph for ProcessMCMC.cpp:

Go to the source code of this file.

Functions

void ProcessMCMC (const std::string &inputFile)
 Main function processing MCMC and Producing plots. More...
 
void MultipleProcessMCMC ()
 Function producing comparison of posterior and more betwen a few MCMC chains. More...
 
void CalcBayesFactor (MCMCProcessor *Processor)
 KS: Calculate Bayes factor for a given hypothesis, most informative are those related to osc params. However, it make relative easy interpretation for switch dials. More...
 
void CalcSavageDickey (MCMCProcessor *Processor)
 
void CalcBipolarPlot (MCMCProcessor *Processor)
 
void CalcParameterEvolution (MCMCProcessor *Processor)
 
void GetTrianglePlot (MCMCProcessor *Processor)
 
void DiagnoseCovarianceMatrix (MCMCProcessor *Processor, const std::string &inputFile)
 KS: You validate stability of posterior covariance matrix, you set burn calc cov matrix increase burn calc again and compare. By performing such operation several hundred times we can check when matrix becomes stable. More...
 
void ReweightPrior (MCMCProcessor *Processor)
 
TH2D * TMatrixIntoTH2D (TMatrixDSym *Matrix, const std::string &title)
 KS: Convert TMatrix to TH2D, mostly useful for making fancy plots. More...
 
void KolmogorovSmirnovTest (const std::vector< std::unique_ptr< MCMCProcessor >> &Processor, const std::unique_ptr< TCanvas > &Posterior, const TString &canvasname)
 KS: Perform KS test to check if two posteriors for the same parameter came from the same distribution. More...
 
int main (int argc, char *argv[])
 
std::map< std::string, std::pair< double, double > > GetCustomBinning (const YAML::Node &Settings)
 Parse custom binning edges from a YAML configuration node. More...
 

Variables

int nFiles
 
std::vector< std::string > FileNames
 
std::vector< std::string > TitleNames
 
std::string config
 

Detailed Description

Main exectable responsible for different types of MCMC processing like drawing posteriors, triangle plots etc. Actual implantation of methods is in MCMCProcessor.

Author
Kamil Skwarczynski

Definition in file ProcessMCMC.cpp.

Function Documentation

◆ CalcBayesFactor()

void CalcBayesFactor ( MCMCProcessor Processor)
inline

KS: Calculate Bayes factor for a given hypothesis, most informative are those related to osc params. However, it make relative easy interpretation for switch dials.

Definition at line 420 of file ProcessMCMC.cpp.

421 {
422  YAML::Node card_yaml = M3OpenConfig(config.c_str());
423  YAML::Node Settings = card_yaml["ProcessMCMC"];
424 
425  std::vector<std::string> ParNames;
426  std::vector<std::vector<double>> Model1Bounds;
427  std::vector<std::vector<double>> Model2Bounds;
428  std::vector<std::vector<std::string>> ModelNames;
429  for (const auto& dg : Settings["BayesFactor"])
430  {
431  ParNames.push_back(dg[0].as<std::string>());
432  ModelNames.push_back(dg[1].as<std::vector<std::string>>());
433  Model1Bounds.push_back(dg[2].as<std::vector<double>>());
434  Model2Bounds.push_back(dg[3].as<std::vector<double>>());
435  }
436 
437  Processor->GetBayesFactor(ParNames, Model1Bounds, Model2Bounds, ModelNames);
438 }
std::string config
Definition: ProcessMCMC.cpp:29
#define M3OpenConfig(filename)
Macro to simplify calling LoadYaml with file and line info.
Definition: YamlHelper.h:561
void GetBayesFactor(const std::vector< std::string > &ParName, const std::vector< std::vector< double >> &Model1Bounds, const std::vector< std::vector< double >> &Model2Bounds, const std::vector< std::vector< std::string >> &ModelNames)
Calculate Bayes factor for vector of params, and model boundaries.

◆ CalcBipolarPlot()

void CalcBipolarPlot ( MCMCProcessor Processor)
inline

Definition at line 473 of file ProcessMCMC.cpp.

474 {
475  YAML::Node card_yaml = M3OpenConfig(config.c_str());
476  YAML::Node Settings = card_yaml["ProcessMCMC"];
477 
478  std::vector<std::string> ParNames;
479  for (const auto& d : Settings["BipolarPlot"])
480  {
481  ParNames.push_back(d[0].as<std::string>());
482  }
483  Processor->GetPolarPlot(ParNames);
484 }
void GetPolarPlot(const std::vector< std::string > &ParNames)
Make funny polar plot.

◆ CalcParameterEvolution()

void CalcParameterEvolution ( MCMCProcessor Processor)
inline

Definition at line 458 of file ProcessMCMC.cpp.

459 {
460  YAML::Node card_yaml = M3OpenConfig(config.c_str());
461  YAML::Node Settings = card_yaml["ProcessMCMC"];
462 
463  std::vector<std::string> ParNames;
464  std::vector<int> Intervals;
465  for (const auto& d : Settings["ParameterEvolution"])
466  {
467  ParNames.push_back(d[0].as<std::string>());
468  Intervals.push_back(d[1].as<int>());
469  }
470  Processor->ParameterEvolution(ParNames, Intervals);
471 }
void ParameterEvolution(const std::vector< std::string > &Names, const std::vector< int > &NIntervals)
Make .gif of parameter evolution.

◆ CalcSavageDickey()

void CalcSavageDickey ( MCMCProcessor Processor)
inline

Definition at line 440 of file ProcessMCMC.cpp.

441 {
442  YAML::Node card_yaml = M3OpenConfig(config.c_str());
443  YAML::Node Settings = card_yaml["ProcessMCMC"];
444 
445  std::vector<std::string> ParNames;
446  std::vector<double> EvaluationPoint;
447  std::vector<std::vector<double>> Bounds;
448 
449  for (const auto& d : Settings["SavageDickey"])
450  {
451  ParNames.push_back(d[0].as<std::string>());
452  EvaluationPoint.push_back(d[1].as<double>());
453  Bounds.push_back(d[2].as<std::vector<double>>());
454  }
455  Processor->GetSavageDickey(ParNames, EvaluationPoint, Bounds);
456 }
void GetSavageDickey(const std::vector< std::string > &ParName, const std::vector< double > &EvaluationPoint, const std::vector< std::vector< double >> &Bounds)
Calculate Bayes factor for point like hypothesis using SavageDickey.

◆ DiagnoseCovarianceMatrix()

void DiagnoseCovarianceMatrix ( MCMCProcessor Processor,
const std::string &  inputFile 
)
inline

KS: You validate stability of posterior covariance matrix, you set burn calc cov matrix increase burn calc again and compare. By performing such operation several hundred times we can check when matrix becomes stable.

Definition at line 506 of file ProcessMCMC.cpp.

507 {
508  //Turn of plots from Processor
509  Processor->SetPrintToPDF(false);
510  // Open a TCanvas to write the posterior onto
511  auto Canvas = std::make_unique<TCanvas>("Canvas", "Canvas", 0, 0, 1024, 1024);
512  Canvas->SetGrid();
513  gStyle->SetOptStat(0);
514  gStyle->SetOptTitle(0);
515  Canvas->SetTickx();
516  Canvas->SetTicky();
517  Canvas->SetBottomMargin(0.1f);
518  Canvas->SetTopMargin(0.05f);
519  Canvas->SetRightMargin(0.15f);
520  Canvas->SetLeftMargin(0.10f);
521 
522  //KS: Fancy colours
523  const int NRGBs = 10;
524  TColor::InitializeColors();
525  Double_t stops[NRGBs] = { 0.00, 0.10, 0.25, 0.35, 0.50, 0.60, 0.65, 0.75, 0.90, 1.00 };
526  Double_t red[NRGBs] = { 0.50, 1.00, 1.00, 0.25, 0.00, 0.10, 0.50, 1.00, 0.75, 0.55 };
527  Double_t green[NRGBs] = { 0.00, 0.25, 1.00, 0.25, 0.00, 0.60, 0.90, 1.00, 0.75, 0.75 };
528  Double_t blue[NRGBs] = { 0.00, 0.25, 1.00, 1.00, 0.50, 0.60, 0.90, 1.00, 0.05, 0.05 };
529  TColor::CreateGradientColorTable(NRGBs, stops, red, green, blue, 255);
530  gStyle->SetNumberContours(255);
531 
532  std::string OutName = inputFile;
533  OutName = OutName.substr(0, OutName.find(".root"));
534  Canvas->Print(Form("Correlation_%s.pdf[", OutName.c_str()), "pdf");
535  Canvas->Print(Form("Covariance_%s.pdf[", OutName.c_str()), "pdf");
536 
537  YAML::Node card_yaml = M3OpenConfig(config.c_str());
538  YAML::Node Settings = card_yaml["ProcessMCMC"];
539 
540  const int entries = int(Processor->GetnSteps());
541  const int NIntervals = GetFromManager<int>(Settings["NIntervals"], 5);
542  const int IntervalsSize = entries/NIntervals;
543  //We start with burn from 0 (no burn in at all)
544  int BurnIn = 0;
545  MACH3LOG_INFO("Diagnosing matrices with entries={}, NIntervals={} and IntervalsSize={}", entries, NIntervals, IntervalsSize);
546 
547  TMatrixDSym *Covariance = nullptr;
548  TMatrixDSym *Correlation = nullptr;
549 
550  TH2D *CovariancePreviousHist = nullptr;
551  TH2D *CorrelationPreviousHist = nullptr;
552 
553  TH2D *CovarianceHist = nullptr;
554  TH2D *CorrelationHist = nullptr;
555 
556  //KS: Get first covariances, we need two for comparison...
557  Processor->SetStepCut(BurnIn);
558  Processor->GetCovariance(Covariance, Correlation);
559 
560  CovariancePreviousHist = TMatrixIntoTH2D(Covariance, "Covariance");
561  CorrelationPreviousHist = TMatrixIntoTH2D(Correlation, "Correlation");
562 
563  delete Covariance;
564  Covariance = nullptr;
565  delete Correlation;
566  Correlation = nullptr;
567 
568  //KS: Loop over all desired cuts
569  for(int k = 1; k < NIntervals; ++k)
570  {
571  BurnIn = k*IntervalsSize;
572  Processor->SetStepCut(BurnIn);
573  Processor->GetCovariance(Covariance, Correlation);
574  Processor->ResetHistograms();
575 
576  CovarianceHist = TMatrixIntoTH2D(Covariance, "Covariance");
577  CorrelationHist = TMatrixIntoTH2D(Correlation, "Correlation");
578 
579  TH2D *CovarianceDiff = static_cast<TH2D*>(CovarianceHist->Clone("Covariance_Ratio"));
580  TH2D *CorrelationDiff = static_cast<TH2D*>(CorrelationHist->Clone("Correlation_Ratio"));
581 
582  //KS: Bit messy but quite often covariance is 0 is divided by 0 is problematic so
583  #ifdef MULTITHREAD
584  #pragma omp parallel for
585  #endif
586  for (int j = 1; j < CovarianceDiff->GetXaxis()->GetNbins()+1; ++j)
587  {
588  for (int i = 1; i < CovarianceDiff->GetYaxis()->GetNbins()+1; ++i)
589  {
590  if( std::fabs (CovarianceDiff->GetBinContent(j, i)) < 1.e-5 && std::fabs (CovariancePreviousHist->GetBinContent(j, i)) < 1.e-5)
591  {
592  CovarianceDiff->SetBinContent(j, i, M3::_BAD_DOUBLE_);
593  CovariancePreviousHist->SetBinContent(j, i, M3::_BAD_DOUBLE_);
594  }
595  if( std::fabs (CorrelationDiff->GetBinContent(j, i)) < 1.e-5 && std::fabs (CorrelationPreviousHist->GetBinContent(j, i)) < 1.e-5)
596  {
597  CorrelationDiff->SetBinContent(j, i, M3::_BAD_DOUBLE_);
598  CorrelationPreviousHist->SetBinContent(j, i, M3::_BAD_DOUBLE_);
599  }
600  }
601  }
602  //Divide matrices
603  CovarianceDiff->Divide(CovariancePreviousHist);
604  CorrelationDiff->Divide(CorrelationPreviousHist);
605 
606  //Now it is time for fancy names etc.
607  for (int j = 0; j < CovarianceDiff->GetXaxis()->GetNbins(); ++j)
608  {
609  TString Title = "";
610  double Prior = 1.0;
611  double PriorError = 1.0;
612 
613  Processor->GetNthParameter(j, Prior, PriorError, Title);
614 
615  CovarianceDiff->GetXaxis()->SetBinLabel(j+1, Title);
616  CovarianceDiff->GetYaxis()->SetBinLabel(j+1, Title);
617  CorrelationDiff->GetXaxis()->SetBinLabel(j+1, Title);
618  CorrelationDiff->GetYaxis()->SetBinLabel(j+1, Title);
619  }
620  CovarianceDiff->GetXaxis()->SetLabelSize(0.015f);
621  CovarianceDiff->GetYaxis()->SetLabelSize(0.015f);
622  CorrelationDiff->GetXaxis()->SetLabelSize(0.015f);
623  CorrelationDiff->GetYaxis()->SetLabelSize(0.015f);
624 
625  std::stringstream ss;
626  ss << "BCut_";
627  ss << BurnIn;
628  ss << "/";
629  ss << "BCut_";
630  ss << (k-1)*IntervalsSize;
631  std::string str = ss.str();
632 
633  TString Title = "Cov " + str;
634  CovarianceDiff->GetZaxis()->SetTitle( Title );
635  Title = "Corr " + str;
636  CorrelationDiff->GetZaxis()->SetTitle(Title);
637 
638  CovarianceDiff->SetMinimum(-2);
639  CovarianceDiff->SetMaximum(2);
640  CorrelationDiff->SetMinimum(-2);
641  CorrelationDiff->SetMaximum(2);
642 
643  Canvas->cd();
644  CovarianceDiff->Draw("colz");
645  Canvas->Print(Form("Covariance_%s.pdf", OutName.c_str()), "pdf");
646 
647  CorrelationDiff->Draw("colz");
648  Canvas->Print(Form("Correlation_%s.pdf", OutName.c_str()), "pdf");
649 
650  //KS: Current hist become previous as we need it for further comparison
651  delete CovariancePreviousHist;
652  CovariancePreviousHist = static_cast<TH2D*>(CovarianceHist->Clone());
653  delete CorrelationPreviousHist;
654  CorrelationPreviousHist = static_cast<TH2D*>(CorrelationHist->Clone());
655 
656  delete CovarianceHist;
657  CovarianceHist = nullptr;
658  delete CorrelationHist;
659  CorrelationHist = nullptr;
660 
661  delete CovarianceDiff;
662  delete CorrelationDiff;
663  delete Covariance;
664  Covariance = nullptr;
665  delete Correlation;
666  Correlation = nullptr;
667  }
668  Canvas->cd();
669  Canvas->Print(Form("Covariance_%s.pdf]", OutName.c_str()), "pdf");
670  Canvas->Print(Form("Correlation_%s.pdf]", OutName.c_str()), "pdf");
671 
672  Processor->SetPrintToPDF(true);
673  if(Covariance != nullptr) delete Covariance;
674  if(Correlation != nullptr) delete Correlation;
675  if(CovariancePreviousHist != nullptr) delete CovariancePreviousHist;
676  if(CorrelationPreviousHist != nullptr) delete CorrelationPreviousHist;
677  if(CovarianceHist != nullptr) delete CovarianceHist;
678  if(CorrelationHist != nullptr) delete CorrelationHist;
679 }
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:25
TH2D * TMatrixIntoTH2D(TMatrixDSym *Matrix, const std::string &title)
KS: Convert TMatrix to TH2D, mostly useful for making fancy plots.
void GetNthParameter(const int param, double &Prior, double &PriorError, TString &Title) const
Get properties of parameter by passing it number.
void ResetHistograms()
Reset 2D posteriors, in case we would like to calculate in again with different BurnInCut.
void SetPrintToPDF(const bool PlotOrNot)
Long64_t GetnSteps()
Get Number of Steps that Chain has, for merged chains will not be the same nEntries.
void GetCovariance(TMatrixDSym *&Cov, TMatrixDSym *&Corr)
Get the post-fit covariances and correlations.
void SetStepCut(const std::string &Cuts)
Set the step cutting by string.
constexpr static const double _BAD_DOUBLE_
Default value used for double initialisation.
Definition: Core.h:46

◆ GetCustomBinning()

std::map<std::string, std::pair<double, double> > GetCustomBinning ( const YAML::Node &  Settings)

Parse custom binning edges from a YAML configuration node.

This function reads the CustomBinEdges section of the YAML config and returns a mapping of parameter names to their lower and upper edges.

The expected YAML syntax is:

CustomBinEdges:
delta_cp: [-3.141592, 3.141592]
another_param: [min, max]
Parameters
SettingsYAML configuration node containing the optional CustomBinEdges section.

Definition at line 92 of file ProcessMCMC.cpp.

93 {
94  std::map<std::string, std::pair<double, double>> CustomBinning;
95  if (Settings["CustomBinEdges"]) {
96  const YAML::Node& edges = Settings["CustomBinEdges"];
97 
98  for (const auto& node : edges) {
99  std::string key = node.first.as<std::string>();
100  auto values = node.second.as<std::vector<double>>();
101 
102  if (values.size() == 2) {
103  CustomBinning[key] = std::make_pair(values[0], values[1]);
104  MACH3LOG_DEBUG("Adding custom binning {} with {:.4f}, {:.4f}", key, values[0], values[1]);
105  } else {
106  MACH3LOG_ERROR("Invalid number of values for key: {}", key);
107  throw MaCh3Exception(__FILE__ , __LINE__ );
108  }
109  }
110  }
111  return CustomBinning;
112 }
#define MACH3LOG_DEBUG
Definition: MaCh3Logger.h:24
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:27
Custom exception class for MaCh3 errors.

◆ GetTrianglePlot()

void GetTrianglePlot ( MCMCProcessor Processor)
inline

Definition at line 486 of file ProcessMCMC.cpp.

486  {
487  YAML::Node card_yaml = M3OpenConfig(config.c_str());
488  YAML::Node Settings = card_yaml["ProcessMCMC"];
489 
490  for (const auto& dg : Settings["TrianglePlot"])
491  {
492  std::string ParName = dg[0].as<std::string>();
493 
494  std::vector<std::string> NameVec = dg[1].as<std::vector<std::string>>();
495  Processor->MakeTrianglePlot(NameVec,
496  GetFromManager<std::vector<double>>(Settings["CredibleIntervals"], {0.99, 0.90, 0.68}),
497  GetFromManager<std::vector<short int>>(Settings["CredibleIntervalsColours"], {436, 430, 422}),
498  GetFromManager<std::vector<double>>(Settings["CredibleRegions"], {0.99, 0.90, 0.68}),
499  GetFromManager<std::vector<short int>>(Settings["CredibleRegionStyle"], {2, 1, 3}),
500  GetFromManager<std::vector<short int>>(Settings["CredibleRegionColor"], {413, 406, 416}),
501  GetFromManager<bool>(Settings["CredibleInSigmas"], false));
502  }
503 }
Type GetFromManager(const YAML::Node &node, Type defval, const std::string File="", const int Line=1)
Get content of config file if node is not found take default value specified.
Definition: YamlHelper.h:299
void MakeTrianglePlot(const std::vector< std::string > &ParNames, const std::vector< double > &CredibleIntervals={0.99, 0.90, 0.68 }, const std::vector< Color_t > &CredibleIntervalsColours={kCyan+4, kCyan-2, kCyan-10}, const std::vector< double > &CredibleRegions={0.99, 0.90, 0.68}, const std::vector< Style_t > &CredibleRegionStyle={kDashed, kSolid, kDotted}, const std::vector< Color_t > &CredibleRegionColor={kGreen-3, kGreen-10, kGreen}, const bool CredibleInSigmas=false)
Make fancy triangle plot for selected parameters.

◆ KolmogorovSmirnovTest()

void KolmogorovSmirnovTest ( const std::vector< std::unique_ptr< MCMCProcessor >> &  Processor,
const std::unique_ptr< TCanvas > &  Posterior,
const TString &  canvasname 
)
inline

KS: Perform KS test to check if two posteriors for the same parameter came from the same distribution.

Definition at line 710 of file ProcessMCMC.cpp.

713 {
714  constexpr Color_t CumulativeColor[] = {kBlue-1, kRed, kGreen+2};
715  constexpr Style_t CumulativeStyle[] = {kSolid, kDashed, kDotted};
716 
717  for(int i = 0; i < Processor[0]->GetNParams(); ++i)
718  {
719  // This holds the posterior density
720  std::vector<std::unique_ptr<TH1D>> hpost(nFiles);
721  std::vector<std::unique_ptr<TH1D>> CumulativeDistribution(nFiles);
722 
723  TString Title;
724  double Prior = 1.0;
725  double PriorError = 1.0;
726 
727  Processor[0]->GetNthParameter(i, Prior, PriorError, Title);
728  bool Skip = false;
729  for (int ik = 0 ; ik < nFiles; ik++)
730  {
731  int Index = 0;
732  if(ik == 0 ) Index = i;
733  else
734  {
735  // KS: If somehow this chain doesn't given params we skip it
736  Index = Processor[ik]->GetParamIndexFromName(hpost[0]->GetTitle());
737  if(Index == M3::_BAD_INT_)
738  {
739  Skip = true;
740  break;
741  }
742  }
743  hpost[ik] = M3::Clone(Processor[ik]->GetHpost(Index));
744  CumulativeDistribution[ik] = M3::Clone(Processor[ik]->GetHpost(Index));
745  CumulativeDistribution[ik]->Fill(0., 0.);
746  CumulativeDistribution[ik]->Reset();
747  CumulativeDistribution[ik]->SetMaximum(1.);
748  TString TempTitle = Title+" Kolmogorov Smirnov";
749  CumulativeDistribution[ik]->SetTitle(TempTitle);
750 
751  TempTitle = Title+" Value";
752  CumulativeDistribution[ik]->GetXaxis()->SetTitle(TempTitle);
753  CumulativeDistribution[ik]->GetYaxis()->SetTitle("Cumulative Probability");
754 
755  CumulativeDistribution[ik]->SetLineWidth(2);
756  CumulativeDistribution[ik]->SetLineColor(CumulativeColor[ik]);
757  CumulativeDistribution[ik]->SetLineStyle(CumulativeStyle[ik]);
758  }
759 
760  // Don't plot if this is a fixed histogram (i.e. the peak is the whole integral)
761  if(hpost[0]->GetMaximum() == hpost[0]->Integral()*1.5 || Skip) {
762  continue;
763  }
764 
765  for (int ik = 0 ; ik < nFiles; ik++)
766  {
767  const int NumberOfBins = hpost[ik]->GetXaxis()->GetNbins();
768  double Cumulative = 0;
769  const double Integral = hpost[ik]->Integral();
770  for (int j = 1; j < NumberOfBins+1; ++j)
771  {
772  Cumulative += hpost[ik]->GetBinContent(j)/Integral;
773  CumulativeDistribution[ik]->SetBinContent(j, Cumulative);
774  }
775  //KS: Set overflow to 1 just in case
776  CumulativeDistribution[ik]->SetBinContent(NumberOfBins+1, 1.);
777  }
778 
779  std::vector<int> TestStatBin(nFiles, 0);
780  std::vector<double> TestStatD(nFiles, -999);
781  std::vector<std::unique_ptr<TLine>> LineD(nFiles);
782  //Find KS statistic
783  for (int ik = 1 ; ik < nFiles; ik++)
784  {
785  const int NumberOfBins = CumulativeDistribution[0]->GetXaxis()->GetNbins();
786  for (int j = 1; j < NumberOfBins+1; ++j)
787  {
788  const double BinValue = CumulativeDistribution[0]->GetBinCenter(j);
789  const int BinNumber = CumulativeDistribution[ik]->FindBin(BinValue);
790  //KS: Calculate D statistic for this bin, only save it if it's bigger than previously found value
791  double TempDstat = std::fabs(CumulativeDistribution[0]->GetBinContent(j) - CumulativeDistribution[ik]->GetBinContent(BinNumber));
792  if(TempDstat > TestStatD[ik])
793  {
794  TestStatD[ik] = TempDstat;
795  TestStatBin[ik] = j;
796  }
797  }
798  }
799 
800  for (int ik = 0 ; ik < nFiles; ik++)
801  {
802  LineD[ik] = std::make_unique<TLine>(CumulativeDistribution[0]->GetBinCenter(TestStatBin[ik]), 0, CumulativeDistribution[0]->GetBinCenter(TestStatBin[ik]), CumulativeDistribution[0]->GetBinContent(TestStatBin[ik]));
803  LineD[ik]->SetLineColor(CumulativeColor[ik]);
804  LineD[ik]->SetLineWidth(2.0);
805  }
806  CumulativeDistribution[0]->Draw();
807  for (int ik = 0 ; ik < nFiles; ik++)
808  CumulativeDistribution[ik]->Draw("SAME");
809 
810  auto leg = std::make_unique<TLegend>(0.15, 0.7, 0.5, 0.90);
811  leg->SetTextSize(0.04f);
812  for (int ik = 0; ik < nFiles; ik++)
813  leg->AddEntry(CumulativeDistribution[ik].get(), TitleNames[ik].c_str(), "l");
814  for (int ik = 1; ik < nFiles; ik++)
815  leg->AddEntry(LineD[ik].get(), Form("#Delta D = %.4f", TestStatD[ik]), "l");
816 
817  leg->SetLineColor(0);
818  leg->SetLineStyle(0);
819  leg->SetFillColor(0);
820  leg->SetFillStyle(0);
821  leg->Draw("SAME");
822 
823  for (int ik = 1; ik < nFiles; ik++)
824  LineD[ik]->Draw("sam");
825 
826  Posterior->cd();
827  Posterior->Print(canvasname);
828  } //End loop over parameter
829 }
std::vector< std::string > TitleNames
Definition: ProcessMCMC.cpp:28
int nFiles
Definition: ProcessMCMC.cpp:26
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.
constexpr static const int _BAD_INT_
Default value used for int initialisation.
Definition: Core.h:48

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 31 of file ProcessMCMC.cpp.

32 {
34  nFiles = 0;
35  if (argc != 3 && argc !=6 && argc != 8)
36  {
37  MACH3LOG_ERROR("How to use: ");
38  MACH3LOG_ERROR(" single chain: {} <Config> <MCMM_ND_Output.root>", argv[0]);
39  MACH3LOG_ERROR(" two chain: {} <Config> <MCMM_ND_Output_1.root> <Title 1> <MCMC_ND_Output_2.root> <Title 2>", argv[0]);
40  MACH3LOG_ERROR(" three chain: {} <Config> <MCMM_ND_Output_1.root> <Title 1> <MCMC_ND_Output_2.root> <Title 2> <MCMC_ND_Output_3.root> <Title 3>", argv[0]);
41  throw MaCh3Exception(__FILE__ , __LINE__ );
42  }
43 
44  config = argv[1];
45  YAML::Node card_yaml = M3OpenConfig(config);
46  if (!CheckNodeExists(card_yaml, "ProcessMCMC")) {
47  MACH3LOG_ERROR("The 'ProcessMCMC' node is not defined in the YAML configuration.");
48  throw MaCh3Exception(__FILE__ , __LINE__ );
49  }
50 
51  if (argc == 3)
52  {
53  MACH3LOG_INFO("Producing single fit output");
54  std::string filename = argv[2];
55  ProcessMCMC(filename);
56  }
57  // If we want to compare two or more fits (e.g. binning changes or introducing new params/priors)
58  else if (argc == 6 || argc == 8)
59  {
60  MACH3LOG_INFO("Producing two fit comparison");
61  FileNames.push_back(argv[2]);
62  TitleNames.push_back(argv[3]);
63 
64  FileNames.push_back(argv[4]);
65  TitleNames.push_back(argv[5]);
66  //KS: If there is third file add it
67  if(argc == 8)
68  {
69  FileNames.push_back(argv[6]);
70  TitleNames.push_back(argv[7]);
71  }
72 
74  }
75  return 0;
76 }
void SetMaCh3LoggerFormat()
Set messaging format of the logger.
Definition: MaCh3Logger.h:51
void ProcessMCMC(const std::string &inputFile)
Main function processing MCMC and Producing plots.
void MultipleProcessMCMC()
Function producing comparison of posterior and more betwen a few MCMC chains.
std::vector< std::string > FileNames
Definition: ProcessMCMC.cpp:27
bool CheckNodeExists(const YAML::Node &node, Args... args)
KS: Wrapper function to call the recursive helper.
Definition: YamlHelper.h:55

◆ MultipleProcessMCMC()

void MultipleProcessMCMC ( )
inline

Function producing comparison of posterior and more betwen a few MCMC chains.

Definition at line 211 of file ProcessMCMC.cpp.

212 {
213  YAML::Node card_yaml = M3OpenConfig(config.c_str());
214  YAML::Node Settings = card_yaml["ProcessMCMC"];
215 
216  constexpr Color_t PosteriorColor[] = {kBlue-1, kRed, kGreen+2};
217  //constexpr Style_t PosteriorStyle[] = {kSolid, kDashed, kDotted};
218  nFiles = int(FileNames.size());
219  std::vector<std::unique_ptr<MCMCProcessor>> Processor(nFiles);
220 
221  if(!Settings["BurnInSteps"]) {
222  MACH3LOG_WARN("BurnInSteps not set, defaulting to 20%");
223  }
224 
225  for (int ik = 0; ik < nFiles; ik++)
226  {
227  MACH3LOG_INFO("File for study: {}", FileNames[ik]);
228  // Make the processor
229  Processor[ik] = std::make_unique<MCMCProcessor>(FileNames[ik]);
230  Processor[ik]->SetOutputSuffix(("_" + std::to_string(ik)).c_str());
231 
232  Processor[ik]->SetExcludedTypes(GetFromManager<std::vector<std::string>>(Settings["ExcludedTypes"], {}));
233  Processor[ik]->SetExcludedNames(GetFromManager<std::vector<std::string>>(Settings["ExcludedNames"], {}));
234  Processor[ik]->SetExcludedGroups(GetFromManager<std::vector<std::string>>(Settings["ExcludedGroups"], {}));
235 
236  //Apply additional cuts to 1D posterior
237  Processor[ik]->SetPosterior1DCut(GetFromManager<std::string>(Settings["Posterior1DCut"], ""));
238 
239  Processor[ik]->SetPlotRelativeToPrior(GetFromManager<bool>(Settings["PlotRelativeToPrior"], false));
240  Processor[ik]->SetFancyNames(GetFromManager<bool>(Settings["FancyNames"], true));
241  Processor[ik]->Initialise();
242 
243  if(Settings["BurnInSteps"]) {
244  Processor[ik]->SetStepCut(Settings["BurnInSteps"].as<int>());
245  }else {
246  Processor[ik]->SetStepCut(static_cast<int>(Processor[ik]->GetnSteps()/5));
247  }
248 
249  if(Settings["MaxEntries"]) {
250  Processor[ik]->SetEntries(Get<int>(Settings["MaxEntries"], __FILE__, __LINE__));
251  }
252  if(Settings["NBins"]) {
253  Processor[ik]->SetNBins(Get<int>(Settings["NBins"], __FILE__, __LINE__));
254  }
255  }
256 
257  Processor[0]->MakePostfit(GetCustomBinning(Settings));
258  Processor[0]->DrawPostfit();
259  // Get edges from first histogram to ensure all params use same binning
260  std::map<std::string, std::pair<double, double>> ParamEdges;
261  for(int i = 0; i < Processor[0]->GetNParams(); ++i) {
262  // Get the histogram for the i-th parameter
263  TH1D* hist = Processor[0]->GetHpost(i);
264  if (!hist) {
265  MACH3LOG_DEBUG("Histogram for parameter {} is null.", i);
266  continue;
267  }
268 
269  // Get the parameter name (title of the histogram)
270  std::string paramName = hist->GetTitle();
271 
272  // Get the axis limits (edges)
273  TAxis* axis = hist->GetXaxis();
274  double xmin = axis->GetXmin();
275  double xmax = axis->GetXmax();
276 
277  MACH3LOG_DEBUG("Adding bin edges for {} equal to {:.4f}, {:.4f}",paramName, xmin, xmax);
278  // Insert into the map
279  ParamEdges[paramName] = std::make_pair(xmin, xmax);
280  }
281 
282  //KS: Multithreading here is very tempting but there are some issues with root that need to be resovled :(
283  for (int ik = 1; ik < nFiles; ik++)
284  {
285  // Make the postfit
286  Processor[ik]->MakePostfit(ParamEdges);
287  Processor[ik]->DrawPostfit();
288  }
289 
290  // Open a TCanvas to write the posterior onto
291  auto Posterior = std::make_unique<TCanvas>("PosteriorMulti", "PosteriorMulti", 0, 0, 1024, 1024);
292  gStyle->SetOptStat(0);
293  gStyle->SetOptTitle(0);
294  Posterior->SetGrid();
295  Posterior->SetBottomMargin(0.1f);
296  Posterior->SetTopMargin(0.05f);
297  Posterior->SetRightMargin(0.03f);
298  Posterior->SetLeftMargin(0.15f);
299 
300  // First filename: keep path, just remove ".root"
301  // Would be nice to specify outpath in a later update
302  size_t pos = FileNames[0].rfind(".root");
303  std::string base = (pos == std::string::npos) ? FileNames[0] : FileNames[0].substr(0, pos);
304  TString canvasname = base;
305 
306  // Remaining filenames: strip path and ".root"
307  // So if you have /path/to/file1.root and /path/to/file2.root or /another/path/to/file2.root, canvasname = /path/to/file1_file2.root
308  for (int ik = 1; ik < nFiles; ik++) {
309  pos = FileNames[ik].find_last_of('/');
310  base = (pos == std::string::npos) ? FileNames[ik] : FileNames[ik].substr(pos + 1);
311  pos = base.rfind(".root");
312  if (pos != std::string::npos) base = base.substr(0, pos);
313  canvasname += "_" + TString(base);
314  }
315 
316  canvasname = canvasname +".pdf[";
317 
318  Posterior->Print(canvasname);
319  // Once the pdf file is open no longer need to bracket
320  canvasname.ReplaceAll("[","");
321 
322  for(int i = 0; i < Processor[0]->GetNParams(); ++i)
323  {
324  // This holds the posterior density
325  std::vector<std::unique_ptr<TH1D>> hpost(nFiles);
326  std::vector<std::unique_ptr<TLine>> hpd(nFiles);
327  hpost[0] = M3::Clone(Processor[0]->GetHpost(i));
328  hpost[0]->GetYaxis()->SetTitle("Posterior Density");
329  bool Skip = false;
330  for (int ik = 1 ; ik < nFiles; ik++)
331  {
332  // KS: If somehow this chain doesn't given params we skip it
333  const int Index = Processor[ik]->GetParamIndexFromName(hpost[0]->GetTitle());
334  if(Index == M3::_BAD_INT_)
335  {
336  Skip = true;
337  break;
338  }
339  hpost[ik] = M3::Clone(Processor[ik]->GetHpost(Index));
340  }
341 
342  // Don't plot if this is a fixed histogram (i.e. the peak is the whole integral)
343  if(hpost[0]->GetMaximum() == hpost[0]->Integral()*1.5 || Skip) {
344  continue;
345  }
346  for (int ik = 0; ik < nFiles; ik++)
347  {
348  RemoveFitter(hpost[ik].get(), "Gauss");
349 
350  // Set some nice colours
351  hpost[ik]->SetLineColor(PosteriorColor[ik]);
352  //hpost[ik]->SetLineStyle(PosteriorStyle[ik]);
353  hpost[ik]->SetLineWidth(2);
354 
355  // Area normalise the distributions
356  hpost[ik]->Scale(1./hpost[ik]->Integral());
357  }
358  TString Title;
359  double Prior = 1.0;
360  double PriorError = 1.0;
361 
362  Processor[0]->GetNthParameter(i, Prior, PriorError, Title);
363 
364  // Now make the TLine for the Asimov
365  auto Asimov = std::make_unique<TLine>(Prior, hpost[0]->GetMinimum(), Prior, hpost[0]->GetMaximum());
366  Asimov->SetLineColor(kRed-3);
367  Asimov->SetLineWidth(2);
368  Asimov->SetLineStyle(kDashed);
369 
370  // Make a nice little TLegend
371  auto leg = std::make_unique<TLegend>(0.20, 0.7, 0.6, 0.97);
372  leg->SetTextSize(0.03f);
373  leg->SetFillColor(0);
374  leg->SetFillStyle(0);
375  leg->SetLineColor(0);
376  leg->SetLineStyle(0);
377  TString asimovLeg = Form("#splitline{Prior}{x = %.2f , #sigma = %.2f}", Prior, PriorError);
378  leg->AddEntry(Asimov.get(), asimovLeg, "l");
379 
380  for (int ik = 0; ik < nFiles; ik++)
381  {
382  TString rebinLeg = Form("#splitline{%s}{#mu = %.2f, #sigma = %.2f}", TitleNames[ik].c_str(), hpost[ik]->GetMean(), hpost[ik]->GetRMS());
383  leg->AddEntry(hpost[ik].get(), rebinLeg, "l");
384 
385  hpd[ik] = std::make_unique<TLine>(hpost[ik]->GetBinCenter(hpost[ik]->GetMaximumBin()), hpost[ik]->GetMinimum(),
386  hpost[ik]->GetBinCenter(hpost[ik]->GetMaximumBin()), hpost[ik]->GetMaximum());
387  hpd[ik]->SetLineColor(hpost[ik]->GetLineColor());
388  hpd[ik]->SetLineWidth(2);
389  hpd[ik]->SetLineStyle(kSolid);
390  }
391 
392  // Find the maximum value to nicely resize hist
393  double maximum = 0;
394  for (int ik = 0; ik < nFiles; ik++) maximum = std::max(maximum, hpost[ik]->GetMaximum());
395  for (int ik = 0; ik < nFiles; ik++) hpost[ik]->SetMaximum(1.3*maximum);
396 
397  hpost[0]->Draw("hist");
398  for (int ik = 1; ik < nFiles; ik++) hpost[ik]->Draw("hist same");
399  Asimov->Draw("same");
400  for (int ik = 0; ik < nFiles; ik++) hpd[ik]->Draw("same");
401  leg->Draw("same");
402  Posterior->cd();
403  Posterior->Print(canvasname);
404  }//End loop over parameters
405 
406  // Finally draw the parameter plot onto the PDF
407  // Close the .pdf file with all the posteriors
408  Posterior->cd();
409  Posterior->Clear();
410 
411  if(GetFromManager<bool>(Settings["PerformKStest"], true)) KolmogorovSmirnovTest(Processor, Posterior, canvasname);
412 
413  // Close the pdf file
414  MACH3LOG_INFO("Closing pdf {}", canvasname);
415  canvasname+="]";
416  Posterior->Print(canvasname);
417 }
void RemoveFitter(TH1D *hist, const std::string &name)
KS: Remove fitted TF1 from hist to make comparison easier.
#define MACH3LOG_WARN
Definition: MaCh3Logger.h:26
void KolmogorovSmirnovTest(const std::vector< std::unique_ptr< MCMCProcessor >> &Processor, const std::unique_ptr< TCanvas > &Posterior, const TString &canvasname)
KS: Perform KS test to check if two posteriors for the same parameter came from the same distribution...
std::map< std::string, std::pair< double, double > > GetCustomBinning(const YAML::Node &Settings)
Parse custom binning edges from a YAML configuration node.
Definition: ProcessMCMC.cpp:92

◆ ProcessMCMC()

void ProcessMCMC ( const std::string &  inputFile)
inline

Main function processing MCMC and Producing plots.

Definition at line 114 of file ProcessMCMC.cpp.

115 {
116  MACH3LOG_INFO("File for study: {} with config {}", inputFile, config);
117  // Make the processor)
118  auto Processor = std::make_unique<OscProcessor>(inputFile);
119 
120  YAML::Node card_yaml = M3OpenConfig(config.c_str());
121  YAML::Node Settings = card_yaml["ProcessMCMC"];
122 
123  const bool PlotCorr = GetFromManager<bool>(Settings["PlotCorr"], false);
124 
125  Processor->SetExcludedTypes(GetFromManager<std::vector<std::string>>(Settings["ExcludedTypes"], {}));
126  Processor->SetExcludedNames(GetFromManager<std::vector<std::string>>(Settings["ExcludedNames"], {}));
127  Processor->SetExcludedGroups(GetFromManager<std::vector<std::string>>(Settings["ExcludedGroups"], {}));
128 
129  //Apply additional cuts to 1D posterior
130  Processor->SetPosterior1DCut(GetFromManager<std::string>(Settings["Posterior1DCut"], ""));
131 
132  if(PlotCorr) Processor->SetOutputSuffix("_drawCorr");
133  //KS:Turn off plotting detector and some other setting, should be via some config
134  Processor->SetPlotRelativeToPrior(GetFromManager<bool>(Settings["PlotRelativeToPrior"], false));
135  Processor->SetPrintToPDF(GetFromManager<bool>(Settings["PrintToPDF"], true));
136 
137  //KS: Whether you want prior error bands for parameters with flat prior or not
138  Processor->SetPlotErrorForFlatPrior(GetFromManager<bool>(Settings["PlotErrorForFlatPrior"], true));
139  Processor->SetFancyNames(GetFromManager<bool>(Settings["FancyNames"], true));
140  Processor->SetPlotBinValue(GetFromManager<bool>(Settings["PlotBinValue"], false));
141  //KS: Plot only 2D posteriors with correlations greater than 0.2
142  Processor->SetPost2DPlotThreshold(GetFromManager<double>(Settings["Post2DPlotThreshold"], 0.2));
143 
144  Processor->Initialise();
145 
146  if(Settings["BurnInSteps"]) {
147  Processor->SetStepCut(Settings["BurnInSteps"].as<int>());
148  } else {
149  MACH3LOG_WARN("BurnInSteps not set, defaulting to 20%");
150  Processor->SetStepCut(static_cast<int>(Processor->GetnSteps()/5));
151  }
152  if(Settings["MaxEntries"]) {
153  Processor->SetEntries(Get<int>(Settings["MaxEntries"], __FILE__, __LINE__));
154  }
155  if(Settings["NBins"]) {
156  Processor->SetNBins(Get<int>(Settings["NBins"], __FILE__, __LINE__));
157  }
158  if(Settings["Thinning"])
159  {
160  if(Settings["Thinning"][0].as<bool>()){
161  Processor->ThinMCMC(Settings["Thinning"][1].as<int>());
162  }
163  }
164  // Make the postfit
165  Processor->MakePostfit(GetCustomBinning(Settings));
166  Processor->DrawPostfit();
167  //KS: Should set via config whether you want below or not
168  if(GetFromManager<bool>(Settings["MakeCredibleIntervals"], true)) {
169  Processor->MakeCredibleIntervals(GetFromManager<std::vector<double>>(Settings["CredibleIntervals"], {0.99, 0.90, 0.68}),
170  GetFromManager<std::vector<short int>>(Settings["CredibleIntervalsColours"], {436, 430, 422}),
171  GetFromManager<bool>(Settings["CredibleInSigmas"], false));
172  }
173  if(GetFromManager<bool>(Settings["CalcBayesFactor"], true)) CalcBayesFactor(Processor.get());
174  if(GetFromManager<bool>(Settings["CalcSavageDickey"], true)) CalcSavageDickey(Processor.get());
175  if(GetFromManager<bool>(Settings["CalcBipolarPlot"], false)) CalcBipolarPlot(Processor.get());
176  if(GetFromManager<bool>(Settings["CalcParameterEvolution"], false)) CalcParameterEvolution(Processor.get());
177 
178  if(PlotCorr)
179  {
180  Processor->SetSmoothing(GetFromManager<bool>(Settings["Smoothing"], true));
181  // Make the covariance matrix
182  //We have different treatment for multithread
183  Processor->CacheSteps();
184  //KS: Since we cached let's make fancy violins :)
185  if(GetFromManager<bool>(Settings["MakeViolin"], true)) Processor->MakeViolin();
186  Processor->MakeCovariance_MP();
187 
188  Processor->DrawCovariance();
189  if(GetFromManager<bool>(Settings["MakeCovarianceYAML"], true)) Processor->MakeCovarianceYAML(GetFromManager<std::string>(Settings["CovarianceYAMLOutName"], "UpdatedCorrelationMatrix.yaml"), GetFromManager<std::string>(Settings["CovarianceYAMLMeansMethod"], "HPD"));
190 
191  auto const &MakeSubOptimality = Settings["MakeSubOptimality"];
192  if(MakeSubOptimality[0].as<bool>()) Processor->MakeSubOptimality(MakeSubOptimality[1].as<int>());
193 
194  if(GetFromManager<bool>(Settings["MakeCredibleRegions"], false)) {
195  Processor->MakeCredibleRegions(GetFromManager<std::vector<double>>(Settings["CredibleRegions"], {0.99, 0.90, 0.68}),
196  GetFromManager<std::vector<short int>>(Settings["CredibleRegionStyle"], {2, 1, 3}),
197  GetFromManager<std::vector<short int>>(Settings["CredibleRegionColor"], {413, 406, 416}),
198  GetFromManager<bool>(Settings["CredibleInSigmas"], false),
199  GetFromManager<bool>(Settings["Draw2DPosterior"], true),
200  GetFromManager<bool>(Settings["DrawBestFit"], true));
201  }
202  if(GetFromManager<bool>(Settings["GetTrianglePlot"], true)) GetTrianglePlot(Processor.get());
203 
204  //KS: When creating covariance matrix longest time is spend on caching every step, since we already cached we can run some fancy covariance stability diagnostic
205  if(GetFromManager<bool>(Settings["DiagnoseCovarianceMatrix"], false)) DiagnoseCovarianceMatrix(Processor.get(), inputFile);
206  }
207  if(GetFromManager<bool>(Settings["ReweightPrior"], false)) ReweightPrior(Processor.get());
208  if(GetFromManager<bool>(Settings["JarlskogAnalysis"], true)) Processor->PerformJarlskogAnalysis();
209 }
void GetTrianglePlot(MCMCProcessor *Processor)
void DiagnoseCovarianceMatrix(MCMCProcessor *Processor, const std::string &inputFile)
KS: You validate stability of posterior covariance matrix, you set burn calc cov matrix increase burn...
void CalcBipolarPlot(MCMCProcessor *Processor)
void CalcParameterEvolution(MCMCProcessor *Processor)
void ReweightPrior(MCMCProcessor *Processor)
void CalcBayesFactor(MCMCProcessor *Processor)
KS: Calculate Bayes factor for a given hypothesis, most informative are those related to osc params....
void CalcSavageDickey(MCMCProcessor *Processor)

◆ ReweightPrior()

void ReweightPrior ( MCMCProcessor Processor)
inline

Definition at line 681 of file ProcessMCMC.cpp.

682 {
683  YAML::Node card_yaml = M3OpenConfig(config.c_str());
684  YAML::Node Settings = card_yaml["ProcessMCMC"];
685 
686  const auto& Prior = Settings["PriorReweighting"];
687  std::vector<std::string> Names = Prior[0].as<std::vector<std::string>>();
688  std::vector<double> NewCentral = Prior[1].as<std::vector<double>>();
689  std::vector<double> NewError = Prior[2].as<std::vector<double>>();
690 
691  Processor->ReweightPrior(Names, NewCentral, NewError);
692 }
void ReweightPrior(const std::vector< std::string > &Names, const std::vector< double > &NewCentral, const std::vector< double > &NewError)
Reweight Prior by giving new central value and new error.

◆ TMatrixIntoTH2D()

TH2D * TMatrixIntoTH2D ( TMatrixDSym *  Matrix,
const std::string &  title 
)
inline

KS: Convert TMatrix to TH2D, mostly useful for making fancy plots.

Definition at line 695 of file ProcessMCMC.cpp.

696 {
697  TH2D* hMatrix = new TH2D(title.c_str(), title.c_str(), Matrix->GetNrows(), 0.0, Matrix->GetNrows(), Matrix->GetNcols(), 0.0, Matrix->GetNcols());
698  for(int i = 0; i < Matrix->GetNrows(); i++)
699  {
700  for(int j = 0; j < Matrix->GetNcols(); j++)
701  {
702  //KS: +1 because there is offset in histogram relative to TMatrix
703  hMatrix->SetBinContent(i+1,j+1, (*Matrix)(i,j));
704  }
705  }
706  return hMatrix;
707 }

Variable Documentation

◆ config

std::string config

Definition at line 29 of file ProcessMCMC.cpp.

◆ FileNames

std::vector<std::string> FileNames

Definition at line 27 of file ProcessMCMC.cpp.

◆ nFiles

int nFiles

Definition at line 26 of file ProcessMCMC.cpp.

◆ TitleNames

std::vector<std::string> TitleNames

Definition at line 28 of file ProcessMCMC.cpp.