MaCh3  2.8.0
Reference Guide
Public Member Functions | Protected Member Functions | Protected Attributes | List of all members
FitterBase Class Referenceabstract

Base class for implementing fitting algorithms. More...

#include <Fitters/Algorithms/FitterBase.h>

Inheritance diagram for FitterBase:
[legend]
Collaboration diagram for FitterBase:
[legend]

Public Member Functions

 FitterBase (Manager *const fitMan)
 Constructor. More...
 
virtual ~FitterBase ()
 Destructor for the FitterBase class. More...
 
void AddSampleHandler (SampleHandlerInterface *sample)
 This function adds a sample PDF object to the analysis framework. The sample PDF object will be utilized in fitting procedures or likelihood scans. More...
 
void AddSystObj (ParameterHandlerBase *cov)
 This function adds a Covariance object to the analysis framework. The Covariance object will be utilized in fitting procedures or likelihood scans. More...
 
virtual void RunMCMC ()=0
 The specific fitting algorithm implemented in this function depends on the derived class. It could be Markov Chain Monte Carlo (MCMC), MinuitFit, or another algorithm. More...
 
void DragRace (const int NLaps=100)
 Calculates the required time for each sample or covariance object in a drag race simulation. Inspired by Dan's feature. More...
 
void RunLLHScan ()
 Perform a 1D likelihood scan. More...
 
void RunLLHMap ()
 Perform a general multi-dimensional likelihood scan. More...
 
void GetStepScaleBasedOnLLHScan (const std::string &filename="")
 LLH scan is good first estimate of step scale. More...
 
void Run2DLLHScan ()
 Perform a 2D likelihood scan. More...
 
void RunSigmaVar ()
 Perform a 1D/2D sigma var for all samples. More...
 
virtual void StartFromPreviousFit (const std::string &FitName)
 Allow to start from previous fit/chain. More...
 
std::string GetName () const
 Get name of class. More...
 
virtual std::string GetFancyName () const
 This name is to get include some special algorithm extensions. More...
 

Protected Member Functions

void ProcessMCMC ()
 Process MCMC output. More...
 
void PrepareOutput ()
 Prepare the output file. More...
 
void SaveOutput ()
 Save output and close files. More...
 
void SanitiseInputs ()
 Remove obsolete memory and make other checks before fit starts. More...
 
void SaveSettings ()
 Save the settings that the MCMC was run with. More...
 
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. Barrow. More...
 
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. More...
 
bool CheckSkipParameter (const std::vector< std::string > &SkipVector, const std::string &ParamName) const
 KS: Check whether we want to skip parameter using skip vector. More...
 
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 parameter values then usual 1, 3 sigma. More...
 
std::vector< double > CalculateBinEdges (double lowerlimit, double upperlimit, int n_points) const
 

Protected Attributes

Manager * fitMan
 The manager for configuration handling. More...
 
unsigned int step
 current state More...
 
double logLCurr
 current likelihood More...
 
double logLProp
 proposed likelihood More...
 
double accProb
 current acceptance prob More...
 
int accCount
 counts accepted steps More...
 
unsigned int stepStart
 step start, by default 0 if we start from previous chain then it will be different More...
 
std::vector< double > sample_llh
 store the llh breakdowns More...
 
std::vector< double > syst_llh
 systematic llh breakdowns More...
 
std::vector< SampleHandlerInterface * > samples
 Sample holder. More...
 
unsigned int TotalNSamples
 Total number of samples used, single SampleHandler can store more than one analysis sample! More...
 
std::vector< ParameterHandlerBase * > systematics
 Systematic holder. More...
 
std::unique_ptr< TStopwatch > clock
 tells global time how long fit took More...
 
std::unique_ptr< TStopwatch > stepClock
 tells how long single step/fit iteration took More...
 
double stepTime
 Time of single step. More...
 
TFile * outputFile
 Output. More...
 
TDirectory * CovFolder
 Output cov folder. More...
 
TDirectory * SampleFolder
 Output sample folder. More...
 
TTree * outTree
 Output tree with posteriors. More...
 
int auto_save
 auto save every N steps More...
 
bool fTestLikelihood
 Necessary for some fitting algorithms like PSO. More...
 
bool FileSaved
 Checks if file saved not repeat some operations. More...
 
bool SettingsSaved
 Checks if setting saved not repeat some operations. More...
 
bool OutputPrepared
 Checks if output prepared not repeat some operations. More...
 
std::string AlgorithmName
 Name of fitting algorithm that is being used. More...
 

Detailed Description

Base class for implementing fitting algorithms.

This class wraps MaCh3 classes like SampleHandlerInterface and ParameterHandlerBase. It serves as a base for different fitting algorithms and for validation techniques such as LLH scans.

Author
Asher Kaboth
Kamil Skwarczynski

Definition at line 29 of file FitterBase.h.

Constructor & Destructor Documentation

◆ FitterBase()

_MaCh3_Safe_Include_Start_ _MaCh3_Safe_Include_End_ FitterBase::FitterBase ( Manager *const  fitMan)

Constructor.

Parameters
fitManA pointer to a manager object, which will handle all settings.

Definition at line 17 of file FitterBase.cpp.

17  : fitMan(man) {
18 // *************************
19  AlgorithmName = "";
20  //Get mach3 modes from Manager
21  auto Seed = Get<int>(fitMan->raw()["General"]["Seed"], __FILE__, __LINE__);
22  M3::rand::SetSeed(Seed);
23  // Counter of the accepted # of steps
24  accCount = 0;
25  step = 0;
26  stepStart = 0;
27 
28  clock = std::make_unique<TStopwatch>();
29  stepClock = std::make_unique<TStopwatch>();
30  #ifdef MACH3_DEBUG
31  // Fit summary and debug info
32  debug = GetFromManager<bool>(fitMan->raw()["General"]["Debug"], false, __FILE__ , __LINE__);
33  #endif
34 
35  auto outfile = Get<std::string>(fitMan->raw()["General"]["OutputFile"], __FILE__ , __LINE__);
36  // Save output every auto_save steps
37  //you don't want this too often https://root.cern/root/html606/TTree_8cxx_source.html#l01229
38  auto_save = Get<int>(fitMan->raw()["General"]["MCMC"]["AutoSave"], __FILE__ , __LINE__);
39 
40  // Set the output file
41  outputFile = M3::Open(outfile, "RECREATE", __FILE__, __LINE__);
42  outputFile->cd();
43  // Set output tree
44  outTree = new TTree("posteriors", "Posterior_Distributions");
45  // Auto-save every 200MB, the bigger the better https://root.cern/root/html606/TTree_8cxx_source.html#l01229
46  outTree->SetAutoSave(-200E6);
47 
48  FileSaved = false;
49  SettingsSaved = false;
50  OutputPrepared = false;
51 
52  //Create TDirectory
53  CovFolder = outputFile->mkdir("CovarianceFolder");
54  outputFile->cd();
55  SampleFolder = outputFile->mkdir("SampleFolder");
56  outputFile->cd();
57 
58  #ifdef MACH3_DEBUG
59  // Prepare the output log file
60  if (debug) debugFile.open((outfile+".log").c_str());
61  #endif
62 
63  TotalNSamples = 0;
64  fTestLikelihood = GetFromManager<bool>(fitMan->raw()["General"]["Fitter"]["FitTestLikelihood"], false, __FILE__ , __LINE__);
65 }
int accCount
counts accepted steps
Definition: FitterBase.h:131
bool OutputPrepared
Checks if output prepared not repeat some operations.
Definition: FitterBase.h:174
TFile * outputFile
Output.
Definition: FitterBase.h:156
unsigned int step
current state
Definition: FitterBase.h:123
bool SettingsSaved
Checks if setting saved not repeat some operations.
Definition: FitterBase.h:172
bool FileSaved
Checks if file saved not repeat some operations.
Definition: FitterBase.h:170
std::string AlgorithmName
Name of fitting algorithm that is being used.
Definition: FitterBase.h:177
std::unique_ptr< TStopwatch > clock
tells global time how long fit took
Definition: FitterBase.h:149
Manager * fitMan
The manager for configuration handling.
Definition: FitterBase.h:120
unsigned int stepStart
step start, by default 0 if we start from previous chain then it will be different
Definition: FitterBase.h:133
std::unique_ptr< TStopwatch > stepClock
tells how long single step/fit iteration took
Definition: FitterBase.h:151
TDirectory * CovFolder
Output cov folder.
Definition: FitterBase.h:158
TDirectory * SampleFolder
Output sample folder.
Definition: FitterBase.h:160
unsigned int TotalNSamples
Total number of samples used, single SampleHandler can store more than one analysis sample!
Definition: FitterBase.h:143
int auto_save
auto save every N steps
Definition: FitterBase.h:164
bool fTestLikelihood
Necessary for some fitting algorithms like PSO.
Definition: FitterBase.h:167
TTree * outTree
Output tree with posteriors.
Definition: FitterBase.h:162
YAML::Node const & raw() const
Return config.
Definition: Manager.h:48
void SetSeed(const std::uint64_t seed)
Set the global random seed.
Definition: Random.h:111
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.

◆ ~FitterBase()

FitterBase::~FitterBase ( )
virtual

Destructor for the FitterBase class.

Definition at line 69 of file FitterBase.cpp.

69  {
70 // *************************
71  SaveOutput();
72  if(outputFile != nullptr) delete outputFile;
73  outputFile = nullptr;
74  MACH3LOG_DEBUG("Closing MaCh3 Fitter Engine");
75 }
#define MACH3LOG_DEBUG
Definition: MaCh3Logger.h:34
void SaveOutput()
Save output and close files.
Definition: FitterBase.cpp:233

Member Function Documentation

◆ AddSampleHandler()

void FitterBase::AddSampleHandler ( SampleHandlerInterface *  sample)

This function adds a sample PDF object to the analysis framework. The sample PDF object will be utilized in fitting procedures or likelihood scans.

Parameters
sampleA pointer to a sample PDF object derived from ParameterHandlerBase.

Definition at line 264 of file FitterBase.cpp.

264  {
265 // *************************
266  // Check if any subsample name collides with already-registered subsamples
267  for (const auto &s : samples) {
268  for (int iExisting = 0; iExisting < s->GetNSamples(); ++iExisting) {
269  for (int iNew = 0; iNew < sample->GetNSamples(); ++iNew) {
270  if (s->GetSampleTitle(iExisting) == sample->GetSampleTitle(iNew)) {
272  "Duplicate sample title '{}' in handler {} detected: "
273  "same title exist in handler ", sample->GetSampleTitle(iNew),
274  sample->GetName(), s->GetName());
275  throw MaCh3Exception(__FILE__, __LINE__);
276  }
277  }
278  }
279  }
280 
281  for (const auto &s : samples) {
282  if (s->GetName() == sample->GetName()) {
283  MACH3LOG_ERROR("SampleHandler with name '{}' already exists!", sample->GetName());
284  MACH3LOG_ERROR("Is it intended?");
285  throw MaCh3Exception(__FILE__ , __LINE__ );
286  }
287  }
288  // Save additional info from samples
289  SampleFolder->cd();
290 
292  TotalNSamples += sample->GetNSamples();
293  MACH3LOG_INFO("Adding {} object, with {} samples", sample->GetName(), sample->GetNSamples());
294  samples.push_back(sample);
295  outputFile->cd();
296 }
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:37
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:35
std::vector< SampleHandlerInterface * > samples
Sample holder.
Definition: FitterBase.h:141
Custom exception class used throughout MaCh3.
virtual std::string GetName() const =0
Get name for Sample Handler.
virtual void SaveAdditionalInfo([[maybe_unused]] TDirectory *Dir)
Store additional info in a chain.
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.

