MaCh3  2.2.3
Reference Guide
PredictiveThrower.cpp
Go to the documentation of this file.
1 #include "PredictiveThrower.h"
4 
5 // *************************
7 // *************************
8  AlgorithmName = "PredictiveThrower";
9  if(!CheckNodeExists(fitMan->raw(), "Predictive")) {
10  MACH3LOG_ERROR("Predictive is missing in your main yaml config");
11  throw MaCh3Exception(__FILE__ , __LINE__ );
12  }
13 
14  ModelSystematic = nullptr;
15  // Use the full likelihood for the Prior/Posterior predictive pvalue
16  FullLLH = GetFromManager<bool>(fitMan->raw()["Predictive"]["FullLLH"], false, __FILE__, __LINE__ );
17  NModelParams = 0;
18 
19  Is_PriorPredictive = Get<bool>(fitMan->raw()["Predictive"]["PriorPredictive"], __FILE__, __LINE__);
20  Ntoys = Get<int>(fitMan->raw()["Predictive"]["Ntoy"], __FILE__, __LINE__);
21 
22  ReweightWeight.resize(Ntoys);
23  PenaltyTerm.resize(Ntoys);
24 }
25 
26 // *************************
27 // Destructor:
29 // *************************
30 
31 }
32 
33 // *************************
35 // *************************
36  // WARNING This should be removed in the future
37  auto DoNotThrowLegacyCov = GetFromManager<std::vector<std::string>>(fitMan->raw()["Predictive"]["DoNotThrowLegacyCov"], {}, __FILE__, __LINE__);
39  for (size_t i = 0; i < DoNotThrowLegacyCov.size(); ++i) {
40  for (size_t s = 0; s < systematics.size(); ++s) {
41  if (systematics[s]->GetName() == DoNotThrowLegacyCov[i]) {
42  systematics[s]->SetParameters();
43  break;
44  }
45  }
46  }
47 
49 
51  if (ModelSystematic && !ParameterOnlyToVary.empty()) {
52  for (int i = 0; i < ModelSystematic->GetNumParams(); ++i) {
53  if (ParameterOnlyToVary.find(i) == ParameterOnlyToVary.end()) {
55  }
56  }
57  }
58 }
59 
60 // *************************
62 // *************************
64  for (size_t iPDF = 0; iPDF < samples.size(); iPDF++)
65  {
66  auto* MaCh3Sample = dynamic_cast<SampleHandlerFD*>(samples[iPDF]);
67  if (!MaCh3Sample) {
68  MACH3LOG_ERROR("Sample {} do not inherit from SampleHandlerFD this is not implemented", samples[iPDF]->GetTitle());
69  throw MaCh3Exception(__FILE__, __LINE__);
70  }
71  TotalNumberOfSamples += samples[iPDF]->GetNsamples();
72  if(samples[iPDF]->GetNsamples() > 1){
73  MACH3LOG_ERROR("Sample has more than one sample {} ::", samples[iPDF]->GetNsamples());
74  throw MaCh3Exception(__FILE__ , __LINE__ );
75  }
76  }
77 
83 
86 
87  int currentIndex = 0;
88  for (size_t iPDF = 0; iPDF < samples.size(); ++iPDF) {
89  for (int subSampleIndex = 0; subSampleIndex < samples[iPDF]->GetNsamples(); ++subSampleIndex) {
90  SampleObjectMap[currentIndex] = static_cast<int>(iPDF); // map the current global sample index to this sample object
91  ++currentIndex;
92  }
93  }
94 
95  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
96  MC_Hist_Toy[sample].resize(Ntoys);
97  W2_Hist_Toy[sample].resize(Ntoys);
98  SampleNames[sample] = samples[sample]->GetTitle();
99  }
101 }
102 
103 // *************************
104 // Produce MaCh3 toys:
106 // *************************
107  int counter = 0;
108  for (size_t s = 0; s < systematics.size(); ++s) {
109  auto* MaCh3Params = dynamic_cast<ParameterHandlerGeneric*>(systematics[s]);
110  if(MaCh3Params) {
111  ModelSystematic = MaCh3Params;
112  counter++;
113  }
114  }
115 
117 
118  if(Is_PriorPredictive) {
119  MACH3LOG_INFO("You've chosen to run Prior Predictive Distribution");
120  } else {
121  auto PosteriorFileName = Get<std::string>(fitMan->raw()["Predictive"]["PosteriorFile"], __FILE__, __LINE__);
122  //KS: We use MCMCProcessor to get names of covariances that were actually used to produce given chain
123  MCMCProcessor Processor(PosteriorFileName);
124  Processor.Initialise();
125 
127  YAML::Node ConfigInChain = Processor.GetCovConfig(kXSecPar);
128  if(ModelSystematic){
129  YAML::Node ConfigNow = ModelSystematic->GetConfig();
130  if (!compareYAMLNodes(ConfigNow, ConfigInChain))
131  {
132  MACH3LOG_ERROR("Yaml configs in previous chain and current one are different", PosteriorFileName);
133  throw MaCh3Exception(__FILE__ , __LINE__ );
134  }
135  }
136  }
137  if(counter > 1) {
138  MACH3LOG_ERROR("Found {} ParmaterHandler inheriting from ParameterHandlerGeneric, I can accept at most 1", counter);
139  throw MaCh3Exception(__FILE__, __LINE__);
140  }
141 
142  for (size_t s = 0; s < systematics.size(); ++s) {
143  NModelParams += systematics[s]->GetNumParams();
144  }
145 
146  if (ModelSystematic) {
147  auto ThrowParamGroupOnly = GetFromManager<std::vector<std::string>>(fitMan->raw()["Predictive"]["ThrowParamGroupOnly"], {}, __FILE__, __LINE__);
148  auto UniqueParamGroup = ModelSystematic->GetUniqueParameterGroups();
149  auto ParameterOnlyToVaryString = GetFromManager<std::vector<std::string>>(fitMan->raw()["Predictive"]["ThrowSinlgeParams"], {}, __FILE__, __LINE__);
150 
151  if (!ThrowParamGroupOnly.empty() && !ParameterOnlyToVaryString.empty()) {
152  MACH3LOG_ERROR("Can't use ThrowParamGroupOnly and ThrowSinlgeParams at the same time");
153  throw MaCh3Exception(__FILE__, __LINE__);
154  }
155 
156  if (!ParameterOnlyToVaryString.empty()) {
157  MACH3LOG_INFO("I will throw only: {}", fmt::join(ParameterOnlyToVaryString, ", "));
158  std::vector<int> ParameterVary(ParameterOnlyToVaryString.size());
159 
160  for (size_t i = 0; i < ParameterOnlyToVaryString.size(); ++i) {
161  ParameterVary[i] = ModelSystematic->GetParIndex(ParameterOnlyToVaryString[i]);
162  if (ParameterVary[i] == M3::_BAD_INT_) {
163  MACH3LOG_ERROR("Can't proceed if param {} is missing", ParameterOnlyToVaryString[i]);
164  throw MaCh3Exception(__FILE__, __LINE__);
165  }
166  }
167  ParameterOnlyToVary = std::unordered_set<int>(ParameterVary.begin(), ParameterVary.end());
168  } else {
169  MACH3LOG_INFO("I have following parameter groups: {}", fmt::join(UniqueParamGroup, ", "));
170  if (ThrowParamGroupOnly.empty()) {
171  MACH3LOG_INFO("I will vary all");
172  } else {
173  std::unordered_set<std::string> throwOnlySet(ThrowParamGroupOnly.begin(), ThrowParamGroupOnly.end());
174  ParameterGroupsNotVaried.clear();
175 
176  for (const auto& group : UniqueParamGroup) {
177  if (throwOnlySet.find(group) == throwOnlySet.end()) {
178  ParameterGroupsNotVaried.push_back(group);
179  }
180  }
181 
182  MACH3LOG_INFO("I will vary: {}", fmt::join(ThrowParamGroupOnly, ", "));
183  MACH3LOG_INFO("Exclude: {}", fmt::join(ParameterGroupsNotVaried, ", "));
184  }
185  }
186  }
187 }
188 
189 // *************************
190 // Try loading toys
192 // *************************
193  auto PosteriorFileName = Get<std::string>(fitMan->raw()["Predictive"]["PosteriorFile"], __FILE__, __LINE__);
194  // Open the ROOT file
195  TFile* file = TFile::Open(PosteriorFileName.c_str(), "READ");
196  TDirectory* ToyDir = nullptr;
197  if (!file || file->IsZombie()) {
198  return false;
199  } else {
200  // Check for the "toys" directory
201  if ((ToyDir = file->GetDirectory("Toys"))) {
202  MACH3LOG_INFO("Found toys in Posterior file will attempt toy reading");
203  } else {
204  file->Close();
205  delete file;
206  return false;
207  }
208  }
209 
210  // Finally get the TTree branch with the penalty vectors for each of the toy throws
211  TTree* PenaltyTree = static_cast<TTree*>(file->Get("ToySummary"));
212  if (!PenaltyTree) {
213  MACH3LOG_WARN("ToySummary TTree not found in file.");
214  file->Close();
215  delete file;
216  return false;
217  }
218 
219  Ntoys = static_cast<int>(PenaltyTree->GetEntries());
220  int ConfigNtoys = Get<int>(fitMan->raw()["Predictive"]["Ntoy"], __FILE__, __LINE__);;
221  if (Ntoys != ConfigNtoys) {
222  MACH3LOG_WARN("Found different number of toys in saved file than asked to run!");
223  MACH3LOG_INFO("Will read _ALL_ toys in the file");
224  MACH3LOG_INFO("Ntoys in file: {}", Ntoys);
225  MACH3LOG_INFO("Ntoys specified: {}", ConfigNtoys);
226  }
227 
228  PenaltyTerm.resize(Ntoys);
229  ReweightWeight.resize(Ntoys);
230 
231  double Penalty = 0, Weight = 1;
232  PenaltyTree->SetBranchAddress("Penalty", &Penalty);
233  PenaltyTree->SetBranchAddress("Weight", &Weight);
234  PenaltyTree->SetBranchAddress("NModelParams", &NModelParams);
235 
236  for (int i = 0; i < Ntoys; ++i) {
237  PenaltyTree->GetEntry(i);
238  if (FullLLH) {
239  PenaltyTerm[i] = Penalty;
240  } else {
241  PenaltyTerm[i] = 0.0;
242  }
243 
244  ReweightWeight[i] = Weight;
245  }
246  // Resize all vectors and get sample names
248 
249  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
250  TH1D* DataHist1D = static_cast<TH1D*>(ToyDir->Get((SampleNames[sample] + "_data").c_str()));
251  Data_Hist[sample] = M3::Clone(DataHist1D);
252 
253  TH1D* MCHist1D = static_cast<TH1D*>(ToyDir->Get((SampleNames[sample] + "_mc").c_str()));
254  MC_Nom_Hist[sample] = M3::Clone(MCHist1D);
255 
256  TH1D* W2Hist1D = static_cast<TH1D*>(ToyDir->Get((SampleNames[sample] + "_w2").c_str()));
257  W2_Nom_Hist[sample] = M3::Clone(W2Hist1D);
258  }
259 
260 
261  for (int iToy = 0; iToy < Ntoys; ++iToy)
262  {
263  if (iToy % 100 == 0) MACH3LOG_INFO(" Loaded toy {}", iToy);
264 
265  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
266  TH1D* MCHist1D = static_cast<TH1D*>(ToyDir->Get((SampleNames[sample] + "_mc_" + std::to_string(iToy)).c_str()));
267  TH1D* W2Hist1D = static_cast<TH1D*>(ToyDir->Get((SampleNames[sample] + "_w2_" + std::to_string(iToy)).c_str()));
268 
269  MC_Hist_Toy[sample][iToy] = M3::Clone(MCHist1D);
270  W2_Hist_Toy[sample][iToy] = M3::Clone(W2Hist1D);
271  }
272  }
273 
274  file->Close();
275  delete file;
276  return true;
277 }
278 
279 // *************************
280 // Produce MaCh3 toys:
282 // *************************
284  if(LoadToys()) return;
285 
288 
289  auto PosteriorFileName = Get<std::string>(fitMan->raw()["Predictive"]["PosteriorFile"], __FILE__, __LINE__);
290 
291  MACH3LOG_INFO("Starting {}", __func__);
292 
293  outputFile->cd();
294  double Penalty = 0, Weight = 1;
295  int Draw = 0;
296 
297  TTree *ToyTree = new TTree("ToySummary", "ToySummary");
298  ToyTree->Branch("Penalty", &Penalty, "Penalty/D");
299  ToyTree->Branch("Weight", &Weight, "Weight/D");
300  ToyTree->Branch("Draw", &Draw, "Draw/I");
301  ToyTree->Branch("NModelParams", &NModelParams, "NModelParams/I");
302 
303  TDirectory* ToyDirectory = outputFile->mkdir("Toys");
304  ToyDirectory->cd();
305 
306  for (size_t iPDF = 0; iPDF < samples.size(); iPDF++)
307  {
308  auto* MaCh3Sample = dynamic_cast<SampleHandlerFD*>(samples[iPDF]);
309  for (int SampleIndex = 0; SampleIndex < MaCh3Sample->GetNsamples(); ++SampleIndex)
310  {
311  // Get nominal spectra and event rates
312  TH1D* DataHist1D = static_cast<TH1D*>(MaCh3Sample->GetDataHist(1));
313  Data_Hist[iPDF] = M3::Clone(DataHist1D, MaCh3Sample->GetTitle() + "_data");
314  Data_Hist[iPDF]->Write((MaCh3Sample->GetTitle() + "_data").c_str());
315 
316  TH1D* MCHist1D = static_cast<TH1D*>(MaCh3Sample->GetMCHist(1));
317  MC_Nom_Hist[iPDF] = M3::Clone(MCHist1D, MaCh3Sample->GetTitle() + "_mc");
318  MCHist1D->Write((MaCh3Sample->GetTitle() + "_mc").c_str());
319 
320  TH1D* W2Hist1D = static_cast<TH1D*>(MaCh3Sample->GetW2Hist(1));
321  W2_Nom_Hist[iPDF] = M3::Clone(W2Hist1D, MaCh3Sample->GetTitle() + "_w2");
322  W2Hist1D->Write((MaCh3Sample->GetTitle() + "_w2").c_str());
323  delete W2Hist1D;
324  }
325  }
326 
328  std::vector<std::vector<double>> branch_vals(systematics.size());
329  std::vector<std::vector<std::string>> branch_name(systematics.size());
330 
331  TChain* PosteriorFile = new TChain("posteriors");
332  PosteriorFile->Add(PosteriorFileName.c_str());
333  unsigned int Step = 0;
334  PosteriorFile->SetBranchAddress("step", &Step);
335 
336  if (PosteriorFile->GetBranch("Weight")) {
337  PosteriorFile->SetBranchStatus("Weight", true);
338  PosteriorFile->SetBranchAddress("Weight", &Weight);
339  } else {
340  MACH3LOG_WARN("Not applying reweighting weight");
341  Weight = 1.0;
342  }
343 
344  for (size_t s = 0; s < systematics.size(); ++s) {
345  systematics[s]->MatchMaCh3OutputBranches(PosteriorFile, branch_vals[s], branch_name[s]);
346  }
347  //Get the burn-in from the config
348  auto burn_in = Get<unsigned int>(fitMan->raw()["Predictive"]["BurnInSteps"], __FILE__, __LINE__);
349 
350  //DL: Adding sanity check for chains shorter than burn in
351  const unsigned int maxNsteps = static_cast<unsigned int>(PosteriorFile->GetMaximum("step"));
352  if(burn_in >= maxNsteps)
353  {
354  MACH3LOG_ERROR("You are running on a chain shorter than burn in cut");
355  MACH3LOG_ERROR("Maximal value of nSteps: {}, burn in cut {}", maxNsteps, burn_in);
356  MACH3LOG_ERROR("You will run into infinite loop");
357  MACH3LOG_ERROR("You can make new chain or modify burn in cut");
358  throw MaCh3Exception(__FILE__,__LINE__);
359  }
360 
361  TStopwatch TempClock;
362  TempClock.Start();
363  for(int i = 0; i < Ntoys; i++)
364  {
365  if( i % (Ntoys/10) == 0) {
367  }
368  int entry = 0;
369  Step = 0;
370 
371  //YSP: Ensures you get an entry from the mcmc even when burn_in is set to zero (Although not advised :p ).
372  //Take 200k burn in steps, WP: Eb C in 1st peaky
373  // If we have combined chains by hadd need to check the step in the chain
374  // Note, entry is not necessarily same as step due to merged ROOT files, so can't choose entry in the range BurnIn - nEntries :(
375  while(Step < burn_in){
376  entry = random->Integer(static_cast<unsigned int>(PosteriorFile->GetEntries()));
377  PosteriorFile->GetEntry(entry);
378  }
379  if(!Is_PriorPredictive) Draw = entry;
380  for (size_t s = 0; s < systematics.size(); ++s)
381  {
382  systematics[s]->SetParameters(branch_vals[s]);
383 
384  //KS: Below line can help you get prior predictive distributions which are helpful for getting pre and post ND fit spectra
385  //YSP: If not set in the config, the code runs SK Posterior Predictive distributions by default. If true, then the code runs SK prior predictive.
386  if(Is_PriorPredictive) systematics[s]->ThrowParameters();
387  }
388 
389  // This set some params to prior value this way you can evaluate errors from subset of errors
390  SetParamters();
391 
392  Penalty = 0;
393  if(FullLLH) {
394  for (size_t s = 0; s < systematics.size(); ++s) {
395  //KS: do times 2 because banff reports chi2
396  Penalty = 2.0 * systematics[s]->GetLikelihood();
397  }
398  }
399 
400  PenaltyTerm[i] = Penalty;
401  ReweightWeight[i] = Weight;
402 
403  for (size_t iPDF = 0; iPDF < samples.size(); iPDF++) {
404  samples[iPDF]->Reweight();
405  }
406 
407  for (size_t iPDF = 0; iPDF < samples.size(); iPDF++)
408  {
409  auto* MaCh3Sample = dynamic_cast<SampleHandlerFD*>(samples[iPDF]);
410  for (int SampleIndex = 0; SampleIndex < MaCh3Sample->GetNsamples(); ++SampleIndex)
411  {
412  TH1D* MCHist1D = static_cast<TH1D*>(MaCh3Sample->GetMCHist(1));
413  MC_Hist_Toy[iPDF][i] = M3::Clone(MCHist1D, MaCh3Sample->GetTitle() + "_mc_" + std::to_string(i));
414  MC_Hist_Toy[iPDF][i]->Write();
415 
416  TH1D* W2Hist1D = static_cast<TH1D*>(MaCh3Sample->GetW2Hist(1));
417  W2_Hist_Toy[iPDF][i] = M3::Clone(W2Hist1D, MaCh3Sample->GetTitle() + "_w2_" + std::to_string(i));
418  W2_Hist_Toy[iPDF][i]->Write();
419  delete W2Hist1D;
420  }
421  }
422  ToyTree->Fill();
423  }//end of toys loop
424  TempClock.Stop();
425 
426  delete PosteriorFile;
427  ToyDirectory->Close();
428  delete ToyDirectory;
429 
430  outputFile->cd();
431  ToyTree->Write();
432  delete ToyTree;
433 
434  MACH3LOG_INFO("{} took {:.2f}s to finish for {} toys", __func__, TempClock.RealTime(), Ntoys);
435 }
436 
437 // *************************
438 std::vector<std::unique_ptr<TH2D>> PredictiveThrower::ProduceSpectra(const std::vector<std::vector<std::unique_ptr<TH1D>>>& Toys,
439  const std::string suffix) {
440 // *************************
441  std::vector<double> MaxValue(TotalNumberOfSamples);
442  #ifdef MULTITHREAD
443  #pragma omp parallel for collapse(2)
444  #endif
445  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
446  for (int toy = 0; toy < Ntoys; ++toy) {
447  double max_val = Toys[sample][toy]->GetMaximum();
448  MaxValue[sample] = std::max(MaxValue[sample], max_val);
449  }
450  }
451 
452  std::vector<std::unique_ptr<TH2D>> Spectra(TotalNumberOfSamples);
453  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
454  // Get MC histogram x-axis binning
455  TH1D* refHist = Toys[sample][0].get();
456 
457  const int n_bins_x = refHist->GetNbinsX();
458  std::vector<double> x_bin_edges(n_bins_x + 1);
459  for (int b = 0; b <= n_bins_x; ++b) {
460  x_bin_edges[b] = refHist->GetXaxis()->GetBinLowEdge(b + 1); // ROOT bins start at 1
461  }
462  // Last edge is upper edge of last bin:
463  x_bin_edges[n_bins_x] = refHist->GetXaxis()->GetBinUpEdge(n_bins_x);
464 
465  constexpr int n_bins_y = 400;
466  constexpr double y_min = 0.0;
467  const double y_max = MaxValue[sample] * 1.05;
468 
469  // Create TH2D with variable binning on x axis
470  Spectra[sample] = std::make_unique<TH2D>(
471  (SampleNames[sample] + "_" + suffix).c_str(), // name
472  (SampleNames[sample] + "_" + suffix).c_str(), // title
473  n_bins_x, x_bin_edges.data(), // x axis bins
474  n_bins_y, y_min, y_max // y axis bins
475  );
476 
477  Spectra[sample]->SetDirectory(nullptr);
478  Spectra[sample]->Sumw2(true);
479  }
480 
481  #ifdef MULTITHREAD
482  #pragma omp parallel for
483  #endif
484  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
485  for (int toy = 0; toy < Ntoys; ++toy) {
486  FastViolinFill(Spectra[sample].get(), Toys[sample][toy].get());
487  }
488  }
489 
490  return Spectra;
491 }
492 
493 // *************************
494 std::unique_ptr<TH1D> PredictiveThrower::MakePredictive(const std::vector<std::unique_ptr<TH1D>>& Toys,
495  const std::string& Sample_Name,
496  const std::string& suffix,
497  const bool DebugHistograms) {
498 // *************************
499  constexpr int nXBins = 100;
500  int nbinsx = Toys[0]->GetNbinsX();
501 
502  auto PredictiveHist = std::make_unique<TH1D>((Sample_Name + "_" + suffix + "_PostPred").c_str(),
503  (Sample_Name + "_" + suffix + "_PostPred").c_str(),
504  nbinsx, Toys[0]->GetXaxis()->GetXbins()->GetArray());
505  PredictiveHist->SetDirectory(nullptr);
506 
507  for (int i = 1; i <= nbinsx; ++i) {
508  double x_low = Toys[0]->GetXaxis()->GetBinLowEdge(i);
509  double x_high = Toys[0]->GetXaxis()->GetBinUpEdge(i);
510  TString projName = TString::Format("%s %s X: [%.3f, %.3f]", Sample_Name.c_str(), suffix.c_str(), x_low, x_high);
511  auto PosteriorHist = std::make_unique<TH1D>(projName, projName, nXBins, 1, -1);
512  PosteriorHist->SetDirectory(nullptr);
513 
514  for (size_t iToy = 0; iToy < Toys.size(); ++iToy) {
515  const double Content = Toys[iToy]->GetBinContent(i);
516  PosteriorHist->Fill(Content, ReweightWeight[iToy]);
517  }
518 
519  if(DebugHistograms) PosteriorHist->Write();
520 
521  const double nMean = PosteriorHist->GetMean();
522  const double nMeanError = PosteriorHist->GetRMS();
523 
524  PredictiveHist->SetBinContent(i, nMean);
525  PredictiveHist->SetBinError(i, nMeanError);
526  }
527 
528  PredictiveHist->Write();
529  return PredictiveHist;
530 }
531 
532 // *************************
533 // Perform predictive analysis
535 // *************************
536  MACH3LOG_INFO("Starting {}", __func__);
537  TStopwatch TempClock;
538  TempClock.Start();
539 
540  auto DebugHistograms = GetFromManager<bool>(fitMan->raw()["Predictive"]["DebugHistograms"], false, __FILE__, __LINE__);
541 
542  TDirectory* PredictiveDir = outputFile->mkdir("Predictive");
543  std::vector<TDirectory*> SampleDirectories;
544  SampleDirectories.resize(TotalNumberOfSamples+1);
545 
546  for (int sample = 0; sample < TotalNumberOfSamples+1; ++sample) {
547  SampleDirectories[sample] = PredictiveDir->mkdir(SampleNames[sample].c_str());
548  }
549 
550  std::vector<std::unique_ptr<TH2D>> Spectra_mc = ProduceSpectra(MC_Hist_Toy, "mc");
551  //std::vector<std::unique_ptr<TH2D>> Spectra_w2 = ProduceSpectra(W2_Hist_Toy, "w2");
552  std::vector<std::unique_ptr<TH1D>> PostPred_mc(TotalNumberOfSamples);
553  //std::vector<std::unique_ptr<TH1D>> PostPred_w2(TotalNumberOfSamples);
554  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
555  SampleDirectories[sample]->cd();
556  Spectra_mc[sample]->Write();
557  //Spectra_w2[sample]->Write();
558 
559  PostPred_mc[sample] = MakePredictive(MC_Hist_Toy[sample], SampleNames[sample], "mc", DebugHistograms);
560  //PostPred_w2[sample] = MakePredictive(W2_Hist_Toy[sample], SampleNames[sample], "w2", DebugHistograms);
561  }
562 
563  PosteriorPredictivepValue(PostPred_mc,
564  //PostPred_w2,
565  SampleDirectories);
566 
567  // Close directories
568  for (int sample = 0; sample < TotalNumberOfSamples+1; ++sample) {
569  SampleDirectories[sample]->Close();
570  delete SampleDirectories[sample];
571  }
572 
573  PredictiveDir->Close();
574  delete PredictiveDir;
575 
576  outputFile->cd();
577 
578  TempClock.Stop();
579  MACH3LOG_INFO("{} took {:.2f}s to finish for {} toys", __func__, TempClock.RealTime(), Ntoys);
580 }
581 
582 // *************************
583 double PredictiveThrower::GetLLH(const std::unique_ptr<TH1D>& DatHist,
584  const std::unique_ptr<TH1D>& MCHist,
585  const std::unique_ptr<TH1D>& W2Hist,
586  SampleHandlerBase* SampleHandler) {
587 // *************************
588  double llh = 0.0;
589  for (int i = 1; i <= DatHist->GetXaxis()->GetNbins(); ++i)
590  {
591  const double data = DatHist->GetBinContent(i);
592  const double mc = MCHist->GetBinContent(i);
593  const double w2 = W2Hist->GetBinContent(i);
594  llh += SampleHandler->GetTestStatLLH(data, mc, w2);
595  }
596  //KS: do times 2 because banff reports chi2
597  return 2*llh;
598 }
599 
600 // *************************
601 void PredictiveThrower::PosteriorPredictivepValue(const std::vector<std::unique_ptr<TH1D>>& PostPred_mc,
602  //const std::vector<std::unique_ptr<TH1D>>& PostPred_w2,
603  const std::vector<TDirectory*>& SampleDir) {
604 // *************************
605  //(void) PostPred_w2;
606  // [Toys][Sample]
607  std::vector<std::vector<double>> chi2_dat_vec(Ntoys);
608  std::vector<std::vector<double>> chi2_mc_vec(Ntoys);
609  std::vector<std::vector<double>> chi2_pred_vec(Ntoys);
610 
611  for(int iToy = 0; iToy < Ntoys; iToy++) {
612  chi2_dat_vec[iToy].resize(TotalNumberOfSamples+1, 0);
613  chi2_mc_vec[iToy].resize(TotalNumberOfSamples+1, 0);
614  chi2_pred_vec[iToy].resize(TotalNumberOfSamples+1, 0);
615 
616  chi2_dat_vec[iToy].back() = PenaltyTerm[iToy];
617  chi2_mc_vec[iToy].back() = PenaltyTerm[iToy];
618  chi2_pred_vec[iToy].back() = PenaltyTerm[iToy];
619 
621  for (int iSample = 0; iSample < TotalNumberOfSamples; ++iSample) {
622  auto DrawFluctHist = M3::Clone(MC_Hist_Toy[iSample][iToy].get());
623  MakeFluctuatedHistogramAlternative(DrawFluctHist.get(), MC_Hist_Toy[iSample][iToy].get(), random.get());
624 
625  auto PredFluctHist = M3::Clone(PostPred_mc[iSample].get());
626  MakeFluctuatedHistogramAlternative(PredFluctHist.get(), PostPred_mc[iSample].get(), random.get());
627 
628  // Okay now we can do our chi2 calculation for our sample
629  chi2_dat_vec[iToy][iSample] = GetLLH(Data_Hist[iSample], MC_Hist_Toy[iSample][iToy], W2_Hist_Toy[iSample][iToy], samples[SampleObjectMap[iSample]]);
630  chi2_mc_vec[iToy][iSample] = GetLLH(DrawFluctHist, MC_Hist_Toy[iSample][iToy], W2_Hist_Toy[iSample][iToy], samples[SampleObjectMap[iSample]]);
631  chi2_pred_vec[iToy][iSample] = GetLLH(PredFluctHist, MC_Hist_Toy[iSample][iToy], W2_Hist_Toy[iSample][iToy], samples[SampleObjectMap[iSample]]);
632 
633  chi2_dat_vec[iToy].back() += chi2_dat_vec[iToy][iSample];
634  chi2_mc_vec[iToy].back() += chi2_mc_vec[iToy][iSample];
635  chi2_pred_vec[iToy].back() += chi2_pred_vec[iToy][iSample];
636  }
637  }
638 
639  MakeChi2Plots(chi2_mc_vec, "-2LLH (Draw Fluc, Draw)", chi2_dat_vec, "-2LLH (Data, Draw)", SampleDir, "_drawfluc_draw");
640  MakeChi2Plots(chi2_pred_vec, "-2LLH (Pred Fluc, Draw)", chi2_dat_vec, "-2LLH (Data, Draw)", SampleDir, "_predfluc_draw");
641 }
642 
643 // *************************
644 void PredictiveThrower::MakeChi2Plots(const std::vector<std::vector<double>>& Chi2_x,
645  const std::string& Chi2_x_title,
646  const std::vector<std::vector<double>>& Chi2_y,
647  const std::string& Chi2_y_title,
648  const std::vector<TDirectory*>& SampleDir,
649  const std::string Title) {
650 // *************************
651  for (int iSample = 0; iSample < TotalNumberOfSamples+1; ++iSample) {
652  SampleDir[iSample]->cd();
653 
654  // Transpose to extract chi2 values for a given sample across all toys
655  std::vector<double> chi2_y_sample(Ntoys);
656  std::vector<double> chi2_x_per_sample(Ntoys);
657 
658  for (int iToy = 0; iToy < Ntoys; ++iToy) {
659  chi2_y_sample[iToy] = Chi2_y[iToy][iSample];
660  chi2_x_per_sample[iToy] = Chi2_x[iToy][iSample];
661  }
662 
663  const double min_val = std::min(*std::min_element(chi2_y_sample.begin(), chi2_y_sample.end()),
664  *std::min_element(chi2_x_per_sample.begin(), chi2_x_per_sample.end()));
665  const double max_val = std::max(*std::max_element(chi2_y_sample.begin(), chi2_y_sample.end()),
666  *std::max_element(chi2_x_per_sample.begin(), chi2_x_per_sample.end()));
667 
668  auto chi2_hist = std::make_unique<TH2D>((SampleNames[iSample] + Title).c_str(),
669  (SampleNames[iSample] + Title).c_str(),
670  100, min_val, max_val, 100, min_val, max_val);
671  chi2_hist->SetDirectory(nullptr);
672  chi2_hist->GetXaxis()->SetTitle(Chi2_x_title.c_str());
673  chi2_hist->GetYaxis()->SetTitle(Chi2_y_title.c_str());
674 
675  for (int iToy = 0; iToy < Ntoys; ++iToy) {
676  chi2_hist->Fill(chi2_x_per_sample[iToy], chi2_y_sample[iToy]);
677  }
678 
679  Get2DBayesianpValue(chi2_hist.get());
680  chi2_hist->Write();
681  }
682 }
MaCh3Plotting::PlottingManager * man
void MakeFluctuatedHistogramAlternative(TH1D *FluctHist, TH1D *PolyHist, TRandom3 *rand)
Make Poisson fluctuation of TH1D hist using slow method which is only for cross-check.
void FastViolinFill(TH2D *violin, TH1D *hist_1d)
KS: Fill Violin histogram with entry from a toy.
@ kXSecPar
Definition: MCMCProcessor.h:49
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:27
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:25
#define MACH3LOG_WARN
Definition: MaCh3Logger.h:26
void Get2DBayesianpValue(TH2D *Histogram)
Calculates the 2D Bayesian p-value and generates a visualization.
bool compareYAMLNodes(const YAML::Node &node1, const YAML::Node &node2)
Compare if yaml nodes are identical.
Definition: YamlHelper.h:180
bool CheckNodeExists(const YAML::Node &node, Args... args)
KS: Wrapper function to call the recursive helper.
Definition: YamlHelper.h:55
Base class for implementing fitting algorithms.
Definition: FitterBase.h:23
std::string GetName() const
Get name of class.
Definition: FitterBase.h:70
std::unique_ptr< TRandom3 > random
Random number.
Definition: FitterBase.h:146
std::vector< SampleHandlerBase * > samples
Sample holder.
Definition: FitterBase.h:131
TFile * outputFile
Output.
Definition: FitterBase.h:149
manager * fitMan
The manager.
Definition: FitterBase.h:110
std::string AlgorithmName
Name of fitting algorithm that is being used.
Definition: FitterBase.h:170
std::vector< ParameterHandlerBase * > systematics
Systematic holder.
Definition: FitterBase.h:136
Class responsible for processing MCMC chains, performing diagnostics, generating plots,...
Definition: MCMCProcessor.h:61
void Initialise()
Scan chain, what parameters we have and load information from covariance matrices.
YAML::Node GetCovConfig(const int i) const
Get Yaml config obtained from a Chain.
Custom exception class for MaCh3 errors.
Class responsible for handling of systematic error parameters with different types defined in the con...
void SetParamters()
This set some params to prior value this way you can evaluate errors from subset of errors.
std::vector< double > PenaltyTerm
Penalty term values for each toy by default 0.
std::vector< std::string > SampleNames
Name of a single sample.
std::vector< std::unique_ptr< TH1D > > MC_Nom_Hist
Vector of MC histograms.
virtual ~PredictiveThrower()
Destructor.
bool FullLLH
KS: Use Full LLH or only sample contribution based on discussion with Asher we almost always only wan...
std::unique_ptr< TH1D > MakePredictive(const std::vector< std::unique_ptr< TH1D >> &Toys, const std::string &Sample_Name, const std::string &suffix, const bool DebugHistograms)
Produce posterior predictive distribution.
void RunPredictiveAnalysis()
Main routine responsible for producing posterior predictive distributions and $p$-value.
bool LoadToys()
Load existing toys.
PredictiveThrower(manager *const fitMan)
Constructor.
std::vector< std::vector< std::unique_ptr< TH1D > > > W2_Hist_Toy
std::unordered_set< int > ParameterOnlyToVary
KS: Index of parameters groups that will be varied.
bool Is_PriorPredictive
Whether it is Prior or Posterior predictive.
std::vector< std::string > ParameterGroupsNotVaried
KS: Names of parameter groups that will not be varied.
std::vector< std::unique_ptr< TH1D > > W2_Nom_Hist
Vector of W2 histograms.
int NModelParams
KS: Count total number of model parameters which can be used for stuff like BIC.
int Ntoys
Number of toys we are generating analysing.
void SetupToyGeneration()
Setup useful variables etc before stating toy generation.
void MakeChi2Plots(const std::vector< std::vector< double >> &Chi2_x, const std::string &Chi2_x_title, const std::vector< std::vector< double >> &Chi2_y, const std::string &Chi2_y_title, const std::vector< TDirectory * > &SampleDir, const std::string Title)
Produce Chi2 plot for a single sample based on which $p$-value is calculated.
std::vector< int > SampleObjectMap
Maps if sample with given SampleHandler, useful if we have more than one sample in single object.
void SetupSampleInformation()
Setup sample information.
void PosteriorPredictivepValue(const std::vector< std::unique_ptr< TH1D >> &PostPred_mc, const std::vector< TDirectory * > &SampleDir)
Calculate Posterior Predictive $p$-value.
int TotalNumberOfSamples
Number of toys we are generating analysing.
void ProduceToys()
Produce toys by throwing from MCMC.
std::vector< std::unique_ptr< TH2D > > ProduceSpectra(const std::vector< std::vector< std::unique_ptr< TH1D >>> &Toys, const std::string suffix)
Produce Violin style spectra.
ParameterHandlerGeneric * ModelSystematic
Pointer to El Generico.
std::vector< double > ReweightWeight
Reweighting factors applied for each toy, by default 1.
double GetLLH(const std::unique_ptr< TH1D > &DatHist, const std::unique_ptr< TH1D > &MCHist, const std::unique_ptr< TH1D > &W2Hist, SampleHandlerBase *SampleHandler)
Helper functions to calculate likelihoods using TH1D.
std::vector< std::unique_ptr< TH1D > > Data_Hist
Vector of Data histograms.
std::vector< std::vector< std::unique_ptr< TH1D > > > MC_Hist_Toy
Class responsible for handling implementation of samples used in analysis, reweighting and returning ...
Class responsible for handling implementation of samples used in analysis, reweighting and returning ...
The manager class is responsible for managing configurations and settings.
Definition: Manager.h:16
YAML::Node const & raw()
Return config.
Definition: Manager.h:41
int GetNumParams() const
Get total number of parameters.
int GetParIndex(const std::string &name) const
Get index based on name.
double GetParInit(const int i) const
Get prior parameter value.
std::vector< std::string > GetUniqueParameterGroups()
KS: Get names of all unique parameter groups.
YAML::Node GetConfig() const
Getter to return a copy of the YAML node.
void SetParProp(const int i, const double val)
Set proposed parameter value.
void SetGroupOnlyParameters(const std::string &Group, const std::vector< double > &Pars={})
KS Function to set to prior parameters of a given group or values from vector.
double GetTestStatLLH(const double data, const double mc, const double w2) const
Calculate test statistic for a single bin. Calculation depends on setting of fTestStatistic....
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.
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.
constexpr static const int _BAD_INT_
Default value used for int initialisation.
Definition: Core.h:48
void PrintProgressBar(const Long64_t Done, const Long64_t All)
KS: Simply print progress bar.
Definition: Monitor.cpp:213