MaCh3  2.6.0
Reference Guide
FitterBase.cpp
Go to the documentation of this file.
1 #include "FitterBase.h"
2 
4 #include "TRandom.h"
5 #include "TStopwatch.h"
6 #include "TTree.h"
7 #include "TGraphAsymmErrors.h"
9 
10 #pragma GCC diagnostic ignored "-Wuseless-cast"
11 
12 // *************************
13 // Initialise the Manager and make it an object of FitterBase class
14 // Now we can dump Manager settings to the output file
15 FitterBase::FitterBase(Manager * const man) : fitMan(man) {
16 // *************************
17  AlgorithmName = "";
18  //Get mach3 modes from Manager
19  random = std::make_unique<TRandom3>(Get<int>(fitMan->raw()["General"]["Seed"], __FILE__, __LINE__));
20 
21  // Counter of the accepted # of steps
22  accCount = 0;
23  step = 0;
24  stepStart = 0;
25 
26  clock = std::make_unique<TStopwatch>();
27  stepClock = std::make_unique<TStopwatch>();
28  #ifdef MACH3_DEBUG
29  // Fit summary and debug info
30  debug = GetFromManager<bool>(fitMan->raw()["General"]["Debug"], false, __FILE__ , __LINE__);
31  #endif
32 
33  auto outfile = Get<std::string>(fitMan->raw()["General"]["OutputFile"], __FILE__ , __LINE__);
34  // Save output every auto_save steps
35  //you don't want this too often https://root.cern/root/html606/TTree_8cxx_source.html#l01229
36  auto_save = Get<int>(fitMan->raw()["General"]["MCMC"]["AutoSave"], __FILE__ , __LINE__);
37 
38  // Set the output file
39  outputFile = M3::Open(outfile, "RECREATE", __FILE__, __LINE__);
40  outputFile->cd();
41  // Set output tree
42  outTree = new TTree("posteriors", "Posterior_Distributions");
43  // Auto-save every 200MB, the bigger the better https://root.cern/root/html606/TTree_8cxx_source.html#l01229
44  outTree->SetAutoSave(-200E6);
45 
46  FileSaved = false;
47  SettingsSaved = false;
48  OutputPrepared = false;
49 
50  //Create TDirectory
51  CovFolder = outputFile->mkdir("CovarianceFolder");
52  outputFile->cd();
53  SampleFolder = outputFile->mkdir("SampleFolder");
54  outputFile->cd();
55 
56  #ifdef MACH3_DEBUG
57  // Prepare the output log file
58  if (debug) debugFile.open((outfile+".log").c_str());
59  #endif
60 
61  TotalNSamples = 0;
62  fTestLikelihood = GetFromManager<bool>(fitMan->raw()["General"]["Fitter"]["FitTestLikelihood"], false, __FILE__ , __LINE__);
63 }
64 
65 // *************************
66 // Destructor: close the logger and output file
68 // *************************
69  SaveOutput();
70  if(outputFile != nullptr) delete outputFile;
71  outputFile = nullptr;
72  MACH3LOG_DEBUG("Closing MaCh3 Fitter Engine");
73 }
74 
75 // *******************
76 // Prepare the output tree
78 // *******************
79  if(SettingsSaved) return;
80 
81  outputFile->cd();
82 
83  TDirectory* MaCh3Version = outputFile->mkdir("MaCh3Engine");
84  MaCh3Version->cd();
85 
86  if (std::getenv("MaCh3_ROOT") == nullptr) {
87  MACH3LOG_ERROR("Need MaCh3_ROOT environment variable");
88  MACH3LOG_ERROR("Please remember about source bin/setup.MaCh3.sh");
89  throw MaCh3Exception(__FILE__ , __LINE__ );
90  }
91 
92  if (std::getenv("MACH3") == nullptr) {
93  MACH3LOG_ERROR("Need MACH3 environment variable");
94  throw MaCh3Exception(__FILE__ , __LINE__ );
95  }
96 
97  std::string header_path = std::string(std::getenv("MACH3"));
98  header_path += "/version.h";
99  FILE* file = fopen(header_path.c_str(), "r");
100  //KS: It is better to use experiment specific header file. If given experiment didn't provide it we gonna use one given by Core MaCh3.
101  if (!file) {
102  header_path = std::string(std::getenv("MaCh3_ROOT"));
103  header_path += "/version.h";
104  } else {
105  fclose(file);
106  }
107 
108  // EM: embed the cmake generated version.h file
109  TMacro versionHeader("version_header", "version_header");
110  versionHeader.ReadFile(header_path.c_str());
111  versionHeader.Write();
112 
113  if(GetName() == ""){
114  MACH3LOG_ERROR("Name of currently used algorithm is {}", GetName());
115  MACH3LOG_ERROR("Have you forgotten to modify AlgorithmName?");
116  throw MaCh3Exception(__FILE__ , __LINE__ );
117  }
118  TNamed Engine(GetName(), GetName());
119  Engine.Write(GetName().c_str());
120 
121  MaCh3Version->Write();
122  delete MaCh3Version;
123 
124  outputFile->cd();
125 
127 
128  MACH3LOG_WARN("\033[0;31mCurrent Total RAM usage is {:.2f} GB\033[0m", M3::Utils::getValue("VmRSS") / 1048576.0);
129  MACH3LOG_WARN("\033[0;31mOut of Total available RAM {:.2f} GB\033[0m", M3::Utils::getValue("MemTotal") / 1048576.0);
130 
131  MACH3LOG_INFO("#####Current Setup#####");
132  MACH3LOG_INFO("Number of covariances: {}", systematics.size());
133  for(unsigned int i = 0; i < systematics.size(); ++i)
134  MACH3LOG_INFO("{}: Cov name: {}, it has {} params", i, systematics[i]->GetName(), systematics[i]->GetNumParams());
135  MACH3LOG_INFO("Number of SampleHandlers: {}", samples.size());
136  for(unsigned int i = 0; i < samples.size(); ++i) {
137  MACH3LOG_INFO("{}: SampleHandler name: {}, it has {} samples",i , samples[i]->GetName(), samples[i]->GetNSamples());
138  for(int iSam = 0; iSam < samples[i]->GetNSamples(); ++iSam) {
139  MACH3LOG_INFO(" {}: Sample title: {}, with {} osc channels",iSam , samples[i]->GetSampleTitle(iSam), samples[i]->GetNOscChannels(iSam));
140  }
141  }
142  //TN: Have to close the folder in order to write it to disk before SaveOutput is called in the destructor
143  CovFolder->Close();
144  SampleFolder->Close();
145 
146  SettingsSaved = true;
147 }
148 
149 // *******************
150 // Prepare the output tree
152 // *******************
153  if(OutputPrepared) return;
154  //MS: Check if we are fitting the test likelihood, rather than T2K likelihood, and only setup T2K output if not
155  if(!fTestLikelihood)
156  {
157  // Check that we have added samples
158  if (!samples.size()) {
159  MACH3LOG_CRITICAL("No samples Found! Is this really what you wanted?");
160  //throw MaCh3Exception(__FILE__ , __LINE__ );
161  }
162 
163  // Do we want to save proposal? This will break plotting scripts and is heave for disk space and step time. Only use when debugging
164  bool SaveProposal = GetFromManager<bool>(fitMan->raw()["General"]["SaveProposal"], false, __FILE__ , __LINE__);
165 
166  if(SaveProposal) MACH3LOG_INFO("Will save in the chain proposal parameters and LogL");
167  // Prepare the output trees
168  for (ParameterHandlerBase *cov : systematics) {
169  cov->SetBranches(*outTree, SaveProposal);
170  }
171 
172  outTree->Branch("LogL", &logLCurr, "LogL/D");
173  if(SaveProposal) outTree->Branch("LogLProp", &logLProp, "LogLProp/D");
174  outTree->Branch("accProb", &accProb, "accProb/D");
175  outTree->Branch("step", &step, "step/i");
176  outTree->Branch("stepTime", &stepTime, "stepTime/D");
177 
178  // Store individual likelihood components
179  // Using double means double as large output file!
180  sample_llh.resize(samples.size());
181  syst_llh.resize(systematics.size());
182 
183  for (size_t i = 0; i < samples.size(); ++i) {
184  std::stringstream oss, oss2;
185  oss << "LogL_sample_" << i;
186  oss2 << oss.str() << "/D";
187  outTree->Branch(oss.str().c_str(), &sample_llh[i], oss2.str().c_str());
188  }
189 
190  for (size_t i = 0; i < systematics.size(); ++i) {
191  std::stringstream oss, oss2;
192  oss << "LogL_systematic_" << systematics[i]->GetName();
193  oss2 << oss.str() << "/D";
194  outTree->Branch(oss.str().c_str(), &syst_llh[i], oss2.str().c_str());
195  }
196  }
197  else
198  {
199  outTree->Branch("LogL", &logLCurr, "LogL/D");
200  outTree->Branch("accProb", &accProb, "accProb/D");
201  outTree->Branch("step", &step, "step/i");
202  outTree->Branch("stepTime", &stepTime, "stepTime/D");
203  }
204 
205  MACH3LOG_INFO("-------------------- Starting MCMC --------------------");
206  #ifdef MACH3_DEBUG
207  if (debug) {
208  debugFile << "----- Starting MCMC -----" << std::endl;
209  }
210  #endif
211  // Time the progress
212 
213 
214  clock->Start();
215 
216 
217  OutputPrepared = true;
218 }
219 
220 // *******************
222 // *******************
223  for (size_t i = 0; i < samples.size(); ++i) {
224  samples[i]->CleanMemoryBeforeFit();
225  }
226 }
227 
228 // *******************
230 // *******************
231  if(FileSaved) return;
232  //Stop Clock
233  clock->Stop();
234 
235  //KS: Some version of ROOT keep spamming about accessing already deleted object which is wrong and not helpful...
236  int originalErrorLevel = gErrorIgnoreLevel;
237  gErrorIgnoreLevel = kFatal;
238 
239  outputFile->cd();
240  outTree->Write();
241 
242  MACH3LOG_INFO("{} steps took {:.2e} seconds to complete. ({:.2e}s / step).", step - stepStart, clock->RealTime(), clock->RealTime() / static_cast<double>(step - stepStart));
243  MACH3LOG_INFO("{} steps were accepted.", accCount);
244  #ifdef MACH3_DEBUG
245  if (debug)
246  {
247  debugFile << "\n\n" << step << " steps took " << clock->RealTime() << " seconds to complete. (" << clock->RealTime() / step << "s / step).\n" << accCount<< " steps were accepted." << std::endl;
248  debugFile.close();
249  }
250  #endif
251 
252  outputFile->Close();
253  FileSaved = true;
254 
255  gErrorIgnoreLevel = originalErrorLevel;
256 }
257 
258 // *************************
259 // Add SampleHandler object to the Markov Chain
261 // *************************
262  // Check if any subsample name collides with already-registered subsamples
263  for (const auto &s : samples) {
264  for (int iExisting = 0; iExisting < s->GetNSamples(); ++iExisting) {
265  for (int iNew = 0; iNew < sample->GetNSamples(); ++iNew) {
266  if (s->GetSampleTitle(iExisting) == sample->GetSampleTitle(iNew)) {
268  "Duplicate sample title '{}' in handler {} detected: "
269  "same title exist in handler ", sample->GetSampleTitle(iNew),
270  sample->GetName(), s->GetName());
271  throw MaCh3Exception(__FILE__, __LINE__);
272  }
273  }
274  }
275  }
276 
277  for (const auto &s : samples) {
278  if (s->GetName() == sample->GetName()) {
279  MACH3LOG_ERROR("SampleHandler with name '{}' already exists!", sample->GetName());
280  MACH3LOG_ERROR("Is it intended?");
281  throw MaCh3Exception(__FILE__ , __LINE__ );
282  }
283  }
284  // Save additional info from samples
285  SampleFolder->cd();
286 
288  TotalNSamples += sample->GetNSamples();
289  MACH3LOG_INFO("Adding {} object, with {} samples", sample->GetName(), sample->GetNSamples());
290  samples.push_back(sample);
291  outputFile->cd();
292 }
293 
294 // *************************
295 // Add flux systematics, cross-section systematics, ND systematics to the chain
297 // *************************
298  MACH3LOG_INFO("Adding systematic object {}, with {} params", cov->GetName(), cov->GetNumParams());
299  // KS: Need to make sure we don't have params with same name, otherwise ROOT I/O and parts of MaCh3 will be terribly confused...
300  for (size_t s = 0; s < systematics.size(); ++s)
301  {
302  for (int iPar = 0; iPar < systematics[s]->GetNumParams(); ++iPar)
303  {
304  for (int i = 0; i < cov->GetNumParams(); ++i)
305  {
306  if(systematics[s]->GetParName(iPar) == cov->GetParName(i)){
307  MACH3LOG_ERROR("ParameterHandler {} has param '{}' which already exists in in {}, with name {}",
308  cov->GetName(), cov->GetParName(i), systematics[s]->GetName(), systematics[s]->GetParName(iPar));
309  throw MaCh3Exception(__FILE__ , __LINE__ );
310  }
311  // Same for fancy name
312  if(systematics[s]->GetParFancyName(iPar) == cov->GetParFancyName(i)){
313  MACH3LOG_ERROR("ParameterHandler {} has param '{}' which already exists in {}, with name {}",
314  cov->GetName(), cov->GetParFancyName(i), systematics[s]->GetName(), systematics[s]->GetParFancyName(iPar));
315  throw MaCh3Exception(__FILE__ , __LINE__ );
316  }
317  }
318  }
319  }
320 
321  systematics.push_back(cov);
322 
323  CovFolder->cd();
324  std::vector<double> n_vec(cov->GetNumParams());
325  for (int i = 0; i < cov->GetNumParams(); ++i) {
326  n_vec[i] = cov->GetParPreFit(i);
327  }
328  cov->GetCovMatrix()->Write(cov->GetName().c_str());
329 
330  TH2D* CorrMatrix = cov->GetCorrelationMatrix();
331  CorrMatrix->Write((cov->GetName() + std::string("_Corr")).c_str());
332  delete CorrMatrix;
333 
334  // If we have yaml config file for covariance let's save it
335  YAML::Node Config = cov->GetConfig();
336  if(!Config.IsNull())
337  {
338  TMacro ConfigSave = YAMLtoTMacro(Config, (std::string("Config_") + cov->GetName()));
339  ConfigSave.Write();
340  }
341 
342  outputFile->cd();
343 }
344 
345 // *******************
346 void FitterBase::StartFromPreviousFit(const std::string& FitName) {
347 // *******************
348  MACH3LOG_INFO("Getting starting position from {}", FitName);
349  TFile *infile = M3::Open(FitName, "READ", __FILE__, __LINE__);
350  TTree *posts = infile->Get<TTree>("posteriors");
351  double log_val = M3::_LARGE_LOGL_;
352  posts->SetBranchAddress("LogL",&log_val);
353 
354  for (size_t s = 0; s < systematics.size(); ++s)
355  {
356  TDirectory* CovarianceFolder = infile->Get<TDirectory>("CovarianceFolder");
357 
358  std::string ConfigName = "Config_" + systematics[s]->GetName();
359  TMacro *ConfigCov = CovarianceFolder->Get<TMacro>(ConfigName.c_str());
360  // KS: Not every covariance uses yaml, if it uses yaml make sure they are identical
361  if (ConfigCov != nullptr) {
362  // Config which was in MCMC from which we are starting
363  YAML::Node CovSettings = TMacroToYAML(*ConfigCov);
364  // Config from currently used cov object
365  YAML::Node ConfigCurrent = systematics[s]->GetConfig();
366 
367  if (!compareYAMLNodes(CovSettings, ConfigCurrent))
368  {
369  MACH3LOG_ERROR("Yaml configs in previous chain (from path {}) and current one are different", FitName);
370  throw MaCh3Exception(__FILE__ , __LINE__ );
371  }
372  delete ConfigCov;
373  }
374 
375  CovarianceFolder->Close();
376  delete CovarianceFolder;
377 
378  std::vector<double> branch_vals;
379  std::vector<std::string> branch_name;
380  systematics[s]->MatchMaCh3OutputBranches(posts, branch_vals, branch_name);
381  posts->GetEntry(posts->GetEntries()-1);
382 
383  systematics[s]->SetParameters(branch_vals);
384  systematics[s]->AcceptStep();
385 
386  MACH3LOG_INFO("Printing new starting values for: {}", systematics[s]->GetName());
387  systematics[s]->PrintPreFitCurrPropValues();
388 
389  // Resetting branch addressed to nullptr as we don't want to write into a deleted vector out of scope...
390  for (int i = 0; i < systematics[s]->GetNumParams(); ++i) {
391  posts->SetBranchAddress(systematics[s]->GetParName(i).c_str(), nullptr);
392  }
393  }
394  logLCurr = log_val;
395  logLProp = log_val;
396 
397  delete posts;
398  infile->Close();
399  delete infile;
400 }
401 
402 // *******************
403 // Process the MCMC output to get postfit etc
405 // *******************
406  if (fitMan == nullptr) return;
407 
408  // Process the MCMC
409  if (GetFromManager<bool>(fitMan->raw()["General"]["ProcessMCMC"], false, __FILE__ , __LINE__)){
410  // Make the processor
411  MCMCProcessor Processor(std::string(outputFile->GetName()));
412 
413  Processor.Initialise();
414  // Make the TVectorD pointers which hold the processed output
415  TVectorD *Central = nullptr;
416  TVectorD *Errors = nullptr;
417  TVectorD *Central_Gauss = nullptr;
418  TVectorD *Errors_Gauss = nullptr;
419  TVectorD *Peaks = nullptr;
420 
421  // Make the postfit
422  Processor.GetPostfit(Central, Errors, Central_Gauss, Errors_Gauss, Peaks);
423  Processor.DrawPostfit();
424 
425  // Make the TMatrix pointers which hold the processed output
426  TMatrixDSym *Covariance = nullptr;
427  TMatrixDSym *Correlation = nullptr;
428 
429  // Make the covariance matrix
430  Processor.GetCovariance(Covariance, Correlation);
431  Processor.DrawCovariance();
432 
433  std::vector<TString> BranchNames = Processor.GetBranchNames();
434 
435  // Re-open the TFile
436  if (!outputFile->IsOpen()) {
437  MACH3LOG_INFO("Opening output again to update with means..");
438  outputFile = new TFile(Get<std::string>(fitMan->raw()["General"]["OutputFile"], __FILE__, __LINE__).c_str(), "UPDATE");
439  }
440  Central->Write("PDF_Means");
441  Errors->Write("PDF_Errors");
442  Central_Gauss->Write("Gauss_Means");
443  Errors_Gauss->Write("Errors_Gauss");
444  Covariance->Write("Covariance");
445  Correlation->Write("Correlation");
446  }
447 }
448 
449 // *************************
450 // Run Drag Race
451 void FitterBase::DragRace(const int NLaps) {
452 // *************************
453  MACH3LOG_INFO("Let the Race Begin!");
454  MACH3LOG_INFO("All tests will be performed with {} threads", M3::GetNThreads());
455 
456  // Reweight the MC
457  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs)
458  {
459  TStopwatch clockRace;
460  clockRace.Start();
461  for(int Lap = 0; Lap < NLaps; ++Lap) {
462  samples[ivs]->Reweight();
463  }
464  clockRace.Stop();
465  MACH3LOG_INFO("It took {:.4f} s to reweights {} times sample: {}", clockRace.RealTime(), NLaps, samples[ivs]->GetName());
466  MACH3LOG_INFO("On average {:.6f}", clockRace.RealTime()/NLaps);
467  }
468 
469  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs)
470  {
471  TStopwatch clockRace;
472  clockRace.Start();
473  for(int Lap = 0; Lap < NLaps; ++Lap) {
474  samples[ivs]->GetLikelihood();
475  }
476  clockRace.Stop();
477  MACH3LOG_INFO("It took {:.4f} s to calculate GetLikelihood {} times sample: {}", clockRace.RealTime(), NLaps, samples[ivs]->GetName());
478  MACH3LOG_INFO("On average {:.6f}", clockRace.RealTime()/NLaps);
479  }
480  // Get vector of proposed steps. If we want to run LLH scan or something else after we need to revert changes after proposing steps multiple times
481  std::vector<std::vector<double>> StepsValuesBefore(systematics.size());
482  for (size_t s = 0; s < systematics.size(); ++s) {
483  StepsValuesBefore[s] = systematics[s]->GetProposed();
484  }
485  for (size_t s = 0; s < systematics.size(); ++s) {
486  TStopwatch clockRace;
487  clockRace.Start();
488  for(int Lap = 0; Lap < NLaps; ++Lap) {
489  systematics[s]->ProposeStep();
490  }
491  clockRace.Stop();
492  MACH3LOG_INFO("It took {:.4f} s to propose step {} times cov: {}", clockRace.RealTime(), NLaps, systematics[s]->GetName());
493  MACH3LOG_INFO("On average {:.6f}", clockRace.RealTime()/NLaps);
494  }
495  for (size_t s = 0; s < systematics.size(); ++s) {
496  systematics[s]->SetParameters(StepsValuesBefore[s]);
497  }
498 
499  for (size_t s = 0; s < systematics.size(); ++s) {
500  TStopwatch clockRace;
501  clockRace.Start();
502  for(int Lap = 0; Lap < NLaps; ++Lap) {
503  systematics[s]->GetLikelihood();
504  }
505  clockRace.Stop();
506  MACH3LOG_INFO("It took {:.4f} s to calculate get likelihood {} times cov: {}", clockRace.RealTime(), NLaps, systematics[s]->GetName());
507  MACH3LOG_INFO("On average {:.6f}", clockRace.RealTime()/NLaps);
508  }
509  MACH3LOG_INFO("End of race");
510 }
511 
512 // *************************
513 bool FitterBase::GetScanRange(std::map<std::string, std::vector<double>>& scanRanges) const {
514 // *************************
515  bool isScanRanges = false;
516  // YSP: Set up a mapping to store parameters with user-specified ranges, suggested by D. Barrow
517  if(fitMan->raw()["LLHScan"]["ScanRanges"]){
518  YAML::Node scanRangesList = fitMan->raw()["LLHScan"]["ScanRanges"];
519  for (auto it = scanRangesList.begin(); it != scanRangesList.end(); ++it) {
520  std::string itname = it->first.as<std::string>();
521  std::vector<double> itrange = it->second.as<std::vector<double>>();
522  // Set the mapping as param_name:param_range
523  scanRanges[itname] = itrange;
524  }
525  isScanRanges = true;
526  } else {
527  MACH3LOG_INFO("There are no user-defined parameter ranges, so I'll use default param bounds for LLH Scans");
528  }
529  return isScanRanges;
530 }
531 
532 // *************************
533 bool FitterBase::CheckSkipParameter(const std::vector<std::string>& SkipVector, const std::string& ParamName) const {
534 // *************************
535  return M3::CaseInsensitiveMatchAny(ParamName, SkipVector);
536 }
537 
538 
539 // *************************
540 void FitterBase::GetParameterScanRange(const ParameterHandlerBase* cov, const int i, double& CentralValue,
541  double& lower, double& upper, const int n_points, const std::string& suffix) const {
542 // *************************
543  // YSP: Set up a mapping to store parameters with user-specified ranges, suggested by D. Barrow
544  std::map<std::string, std::vector<double>> scanRanges;
545  const bool isScanRanges = GetScanRange(scanRanges);
546 
547  double nSigma = GetFromManager<int>(fitMan->raw()["LLHScan"]["LLHScanSigma"], 1., __FILE__, __LINE__);
548  bool IsPCA = cov->IsPCA();
549 
550  // Get the parameter name
551  std::string name = cov->GetParFancyName(i);
552  if (IsPCA) name += "_PCA";
553 
554  // Get the parameter priors and bounds
555  CentralValue = cov->GetParProp(i);
556  if (IsPCA) CentralValue = cov->GetPCAHandler()->GetParPropPCA(i);
557 
558  double prior = cov->GetParPreFit(i);
559  if (IsPCA) prior = cov->GetPCAHandler()->GetPreFitValuePCA(i);
560 
561  if (std::abs(CentralValue - prior) > 1e-10) {
562  MACH3LOG_INFO("For {} scanning around value {} rather than prior {}", name, CentralValue, prior);
563  }
564 
565  // Get the covariance matrix and do the +/- nSigma
566  // Set lower and upper bounds relative the CentralValue
567  // Set the parameter ranges between which LLH points are scanned
568  lower = CentralValue - nSigma*cov->GetDiagonalError(i);
569  upper = CentralValue + nSigma*cov->GetDiagonalError(i);
570  // If PCA, transform these parameter values to the PCA basis
571  if (IsPCA) {
572  lower = CentralValue - nSigma*std::sqrt((cov->GetPCAHandler()->GetEigenValues())(i));
573  upper = CentralValue + nSigma*std::sqrt((cov->GetPCAHandler()->GetEigenValues())(i));
574  MACH3LOG_INFO("eval {} = {:.2f}", i, cov->GetPCAHandler()->GetEigenValues()(i));
575  MACH3LOG_INFO("CV {} = {:.2f}", i, CentralValue);
576  MACH3LOG_INFO("lower {} = {:.2f}", i, lower);
577  MACH3LOG_INFO("upper {} = {:.2f}", i, upper);
578  MACH3LOG_INFO("nSigma = {:.2f}", nSigma);
579  }
580 
581  // Implementation suggested by D. Barrow
582  // If param ranges are specified in scanRanges node, extract it from there
583  if(isScanRanges){
584  // Find matching entries through std::maps
585  auto it = scanRanges.find(name);
586  if (it != scanRanges.end() && it->second.size() == 2) { //Making sure the range is has only two entries
587  lower = it->second[0];
588  upper = it->second[1];
589  MACH3LOG_INFO("Found matching param name for setting specified range for {}", name);
590  MACH3LOG_INFO("Range for {} = [{:.2f}, {:.2f}]", name, lower, upper);
591  }
592  }
593 
594  // Cross-section and flux parameters have boundaries that we scan between, check that these are respected in setting lower and upper variables
595  // This also applies for other parameters like osc, etc.
596  lower = std::max(lower, cov->GetLowerBound(i));
597  upper = std::min(upper, cov->GetUpperBound(i));
598  MACH3LOG_INFO("Scanning {} {} with {} steps, from [{:.2f} , {:.2f}], CV = {:.2f}", suffix, name, n_points, lower, upper, CentralValue);
599 }
600 
601 // *************************
602 // Run LLH scan
604 // *************************
605  // Save the settings into the output file
606  SaveSettings();
607 
608  MACH3LOG_INFO("Starting {}", __func__);
609 
610  //KS: Turn it on if you want LLH scan for each ND sample separately, which increase time significantly but can be useful for validating new samples or dials.
611  bool PlotLLHScanBySample = GetFromManager<bool>(fitMan->raw()["LLHScan"]["LLHScanBySample"], false, __FILE__ , __LINE__);
612  auto SkipVector = GetFromManager<std::vector<std::string>>(fitMan->raw()["LLHScan"]["LLHScanSkipVector"], {}, __FILE__ , __LINE__);
613 
614  // Now finally get onto the LLH scan stuff
615  // Very similar code to MCMC but never start MCMC; just scan over the parameter space
616  std::vector<TDirectory *> Cov_LLH(systematics.size());
617  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc )
618  {
619  std::string NameTemp = systematics[ivc]->GetName();
620  NameTemp = NameTemp.substr(0, NameTemp.find("_cov")) + "_LLH";
621  Cov_LLH[ivc] = outputFile->mkdir(NameTemp.c_str());
622  }
623 
624  std::vector<TDirectory *> SampleClass_LLH(samples.size());
625  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
626  {
627  std::string NameTemp = samples[ivs]->GetName();
628  SampleClass_LLH[ivs] = outputFile->mkdir(NameTemp.c_str());
629  }
630 
631  TDirectory *Sample_LLH = outputFile->mkdir("Sample_LLH");
632  TDirectory *Total_LLH = outputFile->mkdir("Total_LLH");
633 
634  std::vector<TDirectory *>SampleSplit_LLH;
635  if(PlotLLHScanBySample)
636  {
637  SampleSplit_LLH.resize(TotalNSamples);
638  int SampleIterator = 0;
639  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
640  {
641  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is )
642  {
643  SampleSplit_LLH[SampleIterator] = outputFile->mkdir((samples[ivs]->GetSampleTitle(is)+ "_LLH").c_str());
644  SampleIterator++;
645  }
646  }
647  }
648  // Number of points we do for each LLH scan
649  const int n_points = GetFromManager<int>(fitMan->raw()["LLHScan"]["LLHScanPoints"], 100, __FILE__ , __LINE__);
650 
651  // We print 5 reweights
652  const int countwidth = int(double(n_points)/double(5));
653 
654  // Loop over the covariance classes
655  for (ParameterHandlerBase *cov : systematics)
656  {
657  // Scan over all the parameters
658  // Get the number of parameters
659  int npars = cov->GetNumParams();
660  bool IsPCA = cov->IsPCA();
661  if (IsPCA) npars = cov->GetNParameters();
662  for (int i = 0; i < npars; ++i)
663  {
664  // Get the parameter name
665  std::string name = cov->GetParFancyName(i);
666  if (IsPCA) name += "_PCA";
667  // KS: Check if we want to skip this parameter
668  if(CheckSkipParameter(SkipVector, name)) continue;
669  // Get the parameter central and bounds
670  double CentralValue, lower, upper;
671  GetParameterScanRange(cov, i, CentralValue, lower, upper, n_points);
672  // Make the TH1D
673  auto hScan = std::make_unique<TH1D>((name + "_full").c_str(), (name + "_full").c_str(), n_points, lower, upper);
674  hScan->SetTitle((std::string("2LLH_full, ") + name + ";" + name + "; -2(ln L_{sample} + ln L_{xsec+flux} + ln L_{det})").c_str());
675  hScan->SetDirectory(nullptr);
676 
677  auto hScanSam = std::make_unique<TH1D>((name + "_sam").c_str(), (name + "_sam").c_str(), n_points, lower, upper);
678  hScanSam->SetTitle((std::string("2LLH_sam, ") + name + ";" + name + "; -2(ln L_{sample})").c_str());
679  hScanSam->SetDirectory(nullptr);
680 
681  std::vector<std::unique_ptr<TH1D>> hScanSample(samples.size());
682  std::vector<double> nSamLLH(samples.size(), 0.0);
683  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
684  {
685  std::string NameTemp = samples[ivs]->GetName();
686  hScanSample[ivs] = std::make_unique<TH1D>((name+"_"+NameTemp).c_str(), (name+"_" + NameTemp).c_str(), n_points, lower, upper);
687  hScanSample[ivs]->SetDirectory(nullptr);
688  hScanSample[ivs]->SetTitle(("2LLH_" + NameTemp + ", " + name + ";" + name + "; -2(ln L_{" + NameTemp +"})").c_str());
689  }
690 
691  std::vector<std::unique_ptr<TH1D>> hScanCov(systematics.size());
692  std::vector<double> nCovLLH(systematics.size(), 0.0);
693  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc )
694  {
695  std::string NameTemp = systematics[ivc]->GetName();
696  NameTemp = NameTemp.substr(0, NameTemp.find("_cov"));
697  hScanCov[ivc] = std::make_unique<TH1D>((name + "_" + NameTemp).c_str(), (name + "_" + NameTemp).c_str(), n_points, lower, upper);
698  hScanCov[ivc]->SetDirectory(nullptr);
699  hScanCov[ivc]->SetTitle(("2LLH_" + NameTemp + ", " + name + ";" + name + "; -2(ln L_{" + NameTemp +"})").c_str());
700  }
701 
702  std::vector<std::unique_ptr<TH1D>> hScanSamSplit;
703  std::vector<double> sampleSplitllh;
704  if(PlotLLHScanBySample)
705  {
706  int SampleIterator = 0;
707  hScanSamSplit.resize(TotalNSamples);
708  sampleSplitllh.resize(TotalNSamples);
709  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
710  {
711  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is )
712  {
713  auto histName = name + samples[ivs]->GetSampleTitle(is);
714  auto histTitle = std::string("2LLH_sam, ") + name + ";" + name + "; -2(ln L_{sample})";
715  hScanSamSplit[SampleIterator] = std::make_unique<TH1D>(histName.c_str(), histTitle.c_str(), n_points, lower, upper);
716  hScanSamSplit[SampleIterator]->SetDirectory(nullptr);
717  SampleIterator++;
718  }
719  }
720  }
721 
722  // Scan over the parameter space
723  for (int j = 0; j < n_points; ++j)
724  {
725  if (j % countwidth == 0)
726  M3::Utils::PrintProgressBar(j, n_points);
727 
728  // For PCA we have to do it differently
729  if (IsPCA) {
730  cov->GetPCAHandler()->SetParPropPCA(i, hScan->GetBinCenter(j+1));
731  } else {
732  // Set the parameter
733  cov->SetParProp(i, hScan->GetBinCenter(j+1));
734  }
735 
736  // Reweight the MC
737  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs ){
738  samples[ivs]->Reweight();
739  }
740  //Total LLH
741  double totalllh = 0.;
742 
743  // Get the -log L likelihoods
744  double samplellh = 0.;
745 
746  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs ) {
747  nSamLLH[ivs] = samples[ivs]->GetLikelihood();
748  samplellh += nSamLLH[ivs];
749  }
750 
751  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc ) {
752  nCovLLH[ivc] = systematics[ivc]->GetLikelihood();
753  totalllh += nCovLLH[ivc];
754  }
755 
756  totalllh += samplellh;
757 
758  if(PlotLLHScanBySample)
759  {
760  int SampleIterator = 0;
761  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
762  {
763  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is)
764  {
765  sampleSplitllh[SampleIterator] = samples[ivs]->GetSampleLikelihood(is);
766  SampleIterator++;
767  }
768  }
769  }
770 
771  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs ) {
772  hScanSample[ivs]->SetBinContent(j+1, 2*nSamLLH[ivs]);
773  }
774  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc ) {
775  hScanCov[ivc]->SetBinContent(j+1, 2*nCovLLH[ivc]);
776  }
777 
778  hScanSam->SetBinContent(j+1, 2*samplellh);
779  hScan->SetBinContent(j+1, 2*totalllh);
780 
781  if(PlotLLHScanBySample)
782  {
783  int SampleIterator = 0;
784  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
785  {
786  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is)
787  {
788  hScanSamSplit[SampleIterator]->SetBinContent(j+1, 2*sampleSplitllh[SampleIterator]);
789  SampleIterator++;
790  }
791  }
792  }
793  }
794  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc )
795  {
796  Cov_LLH[ivc]->cd();
797  hScanCov[ivc]->Write();
798  }
799 
800  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
801  {
802  SampleClass_LLH[ivs]->cd();
803  hScanSample[ivs]->Write();
804  }
805  Sample_LLH->cd();
806  hScanSam->Write();
807  Total_LLH->cd();
808  hScan->Write();
809 
810  if(PlotLLHScanBySample)
811  {
812  int SampleIterator = 0;
813  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
814  {
815  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is)
816  {
817  SampleSplit_LLH[SampleIterator]->cd();
818  hScanSamSplit[SampleIterator]->Write();
819  SampleIterator++;
820  }
821  }
822  }
823 
824  // Reset the parameters to their CentralValue central values
825  if (IsPCA) {
826  cov->GetPCAHandler()->SetParPropPCA(i, CentralValue);
827  } else {
828  cov->SetParProp(i, CentralValue);
829  }
830  }//end loop over systematics
831  }//end loop covariance classes
832 
833  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc )
834  {
835  Cov_LLH[ivc]->Write();
836  delete Cov_LLH[ivc];
837  }
838 
839  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
840  {
841  SampleClass_LLH[ivs]->Write();
842  delete SampleClass_LLH[ivs];
843  }
844 
845  Sample_LLH->Write();
846  delete Sample_LLH;
847 
848  Total_LLH->Write();
849  delete Total_LLH;
850 
851  if(PlotLLHScanBySample)
852  {
853  int SampleIterator = 0;
854  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
855  {
856  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is )
857  {
858  SampleSplit_LLH[SampleIterator]->Write();
859  delete SampleSplit_LLH[SampleIterator];
860  SampleIterator++;
861  }
862  }
863  }
864 }
865 
866 // *************************
867 //LLH scan is good first estimate of step scale
868 void FitterBase::GetStepScaleBasedOnLLHScan(const std::string& outputFileName) {
869 // *************************
870  TFile* outputFileLLH = nullptr;
871  bool ownsfile = false;
872  if(outputFileName != ""){
873  outputFileLLH = M3::Open(outputFileName, "READ", __FILE__, __LINE__);
874  ownsfile = true;
875  } else {
876  outputFileLLH = outputFile;
877  }
878  TDirectory *Sample_LLH = outputFileLLH->Get<TDirectory>("Sample_LLH");
879  MACH3LOG_INFO("Starting Get Step Scale Based On LLHScan");
880 
881  if(!Sample_LLH || Sample_LLH->IsZombie())
882  {
883  MACH3LOG_WARN("Couldn't find Sample_LLH, it looks like LLH scan wasn't run, will do this now");
884  RunLLHScan();
885  Sample_LLH = outputFileLLH->Get<TDirectory>("Sample_LLH");
886  }
887 
888  for (ParameterHandlerBase *cov : systematics)
889  {
890  const int npars = cov->GetNumParams();
891  std::vector<double> StepScale(npars);
892  for (int i = 0; i < npars; ++i)
893  {
894  std::string name = cov->GetParFancyName(i);
895  StepScale[i] = cov->GetIndivStepScale(i);
896  TH1D* LLHScan = Sample_LLH->Get<TH1D>((name+"_sam").c_str());
897  if(LLHScan == nullptr)
898  {
899  MACH3LOG_WARN("Couldn't find LLH scan, for {}, skipping", name);
900  continue;
901  }
902  const double LLH_val = std::max(LLHScan->GetBinContent(1), LLHScan->GetBinContent(LLHScan->GetNbinsX()));
903  //If there is no sensitivity leave it
904  if(LLH_val < 0.001) continue;
905 
906  // EM: assuming that the likelihood is gaussian, approximate sigma value is given by variation/sqrt(-2LLH)
907  // can evaluate this at any point, simple to evaluate it in the first bin of the LLH scan
908  // KS: We assume variation is 1 sigma, each dial has different scale so it becomes faff...
909  const double Var = 1.;
910  const double approxSigma = std::abs(Var)/std::sqrt(LLH_val);
911  const double GlobalScale = cov->GetGlobalStepScale();
912  // Based on Ewan comment I just took the 1sigma width from the LLH, assuming it was Gaussian, but then had to also scale by 2.38/sqrt(N_params)
913  const double TargetStep = approxSigma * 2.38 / std::sqrt(npars);
914  // KS: Need to divide by currently used gloalStepScale
915  const double NewStepScale = TargetStep / GlobalScale;
916 
917  StepScale[i] = NewStepScale;
918  MACH3LOG_DEBUG("Sigma: {}", approxSigma);
919  MACH3LOG_DEBUG("Target Step Size (before accounting for global step size): {}", TargetStep);
920  MACH3LOG_DEBUG("Optimal Step Size: {}", NewStepScale);
921  }
922  cov->SetIndivStepScale(StepScale);
923  cov->SaveUpdatedMatrixConfig();
924  }
925  if(ownsfile && outputFileLLH != nullptr) delete outputFileLLH;
926 }
927 
928 // *************************
929 // Run 2D LLH scan
931 // *************************
932  // Save the settings into the output file
933  SaveSettings();
934 
935  MACH3LOG_INFO("Starting 2D LLH Scan");
936 
937  TDirectory *Sample_2DLLH = outputFile->mkdir("Sample_2DLLH");
938  auto SkipVector = GetFromManager<std::vector<std::string>>(fitMan->raw()["LLHScan"]["LLHScanSkipVector"], {}, __FILE__ , __LINE__);;
939 
940  // Number of points we do for each LLH scan
941  const int n_points = GetFromManager<int>(fitMan->raw()["LLHScan"]["2DLLHScanPoints"], 20, __FILE__ , __LINE__);
942  // We print 5 reweights
943  const int countwidth = int(double(n_points)/double(5));
944 
945  // Loop over the covariance classes
946  for (ParameterHandlerBase *cov : systematics)
947  {
948  // Scan over all the parameters
949  // Get the number of parameters
950  int npars = cov->GetNumParams();
951  bool IsPCA = cov->IsPCA();
952  if (IsPCA) npars = cov->GetNParameters();
953 
954  for (int i = 0; i < npars; ++i)
955  {
956  std::string name_x = cov->GetParFancyName(i);
957  if (IsPCA) name_x += "_PCA";
958  // Get the parameter central and bounds
959  double central_x, lower_x, upper_x;
960  GetParameterScanRange(cov, i, central_x, lower_x, upper_x, n_points, "X");
961 
962  // KS: Check if we want to skip this parameter
963  if(CheckSkipParameter(SkipVector, name_x)) continue;
964 
965  for (int j = 0; j < i; ++j)
966  {
967  std::string name_y = cov->GetParFancyName(j);
968  if (IsPCA) name_y += "_PCA";
969  // KS: Check if we want to skip this parameter
970  if(CheckSkipParameter(SkipVector, name_y)) continue;
971 
972  // Get the parameter central and bounds
973  double central_y, lower_y, upper_y;
974  GetParameterScanRange(cov, j, central_y, lower_y, upper_y, n_points, "Y");
975 
976  auto hScanSam = std::make_unique<TH2D>((name_x + "_" + name_y + "_sam").c_str(), (name_x + "_" + name_y + "_sam").c_str(),
977  n_points, lower_x, upper_x, n_points, lower_y, upper_y);
978  hScanSam->SetDirectory(nullptr);
979  hScanSam->GetXaxis()->SetTitle(name_x.c_str());
980  hScanSam->GetYaxis()->SetTitle(name_y.c_str());
981  hScanSam->GetZaxis()->SetTitle("2LLH_sam");
982 
983  // Scan over the parameter space
984  for (int x = 0; x < n_points; ++x)
985  {
986  if (x % countwidth == 0)
987  M3::Utils::PrintProgressBar(x, n_points);
988 
989  for (int y = 0; y < n_points; ++y)
990  {
991  // For PCA we have to do it differently
992  if (IsPCA) {
993  cov->GetPCAHandler()->SetParPropPCA(i, hScanSam->GetXaxis()->GetBinCenter(x+1));
994  cov->GetPCAHandler()->SetParPropPCA(j, hScanSam->GetYaxis()->GetBinCenter(y+1));
995  } else {
996  // Set the parameter
997  cov->SetParProp(i, hScanSam->GetXaxis()->GetBinCenter(x+1));
998  cov->SetParProp(j, hScanSam->GetYaxis()->GetBinCenter(y+1));
999  }
1000  // Reweight the MC
1001  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs) {
1002  samples[ivs]->Reweight();
1003  }
1004 
1005  // Get the -log L likelihoods
1006  double samplellh = 0;
1007  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs) {
1008  samplellh += samples[ivs]->GetLikelihood();
1009  }
1010  hScanSam->SetBinContent(x+1, y+1, 2*samplellh);
1011  }// end loop over y points
1012  } // end loop over x points
1013 
1014  Sample_2DLLH->cd();
1015  hScanSam->Write();
1016  // Reset the parameters to their central central values
1017  if (IsPCA) {
1018  cov->GetPCAHandler()->SetParPropPCA(i, central_x);
1019  cov->GetPCAHandler()->SetParPropPCA(j, central_y);
1020  } else {
1021  cov->SetParProp(i, central_x);
1022  cov->SetParProp(j, central_y);
1023  }
1024  } //end loop over systematics y
1025  }//end loop over systematics X
1026  }//end loop covariance classes
1027  Sample_2DLLH->Write();
1028  delete Sample_2DLLH;
1029 }
1030 
1031 // *************************
1032 // Run a general multi-dimensional LLH scan
1034 // *************************
1035  // Save the settings into the output file
1036  SaveSettings();
1037 
1038  MACH3LOG_INFO("Starting {}", __func__);
1039 
1040  //KS: Turn it on if you want LLH scan for each ND sample separately, which increase time significantly but can be useful for validating new samples or dials.
1041  bool PlotLLHScanBySample = GetFromManager<bool>(fitMan->raw()["LLHScan"]["LLHScanBySample"], false, __FILE__ , __LINE__);
1042  auto ParamsOfInterest = GetFromManager<std::vector<std::string>>(fitMan->raw()["LLHScan"]["LLHParameters"], {}, __FILE__, __LINE__);
1043 
1044  if(ParamsOfInterest.empty()) {
1045  MACH3LOG_WARN("There were no LLH parameters of interest specified to run the LLHMap! LLHMap will not run at all ...");
1046  return;
1047  }
1048 
1049  // Parameters IDs within the covariance objects
1050  // ParamsCovIDs = {Name, CovObj, IDinCovObj}
1051  std::vector<std::tuple<std::string, ParameterHandlerBase*, int>> ParamsCovIDs;
1052  for(auto& p : ParamsOfInterest) {
1053  bool found = false;
1054  for(auto cov : systematics) {
1055  for(int c = 0; c < cov->GetNumParams(); ++c) {
1056  if(cov->GetParName(c) == p || cov->GetParFancyName(c) == p) {
1057  bool add = true;
1058  for(auto& pc : ParamsCovIDs) {
1059  if(std::get<1>(pc) == cov && std::get<2>(pc) == c)
1060  {
1061  MACH3LOG_WARN("Parameter {} as {}({}) listed multiple times for LLHMap, omitting and using only once!", p, cov->GetName(), c);
1062  add = false;
1063  break;
1064  }
1065  }
1066 
1067  if(add)
1068  ParamsCovIDs.push_back(std::make_tuple(p, cov, c));
1069 
1070  found = true;
1071  break;
1072  }
1073  }
1074  if(found)
1075  break;
1076  }
1077  if(found)
1078  MACH3LOG_INFO("Parameter {} found in {} at an index {}.", p, std::get<1>(ParamsCovIDs.back())->GetName(), std::get<2>(ParamsCovIDs.back()));
1079  else
1080  MACH3LOG_WARN("Parameter {} not found in any of the systematic covariance objects. Will not scan over this one!", p);
1081  }
1082 
1083  // ParamsRanges["parameter"] = {nPoints, {low, high}}
1084  std::map<std::string, std::pair<int, std::pair<double, double>>> ParamsRanges;
1085 
1086  MACH3LOG_INFO("======================================================================================");
1087  MACH3LOG_INFO("Performing a general multi-dimensional LogL map scan over following parameters ranges:");
1088  MACH3LOG_INFO("======================================================================================");
1089  unsigned long TotalPoints = 1;
1090 
1091  double nSigma = GetFromManager<int>(fitMan->raw()["LLHScan"]["LLHScanSigma"], 1., __FILE__, __LINE__);
1092 
1093  // TN: Setting up the scan ranges might look like a re-implementation of the
1094  // FitterBase::GetScanRange, but I guess the use-case here is a bit different.
1095  // Anyway, just in case, we can discuss and rewrite to everyone's liking!
1096  for(auto& p : ParamsCovIDs) {
1097  // Auxiliary vars to help readability
1098  std::string name = std::get<0>(p);
1099  int i = std::get<2>(p);
1100  ParameterHandlerBase* cov = std::get<1>(p);
1101 
1102  ParamsRanges[name].first = GetFromManager<int>(fitMan->raw()["LLHScan"]["LLHScanPoints"], 20, __FILE__, __LINE__);
1103  if(CheckNodeExists(fitMan->raw(),"LLHScan","ScanPoints"))
1104  ParamsRanges[name].first = GetFromManager<int>(fitMan->raw()["LLHScan"]["ScanPoints"][name], ParamsRanges[name].first, __FILE__, __LINE__);
1105 
1106  // Get the parameter priors and bounds
1107  double CentralValue = cov->GetParProp(i);
1108 
1109  bool IsPCA = cov->IsPCA();
1110  if (IsPCA)
1111  CentralValue = cov->GetPCAHandler()->GetParPropPCA(i);
1112 
1113  double prior = cov->GetParPreFit(i);
1114  if (IsPCA)
1115  prior = cov->GetPCAHandler()->GetPreFitValuePCA(i);
1116 
1117  if (std::abs(CentralValue - prior) > 1e-10) {
1118  MACH3LOG_INFO("For {} scanning around value {} rather than prior {}", name, CentralValue, prior);
1119  }
1120  // Get the covariance matrix and do the +/- nSigma
1121  // Set lower and upper bounds relative the CentralValue
1122  // Set the parameter ranges between which LLH points are scanned
1123  double lower = CentralValue - nSigma*cov->GetDiagonalError(i);
1124  double upper = CentralValue + nSigma*cov->GetDiagonalError(i);
1125  // If PCA, transform these parameter values to the PCA basis
1126  if (IsPCA) {
1127  lower = CentralValue - nSigma*std::sqrt((cov->GetPCAHandler()->GetEigenValues())(i));
1128  upper = CentralValue + nSigma*std::sqrt((cov->GetPCAHandler()->GetEigenValues())(i));
1129  MACH3LOG_INFO("eval {} = {:.2f}", i, cov->GetPCAHandler()->GetEigenValues()(i));
1130  MACH3LOG_INFO("CV {} = {:.2f}", i, CentralValue);
1131  MACH3LOG_INFO("lower {} = {:.2f}", i, lower);
1132  MACH3LOG_INFO("upper {} = {:.2f}", i, upper);
1133  MACH3LOG_INFO("nSigma = {:.2f}", nSigma);
1134  }
1135 
1136  ParamsRanges[name].second = {lower,upper};
1137 
1138  if(CheckNodeExists(fitMan->raw(),"LLHScan","ScanRanges"))
1139  ParamsRanges[name].second = GetFromManager<std::pair<double,double>>(fitMan->raw()["LLHScan"]["ScanRanges"][name], ParamsRanges[name].second, __FILE__, __LINE__);
1140 
1141  MACH3LOG_INFO("{} from {:.4f} (lower bin edge) to {:.4f} (upper bin edge) with a {:.5f} step ({} points total)",
1142  name, ParamsRanges[name].second.first, ParamsRanges[name].second.second,
1143  (ParamsRanges[name].second.second - ParamsRanges[name].second.first)/(ParamsRanges[name].first),
1144  ParamsRanges[name].first);
1145 
1146  TotalPoints *= ParamsRanges[name].first;
1147  }
1148 
1149  // TN: Waiting for C++ 20 std::format() function
1150  MACH3LOG_INFO("In total, looping over {} points, from {} parameters. Estimates for run time:", TotalPoints, ParamsCovIDs.size());
1151  MACH3LOG_INFO(" 1 s per point = {} hours", double(TotalPoints)/3600.);
1152  MACH3LOG_INFO(" 0.1 s per point = {} hours", double(TotalPoints)/36000.);
1153  MACH3LOG_INFO("0.01 s per point = {} hours", double(TotalPoints)/360000.);
1154  MACH3LOG_INFO("==================================================================================");
1155 
1156  const int countwidth = int(double(TotalPoints)/double(20));
1157 
1158  // Tree to store LogL values
1159  auto LLHMap = new TTree("llhmap", "LLH Map");
1160 
1161  std::vector<double> CovLogL(systematics.size());
1162  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc )
1163  {
1164  std::string NameTemp = systematics[ivc]->GetName();
1165  NameTemp = NameTemp.substr(0, NameTemp.find("_cov")) + "_LLH";
1166  LLHMap->Branch(NameTemp.c_str(), &CovLogL[ivc]);
1167  }
1168 
1169  std::vector<double> SampleClassLogL(samples.size());
1170  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
1171  {
1172  std::string NameTemp = samples[ivs]->GetName()+"_LLH";
1173  LLHMap->Branch(NameTemp.c_str(), &SampleClassLogL[ivs]);
1174  }
1175 
1176  double SampleLogL, TotalLogL;
1177  LLHMap->Branch("Sample_LLH", &SampleLogL);
1178  LLHMap->Branch("Total_LLH", &TotalLogL);
1179 
1180  std::vector<double>SampleSplitLogL;
1181  if(PlotLLHScanBySample)
1182  {
1183  SampleSplitLogL.resize(TotalNSamples);
1184  int SampleIterator = 0;
1185  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
1186  {
1187  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is )
1188  {
1189  std::string NameTemp =samples[ivs]->GetSampleTitle(is)+"_LLH";
1190  LLHMap->Branch(NameTemp.c_str(), &SampleSplitLogL[SampleIterator]);
1191  SampleIterator++;
1192  }
1193  }
1194  }
1195 
1196  std::vector<double> ParamsValues(ParamsCovIDs.size());
1197  for(unsigned int i=0; i < ParamsCovIDs.size(); ++i)
1198  LLHMap->Branch(std::get<0>(ParamsCovIDs[i]).c_str(), &ParamsValues[i]);
1199 
1200  // Setting up the scan
1201  // Starting at index {0,0,0,...}
1202  std::vector<unsigned long> idx(ParamsCovIDs.size(), 0);
1203 
1204  // loop over scanned points sp
1205  for(unsigned long sp = 0; sp < TotalPoints; ++sp)
1206  {
1207  // At each point need to find the indices and test values to calculate LogL
1208  for(unsigned int n = 0; n < ParamsCovIDs.size(); ++n)
1209  {
1210  // Auxiliaries
1211  std::string name = std::get<0>(ParamsCovIDs[n]);
1212  int points = ParamsRanges[name].first;
1213  double low = ParamsRanges[name].second.first;
1214  double high = ParamsRanges[name].second.second;
1215 
1216  // Find the n-th index of the sp-th scanned point
1217  unsigned long dev = 1;
1218  for(unsigned int m = 0; m <= n; ++m)
1219  dev *= ParamsRanges[std::get<0>(ParamsCovIDs[m])].first;
1220 
1221  idx[n] = sp % dev;
1222  if (n > 0)
1223  idx[n] = idx[n] / ( dev / points );
1224 
1225  // Parameter test value = low + ( high - low ) * idx / #points
1226  ParamsValues[n] = low + (2 * double(idx[n]) + 1) * (high-low) / (2 * double(points));
1227 
1228  // Now set the covariance objects
1229  // Auxiliary
1230  ParameterHandlerBase* cov = std::get<1>(ParamsCovIDs[n]);
1231  int i = std::get<2>(ParamsCovIDs[n]);
1232 
1233  if(cov->IsPCA())
1234  cov->GetPCAHandler()->SetParPropPCA(i, ParamsValues[n]);
1235  else
1236  cov->SetParProp(i, ParamsValues[n]);
1237  }
1238 
1239  // Reweight samples and calculate LogL
1240  TotalLogL = .0;
1241  SampleLogL = .0;
1242 
1243  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs)
1244  samples[ivs]->Reweight();
1245 
1246  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs)
1247  {
1248  SampleClassLogL[ivs] = 2.*samples[ivs]->GetLikelihood();
1249  SampleLogL += SampleClassLogL[ivs];
1250  }
1251  TotalLogL += SampleLogL;
1252 
1253  // CovObjs LogL
1254  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc )
1255  {
1256  CovLogL[ivc] = 2.*systematics[ivc]->GetLikelihood();
1257  TotalLogL += CovLogL[ivc];
1258  }
1259 
1260  if(PlotLLHScanBySample)
1261  {
1262  int SampleIterator = 0;
1263  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
1264  {
1265  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is)
1266  {
1267  SampleSplitLogL[SampleIterator] = 2.*samples[ivs]->GetSampleLikelihood(is);
1268  SampleIterator++;
1269  }
1270  }
1271  }
1272 
1273  LLHMap->Fill();
1274 
1275  if (sp % countwidth == 0)
1276  M3::Utils::PrintProgressBar(sp, TotalPoints);
1277  }
1278 
1279  outputFile->cd();
1280  LLHMap->Write();
1281 }
1282 
1283 // *************************
1284 // For comparison with P-Theta we usually have to apply different parameter values then usual 1, 3 sigma
1285 void FitterBase::CustomRange(const std::string& ParName, const double sigma, double& ParamShiftValue) const {
1286 // *************************
1287  if(!fitMan->raw()["SigmaVar"]["CustomRange"]) return;
1288 
1289  auto Config = fitMan->raw()["SigmaVar"]["CustomRange"];
1290 
1291  const auto sigmaStr = std::to_string(static_cast<int>(std::round(sigma)));
1292 
1293  if (Config[ParName] && Config[ParName][sigmaStr]) {
1294  ParamShiftValue = Config[ParName][sigmaStr].as<double>();
1295  MACH3LOG_INFO(" ::: setting custom range from config ::: {} -> {}", ParName, ParamShiftValue);
1296  }
1297 }
1298 
1299 // *************************
1301 void WriteHistograms(TH1 *hist, const std::string& baseName) {
1302 // *************************
1303  if (!hist) return;
1304  hist->SetTitle(baseName.c_str());
1305  // Get the class name of the histogram
1306  TString className = hist->ClassName();
1307 
1308  // Set the appropriate axis title based on the histogram type
1309  if (className.Contains("TH1")) {
1310  hist->GetYaxis()->SetTitle("Events");
1311  } else if (className.Contains("TH2")) {
1312  hist->GetZaxis()->SetTitle("Events");
1313  }
1314  hist->Write(baseName.c_str());
1315 }
1316 
1317 // *************************
1320  const std::string& suffix,
1321  const bool by_mode,
1322  const bool by_channel,
1323  const std::vector<TDirectory*>& SampleDir) {
1324 // *************************
1325  MaCh3Modes *modes = sample->GetMaCh3Modes();
1326  for (int iSample = 0; iSample < sample->GetNSamples(); ++iSample) {
1327  SampleDir[iSample]->cd();
1328  const std::string sampleName = sample->GetSampleTitle(iSample);
1329  for(int iDim1 = 0; iDim1 < sample->GetNDim(iSample); iDim1++) {
1330  std::string ProjectionName = sample->GetKinVarName(iSample, iDim1);
1331  std::string ProjectionSuffix = "_1DProj" + std::to_string(iDim1);
1332 
1333  // Probably a better way of handling this logic
1334  if (by_mode) {
1335  for (int iMode = 0; iMode < modes->GetNModes(); ++iMode) {
1336  auto modeHist = sample->Get1DVarHistByModeAndChannel(iSample, ProjectionName, iMode);
1337  WriteHistograms(modeHist.get(), sampleName + "_" + modes->GetMaCh3ModeName(iMode) + ProjectionSuffix + suffix);
1338  }
1339  }
1340 
1341  if (by_channel) {
1342  for (int iChan = 0; iChan < sample->GetNOscChannels(iSample); ++iChan) {
1343  auto chanHist = sample->Get1DVarHistByModeAndChannel(iSample, ProjectionName, -1, iChan); // -1 skips over mode plotting
1344  WriteHistograms(chanHist.get(), sampleName + "_" + sample->GetFlavourName(iSample, iChan) + ProjectionSuffix + suffix);
1345  }
1346  }
1347 
1348  if (by_mode && by_channel) {
1349  for (int iMode = 0; iMode < modes->GetNModes(); ++iMode) {
1350  for (int iChan = 0; iChan < sample->GetNOscChannels(iSample); ++iChan) {
1351  auto hist = sample->Get1DVarHistByModeAndChannel(iSample, ProjectionName, iMode, iChan);
1352  WriteHistograms(hist.get(), sampleName + "_" + modes->GetMaCh3ModeName(iMode) + "_" + sample->GetFlavourName(iSample, iChan) + ProjectionSuffix + suffix);
1353  }
1354  }
1355  }
1356 
1357  if (!by_mode && !by_channel) {
1358  auto hist = sample->Get1DVarHist(iSample, ProjectionName);
1359  WriteHistograms(hist.get(), sampleName + ProjectionSuffix + suffix);
1360  // Only for 2D and Beyond
1361  for (int iDim2 = iDim1 + 1; iDim2 < sample->GetNDim(iSample); ++iDim2) {
1362  // Get the names for the two dimensions
1363  std::string XVarName = sample->GetKinVarName(iSample, iDim1);
1364  std::string YVarName = sample->GetKinVarName(iSample, iDim2);
1365 
1366  // Get the 2D histogram for this pair
1367  auto hist2D = sample->Get2DVarHist(iSample, XVarName, YVarName);
1368 
1369  // Write the histogram
1370  std::string suffix2D = "_2DProj_" + std::to_string(iDim1) + "_vs_" + std::to_string(iDim2) + suffix;
1371  WriteHistograms(hist2D.get(), sampleName + suffix2D);
1372  }
1373  }
1374  }
1375  }
1376 }
1377 
1378 // *************************
1380 // *************************
1381  // Save the settings into the output file
1382  SaveSettings();
1383 
1384  bool plot_by_mode = GetFromManager<bool>(fitMan->raw()["SigmaVar"]["PlotByMode"], false, __FILE__ , __LINE__);
1385  bool plot_by_channel = GetFromManager<bool>(fitMan->raw()["SigmaVar"]["PlotByChannel"], false, __FILE__ , __LINE__);
1386  auto SkipVector = GetFromManager<std::vector<std::string>>(fitMan->raw()["SigmaVar"]["SkipVector"], {}, __FILE__ , __LINE__);
1387 
1388  if (plot_by_mode) MACH3LOG_INFO("Plotting by sample and mode");
1389  if (plot_by_channel) MACH3LOG_INFO("Plotting by sample and channel");
1390  if (!plot_by_mode && !plot_by_channel) MACH3LOG_INFO("Plotting by sample only");
1391  if (plot_by_mode && plot_by_channel) MACH3LOG_INFO("Plotting by sample, mode and channel");
1392 
1393  auto SigmaArray = GetFromManager<std::vector<double>>(fitMan->raw()["SigmaVar"]["SigmaArray"], {-3, -1, 0, 1, 3}, __FILE__ , __LINE__);
1394  if (std::find(SigmaArray.begin(), SigmaArray.end(), 0.0) == SigmaArray.end()) {
1395  MACH3LOG_ERROR(":: SigmaArray does not contain 0! Current contents: {} ::", fmt::join(SigmaArray, ", "));
1396  throw MaCh3Exception(__FILE__, __LINE__);
1397  }
1398 
1399  TDirectory* SigmaDir = outputFile->mkdir("SigmaVar");
1400  outputFile->cd();
1401 
1402  for (size_t s = 0; s < systematics.size(); ++s)
1403  {
1404  for(int i = 0; i < systematics[s]->GetNumParams(); i++)
1405  {
1406  std::string ParName = systematics[s]->GetParFancyName(i);
1407  // KS: Check if we want to skip this parameter
1408  if(CheckSkipParameter(SkipVector, ParName)) continue;
1409 
1410  MACH3LOG_INFO(":: Param {} ::", systematics[s]->GetParFancyName(i));
1411 
1412  TDirectory* ParamDir = SigmaDir->mkdir(ParName.c_str());
1413  ParamDir->cd();
1414 
1415  const double ParamCentralValue = systematics[s]->GetParProp(i);
1416  const double Prior = systematics[s]->GetParPreFit(i);
1417  const double ParamLower = systematics[s]->GetLowerBound(i);
1418  const double ParamUpper = systematics[s]->GetUpperBound(i);
1419 
1420  if (std::abs(ParamCentralValue - Prior) > 1e-10) {
1421  MACH3LOG_INFO("For {} scanning around value {} rather than prior {}", ParName, ParamCentralValue, Prior);
1422  }
1423 
1424  for(unsigned int iSample = 0; iSample < samples.size(); ++iSample)
1425  {
1426  auto* MaCh3Sample = samples[iSample];
1427  std::vector<TDirectory*> SampleDir(MaCh3Sample->GetNSamples());
1428  for (int SampleIndex = 0; SampleIndex < MaCh3Sample->GetNSamples(); ++SampleIndex) {
1429  SampleDir[SampleIndex] = ParamDir->mkdir(MaCh3Sample->GetSampleTitle(SampleIndex).c_str());
1430  }
1431 
1432  for (size_t j = 0; j < SigmaArray.size(); ++j) {
1433  double sigma = SigmaArray[j];
1434 
1435  double ParamShiftValue = ParamCentralValue + sigma * std::sqrt((*systematics[s]->GetCovMatrix())(i,i));
1436  ParamShiftValue = std::max(std::min(ParamShiftValue, ParamUpper), ParamLower);
1437 
1439  CustomRange(ParName, sigma, ParamShiftValue);
1440 
1441  MACH3LOG_INFO(" - set to {:<5.2f} ({:<2} sigma shift)", ParamShiftValue, sigma);
1442  systematics[s]->SetParProp(i, ParamShiftValue);
1443 
1444  std::ostringstream valStream;
1445  valStream << std::fixed << std::setprecision(2) << ParamShiftValue;
1446  std::string valueStr = valStream.str();
1447 
1448  std::ostringstream sigmaStream;
1449  sigmaStream << std::fixed << std::setprecision(2) << std::abs(sigma);
1450  std::string sigmaStr = sigmaStream.str();
1451 
1452  std::string suffix;
1453  if (sigma == 0) {
1454  suffix = "_" + ParName + "_nom_val_" + valueStr;
1455  } else {
1456  std::string sign = (sigma > 0) ? "p" : "n";
1457  suffix = "_" + ParName + "_sig_" + sign + sigmaStr + "_val_" + valueStr;
1458  }
1459 
1460  systematics[s]->SetParProp(i, ParamShiftValue);
1461  MaCh3Sample->Reweight();
1462 
1463  WriteHistogramsByMode(MaCh3Sample, suffix, plot_by_mode, plot_by_channel, SampleDir);
1464  }
1465  for (int subSampleIndex = 0; subSampleIndex < MaCh3Sample->GetNSamples(); ++subSampleIndex) {
1466  SampleDir[subSampleIndex]->Close();
1467  delete SampleDir[subSampleIndex];
1468  }
1469  ParamDir->cd();
1470  }
1471 
1472  systematics[s]->SetParProp(i, ParamCentralValue);
1473  MACH3LOG_INFO(" - set back to CV {:<5.2f}", ParamCentralValue);
1474  MACH3LOG_INFO("");
1475  ParamDir->Close();
1476  delete ParamDir;
1477  SigmaDir->cd();
1478  } // end loop over params
1479  } // end loop over systemics
1480  SigmaDir->Close();
1481  delete SigmaDir;
1482 
1483  outputFile->cd();
1484 }
#define _MaCh3_Safe_Include_Start_
KS: Avoiding warning checking for headers.
Definition: Core.h:126
#define _MaCh3_Safe_Include_End_
void WriteHistogramsByMode(SampleHandlerInterface *sample, const std::string &suffix, const bool by_mode, const bool by_channel, const std::vector< TDirectory * > &SampleDir)
Generic histogram writer - should make main code more palatable.
void WriteHistograms(TH1 *hist, const std::string &baseName)
Helper to write histograms.
#define MACH3LOG_CRITICAL
Definition: MaCh3Logger.h:38
#define MACH3LOG_DEBUG
Definition: MaCh3Logger.h:34
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:37
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:35
#define MACH3LOG_WARN
Definition: MaCh3Logger.h:36
std::vector< TString > BranchNames
Definition: RHat.cpp:54
TMacro YAMLtoTMacro(const YAML::Node &yaml_node, const std::string &name)
Convert a YAML node to a ROOT TMacro object.
Definition: YamlHelper.h:167
YAML::Node TMacroToYAML(const TMacro &macro)
KS: Convert a ROOT TMacro object to a YAML node.
Definition: YamlHelper.h:152
bool compareYAMLNodes(const YAML::Node &node1, const YAML::Node &node2, bool Mute=false)
Compare if yaml nodes are identical.
Definition: YamlHelper.h:186
bool CheckNodeExists(const YAML::Node &node, Args... args)
KS: Wrapper function to call the recursive helper.
Definition: YamlHelper.h:60
void RunLLHScan()
Perform a 1D likelihood scan.
Definition: FitterBase.cpp:603
FitterBase(Manager *const fitMan)
Constructor.
Definition: FitterBase.cpp:15
void AddSystObj(ParameterHandlerBase *cov)
This function adds a Covariance object to the analysis framework. The Covariance object will be utili...
Definition: FitterBase.cpp:296
std::string GetName() const
Get name of class.
Definition: FitterBase.h:75
std::unique_ptr< TRandom3 > random
Random number.
Definition: FitterBase.h:149
double logLProp
proposed likelihood
Definition: FitterBase.h:120
bool CheckSkipParameter(const std::vector< std::string > &SkipVector, const std::string &ParamName) const
KS: Check whether we want to skip parameter using skip vector.
Definition: FitterBase.cpp:533
void ProcessMCMC()
Process MCMC output.
Definition: FitterBase.cpp:404
int accCount
counts accepted steps
Definition: FitterBase.h:124
bool OutputPrepared
Checks if output prepared not repeat some operations.
Definition: FitterBase.h:170
void SaveOutput()
Save output and close files.
Definition: FitterBase.cpp:229
TFile * outputFile
Output.
Definition: FitterBase.h:152
void SaveSettings()
Save the settings that the MCMC was run with.
Definition: FitterBase.cpp:77
unsigned int step
current state
Definition: FitterBase.h:116
void PrepareOutput()
Prepare the output file.
Definition: FitterBase.cpp:151
bool SettingsSaved
Checks if setting saved not repeat some operations.
Definition: FitterBase.h:168
double accProb
current acceptance prob
Definition: FitterBase.h:122
virtual void StartFromPreviousFit(const std::string &FitName)
Allow to start from previous fit/chain.
Definition: FitterBase.cpp:346
bool FileSaved
Checks if file saved not repeat some operations.
Definition: FitterBase.h:166
std::string AlgorithmName
Name of fitting algorithm that is being used.
Definition: FitterBase.h:173
std::vector< double > sample_llh
store the llh breakdowns
Definition: FitterBase.h:129
void RunSigmaVar()
Perform a 1D/2D sigma var for all samples.
std::vector< SampleHandlerInterface * > samples
Sample holder.
Definition: FitterBase.h:134
void GetParameterScanRange(const ParameterHandlerBase *cov, const int i, double &CentralValue, double &lower, double &upper, const int n_points, const std::string &suffix="") const
Helper function to get parameter scan range, central value.
Definition: FitterBase.cpp:540
double stepTime
Time of single step.
Definition: FitterBase.h:146
std::unique_ptr< TStopwatch > clock
tells global time how long fit took
Definition: FitterBase.h:142
Manager * fitMan
The manager for configuration handling.
Definition: FitterBase.h:113
unsigned int stepStart
step start, by default 0 if we start from previous chain then it will be different
Definition: FitterBase.h:126
bool GetScanRange(std::map< std::string, std::vector< double >> &scanRanges) const
YSP: Set up a mapping to store parameters with user-specified ranges, suggested by D....
Definition: FitterBase.cpp:513
std::unique_ptr< TStopwatch > stepClock
tells how long single step/fit iteration took
Definition: FitterBase.h:144
TDirectory * CovFolder
Output cov folder.
Definition: FitterBase.h:154
void CustomRange(const std::string &ParName, const double sigma, double &ParamShiftValue) const
For comparison with other fitting frameworks (like P-Theta) we usually have to apply different parame...
TDirectory * SampleFolder
Output sample folder.
Definition: FitterBase.h:156
void DragRace(const int NLaps=100)
Calculates the required time for each sample or covariance object in a drag race simulation....
Definition: FitterBase.cpp:451
void Run2DLLHScan()
Perform a 2D likelihood scan.
Definition: FitterBase.cpp:930
unsigned int TotalNSamples
Total number of samples used, single SampleHandler can store more than one analysis sample!
Definition: FitterBase.h:136
double logLCurr
current likelihood
Definition: FitterBase.h:118
void RunLLHMap()
Perform a general multi-dimensional likelihood scan.
std::vector< double > syst_llh
systematic llh breakdowns
Definition: FitterBase.h:131
int auto_save
auto save every N steps
Definition: FitterBase.h:160
bool fTestLikelihood
Necessary for some fitting algorithms like PSO.
Definition: FitterBase.h:163
void GetStepScaleBasedOnLLHScan(const std::string &filename="")
LLH scan is good first estimate of step scale.
Definition: FitterBase.cpp:868
virtual ~FitterBase()
Destructor for the FitterBase class.
Definition: FitterBase.cpp:67
TTree * outTree
Output tree with posteriors.
Definition: FitterBase.h:158
void SanitiseInputs()
Remove obsolete memory and make other checks before fit starts.
Definition: FitterBase.cpp:221
void AddSampleHandler(SampleHandlerInterface *sample)
This function adds a sample PDF object to the analysis framework. The sample PDF object will be utili...
Definition: FitterBase.cpp:260
std::vector< ParameterHandlerBase * > systematics
Systematic holder.
Definition: FitterBase.h:139
Class responsible for processing MCMC chains, performing diagnostics, generating plots,...
Definition: MCMCProcessor.h:61
const std::vector< TString > & GetBranchNames() const
Get the vector of branch names from root file.
void Initialise()
Scan chain, what parameters we have and load information from covariance matrices.
void GetPostfit(TVectorD *&Central, TVectorD *&Errors, TVectorD *&Central_Gauss, TVectorD *&Errors_Gauss, TVectorD *&Peaks)
Get the post-fit results (arithmetic and Gaussian)
void DrawCovariance()
Draw the post-fit covariances.
void DrawPostfit()
Draw the post-fit comparisons.
void GetCovariance(TMatrixDSym *&Cov, TMatrixDSym *&Corr)
Get the post-fit covariances and correlations.
Custom exception class used throughout MaCh3.
KS: Class describing MaCh3 modes used in the analysis, it is being initialised from config.
Definition: MaCh3Modes.h:142
int GetNModes() const
KS: Get number of modes, keep in mind actual number is +1 greater due to unknown category.
Definition: MaCh3Modes.h:155
std::string GetMaCh3ModeName(const int Index) const
KS: Get normal name of mode, if mode not known you will get UNKNOWN_BAD.
Definition: MaCh3Modes.cpp:156
The manager class is responsible for managing configurations and settings.
Definition: Manager.h:16
YAML::Node const & raw() const
Return config.
Definition: Manager.h:47
void SaveSettings(TFile *const OutputFile) const
Add manager useful information's to TFile, in most cases to Fitter.
Definition: Manager.cpp:40
double GetParPropPCA(const int i) const
Get current parameter value using PCA.
Definition: PCAHandler.h:150
void SetParPropPCA(const int i, const double value)
Set proposed value for parameter in PCA base.
Definition: PCAHandler.h:133
double GetPreFitValuePCA(const int i) const
Get current parameter value using PCA.
Definition: PCAHandler.h:156
const TVectorD GetEigenValues() const
Get eigen values for all parameters, if you want for decomposed only parameters use GetEigenValuesMas...
Definition: PCAHandler.h:172
Base class for handling systematic uncertainty parameters.
int GetNumParams() const
Get total number of parameters.
TH2D * GetCorrelationMatrix() const
KS: Convert covariance matrix to correlation matrix and return TH2D which can be used for fancy plott...
std::string GetParName(const int i) const
Get name of parameter.
void SetParProp(const int i, const double val)
Set proposed parameter value.
double GetUpperBound(const int i) const
Get upper parameter bound in which it is physically valid.
TMatrixDSym * GetCovMatrix() const
Return covariance matrix.
std::string GetParFancyName(const int i) const
Get fancy name of the Parameter.
PCAHandler * GetPCAHandler() const
Get pointer for PCAHandler.
double GetLowerBound(const int i) const
Get lower parameter bound in which it is physically valid.
bool IsPCA() const
is PCA, can use to query e.g. LLH scans
std::string GetName() const
Get name of covariance.
double GetParPreFit(const int i) const
Get prior parameter value.
M3::float_t GetParProp(const int i) const
Get proposed parameter value.
double GetDiagonalError(const int i) const
Get diagonal error for ith parameter.
YAML::Node GetConfig() const
Getter to return a copy of the YAML node.
Class responsible for handling implementation of samples used in analysis, reweighting and returning ...
virtual std::unique_ptr< TH1 > Get1DVarHistByModeAndChannel(const int iSample, const std::string &ProjectionVar_Str, const int kModeToFill=-1, const int kChannelToFill=-1, const int WeightStyle=0)=0
Build a 1D histogram for a given variable, optionally filtered by mode and channel.
virtual std::string GetName() const =0
Get name for Sample Handler.
virtual std::unique_ptr< TH1 > Get1DVarHist(const int iSample, const std::string &ProjectionVar, const std::vector< KinematicCut > &EventSelectionVec={}, int WeightStyle=0, const std::vector< KinematicCut > &SubEventSelectionVec={})=0
Return 1D projection of MC into given 1D variable (doesn't have to be variable used in the fit)
virtual std::string GetFlavourName(const int iSample, const int iChannel) const =0
Get the flavour name for a given sample and oscillation channel.
virtual void SaveAdditionalInfo([[maybe_unused]] TDirectory *Dir)
Store additional info in a chain.
MaCh3Modes * GetMaCh3Modes() const
Return pointer to MaCh3 modes.
virtual int GetNOscChannels(const int iSample) const =0
Get number of oscillation channels for a single sample.
virtual M3::int_t GetNSamples()
returns total number of samples
virtual std::string GetSampleTitle(const int iSample) const =0
Get fancy title for specified samples.
virtual std::string GetKinVarName(const int iSample, const int Dimension) const =0
Return Kinematic Variable name for specified sample and dimension for example "Reconstructed_Neutrino...
virtual std::unique_ptr< TH2 > Get2DVarHist(const int iSample, const std::string &ProjectionVarX, const std::string &ProjectionVarY, const std::vector< KinematicCut > &EventSelectionVec={}, const int WeightStyle=0, const std::vector< KinematicCut > &SubEventSelectionVec={})=0
Build a 2D projection of MC events into specified variables.
virtual int GetNDim(const int Sample) const =0
DB Get what dimensionality binning for given sample has.
int getValue(const std::string &Type)
CW: Get info like RAM.
Definition: Monitor.cpp:252
void PrintProgressBar(const Long64_t Done, const Long64_t All)
KS: Simply print progress bar.
Definition: Monitor.cpp:229
constexpr static const double _LARGE_LOGL_
Large Likelihood is used it parameter go out of physical boundary, this indicates in MCMC that such s...
Definition: Core.h:80
TFile * Open(const std::string &Name, const std::string &Type, const std::string &File, const int Line)
Opens a ROOT file with the given name and mode.
int GetNThreads()
number of threads which we need for example for TRandom3
Definition: Monitor.cpp:372
bool CaseInsensitiveMatchAny(std::string Text, const std::vector< std::string > &Patterns)
Matches a string against a simple wildcard Pattern using regex. Is not case sensitive.