◆ AddSystObj()

void FitterBase::AddSystObj ( ParameterHandlerBase *  cov)

This function adds a Covariance object to the analysis framework. The Covariance object will be utilized in fitting procedures or likelihood scans.

Parameters
covA pointer to a Covariance object derived from ParameterHandlerBase.

Definition at line 300 of file FitterBase.cpp.

300  {
301 // *************************
302  MACH3LOG_INFO("Adding systematic object {}, with {} params", cov->GetName(), cov->GetNumParams());
303  // 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...
304  for (size_t s = 0; s < systematics.size(); ++s)
305  {
306  for (int iPar = 0; iPar < systematics[s]->GetNumParams(); ++iPar)
307  {
308  for (int i = 0; i < cov->GetNumParams(); ++i)
309  {
310  if(systematics[s]->GetParName(iPar) == cov->GetParName(i)){
311  MACH3LOG_ERROR("ParameterHandler {} has param '{}' which already exists in in {}, with name {}",
312  cov->GetName(), cov->GetParName(i), systematics[s]->GetName(), systematics[s]->GetParName(iPar));
313  throw MaCh3Exception(__FILE__ , __LINE__ );
314  }
315  // Same for fancy name
316  if(systematics[s]->GetParFancyName(iPar) == cov->GetParFancyName(i)){
317  MACH3LOG_ERROR("ParameterHandler {} has param '{}' which already exists in {}, with name {}",
318  cov->GetName(), cov->GetParFancyName(i), systematics[s]->GetName(), systematics[s]->GetParFancyName(iPar));
319  throw MaCh3Exception(__FILE__ , __LINE__ );
320  }
321  }
322  }
323  }
324 
325  systematics.push_back(cov);
326 
327  CovFolder->cd();
328  std::vector<double> n_vec(cov->GetNumParams());
329  for (int i = 0; i < cov->GetNumParams(); ++i) {
330  n_vec[i] = cov->GetParPreFit(i);
331  }
332  cov->GetCovMatrix()->Write(cov->GetName().c_str());
333 
334  TH2D* CorrMatrix = cov->GetCorrelationMatrix();
335  CorrMatrix->Write((cov->GetName() + std::string("_Corr")).c_str());
336  delete CorrMatrix;
337 
338  // If we have yaml config file for covariance let's save it
339  YAML::Node Config = cov->GetConfig();
340  if(!Config.IsNull())
341  {
342  TMacro ConfigSave = YAMLtoTMacro(Config, (std::string("Config_") + cov->GetName()));
343  ConfigSave.Write();
344  }
345 
346  outputFile->cd();
347 }
TMacro YAMLtoTMacro(const YAML::Node &yaml_node, const std::string &name)
Convert a YAML node to a ROOT TMacro object.
Definition: YamlHelper.h:166
std::vector< ParameterHandlerBase * > systematics
Systematic holder.
Definition: FitterBase.h:146
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.
TMatrixDSym * GetCovMatrix() const
Return covariance matrix.
std::string GetParFancyName(const int i) const
Get fancy name of the Parameter.
std::string GetName() const
Get name of covariance.
double GetParPreFit(const int i) const
Get prior parameter value.
YAML::Node GetConfig() const
Getter to return a copy of the YAML node.

◆ CalculateBinEdges()

std::vector< double > FitterBase::CalculateBinEdges ( double  lowerlimit,
double  upperlimit,
int  n_points 
) const
protected

Definition at line 606 of file FitterBase.cpp.

606  {
607 // *************************
608  std::vector<double> binEdges(n_points + 1);
609 
610  double logLower = std::log10(lowerlimit);
611  double logUpper = std::log10(upperlimit);
612 
613  for (int j = 0; j <= n_points; ++j) {
614  binEdges[j] = std::pow(10.0, logLower + (logUpper - logLower) * double(j) / double(n_points));
615  }
616 
617  return binEdges;
618 }

◆ CheckSkipParameter()

bool FitterBase::CheckSkipParameter ( const std::vector< std::string > &  SkipVector,
const std::string &  ParamName 
) const
protected

KS: Check whether we want to skip parameter using skip vector.

Definition at line 537 of file FitterBase.cpp.

537  {
538 // *************************
539  return M3::CaseInsensitiveMatchAny(ParamName, SkipVector);
540 }
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.

◆ CustomRange()

void FitterBase::CustomRange ( const std::string &  ParName,
const double  sigma,
double &  ParamShiftValue 
) const
protected

For comparison with other fitting frameworks (like P-Theta) we usually have to apply different parameter values then usual 1, 3 sigma.

Example YAML format:

SigmaVar:
Q2_norm_7: { "3": 2.0 }
SRC_Norm_O: { "-1": 0.5, "1": 1.5, "3": 2.0 }

Definition at line 1444 of file FitterBase.cpp.

1444  {
1445 // *************************
1446  if(!fitMan->raw()["SigmaVar"]["CustomRange"]) return;
1447 
1448  auto Config = fitMan->raw()["SigmaVar"]["CustomRange"];
1449 
1450  const auto sigmaStr = std::to_string(static_cast<int>(std::round(sigma)));
1451 
1452  if (Config[ParName] && Config[ParName][sigmaStr]) {
1453  ParamShiftValue = Config[ParName][sigmaStr].as<double>();
1454  MACH3LOG_INFO(" ::: setting custom range from config ::: {} -> {}", ParName, ParamShiftValue);
1455  }
1456 }

◆ DragRace()

void FitterBase::DragRace ( const int  NLaps = 100)

Calculates the required time for each sample or covariance object in a drag race simulation. Inspired by Dan's feature.

Parameters
NLapsnumber of laps, every part of Fitter will be tested with given number of laps and you will get total and average time

Definition at line 455 of file FitterBase.cpp.

455  {
456 // *************************
457  MACH3LOG_INFO("Let the Race Begin!");
458  MACH3LOG_INFO("All tests will be performed with {} threads", M3::GetNThreads());
459 
460  // Reweight the MC
461  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs)
462  {
463  TStopwatch clockRace;
464  clockRace.Start();
465  for(int Lap = 0; Lap < NLaps; ++Lap) {
466  samples[ivs]->Reweight();
467  }
468  clockRace.Stop();
469  MACH3LOG_INFO("It took {:.4f} s to reweights {} times sample: {}", clockRace.RealTime(), NLaps, samples[ivs]->GetName());
470  MACH3LOG_INFO("On average {:.6f}", clockRace.RealTime()/NLaps);
471  }
472 
473  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs)
474  {
475  TStopwatch clockRace;
476  clockRace.Start();
477  for(int Lap = 0; Lap < NLaps; ++Lap) {
478  samples[ivs]->GetLikelihood();
479  }
480  clockRace.Stop();
481  MACH3LOG_INFO("It took {:.4f} s to calculate GetLikelihood {} times sample: {}", clockRace.RealTime(), NLaps, samples[ivs]->GetName());
482  MACH3LOG_INFO("On average {:.6f}", clockRace.RealTime()/NLaps);
483  }
484  // 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
485  std::vector<std::vector<double>> StepsValuesBefore(systematics.size());
486  for (size_t s = 0; s < systematics.size(); ++s) {
487  StepsValuesBefore[s] = systematics[s]->GetProposed();
488  }
489  for (size_t s = 0; s < systematics.size(); ++s) {
490  TStopwatch clockRace;
491  clockRace.Start();
492  for(int Lap = 0; Lap < NLaps; ++Lap) {
493  systematics[s]->ProposeStep();
494  }
495  clockRace.Stop();
496  MACH3LOG_INFO("It took {:.4f} s to propose step {} times cov: {}", clockRace.RealTime(), NLaps, systematics[s]->GetName());
497  MACH3LOG_INFO("On average {:.6f}", clockRace.RealTime()/NLaps);
498  }
499  for (size_t s = 0; s < systematics.size(); ++s) {
500  systematics[s]->SetParameters(StepsValuesBefore[s]);
501  }
502 
503  for (size_t s = 0; s < systematics.size(); ++s) {
504  TStopwatch clockRace;
505  clockRace.Start();
506  for(int Lap = 0; Lap < NLaps; ++Lap) {
507  systematics[s]->GetLikelihood();
508  }
509  clockRace.Stop();
510  MACH3LOG_INFO("It took {:.4f} s to calculate get likelihood {} times cov: {}", clockRace.RealTime(), NLaps, systematics[s]->GetName());
511  MACH3LOG_INFO("On average {:.6f}", clockRace.RealTime()/NLaps);
512  }
513  MACH3LOG_INFO("End of race");
514 }
int GetNThreads()
number of threads which we need for example for TRandom3
Definition: Monitor.cpp:372

◆ GetFancyName()

virtual std::string FitterBase::GetFancyName ( ) const
inlinevirtual

This name is to get include some special algorithm extensions.

Reimplemented in MCMCBase.

Definition at line 77 of file FitterBase.h.

77 {return GetName();};
std::string GetName() const
Get name of class.
Definition: FitterBase.h:75

◆ GetName()

std::string FitterBase::GetName ( ) const
inline

Get name of class.

Definition at line 75 of file FitterBase.h.

75 {return AlgorithmName;};

◆ GetParameterScanRange()

void FitterBase::GetParameterScanRange ( const ParameterHandlerBase *  cov,
const int  i,
double &  CentralValue,
double &  lower,
double &  upper,
const int  n_points,
const std::string &  suffix = "" 
) const
protected

Helper function to get parameter scan range, central value.

Definition at line 543 of file FitterBase.cpp.

