MaCh3  2.6.1
Reference Guide
MCMCBase.cpp
Go to the documentation of this file.
1 #include "Fitters/MCMCBase.h"
2 
3 // *************************
4 // Initialise the Manager and make it an object of mcmc class
5 // Now we can dump Manager settings to the output file
7 // *************************
8  // Beginning step number
9  stepStart = 0;
10 
11  // Starting parameters should be thrown
12  out_of_bounds = false;
13  chainLength = Get<unsigned>(fitMan->raw()["General"]["MCMC"]["NSteps"], __FILE__, __LINE__);
14  if (chainLength < 10){
15  MACH3LOG_ERROR("MCMC chain length must be at least 10 steps, otherwise this will result in a floating point exception.");
16  throw MaCh3Exception(__FILE__, __LINE__);
17  }
18 
19  AnnealTemp = GetFromManager<double>(fitMan->raw()["General"]["MCMC"]["AnnealTemp"], -999, __FILE__ , __LINE__);
20  if (AnnealTemp < 0)
21  anneal = false;
22  else
23  {
24  MACH3LOG_INFO("Enabling simulated annealing with T = {}", AnnealTemp);
25  anneal = true;
26  }
27 }
28 
29 
30 // *******************
31 // Run the Markov chain with all the systematic objects added
33 // *******************
34  // Multicanonical method toggle from yaml config
35  multicanonical = GetFromManager<bool>(fitMan->raw()["General"]["MCMC"]["Multicanonical"]["Enabled"], false, __FILE__, __LINE__);
36  MACH3LOG_INFO("Multicanonical Method: {}", multicanonical);
37 
38  if (multicanonical) {
40  multicanonicalHandler = std::make_unique<MulticanonicalMCMCHandler>();
41 
42  // Initialize the multicanonical handler with the systematics
43  multicanonicalHandler->InitializeMulticanonicalHandlerConfig(fitMan, systematics);
44  AlgorithmName += "_UmbrellaSampling"; // Append to the algorithm name
45 #ifdef MACH3_DEBUG
46  // Enable debug output stream for multicanonical handler if debug is enabled
47  multicanonicalHandler->setDebugStream(&debugFile, debug);
48 #endif
49  }
50 
51  // Save the settings into the output file
52  SaveSettings();
53 
54  // Prepare the output branches
55  PrepareOutput();
56 
57  // Remove obsolete memory and make other checks before fit starts
59 
60  // Print Progress before Propose Step
61  PrintProgress(false);
62 
63  // Only propose step if we are running fresh chain. If we are running from previous chain then it's not needed and we can use usual pipeline
64  if(stepStart == 0) {
65  // Reconfigure the samples, systematics and oscillation for first weight
66  // ProposeStep sets logLProp
67  ProposeStep();
68 
69  // Initialise the value of the multicanonical parameter to the centres of the umbrellas
70  if (multicanonical){
71  multicanonicalHandler->InitializeMulticanonicalParams(systematics);
72  }
73  // Set the current logL to the proposed logL for the 0th step
74  // Accept the first step to set logLCurr: this shouldn't affect the MCMC because we ignore the first N steps in burn-in
76  }
77 
78  // Begin MCMC
79  const auto StepEnd = stepStart + chainLength;
80  for (step = stepStart; step < StepEnd; ++step)
81  {
82  DoMCMCStep();
83  }
84  // Save all the MCMC output
85  SaveOutput();
86 
87  // Process MCMC
88  ProcessMCMC();
89 
90  // Save the adaptive MCMC
91  for (const auto &syst : systematics)
92  {
93  if (syst->GetDoAdaption())
94  {
95  auto adaptive_handler = syst->GetAdaptiveHandler();
96  adaptive_handler->SaveAdaptiveToFile(adaptive_handler->GetOutFileName(), syst->GetName(), true);
97  }
98  }
99 }
100 
101 // *******************
103 // *******************
105  PreStepProcess();
107  DoStep();
109  PostStepProcess();
110 }
111 
112 // *******************
114 // *******************
115  stepClock->Start();
116  out_of_bounds = false;
117 
118  // Print 10 steps in total
119  if ((step - stepStart) % (chainLength / 10) == 0)
120  {
122  PrintProgress();
123  }
124 }
125 
126 // *************************
128 // *************************
129  //KS: Some version of ROOT keep spamming about accessing already deleted object which is wrong and not helpful...
130  int originalErrorLevel = gErrorIgnoreLevel;
131  gErrorIgnoreLevel = kFatal;
132 
133  stepClock->Stop();
134  stepTime = stepClock->RealTime();
135 
136  // Write step to output tree
137  outTree->Fill();
138 
139  // Do Adaptive MCMC
140  AdaptiveStep();
141 
142  if (step % auto_save == 0){
143  outTree->AutoSave();
144  }
145  gErrorIgnoreLevel = originalErrorLevel;
146 }
147 
148 // *******************
149 // Print the fit output progress
150 void MCMCBase::PrintProgress(bool StepsPrint) {
151 // *******************
152  if(StepsPrint) MACH3LOG_INFO("Step:\t{}/{}, current: {:.2f}, proposed: {:.2f}", step - stepStart, chainLength, logLCurr, logLProp);
153  if(StepsPrint) MACH3LOG_INFO("Accepted/Total steps: {}/{} = {:.2f}", accCount, step - stepStart, static_cast<double>(accCount) / static_cast<double>(step - stepStart));
154 
155  for (size_t i = 0; i < samples.size(); ++i) {
156  samples[i]->PrintRates();
157  }
158 
159  for (ParameterHandlerBase *cov : systematics) {
160  cov->PrintPreFitCurrPropValues();
161  }
162 #ifdef MACH3_DEBUG
163  if (debug)
164  {
165  debugFile << "\n-------------------------------------------------------" << std::endl;
166  debugFile << "Step:\t" << step + 1 << "/" << chainLength << " | current: " << logLCurr << " proposed: " << logLProp << std::endl;
167  }
168 #endif
169 }
170 
171 // *******************
172 // Handles warnings for low acceptance rates
174 // *******************
175  const auto StepEnd = stepStart + chainLength;
176 
177  // Skip check for reallllly early steps
178  if(step - stepStart < std::min(10.0, static_cast<double>(StepEnd)/10)) {
179  return;
180  }
181  // KS: Do not add "throw", this can crash CI or some short dummy chains for testing
182  if(accCount==0 && step - stepStart > StepEnd/10) {
183  MACH3LOG_CRITICAL("No steps were accepted in the MCMC chain after {} steps. Please check your step sizes.", step - stepStart);
184  }
185 
186  double acc_rate = static_cast<double>(accCount) / static_cast<double>(step - stepStart);
187 
188  if (acc_rate < 0.01) {
189  MACH3LOG_WARN("Acceptance rate is very low: {:.4f}. This may indicate that the proposal distribution is not well-tuned. Consider reducing the step size.", acc_rate);
190  } else if (acc_rate > 0.5) {
191  MACH3LOG_WARN("Acceptance rate is very high: {:.4f}. This may indicate that the proposal distribution is too narrow. Consider increasing the step sizes.", acc_rate);
192  }
193 }
194 
195 // *******************
196 void MCMCBase::StartFromPreviousFit(const std::string &FitName) {
197 // *******************
198  // Use base class
200 
201  // For MCMC we also need to set stepStart
202  TFile *infile = M3::Open(FitName, "READ", __FILE__, __LINE__);
203  TTree *posts = infile->Get<TTree>("posteriors");
204  unsigned int step_val = 0;
205 
206  posts->SetBranchAddress("step", &step_val);
207  posts->GetEntry(posts->GetEntries() - 1);
208 
209  stepStart = step_val;
210  // KS: Also update number of steps if using adaption
211  for (unsigned int i = 0; i < systematics.size(); ++i) {
212  if (systematics[i]->GetDoAdaption()) {
213  systematics[i]->SetNumberOfSteps(stepStart);
214  }
215  }
216  infile->Close();
217  delete infile;
218 }
219 
220 // *************************
222 // *************************
223  // Save the Adaptive output
224  for (const auto &syst : systematics)
225  {
226  if (syst->GetDoAdaption()){
227  syst->UpdateAdaptiveCovariance();
228  }
229  }
230 }
231 
232 // *************************
233 bool MCMCBase::IsStepAccepted(const double acc_prob) {
234 // *************************
235  // Get the random number
236  const double fRandom = random->Rndm();
237  // Do the accept/reject
238  #ifdef MACH3_DEBUG
239  debugFile << " logLProp: " << logLProp << " logLCurr: " << logLCurr << " acc_prob: " << acc_prob << " fRandom: " << fRandom << std::endl;
240  #endif
241 
242  if (fRandom > acc_prob)
243  {
244  // Reject
245  return false;
246  }
247  return true;
248 }
249 
250 // *************************
252 // *************************
253  ++accCount;
254  logLCurr = logLProp;
255 
256  // Loop over systematics and accept
257  for (size_t s = 0; s < systematics.size(); ++s)
258  {
259  systematics[s]->AcceptStep();
260  }
261 }
#define MACH3LOG_CRITICAL
Definition: MaCh3Logger.h:38
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:37
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:35
#define MACH3LOG_WARN
Definition: MaCh3Logger.h:36
Base class for implementing fitting algorithms.
Definition: FitterBase.h:29
std::unique_ptr< TRandom3 > random
Random number.
Definition: FitterBase.h:153
double logLProp
proposed likelihood
Definition: FitterBase.h:124
void ProcessMCMC()
Process MCMC output.
Definition: FitterBase.cpp:407
int accCount
counts accepted steps
Definition: FitterBase.h:128
void SaveOutput()
Save output and close files.
Definition: FitterBase.cpp:232
void SaveSettings()
Save the settings that the MCMC was run with.
Definition: FitterBase.cpp:80
unsigned int step
current state
Definition: FitterBase.h:120
void PrepareOutput()
Prepare the output file.
Definition: FitterBase.cpp:154
virtual void StartFromPreviousFit(const std::string &FitName)
Allow to start from previous fit/chain.
Definition: FitterBase.cpp:349
std::string AlgorithmName
Name of fitting algorithm that is being used.
Definition: FitterBase.h:177
std::vector< SampleHandlerInterface * > samples
Sample holder.
Definition: FitterBase.h:138
double stepTime
Time of single step.
Definition: FitterBase.h:150
Manager * fitMan
The manager for configuration handling.
Definition: FitterBase.h:117
unsigned int stepStart
step start, by default 0 if we start from previous chain then it will be different
Definition: FitterBase.h:130
std::unique_ptr< TStopwatch > stepClock
tells how long single step/fit iteration took
Definition: FitterBase.h:148
double logLCurr
current likelihood
Definition: FitterBase.h:122
int auto_save
auto save every N steps
Definition: FitterBase.h:164
TTree * outTree
Output tree with posteriors.
Definition: FitterBase.h:162
void SanitiseInputs()
Remove obsolete memory and make other checks before fit starts.
Definition: FitterBase.cpp:224
std::vector< ParameterHandlerBase * > systematics
Systematic holder.
Definition: FitterBase.h:143
std::unique_ptr< MulticanonicalMCMCHandler > multicanonicalHandler
multicanonical handler for umbrella sampling
Definition: MCMCBase.h:64
MCMCBase(Manager *const fitMan)
Constructor.
Definition: MCMCBase.cpp:6
bool anneal
simulated annealing
Definition: MCMCBase.h:76
void RunMCMC() final
Actual implementation of MCMC fitting algorithm.
Definition: MCMCBase.cpp:32
unsigned int chainLength
number of steps in chain
Definition: MCMCBase.h:73
void StartFromPreviousFit(const std::string &FitName) final
Allow to start from previous fit/chain.
Definition: MCMCBase.cpp:196
void AcceptStep()
Accept a step.
Definition: MCMCBase.cpp:251
double AnnealTemp
simulated annealing temperature
Definition: MCMCBase.h:78
bool out_of_bounds
Do we reject based on hitting boundaries in systs.
Definition: MCMCBase.h:67
bool IsStepAccepted(const double acc_prob)
Is step accepted?
Definition: MCMCBase.cpp:233
void DoMCMCStep()
The full StartStep->DoStep->EndStep chain.
Definition: MCMCBase.cpp:102
void PreStepProcess()
Actions before step proposal [start stopwatch].
Definition: MCMCBase.cpp:113
bool multicanonical
multi-canonical method toggle on/off
Definition: MCMCBase.h:81
virtual void ProposeStep()=0
Propose a step.
void CheckAcceptanceRates()
Check the acceptance rates.
Definition: MCMCBase.cpp:173
void PrintProgress(const bool StepsPrint=true)
Print the progress.
Definition: MCMCBase.cpp:150
virtual void DoStep()=0
The MCMC step proposal and acceptance.
void PostStepProcess()
Actions after step proposal [end stopwatch, fill tree].
Definition: MCMCBase.cpp:127
void AdaptiveStep()
Adaptive MCMC step.
Definition: MCMCBase.cpp:221
Custom exception class used throughout MaCh3.
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
Base class for handling systematic uncertainty parameters.
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.