MaCh3  2.2.3
Reference Guide
ProcessMCMC.cpp
Go to the documentation of this file.
1 //MaCh3 includes
2 #include "Fitters/OscProcessor.h"
3 #include "Manager/Manager.h"
4 
8 
10 inline void ProcessMCMC(const std::string& inputFile);
12 inline void MultipleProcessMCMC();
13 inline void CalcBayesFactor(MCMCProcessor* Processor);
14 inline void CalcSavageDickey(MCMCProcessor* Processor);
15 inline void CalcBipolarPlot(MCMCProcessor* Processor);
16 inline void CalcParameterEvolution(MCMCProcessor* Processor);
17 inline void GetTrianglePlot(MCMCProcessor* Processor);
18 inline void DiagnoseCovarianceMatrix(MCMCProcessor* Processor, const std::string& inputFile);
19 inline void ReweightPrior(MCMCProcessor* Processor);
21 inline TH2D* TMatrixIntoTH2D(TMatrixDSym* Matrix, const std::string& title);
23 inline void KolmogorovSmirnovTest(const std::vector<std::unique_ptr<MCMCProcessor>>& Processor,
24  const std::unique_ptr<TCanvas>& Posterior,
25  const TString& canvasname);
26 int nFiles;
27 std::vector <std::string> FileNames;
28 std::vector <std::string> TitleNames;
29 std::string config;
30 
31 int main(int argc, char *argv[])
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 }
77 
92 std::map<std::string, std::pair<double, double>> GetCustomBinning(const YAML::Node& Settings)
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 }
113 
114 void ProcessMCMC(const std::string& inputFile)
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 }
210 
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 }
418 
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 }
439 
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 }
457 
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 }
472 
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 }
485 
486 void GetTrianglePlot(MCMCProcessor* Processor) {
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 }
504 
506 void DiagnoseCovarianceMatrix(MCMCProcessor* Processor, const std::string& inputFile)
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 }
680 
681 void ReweightPrior(MCMCProcessor* Processor)
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 }
693 
694 //KS: Convert TMatrix to TH2D, mostly useful for making fancy plots
695 TH2D* TMatrixIntoTH2D(TMatrixDSym* Matrix, const std::string& title)
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 }
708 
709 // KS: Perform KS test to check if two posteriors for the same parameter came from the same distribution
710 void KolmogorovSmirnovTest(const std::vector<std::unique_ptr<MCMCProcessor>>& Processor,
711  const std::unique_ptr<TCanvas>& Posterior,
712  const TString& canvasname)
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 }
void RemoveFitter(TH1D *hist, const std::string &name)
KS: Remove fitted TF1 from hist to make comparison easier.
#define MACH3LOG_DEBUG
Definition: MaCh3Logger.h:24
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:27
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:25
void SetMaCh3LoggerFormat()
Set messaging format of the logger.
Definition: MaCh3Logger.h:51
#define MACH3LOG_WARN
Definition: MaCh3Logger.h:26
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...
int main(int argc, char *argv[])
Definition: ProcessMCMC.cpp:31
std::string config
Definition: ProcessMCMC.cpp:29
TH2D * TMatrixIntoTH2D(TMatrixDSym *Matrix, const std::string &title)
KS: Convert TMatrix to TH2D, mostly useful for making fancy plots.
std::vector< std::string > TitleNames
Definition: ProcessMCMC.cpp:28
void CalcBipolarPlot(MCMCProcessor *Processor)
void CalcParameterEvolution(MCMCProcessor *Processor)
void ProcessMCMC(const std::string &inputFile)
Main function processing MCMC and Producing plots.
int nFiles
Definition: ProcessMCMC.cpp:26
void MultipleProcessMCMC()
Function producing comparison of posterior and more betwen a few MCMC chains.
std::vector< std::string > FileNames
Definition: ProcessMCMC.cpp:27
void ReweightPrior(MCMCProcessor *Processor)
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...
void CalcBayesFactor(MCMCProcessor *Processor)
KS: Calculate Bayes factor for a given hypothesis, most informative are those related to osc params....
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
void CalcSavageDickey(MCMCProcessor *Processor)
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
bool CheckNodeExists(const YAML::Node &node, Args... args)
KS: Wrapper function to call the recursive helper.
Definition: YamlHelper.h:55
#define M3OpenConfig(filename)
Macro to simplify calling LoadYaml with file and line info.
Definition: YamlHelper.h:561
Class responsible for processing MCMC chains, performing diagnostics, generating plots,...
Definition: MCMCProcessor.h:61
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 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.
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.
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 GetPolarPlot(const std::vector< std::string > &ParNames)
Make funny polar plot.
void ParameterEvolution(const std::vector< std::string > &Names, const std::vector< int > &NIntervals)
Make .gif of parameter evolution.
void GetCovariance(TMatrixDSym *&Cov, TMatrixDSym *&Corr)
Get the post-fit covariances and correlations.
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.
void SetStepCut(const std::string &Cuts)
Set the step cutting by string.
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.
Custom exception class for MaCh3 errors.
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 double _BAD_DOUBLE_
Default value used for double initialisation.
Definition: Core.h:46
constexpr static const int _BAD_INT_
Default value used for int initialisation.
Definition: Core.h:48