544  {
545 // *************************
546  // YSP: Set up a mapping to store parameters with user-specified ranges, suggested by D. Barrow
547  std::map<std::string, std::vector<double>> scanRanges;
548  const bool isScanRanges = GetScanRange(scanRanges);
549 
550  double nSigma = GetFromManager<int>(fitMan->raw()["LLHScan"]["LLHScanSigma"], 1., __FILE__, __LINE__);
551  bool IsPCA = cov->IsPCA();
552 
553  // Get the parameter name
554  std::string name = cov->GetParFancyName(i);
555  if (IsPCA) name += "_PCA";
556 
557  // Get the parameter priors and bounds
558  CentralValue = cov->GetParProp(i);
559  if (IsPCA) CentralValue = cov->GetPCAHandler()->GetParPropPCA(i);
560 
561  double prior = cov->GetParPreFit(i);
562  if (IsPCA) prior = cov->GetPCAHandler()->GetPreFitValuePCA(i);
563 
564  if (std::abs(CentralValue - prior) > 1e-10) {
565  MACH3LOG_INFO("For {} scanning around value {:.4f} rather than prior {:.4f}", name, CentralValue, prior);
566  }
567 
568  // Get the covariance matrix and do the +/- nSigma
569  // Set lower and upper bounds relative the CentralValue
570  // Set the parameter ranges between which LLH points are scanned
571  lower = CentralValue - nSigma*cov->GetDiagonalError(i);
572  upper = CentralValue + nSigma*cov->GetDiagonalError(i);
573  // If PCA, transform these parameter values to the PCA basis
574  if (IsPCA) {
575  lower = CentralValue - nSigma*std::sqrt((cov->GetPCAHandler()->GetEigenValues())(i));
576  upper = CentralValue + nSigma*std::sqrt((cov->GetPCAHandler()->GetEigenValues())(i));
577  MACH3LOG_INFO("eval {} = {:.2f}", i, cov->GetPCAHandler()->GetEigenValues()(i));
578  MACH3LOG_INFO("CV {} = {:.2f}", i, CentralValue);
579  MACH3LOG_INFO("lower {} = {:.2f}", i, lower);
580  MACH3LOG_INFO("upper {} = {:.2f}", i, upper);
581  MACH3LOG_INFO("nSigma = {:.2f}", nSigma);
582  }
583 
584  // Implementation suggested by D. Barrow
585  // If param ranges are specified in scanRanges node, extract it from there
586  if(isScanRanges){
587  // Find matching entries through std::maps
588  auto it = scanRanges.find(name);
589  if (it != scanRanges.end() && it->second.size() == 2) { //Making sure the range is has only two entries
590  lower = it->second[0];
591  upper = it->second[1];
592  MACH3LOG_INFO("Found matching param name for setting specified range for {}", name);
593  MACH3LOG_INFO("Range for {} = [{:.2f}, {:.2f}]", name, lower, upper);
594  }
595  }
596 
597  // Cross-section and flux parameters have boundaries that we scan between, check that these are respected in setting lower and upper variables
598  // This also applies for other parameters like osc, etc.
599  lower = std::max(lower, cov->GetLowerBound(i));
600  upper = std::min(upper, cov->GetUpperBound(i));
601  MACH3LOG_INFO("Scanning {} {} with {} steps, from [{:.2f} , {:.2f}], CV = {:.2f}", suffix, name, n_points, lower, upper, CentralValue);
602 }
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:517
double GetParPropPCA(const int i) const
Get current parameter value using PCA.
Definition: PCAHandler.h:149
double GetPreFitValuePCA(const int i) const
Get current parameter value using PCA.
Definition: PCAHandler.h:155
const TVectorD GetEigenValues() const
Get eigen values for all parameters, if you want for decomposed only parameters use GetEigenValuesMas...
Definition: PCAHandler.h:171
double GetUpperBound(const int i) const
Get upper parameter bound in which it is physically valid.
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
M3::float_t GetParProp(const int i) const
Get proposed parameter value.
double GetDiagonalError(const int i) const
Get diagonal error for ith parameter.

◆ GetScanRange()

bool FitterBase::GetScanRange ( std::map< std::string, std::vector< double >> &  scanRanges) const
protected

YSP: Set up a mapping to store parameters with user-specified ranges, suggested by D. Barrow.

Parameters
scanRangesA map with user specified parameter ranges

Definition at line 517 of file FitterBase.cpp.

517  {
518 // *************************
519  bool isScanRanges = false;
520  // YSP: Set up a mapping to store parameters with user-specified ranges, suggested by D. Barrow
521  if(fitMan->raw()["LLHScan"]["ScanRanges"]){
522  YAML::Node scanRangesList = fitMan->raw()["LLHScan"]["ScanRanges"];
523  for (auto it = scanRangesList.begin(); it != scanRangesList.end(); ++it) {
524  std::string itname = it->first.as<std::string>();
525  std::vector<double> itrange = it->second.as<std::vector<double>>();
526  // Set the mapping as param_name:param_range
527  scanRanges[itname] = itrange;
528  }
529  isScanRanges = true;
530  } else {
531  MACH3LOG_INFO("There are no user-defined parameter ranges, so I'll use default param bounds for LLH Scans");
532  }
533  return isScanRanges;
534 }

◆ GetStepScaleBasedOnLLHScan()

void FitterBase::GetStepScaleBasedOnLLHScan ( const std::string &  filename = "")

LLH scan is good first estimate of step scale.

Parameters
filenameby default empty, however if specified it will allow to load LLH scan from external file

Definition at line 906 of file FitterBase.cpp.

906  {
907 // *************************
908 
909  TFile* outputFileLLH = nullptr;
910  bool ownsfile = false;
911 
912  if(outputFileName != ""){
913  //If filename matches that in the config file, get ownership issues. Easier just to run LLH scan again with correct ownership
914  if (outputFile != nullptr && std::string(outputFile->GetName()) == outputFileName) {
915  outputFileLLH = outputFile;
916  }
917  else {
918  outputFileLLH = M3::Open(outputFileName, "READ", __FILE__, __LINE__);
919  ownsfile = true;
920  }
921  }
922  else if (outputFile != nullptr)
923  outputFileLLH = outputFile;
924 
925  MACH3LOG_INFO("Starting Get Step Scale Based On LLHScan");
926 
927  auto ParamVector = GetFromManager<std::vector<std::string>>(fitMan->raw()["LLHScan"]["StepScaleParameters"], {}, __FILE__ , __LINE__);
928 
929  std::string LLH_type = "Sample_LLH";
930  const std::string llhType = GetFromManager<std::string>(fitMan->raw()["LLHScan"]["LLHType"], {}, __FILE__ , __LINE__);
931  if(!llhType.empty()){
932  LLH_type = llhType;
933  }
934 
935  TDirectory *LLHScans = nullptr;
936  if(outputFileLLH != nullptr)
937  LLHScans = outputFileLLH->Get<TDirectory>(LLH_type.c_str());
938 
939  if(!LLHScans || LLHScans->IsZombie() || LLHScans == nullptr)
940  {
941  MACH3LOG_WARN("Couldn't find LLH directory, it looks like LLH scan wasn't run, will do this now");
942  RunLLHScan();
943  outputFileLLH = outputFile;
944  LLHScans = outputFileLLH->Get<TDirectory>(LLH_type.c_str());
945  }
946 
947  for (ParameterHandlerBase *cov : systematics)
948  {
949  MACH3LOG_INFO("Step scale before optimisation");
950  cov->PrintIndivStepScale();
951  const int npars = cov->GetNumParams();
952 
953  // Vector of parameter names correlated to given parameter, from correlation matrix
954  std::vector<std::vector<std::string>> CorrParams(npars);
955  std::vector<double> StepScale(npars);
956  TMatrixDSym *cov_matrix = cov->GetCovMatrix();
957 
958  for (int i = 0; i < npars; ++i)
959  {
960  std::string name = cov->GetParFancyName(i);
961 
962  //Make vector of parameters which are correlated to given parameter
963  std::map<std::string, double> parCorr;
964  for (int j = 0; j < npars; ++j) {
965  double correlation = (*cov_matrix)(i, j) / std::sqrt((*cov_matrix)(i, i) * (*cov_matrix)(j, j));
966  std::string par_corr_name = cov->GetParFancyName(j);
967  parCorr[par_corr_name] = correlation;
968  }
969 
970  for (const auto& corrMap : parCorr){
971  std::string corr_var_name = corrMap.first;
972  if (!ParamVector.empty()){
973  if (std::find(ParamVector.begin(), ParamVector.end(), name) == ParamVector.end()) {
974  // Only create vector if parameter is in chosen list from config file
975  continue;
976  }
977  if (std::find(ParamVector.begin(), ParamVector.end(), corr_var_name) == ParamVector.end()) {
978  // Only consider correlation of parameters in chosen list
979  continue;
980  }
981 
982  }
983  double corr = corrMap.second;
984  int index = cov->GetParIndex(corr_var_name);
985  if(index == i) continue;
986  // Cut on what is consider a correlated parameter
987  // Also only allow same groups correlations
988  std::string parameter_group_i = "";
989  std::string parameter_group_index = "";
990  //If type isnt specified, allow parameters of different groups to be correlated
991  if (auto *param_handler= dynamic_cast<ParameterHandlerGeneric *>(cov)) {
992  parameter_group_i = param_handler->GetParamGroup(i);
993  parameter_group_index = param_handler->GetParamGroup(index);
994  }
995  if(std::abs(corr) > 0.3 && parameter_group_i == parameter_group_index)
996  CorrParams[i].push_back(corr_var_name);
997  }
998  StepScale[i] = cov->GetIndivStepScale(i);
999 
1000  if (!ParamVector.empty()){
1001  if (std::find(ParamVector.begin(), ParamVector.end(), name) == ParamVector.end()) {
1002  // 'name' is not in the vector, skip this iteration
1003  continue;
1004  }
1005  }
1006 
1007  TH1D* LLHScan = nullptr;
1008  if(LLH_type == "Total_LLH")
1009  LLHScan = LLHScans->Get<TH1D>((name+"_full").c_str());
1010  else
1011  LLHScan = LLHScans->Get<TH1D>((name+"_sam").c_str());
1012 
1013  if(LLHScan == nullptr)
1014  {
1015  MACH3LOG_WARN("Couldn't find LLH scan, for {}, skipping", name);
1016  continue;
1017  }
1018  const double LLH_val = std::max(LLHScan->GetBinContent(1), LLHScan->GetBinContent(LLHScan->GetNbinsX()));
1019  //If there is no sensitivity leave it
1020  if(LLH_val < 0.001) continue;
1021 
1022  // EM: assuming that the likelihood is gaussian, approximate sigma value is given by variation/sqrt(-2LLH)
1023  // can evaluate this at any point, simple to evaluate it in the first bin of the LLH scan
1024  // KS: We assume variation is 1 sigma, each dial has different scale so it becomes faff...
1025  const double Var = 1.;
1026  const double approxSigma = std::abs(Var)/std::sqrt(LLH_val);
1027  const double GlobalScale = cov->GetGlobalStepScale();
1028  // 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)
1029  const double TargetStep = approxSigma * 2.38 / std::sqrt(npars);
1030  // KS: Need to divide by currently used gloalStepScale
1031  const double NewStepScale = TargetStep / GlobalScale;
1032 
1033  StepScale[i] = NewStepScale;
1034  MACH3LOG_DEBUG("Sigma: {}", approxSigma);
1035  MACH3LOG_DEBUG("Target Step Size (before accounting for global step size): {}", TargetStep);
1036  MACH3LOG_DEBUG("Optimal Step Size: {}", NewStepScale);
1037  }
1038  std::vector<double> StepScaleCorr = StepScale;
1039  for (int p = 0; p < npars; p++){
1040  //Adjust parameter step scale if correlated parameters exist
1041  if(CorrParams[p].size() != 0){
1042  double avg_step_scale = StepScale[p];
1043  for(const auto& corrName : CorrParams[p]) {
1044  int index = cov->GetParIndex(corrName);
1045  avg_step_scale += StepScale[index];
1046  }
1047  //Determine average step scale for correlated parameters
1048  avg_step_scale /= static_cast<double>(CorrParams[p].size()) + 1.0;
1049  StepScaleCorr[p] = avg_step_scale;
1050  MACH3LOG_INFO("Changed step scale of parameter {} from {} to {}",cov->GetParFancyName(p),StepScale[p],StepScaleCorr[p]);
1051  }
1052  }
1053  MACH3LOG_INFO("Step scale after optimisation");
1054  cov->SetIndivStepScale(StepScaleCorr);
1055  cov->SaveUpdatedMatrixConfig();
1056  }
1057  if(ownsfile && outputFileLLH != nullptr) delete outputFileLLH;
1058 }
#define MACH3LOG_WARN
Definition: MaCh3Logger.h:36
void RunLLHScan()
Perform a 1D likelihood scan.
Definition: FitterBase.cpp:622
Base class for handling systematic uncertainty parameters.
Class responsible for handling of systematic error parameters with different types defined in the con...

◆ PrepareOutput()

void FitterBase::PrepareOutput ( )
protected

Prepare the output file.

Definition at line 155 of file FitterBase.cpp.

155  {
156 // *******************
157  if(OutputPrepared) return;
158  //MS: Check if we are fitting the test likelihood, rather than T2K likelihood, and only setup T2K output if not
159  if(!fTestLikelihood)
160  {
161  // Check that we have added samples
162  if (!samples.size()) {
163  MACH3LOG_CRITICAL("No samples Found! Is this really what you wanted?");
164  //throw MaCh3Exception(__FILE__ , __LINE__ );
165  }
166 
167  // Do we want to save proposal? This will break plotting scripts and is heave for disk space and step time. Only use when debugging
168  bool SaveProposal = GetFromManager<bool>(fitMan->raw()["General"]["SaveProposal"], false, __FILE__ , __LINE__);
169 
170  if(SaveProposal) MACH3LOG_INFO("Will save in the chain proposal parameters and LogL");
171  // Prepare the output trees
172  for (ParameterHandlerBase *cov : systematics) {
173  cov->SetBranches(*outTree, SaveProposal);
174  }
175 
176  outTree->Branch("LogL", &logLCurr, "LogL/D");
177  if(SaveProposal) outTree->Branch("LogLProp", &logLProp, "LogLProp/D");
178  outTree->Branch("accProb", &accProb, "accProb/D");
179  outTree->Branch("step", &step, "step/i");
180  outTree->Branch("stepTime", &stepTime, "stepTime/D");
181 
182  // Store individual likelihood components
183  // Using double means double as large output file!
184  sample_llh.resize(samples.size());
185  syst_llh.resize(systematics.size());
186 
187  for (size_t i = 0; i < samples.size(); ++i) {
188  std::stringstream oss, oss2;
189  oss << "LogL_sample_" << i;
190  oss2 << oss.str() << "/D";
191  outTree->Branch(oss.str().c_str(), &sample_llh[i], oss2.str().c_str());
192  }
193 
194  for (size_t i = 0; i < systematics.size(); ++i) {
195  std::stringstream oss, oss2;
196  oss << "LogL_systematic_" << systematics[i]->GetName();
197  oss2 << oss.str() << "/D";
198  outTree->Branch(oss.str().c_str(), &syst_llh[i], oss2.str().c_str());
199  }
200  }
201  else
202  {
203  outTree->Branch("LogL", &logLCurr, "LogL/D");
204  outTree->Branch("accProb", &accProb, "accProb/D");
205  outTree->Branch("step", &step, "step/i");
206  outTree->Branch("stepTime", &stepTime, "stepTime/D");
207  }
208 
209  MACH3LOG_INFO("-------------------- Starting MCMC --------------------");
210  #ifdef MACH3_DEBUG
211  if (debug) {
212  debugFile << "----- Starting MCMC -----" << std::endl;
213  }
214  #endif
215  // Time the progress
216 
217 
218  clock->Start();
219 
220 
221  OutputPrepared = true;
222 }
#define MACH3LOG_CRITICAL
Definition: MaCh3Logger.h:38
double logLProp
proposed likelihood
Definition: FitterBase.h:127
double accProb
current acceptance prob
Definition: FitterBase.h:129
std::vector< double > sample_llh
store the llh breakdowns
Definition: FitterBase.h:136
double stepTime
Time of single step.
Definition: FitterBase.h:153
double logLCurr
current likelihood
Definition: FitterBase.h:125
std::vector< double > syst_llh
systematic llh breakdowns
Definition: FitterBase.h:138

◆ ProcessMCMC()

void FitterBase::ProcessMCMC ( )
protected

Process MCMC output.

Definition at line 408 of file FitterBase.cpp.

408  {
409 // *******************
410  if (fitMan == nullptr) return;
411 
412  // Process the MCMC
413  if (GetFromManager<bool>(fitMan->raw()["General"]["ProcessMCMC"], false, __FILE__ , __LINE__)){
414  // Make the processor
415  MCMCProcessor Processor(std::string(outputFile->GetName()));
416 
417  Processor.Initialise();
418  // Make the TVectorD pointers which hold the processed output
419  TVectorD *Central = nullptr;
420  TVectorD *Errors = nullptr;
421  TVectorD *Central_Gauss = nullptr;
422  TVectorD *Errors_Gauss = nullptr;
423  TVectorD *Peaks = nullptr;
424 
425  // Make the postfit
426  Processor.GetPostfit(Central, Errors, Central_Gauss, Errors_Gauss, Peaks);
427  Processor.DrawPostfit();
428 
429  // Make the TMatrix pointers which hold the processed output
430  TMatrixDSym *Covariance = nullptr;
431  TMatrixDSym *Correlation = nullptr;
432 
433  // Make the covariance matrix
434  Processor.GetCovariance(Covariance, Correlation);
435  Processor.DrawCovariance();
436 
437  std::vector<TString> BranchNames = Processor.GetBranchNames();
438 
439  // Re-open the TFile
440  if (!outputFile->IsOpen()) {
441  MACH3LOG_INFO("Opening output again to update with means..");
442  outputFile = new TFile(Get<std::string>(fitMan->raw()["General"]["OutputFile"], __FILE__, __LINE__).c_str(), "UPDATE");
443  }
444  Central->Write("PDF_Means");
445  Errors->Write("PDF_Errors");
446  Central_Gauss->Write("Gauss_Means");
447  Errors_Gauss->Write("Errors_Gauss");
448  Covariance->Write("Covariance");
449  Correlation->Write("Correlation");
450  }
451 }
Class responsible for processing MCMC chains, performing diagnostics, generating plots,...
Definition: MCMCProcessor.h:60

◆ Run2DLLHScan()

void FitterBase::Run2DLLHScan ( )

Perform a 2D likelihood scan.

Warning
This operation may take a significant amount of time, especially for complex models.

Definition at line 1061 of file FitterBase.cpp.

1061  {
1062 // *************************
1063  // Save the settings into the output file
1064  SaveSettings();
1065 
1066  MACH3LOG_INFO("Starting 2D LLH Scan");
1067 
1068  TDirectory *Sample_2DLLH = outputFile->mkdir("Sample_2DLLH");
1069  auto SkipVector = GetFromManager<std::vector<std::string>>(fitMan->raw()["LLHScan"]["LLHScanSkipVector"], {}, __FILE__ , __LINE__);;
1070 
1071  //Do we want a logarithmic LLH scan
1072  bool LLHLogarithmic = GetFromManager<bool>(fitMan->raw()["LLHScan"]["LLHLogarithmic"], false, __FILE__ , __LINE__);
1073 
1074  // Number of points we do for each LLH scan
1075  const int n_points = GetFromManager<int>(fitMan->raw()["LLHScan"]["2DLLHScanPoints"], 20, __FILE__ , __LINE__);
1076  // We print 5 reweights
1077  const int countwidth = int(double(n_points)/double(5));
1078 
1079  // Loop over the covariance classes
1080  for (ParameterHandlerBase *cov : systematics)
1081  {
1082  // Scan over all the parameters
1083  // Get the number of parameters
1084  int npars = cov->GetNumParams();
1085  bool IsPCA = cov->IsPCA();
1086  if (IsPCA) npars = cov->GetNParameters();
1087 
1088  for (int i = 0; i < npars; ++i)
1089  {
1090  std::string name_x = cov->GetParFancyName(i);
1091  if (IsPCA) name_x += "_PCA";
1092  // Get the parameter central and bounds
1093  double central_x, lower_x, upper_x;
1094  GetParameterScanRange(cov, i, central_x, lower_x, upper_x, n_points, "X");
1095  std::vector<double> binEdges_x;
1096 
1097  //Logarithmic scan
1098  if(LLHLogarithmic){
1099  if (lower_x < 0.0 || upper_x < 0.0){
1100  MACH3LOG_WARN("Cannot perform logarithmic scan for {} "" with range [{}, {}], falling back to linear scan", name_x, lower_x, upper_x);
1101  } else {
1102  binEdges_x = CalculateBinEdges(lower_x, upper_x, n_points);
1103  }
1104  }
1105  // KS: Check if we want to skip this parameter
1106  if(CheckSkipParameter(SkipVector, name_x)) continue;
1107 
1108  for (int j = 0; j < i; ++j)
1109  {
1110  std::string name_y = cov->GetParFancyName(j);
1111  if (IsPCA) name_y += "_PCA";
1112  // KS: Check if we want to skip this parameter
1113  if(CheckSkipParameter(SkipVector, name_y)) continue;
1114 
1115  std::unique_ptr<TH2D> hScanSam;
1116  // Get the parameter central and bounds
1117  double central_y, lower_y, upper_y;
1118  GetParameterScanRange(cov, j, central_y, lower_y, upper_y, n_points, "Y");
1119  if(LLHLogarithmic){
1120  //negative values break it
1121  if (lower_x < 0.0 || upper_x < 0.0 || lower_y < 0.0 || upper_y < 0.0 ) {
1122  MACH3LOG_WARN("Cannot perform logarithmic scan for {} and {} "" with range [{}, {}], [{}, {}], falling back to linear scan", name_x, lower_x, upper_x, name_y, lower_y, upper_y);
1123  hScanSam = std::make_unique<TH2D>((name_x + "_" + name_y + "_sam").c_str(), (name_x + "_" + name_y + "_sam").c_str(), n_points, lower_x, upper_x, n_points, lower_y, upper_y);
1124  hScanSam->SetDirectory(nullptr);
1125  hScanSam->GetXaxis()->SetTitle(name_x.c_str());
1126  hScanSam->GetYaxis()->SetTitle(name_y.c_str());
1127  hScanSam->GetZaxis()->SetTitle("2LLH_sam");
1128  } else {
1129  auto binEdges_y = CalculateBinEdges(lower_y, upper_y, n_points);
1130  hScanSam = std::make_unique<TH2D>((name_x + "_" + name_y + "_sam").c_str(), (name_x + "_" + name_y + "_sam").c_str(), n_points, binEdges_x.data(), n_points, binEdges_y.data());
1131  }
1132  }
1133  //If not then just do the normal thing
1134  else {
1135  hScanSam = std::make_unique<TH2D>((name_x + "_" + name_y + "_sam").c_str(), (name_x + "_" + name_y + "_sam").c_str(), n_points, lower_x, upper_x, n_points, lower_y, upper_y);
1136  hScanSam->SetDirectory(nullptr);
1137  hScanSam->GetXaxis()->SetTitle(name_x.c_str());
1138  hScanSam->GetYaxis()->SetTitle(name_y.c_str());
1139  hScanSam->GetZaxis()->SetTitle("2LLH_sam");
1140  }
1141 
1142  // Scan over the parameter space
1143  for (int x = 0; x < n_points; ++x)
1144  {
1145  if (x % countwidth == 0)
1146  M3::Utils::PrintProgressBar(x, n_points);
1147 
1148  for (int y = 0; y < n_points; ++y)
1149  {
1150  // For PCA we have to do it differently
1151  if (IsPCA) {
1152  cov->GetPCAHandler()->SetParPropPCA(i, hScanSam->GetXaxis()->GetBinCenter(x+1));
1153  cov->GetPCAHandler()->SetParPropPCA(j, hScanSam->GetYaxis()->GetBinCenter(y+1));
1154  } else {
1155  // Set the parameter
1156  cov->SetParProp(i, hScanSam->GetXaxis()->GetBinCenter(x+1));
1157  cov->SetParProp(j, hScanSam->GetYaxis()->GetBinCenter(y+1));
1158  }
1159  // Reweight the MC
1160  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs) {
1161  samples[ivs]->Reweight();
1162  }
1163 
1164  // Get the -log L likelihoods
1165  double samplellh = 0;
1166  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs) {
1167  samplellh += samples[ivs]->GetLikelihood();
1168  }
1169  hScanSam->SetBinContent(x+1, y+1, 2*samplellh);
1170  }// end loop over y points
1171  } // end loop over x points
1172 
1173  Sample_2DLLH->cd();
1174  hScanSam->Write();
1175  // Reset the parameters to their central central values
1176  if (IsPCA) {
1177  cov->GetPCAHandler()->SetParPropPCA(i, central_x);
1178  cov->GetPCAHandler()->SetParPropPCA(j, central_y);
1179  } else {
1180  cov->SetParProp(i, central_x);
1181  cov->SetParProp(j, central_y);
1182  }
1183  } //end loop over systematics y
1184  }//end loop over systematics X
1185  }//end loop covariance classes
1186  Sample_2DLLH->Write();
1187  delete Sample_2DLLH;
1188 }
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:537
void SaveSettings()
Save the settings that the MCMC was run with.
Definition: FitterBase.cpp:79
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:543
std::vector< double > CalculateBinEdges(double lowerlimit, double upperlimit, int n_points) const
Definition: FitterBase.cpp:606
void PrintProgressBar(const Long64_t Done, const Long64_t All)
KS: Simply print progress bar.
Definition: Monitor.cpp:229

◆ RunLLHMap()

void FitterBase::RunLLHMap ( )

Perform a general multi-dimensional likelihood scan.

Author
Tomas Nosek

Definition at line 1192 of file FitterBase.cpp.

1192  {
1193 // *************************
1194  // Save the settings into the output file
1195  SaveSettings();
1196 
1197  MACH3LOG_INFO("Starting {}", __func__);
1198 
1199  //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.
1200  bool PlotLLHScanBySample = GetFromManager<bool>(fitMan->raw()["LLHScan"]["LLHScanBySample"], false, __FILE__ , __LINE__);
1201  auto ParamsOfInterest = GetFromManager<std::vector<std::string>>(fitMan->raw()["LLHScan"]["LLHParameters"], {}, __FILE__, __LINE__);
1202 
1203  if(ParamsOfInterest.empty()) {
1204  MACH3LOG_WARN("There were no LLH parameters of interest specified to run the LLHMap! LLHMap will not run at all ...");
1205  return;
1206  }
1207 
1208  // Parameters IDs within the covariance objects
1209  // ParamsCovIDs = {Name, CovObj, IDinCovObj}
1210  std::vector<std::tuple<std::string, ParameterHandlerBase*, int>> ParamsCovIDs;
1211  for(auto& p : ParamsOfInterest) {
1212  bool found = false;
1213  for(auto cov : systematics) {
1214  for(int c = 0; c < cov->GetNumParams(); ++c) {
1215  if(cov->GetParName(c) == p || cov->GetParFancyName(c) == p) {
1216  bool add = true;
1217  for(auto& pc : ParamsCovIDs) {
1218  if(std::get<1>(pc) == cov && std::get<2>(pc) == c)
1219  {
1220  MACH3LOG_WARN("Parameter {} as {}({}) listed multiple times for LLHMap, omitting and using only once!", p, cov->GetName(), c);
1221  add = false;
1222  break;
1223  }
1224  }
1225 
1226  if(add)
1227  ParamsCovIDs.push_back(std::make_tuple(p, cov, c));
1228 
1229  found = true;
1230  break;
1231  }
1232  }
1233  if(found)
1234  break;
1235  }
1236  if(found)
1237  MACH3LOG_INFO("Parameter {} found in {} at an index {}.", p, std::get<1>(ParamsCovIDs.back())->GetName(), std::get<2>(ParamsCovIDs.back()));
1238  else
1239  MACH3LOG_WARN("Parameter {} not found in any of the systematic covariance objects. Will not scan over this one!", p);
1240  }
1241 
1242  // ParamsRanges["parameter"] = {nPoints, {low, high}}
1243  std::map<std::string, std::pair<int, std::pair<double, double>>> ParamsRanges;
1244 
1245  MACH3LOG_INFO("======================================================================================");
1246  MACH3LOG_INFO("Performing a general multi-dimensional LogL map scan over following parameters ranges:");
1247  MACH3LOG_INFO("======================================================================================");
1248  unsigned long TotalPoints = 1;
1249 
1250  double nSigma = GetFromManager<int>(fitMan->raw()["LLHScan"]["LLHScanSigma"], 1., __FILE__, __LINE__);
1251 
1252  // TN: Setting up the scan ranges might look like a re-implementation of the
1253  // FitterBase::GetScanRange, but I guess the use-case here is a bit different.
1254  // Anyway, just in case, we can discuss and rewrite to everyone's liking!
1255  for(auto& p : ParamsCovIDs) {
1256  // Auxiliary vars to help readability
1257  std::string name = std::get<0>(p);
1258  int i = std::get<2>(p);
1259  ParameterHandlerBase* cov = std::get<1>(p);
1260 
1261  ParamsRanges[name].first = GetFromManager<int>(fitMan->raw()["LLHScan"]["LLHScanPoints"], 20, __FILE__, __LINE__);
1262  if(CheckNodeExists(fitMan->raw(),"LLHScan","ScanPoints"))
1263  ParamsRanges[name].first = GetFromManager<int>(fitMan->raw()["LLHScan"]["ScanPoints"][name], ParamsRanges[name].first, __FILE__, __LINE__);
1264 
1265  // Get the parameter priors and bounds
1266  double CentralValue = cov->GetParProp(i);
1267 
1268  bool IsPCA = cov->IsPCA();
1269  if (IsPCA)
1270  CentralValue = cov->GetPCAHandler()->GetParPropPCA(i);
1271 
1272  double prior = cov->GetParPreFit(i);
1273  if (IsPCA)
1274  prior = cov->GetPCAHandler()->GetPreFitValuePCA(i);
1275 
1276  if (std::abs(CentralValue - prior) > 1e-10) {
1277  MACH3LOG_INFO("For {} scanning around value {} rather than prior {}", name, CentralValue, prior);
1278  }
1279  // Get the covariance matrix and do the +/- nSigma
1280  // Set lower and upper bounds relative the CentralValue
1281  // Set the parameter ranges between which LLH points are scanned
1282  double lower = CentralValue - nSigma*cov->GetDiagonalError(i);
1283  double upper = CentralValue + nSigma*cov->GetDiagonalError(i);
1284  // If PCA, transform these parameter values to the PCA basis
1285  if (IsPCA) {
1286  lower = CentralValue - nSigma*std::sqrt((cov->GetPCAHandler()->GetEigenValues())(i));
1287  upper = CentralValue + nSigma*std::sqrt((cov->GetPCAHandler()->GetEigenValues())(i));
1288  MACH3LOG_INFO("eval {} = {:.2f}", i, cov->GetPCAHandler()->GetEigenValues()(i));
1289  MACH3LOG_INFO("CV {} = {:.2f}", i, CentralValue);
1290  MACH3LOG_INFO("lower {} = {:.2f}", i, lower);
1291  MACH3LOG_INFO("upper {} = {:.2f}", i, upper);
1292  MACH3LOG_INFO("nSigma = {:.2f}", nSigma);
1293  }
1294 
1295  ParamsRanges[name].second = {lower,upper};
1296 
1297  if(CheckNodeExists(fitMan->raw(),"LLHScan","ScanRanges"))
1298  ParamsRanges[name].second = GetFromManager<std::pair<double,double>>(fitMan->raw()["LLHScan"]["ScanRanges"][name], ParamsRanges[name].second, __FILE__, __LINE__);
1299 
1300  MACH3LOG_INFO("{} from {:.4f} (lower bin edge) to {:.4f} (upper bin edge) with a {:.5f} step ({} points total)",
1301  name, ParamsRanges[name].second.first, ParamsRanges[name].second.second,
1302  (ParamsRanges[name].second.second - ParamsRanges[name].second.first)/(ParamsRanges[name].first),
1303  ParamsRanges[name].first);
1304 
1305  TotalPoints *= ParamsRanges[name].first;
1306  }
1307 
1308  // TN: Waiting for C++ 20 std::format() function
1309  MACH3LOG_INFO("In total, looping over {} points, from {} parameters. Estimates for run time:", TotalPoints, ParamsCovIDs.size());
1310  MACH3LOG_INFO(" 1 s per point = {:.4f} hours", double(TotalPoints)/3600.);
1311  MACH3LOG_INFO(" 0.1 s per point = {:.4f} hours", double(TotalPoints)/36000.);
1312  MACH3LOG_INFO("0.01 s per point = {:.4f} hours", double(TotalPoints)/360000.);
1313  MACH3LOG_INFO("==================================================================================");
1314 
1315  const int countwidth = int(double(TotalPoints)/double(20));
1316 
1317  // Tree to store LogL values
1318  auto LLHMap = new TTree("llhmap", "LLH Map");
1319 
1320  std::vector<double> CovLogL(systematics.size());
1321  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc )
1322  {
1323  std::string NameTemp = systematics[ivc]->GetName();
1324  NameTemp = NameTemp.substr(0, NameTemp.find("_cov")) + "_LLH";
1325  LLHMap->Branch(NameTemp.c_str(), &CovLogL[ivc]);
1326  }
1327 
1328  std::vector<double> SampleClassLogL(samples.size());
1329  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
1330  {
1331  std::string NameTemp = samples[ivs]->GetName()+"_LLH";
1332  LLHMap->Branch(NameTemp.c_str(), &SampleClassLogL[ivs]);
1333  }
1334 
1335  double SampleLogL, TotalLogL;
1336  LLHMap->Branch("Sample_LLH", &SampleLogL);
1337  LLHMap->Branch("Total_LLH", &TotalLogL);
1338 
1339  std::vector<double>SampleSplitLogL;
1340  if(PlotLLHScanBySample)
1341  {
1342  SampleSplitLogL.resize(TotalNSamples);
1343  int SampleIterator = 0;
1344  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
1345  {
1346  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is )
1347  {
1348  std::string NameTemp =samples[ivs]->GetSampleTitle(is)+"_LLH";
1349  LLHMap->Branch(NameTemp.c_str(), &SampleSplitLogL[SampleIterator]);
1350  SampleIterator++;
1351  }
1352  }
1353  }
1354 
1355  std::vector<double> ParamsValues(ParamsCovIDs.size());
1356  for(unsigned int i=0; i < ParamsCovIDs.size(); ++i)
1357  LLHMap->Branch(std::get<0>(ParamsCovIDs[i]).c_str(), &ParamsValues[i]);
1358 
1359  // Setting up the scan
1360  // Starting at index {0,0,0,...}
1361  std::vector<unsigned long> idx(ParamsCovIDs.size(), 0);
1362 
1363  // loop over scanned points sp
1364  for(unsigned long sp = 0; sp < TotalPoints; ++sp)
1365  {
1366  // At each point need to find the indices and test values to calculate LogL
1367  for(unsigned int n = 0; n < ParamsCovIDs.size(); ++n)
1368  {
1369  // Auxiliaries
1370  std::string name = std::get<0>(ParamsCovIDs[n]);
1371  int points = ParamsRanges[name].first;
1372  double low = ParamsRanges[name].second.first;
1373  double high = ParamsRanges[name].second.second;
1374 
1375  // Find the n-th index of the sp-th scanned point
1376  unsigned long dev = 1;
1377  for(unsigned int m = 0; m <= n; ++m)
1378  dev *= ParamsRanges[std::get<0>(ParamsCovIDs[m])].first;
1379 
1380  idx[n] = sp % dev;
1381  if (n > 0)
1382  idx[n] = idx[n] / ( dev / points );
1383 
1384  // Parameter test value = low + ( high - low ) * idx / #points
1385  ParamsValues[n] = low + (2 * double(idx[n]) + 1) * (high-low) / (2 * double(points));
1386 
1387  // Now set the covariance objects
1388  // Auxiliary
1389  ParameterHandlerBase* cov = std::get<1>(ParamsCovIDs[n]);
1390  int i = std::get<2>(ParamsCovIDs[n]);
1391 
1392  if(cov->IsPCA())
1393  cov->GetPCAHandler()->SetParPropPCA(i, ParamsValues[n]);
1394  else
1395  cov->SetParProp(i, ParamsValues[n]);
1396  }
1397 
1398  // Reweight samples and calculate LogL
1399  TotalLogL = .0;
1400  SampleLogL = .0;
1401 
1402  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs)
1403  samples[ivs]->Reweight();
1404 
1405  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs)
1406  {
1407  SampleClassLogL[ivs] = 2.*samples[ivs]->GetLikelihood();
1408  SampleLogL += SampleClassLogL[ivs];
1409  }
1410  TotalLogL += SampleLogL;
1411 
1412  // CovObjs LogL
1413  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc )
1414  {
1415  CovLogL[ivc] = 2.*systematics[ivc]->GetLikelihood();
1416  TotalLogL += CovLogL[ivc];
1417  }
1418 
1419  if(PlotLLHScanBySample)
1420  {
1421  int SampleIterator = 0;
1422  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
1423  {
1424  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is)
1425  {
1426  SampleSplitLogL[SampleIterator] = 2.*samples[ivs]->GetSampleLikelihood(is);
1427  SampleIterator++;
1428  }
1429  }
1430  }
1431 
1432  LLHMap->Fill();
1433 
1434  if (sp % countwidth == 0)
1435  M3::Utils::PrintProgressBar(sp, TotalPoints);
1436  }
1437 
1438  outputFile->cd();
1439  LLHMap->Write();
1440 }
bool CheckNodeExists(const YAML::Node &node, Args... args)
KS: Wrapper function to call the recursive helper.
Definition: YamlHelper.h:59
void SetParPropPCA(const int i, const double value)
Set proposed value for parameter in PCA base.
Definition: PCAHandler.h:132
void SetParProp(const int i, const double val)
Set proposed parameter value.

◆ RunLLHScan()

void FitterBase::RunLLHScan ( )

Perform a 1D likelihood scan.

Definition at line 622 of file FitterBase.cpp.

622  {
623 // *************************
624  // Save the settings into the output file
625  SaveSettings();
626 
627  MACH3LOG_INFO("Starting {}", __func__);
628 
629  //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.
630  bool PlotLLHScanBySample = GetFromManager<bool>(fitMan->raw()["LLHScan"]["LLHScanBySample"], false, __FILE__ , __LINE__);
631  auto SkipVector = GetFromManager<std::vector<std::string>>(fitMan->raw()["LLHScan"]["LLHScanSkipVector"], {}, __FILE__ , __LINE__);
632  //Do we want a logarithmic LLH scan
633  bool LLHLogarithmic = GetFromManager<bool>(fitMan->raw()["LLHScan"]["LLHLogarithmic"], false, __FILE__ , __LINE__);
634 
635  // Now finally get onto the LLH scan stuff
636  // Very similar code to MCMC but never start MCMC; just scan over the parameter space
637  std::vector<TDirectory *> Cov_LLH(systematics.size());
638  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc )
639  {
640  std::string NameTemp = systematics[ivc]->GetName();
641  NameTemp = NameTemp.substr(0, NameTemp.find("_cov")) + "_LLH";
642  Cov_LLH[ivc] = outputFile->mkdir(NameTemp.c_str());
643  }
644 
645  std::vector<TDirectory *> SampleClass_LLH(samples.size());
646  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
647  {
648  std::string NameTemp = samples[ivs]->GetName();
649  SampleClass_LLH[ivs] = outputFile->mkdir(NameTemp.c_str());
650  }
651 
652  TDirectory *Sample_LLH = outputFile->mkdir("Sample_LLH");
653  TDirectory *Total_LLH = outputFile->mkdir("Total_LLH");
654 
655  std::vector<TDirectory *>SampleSplit_LLH;
656  if(PlotLLHScanBySample)
657  {
658  SampleSplit_LLH.resize(TotalNSamples);
659  int SampleIterator = 0;
660  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
661  {
662  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is )
663  {
664  SampleSplit_LLH[SampleIterator] = outputFile->mkdir((samples[ivs]->GetSampleTitle(is)+ "_LLH").c_str());
665  SampleIterator++;
666  }
667  }
668  }
669  // Number of points we do for each LLH scan
670  const int n_points = GetFromManager<int>(fitMan->raw()["LLHScan"]["LLHScanPoints"], 100, __FILE__ , __LINE__);
671 
672  // We print 5 reweights
673  const int countwidth = int(double(n_points)/double(5));
674 
675  // Loop over the covariance classes
676  for (ParameterHandlerBase *cov : systematics)
677  {
678  // Scan over all the parameters
679  // Get the number of parameters
680  int npars = cov->GetNumParams();
681  bool IsPCA = cov->IsPCA();
682  if (IsPCA) npars = cov->GetNParameters();
683  for (int i = 0; i < npars; ++i)
684  {
685  // Get the parameter name
686  std::string name = cov->GetParFancyName(i);
687  if (IsPCA) name += "_PCA";
688  // KS: Check if we want to skip this parameter
689  if(CheckSkipParameter(SkipVector, name)) continue;
690  // Get the parameter central and bounds
691  double CentralValue, lower, upper;
692  GetParameterScanRange(cov, i, CentralValue, lower, upper, n_points);
693  // Define the TH1D
694  std::unique_ptr<TH1D> hScan;
695  // See if we want to do it logarithmically
696  if(LLHLogarithmic){
697  //negative values break it
698  if (lower < 0.0 || upper < 0.0) {
699  MACH3LOG_WARN("Cannot perform logarithmic scan for {} "" with range [{}, {}], falling back to linear scan",name, lower, upper);
700  hScan = std::make_unique<TH1D>((name + "_full").c_str(), (name + "_full").c_str(), n_points, lower, upper);
701  } else {
702  auto binEdges = CalculateBinEdges(lower, upper, n_points);
703  hScan = std::make_unique<TH1D>((name + "_full").c_str(), (name + "_full").c_str(), n_points, binEdges.data());
704  }
705  }
706  //If not then just do the normal thing
707  else {
708  hScan = std::make_unique<TH1D>((name + "_full").c_str(), (name + "_full").c_str(), n_points, lower, upper);
709  }
710 
711  hScan->SetTitle((std::string("2LLH_full, ") + name + ";" + name + "; -2(ln L_{sample} + ln L_{xsec+flux} + ln L_{det})").c_str());
712  hScan->SetDirectory(nullptr);
713 
714  auto hScanSam = std::make_unique<TH1D>((name + "_sam").c_str(), (name + "_sam").c_str(), n_points, lower, upper);
715  hScanSam->SetTitle((std::string("2LLH_sam, ") + name + ";" + name + "; -2(ln L_{sample})").c_str());
716  hScanSam->SetDirectory(nullptr);
717 
718  std::vector<std::unique_ptr<TH1D>> hScanSample(samples.size());
719  std::vector<double> nSamLLH(samples.size(), 0.0);
720  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
721  {
722  std::string NameTemp = samples[ivs]->GetName();
723  hScanSample[ivs] = std::make_unique<TH1D>((name+"_"+NameTemp).c_str(), (name+"_" + NameTemp).c_str(), n_points, lower, upper);
724  hScanSample[ivs]->SetDirectory(nullptr);
725  hScanSample[ivs]->SetTitle(("2LLH_" + NameTemp + ", " + name + ";" + name + "; -2(ln L_{" + NameTemp +"})").c_str());
726  }
727 
728  std::vector<std::unique_ptr<TH1D>> hScanCov(systematics.size());
729  std::vector<double> nCovLLH(systematics.size(), 0.0);
730  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc )
731  {
732  std::string NameTemp = systematics[ivc]->GetName();
733  NameTemp = NameTemp.substr(0, NameTemp.find("_cov"));
734  hScanCov[ivc] = std::make_unique<TH1D>((name + "_" + NameTemp).c_str(), (name + "_" + NameTemp).c_str(), n_points, lower, upper);
735  hScanCov[ivc]->SetDirectory(nullptr);
736  hScanCov[ivc]->SetTitle(("2LLH_" + NameTemp + ", " + name + ";" + name + "; -2(ln L_{" + NameTemp +"})").c_str());
737  }
738 
739  std::vector<std::unique_ptr<TH1D>> hScanSamSplit;
740  std::vector<double> sampleSplitllh;
741  if(PlotLLHScanBySample)
742  {
743  int SampleIterator = 0;
744  hScanSamSplit.resize(TotalNSamples);
745  sampleSplitllh.resize(TotalNSamples);
746  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
747  {
748  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is )
749  {
750  auto histName = name + samples[ivs]->GetSampleTitle(is);
751  auto histTitle = std::string("2LLH_sam, ") + name + ";" + name + "; -2(ln L_{sample})";
752  hScanSamSplit[SampleIterator] = std::make_unique<TH1D>(histName.c_str(), histTitle.c_str(), n_points, lower, upper);
753  hScanSamSplit[SampleIterator]->SetDirectory(nullptr);
754  SampleIterator++;
755  }
756  }
757  }
758 
759  // Scan over the parameter space
760 
761  for (int j = 0; j < n_points; ++j)
762  {
763  if (j % countwidth == 0)
764  M3::Utils::PrintProgressBar(j, n_points);
765 
766  // For PCA we have to do it differently
767  if (IsPCA) {
768  cov->GetPCAHandler()->SetParPropPCA(i, hScan->GetBinCenter(j+1));
769  } else {
770  // Set the parameter
771  cov->SetParProp(i, hScan->GetBinCenter(j+1));
772  }
773 
774  // Reweight the MC
775  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs ){
776  samples[ivs]->Reweight();
777  }
778  //Total LLH
779  double totalllh = 0.;
780 
781  // Get the -log L likelihoods
782  double samplellh = 0.;
783 
784  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs ) {
785  nSamLLH[ivs] = samples[ivs]->GetLikelihood();
786  samplellh += nSamLLH[ivs];
787  }
788 
789  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc ) {
790  nCovLLH[ivc] = systematics[ivc]->GetLikelihood();
791  totalllh += nCovLLH[ivc];
792  }
793 
794  totalllh += samplellh;
795 
796  if(PlotLLHScanBySample)
797  {
798  int SampleIterator = 0;
799  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
800  {
801  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is)
802  {
803  sampleSplitllh[SampleIterator] = samples[ivs]->GetSampleLikelihood(is);
804  SampleIterator++;
805  }
806  }
807  }
808 
809  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs ) {
810  hScanSample[ivs]->SetBinContent(j+1, 2*nSamLLH[ivs]);
811  }
812  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc ) {
813  hScanCov[ivc]->SetBinContent(j+1, 2*nCovLLH[ivc]);
814  }
815 
816  hScanSam->SetBinContent(j+1, 2*samplellh);
817  hScan->SetBinContent(j+1, 2*totalllh);
818 
819  if(PlotLLHScanBySample)
820  {
821  int SampleIterator = 0;
822  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
823  {
824  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is)
825  {
826  hScanSamSplit[SampleIterator]->SetBinContent(j+1, 2*sampleSplitllh[SampleIterator]);
827  SampleIterator++;
828  }
829  }
830  }
831  }
832  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc )
833  {
834  Cov_LLH[ivc]->cd();
835  hScanCov[ivc]->Write();
836  }
837 
838  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
839  {
840  SampleClass_LLH[ivs]->cd();
841  hScanSample[ivs]->Write();
842  }
843  Sample_LLH->cd();
844  hScanSam->Write();
845  Total_LLH->cd();
846  hScan->Write();
847 
848  if(PlotLLHScanBySample)
849  {
850  int SampleIterator = 0;
851  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
852  {
853  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is)
854  {
855  SampleSplit_LLH[SampleIterator]->cd();
856  hScanSamSplit[SampleIterator]->Write();
857  SampleIterator++;
858  }
859  }
860  }
861 
862  // Reset the parameters to their CentralValue central values
863  if (IsPCA) {
864  cov->GetPCAHandler()->SetParPropPCA(i, CentralValue);
865  } else {
866  cov->SetParProp(i, CentralValue);
867  }
868  }//end loop over systematics
869  }//end loop covariance classes
870 
871  for(unsigned int ivc = 0; ivc < systematics.size(); ++ivc )
872  {
873  Cov_LLH[ivc]->Write();
874  delete Cov_LLH[ivc];
875  }
876 
877  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
878  {
879  SampleClass_LLH[ivs]->Write();
880  delete SampleClass_LLH[ivs];
881  }
882 
883  Sample_LLH->Write();
884  delete Sample_LLH;
885 
886  Total_LLH->Write();
887  delete Total_LLH;
888 
889  if(PlotLLHScanBySample)
890  {
891  int SampleIterator = 0;
892  for(unsigned int ivs = 0; ivs < samples.size(); ++ivs )
893  {
894  for(int is = 0; is < samples[ivs]->GetNSamples(); ++is )
895  {
896  SampleSplit_LLH[SampleIterator]->Write();
897  delete SampleSplit_LLH[SampleIterator];
898  SampleIterator++;
899  }
900  }
901  }
902 }

◆ RunMCMC()

virtual void FitterBase::RunMCMC ( )
pure virtual

The specific fitting algorithm implemented in this function depends on the derived class. It could be Markov Chain Monte Carlo (MCMC), MinuitFit, or another algorithm.

Implemented in PyLikelihoodFit, PyFitterBase, NuDockServerBase, PredictiveThrower, PSO, MinuitFit, and MCMCBase.

◆ RunSigmaVar()

void FitterBase::RunSigmaVar ( )

Perform a 1D/2D sigma var for all samples.

Apply custom range to make easier comparison with p-theta

Definition at line 1538 of file FitterBase.cpp.

1538  {
1539 // *************************
1540  // Save the settings into the output file
1541  SaveSettings();
1542 
1543  bool plot_by_mode = GetFromManager<bool>(fitMan->raw()["SigmaVar"]["PlotByMode"], false, __FILE__ , __LINE__);
1544  bool plot_by_channel = GetFromManager<bool>(fitMan->raw()["SigmaVar"]["PlotByChannel"], false, __FILE__ , __LINE__);
1545  auto SkipVector = GetFromManager<std::vector<std::string>>(fitMan->raw()["SigmaVar"]["SkipVector"], {}, __FILE__ , __LINE__);
1546 
1547  if (plot_by_mode) MACH3LOG_INFO("Plotting by sample and mode");
1548  if (plot_by_channel) MACH3LOG_INFO("Plotting by sample and channel");
1549  if (!plot_by_mode && !plot_by_channel) MACH3LOG_INFO("Plotting by sample only");
1550  if (plot_by_mode && plot_by_channel) MACH3LOG_INFO("Plotting by sample, mode and channel");
1551 
1552  auto SigmaArray = GetFromManager<std::vector<double>>(fitMan->raw()["SigmaVar"]["SigmaArray"], {-3, -1, 0, 1, 3}, __FILE__ , __LINE__);
1553  if (std::find(SigmaArray.begin(), SigmaArray.end(), 0.0) == SigmaArray.end()) {
1554  MACH3LOG_ERROR(":: SigmaArray does not contain 0! Current contents: {} ::", fmt::join(SigmaArray, ", "));
1555  throw MaCh3Exception(__FILE__, __LINE__);
1556  }
1557 
1558  TDirectory* SigmaDir = outputFile->mkdir("SigmaVar");
1559  outputFile->cd();
1560 
1561  for (size_t s = 0; s < systematics.size(); ++s)
1562  {
1563  for(int i = 0; i < systematics[s]->GetNumParams(); i++)
1564  {
1565  std::string ParName = systematics[s]->GetParFancyName(i);
1566  // KS: Check if we want to skip this parameter
1567  if(CheckSkipParameter(SkipVector, ParName)) continue;
1568 
1569  MACH3LOG_INFO(":: Param {} ::", systematics[s]->GetParFancyName(i));
1570 
1571  TDirectory* ParamDir = SigmaDir->mkdir(ParName.c_str());
1572  ParamDir->cd();
1573 
1574  const double ParamCentralValue = systematics[s]->GetParProp(i);
1575  const double Prior = systematics[s]->GetParPreFit(i);
1576  const double ParamLower = systematics[s]->GetLowerBound(i);
1577  const double ParamUpper = systematics[s]->GetUpperBound(i);
1578 
1579  if (std::abs(ParamCentralValue - Prior) > 1e-10) {
1580  MACH3LOG_INFO("For {} scanning around value {} rather than prior {}", ParName, ParamCentralValue, Prior);
1581  }
1582 
1583  for(unsigned int iSample = 0; iSample < samples.size(); ++iSample)
1584  {
1585  auto* MaCh3Sample = samples[iSample];
1586  std::vector<TDirectory*> SampleDir(MaCh3Sample->GetNSamples());
1587  for (int SampleIndex = 0; SampleIndex < MaCh3Sample->GetNSamples(); ++SampleIndex) {
1588  SampleDir[SampleIndex] = ParamDir->mkdir(MaCh3Sample->GetSampleTitle(SampleIndex).c_str());
1589  }
1590 
1591  for (size_t j = 0; j < SigmaArray.size(); ++j) {
1592  double sigma = SigmaArray[j];
1593 
1594  double ParamShiftValue = ParamCentralValue + sigma * std::sqrt((*systematics[s]->GetCovMatrix())(i,i));
1595  ParamShiftValue = std::max(std::min(ParamShiftValue, ParamUpper), ParamLower);
1596 
1598  CustomRange(ParName, sigma, ParamShiftValue);
1599 
1600  MACH3LOG_INFO(" - set to {:<5.2f} ({:<2} sigma shift)", ParamShiftValue, sigma);
1601  systematics[s]->SetParProp(i, ParamShiftValue);
1602 
1603  std::ostringstream valStream;
1604  valStream << std::fixed << std::setprecision(2) << ParamShiftValue;
1605  std::string valueStr = valStream.str();
1606 
1607  std::ostringstream sigmaStream;
1608  sigmaStream << std::fixed << std::setprecision(2) << std::abs(sigma);
1609  std::string sigmaStr = sigmaStream.str();
1610 
1611  std::string suffix;
1612  if (sigma == 0) {
1613  suffix = "_" + ParName + "_nom_val_" + valueStr;
1614  } else {
1615  std::string sign = (sigma > 0) ? "p" : "n";
1616  suffix = "_" + ParName + "_sig_" + sign + sigmaStr + "_val_" + valueStr;
1617  }
1618 
1619  systematics[s]->SetParProp(i, ParamShiftValue);
1620  MaCh3Sample->Reweight();
1621 
1622  WriteHistogramsByMode(MaCh3Sample, suffix, plot_by_mode, plot_by_channel, SampleDir);
1623  }
1624  for (int subSampleIndex = 0; subSampleIndex < MaCh3Sample->GetNSamples(); ++subSampleIndex) {
1625  SampleDir[subSampleIndex]->Close();
1626  delete SampleDir[subSampleIndex];
1627  }
1628  ParamDir->cd();
1629  }
1630 
1631  systematics[s]->SetParProp(i, ParamCentralValue);
1632  MACH3LOG_INFO(" - set back to CV {:<5.2f}", ParamCentralValue);
1633  MACH3LOG_INFO("");
1634  ParamDir->Close();
1635  delete ParamDir;
1636  SigmaDir->cd();
1637  } // end loop over params
1638  } // end loop over systemics
1639  SigmaDir->Close();
1640  delete SigmaDir;
1641 
1642  outputFile->cd();
1643 }
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 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...
std::string join(const Container &values, std::string_view separator=" ")
Join all values in a container into a single string.
Definition: TablePrinter.h:36

◆ SanitiseInputs()

void FitterBase::SanitiseInputs ( )
protected

Remove obsolete memory and make other checks before fit starts.

Todo:
consider expanding into ParmaterHandler and add more sanitisers

Definition at line 225 of file FitterBase.cpp.

225  {
226 // *******************
227  for (size_t i = 0; i < samples.size(); ++i) {
228  samples[i]->CleanMemoryBeforeFit();
229  }
230 }

◆ SaveOutput()

void FitterBase::SaveOutput ( )
protected

Save output and close files.

Definition at line 233 of file FitterBase.cpp.

233  {
234 // *******************
235  if(FileSaved) return;
236  //Stop Clock
237  clock->Stop();
238 
239  //KS: Some version of ROOT keep spamming about accessing already deleted object which is wrong and not helpful...
240  int originalErrorLevel = gErrorIgnoreLevel;
241  gErrorIgnoreLevel = kFatal;
242 
243  outputFile->cd();
244  outTree->Write();
245 
246  MACH3LOG_INFO("{} steps took {:.2e} seconds to complete. ({:.2e}s / step).", step - stepStart, clock->RealTime(), clock->RealTime() / static_cast<double>(step - stepStart));
247  MACH3LOG_INFO("{} steps were accepted.", accCount);
248  #ifdef MACH3_DEBUG
249  if (debug)
250  {
251  debugFile << "\n\n" << step << " steps took " << clock->RealTime() << " seconds to complete. (" << clock->RealTime() / step << "s / step).\n" << accCount<< " steps were accepted." << std::endl;
252  debugFile.close();
253  }
254  #endif
255 
256  outputFile->Close();
257  FileSaved = true;
258 
259  gErrorIgnoreLevel = originalErrorLevel;
260 }

◆ SaveSettings()

void FitterBase::SaveSettings ( )
protected

Save the settings that the MCMC was run with.

Definition at line 79 of file FitterBase.cpp.

79  {
80 // *******************
81  if(SettingsSaved) return;
82 
83  outputFile->cd();
84 
85  TDirectory* MaCh3Version = outputFile->mkdir("MaCh3Engine");
86  MaCh3Version->cd();
87 
88  if (std::getenv("MaCh3_ROOT") == nullptr) {
89  MACH3LOG_ERROR("Need MaCh3_ROOT environment variable");
90  MACH3LOG_ERROR("Please remember about source bin/setup.MaCh3.sh");
91  throw MaCh3Exception(__FILE__ , __LINE__ );
92  }
93 
94  if (std::getenv("MACH3") == nullptr) {
95  MACH3LOG_ERROR("Need MACH3 environment variable");
96  throw MaCh3Exception(__FILE__ , __LINE__ );
97  }
98 
99  std::string header_path = std::string(std::getenv("MACH3"));
100  header_path += "/version.h";
101  FILE* file = fopen(header_path.c_str(), "r");
102  //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.
103  if (!file) {
104  header_path = std::string(std::getenv("MaCh3_ROOT"));
105  header_path += "/version.h";
106  } else {
107  fclose(file);
108  }
109 
110  // EM: embed the cmake generated version.h file
111  TMacro versionHeader("version_header", "version_header");
112  versionHeader.ReadFile(header_path.c_str());
113  versionHeader.Write();
114 
115  auto Name = GetFancyName();
116  if(Name == ""){
117  MACH3LOG_ERROR("Name of currently used algorithm is {}", Name);
118  MACH3LOG_ERROR("Have you forgotten to modify AlgorithmName?");
119  throw MaCh3Exception(__FILE__ , __LINE__ );
120  }
121  TNamed Engine(Name, Name);
122  Engine.Write(Name.c_str());
123 
124  MaCh3Version->Write();
125  delete MaCh3Version;
126 
127  outputFile->cd();
128 
130 
131  MACH3LOG_WARN("\033[0;31mCurrent Total RAM usage is {:.2f} GB\033[0m", M3::Utils::getValue("VmRSS") / 1048576.0);
132  MACH3LOG_WARN("\033[0;31mOut of Total available RAM {:.2f} GB\033[0m", M3::Utils::getValue("MemTotal") / 1048576.0);
133 
134  MACH3LOG_INFO("#####Current Setup#####");
135  MACH3LOG_INFO("Number of covariances: {}", systematics.size());
136  for(unsigned int i = 0; i < systematics.size(); ++i){
137  MACH3LOG_INFO("{}: Cov name: {}, it has {} params", i, systematics[i]->GetName(), systematics[i]->GetNumParams());
138  }
139  MACH3LOG_INFO("Number of SampleHandlers: {}", samples.size());
140  for(unsigned int i = 0; i < samples.size(); ++i) {
141  MACH3LOG_INFO("{}: SampleHandler name: {}, it has {} samples",i , samples[i]->GetName(), samples[i]->GetNSamples());
142  for(int iSam = 0; iSam < samples[i]->GetNSamples(); ++iSam) {
143  MACH3LOG_INFO(" {}: Sample title: {}, with {} osc channels",iSam , samples[i]->GetSampleTitle(iSam), samples[i]->GetNOscChannels(iSam));
144  }
145  }
146  //TN: Have to close the folder in order to write it to disk before SaveOutput is called in the destructor
147  CovFolder->Close();
148  SampleFolder->Close();
149 
150  SettingsSaved = true;
151 }
virtual std::string GetFancyName() const
This name is to get include some special algorithm extensions.
Definition: FitterBase.h:77
void SaveSettings(TFile *const OutputFile) const
Add manager useful information's to TFile, in most cases to Fitter.
Definition: Manager.cpp:40
int getValue(const std::string &Type)
CW: Get info like RAM.
Definition: Monitor.cpp:252

◆ StartFromPreviousFit()

void FitterBase::StartFromPreviousFit ( const std::string &  FitName)
virtual

Allow to start from previous fit/chain.

Parameters
FitNameName of previous chain

Reimplemented in MCMCBase.

Definition at line 350 of file FitterBase.cpp.

350  {
351 // *******************
352  MACH3LOG_INFO("Getting starting position from {}", FitName);
353  TFile *infile = M3::Open(FitName, "READ", __FILE__, __LINE__);
354  TTree *posts = infile->Get<TTree>("posteriors");
355  double log_val = M3::_LARGE_LOGL_;
356  posts->SetBranchAddress("LogL",&log_val);
357 
358  for (size_t s = 0; s < systematics.size(); ++s)
359  {
360  TDirectory* CovarianceFolder = infile->Get<TDirectory>("CovarianceFolder");
361 
362  std::string ConfigName = "Config_" + systematics[s]->GetName();
363  TMacro *ConfigCov = CovarianceFolder->Get<TMacro>(ConfigName.c_str());
364  // KS: Not every covariance uses yaml, if it uses yaml make sure they are identical
365  if (ConfigCov != nullptr) {
366  // Config which was in MCMC from which we are starting
367  YAML::Node CovSettings = TMacroToYAML(*ConfigCov);
368  // Config from currently used cov object
369  YAML::Node ConfigCurrent = systematics[s]->GetConfig();
370 
371  if (!compareYAMLNodes(CovSettings, ConfigCurrent))
372  {
373  MACH3LOG_ERROR("Yaml configs in previous chain (from path {}) and current one are different", FitName);
374  throw MaCh3Exception(__FILE__ , __LINE__ );
375  }
376  delete ConfigCov;
377  }
378 
379  CovarianceFolder->Close();
380  delete CovarianceFolder;
381 
382  std::vector<double> branch_vals;
383  std::vector<std::string> branch_name;
384  systematics[s]->MatchMaCh3OutputBranches(posts, branch_vals, branch_name);
385  posts->GetEntry(posts->GetEntries()-1);
386 
387  systematics[s]->SetParameters(branch_vals);
388  systematics[s]->AcceptStep();
389 
390  MACH3LOG_INFO("Printing new starting values for: {}", systematics[s]->GetName());
391  systematics[s]->PrintPreFitCurrPropValues();
392 
393  // Resetting branch addressed to nullptr as we don't want to write into a deleted vector out of scope...
394  for (int i = 0; i < systematics[s]->GetNumParams(); ++i) {
395  posts->SetBranchAddress(systematics[s]->GetParName(i).c_str(), nullptr);
396  }
397  }
398  logLCurr = log_val;
399  logLProp = log_val;
400 
401  delete posts;
402  infile->Close();
403  delete infile;
404 }
YAML::Node TMacroToYAML(const TMacro &macro)
KS: Convert a ROOT TMacro object to a YAML node.
Definition: YamlHelper.h:151
bool compareYAMLNodes(const YAML::Node &node1, const YAML::Node &node2, bool Mute=false)
Compare if yaml nodes are identical.
Definition: YamlHelper.h:185
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

Member Data Documentation

◆ accCount

int FitterBase::accCount
protected

counts accepted steps

Definition at line 131 of file FitterBase.h.

◆ accProb

double FitterBase::accProb
protected

current acceptance prob

Definition at line 129 of file FitterBase.h.

◆ AlgorithmName

std::string FitterBase::AlgorithmName
protected

Name of fitting algorithm that is being used.

Definition at line 177 of file FitterBase.h.

◆ auto_save

int FitterBase::auto_save
protected

auto save every N steps

Definition at line 164 of file FitterBase.h.

◆ clock

std::unique_ptr<TStopwatch> FitterBase::clock
protected

tells global time how long fit took

Definition at line 149 of file FitterBase.h.

◆ CovFolder

TDirectory* FitterBase::CovFolder
protected

Output cov folder.

Definition at line 158 of file FitterBase.h.

◆ FileSaved

bool FitterBase::FileSaved
protected

Checks if file saved not repeat some operations.

Definition at line 170 of file FitterBase.h.

◆ fitMan

Manager* FitterBase::fitMan
protected

The manager for configuration handling.

Definition at line 120 of file FitterBase.h.

◆ fTestLikelihood

bool FitterBase::fTestLikelihood
protected

Necessary for some fitting algorithms like PSO.

Definition at line 167 of file FitterBase.h.

◆ logLCurr

double FitterBase::logLCurr
protected

current likelihood

Definition at line 125 of file FitterBase.h.

◆ logLProp

double FitterBase::logLProp
protected

proposed likelihood

Definition at line 127 of file FitterBase.h.

◆ outputFile

TFile* FitterBase::outputFile
protected

Output.

Definition at line 156 of file FitterBase.h.

◆ OutputPrepared

bool FitterBase::OutputPrepared
protected

Checks if output prepared not repeat some operations.

Definition at line 174 of file FitterBase.h.

◆ outTree

TTree* FitterBase::outTree
protected

Output tree with posteriors.

Definition at line 162 of file FitterBase.h.

◆ sample_llh

std::vector<double> FitterBase::sample_llh
protected

store the llh breakdowns

Definition at line 136 of file FitterBase.h.

◆ SampleFolder

TDirectory* FitterBase::SampleFolder
protected

Output sample folder.

Definition at line 160 of file FitterBase.h.

◆ samples

std::vector<SampleHandlerInterface*> FitterBase::samples
protected

Sample holder.

Definition at line 141 of file FitterBase.h.

◆ SettingsSaved

bool FitterBase::SettingsSaved
protected

Checks if setting saved not repeat some operations.

Definition at line 172 of file FitterBase.h.

◆ step

unsigned int FitterBase::step
protected

current state

Definition at line 123 of file FitterBase.h.

◆ stepClock

std::unique_ptr<TStopwatch> FitterBase::stepClock
protected

tells how long single step/fit iteration took

Definition at line 151 of file FitterBase.h.

◆ stepStart

unsigned int FitterBase::stepStart
protected

step start, by default 0 if we start from previous chain then it will be different

Definition at line 133 of file FitterBase.h.

◆ stepTime

double FitterBase::stepTime
protected

Time of single step.

Definition at line 153 of file FitterBase.h.

◆ syst_llh

std::vector<double> FitterBase::syst_llh
protected

systematic llh breakdowns

Definition at line 138 of file FitterBase.h.

◆ systematics

std::vector<ParameterHandlerBase*> FitterBase::systematics
protected

Systematic holder.

Definition at line 146 of file FitterBase.h.

◆ TotalNSamples

unsigned int FitterBase::TotalNSamples
protected

Total number of samples used, single SampleHandler can store more than one analysis sample!

Definition at line 143 of file FitterBase.h.


The documentation for this class was generated from the following files: