BCEngineMCMC.cxx
1 /*
2  * Copyright (C) 2007-2018, the BAT core developer team
3  * All rights reserved.
4  *
5  * For the licensing terms see doc/COPYING.
6  * For documentation see http://mpp.mpg.de/bat
7  */
8 
9 // ---------------------------------------------------------
10 #include <config.h>
11 
12 #include "BCEngineMCMC.h"
13 
14 #include "BCAux.h"
15 #include "BCGaussianPrior.h"
16 #include "BCH1D.h"
17 #include "BCH2D.h"
18 #include "BCMath.h"
19 #include "BCPrior.h"
20 #include "BCSplitGaussianPrior.h"
21 #include "BCTF1LogPrior.h"
22 #include "BCTF1Prior.h"
23 #include "BCTH1Prior.h"
24 #include "BCVariable.h"
25 #include "config.h"
26 
27 #include <TCanvas.h>
28 #include <TDecompChol.h>
29 #include <TF1.h>
30 #include <TFile.h>
31 #include <TGraph.h>
32 #include <TGraphErrors.h>
33 #include <TGraphAsymmErrors.h>
34 #include <TH1.h>
35 #include <TH2.h>
36 #include <TH2D.h>
37 #include <TKey.h>
38 #include <TLatex.h>
39 #include <TLegend.h>
40 #include <TLine.h>
41 #include <TList.h>
42 #include <TObject.h>
43 #include <TROOT.h>
44 #include <TSeqCollection.h>
45 #include <TStyle.h>
46 #include <TTree.h>
47 
48 #include <cmath>
49 
50 #if THREAD_PARALLELIZATION
51 #include <omp.h>
52 #endif
53 
54 // ---------------------------------------------------------
55 BCEngineMCMC::BCEngineMCMC(const std::string& name)
56  : fMCMCNIterationsConvergenceGlobal(-1),
57  fMCMCFlagWriteChainToFile(false),
58  fMCMCFlagWritePreRunToFile(false),
59  fMCMCOutputFile(0),
60  fMCMCOutputFilename(""),
61  fMCMCOutputFileOption(""),
62  fMCMCScaleFactorLowerLimit(0),
63  fMCMCScaleFactorUpperLimit(std::numeric_limits<double>::max()),
64  fMultivariateCovarianceUpdates(0),
65  fMultivariateCovarianceUpdateLambda(0.5),
66  fMultivariateEpsilon(0.05),
67  fMultivariateScaleMultiplier(1.5),
68  fMCMCEfficiencyMin(0.15),
69  fMCMCEfficiencyMax(0.35),
70  fInitialPositionScheme(BCEngineMCMC::kInitRandomUniform),
71  fInitialPositionAttemptLimit(100),
72  fMCMCProposeMultivariate(true),
73  fMCMCProposalFunctionDof(1.0),
74  fMCMCPhase(BCEngineMCMC::kUnsetPhase),
75  fCorrectRValueForSamplingVariability(false),
76  fMCMCRValueParametersCriterion(1.1),
77  fMCMCTree(NULL),
78  fMCMCTreeLoaded(false),
79  fMCMCTreeReuseObservables(true),
80  fParameterTree(NULL),
81  fRescaleHistogramRangesAfterPreRun(false),
82  fHistogramRescalePadding(0.1)
83 {
84  SetName(name);
85  SetPrecision(BCEngineMCMC::kMedium);
86  SetRandomSeed(0);
87 }
88 
89 // ---------------------------------------------------------
90 BCEngineMCMC::BCEngineMCMC(const std::string& filename, const std::string& name, bool loadObservables)
94  fMCMCOutputFile(NULL),
98  fMCMCScaleFactorUpperLimit(std::numeric_limits<double>::max()),
101  fMultivariateEpsilon(5.e-2),
103  fMCMCEfficiencyMin(0.15),
104  fMCMCEfficiencyMax(0.35),
112  fMCMCTree(NULL),
113  fMCMCTreeLoaded(false),
115  fParameterTree(NULL),
118 {
119  SetName(name);
120  SetPrecision(BCEngineMCMC::kMedium);
121  SetRandomSeed(0);
122  LoadMCMC(filename, "", "", loadObservables);
123 }
124 
125 // ---------------------------------------------------------
127  : fMCMCThreadLocalStorage(other.fMCMCThreadLocalStorage),
128  fChainIndex(other.fChainIndex),
129  fName(other.fName),
130  fSafeName(other.fSafeName),
131  fParameters(other.fParameters),
132  fObservables(other.fObservables),
133  fMCMCNChains(other.fMCMCNChains),
134  fMCMCNLag(other.fMCMCNLag),
164  fMCMCPhase(other.fMCMCPhase),
165  fMCMCStates(other.fMCMCStates),
171  fRandom(other.fRandom),
172  fRequestedH2(other.fRequestedH2),
173  fMCMCTree(NULL),
174  fMCMCTreeLoaded(false),
177  fParameterTree(NULL),
178  fLocalModes(other.fLocalModes),
184 {
185  // set again in case user overloads the setter to create custom structures
186  SetNChains(other.fMCMCNChains);
187 
188  CloneMarginals(other);
189 }
190 
192 {
193  if (this == &other) {
194  return *this;
195  }
196 
197  DeleteMarginals();
198  CloseOutputFile();
199 
200  // exception safety
201  try {
202  fMCMCThreadLocalStorage = other.fMCMCThreadLocalStorage;
203  fChainIndex = other.fChainIndex;
204  fName = other.fName;
205  fSafeName = other.fSafeName;
206  fParameters = other.fParameters;
207  fObservables = other.fObservables;
208  SetNChains(other.fMCMCNChains);
209  fMCMCNLag = other.fMCMCNLag;
238  fMCMCPhase = other.fMCMCPhase;
245  fRandom = other.fRandom;
246  fRequestedH2 = other.fRequestedH2;
249  fLocalModes = other.fLocalModes;
254  fObjectTrash = other.fObjectTrash;
255 
256  // don't create file!
257 
258  CloneMarginals(other);
259  } catch (...) {
260  // leave object in sane state but otherwise don't know what to do with exception
261  DeleteMarginals();
262  throw;
263  }
264 
265  return *this;
266 }
267 
268 // ---------------------------------------------------------
269 void BCEngineMCMC::CloneMarginals(const BCEngineMCMC& other)
270 {
271  fH1Marginalized = std::vector<TH1*>(other.fH1Marginalized.size(), NULL);
272  for (unsigned i = 0; i < other.fH1Marginalized.size(); ++i)
273  if (other.fH1Marginalized[i])
275 
276  if (!other.fH2Marginalized.empty() && !other.fH2Marginalized.front().empty()) {
277  fH2Marginalized = std::vector<std::vector<TH2*> > (other.fH2Marginalized.size(), std::vector<TH2*>(other.fH2Marginalized.front().size(), NULL));
278  for (unsigned i = 0; i < other.fH2Marginalized.size(); ++i) {
279  fH2Marginalized[i].assign(other.fH2Marginalized[i].size(), NULL);
280  for (unsigned j = 0; j < other.fH2Marginalized[i].size(); ++j)
281  if (other.fH2Marginalized[i][j])
282  fH2Marginalized[i][j] = BCAux::OwnClone(other.fH2Marginalized[i][j]);
283  }
284  }
285 }
286 
287 // ---------------------------------------------------------
288 void BCEngineMCMC::DeleteMarginals()
289 {
290  // delete 1-d marginalized distributions
291  for (unsigned i = 0; i < fH1Marginalized.size(); ++i)
292  delete fH1Marginalized[i];
293 
294  // delete 2-d marginalized distributions
295  for (unsigned i = 0; i < fH2Marginalized.size(); ++i)
296  for (unsigned j = 0; j < fH2Marginalized[i].size(); ++j)
297  delete fH2Marginalized[i][j];
298 }
299 
300 // ---------------------------------------------------------
302 {
303  DeleteMarginals();
304  CloseOutputFile();
305 }
306 
307 // ---------------------------------------------------------
308 void BCEngineMCMC::SetName(const std::string& name)
309 {
310  fName = name;
311  fSafeName = BCAux::SafeName(name);
312 }
313 
314 // ---------------------------------------------------------
315 void BCEngineMCMC::SetPrior(unsigned index, TF1& f, bool logL)
316 {
317  if (logL)
318  fParameters.At(index).SetPrior(new BCTF1LogPrior(f));
319  else
320  fParameters.At(index).SetPrior(new BCTF1Prior(f));
321 }
322 
323 // ---------------------------------------------------------
324 void BCEngineMCMC::SetPrior(unsigned index, TH1& h, bool interpolate)
325 {
326  fParameters.At(index).SetPrior(new BCTH1Prior(h, interpolate));
327 }
328 
329 // ---------------------------------------------------------
330 void BCEngineMCMC::SetPriorGauss(unsigned index, double mean, double sigma)
331 {
332  fParameters.At(index).SetPrior(new BCGaussianPrior(mean, sigma));
333 }
334 
335 // ---------------------------------------------------------
336 void BCEngineMCMC::SetPriorGauss(unsigned index, double mean, double sigma_below, double sigma_above)
337 {
338  fParameters.At(index).SetPrior(new BCSplitGaussianPrior(mean, sigma_below, sigma_above));
339 }
340 
341 // ---------------------------------------------------------
342 void BCEngineMCMC::SetNLag(unsigned n)
343 {
344  if (n == 0) {
345  BCLog::OutError("Invalid lag = 0 given. Set to lag = 1");
346  fMCMCNLag = 1;
347  } else {
348  fMCMCNLag = n;
349  }
350 }
351 
352 // ---------------------------------------------------------
354 {
355 
356  // don't clear means, variances etc. during prerun
358 
359  // take every iteration
360  fMCMCNLag = 1;
361 
362  switch (precision) {
363 
364  case BCEngineMCMC::kLow:
365  SetNChains(1);
369  fMCMCNIterationsRun = 10000;
370  break;
371 
372  case BCEngineMCMC::kQuick:
373  SetNChains(2);
377  fMCMCNIterationsRun = 10000;
378  break;
379 
380  case BCEngineMCMC::kMedium:
381  SetNChains(4);
384  fMCMCNIterationsPreRunMax = 100000;
385  fMCMCNIterationsRun = 100000;
386  break;
387 
388  case BCEngineMCMC::kHigh:
389  SetNChains(8);
392  fMCMCNIterationsPreRunMax = 1000000;
393  fMCMCNIterationsRun = 1000000;
394  break;
395 
396  case BCEngineMCMC::kVeryHigh:
397  SetNChains(8);
400  fMCMCNIterationsPreRunMax = 10000000;
401  fMCMCNIterationsRun = 10000000;
402  break;
403 
404  default:
405  BCLOG_ERROR("Invalid precision");
406  }
407 }
408 
409 // ---------------------------------------------------------
411 {
412  SetNChains(other.fMCMCNChains);
413  fMCMCNLag = other.fMCMCNLag;
427 }
428 
429 // --------------------------------------------------------
431 {
432  if (flag && fMCMCOutputFilename.empty())
433  BCLog::OutError("BCEngineMCMC::WriteMarkovChainRun: First turn on output using WriteMarkovChain(filename, option, main_run, pre_run).");
435 }
436 
437 // --------------------------------------------------------
439 {
440  if (flag && fMCMCOutputFilename.empty())
441  BCLog::OutError("BCEngineMCMC::WriteMarkovChainPreRun: First turn on output using WriteMarkovChain(filename, option, main_run, pre_run).");
443 }
444 
445 // --------------------------------------------------------
446 void BCEngineMCMC::WriteMarkovChain(const std::string& filename, const std::string& option, bool flag_run, bool flag_prerun)
447 {
448  // if setting both false
449  if (!flag_run && !flag_prerun)
450  WriteMarkovChain(false);
451 
452  if (filename.empty()) {
453  BCLog::OutError("BCEngineMCMC::WriteMarkovChain: You must specify the filename when turning on Markov chain output.");
454  return WriteMarkovChain(false);
455  }
456 
457  fMCMCOutputFilename = filename;
458  fMCMCOutputFileOption = option;
459  fMCMCFlagWriteChainToFile = flag_run;
460  fMCMCFlagWritePreRunToFile = flag_prerun;
461 }
462 
463 // --------------------------------------------------------
464 void BCEngineMCMC::WriteMarginalizedDistributions(const std::string& filename, const std::string& option, bool closeExistingFile)
465 {
466  // remember current directory
467  TDirectory* dir = gDirectory;
468 
469  // look to see if file is already open
470  TSeqCollection* listOfFiles = gROOT->GetListOfFiles();
471  TFile* fOut = NULL;
472  for (int i = 0; i < listOfFiles->GetEntries(); ++i)
473  if (listOfFiles->At(i) && filename.compare(listOfFiles->At(i)->GetName()) == 0) {
474  fOut = dynamic_cast<TFile*>(listOfFiles->At(i));
475  break;
476  }
477  if (fOut) {
478  if (option.compare("RECREATE") == 0) {
479  // if recreating, close current file, which will be overwritten
480  BCLog::OutError("BCEngineMCMC::WriteMarginalizedDistributions: File already open. option \"RECREATE\" will now overwrite it!");
481  if (fOut->IsWritable())
482  fOut->Write(0, TObject::kWriteDelete);
483  fOut->Close();
484  fOut = NULL;
485  closeExistingFile = true; // existing file closed; close newly opened file
486  } else if (option.compare("UPDATE") == 0 && !fOut->IsWritable()) {
487  BCLog::OutError("BCEngineMCMC::WriteMarginalizedDistributions: File already open but not in readable mode.");
488  return;
489  }
490  } else {
491  closeExistingFile = true; // no pre-open file found; close newly opened file
492  }
493 
494  // else open file
495  if (!fOut)
496  fOut = TFile::Open(filename.c_str(), option.c_str());
497 
498  if (!fOut) {
499  BCLog::OutError("BCEngineMCMC::WriteMarginalizedDistributions: Could not open output file.");
500  return;
501  }
502 
503  if (!fOut->IsWritable()) {
504  BCLog::OutError("BCEngineMCMC::WriteMarginalizedDistributions: File must be opened in writeable mode.");
505  return;
506  }
507 
508  // write histograms
509  for (unsigned i = 0; i < GetNVariables(); ++i) {
511  fOut->WriteTObject(GetMarginalizedHistogram(i));
512  for (unsigned j = 0; j < GetNVariables(); ++j)
513  if (MarginalizedHistogramExists(i, j))
514  fOut->WriteTObject(GetMarginalizedHistogram(i, j));
515  }
516 
517  // Causes multiple instances of any tree that already exists in the root file.
518  // fOut->Write();
519 
520  if (closeExistingFile)
521  fOut->Close();
522 
523  // restore directory
524  gDirectory = dir;
525 }
526 
527 // --------------------------------------------------------
528 TH1* BCEngineMCMC::GetMarginalizedHistogram(unsigned index) const
529 {
530  if (index >= fH1Marginalized.size()) {
531  BCLog::OutError(Form("BCEngineMCMC::GetMarginalizedHistogram. Index %u out of range.", index));
532  return 0;
533  }
534 
535  if (fH1Marginalized[index])
536  return fH1Marginalized[index];
537 
538  // else output warning
539  if (index < GetNVariables()) // Marginalization of model parameter
540  BCLog::OutWarning(Form("BCEngineMCMC::GetMarginalizedHistogram: marginal distribution not stored for %s %s", GetVariable(index).GetPrefix().data(), GetVariable(index).GetName().data()));
541 
542  return NULL;
543 }
544 
545 // --------------------------------------------------------
546 TH2* BCEngineMCMC::GetMarginalizedHistogram(unsigned i, unsigned j) const
547 {
548  if (i == j) {
549  BCLog::OutError(Form("BCEngineMCMC::GetMarginalizedHistogram. Called with identical indices %u.", i));
550  return NULL;
551  }
552 
553  if (i >= fH2Marginalized.size()) {
554  BCLog::OutError(Form("BCEngineMCMC::GetMarginalizedHistogram. Index %u out of range.", i));
555  return NULL;
556  }
557  if (j >= fH2Marginalized[i].size()) {
558  BCLog::OutError(Form("BCEngineMCMC::GetMarginalizedHistogram. Index %u out of range.", j));
559  return NULL;
560  }
561 
562  if (fH2Marginalized[i][j])
563  return fH2Marginalized[i][j];
564 
565  if (i < GetNVariables() && j < GetNVariables())
566  BCLog::OutWarning(Form("BCEngineMCMC::GetMarginalizedHistogram : marginal distribution not stored for %s %s vs %s %s",
567  GetVariable(i).GetPrefix().data(), GetVariable(i).GetName().data(),
568  GetVariable(j).GetPrefix().data(), GetVariable(j).GetName().data()));
569  return NULL;
570 }
571 
572 // --------------------------------------------------------
574 {
575  TH1* h = GetMarginalizedHistogram(index);
576 
577  BCH1D bch(h);
578 
579  if (bch.Valid() && index < GetBestFitParameters().size())
580  // set global mode if available
581  bch.SetGlobalMode(GetBestFitParameters()[index]);
582 
583  return bch;
584 }
585 
586 // --------------------------------------------------------
587 BCH2D BCEngineMCMC::GetMarginalized(unsigned i, unsigned j) const
588 {
589  TH2* h = NULL;
590 
593  else
594  h = GetMarginalizedHistogram(i, j);
595 
596  BCH2D bch(h);
597 
598  // set global mode if available
599  if (bch.Valid() && i < GetBestFitParameters().size() && j < GetBestFitParameters().size())
601 
602  return bch;
603 }
604 
605 // --------------------------------------------------------
607 {
608  // serial case is the default
609  static const unsigned defaultChain = 0;
610 
611  if (fChainIndex.empty())
612  return defaultChain;
613 
614  int id = 0;
615 #if THREAD_PARALLELIZATION
616  id = omp_get_thread_num();
617 #endif
618  return fChainIndex.at(id);
619 }
620 
621 // ---------------------------------------------------------
623 {
624  if (fMCMCPhase == kUnsetPhase)
625  return 0;
626  BCLOG_WARNING(Form("global %d min %d max %d", fMCMCNIterationsConvergenceGlobal, int(fMCMCNIterationsPreRunMin), int(fMCMCNIterationsPreRunMax)));
630 }
631 
632 // ---------------------------------------------------------
633 const std::vector<double>& BCEngineMCMC::GetBestFitParameters() const
634 {
636 }
637 
638 // ---------------------------------------------------------
639 const std::vector<double>& BCEngineMCMC::GetBestFitParameterErrors() const
640 {
642  BCLOG_ERROR("Standard errors not available. Run Markov chain first");
643 
645 }
646 
647 // ---------------------------------------------------------
648 const std::vector<double>& BCEngineMCMC::GetLocalModes(bool force_recalculation)
649 {
650  if (fLocalModes.empty() || force_recalculation) {
651  fLocalModes.clear();
652  for (unsigned i = 0; i < GetNVariables(); ++i)
653  if (i < GetNParameters() && GetParameter(i).Fixed())
654  fLocalModes.push_back(GetParameter(i).GetFixedValue());
655  else if (fH1Marginalized[i]) {
656  fLocalModes.push_back(fH1Marginalized[i]->GetBinCenter(fH1Marginalized[i]->GetMaximumBin()));
657  } else {
658  if (i < GetNParameters()) {
659  BCLog::OutError("BCEngineMCMC::GetLocalModes : unfixed parameter is missing marginalized information. returning empty vector.");
660  fLocalModes.clear();
661  break;
662  } else {
663  BCLog::OutWarning("BCEngineMCMC::GetLocalModes : user-defined observable is missing marginalized information. returning only local modes of parameters.");
664  fLocalModes.resize(GetNParameters());
665  break;
666  }
667  }
668  }
669  return fLocalModes;
670 }
671 
672 // --------------------------------------------------------
673 void BCEngineMCMC::SetInitialPositions(const std::vector<double>& x0)
674 {
675  if (x0.size() != GetNParameters()) {
676  BCLOG_ERROR(Form("#initial positions does not match #parameters: %u vs %u", unsigned(x0.size()), GetNParameters()));
677  return;
678  }
679  fMCMCInitialPosition.clear();
680  for (unsigned i = 0; i < GetNChains(); ++i)
681  fMCMCInitialPosition.push_back(x0);
683 }
684 
685 // --------------------------------------------------------
686 void BCEngineMCMC::SetRandomSeed(unsigned seed)
687 {
688  // set main generator
689  fRandom.SetSeed(seed);
690 
691  // call once so return value of GetSeed() fixed
692  fRandom.Rndm();
693 
694  SyncThreadStorage();
695 
696  // type conversion to avoid compiler warnings
697  if (size_t(fMCMCNChains) != fMCMCThreadLocalStorage.size())
698  BCLog::OutError(Form("#chains does not match #(thread local storages): %d vs %u",
699  fMCMCNChains, unsigned(fMCMCThreadLocalStorage.size())));
700 }
701 
702 // --------------------------------------------------------
703 void BCEngineMCMC::InitializeMarkovChainTree(bool replacetree, bool replacefile)
704 {
705  if (replacetree) {
706  delete fMCMCTree;
707  fMCMCTree = NULL;
708  delete fParameterTree;
709  fParameterTree = NULL;
710  }
711  if (replacefile) {
712  if (fMCMCOutputFile)
713  fMCMCOutputFile->Close();
714  delete fMCMCOutputFile;
715  fMCMCOutputFile = NULL;
716  }
717 
718  // don't initialize a 2nd time
720  return;
721 
722  TDirectory* dir = gDirectory;
723 
724  // create file
725  if (!fMCMCOutputFile)
726  fMCMCOutputFile = TFile::Open(fMCMCOutputFilename.c_str(), fMCMCOutputFileOption.c_str());
727  // if failed
728  if (!fMCMCOutputFile) {
729  BCLog::OutError("BCEngineMCMC::InitializeMarkovChainTree: Could not create new file.");
730  WriteMarkovChain(false);
731  return;
732  }
733  // if file mode not writeable
734  if (fMCMCOutputFile && !fMCMCOutputFile->IsWritable()) {
735  BCLog::OutError("BCEngineMCMC::InitializeMarkovChainTree: File must be opened in a writeable mode.");
736  delete fMCMCOutputFile;
737  fMCMCOutputFile = 0;
738  WriteMarkovChain(false);
739  return;
740  }
741 
742  // change to output file (directory)
743  fMCMCOutputFile->cd();
744 
745  if (fMCMCTree)
746  // Add existing MCMC tree to output file
748  else {
749  // or create new MCMC tree (under umbrella of output file)
750  fMCMCTree = new TTree(TString::Format("%s_mcmc", GetSafeName().data()), TString::Format("%s_mcmc", GetSafeName().data()));
751  fMCMCTree->Branch("Chain", &fMCMCTree_Chain, "chain/i");
752  fMCMCTree->Branch("Iteration", &fMCMCTree_State.iteration, "iteration/i");
753  fMCMCTree->Branch("Phase", &fMCMCPhase, "phase/I");
754  fMCMCTree->Branch("LogProbability", &fMCMCTree_State.log_probability, "log_probability/D");
756  for (unsigned j = 0; j < GetNParameters(); ++j) {
757  fMCMCTree->Branch(GetParameter(j).GetSafeName().data(), &fMCMCTree_State.parameters[j], (GetParameter(j).GetSafeName() + "/D").data());
758  fMCMCTree->SetAlias(TString::Format("Parameter%i", j), GetParameter(j).GetSafeName().data());
759  }
761  for (unsigned j = 0; j < GetNObservables(); ++j) {
762  fMCMCTree->Branch(GetObservable(j).GetSafeName().data(), &fMCMCTree_State.observables[j], (GetObservable(j).GetSafeName() + "/D").data());
763  fMCMCTree->SetAlias(TString::Format("Observable%i", j), GetObservable(j).GetSafeName().data());
764  }
765  }
766 
767  if (fParameterTree)
768  // add existing parameter tree to output file
770  else {
771  // or create new parameter tree (under umbrella of output file)
772  fParameterTree = new TTree(TString::Format("%s_parameters", GetSafeName().data()), TString::Format("%s_parameters", GetSafeName().data()));
773  bool p_parameter, p_fill_1d, p_fill_2d, p_fixed;
774  unsigned p_index, p_precision, p_nbins;
775  char p_name[200], p_safename[200], p_latexname[200], p_unitstring[200];
776  double p_lowerlimit, p_upperlimit, p_fixedvalue;
777  fParameterTree->Branch("parameter", &p_parameter, "parameter/O");
778  fParameterTree->Branch("index", &p_index, "index/i");
779  fParameterTree->Branch("name", p_name, "name/C");
780  fParameterTree->Branch("safe_name", p_safename, "safe_name/C");
781  fParameterTree->Branch("latex_name", p_latexname, "latex_name/C");
782  fParameterTree->Branch("unit_string", p_unitstring, "unit_string/C");
783  fParameterTree->Branch("lower_limit", &p_lowerlimit, "lower_limit/D");
784  fParameterTree->Branch("upper_limit", &p_upperlimit, "upper_limit/D");
785  fParameterTree->Branch("precision", &p_precision, "precision/i");
786  fParameterTree->Branch("nbins", &p_nbins, "nbins/i");
787  fParameterTree->Branch("fill_1d", &p_fill_1d, "fill_1d/O");
788  fParameterTree->Branch("fill_2d", &p_fill_2d, "fill_2d/O");
789  fParameterTree->Branch("fixed", &p_fixed, "fixed/O");
790  fParameterTree->Branch("fixed_value", &p_fixedvalue, "fixed_value/D");
791  for (unsigned i = 0; i < GetNVariables(); ++i) {
792  p_parameter = (i < GetNParameters());
793  p_index = (p_parameter) ? i : i - GetNParameters();
794  strcpy(p_name, GetVariable(i).GetName().data());
795  strcpy(p_safename, GetVariable(i).GetSafeName().data());
796  strcpy(p_latexname, GetVariable(i).GetLatexName().data());
797  strcpy(p_unitstring, GetVariable(i).GetUnitString().data());
798  p_lowerlimit = GetVariable(i).GetLowerLimit();
799  p_upperlimit = GetVariable(i).GetUpperLimit();
800  p_precision = GetVariable(i).GetPrecision();
801  p_nbins = GetVariable(i).GetNbins();
802  p_fill_1d = GetVariable(i).FillH1();
803  p_fill_2d = GetVariable(i).FillH2();
804  p_fixed = p_parameter && GetParameter(i).Fixed();
805  p_fixedvalue = (p_parameter) ? GetParameter(i).GetFixedValue() : 0;
806  fParameterTree->Fill();
807  }
808  fParameterTree->AutoSave("SaveSelf");
809  // fParameterTree->ResetBranchAddresses();
810  }
811 
812  // return to old directory
813  gDirectory = dir;
814 }
815 
816 // --------------------------------------------------------
818 {
819  if (!fParameterTree)
820  return;
821 
822  unsigned nchains = GetNChains();
823  std::vector<double> scale(GetNChains(), 0);
824  std::vector<double> eff(GetNChains(), 0);
825 
826  // check for branch existences
827  TBranch* b_nchains = fParameterTree->GetBranch("nchains");
828  TBranch* b_scale = fParameterTree->GetBranch("scale");
829 
830  // if nchains branch doesn't exist, create it
831  if (b_nchains == 0)
832  b_nchains = fParameterTree->Branch("nchains", &nchains, "nchains/i");
833  // else set 0, so as not to fill
834  else
835  b_nchains = 0;
836 
837  // if scale branch doesn't exist, create it
838  if (b_scale == 0)
839  b_scale = fParameterTree->Branch("scale", &(scale.front()), TString::Format("scale[%d]/D", GetNChains()));
840  // else set 0, so as not to fill
841  else
842  b_scale = 0;
843 
844  // create next effiency branch
845  unsigned i = 0;
846  while (fParameterTree->GetBranch(TString::Format("efficiency_%d", i)))
847  ++i;
848  TBranch* b_eff = fParameterTree->Branch(TString::Format("efficiency_%d", i), &(eff.front()), TString::Format("efficiency_%d[%d]/D", i, GetNChains()));
849 
850  for (unsigned n = 0; n < fParameterTree->GetEntries(); ++n) {
851  if (b_nchains)
852  b_nchains->Fill();
853 
854  for (unsigned j = 0; j < nchains; ++j) {
857  eff[j] = (n < GetNParameters()) ? fMCMCStatistics[j].efficiency[n] : -1;
858  else if (!fMCMCStatistics[j].efficiency.empty())
859  eff[j] = fMCMCStatistics[j].efficiency.front();
860  else
861  eff[j] = -1;
862  }
863 
864  if (b_scale)
865  b_scale->Fill();
866 
867  b_eff->Fill();
868  }
869  fParameterTree->AutoSave("SaveSelf");
870  // fParameterTree->ResetBranchAddresses();
871 }
872 
873 // --------------------------------------------------------
874 bool BCEngineMCMC::ValidMCMCTree(TTree* tree, bool checkObservables) const
875 {
876  if (!tree)
877  return false;
878 
879  if (!(tree->GetBranch("Chain")))
880  return false;
881 
882  if (!(tree->GetBranch("Phase")))
883  return false;
884 
885  unsigned nvar = checkObservables ? GetNObservables() : GetNParameters();
886  for (unsigned i = 0; i < nvar; ++i)
887  if (!(tree->GetBranch(GetVariable(i).GetSafeName().data())))
888  return false;
889 
890  return true;
891 }
892 
893 // --------------------------------------------------------
894 bool BCEngineMCMC::ValidParameterTree(TTree* tree) const
895 {
896  if (!tree)
897  return false;
898 
899  if (!(tree->GetBranch("parameter")))
900  return false;
901 
902  if (!(tree->GetBranch("index")))
903  return false;
904 
905  if (!(tree->GetBranch("name")))
906  return false;
907 
908  if (!(tree->GetBranch("lower_limit")))
909  return false;
910 
911  if (!(tree->GetBranch("upper_limit")))
912  return false;
913 
914  return true;
915 }
916 
917 // --------------------------------------------------------
918 void BCEngineMCMC::LoadParametersFromTree(TTree* partree, bool loadObservables)
919 {
920  // absolutely necessary branches
921  if (!partree->GetBranch("parameter"))
922  throw std::runtime_error("BCEngineMCMC::LoadParametersFromTree: tree missing parameter branch");
923  if (!partree->GetBranch("index"))
924  throw std::runtime_error("BCEngineMCMC::LoadParametersFromTree: tree missing index branch");
925  if (!partree->GetBranch("name"))
926  throw std::runtime_error("BCEngineMCMC::LoadParametersFromTree: tree missing name branch");
927  if (!partree->GetBranch("lower_limit"))
928  throw std::runtime_error("BCEngineMCMC::LoadParametersFromTree: tree missing lower_limit branch");
929  if (!partree->GetBranch("upper_limit"))
930  throw std::runtime_error("BCEngineMCMC::LoadParametersFromTree: tree missing upper_limit branch");
931 
932  partree->ResetBranchAddresses();
933 
934  char p_name[200];
935  double p_lowerlimit;
936  double p_upperlimit;
937 
938  partree->SetBranchAddress("name", p_name);
939  partree->SetBranchAddress("lower_limit", &p_lowerlimit);
940  partree->SetBranchAddress("upper_limit", &p_upperlimit);
941 
942  // not entirely necessary branches
943  char p_latexname[200] = "";
944  unsigned p_precision = 6;
945  unsigned p_nbins = 100;
946  bool p_fill_1d = true;
947  bool p_fill_2d = true;
948  bool p_fixed = false;
949  double p_fixedvalue = 0;
950 
951  if (partree->GetBranch("latex_name"))
952  partree->SetBranchAddress("latex_name", p_latexname);
953  if (partree->GetBranch("precision"))
954  partree->SetBranchAddress("precision", &p_precision);
955  if (partree->GetBranch("nbins"))
956  partree->SetBranchAddress("nbins", &p_nbins);
957  if (partree->GetBranch("fill_1d"))
958  partree->SetBranchAddress("fill_1d", &p_fill_1d);
959  if (partree->GetBranch("fill_2d"))
960  partree->SetBranchAddress("fill_2d", &p_fill_2d);
961  if (partree->GetBranch("fixed"))
962  partree->SetBranchAddress("fixed", &p_fixed);
963  if (partree->GetBranch("fixed_value"))
964  partree->SetBranchAddress("fixed_value", &p_fixedvalue);
965 
966  partree->BuildIndex("parameter", "index");
967 
968  // load parameters
969  // loop over entries with "parameter" branch = true
970  for (unsigned i = 0; partree->GetEntryNumberWithIndex(1, i) >= 0; ++i) {
971  partree->GetEntryWithIndex(1, i);
972  BCParameter Par(p_name, p_lowerlimit, p_upperlimit, p_latexname);
973  if (p_fixed)
974  Par.Fix(p_fixedvalue);
975  Par.SetPrecision(p_precision);
976  Par.FillHistograms(p_fill_1d, p_fill_2d);
977  Par.SetNbins(p_nbins);
978  AddParameter(Par);
979  }
980 
981  // load user-defined observables
982  if (loadObservables) {
984  // loop over entries with "parameter" branch = false
985  for (unsigned i = 0; partree->GetEntryNumberWithIndex(0, i) >= 0; ++i) {
986  partree->GetEntryWithIndex(0, i);
987  BCObservable Obs(p_name, p_lowerlimit, p_upperlimit, p_latexname);
988  Obs.SetPrecision(p_precision);
989  Obs.FillHistograms(p_fill_1d, p_fill_2d);
990  Obs.SetNbins(p_nbins);
991  AddObservable(Obs);
992  }
993  }
994 
995  partree->ResetBranchAddresses();
996 }
997 
998 // --------------------------------------------------------
1000 {
1001  if (partree.GetEntries() < 1)
1002  throw std::runtime_error("BCEngineMCMC::LoadMCMCParameters: tree is empty");
1003  if (!partree.GetBranch("parameter"))
1004  throw std::runtime_error("BCEngineMCMC::LoadMCMCParameters: tree missing parameter branch");
1005  if (!partree.GetBranch("index"))
1006  throw std::runtime_error("BCEngineMCMC::LoadMCMCParameters: tree missing index branch");
1007  if (!partree.GetBranch("nchains"))
1008  throw std::runtime_error("BCEngineMCMC::LoadMCMCParameters: tree missing nchains branch");
1009  if (!partree.GetBranch("efficiency_0"))
1010  throw std::runtime_error("BCEngineMCMC::LoadMCMCParameters: tree missing efficiency_0 branch");
1011  if (!partree.GetBranch("scale"))
1012  throw std::runtime_error("BCEngineMCMC::LoadMCMCParameters: tree missing scale branch");
1013 
1014  partree.ResetBranchAddresses();
1015 
1016  // set number of chains
1017  unsigned p_nchains;
1018  partree.SetBranchAddress("nchains", &p_nchains);
1019  partree.GetEntry(0);
1020  if (p_nchains == 0)
1021  throw std::runtime_error("BCEngineMCMC::LoadMCMCParameters: no chains in branch");
1022  SetNChains(p_nchains);
1023 
1024  std::vector<double> p_efficiency(GetNChains(), -1);
1025  std::vector<double> p_scale(GetNChains(), -1);
1026 
1027  partree.SetBranchAddress("efficiency_0", &p_efficiency[0]);
1028  partree.SetBranchAddress("scale", &p_scale[0]);
1029 
1030  std::vector<std::vector<double> > scales(GetNChains(), std::vector<double>(GetNParameters(), -1));
1031  std::vector<std::vector<double> > efficiencies(GetNChains(), std::vector<double>(GetNParameters(), -1));
1032 
1033  partree.BuildIndex("parameter", "index");
1034 
1035  for (unsigned p = 0; p < GetNParameters(); ++p) {
1036  partree.GetEntryWithIndex(1, p);
1037  for (unsigned c = 0; c < GetNChains(); ++c) {
1038  scales[c][p] = p_scale[c];
1039  efficiencies[c][p] = p_efficiency[c];
1040  }
1041  }
1042 
1043  for (unsigned c = 0; c < GetNChains(); ++c)
1044  for (unsigned p = 0; p < GetNParameters(); ++p)
1045  if (scales[c][p] < 0 || efficiencies[c][p] == -1)
1046  throw std::runtime_error("BCEngineMCMC::LoadMCMCParameters: unset scale or efficiency.");
1047 
1049 
1050  // if multivariate proposal, then all parameters have same efficiency in each chain
1051  // (even fixed ones)
1052  if (GetNParameters() > 1) {
1053  SetProposeMultivariate(true);
1054  for (unsigned c = 0; c < GetNChains() and GetProposeMultivariate(); ++c)
1055  for (unsigned p = 1; p < GetNParameters() and GetProposeMultivariate(); ++p)
1056  if (efficiencies[c][p] != efficiencies[c][p - 1])
1057  SetProposeMultivariate(false);
1058  }
1059  // if only one parameter, leave to what user has set.
1060 
1061  partree.ResetBranchAddresses();
1062 }
1063 
1064 // --------------------------------------------------------
1065 bool BCEngineMCMC::ParameterTreeMatchesModel(TTree* partree, bool checkObservables)
1066 {
1067  bool p_fixed;
1068  char p_name[200];
1069  double p_lowerlimit, p_upperlimit, p_fixedvalue;
1070  partree->SetBranchAddress("name", p_name);
1071  partree->SetBranchAddress("lower_limit", &p_lowerlimit);
1072  partree->SetBranchAddress("upper_limit", &p_upperlimit);
1073  partree->BuildIndex("parameter", "index");
1074 
1075  bool has_fixed = true;
1076  if (partree->GetBranch("fixed"))
1077  partree->SetBranchAddress("fixed", &p_fixed);
1078  else
1079  has_fixed = false;
1080 
1081  bool has_fixed_value = true;
1082  if (partree->GetBranch("fixed_value"))
1083  partree->SetBranchAddress("fixed_value", &p_fixedvalue);
1084  else
1085  has_fixed_value = false;
1086 
1087  // check parameters
1088  for (unsigned i = 0; i < GetNParameters(); ++i) {
1089  if (partree->GetEntryNumberWithIndex(1, i) < 0) {
1090  BCLog::OutError("BCEngineMCMC::ParameterTreeMatchesModel : Parameter tree contains too few entries.");
1091  return false;
1092  }
1093  partree->GetEntryWithIndex(1, i);
1094  if (!GetParameter(i).IsNamed(p_name)) {
1095  BCLog::OutError(Form("BCEngineMCMC::ParameterTreeMatchesModel : Parameter[%d]'s names do not match.", i));
1096  return false;
1097  }
1098  if (GetParameter(i).GetLowerLimit() != p_lowerlimit)
1099  BCLog::OutDetail(Form("BCEngineMCMC::ParameterTreeMatchesModel : Lower limit of parameter \"%s\" does not match.", p_name));
1100  if (GetParameter(i).GetUpperLimit() != p_upperlimit)
1101  BCLog::OutDetail(Form("BCEngineMCMC::ParameterTreeMatchesModel : Upper limit of parameter \"%s\" does not match.", p_name));
1102  if (has_fixed && GetParameter(i).Fixed() != p_fixed) {
1103  if (p_fixed) {
1104  BCLog::OutDetail(Form("BCEngineMCMC::ParameterTreeMatchesModel : Fixed status of parameter \"%s\" does not match. Fixing it to %f.", p_name, p_fixedvalue));
1105  GetParameter(i).Fix(p_fixedvalue);
1106  } else {
1107  BCLog::OutDetail(Form("BCEngineMCMC::ParameterTreeMatchesModel : Fixed status of parameter \"%s\" does not match. Unfixing it.", p_name));
1108  GetParameter(i).Unfix();
1109  }
1110  }
1111  if (has_fixed && GetParameter(i).Fixed() && has_fixed_value && GetParameter(i).GetFixedValue() != p_fixedvalue) {
1112  BCLog::OutDetail(Form("BCEngineMCMC::ParameterTreeMatchesModel : Fixed value of parameter \"%s\" does not match. Updating it.", p_name));
1113  GetParameter(i).Fix(p_fixedvalue);
1114  }
1115  }
1116  if (!checkObservables)
1117  return true;
1118  // check observables
1119  for (unsigned i = 0; i < GetNObservables(); ++i) {
1120  if (partree->GetEntryNumberWithIndex(0, i) < 0) {
1121  BCLog::OutError("BCEngineMCMC::ParameterTreeMatchesModel : Parameters tree contains too few entries.");
1122  return false;
1123  }
1124  partree->GetEntryWithIndex(0, i);
1125  if (!GetObservable(i).IsNamed(p_name)) {
1126  BCLog::OutError(Form("BCEngineMCMC::ParameterTreeMatchesModel : Observable[%d]'s names do not match.", i));
1127  return false;
1128  }
1129  if (GetObservable(i).GetLowerLimit() != p_lowerlimit)
1130  BCLog::OutWarning(Form("BCEngineMCMC::ParameterTreeMatchesModel : Lower limit of observable \"%s\" does not match.", p_name));
1131  if (GetObservable(i).GetUpperLimit() != p_upperlimit)
1132  BCLog::OutWarning(Form("BCEngineMCMC::ParameterTreeMatchesModel : Upper limit of observable \"%s\" does not match.", p_name));
1133  }
1134  return true;
1135 }
1136 
1137 // --------------------------------------------------------
1138 void BCEngineMCMC::LoadMCMC(const std::string& filename, std::string mcmcTreeName, std::string parameterTreeName, bool loadObservables)
1139 {
1140  // save current directory
1141  TDirectory* dir = gDirectory;
1142 
1143  TFile* inputfile = TFile::Open(filename.data(), "READ");
1144  if (!inputfile || inputfile->IsZombie()) {
1145  gDirectory = dir;
1146  throw std::runtime_error(Form("BCEngineMCMC::LoadMCMC: Could not open file %s.", filename.data()));
1147  }
1148 
1149  if (mcmcTreeName.empty() && parameterTreeName.empty()) {
1150  // look through file for trees named according to BAT scheme
1151  TList* LoK = inputfile->GetListOfKeys();
1152  std::vector<std::string> mcmc_names;
1153  std::vector<std::string> parameter_names;
1154  for (int i = 0; i < LoK->GetEntries(); ++i) {
1155  TKey* k = (TKey*)(LoK->At(i));
1156  if (strcmp(k->GetClassName(), "TTree") != 0)
1157  continue;
1158  std::string treeName(k->GetName());
1159  if (treeName.find_last_of("_") == std::string::npos)
1160  continue;
1161  if (treeName.substr(treeName.find_last_of("_")) == "_mcmc")
1162  mcmc_names.push_back(treeName.substr(0, treeName.find_last_of("_")));
1163  else if (treeName.substr(treeName.find_last_of("_")) == "_parameters")
1164  parameter_names.push_back(treeName.substr(0, treeName.find_last_of("_")));
1165  }
1166 
1167  std::vector<std::string> model_names;
1168  for (unsigned i = 0; i < mcmc_names.size(); ++i)
1169  for (unsigned j = 0; j < parameter_names.size(); ++j)
1170  if (mcmc_names[i] == parameter_names[j])
1171  model_names.push_back(mcmc_names[i]);
1172 
1173  if (model_names.empty())
1174  throw std::runtime_error(Form("BCEngineMCMC::LoadMCMC : %s contains no matching MCMC and Parameter trees.", filename.data()));
1175 
1176  if (model_names.size() > 1) {
1177  std::string model_names_string = model_names[0];
1178  for (unsigned i = 0; i < model_names.size(); ++i)
1179  model_names_string += ", " + model_names[i];
1180  throw std::runtime_error(Form("BCEngineMCMC::LoadMCMC : %s contains more than one model, please select one by providing a model name: %s", filename.data(), model_names_string.data()));
1181  }
1182 
1183  mcmcTreeName = model_names[0] + "_mcmc";
1184  parameterTreeName = model_names[0] + "_parameters";
1185 
1186  if (fName.empty())
1187  SetName(model_names[0]);
1188  } else if (fName.empty()) {
1189  // check mcmcTreeName and parameterTreeName for default BAT name scheme [modelname]_mcmc/parameters:
1190  if (mcmcTreeName.find_last_of("_") != std::string::npos && mcmcTreeName.substr(mcmcTreeName.find_last_of("_")) == "_mcmc"
1191  && parameterTreeName.find_last_of("_") != std::string::npos && parameterTreeName.substr(parameterTreeName.find_last_of("_")) == "_parameters") {
1192  fName = mcmcTreeName.substr(0, mcmcTreeName.find_last_of("_"));
1193  }
1194  }
1195 
1196  // set tree names if empty
1197  if (mcmcTreeName.empty())
1198  mcmcTreeName = Form("%s_mcmc", GetSafeName().data());
1199  if (parameterTreeName.empty()) // default parameter tree name
1200  parameterTreeName = Form("%s_parameters", GetSafeName().data());
1201 
1202  TTree* mcmcTree = NULL;
1203  inputfile->GetObject(mcmcTreeName.data(), mcmcTree);
1204  if (!mcmcTree)
1205  throw std::runtime_error(Form("BCEngineMCMC::LoadMCMC : %s does not contain a tree named %s", filename.data(), mcmcTreeName.data()));
1206 
1207 
1208  TTree* parTree = NULL;
1209  inputfile->GetObject(parameterTreeName.data(), parTree);
1210  if (!parTree)
1211  throw std::runtime_error(Form("BCEngineMCMC::LoadMCMC : %s does not contain a tree named %s", filename.data(), parameterTreeName.data()));
1212 
1213  gDirectory = dir;
1214  LoadMCMC(mcmcTree, parTree, loadObservables);
1215 }
1216 
1217 // --------------------------------------------------------
1218 void BCEngineMCMC::LoadMCMC(TTree* mcmcTree, TTree* parTree, bool loadObservables)
1219 {
1220  fMCMCTreeLoaded = false;
1221  fMCMCTreeReuseObservables = loadObservables;
1222 
1223  if (!mcmcTree || !parTree)
1224  throw std::runtime_error("BCEngineMCMC::LoadMCMC : empty trees provided");
1225 
1226  // load parameter tree
1227  if (!ValidParameterTree(parTree))
1228  throw std::runtime_error("BCEngineMCMC::LoadMCMC : invalid parameter tree");
1229 
1230  delete fParameterTree;
1231  fParameterTree = parTree;
1232 
1233  // if parameters is empty
1234  if (GetNParameters() == 0)
1236  // else check parameter tree
1238  throw std::runtime_error("BCEngineMCMC::LoadMCMC : Parameter tree does not match model.");
1239 
1241 
1242  // check mcmc tree
1243  if (!ValidMCMCTree(mcmcTree, fMCMCTreeReuseObservables))
1244  throw std::runtime_error("BCEngineMCMC::LoadMCMC : invalid MCMC tree");
1245 
1246  delete fMCMCTree;
1247  fMCMCTree = mcmcTree;
1248 
1249  fMCMCTreeLoaded = true;
1250 }
1251 
1252 // --------------------------------------------------------
1253 void BCEngineMCMC::Remarginalize(bool autorange)
1254 {
1255  // Check if tree is valid
1257  return;
1258 
1259  // link chain and phase
1260  fMCMCTree->SetBranchAddress("Chain", &fMCMCTree_Chain);
1261  fMCMCTree->SetBranchAddress("Phase", &fMCMCPhase);
1262 
1263  // link log(probability) if available
1264  if (fMCMCTree->GetBranch("LogProbability"))
1265  fMCMCTree->SetBranchAddress("LogProbability", &fMCMCTree_State.log_probability);
1266 
1267  // link iteration if available
1268  if (fMCMCTree->GetBranch("Iteration"))
1269  fMCMCTree->SetBranchAddress("Iteration", &fMCMCTree_State.iteration);
1270  else
1272 
1273  // link log(likelihood) if available
1274  if (fMCMCTree->GetBranch("LogLikelihood"))
1275  fMCMCTree->SetBranchAddress("LogLikelihood", &fMCMCTree_State.log_likelihood);
1276  else
1277  fMCMCTree_State.log_likelihood = -std::numeric_limits<double>::infinity();
1278 
1279  // link log(prior) if available
1280  if (fMCMCTree->GetBranch("LogPrior"))
1281  fMCMCTree->SetBranchAddress("LogPrior", &fMCMCTree_State.log_prior);
1282  else
1283  fMCMCTree_State.log_prior = -std::numeric_limits<double>::infinity();
1284 
1285  // link parameters
1287  for (unsigned i = 0; i < GetNParameters(); ++i)
1288  fMCMCTree->SetBranchAddress(GetParameter(i).GetSafeName().data(), &fMCMCTree_State.parameters[i]);
1289 
1290  // link observables
1293  for (unsigned i = 0; i < GetNObservables(); ++i)
1294  fMCMCTree->SetBranchAddress(GetObservable(i).GetSafeName().data(), &fMCMCTree_State.observables[i]);
1295  }
1296 
1297  // find out how many chains used to generate tree
1298  // (this presumes that chains were run in blocks of one iteration at a time!)
1299  unsigned nchains = 0;
1300  for (int n = 0; n < fMCMCTree->GetEntries(); ++n) {
1301  fMCMCTree->GetEntry(n);
1302  if (nchains > 0 && fMCMCTree_Chain == 0)
1303  break;
1304  if (fMCMCTree_Chain + 1 > nchains)
1305  nchains = fMCMCTree_Chain + 1;
1306  }
1307  SetNChains(nchains);
1308 
1309  MCMCInitialize();
1310 
1311  if (autorange) {
1312  std::vector<double> XMin;
1313  std::vector<double> XMax;
1317  } else {
1318  // find min and max
1319  XMin.assign(GetNVariables(), +std::numeric_limits<double>::infinity());
1320  XMax.assign(GetNVariables(), -std::numeric_limits<double>::infinity());
1321  for (int n = 0; n < fMCMCTree->GetEntries(); ++n) {
1322  fMCMCTree->GetEntry(n);
1323 
1324  if (fMCMCPhase <= 0)
1325  continue;
1326 
1327  for (unsigned i = 0; i < fMCMCTree_State.parameters.size(); ++i) {
1328  XMin[i] = std::min(XMin[i], fMCMCTree_State.parameters[i]);
1329  XMax[i] = std::max(XMax[i], fMCMCTree_State.parameters[i]);
1330  }
1332  for (unsigned i = 0; i < fMCMCTree_State.observables.size(); ++i) {
1333  XMin[GetNParameters() + i] = std::min(XMin[GetNParameters() + i], fMCMCTree_State.observables[i]);
1334  XMax[GetNParameters() + i] = std::max(XMax[GetNParameters() + i], fMCMCTree_State.observables[i]);
1335  }
1336  } else {
1339  for (unsigned i = 0; i < GetNObservables(); ++i) {
1340  XMin[GetNParameters() + i] = std::min(XMin[GetNParameters() + i], fObservables[i].Value());
1341  XMax[GetNParameters() + i] = std::max(XMax[GetNParameters() + i], fObservables[i].Value());
1342  }
1343  }
1344  }
1345  }
1346  if (!XMin.empty() && !XMax.empty()) {
1347  // store mins and maxes, and change
1348  std::vector<double> xmin;
1349  std::vector<double> xmax;
1350  for (unsigned i = 0; i < GetNVariables(); ++i) {
1351  xmin.push_back(GetVariable(i).GetLowerLimit());
1352  xmax.push_back(GetVariable(i).GetUpperLimit());
1353  GetVariable(i).SetLimits(XMin[i], XMax[i]);
1354  }
1355  CreateHistograms();
1356  // restore mins and maxes
1357  for (unsigned i = 0; i < GetNVariables(); ++i)
1358  GetVariable(i).SetLimits(xmin[i], xmax[i]);
1359  }
1360  }
1361 
1364 
1365  fMCMCTree_State.log_probability = -std::numeric_limits<double>::infinity();
1366 
1367  for (unsigned n = 0; n < fMCMCTree->GetEntries(); ++n) {
1368  fMCMCTree->GetEntry(n);
1369 
1371 
1373 
1374  // calculate observables if requested
1377  for (unsigned i = 0; i < GetNObservables(); ++i)
1378  fMCMCStates[fMCMCTree_Chain].observables[i] = GetObservable(i).Value();
1379  }
1380 
1381  // store iteration of convergance
1382  if (fMCMCNIterationsConvergenceGlobal < 0 && fMCMCPhase > 0) {
1383  for (unsigned c = 0; c < fMCMCNChains; ++c)
1384  fMCMCStatistics[c].Reset(false, true);
1386  }
1387 
1389 
1390  if (fMCMCPhase <= 0)
1391  continue;
1392 
1393  MCMCCurrentPointInterface(fMCMCStates[fMCMCTree_Chain].parameters, fMCMCTree_Chain, true);
1394 
1395  // This should be changed:
1396  // MCMCUserIterationInterface() should be deleted
1397  // and the whole block should be replaced with
1398  // InChainFillHistograms(fMCMCStates[fMCMCTree_Chain])
1399  if (fMCMCTree_Chain == fMCMCNChains - 1) {
1402  }
1403  }
1404 
1405  // set mult. var. proposal function covariance to those of main run if empty
1410  }
1411 
1412  // combine statistics
1413  for (unsigned c = 0; c < fMCMCNChains; ++c)
1415 
1416 }
1417 
1418 // --------------------------------------------------------
1419 void BCEngineMCMC::PrepareToContinueMarginalization(const std::string& filename, const std::string& mcmcTreeName, const std::string& parameterTreeName, bool loadObservables, bool autorange)
1420 {
1421  LoadMCMC(filename, mcmcTreeName, parameterTreeName, loadObservables);
1422  Remarginalize(autorange);
1423  // delete trees
1424  delete fMCMCTree;
1425  fMCMCTree = NULL;
1426  delete fParameterTree;
1427  fParameterTree = NULL;
1428 }
1429 
1430 // --------------------------------------------------------
1432 {
1434  return false;
1435 
1436  // Update covariance matricies
1437  unsigned I = 0;
1438  for (unsigned i = 0; i < GetNParameters(); ++i) {
1439  if (GetParameter(i).Fixed())
1440  continue;
1441  unsigned J = I;
1442  for (unsigned j = i; j < GetNParameters(); ++j) {
1443  if (GetParameter(j).Fixed())
1444  continue;
1445  for (unsigned c = 0; c < fMCMCNChains; ++c) {
1446  fMultivariateProposalFunctionCovariance[c][I][J] *= (1 - a);
1447  fMultivariateProposalFunctionCovariance[c][I][J] += a * fMCMCStatistics[c].covariance[i][j];
1449  }
1450  ++J;
1451  }
1452  ++I;
1453  }
1454 
1455  return true;
1456 }
1457 
1458 // --------------------------------------------------------
1460 {
1461  // a = (1+t)^(-lambda)
1463 
1465  return false;
1466 
1468  return true;
1469 }
1470 // --------------------------------------------------------
1472 {
1474  throw std::runtime_error("BCEngineMCMC::CalculateCholeskyDecompositions: size of fMultivariateProposalFunctionCovariance does not match number of chains.");
1475 
1476  // clear decomps
1478 
1479  // create decomposer
1480  TDecompChol CholeskyDecomposer;
1481  // Update cholesky decompositions
1482  for (unsigned c = 0; c < fMCMCNChains; ++c) {
1483 
1484  // try cholesky decomposition
1485  CholeskyDecomposer.SetMatrix(fMultivariateProposalFunctionCovariance[c]*fMCMCProposalFunctionScaleFactor[c][0]);
1486  if (CholeskyDecomposer.Decompose())
1487  fMultivariateProposalFunctionCholeskyDecomposition[c].Transpose(CholeskyDecomposer.GetU());
1488 
1489  else {
1490  // try with covariance + epsilon
1491  BCLog::OutDetail(Form("BCEngineMCMC::CalculateCholeskyDecompositions : chain %u Cholesky decomposition failed! Adding epsilon*I and trying again.", c));
1493  for (int i = 0; i < U.GetNrows(); ++i)
1494  U[i][i] *= (1 + fMultivariateEpsilon);
1495  CholeskyDecomposer.SetMatrix(U);
1496  if (CholeskyDecomposer.Decompose())
1497  fMultivariateProposalFunctionCholeskyDecomposition[c].Transpose(CholeskyDecomposer.GetU());
1498 
1499  else {
1500  // diagonalize
1501  BCLog::OutDetail(Form("BCEngineMCMC::CalculateCholeskyDecompositions : chain %u Cholesky decomposition failed! Setting off-diagonal elements of covariance to zero", c));
1503  for (int i = 0; i < fMultivariateProposalFunctionCholeskyDecomposition[c].GetNrows(); ++i)
1504  for (int j = 0; j < fMultivariateProposalFunctionCholeskyDecomposition[c].GetNcols(); ++j)
1505  if (i != j)
1506  U[i][j] = 0;
1507  CholeskyDecomposer.SetMatrix(U);
1508  if (CholeskyDecomposer.Decompose())
1509  fMultivariateProposalFunctionCholeskyDecomposition[c].Transpose(CholeskyDecomposer.GetU());
1510  else {
1511  throw std::runtime_error(Form("BCEngineMCMC::CalculateCholeskyDecompositions : chain %u Cholesky decomposition failed! No remedies!", c));
1512  }
1513  }
1514  }
1515  }
1516 }
1517 
1518 // --------------------------------------------------------
1519 double BCEngineMCMC::ProposalFunction(unsigned ichain, unsigned iparameter)
1520 {
1521  // multiply by 1 (dof <=0, Gauss) or a random variate that scales the Gaussian to a Student's t with dof degrees of freedom
1522  const double scale = fMCMCThreadLocalStorage[ichain].scale(fMCMCProposalFunctionDof);
1523 
1524  return scale * fMCMCThreadLocalStorage[ichain].rng->Gaus(0, fMCMCProposalFunctionScaleFactor[ichain][iparameter]);
1525 }
1526 
1527 // --------------------------------------------------------
1528 bool BCEngineMCMC::GetProposalPointMetropolis(unsigned chain, std::vector<double>& x)
1529 {
1530  // copy the current point into the new
1531  x = fMCMCStates[chain].parameters;
1532 
1533  // generate N-Free N(0,1) random values
1534  TVectorD& y = fMCMCThreadLocalStorage[chain].yLocal;
1535  for (int i = 0; i < y.GetNrows(); ++i)
1536  y[i] = fMCMCThreadLocalStorage[chain].rng->Gaus(0, 1);
1537 
1538  // multiply by Cholesky decomposition
1540 
1541  // multiply by 1 (dof <=0, Gauss) or a random variate that scales the Gaussian to a Student's t with dof degrees of freedom
1542  const double scale = fMCMCThreadLocalStorage[chain].scale(fMCMCProposalFunctionDof);
1543 
1544  // add values into x
1545  int I = 0;
1546  for (unsigned i = 0; i < GetNParameters() && I < y.GetNrows(); ++i)
1547  if (!GetParameter(i).Fixed()) {
1548  x[i] += y[I] * scale;
1549  ++I;
1550  }
1551 
1552  // return whether point is within limits, ignoring fixed parameters
1553  return GetParameters().IsWithinLimits(x);
1554 }
1555 
1556 // --------------------------------------------------------
1557 bool BCEngineMCMC::GetProposalPointMetropolis(unsigned ichain, unsigned ipar, std::vector<double>& x)
1558 {
1559  // copy the current point into the new
1560  x = fMCMCStates[ichain].parameters;
1561 
1562  // check if parameter is fixed
1563  if (GetParameter(ipar).Fixed()) {
1564  x[ipar] = GetParameter(ipar).GetFixedValue();
1565  return true; // assume that value is inside allowed region
1566  }
1567 
1568  // get unscaled random point in the dimension of the chosen
1569  // parameter. this point might not be in the correct volume.
1570  double proposal = ProposalFunction(ichain, ipar);
1571 
1572  // modify the parameter under study
1573  x[ipar] += proposal * GetParameter(ipar).GetRangeWidth();
1574 
1575  // check if the point is in the correct volume.
1576  return GetParameter(ipar).IsWithinLimits(x[ipar]);
1577 }
1578 
1579 // --------------------------------------------------------
1580 bool BCEngineMCMC::AcceptOrRejectPoint(unsigned chain, unsigned parameter)
1581 {
1582  // retrieve current probability
1583  double p0 = fMCMCStates[chain].log_probability;
1584  if (!std::isfinite(p0)) p0 = -std::numeric_limits<double>::max();
1585  // calculate proposed probability
1586  const double p1 = LogEval(fMCMCThreadLocalStorage[chain].parameters);
1587 
1588  // if the new point is more probable, keep it; or else throw dice
1589  if (std::isfinite(p1) && (p1 >= p0 || log(fMCMCThreadLocalStorage[chain].rng->Rndm()) < (p1 - p0))) {
1590  // accept point
1591  fMCMCStates[chain] = fMCMCThreadLocalStorage[chain];
1592  // increase efficiency
1593  fMCMCStatistics[chain].efficiency[parameter] += (1. - fMCMCStatistics[chain].efficiency[parameter]) / (fMCMCStatistics[chain].n_samples_efficiency + 1.);
1594  // execute user code and return
1595  MCMCCurrentPointInterface(fMCMCStates[chain].parameters, chain, true);
1596  return true;
1597  }
1598 
1599  // else decrease efficiency
1600  fMCMCStatistics[chain].efficiency[parameter] *= 1.*fMCMCStatistics[chain].n_samples_efficiency / (fMCMCStatistics[chain].n_samples_efficiency + 1.);
1601 
1602  // if log(likelihood) of proposed point was not a finite number
1603  if (!std::isfinite(p1)) {
1605  BCLog::OutDebug(Form("log(probability) evaluated to nan or inf in chain %i while at ", chain));
1606  PrintParameters(fMCMCThreadLocalStorage[chain].parameters, BCLog::OutDebug);
1607  } else
1608  BCLog::OutDebug(Form("log(probability) evaluated to nan or inf in chain %i while varying parameter %s to %.3e", chain, GetParameter(parameter).GetName().data(), fMCMCThreadLocalStorage[chain].parameters[parameter]));
1609  }
1610 
1611  // execute user code and return
1612  MCMCCurrentPointInterface(fMCMCThreadLocalStorage[chain].parameters, chain, false);
1613  return false;
1614 }
1615 
1616 // --------------------------------------------------------
1617 bool BCEngineMCMC::GetNewPointMetropolis(unsigned chain, unsigned parameter)
1618 {
1619  // increase counter
1620  ++fMCMCStates[chain].iteration;
1621 
1622  // get proposal point
1623  if (GetProposalPointMetropolis(chain, parameter, fMCMCThreadLocalStorage[chain].parameters))
1624  return AcceptOrRejectPoint(chain, parameter);
1625 
1626  // execute user code and return
1627  MCMCCurrentPointInterface(fMCMCThreadLocalStorage[chain].parameters, chain, false);
1628  return false;
1629 }
1630 
1631 // --------------------------------------------------------
1633 {
1634  // increase counter
1635  ++fMCMCStates[chain].iteration;
1636 
1637  // get proposal point
1638  if (GetProposalPointMetropolis(chain, fMCMCThreadLocalStorage[chain].parameters))
1639  return AcceptOrRejectPoint(chain, 0);
1640 
1641  // execute user code and return
1642  MCMCCurrentPointInterface(fMCMCThreadLocalStorage[chain].parameters, chain, false);
1643  return false;
1644 }
1645 
1646 //--------------------------------------------------------
1648 {
1649  bool return_value = true;
1650 
1651  if (!fMCMCProposeMultivariate) {
1652  /* run over parameters one at a time */
1653 
1654  for (unsigned ipar = 0; ipar < GetNParameters(); ++ipar) {
1655  if (GetParameter(ipar).Fixed())
1656  continue;
1657 
1658  //loop over chains
1659  #pragma omp parallel for schedule(static)
1660  for (unsigned c = 0; c < fMCMCNChains; ++c) {
1661  UpdateChainIndex(c);
1662  return_value &= GetNewPointMetropolis(c, ipar);
1663  }
1664  }
1665 
1666  } else {
1667  /* run over all pars at once */
1668 
1669  //loop over chains
1670  #pragma omp parallel for schedule(static)
1671  for (unsigned c = 0; c < fMCMCNChains; ++c) {
1672  UpdateChainIndex(c);
1673  return_value &= GetNewPointMetropolis(c);
1674  }
1675  }
1676 
1677  // increase number of iterations used in each chain for calculating efficiencies
1678  for (unsigned c = 0; c < fMCMCNChains; ++c)
1679  fMCMCStatistics[c].n_samples_efficiency += 1;
1680 
1682  return return_value;
1683 }
1684 
1685 // --------------------------------------------------------
1687 {
1689  // fill each 1-dimensional histogram that exists
1690  for (unsigned i = 0; i < GetNVariables() && i < fH1Marginalized.size(); ++i)
1691  if (TH1* h = fH1Marginalized[i]) {
1692  if (i < GetNParameters())
1693  h->Fill(cs.parameters[i]);
1694  else if (i - GetNParameters() < GetNObservables())
1695  h->Fill(cs.observables[i - GetNParameters()]);
1696  }
1697 
1699  // fill each 2-dimensional histogram that exists
1700  for (unsigned j = 0; j < GetNVariables() && j < fH2Marginalized.size(); ++j)
1701  for (unsigned k = 0; k < GetNVariables() && k < fH2Marginalized[j].size(); ++k)
1702  if (TH2* h = fH2Marginalized[j][k]) {
1703  if (j < GetNParameters()) {
1704  if (k < GetNParameters())
1705  h->Fill(cs.parameters[j], cs.parameters[k]);
1706  else if (k - GetNParameters() < GetNObservables())
1707  h->Fill(cs.parameters[j], cs.observables[k - GetNParameters()]);
1708  } else if (j - GetNParameters() < GetNObservables()) {
1709  if (k < GetNParameters())
1710  h->Fill(cs.observables[j - GetNParameters()], cs.parameters[k]);
1711  else if (k - GetNParameters() < GetNObservables())
1712  h->Fill(cs.observables[j - GetNParameters()], cs.observables[k - GetNParameters()]);
1713  }
1714  }
1715 }
1716 
1717 // --------------------------------------------------------
1719 {
1720  // loop over chains
1721  for (unsigned c = 0; c < fMCMCNChains; ++c)
1723 }
1724 
1725 // --------------------------------------------------------
1726 void BCEngineMCMC::InChainFillTree(const ChainState& cs, unsigned chain_number)
1727 {
1728  if (!fMCMCTree)
1729  return;
1730  fMCMCTree_Chain = chain_number;
1731  fMCMCTree_State = cs;
1732  fMCMCTree->Fill();
1733 }
1734 
1735 // -------------------------------------------------------
1737 {
1738  // loop over all chains
1739  for (unsigned i = 0; i < fMCMCNChains; ++i)
1741 }
1742 
1743 //---------------------------------------------------------
1745 {
1746  if (!fMCMCOutputFile)
1747  return;
1748 
1749  if (fMCMCOutputFile->IsOpen() && fMCMCOutputFile->IsWritable()) {
1750  fMCMCOutputFile->Write(0, TObject::kWriteDelete);
1751  fMCMCOutputFile->Close();
1752  }
1753  // ROOT also deletes associated named objects, the trees
1754  delete fMCMCOutputFile;
1755  fMCMCOutputFile = NULL;
1756  fMCMCTree = NULL;
1757  fParameterTree = NULL;
1758  fMCMCTreeLoaded = false;
1759 }
1760 
1761 // --------------------------------------------------------
1763 {
1764  // print on screen
1765  BCLog::OutSummary(Form("Pre-run Metropolis MCMC for model \"%s\" ...", GetName().data()));
1766 
1767  // initialize Markov chain
1768  MCMCInitialize();
1769 
1772 
1773  // perform run
1774  BCLog::OutSummary(Form(" --> Perform MCMC pre-run with %i chains, each with maximum %i iterations", fMCMCNChains, fMCMCNIterationsPreRunMax));
1775 
1776  const int old_error_ignore_level = gErrorIgnoreLevel;
1777 
1780 
1782  // multivariate proposal function
1783 
1784  // suppress ROOT errors about Cholesky decomposition
1785  gErrorIgnoreLevel = kBreak;
1786 
1787  // initialize covariance matrices as diag(var_0, var_1, var_2, ...)
1788  // initialize cholesky decomposition as diag(std_0, std_1, std_2, ...)
1789  // for free parameters only
1790  TMatrixDSym S0(GetNFreeParameters());
1791  TMatrixD CD0(GetNFreeParameters(), GetNFreeParameters());
1792  unsigned I = 0;
1793  for (unsigned i = 0; i < GetNParameters(); ++i)
1794  if (!(GetParameter(i).Fixed())) {
1795  if (GetParameter(i).GetPrior() != NULL) {
1796  S0[I][I] = GetParameter(i).GetPriorVariance();
1797  if (!std::isfinite(S0[I][I]))
1798  S0[I][I] = GetParameter(i).GetRangeWidth() * GetParameter(i).GetRangeWidth() / 12;
1799  } else
1800  S0[I][I] = GetParameter(i).GetRangeWidth() * GetParameter(i).GetRangeWidth() / 12;
1801  CD0[I][I] = sqrt(fMCMCProposalFunctionScaleFactor[0][0] * S0[I][I]);
1802  ++I;
1803  }
1804 
1805  // if chains run a second time on a model, the assign does not update the contents. wtf?
1808  }
1809 
1811  // Adjust scales until all parameters are in correct efficiency range in all chains
1812  bool allEfficient = false;
1813  bool inefficientScalesAdjustable = true;
1816 
1817  unsigned nIterationsPreRunCheck = fMCMCNIterationsPreRunCheck;
1818 
1819  // autosave every 10 checks
1820  if (fMCMCTree) {
1821  fMCMCTree->AutoSave("SaveSelf");
1822  }
1823 
1825 
1826  // Cholesky Decomposer for multivariate proposal function
1827  TDecompChol CholeskyDecomposer;
1828 
1829  unsigned nChecks = 0;
1830 
1831  // While loop criteria---do while:
1832  // not yet at maximum number of iterations
1833  // AND ( not yet above minimum number of iterations
1834  // OR an efficiency is out of range, and still adjustable;
1835  // OR the chains have not converged (if using more than one chain);
1836  // OR the minimum number of tuning steps have been made to the multivariate proposal function, if using it.
1837  // )
1840  || (!allEfficient && inefficientScalesAdjustable)
1842 
1843  // Generate (nIterationsCheckConvergence) new points in each chain
1844  for (unsigned i = 0; i < nIterationsPreRunCheck && fMCMCCurrentIteration < (int)fMCMCNIterationsPreRunMax; ++i) {
1845  // get new point & calculate observables
1848 
1849  // update chain statistics
1850  for (unsigned c = 0; c < fMCMCNChains; ++c)
1851  fMCMCStatistics[c].Update(fMCMCStates[c]);
1852 
1853  // update output tree
1855  InChainFillTree();
1856  }
1857 
1859  // Adjust scales until efficiencies within range
1860  allEfficient = true;
1861  inefficientScalesAdjustable = false;
1862 
1863  bool scalesAdjusted = false;
1864 
1865  for (unsigned c = 0; c < fMCMCNChains; ++c) {
1866 
1867  if (fMCMCProposeMultivariate) { // multivariate proposal function, one efficiency per chain
1868 
1869  if (fMCMCStatistics[c].efficiency[0] >= fMCMCEfficiencyMin && fMCMCStatistics[c].efficiency[0] <= fMCMCEfficiencyMax)
1870  continue; // since chain efficiency is in range,
1871 
1872  if (allEfficient) // print header if encountering first bad efficiency
1873  BCLog::OutDetail(Form(" * Efficiency status: Efficiencies not within predefined range after %i iterations. Efficiency of ", fMCMCCurrentIteration));
1874  allEfficient = false;
1875 
1876  double oldScale = fMCMCProposalFunctionScaleFactor[c][0];
1877 
1878  if (fMCMCStatistics[c].efficiency[0] < fMCMCEfficiencyMin) { // efficiency too low... decrease scale factor
1880 
1881  if (fMCMCProposalFunctionScaleFactor[c][0] > fMCMCScaleFactorLowerLimit) { // still room to tune
1882  if (fMCMCStatistics[c].efficiency[0] == 0)
1883  BCLog::OutDetail(Form(" chain %d is below %.0f %% (zero). Scale decreased to %.4g", c, 100 * fMCMCEfficiencyMin, fMCMCProposalFunctionScaleFactor[c][0]));
1884  else if (fMCMCStatistics[c].efficiency[0] < 1.e-2)
1885  BCLog::OutDetail(Form(" chain %d is below %.0f %% (%.0g %%). Scale decreased to %.4g", c, 100 * fMCMCEfficiencyMin, 100 * fMCMCStatistics[c].efficiency[0], fMCMCProposalFunctionScaleFactor[c][0]));
1886  else
1887  BCLog::OutDetail(Form(" chain %d is below %.0f %% (%.0f %%). Scale decreased to %.4g", c, 100 * fMCMCEfficiencyMin, 100 * fMCMCStatistics[c].efficiency[0], fMCMCProposalFunctionScaleFactor[c][0]));
1888  inefficientScalesAdjustable = true;
1889 
1890  } else { // no more room to tune
1892  if (fMCMCStatistics[c].efficiency[0] == 0)
1893  BCLog::OutDetail(Form(" chain %d is below %.0f %% (zero). Scale now at lower limit (%.4g)", c, 100 * fMCMCEfficiencyMin, fMCMCScaleFactorLowerLimit));
1894  else if (fMCMCStatistics[c].efficiency[0] < 1.e-2)
1895  BCLog::OutDetail(Form(" chain %d is below %.0f %% (%.0g %%). Scale now at lower limit (%.4g)", c, 100 * fMCMCEfficiencyMin, 100 * fMCMCStatistics[c].efficiency[0], fMCMCScaleFactorLowerLimit));
1896  else
1897  BCLog::OutDetail(Form(" chain %d is below %.0f %% f(%.0f %%). Scale now at lower limit (%.4g)", c, 100 * fMCMCEfficiencyMin, 100 * fMCMCStatistics[c].efficiency[0], fMCMCScaleFactorLowerLimit));
1898 
1899  }
1900 
1901  } else { // efficiency too high... increase scale factor
1903 
1904  if (fMCMCProposalFunctionScaleFactor[c][0] < fMCMCScaleFactorUpperLimit) { // still room to tune
1905  BCLog::OutDetail(Form(" chain %d is above %.0f %% (%.0f %%). Scale increased to %.4g", c, 100 * fMCMCEfficiencyMax, 100 * fMCMCStatistics[c].efficiency[0], fMCMCProposalFunctionScaleFactor[c][0]));
1906  inefficientScalesAdjustable = true;
1907  } else { // no more room to tune
1909  BCLog::OutDetail(Form(" chain %d is above %.0f %% (%.0f %%). Scale now at upper limit (%.4g)", c, 100 * fMCMCEfficiencyMax, 100 * fMCMCStatistics[c].efficiency[0], fMCMCScaleFactorUpperLimit));
1910  }
1911  }
1912 
1913  if (oldScale != fMCMCProposalFunctionScaleFactor[c][0])
1914  scalesAdjusted = true;
1915 
1916  } else { // factorized proposal function, one efficiency per parameter per chain
1917 
1918  for (unsigned p = 0; p < GetNParameters(); ++p) {
1919 
1920  if (GetParameter(p).Fixed())
1921  continue;
1922 
1923  if (fMCMCStatistics[c].efficiency[p] >= fMCMCEfficiencyMin && fMCMCStatistics[c].efficiency[p] <= fMCMCEfficiencyMax)
1924  continue; // since parameter efficiency is in range for this chain
1925 
1926  if (allEfficient) // print header if first bad efficiency
1927  BCLog::OutDetail(Form(" * Efficiency status: Efficiencies not within pre-defined range after %i iterations. Efficiency of ", fMCMCCurrentIteration));
1928  allEfficient = false;
1929 
1930  double oldScale = fMCMCProposalFunctionScaleFactor[c][p];
1931 
1932  if (fMCMCStatistics[c].efficiency[p] < fMCMCEfficiencyMin) { // efficiency too low... decrease scale factor
1933  fMCMCProposalFunctionScaleFactor[c][p] /= (fMCMCStatistics[c].efficiency[p] < fMCMCEfficiencyMin / 2) ? 4 : 2;
1934 
1935  if (fMCMCProposalFunctionScaleFactor[c][p] > fMCMCScaleFactorLowerLimit) { // still room to tune
1936  if (fMCMCStatistics[c].efficiency[p] == 0)
1937  BCLog::OutDetail(Form(" %-*s is below %.0f %% (zero) in chain %i. Scale decreased to %.4g", fParameters.MaxNameLength(), GetParameter(p).GetName().data(), 100 * fMCMCEfficiencyMin, c, fMCMCProposalFunctionScaleFactor[c][p]));
1938  else if (fMCMCStatistics[c].efficiency[p] < 1.e-2)
1939  BCLog::OutDetail(Form(" %-*s is below %.0f %% (%.0g %%) in chain %i. Scale decreased to %.4g", fParameters.MaxNameLength(), GetParameter(p).GetName().data(), 100 * fMCMCEfficiencyMin, 100 * fMCMCStatistics[c].efficiency[p], c, fMCMCProposalFunctionScaleFactor[c][p]));
1940  else
1941  BCLog::OutDetail(Form(" %-*s is below %.0f %% (%.0f %%) in chain %i. Scale decreased to %.4g", fParameters.MaxNameLength(), GetParameter(p).GetName().data(), 100 * fMCMCEfficiencyMin, 100 * fMCMCStatistics[c].efficiency[p], c, fMCMCProposalFunctionScaleFactor[c][p]));
1942  inefficientScalesAdjustable = true;
1943  } else { // no more room to tune
1944  if (fMCMCStatistics[c].efficiency[p] == 0)
1945  BCLog::OutDetail(Form(" %-*s is below %.0f %% (zero) in chain %i. Scale decreased to %.4g", fParameters.MaxNameLength(), GetParameter(p).GetName().data(), 100 * fMCMCEfficiencyMin, c, fMCMCProposalFunctionScaleFactor[c][p]));
1946  else if (fMCMCStatistics[c].efficiency[p] < 1.e-2)
1947  BCLog::OutDetail(Form(" %-*s is below %.0f %% (%.0g %%) in chain %i. Scale decreased to %.4g", fParameters.MaxNameLength(), GetParameter(p).GetName().data(), 100 * fMCMCEfficiencyMin, 100 * fMCMCStatistics[c].efficiency[p], c, fMCMCProposalFunctionScaleFactor[c][p]));
1948  else
1949  BCLog::OutDetail(Form(" %-*s is below %.0f %% (%.0f %%) in chain %i. Scale decreased to %.4g", fParameters.MaxNameLength(), GetParameter(p).GetName().data(), 100 * fMCMCEfficiencyMin, 100 * fMCMCStatistics[c].efficiency[p], c, fMCMCProposalFunctionScaleFactor[c][p]));
1951  }
1952 
1953  } else { // if efficiency too high ... increase scale factor
1955 
1956  if (fMCMCProposalFunctionScaleFactor[c][p] < fMCMCScaleFactorUpperLimit) { // still room to tune
1957  BCLog::OutDetail(Form(" %-*s is above %.0f %% (%.0f %%) in chain %i. Scale increased to %.4g", fParameters.MaxNameLength(), GetParameter(p).GetName().data(), 100 * fMCMCEfficiencyMax, 100 * fMCMCStatistics[c].efficiency[p], c, fMCMCProposalFunctionScaleFactor[c][p]));
1958  inefficientScalesAdjustable = true;
1959  } else { // no more room to tune
1961  BCLog::OutDetail(Form(" %-*s is above %.0f %% (%.0f %%) in chain %i. Scale now at upper limit (%.4g)", fParameters.MaxNameLength(), GetParameter(p).GetName().data(), 100 * fMCMCEfficiencyMax, 100 * fMCMCStatistics[c].efficiency[p], c, fMCMCScaleFactorUpperLimit));
1962  }
1963  }
1964 
1965  if (oldScale != fMCMCProposalFunctionScaleFactor[c][p])
1966  scalesAdjusted = true;
1967  } // end of parameter loop
1968  }
1969  } // end of chain loop
1970 
1971 
1973  // Check convergence
1974  if (fMCMCNChains > 1) {
1975 
1976  // Calculate & check R values
1978  for (unsigned p = 0; p < GetNParameters(); ++p) {
1979  if (GetParameter(p).Fixed())
1980  continue;
1981  std::vector<double> means(fMCMCNChains, 0);
1982  std::vector<double> variances(fMCMCNChains, 0);
1983  for (unsigned c = 0; c < fMCMCNChains; ++c) {
1984  means[c] = fMCMCStatistics[c].mean[p];
1985  variances[c] = fMCMCStatistics[c].variance[p];
1986  }
1990  }
1991 
1992  // output results if not converged
1994  BCLog::OutDetail(Form(" * Convergence status: Set of %i Markov chains did not converge after %i iterations.", fMCMCNChains, fMCMCCurrentIteration));
1995  BCLog::OutDetail(Form(" - %-*s : R-Value", fParameters.MaxNameLength(), "Parameter"));
1996 
1997  for (unsigned p = 0; p < GetNParameters(); ++p) {
1998  if (GetParameter(p).Fixed())
1999  continue;
2000 
2002  BCLog::OutDetail(Form(" %-*s : %.03f", fParameters.MaxNameLength(), GetParameter(p).GetName().data(), fMCMCRValueParameters[p]));
2003  else if (std::isfinite(fMCMCRValueParameters[p]))
2004  BCLog::OutDetail(Form(" %-*s : %.03f <-- Greater than threshold", fParameters.MaxNameLength(), GetParameter(p).GetName().data(), fMCMCRValueParameters[p]));
2005  else
2006  BCLog::OutDetail(Form(" %-*s : error in calculation", fParameters.MaxNameLength(), GetParameter(p).GetName().data()));
2007  }
2008  } // end convergence conditional
2009  } // end chains>1 conditional
2010  if (fMCMCTree && nChecks % 10 == 0) {
2011  fMCMCTree->AutoSave("SaveSelf");
2012  }
2013 
2014  ++nChecks; // increase number of checks made
2015 
2016  // scales have not been adjusted and convergence has been reached (or only one chain used)
2017  if (!scalesAdjusted && (fMCMCNChains == 1 || fMCMCNIterationsConvergenceGlobal > 0)) {
2019  // still below minimum number of prerun iterations
2020  BCLog::OutDetail(Form(" * Running until at least %d iterations performed in prerun. Current iteration is %d", fMCMCNIterationsPreRunMin, fMCMCCurrentIteration));
2021  else
2022  continue; // HURRAY!
2023  }
2024 
2025  // Update multivariate proposal function covariances
2029  }
2030 
2032  continue;
2033 
2034  // reset statistics
2035  for (unsigned c = 0; c < fMCMCStatistics.size(); ++c)
2036  if (fMCMCPreRunCheckClear > 0 && nChecks % fMCMCPreRunCheckClear == 0)
2037  fMCMCStatistics[c].Reset(false, true); // clear means and (co)variances, preserve mode information, clear efficiency information
2038  else
2039  fMCMCStatistics[c].ResetEfficiencies(); // clear only efficiency information
2040 
2041  } // end prerun iteration while loop
2042 
2043  // restore ROOT error ignore level
2044  gErrorIgnoreLevel = old_error_ignore_level;
2045 
2046  // output results of prerun concerning convergence and scale adjustment
2048  if (allEfficient)
2049  BCLog::OutSummary(Form(" --> Set of %i Markov chains converged within %i iterations, and all scales are adjusted.", fMCMCNChains, fMCMCNIterationsConvergenceGlobal));
2050  else if (!inefficientScalesAdjustable)
2051  BCLog::OutSummary(Form(" --> Set of %i Markov chains converged within %i iterations, but could not adjust all scales (scale limits reached).", fMCMCNChains, fMCMCNIterationsConvergenceGlobal));
2052  else
2053  BCLog::OutSummary(Form(" --> Set of %i Markov chains converged within %i iterations, but could not adjust all scales (maximum number of iterations reached).", fMCMCNChains, fMCMCNIterationsConvergenceGlobal));
2055  BCLog::OutSummary(Form(" --> %i updates to multivariate proposal function's covariances were made.", fMultivariateCovarianceUpdates));
2056  } else if (allEfficient)
2057  BCLog::OutSummary(Form(" --> Set of %i Markov chains did not converge within %i iterations, but all scales are adjusted.", fMCMCNChains, fMCMCNIterationsPreRunMax));
2058  else if (!inefficientScalesAdjustable)
2059  BCLog::OutSummary(Form(" --> Set of %i Markov chains did not converge within %i iterations, and could not adjust all scales (scale limits reached).", fMCMCNChains, fMCMCNIterationsPreRunMax));
2060  else
2061  BCLog::OutSummary(Form(" --> Set of %i Markov chains did not converge within %i iterations, and could not adjust all scales.", fMCMCNChains, fMCMCNIterationsPreRunMax));
2062 
2063 
2064  // combine statistics:
2066  for (unsigned c = 0; c < fMCMCNChains; ++c)
2068 
2070  BCLog::OutDetail(Form(" --> Scale factors and efficiencies (measured in last %u iterations):", fMCMCStatistics.front().n_samples_efficiency));
2071  BCLog::OutDetail(" - Chain : Scale factor Efficiency");
2072  for (unsigned c = 0; c < fMCMCNChains; ++c)
2073  BCLog::OutDetail(Form(" %3d : % 6.4g %4.1f %%", c, fMCMCProposalFunctionScaleFactor[c][0], 100.*fMCMCStatistics[c].efficiency[0]));
2074  } else {
2075  BCLog::OutDetail(Form(" --> Average scale factors and efficiencies (measured in last %u iterations):", fMCMCStatistics.front().n_samples_efficiency));
2076  BCLog::OutDetail(Form(" - %-*s : Scale factor Efficiency", fParameters.MaxNameLength(), "Parameter"));
2077  // print scale factors and efficiencies
2078  for (unsigned i = 0; i < GetNParameters(); ++i) {
2079  if (GetParameter(i).Fixed())
2080  continue;
2081  double scalefactors = 0;
2082  for (unsigned j = 0; j < fMCMCNChains; ++j)
2083  scalefactors += fMCMCProposalFunctionScaleFactor[j][i] / fMCMCNChains;
2084  BCLog::OutDetail(Form(" %-*s : % 6.4g %% %4.1f %%", fParameters.MaxNameLength(), GetParameter(i).GetName().data(), 100.*scalefactors, 100.*fMCMCStatistics_AllChains.efficiency[i]));
2085  }
2086  }
2087 
2088  // reset current iteration
2089  fMCMCCurrentIteration = -1;
2090 
2092  // UpdateParameterTree();
2093  if (fMCMCTree)
2094  fMCMCTree->AutoSave("SaveSelf");
2095  }
2096 
2097  // rescale histograms
2099  CreateHistograms(true);
2100 
2101  // no error
2102  return true;
2103 }
2104 
2105 // --------------------------------------------------------
2106 double BCEngineMCMC::RValue(const std::vector<double>& means, const std::vector<double>& variances, unsigned n, bool correctForSamplingVariability)
2107 {
2108  // calculate R values according to Brooks & Gelman,
2109  // "General Methods for Monitoring Convergence of Iterative Simulations, 1998
2110 
2111  if (means.empty() || variances.empty() || means.size() != variances.size() || n == 0)
2112  return std::numeric_limits<double>::quiet_NaN();
2113 
2114  unsigned m = means.size();
2115 
2116  // means of values
2117  double mean_of_means = 0;
2118  double mean_of_variances = 0;
2119  for (unsigned c = 0; c < m; ++c) {
2120  mean_of_means += means[c];
2121  mean_of_variances += variances[c];
2122  }
2123  mean_of_means *= 1. / m;
2124  mean_of_variances *= 1. / m;
2125 
2126  // variances of values
2127  double variance_of_means = 0;
2128  double variance_of_variances = 0;
2129  for (unsigned c = 0; c < m; ++c) {
2130  variance_of_means += (means[c] - mean_of_means) * (means[c] - mean_of_means);
2131  variance_of_variances += (variances[c] - mean_of_variances) * (variances[c] - mean_of_variances);
2132  }
2133  variance_of_means /= m - 1.;
2134  variance_of_variances /= m - 1.;
2135 
2136  // variance of all samples:
2137  double full_variance = m * (n - 1.) / (m * n - 1) * mean_of_variances + n * (m - 1.) / (m * n - 1) * variance_of_means;
2138 
2139  if (mean_of_variances == 0) {
2140  BCLOG_DEBUG("mean of variances is zero!");
2141  if (full_variance == 0) {
2142  BCLOG_DEBUG("variance of all samples is also zero!");
2143  return 1;
2144  } else
2145  return std::numeric_limits<double>::infinity();
2146  }
2147 
2148  double rvalue = sqrt(full_variance / mean_of_variances); // variance(all samples) / mean(chain variances)
2149 
2150  if (!correctForSamplingVariability)
2151  return rvalue;
2152 
2153  // else correct for initial sampling variability
2154 
2155  double meansquare_of_means = 0;
2156  for (unsigned c = 0; c < m; ++c)
2157  meansquare_of_means += means[c] * means[c];
2158  meansquare_of_means *= 1. / m;
2159 
2160  double covariance_of_variance_with_mean = 0;
2161  double covariance_of_variance_with_meansquare = 0;
2162  for (unsigned c = 0; c < m; ++c) {
2163  covariance_of_variance_with_mean += (variances[c] - mean_of_variances) * (means[c] - mean_of_means);
2164  covariance_of_variance_with_meansquare += (variances[c] - mean_of_variances) * (means[c] * means[c] - meansquare_of_means);
2165  }
2166  covariance_of_variance_with_mean /= m - 1.;
2167  covariance_of_variance_with_meansquare /= m - 1.;
2168 
2169  double N = (n - 1.) / n;
2170  double M = (m + 1.) / m;
2171 
2172  double V = N * full_variance + M * variance_of_means;
2173 
2174  double varV = N * N / m * variance_of_variances + 2 * M / (m - 1) * variance_of_means * variance_of_means
2175  + 2 * M * N / m * (covariance_of_variance_with_meansquare - 2 * mean_of_means * covariance_of_variance_with_mean);
2176 
2177  double df = 2 * V * V / varV;
2178 
2179  return rvalue * sqrt((df + 3) / (df + 1));
2180 }
2181 
2182 // --------------------------------------------------------
2184 {
2185  // check the number of free parameters
2186  if (GetNFreeParameters() <= 0) {
2187  BCLog::OutWarning("BCEngineMCMC::MCMCMetropolis. Number of free parameters <= 0. Do not run Metropolis.");
2188  return false;
2189  }
2190 
2191  // check if prerun should be performed
2193  if (!MetropolisPreRun())
2194  return false;
2195 
2196  // reset statistics
2197  for (unsigned c = 0; c < fMCMCStatistics.size(); ++c)
2198  fMCMCStatistics[c].Reset(false, true); // keep mode, reset efficiencies
2199 
2200  // reset iterations
2201  for (unsigned c = 0; c < fMCMCStates.size(); ++c)
2202  fMCMCStates[c].iteration = 0;
2203  }
2205  InitializeMarkovChainTree(false, false);
2206 
2207  // check that correct objects of correct size have been created
2208  // these checks will fail if the user has changed the number of chains or parameters
2209  // or the fixing of parameters between the pre-run and the main run, or between main runs
2210  if (fMCMCStatistics.size() != fMCMCNChains)
2211  throw std::runtime_error("BCEngineMCMC::Metropolis: size of fMCMCStatistics does not match number of chains.");
2212  if (fMCMCStates.size() != fMCMCNChains)
2213  throw std::runtime_error("BCEngineMCMC::Metropolis: size of fMCMCStates does not match number of chains.");
2214  if (fMCMCThreadLocalStorage.size() != fMCMCNChains)
2215  throw std::runtime_error("BCEngineMCMC::Metropolis: size of fMCMCThreadLocalStorage does not match number of chains.");
2216  for (unsigned c = 0; c < fMCMCThreadLocalStorage.size(); ++c) {
2217  if (fMCMCThreadLocalStorage[c].parameters.size() != GetNParameters())
2218  throw std::runtime_error(Form("BCEngineMCMC::Metropolis: size of fMCMCThreadLocalStorage[%u].parameters does not match number of parameters.", c));
2219  if (!fMCMCThreadLocalStorage[c].rng)
2220  throw std::runtime_error(Form("BCEngineMCMC::Metropolis: fMCMCThreadLocalStorage[%u] lacks random number generator.", c));
2221  }
2224  throw std::runtime_error(Form("BCEngineMCMC::Metropolis: pre-run was run with factorized proposal function."));
2225  // check if cholesky decompositions must be calculated
2226  bool calc_cholesky = false;
2228  calc_cholesky = true;
2229  else {
2230  for (unsigned c = 0; c < fMultivariateProposalFunctionCholeskyDecomposition.size(); ++c)
2231  if (fMultivariateProposalFunctionCholeskyDecomposition[c].GetNrows() != static_cast<int>(GetNFreeParameters()) or
2232  fMultivariateProposalFunctionCholeskyDecomposition[c].GetNcols() != static_cast<int>(GetNFreeParameters()))
2233  calc_cholesky = true;
2234  }
2235  if (calc_cholesky)
2237 
2239  throw std::runtime_error("BCEngineMCMC::Metropolis: size of fMultivariateProposalFunctionCholeskyDecomposition does not match number of chains.");
2240  for (unsigned c = 0; c < fMultivariateProposalFunctionCholeskyDecomposition.size(); ++c)
2241  if (fMultivariateProposalFunctionCholeskyDecomposition[c].GetNrows() != static_cast<int>(GetNFreeParameters()) or
2242  fMultivariateProposalFunctionCholeskyDecomposition[c].GetNcols() != static_cast<int>(GetNFreeParameters()))
2243  throw std::runtime_error(Form("BCEngineMCMC::Metropolis: size of fMultivariateProposalFunctionCholeskyDecomposition[%u] matrix does not match number of free parameters.", c));
2244  for (unsigned c = 0; c < fMCMCThreadLocalStorage.size(); ++c)
2245  if (fMCMCThreadLocalStorage[c].yLocal.GetNrows() != static_cast<int>(GetNFreeParameters()))
2246  throw std::runtime_error(Form("BCEngineMCMC::Metropolis: size of fThreadLocalStorage[%u].yLocal matrix does not match number of free parameters.", c));
2247  } else {
2248  // check that pre-run was not run with multivariate proposal
2250  throw std::runtime_error("BCEngineMCMC::Metropolis: pre-run was run with multivariate proposal function.");
2252  throw std::runtime_error("BCEngineMCMC::Metropolis: size of fProposalFunctionScaleFactor does not match number of chains.");
2253  for (unsigned c = 0; c < fMCMCProposalFunctionScaleFactor.size(); ++c) {
2255  throw std::runtime_error(Form("BCEngineMCMC::Metropolis: size of fMCMCProposalFunctionScaleFactor[%u] does not match number of parameters.", c));
2256  for (unsigned p = 0; p < fMCMCProposalFunctionScaleFactor[c].size(); ++p) {
2257  if (!GetParameter(p).Fixed() && fMCMCProposalFunctionScaleFactor[c][p] <= 0)
2258  throw std::runtime_error(Form("BCEngineMCMC::Metropolis: fMCMCProposalFunctionScaleFactor[%u][%u] <= 0.", c, p));
2259  if (GetParameter(p).Fixed() && fMCMCProposalFunctionScaleFactor[c][p] > 0)
2260  throw std::runtime_error(Form("BCEngineMCMC::Metropolis: parameter %u has been unfixed without rerunning the pre-run.", p));
2261  }
2262  }
2263  }
2264 
2265  // print to screen
2266  BCLog::OutSummary(Form("Run Metropolis MCMC for model \"%s\" ...", GetName().data()));
2267 
2268  // set phase and cycle number
2270 
2271  BCLog::OutSummary(Form(" --> Perform MCMC run with %i chains, each with %i iterations.", fMCMCNChains, fMCMCNIterationsRun));
2272 
2273  unsigned nwrite = UpdateFrequency(fMCMCNIterationsRun);
2274 
2275  // start the run
2278 
2281 
2282  if (fMCMCCurrentIteration % nwrite == 0) {
2283  BCLog::OutDetail(Form(" --> iteration number %6i (%3.0f %%)", fMCMCCurrentIteration, (double)(fMCMCCurrentIteration) / (double)fMCMCNIterationsRun * 100.));
2285  fMCMCTree->AutoSave("SaveSelf");
2286  }
2287 
2288  if (fMCMCCurrentIteration % fMCMCNLag != 0) // apply lag
2289  continue;
2290 
2291  MCMCUserIterationInterface(); // user action (overloadable)
2292 
2293  for (unsigned c = 0; c < fMCMCNChains; ++c)
2294  fMCMCStatistics[c].Update(fMCMCStates[c]);
2295 
2296  // fill histograms
2297  if (!fH1Marginalized.empty() || !fH2Marginalized.empty())
2299 
2300  // write chain to file
2302  InChainFillTree();
2303 
2304  } // end run
2305 
2306  BCLog::OutSummary(Form(" --> Markov chains ran for %i iterations.", fMCMCNIterationsRun));
2307 
2308  // reset total stats
2310  // add in individual chain stats
2311  for (unsigned c = 0; c < fMCMCStatistics.size(); ++c)
2313 
2314  // print efficiencies
2316  BCLog::OutDetail(Form(" --> Efficiencies (measured in %u iterations):", fMCMCStatistics.front().n_samples_efficiency));
2317  BCLog::OutDetail(" - Chain : Efficiency");
2318  for (unsigned c = 0; c < fMCMCNChains; ++c)
2319  BCLog::OutDetail(Form(" %3d : %4.1f %%", c, 100.*fMCMCStatistics[c].efficiency[0]));
2320  } else {
2321  BCLog::OutDetail(Form(" --> Average efficiencies (measured in %u iterations):", fMCMCStatistics_AllChains.n_samples_efficiency / fMCMCNChains));
2322  BCLog::OutDetail(Form(" - %-*s : Efficiency", fParameters.MaxNameLength(), "Parameter"));
2323  for (unsigned i = 0; i < GetNParameters(); ++i) {
2324  if (GetParameter(i).Fixed())
2325  continue;
2326  BCLog::OutDetail(Form(" %-*s : %4.1f %%", fParameters.MaxNameLength(), GetParameter(i).GetName().data(), 100.*fMCMCStatistics_AllChains.efficiency[i]));
2327  }
2328  }
2329 
2332 
2333  BCLog::OutDetail(" --> Global mode from MCMC:");
2334  BCLog::OutDebug(Form(" --> Posterior value: %g", fMCMCStatistics_AllChains.probability_at_mode));
2336 
2337  // reset counter
2338  fMCMCCurrentIteration = -1;
2339 
2340  return true;
2341 }
2342 
2343 // --------------------------------------------------------
2345 {
2346  if (GetNObservables() > 0)
2347  for (unsigned c = 0; c < fMCMCNChains; ++c)
2349 }
2350 
2351 // --------------------------------------------------------
2353 {
2354  if (chain > fMCMCNChains)
2355  return;
2356 
2357  UpdateChainIndex(chain);
2358  CalculateObservables(fMCMCStates[chain].parameters);
2359  for (unsigned j = 0; j < GetNObservables(); ++j)
2360  fMCMCStates[chain].observables[j] = GetObservable(j).Value();
2361 }
2362 
2363 // --------------------------------------------------------
2365 {
2366  // reset variables
2367  fMCMCCurrentIteration = -1;
2368  fMCMCStatistics.clear();
2371  fMCMCStates.clear();
2373  fMCMCRValueParameters.clear();
2374 
2375  for (unsigned i = 0; i < fH1Marginalized.size(); ++i)
2376  delete fH1Marginalized[i];
2377 
2378  for (unsigned i = 0; i < fH2Marginalized.size(); ++i)
2379  for (unsigned j = 0; j < fH2Marginalized[i].size(); ++j)
2380  delete fH2Marginalized[i][j];
2381 
2382  // clear plots
2383  fH1Marginalized.clear();
2384  fH2Marginalized.clear();
2385 
2386  // reset flags
2388 
2389  fLocalModes.clear();
2390 }
2391 
2392 // --------------------------------------------------------
2394 {
2395  // reset phase
2397 
2398  // reset convergence
2400 
2401  // reset statistics counters
2404 
2405  // reset states holder
2407 
2408  // rest r value holders
2409  fMCMCRValueParameters.assign(GetNParameters(), std::numeric_limits<double>::infinity());
2410 
2411  // clear info about local modes
2412  fLocalModes.clear();
2413 
2414  // clear number of multivariate proposal function covariance updates performed
2416 
2417  SyncThreadStorage();
2418 
2419  CreateHistograms(false);
2420 
2421  // set scale factors
2423  // if multivariate
2424 
2425  // if only one scale factor is set, use for all chains
2426  if (fMCMCInitialScaleFactors.size() == 1) {
2428  }
2429  // if one scale factor set per chain:
2430  else if (fMCMCInitialScaleFactors.size() == fMCMCNChains) {
2432  for (unsigned i = 0; i < fMCMCNChains; ++i)
2433  fMCMCProposalFunctionScaleFactor.push_back(std::vector<double>(1, fMCMCInitialScaleFactors[i]));
2434  }
2435  // else initialize proposal function scale factors to 2.38^2 / number of dimensions
2436  else {
2437  fMCMCProposalFunctionScaleFactor.assign(fMCMCNChains, std::vector<double>(1, 2.38 * 2.38 / GetNFreeParameters()));
2438  }
2439  }
2440  // else factorized proposal
2441  else {
2442 
2443  // if provided by user
2444  if (fMCMCInitialScaleFactors.size() == GetNParameters()) {
2446  }
2447  // else calculate from priors
2448  else {
2449  std::vector<double> temp;
2450  for (unsigned i = 0; i < GetNParameters(); ++i)
2451  if (GetParameter(i).Fixed() || GetParameter(i).GetRangeWidth() == 0)
2452  temp.push_back(1);
2453  else {
2454  double var = GetParameter(i).GetPriorVariance();
2455  if (var > 0 && std::isfinite(var))
2456  temp.push_back(sqrt(var) / GetParameter(i).GetRangeWidth());
2457  else
2458  temp.push_back(1. / sqrt(12));
2459  }
2461  }
2462  // set fixed parameters' scale factors to zero
2463  for (unsigned i = 0; i < GetNParameters(); ++i)
2464  if (GetParameter(i).Fixed())
2465  for (unsigned c = 0; c < GetNChains(); ++c)
2467  }
2468 
2469  // before we set the initial position and evaluate the likelihood, it's time to let the user initialize the model with #chains etc. fixed
2471 
2472  /* set initial position */
2473 
2474  // initialize markov chain positions
2475  switch (fInitialPositionScheme) {
2476 
2477  // use range centers
2478  case kInitCenter : {
2479  for (unsigned c = 0; c < fMCMCNChains; ++c) {
2480  fMCMCThreadLocalStorage[c].parameters = GetParameters().GetRangeCenters();
2481  UpdateChainIndex(c);
2482  LogEval(fMCMCThreadLocalStorage[c].parameters);
2483  if (!std::isfinite(fMCMCThreadLocalStorage[c].log_probability))
2484  throw std::runtime_error("BCEngineMCMC::MCMCInitialize : Range center as initial point yields invalid probability.");
2485  fMCMCStates[c] = fMCMCThreadLocalStorage[c];
2486  }
2487 
2488  break;
2489  }
2490 
2491  // uniformly distribute all coordinates in provided ranges
2492  case kInitRandomUniform : {
2493  for (unsigned c = 0; c < fMCMCNChains; ++c) {
2494  for (unsigned n = 0; n < fInitialPositionAttemptLimit && !std::isfinite(fMCMCThreadLocalStorage[c].log_probability); ++n) {
2495  fMCMCThreadLocalStorage[c].parameters = GetParameters().GetUniformRandomValues(fMCMCThreadLocalStorage[c].rng);
2496  UpdateChainIndex(c);
2497  LogEval(fMCMCThreadLocalStorage[c].parameters);
2498  }
2499  if (!std::isfinite(fMCMCThreadLocalStorage[c].log_probability))
2500  throw std::runtime_error(Form("BCEngineMCMC::MCMCInitialize : Could not generate uniformly distributed initial point with valid probability in %u tries.", fInitialPositionAttemptLimit));
2501  fMCMCStates[c] = fMCMCThreadLocalStorage[c];
2502  }
2503 
2504  break;
2505  }
2506 
2507  // use user-defined starting points
2508  case kInitUserDefined : {
2509  // check initial position vector size
2510  if (fMCMCInitialPosition.size() < fMCMCNChains)
2511  throw std::runtime_error("BCEngineMCMC::MCMCInitialize : Too few initial positions provided.");
2512 
2513  // copy positions and set fixed values
2514  // then check whether initial positions are within bounds
2515  // (which also checks that initial position vectors are correct size)
2516  for (unsigned c = 0; c < fMCMCNChains; ++c) {
2517  fMCMCThreadLocalStorage[c].parameters = fMCMCInitialPosition[c];
2518  GetParameters().ApplyFixedValues(fMCMCThreadLocalStorage[c].parameters);
2519  if (!GetParameters().IsWithinLimits(fMCMCThreadLocalStorage[c].parameters)) {
2520  BCLog::OutDebug(Form("Initial point of chain %d", c));
2521  PrintParameters(fMCMCThreadLocalStorage[c].parameters, BCLog::OutDebug);
2522  throw std::runtime_error("BCEngineMCMC::MCMCInitialize : User-defined initial point is out of bounds.");
2523  } else {
2524  UpdateChainIndex(c);
2525  LogEval(fMCMCThreadLocalStorage[c].parameters);
2526  if (!std::isfinite(fMCMCThreadLocalStorage[c].log_probability)) {
2527  BCLog::OutDebug(Form("Initial point of chain %d", c));
2528  PrintParameters(fMCMCThreadLocalStorage[c].parameters, BCLog::OutDebug);
2529  throw std::runtime_error("BCEngineMCMC::MCMCInitialize : User-defined initial point yields invalid probability.");
2530  }
2531  fMCMCStates[c] = fMCMCThreadLocalStorage[c];
2532  }
2533  }
2534 
2535  break;
2536  }
2537 
2538  // randomly distribute according to factorized priors
2539  case kInitRandomPrior : {
2540  if (!GetParameters().ArePriorsSet(true))
2541  throw std::runtime_error("BCEngineMCMC::MCMCInitialize : Not all unfixed parameters have priors set.");
2542 
2543  for (unsigned c = 0; c < fMCMCNChains; ++c) {
2544  for (unsigned n = 0; n < fInitialPositionAttemptLimit && !std::isfinite(fMCMCThreadLocalStorage[c].log_probability); ++n) {
2545  fMCMCThreadLocalStorage[c].parameters = GetParameters().GetRandomValuesAccordingToPriors(fMCMCThreadLocalStorage[c].rng);
2546  // check new point
2547  if (!GetParameters().IsWithinLimits(fMCMCThreadLocalStorage[c].parameters))
2548  throw std::runtime_error("BCEngineMCMC::MCMCInitialize : Could not generate random point within limits.");
2549 
2550  UpdateChainIndex(c);
2551  LogEval(fMCMCThreadLocalStorage[c].parameters);
2552  }
2553  if (!std::isfinite(fMCMCThreadLocalStorage[c].log_probability))
2554  throw std::runtime_error(Form("BCEngineMCMC::MCMCInitialize : Could not generate initial point from prior with valid probability in %u tries.", fInitialPositionAttemptLimit));
2555  fMCMCStates[c] = fMCMCThreadLocalStorage[c];
2556  }
2557 
2558  break;
2559  }
2560 
2561  default:
2562  throw std::runtime_error("BCEngineMCMC::MCMCInitialize : No MCMC position initialization scheme specified.");
2563  } // (switch)
2564 
2565  if (fMCMCStates.empty())
2566  throw std::runtime_error("BCEngineMCMC::MCMCInitialize failed.");
2567 
2568  for (unsigned c = 0; c < fMCMCStates.size(); ++c)
2569  if (fMCMCStates[c].parameters.empty())
2570  throw std::runtime_error("BCEngineMCMC::MCMCInitialize failed.");
2571 }
2572 
2573 // ------------------------------------------------------------
2574 void BCEngineMCMC::SetFillHistogram(int x, int y, bool flag)
2575 {
2576  // check indices
2577  if (x >= (int)fParameters.Size() || - x > (int)fObservables.Size())
2578  return;
2579  if (y >= (int)fParameters.Size() || - y > (int)fObservables.Size())
2580  return;
2581 
2582  if (flag) { // adding
2583  // check for combination already in list
2584  for (unsigned i = 0; i < fRequestedH2.size(); ++i)
2585  if (fRequestedH2[i].first == x && fRequestedH2[i].second == y)
2586  return;
2587  fRequestedH2.push_back(std::make_pair(x, y));
2588  } else { // removing
2589  for (int i = fRequestedH2.size() - 1; i >= 0; --i)
2590  if (fRequestedH2[i].first == x && fRequestedH2[i].second == y)
2591  fRequestedH2.erase(fRequestedH2.begin() + i);
2592  }
2593 }
2594 
2595 // ------------------------------------------------------------
2596 void BCEngineMCMC::CreateHistograms(bool rescale_ranges)
2597 {
2598  // clear existing histograms
2599  for (unsigned i = 0; i < fH1Marginalized.size(); ++i)
2600  delete fH1Marginalized[i];
2601  fH1Marginalized.assign(GetNVariables(), NULL);
2602 
2603  for (unsigned i = 0; i < fH2Marginalized.size(); ++i)
2604  for (unsigned j = 0; j < fH2Marginalized[i].size(); ++j)
2605  delete fH2Marginalized[i][j];
2606  fH2Marginalized.assign(GetNVariables(), std::vector<TH2*>(GetNVariables(), NULL));
2607 
2608  // store old bounds, rescale if rescaling:
2609  std::vector<std::pair<double, double> > original_bounds;
2610  original_bounds.reserve(GetNVariables());
2611  for (unsigned i = 0; i < GetNVariables(); ++i) {
2612  original_bounds.push_back(std::make_pair(GetVariable(i).GetLowerLimit(), GetVariable(i).GetUpperLimit()));
2613  if (i < GetNParameters() && GetParameter(i).Fixed())
2614  continue;
2615  if (rescale_ranges) {
2616  if (i < fMCMCStatistics_AllChains.minimum.size() && std::isfinite(fMCMCStatistics_AllChains.minimum[i]))
2618  if (i < fMCMCStatistics_AllChains.maximum.size() && std::isfinite(fMCMCStatistics_AllChains.maximum[i]))
2620  if (fHistogramRescalePadding > 0) {
2621  // calculate enlargement factor
2622  double range_width_rescale = GetVariable(i).GetRangeWidth() * fHistogramRescalePadding;
2623  // push bounds out, but not beyond original parameter bounds
2624  GetVariable(i).SetLowerLimit(std::max<double>(GetVariable(i).GetLowerLimit() - range_width_rescale, original_bounds.back().first));
2625  GetVariable(i).SetUpperLimit(std::min<double>(GetVariable(i).GetUpperLimit() + range_width_rescale, original_bounds.back().second));
2626  }
2627  }
2628  }
2629 
2630  // define 1-dimensional histograms for marginalization
2631  int filling = 0;
2632 
2633  for (unsigned i = 0; i < GetNVariables(); ++i)
2634  if (GetVariable(i).FillH1()) {
2635  if (i < GetNParameters()) { // parameter
2636  if (!GetParameter(i).Fixed()) {
2637  fH1Marginalized[i] = GetVariable(i).CreateH1(Form("h1_%s_parameter_%s", GetSafeName().data() , GetParameter(i).GetSafeName().data()));
2638  ++filling;
2639  }
2640  } else { // user-defined observable
2641  fH1Marginalized[i] = GetVariable(i).CreateH1(Form("h1_%s_observable_%s", GetSafeName().data() , GetVariable(i).GetSafeName().data()));
2642  ++filling;
2643  }
2644  }
2645 
2646  if (filling == 0) // if filling no 1D histograms, clear vector
2647  fH1Marginalized.clear();
2648 
2649  // define 2D histograms for marginalization
2650  filling = 0;
2651 
2652  // requested 2D histograms in order requested:
2653  for (std::vector<std::pair<int, int> >::const_iterator h = fRequestedH2.begin(); h != fRequestedH2.end(); ++h) {
2654  if (h->first >= 0 && GetParameter(h->first).Fixed())
2655  continue;
2656  if (h->second >= 0 && GetParameter(h->second).Fixed())
2657  continue;
2658 
2659  unsigned i = (h->first >= 0) ? h->first : -(h->first + 1);
2660  unsigned j = (h->second >= 0) ? h->second : -(h->second + 1);
2661 
2662  if (h->first >= 0) {
2663  if (i >= GetNParameters())
2664  continue;
2665 
2666  if (h->second >= 0) { // par vs par
2667  if (j >= GetNParameters())
2668  continue;
2669  fH2Marginalized[i][j] = GetParameter(i).CreateH2(Form("h2_%s_par_%s_vs_par_%s", GetSafeName().data(), GetParameter(j).GetSafeName().data(), GetParameter(i).GetSafeName().data()), GetParameter(j));
2670  } else { // obs vs par
2671  if (j >= GetNObservables())
2672  continue;
2673  fH2Marginalized[i][j + GetNParameters()] = GetParameter(i).CreateH2(Form("h2_%s_obs_%s_vs_par_%s", GetSafeName().data(), GetObservable(j).GetSafeName().data(), GetParameter(i).GetSafeName().data()), GetObservable(j));
2674  }
2675 
2676  } else {
2677  if (i >= GetNObservables())
2678  continue;
2679 
2680  if (h->second >= 0) { // par vs obs
2681  if (j >= GetNParameters())
2682  continue;
2683  fH2Marginalized[i + GetNParameters()][j] = GetObservable(i).CreateH2(Form("h2_%s_par_%s_vs_obs_%s", GetSafeName().data(), GetParameter(j).GetSafeName().data(), GetObservable(i).GetSafeName().data()), GetParameter(j));
2684  } else { // obs vs obs
2685  if (j >= GetNObservables())
2686  continue;
2687  fH2Marginalized[i + GetNParameters()][j + GetNParameters()] = GetObservable(i).CreateH2(Form("h2_%s_obs_%s_vs_obs_%s", GetSafeName().data(), GetObservable(j).GetSafeName().data(), GetObservable(i).GetSafeName().data()), GetObservable(j));
2688  }
2689  }
2690  ++filling;
2691  }
2692 
2693  // automatically produced combinations, using pars' and obvs' FillH2():
2694 
2695  // parameter i as abscissa:
2696  for (unsigned i = 0; i < GetNParameters(); ++i) {
2697  if (GetParameter(i).Fixed() || !GetParameter(i).FillH2())
2698  continue;
2699 
2700  // parameter j as ordinate
2701  for (unsigned j = i + 1; j < GetNParameters(); ++j)
2702  if (!GetParameter(j).Fixed() && GetParameter(j).FillH2() && !fH2Marginalized[i][j]) {
2703  fH2Marginalized[i][j] = GetParameter(i).CreateH2(Form("h2_%s_par_%s_vs_par_%s", GetSafeName().data(), GetParameter(j).GetSafeName().data(), GetParameter(i).GetSafeName().data()), GetParameter(j));
2704  ++filling;
2705  }
2706  // user-defined observable j as ordinate
2707  for (unsigned j = 0; j < GetNObservables(); ++j)
2708  if (GetObservable(j).FillH2() && !fH2Marginalized[i][j + GetNParameters()]) {
2709  fH2Marginalized[i][j + GetNParameters()] = GetParameter(i).CreateH2(Form("h2_%s_obs_%s_vs_par_%s", GetSafeName().data(), GetObservable(j).GetSafeName().data(), GetParameter(i).GetSafeName().data()), GetObservable(j));
2710  ++filling;
2711  }
2712  }
2713 
2714  // user-defined observable i as abscissa
2715  for (unsigned i = 0; i < GetNObservables(); ++i) {
2716  if (!GetObservable(i).FillH2())
2717  continue;
2718 
2719  // user-defined observable j as ordinate
2720  for (unsigned j = i + 1; j < GetNObservables(); ++j)
2721  if (GetObservable(j).FillH2() && !fH2Marginalized[i + GetNParameters()][j + GetNParameters()]) {
2722  fH2Marginalized[i + GetNParameters()][j + GetNParameters()] = GetObservable(i).CreateH2(Form("h2_%s_obs_%s_vs_obs_%s", GetSafeName().data(), GetObservable(j).GetSafeName().data(), GetObservable(i).GetSafeName().data()), GetObservable(j));
2723  ++filling;
2724  }
2725  }
2726 
2727  if (filling == 0) // if filling no 2D histograms, clear vector
2728  fH2Marginalized.clear();
2729 
2730  // restore bounds
2731  for (unsigned i = 0; i < GetNVariables(); ++i)
2732  GetVariable(i).SetLimits(original_bounds[i].first, original_bounds[i].second);
2733 }
2734 
2735 // ---------------------------------------------------------
2737 {
2739  BCLog::OutSummary("");
2741  BCLog::OutSummary("");
2743 }
2744 
2745 // ---------------------------------------------------------
2747 {
2748  BCLog::OutSummary("");
2749  BCLog::OutSummary(" -----------------------------------------------------");
2750  BCLog::OutSummary(" Summary");
2751  BCLog::OutSummary(" -----------------------------------------------------");
2752  BCLog::OutSummary("");
2753 
2754  BCLog::OutSummary(" Model summary");
2755  BCLog::OutSummary(" =============");
2756  BCLog::OutSummary(" Model: " + GetName());
2757  BCLog::OutSummary(Form(" Number of parameters: %u", GetNParameters()));
2758 
2759  if (!fParameters.Empty()) {
2760  BCLog::OutSummary("");
2761  BCLog::OutSummary(" List of parameters and ranges:");
2763  }
2764 
2765  if (!fObservables.Empty()) {
2766  BCLog::OutSummary("");
2767  BCLog::OutSummary(" List of observables and ranges:");
2769  }
2770  BCLog::OutSummary("");
2771 }
2772 
2773 // ---------------------------------------------------------
2775 {
2776  if (GetBestFitParameters().size() != GetNParameters() && GetBestFitParameters().size() != GetNVariables()) {
2777  BCLog::OutSummary("No best fit information available.");
2778  return;
2779  }
2780 
2781  BCLog::OutSummary(" Best Fit Results");
2782  BCLog::OutSummary(" ===========================");
2783  BCLog::OutSummary(Form(" Log of the maximum posterior: %f", GetLogMaximum()));
2784  BCLog::OutSummary("");
2785  BCLog::OutSummary(" Global mode:");
2786 
2787  for (unsigned i = 0; i < GetBestFitParameters().size(); ++i)
2788  BCLog::OutSummary(GetBestFitSummary(i));
2789 }
2790 
2791 // ---------------------------------------------------------
2792 std::string BCEngineMCMC::GetBestFitSummary(unsigned i) const
2793 {
2794  if (i >= GetNVariables())
2795  return std::string("");
2796 
2797  unsigned n = (int)log10(GetNVariables()) + 1;
2798  std::string par_summary = Form(" %*d) %10s \"%s\"%*s : %.*g", n, i, GetVariable(i).GetPrefix().data(),
2799  GetVariable(i).GetName().data(), (int)(GetMaximumParameterNameLength() - GetVariable(i).GetName().length()), "",
2800  GetVariable(i).GetPrecision(), GetBestFitParameters()[i]);
2801 
2802  if (i < GetNParameters() && GetParameter(i).Fixed())
2803  par_summary += " (fixed)";
2804 
2805  return par_summary;
2806 }
2807 
2808 // ---------------------------------------------------------
2810 {
2811  BCLog::OutSummary(" Results of the marginalization");
2812  BCLog::OutSummary(" ==============================");
2813 
2815  // give warning if MCMC did not converge
2816  BCLog::OutSummary(" WARNING: the Markov Chain did not converge!");
2817  BCLog::OutSummary(" Be cautious using the following results!");
2818  BCLog::OutSummary("");
2819  }
2820 
2821  BCLog::OutSummary(" List of variables and properties of the marginalized distributions:");
2822  BCLog::OutSummary("");
2823 
2824  for (unsigned i = 0; i < GetNVariables(); ++i) {
2825  std::string par_summary = Form(" (%u) ", i) + GetVariable(i).GetPrefix() + " \"" + GetVariable(i).GetName() + "\" :";
2826 
2827  if (i < GetNParameters() && GetParameter(i).Fixed()) {
2828  par_summary += Form(" fixed at %.*g", GetVariable(i).GetPrecision(), GetParameter(i).GetFixedValue());
2829  BCLog::OutSummary(par_summary);
2830 
2831  } else if (!MarginalizedHistogramExists(i)) {
2832  par_summary += " histogram does not exist.";
2833  BCLog::OutSummary(par_summary);
2834 
2835  } else {
2836  BCLog::OutSummary(par_summary);
2837  GetMarginalized(i).PrintSummary(" ", GetVariable(i).GetPrecision(), std::vector<double>(1, 0.68));
2838  }
2839 
2840  BCLog::OutSummary("");
2841  }
2842 
2843  if (fMCMCPhase == kMainRun) {
2844 
2845  BCLog::OutSummary(" Status of the MCMC");
2846  BCLog::OutSummary(" ==================");
2847 
2848  if (GetNIterationsConvergenceGlobal() > 0) {
2849  BCLog::OutSummary(" Convergence reached: yes");
2850  BCLog::OutSummary(Form(" Number of iterations until convergence: %d", fMCMCNIterationsConvergenceGlobal));
2851  } else
2852  BCLog::OutSummary(" Convergence reached: no");
2853 
2854  BCLog::OutSummary(Form(" Number of chains: %u", fMCMCNChains));
2855  BCLog::OutSummary(Form(" Number of iterations per chain: %u", fMCMCNIterationsRun));
2856 
2858  BCLog::OutDetail(Form(" Scale factors and efficiencies (measured in last %u iterations):", fMCMCStatistics.front().n_samples_efficiency));
2859  BCLog::OutDetail(" Chain : Scale factor Efficiency");
2860  for (unsigned c = 0; c < fMCMCNChains; ++c) {
2861  BCLog::OutDetail(Form(" %3d : %-6.4g %4.1f %%", c, fMCMCProposalFunctionScaleFactor[c][0], 100.*fMCMCStatistics[c].efficiency[0]));
2862  }
2863 
2864  } else {
2865  BCLog::OutDetail(" Average scale factors and efficiencies:");
2866  BCLog::OutDetail(Form(" %-*s : Scale factor Efficiency", fParameters.MaxNameLength(), "Parameter"));
2867  for (unsigned i = 0; i < GetNParameters(); ++i) {
2868  if (GetParameter(i).Fixed())
2869  continue;
2870  double scalefactor = 0;
2871  for (unsigned j = 0; j < fMCMCNChains; ++j)
2872  scalefactor += fMCMCProposalFunctionScaleFactor[j][i] / fMCMCNChains;
2873  BCLog::OutDetail(Form(" %-*s : % 6.4g %% %4.1f %%", fParameters.MaxNameLength(), GetParameter(i).GetName().data(), 100.*scalefactor, 100.*fMCMCStatistics_AllChains.efficiency[i]));
2874  }
2875  }
2876  }
2877 }
2878 
2879 
2880 // ---------------------------------------------------------
2881 void BCEngineMCMC::PrintParameters(const std::vector<double>& P, void (*output)(const std::string&)) const
2882 {
2883  if (P.size() != GetNParameters() && P.size() != GetNVariables())
2884  return;
2885 
2886  for (unsigned i = 0; i < P.size(); ++i)
2887  output(Form(" %-*s : % .*g", GetMaximumParameterNameLength(P.size() > GetNParameters()), GetVariable(i).GetName().data(), GetVariable(i).GetPrecision(), P[i]));
2888 }
2889 
2890 // ---------------------------------------------------------
2891 std::vector<unsigned> BCEngineMCMC::GetH1DPrintOrder() const
2892 {
2893  std::vector<unsigned> H1Indices;
2894  for (unsigned i = 0; i < GetNVariables(); ++i)
2896  H1Indices.push_back(i);
2897 
2898  return H1Indices;
2899 }
2900 
2901 // ---------------------------------------------------------
2902 std::vector<std::pair<unsigned, unsigned> > BCEngineMCMC::GetH2DPrintOrder() const
2903 {
2904  // create vector for ordering 2D hists properly
2905  std::vector<std::pair<unsigned, unsigned> > H2Coords;
2906  H2Coords.reserve(GetNVariables()*GetNVariables() - 1);
2907  // par vs par
2908  for (unsigned i = 0; i < GetNParameters(); ++i)
2909  for (unsigned j = 0; j < GetNParameters(); ++j)
2910  if (MarginalizedHistogramExists(i, j))
2911  H2Coords.push_back(std::make_pair(i, j));
2912  // obs vs par
2913  for (unsigned i = 0; i < GetNParameters(); ++i)
2914  for (unsigned j = GetNParameters(); j < GetNVariables(); ++j)
2915  if (MarginalizedHistogramExists(i, j))
2916  H2Coords.push_back(std::make_pair(i, j));
2917  // par vs obs
2918  for (unsigned i = GetNParameters(); i < GetNVariables(); ++i)
2919  for (unsigned j = 0; j < GetNParameters(); ++j)
2920  if (MarginalizedHistogramExists(i, j))
2921  H2Coords.push_back(std::make_pair(i, j));
2922  // obs vs obs
2923  for (unsigned i = GetNParameters(); i < GetNVariables(); ++i)
2924  for (unsigned j = GetNParameters(); j < GetNVariables(); ++j)
2925  if (MarginalizedHistogramExists(i, j))
2926  H2Coords.push_back(std::make_pair(i, j));
2927 
2928  return H2Coords;
2929 }
2930 
2931 // ---------------------------------------------------------
2932 unsigned BCEngineMCMC::PrintAllMarginalized(const std::string& filename, unsigned hdiv, unsigned vdiv) const
2933 {
2934  if (GetNVariables() == 0) {
2935  BCLog::OutError("BCEngineMCMC::PrintAllMarginalized : No variables defined!");
2936  return 0;
2937  }
2938 
2939  if (fH1Marginalized.empty() && fH2Marginalized.empty()) {
2940  BCLog::OutError("BCEngineMCMC::PrintAllMarginalized : Marginalized distributions not stored.");
2941  return 0;
2942  }
2943  std::string newFilename(filename);
2944  BCAux::DefaultToPDF(newFilename);
2945  if (newFilename.empty())
2946  return 0;
2947 
2948  // Find nonempty H1's
2949  std::vector<unsigned> H1Indices = GetH1DPrintOrder();
2950  std::vector<BCH1D> h1;
2951  h1.reserve(H1Indices.size());
2952  for (unsigned i = 0; i < H1Indices.size(); ++i) {
2953  if (GetMarginalizedHistogram(H1Indices[i])->Integral() == 0) { // histogram was never filled in range
2954  BCLog::OutWarning(Form("BCEngineMCMC::PrintAllMarginalized : 1D Marginalized histogram for \"%s\" is empty; printing is skipped.", GetVariable(H1Indices[i]).GetName().data()));
2955  continue;
2956  }
2957  h1.push_back(GetMarginalized(H1Indices[i]));
2958  if (h1.back().Valid())
2959  h1.back().CopyOptions(fBCH1DdrawingOptions);
2960  else
2961  h1.pop_back();
2962  }
2963 
2964  // Find nonempty H2's
2965  std::vector<std::pair<unsigned, unsigned> > H2Coords = GetH2DPrintOrder();
2966  std::vector<BCH2D> h2;
2967  h2.reserve(H2Coords.size());
2968  for (unsigned k = 0; k < H2Coords.size(); ++k) {
2969  unsigned i = H2Coords[k].first;
2970  unsigned j = H2Coords[k].second;
2971  if (fH2Marginalized[i][j]->Integral() == 0) { // histogram was never filled in range
2972  BCLog::OutWarning(Form("BCEngineMCMC::PrintAllMarginalized : 2D Marginalized histogram for \"%s\":\"%s\" is empty; printing is skipped.", GetVariable(i).GetName().data(), GetVariable(i).GetName().data()));
2973  continue;
2974  }
2975  h2.push_back(GetMarginalized(i, j));
2976  if (h2.back().Valid())
2977  h2.back().CopyOptions(fBCH2DdrawingOptions);
2978  else
2979  h2.pop_back();
2980  }
2981 
2982  return BCAux::PrintPlots(h1, h2, newFilename, hdiv, vdiv);
2983 }
2984 
2985 // ---------------------------------------------------------
2986 unsigned BCEngineMCMC::PrintParameterPlot(const std::string& filename, int npar, double interval_content, std::vector<double> quantiles, bool rescale_ranges) const
2987 {
2988  std::string newFilename(filename);
2989  BCAux::DefaultToPDF(newFilename);
2990  if (newFilename.empty())
2991  return 0;
2992 
2993  TCanvas c_par("c_parplot_init");
2994  c_par.Print(Form("%s[", newFilename.data()));
2995  c_par.cd();
2996  c_par.SetTicky(1);
2997  c_par.SetFrameLineWidth(0);
2998  c_par.SetFrameLineColor(0);
2999 
3000  if (npar <= 0) // all parameters on one page, all user-defined observables on the next
3001  npar = std::max<int> (GetNParameters(), GetNObservables());
3002 
3003  unsigned pages_printed = 0;
3004 
3005  // parameters first
3006  for (unsigned i = 0; i < GetNParameters(); i += npar)
3007  if (DrawParameterPlot(i, std::min<int>(npar, GetNParameters() - i), interval_content, quantiles, rescale_ranges)) {
3008  c_par.Print(newFilename.data());
3009  c_par.Clear();
3010  ++pages_printed;
3011  }
3012 
3013  // then user-defined observables
3014  for (unsigned i = GetNParameters(); i < GetNVariables(); i += npar)
3015  if (DrawParameterPlot(i, std::min<int>(npar, GetNVariables() - i), interval_content, quantiles, rescale_ranges)) {
3016  c_par.Print(newFilename.data());
3017  c_par.Clear();
3018  ++pages_printed;
3019  }
3020 
3021  c_par.Print(Form("%s]", newFilename.data()));
3022  return pages_printed > 0;
3023 }
3024 
3025 // ---------------------------------------------------------
3026 bool BCEngineMCMC::DrawParameterPlot(unsigned i0, unsigned npar, double interval_content, std::vector<double> quantiles, bool rescale_ranges) const
3027 {
3028 
3029  // if npar==0, print all remaining observables
3030  unsigned i1 = (npar > 0 && i0 + npar <= GetNVariables()) ? i0 + npar : GetNVariables();
3031 
3032  if (i1 <= i0) {
3033  BCLog::OutError(Form("BCSummaryTool::PrintParameterPlot : invalid parameter range [%d, %d)", i0, i1));
3034  return false;
3035  }
3036 
3037  // default quantiles
3038  // TO DO: allow for option to use defualt
3039  // quantiles, and option for no quantiles
3040  if (quantiles.empty()) {
3041  quantiles.push_back(05.00e-2);
3042  quantiles.push_back(10.00e-2);
3043  quantiles.push_back(15.87e-2);
3044  quantiles.push_back(50.00e-2);
3045  quantiles.push_back(84.13e-2);
3046  quantiles.push_back(90.00e-2);
3047  quantiles.push_back(95.00e-2);
3048  }
3049 
3050  // store old ranges, and rescale, if rescaling
3051  std::vector<double> original_min;
3052  std::vector<double> original_max;
3053  original_min.reserve(i1 - i0);
3054  original_max.reserve(i1 - i0);
3055  if (rescale_ranges) {
3056  for (unsigned i = i0; i < i1; ++i) {
3057  BCVariable& var = const_cast<BCVariable&>(GetVariable(i));
3058  original_min.push_back(GetVariable(i).GetLowerLimit());
3059  original_max.push_back(GetVariable(i).GetUpperLimit());
3060  if (i < fMCMCStatistics_AllChains.minimum.size() && std::isfinite(fMCMCStatistics_AllChains.minimum[i]))
3062  if (i < fMCMCStatistics_AllChains.maximum.size() && std::isfinite(fMCMCStatistics_AllChains.maximum[i]))
3064  }
3065  }
3066 
3068  // Gather information
3069 
3070  std::vector<double> x_quantiles;
3071  std::vector<double> quantile_vals;
3072  std::vector<double> x_i;
3073  std::vector<double> x_i_bf;
3074  std::vector<double> mean;
3075  std::vector<double> rms;
3076  std::vector<double> global_mode;
3077  std::vector<double> local_mode;
3078  std::vector<double> interval_lo;
3079  std::vector<double> interval_hi;
3080 
3081  for (unsigned i = i0; i < i1; ++i) {
3082 
3083  if (i < GetNParameters() && GetParameter(i).Fixed())
3084  continue;
3085 
3086  // Global Mode
3087  x_i_bf.push_back(i);
3088  global_mode.push_back(GetVariable(i).PositionInRange(GetBestFitParameters()[i]));
3089  mean.push_back(std::numeric_limits<double>::infinity());
3090  rms.push_back(0);
3091 
3092  if (i < fH1Marginalized.size() && fH1Marginalized[i]) {
3093  BCH1D bch1d_temp = GetMarginalized(i);
3094  if (bch1d_temp.Valid()) {
3095 
3096  x_i.push_back(i);
3097 
3098  // quantiles
3099  x_quantiles.insert(x_quantiles.end(), quantiles.size(), i);
3100  std::vector<double> q(quantiles.size(), 0);
3101  bch1d_temp.GetHistogram()->GetQuantiles(quantiles.size(), &q[0], &quantiles[0]);
3102  for (unsigned j = 0; j < quantiles.size(); ++j)
3103  quantile_vals.push_back(GetVariable(i).PositionInRange(q[j]));
3104 
3105  local_mode.push_back(GetVariable(i).PositionInRange(bch1d_temp.GetLocalMode(0)));
3106  mean.back() = GetVariable(i).PositionInRange(bch1d_temp.GetHistogram()->GetMean());
3107  rms.back() = bch1d_temp.GetHistogram()->GetRMS() / GetVariable(i).GetRangeWidth();
3108 
3109  // smallest interval
3110  BCH1D::BCH1DSmallestInterval SI = bch1d_temp.GetSmallestIntervals(interval_content);
3111  if (SI.intervals.empty()) {
3112  interval_lo.push_back(0);
3113  interval_hi.push_back(0);
3114  } else {
3115  interval_lo.push_back(fabs(SI.intervals.front().mode - SI.intervals.front().xmin) / GetVariable(i).GetRangeWidth());
3116  interval_hi.push_back(fabs(SI.intervals.front().mode - SI.intervals.front().xmax) / GetVariable(i).GetRangeWidth());
3117  }
3118  }
3119  }
3120 
3121  // use chain statistics if they exist:
3122  if (i < fMCMCStatistics_AllChains.mean.size() && std::isfinite(fMCMCStatistics_AllChains.mean[i]))
3124  if (i < fMCMCStatistics_AllChains.variance.size() && std::isfinite(fMCMCStatistics_AllChains.variance[i]))
3125  rms.back() = sqrt(fMCMCStatistics_AllChains.variance[i]) / GetVariable(i).GetRangeWidth();
3126  }
3127 
3128  if (x_i.empty() && x_i_bf.empty())
3129  return false;
3130 
3132  // Draw it all
3133 
3134  // axes have a name, the other objects don't, so they are not registered
3135  // with ROOT and we don't need a guard
3136 
3137  // Create, label, and draw axes
3138  TH2D* hist_axes;
3139  {
3141  hist_axes = new TH2D(Form("h2_axes_parplot_%s_%d_%d", GetSafeName().data(), i0, i1), "", //";;Scaled range [a.u.]",
3142  i1 - i0, i0 - 0.5, i1 - 0.5, 10, -0.05 + 1e-3, 1.05 - 1e-3);
3143  }
3144  fObjectTrash.Put(hist_axes);
3145  hist_axes->SetStats(kFALSE);
3146  hist_axes->GetXaxis()->SetAxisColor(0);
3147  hist_axes->GetXaxis()->SetLabelOffset(0.015);
3148  hist_axes->GetXaxis()->SetLabelSize(std::max<double>(0.01, 0.05 * std::min<double>(1, 4. / hist_axes->GetNbinsX())));
3149  hist_axes->GetXaxis()->SetTickLength(0.0);
3150  hist_axes->GetYaxis()->SetLabelSize(0);
3151 
3152  // set bin labels
3153  for (int i = 0; i < hist_axes->GetNbinsX(); ++i)
3154  hist_axes->GetXaxis()->SetBinLabel(i + 1, GetVariable(i0 + i).GetLatexNameWithUnits().data());
3155  hist_axes->Draw("");
3156 
3157  // Draw lines
3158  TLine* line = new TLine();
3159  fObjectTrash.Put(line);
3160  line->SetLineColor(kBlack);
3161  line->SetLineStyle(1);
3162  line->SetLineWidth(2);
3163  line->DrawLine(hist_axes->GetXaxis()->GetXmin(), 0.0, hist_axes->GetXaxis()->GetXmax(), 0.0);
3164  line->DrawLine(hist_axes->GetXaxis()->GetXmin(), 1.0, hist_axes->GetXaxis()->GetXmax(), 1.0);
3165 
3166  // Mark parameter ranges
3167  TLatex* latex = new TLatex();
3168  fObjectTrash.Put(latex);
3169  latex->SetTextSize(0.02);
3170  for (unsigned i = i0; i < i1; ++i)
3171  if (i < GetNParameters() && GetParameter(i).Fixed()) {
3172  latex->SetTextAlign(22);
3173  latex->DrawLatex((double)i, 0.52, "Fixed at");
3174  latex->DrawLatex((double)i, 0.47, Form("%.*g", GetVariable(i).GetPrecision(), GetParameter(i).GetFixedValue()));
3175  } else {
3176  latex->SetTextAlign(21);
3177  latex->DrawLatex((double)i, 1.015, Form("%+.*g", GetVariable(i).GetPrecision(), GetVariable(i).GetUpperLimit()));
3178  latex->SetTextAlign(23);
3179  latex->DrawLatex((double)i, -0.015, Form("%+.*g", GetVariable(i).GetPrecision(), GetVariable(i).GetLowerLimit()));
3180  }
3181 
3182  // create legend
3183  TLegend* legend = new TLegend();
3184  fObjectTrash.Put(legend);
3185  legend->SetBorderSize(0);
3186  legend->SetFillColor(kWhite);
3187  legend->SetNColumns(2);
3188  legend->SetTextAlign(12);
3189  legend->SetTextSize(0.02 * gPad->GetWNDC());
3190 
3191  if (!x_i.empty()) {
3192 
3193  // Smallest Interval
3194  std::vector<double> x_i_err(x_i.size(), 0.5);
3195  TGraphAsymmErrors* graph_intervals = new TGraphAsymmErrors(x_i.size(), x_i.data(), local_mode.data(), x_i_err.data(), x_i_err.data(), interval_lo.data(), interval_hi.data());
3196  fObjectTrash.Put(graph_intervals);
3197  graph_intervals->SetFillColor(kYellow);
3198  graph_intervals->SetLineStyle(2);
3199  graph_intervals->SetLineColor(kRed);
3200  graph_intervals->SetMarkerSize(0);
3201  graph_intervals->DrawClone("SAME2"); // draw area
3202  //set y-error zero, to draw line at local mode
3203  for (int i = 0; i < graph_intervals->GetN(); ++i)
3204  graph_intervals->SetPointError(i, 0.5, 0.5, 0.0, 0.0);
3205  graph_intervals->Draw("SAMEZ"); // draw local mode
3206 
3207  // Quantiles graph
3208  if (!quantiles.empty()) {
3209  std::vector<double> quantiles_err(x_quantiles.size(), 0.5);
3210  TGraphErrors* graph_quantiles = new TGraphErrors(x_quantiles.size(), x_quantiles.data(), quantile_vals.data(), quantiles_err.data(), 0);
3211  fObjectTrash.Put(graph_quantiles);
3212  graph_quantiles->SetMarkerSize(0);
3213  graph_quantiles->SetLineColor(38);
3214  graph_quantiles->SetLineStyle(2);
3215  graph_quantiles->Draw("SAMEZ");
3216  std::string quantiles_text = "Quantiles (";
3217  for (unsigned i = 0; i < quantiles.size() - 1; ++i)
3218  quantiles_text += Form("%.0f%%, ", quantiles[i] * 100);
3219  quantiles_text += (quantiles.size() > 0) ? Form("%.0f%%)", quantiles.back() * 100) : "none)";
3220  legend->AddEntry(graph_quantiles, quantiles_text.c_str(), "L");
3221  }
3222 
3223  // Means & RMSs
3224  TGraphErrors* graph_mean = new TGraphErrors(x_i.size(), x_i.data(), mean.data(), 0, rms.data());
3225  fObjectTrash.Put(graph_mean);
3226  graph_mean->SetMarkerColor(kBlack);
3227  graph_mean->SetMarkerStyle(21);
3228  graph_mean->SetMarkerSize(1 * gPad->GetWNDC());
3229  graph_mean->Draw("SAMEP");
3230 
3231  legend->AddEntry(graph_mean, "Mean and RMS", "LEP");
3232  legend->AddEntry(graph_intervals, Form("Smallest %.0f%% interval and local mode", 100.*interval_content), "FL");
3233  }
3234 
3235  // Global Modes
3236  if (!x_i_bf.empty()) {
3237  TGraph* graph_mode = new TGraph(x_i_bf.size(), x_i_bf.data(), global_mode.data());
3238  fObjectTrash.Put(graph_mode);
3239  graph_mode->SetMarkerColor(kRed);
3240  graph_mode->SetMarkerStyle(20);
3241  graph_mode->SetMarkerSize(1 * gPad->GetWNDC());
3242  graph_mode->Draw("SAMEP");
3243  legend->AddEntry(graph_mode, "Global mode", "P");
3244  }
3245 
3246  gPad->SetTopMargin(0.02);
3247 
3248  // place legend on top of histogram
3249 #if ROOTVERSION >= 6000000
3250  legend->SetX1(gPad->GetLeftMargin());
3251  legend->SetX2(1. - gPad->GetRightMargin());
3252  double y1 = gPad->GetTopMargin() + legend->GetTextSize() * legend->GetNRows();
3253  legend->SetY1(1. - y1);
3254  legend->SetY2(1. - gPad->GetTopMargin());
3255 #else
3256  legend->SetX1NDC(gPad->GetLeftMargin());
3257  legend->SetX2NDC(1. - gPad->GetRightMargin());
3258  double y1 = gPad->GetTopMargin() + legend->GetTextSize() * legend->GetNRows();
3259  legend->SetY1NDC(1. - y1);
3260  legend->SetY2NDC(1. - gPad->GetTopMargin());
3261 #endif
3262  legend->Draw("SAME");
3263 
3264  gPad->SetTopMargin(y1 + 0.01);
3265 
3266  gPad->RedrawAxis();
3267  gPad->Update();
3268 
3269  // restore ranges
3270  for (unsigned i = 0; i < original_min.size(); ++i)
3271  const_cast<BCVariable&>(GetVariable(i0 + i)).SetLimits(original_min[i], original_max[i]);
3272 
3273  // no error
3274  return true;
3275 }
3276 
3277 // ---------------------------------------------------------
3278 bool BCEngineMCMC::PrintCorrelationMatrix(const std::string& filename) const
3279 {
3280  if (GetNVariables() == 0) {
3281  BCLog::OutError("BCEngineMCMC::PrintCorrelationMatrix : No variables defined!");
3282  return 0;
3283  }
3284 
3285  // create histogram
3286  TH2D hist_corr(Form("hist_correlation_matrix_%s", GetSafeName().data()), ";;", GetNVariables(), -0.5, GetNVariables() - 0.5, GetNVariables(), -0.5, GetNVariables() - 0.5);
3287  hist_corr.SetStats(false);
3288  hist_corr.GetXaxis()->SetTickLength(0.0);
3289  hist_corr.GetYaxis()->SetTickLength(0.0);
3290  hist_corr.GetXaxis()->SetLabelSize(0);
3291  hist_corr.GetYaxis()->SetLabelSize(0);
3292 
3293  // vector of unfilled values:
3294  std::vector<std::pair<unsigned, unsigned> > unfilled;
3295 
3296  // fill histogram
3297  for (unsigned i = 0; i < GetNVariables(); ++i) {
3298  hist_corr.SetBinContent(i + 1, GetNVariables() - i, 1);
3299 
3300  double var_i = (i < fMCMCStatistics_AllChains.variance.size()) ? fMCMCStatistics_AllChains.variance[i] : std::numeric_limits<double>::infinity();
3301  for (unsigned j = i + 1; j < GetNVariables(); ++j) {
3302  double var_j = (j < fMCMCStatistics_AllChains.variance.size()) ? fMCMCStatistics_AllChains.variance[j] : std::numeric_limits<double>::infinity();
3303  double covar_ij = (i < fMCMCStatistics_AllChains.covariance.size() && j < fMCMCStatistics_AllChains.covariance[i].size()) ? fMCMCStatistics_AllChains.covariance[i][j] : std::numeric_limits<double>::infinity();
3304  double corr_ij = std::numeric_limits<double>::infinity();
3305  if (std::isfinite(covar_ij) && std::isfinite(var_i) && std::isfinite(var_j))
3306  corr_ij = covar_ij / sqrt(var_i * var_j);
3307  else if (i < fH2Marginalized.size() && j < fH2Marginalized[i].size() && fH2Marginalized[i][j])
3308  corr_ij = fH2Marginalized[i][j]->GetCorrelationFactor();
3309  else if (j < fH2Marginalized.size() && i < fH2Marginalized[j].size() && fH2Marginalized[j][i])
3310  corr_ij = fH2Marginalized[j][i]->GetCorrelationFactor();
3311  if (std::isfinite(corr_ij)) {
3312  hist_corr.SetBinContent(i + 1, GetNVariables() - j, corr_ij);
3313  hist_corr.SetBinContent(j + 1, GetNVariables() - i, corr_ij);
3314  } else {
3315  unfilled.push_back(std::make_pair(i, j));
3316  }
3317  }
3318  }
3319 
3320  // print to file
3321  TCanvas c_corr("c_corr_matrix");
3322  c_corr.cd();
3323 
3324  double text_size = std::max<double>(0.005, 0.02 * std::min<double>(1., 5. / GetNVariables()));
3325 
3326  TLatex xlabel;
3327  xlabel.SetTextSize(text_size);
3328  xlabel.SetTextAlign(22);
3329 
3330  TLatex ylabel;
3331  ylabel.SetTextSize(text_size);
3332  ylabel.SetTextAlign(22);
3333  ylabel.SetTextAngle(90);
3334 
3335  TLatex corr_number;
3336  corr_number.SetTextSize(text_size);
3337  corr_number.SetTextAlign(22);
3338 
3339  gStyle->SetPalette(54);
3340  gStyle->SetPaintTextFormat("+.2g");
3341  hist_corr.GetZaxis()->SetRangeUser(-1, 1);
3342  hist_corr.GetZaxis()->SetDecimals(true);
3343  hist_corr.GetZaxis()->SetLabelSize(text_size);
3344  hist_corr.Draw("colz");
3345 
3346  // Draw labels and correlations
3347  for (int i = 1; i <= hist_corr.GetNbinsX(); ++i) {
3348  // labels
3349  xlabel.DrawLatex(hist_corr.GetXaxis()->GetBinCenter(i),
3350  hist_corr.GetYaxis()->GetXmax() + 12e-2,
3351  GetVariable(i - 1).GetLatexNameWithUnits().data());
3352 
3353  ylabel.DrawLatex(hist_corr.GetXaxis()->GetXmin() - 12e-2,
3354  hist_corr.GetYaxis()->GetBinCenter(GetNVariables() - i + 1),
3355  GetVariable(i - 1).GetLatexNameWithUnits().data());
3356  for (int j = 1; j <= hist_corr.GetNbinsY(); ++j) {
3357  if (hist_corr.GetBinContent(i, j) >= 0)
3358  corr_number.SetTextColor(kBlack);
3359  else
3360  corr_number.SetTextColor(kWhite);
3361  corr_number.DrawLatex(hist_corr.GetXaxis()->GetBinCenter(i),
3362  hist_corr.GetYaxis()->GetBinCenter(j),
3363  Form("%+.2g", hist_corr.GetBinContent(i, j)));
3364  }
3365  }
3366 
3367  // Blank out empty squares
3368  TBox bcorr;
3369  bcorr.SetFillColor(kWhite);
3370  for (unsigned i = 0; i < unfilled.size(); ++i) {
3371  bcorr.DrawBox(hist_corr.GetXaxis()->GetBinLowEdge(unfilled[i].first + 1), hist_corr.GetYaxis()->GetBinLowEdge(GetNVariables() - unfilled[i].second),
3372  hist_corr.GetXaxis()->GetBinUpEdge (unfilled[i].first + 1), hist_corr.GetYaxis()->GetBinUpEdge (GetNVariables() - unfilled[i].second));
3373  bcorr.DrawBox(hist_corr.GetXaxis()->GetBinLowEdge(unfilled[i].second + 1), hist_corr.GetYaxis()->GetBinLowEdge(GetNVariables() - unfilled[i].first),
3374  hist_corr.GetXaxis()->GetBinUpEdge (unfilled[i].second + 1), hist_corr.GetYaxis()->GetBinUpEdge (GetNVariables() - unfilled[i].first));
3375  }
3376 
3377  // redraw top and right lines
3378  TLine lA;
3379  lA.DrawLine(hist_corr.GetXaxis()->GetXmin(), hist_corr.GetYaxis()->GetXmax(), hist_corr.GetXaxis()->GetXmax(), hist_corr.GetYaxis()->GetXmax());
3380  lA.DrawLine(hist_corr.GetXaxis()->GetXmax(), hist_corr.GetYaxis()->GetXmin(), hist_corr.GetXaxis()->GetXmax(), hist_corr.GetYaxis()->GetXmax());
3381  // draw line between parameters and user-defined observables
3382  if (GetNObservables() > 0) {
3383  lA.DrawLine(hist_corr.GetXaxis()->GetXmin() - 0.40, hist_corr.GetYaxis()->GetBinLowEdge(hist_corr.GetNbinsY() - GetNParameters() + 1),
3384  hist_corr.GetXaxis()->GetBinUpEdge(GetNParameters()), hist_corr.GetYaxis()->GetBinLowEdge(hist_corr.GetNbinsY() - GetNParameters() + 1));
3385  lA.DrawLine(hist_corr.GetXaxis()->GetBinUpEdge(GetNParameters()), hist_corr.GetYaxis()->GetBinLowEdge(hist_corr.GetNbinsY() - GetNParameters() + 1),
3386  hist_corr.GetXaxis()->GetBinUpEdge(GetNParameters()), hist_corr.GetYaxis()->GetXmax() + 0.45);
3387  }
3388 
3389  gPad->RedrawAxis();
3390  c_corr.Print(filename.data());
3391 
3392  // no error
3393  return true;
3394 }
3395 
3396 // ---------------------------------------------------------
3397 bool BCEngineMCMC::PrintCorrelationPlot(const std::string& filename, bool include_observables) const
3398 {
3399  if (GetNVariables() == 0) {
3400  BCLog::OutError("BCEngineMCMC::PrintCorrelationPlot : No variables defined!");
3401  return 0;
3402  }
3403 
3404  // Array of indices for which any marginalizations were stored
3405  std::vector<unsigned> I;
3406  unsigned n = (include_observables) ? GetNVariables() : GetNParameters();
3407  for (unsigned i = 0; i < n && i < fH1Marginalized.size(); ++i) {
3409  I.push_back(i);
3410  else {
3411  for (unsigned j = 0; j < n && j < fH2Marginalized[i].size(); ++j)
3412  if (i != j && MarginalizedHistogramExists(i, j)) {
3413  I.push_back(i);
3414  break;
3415  }
3416  }
3417  }
3418 
3419  if (I.empty()) {
3420  BCLog::OutError("BCEngineMCMC::PrintCorrelationPlot : Marginalized distributions not stored. Cannot print correlation plots.");
3421  return false;
3422  }
3423 
3424  TCanvas c("c_correlation_plot");
3425  c.cd();
3426 
3427  double margin = 0.1;
3428  double padsize = (1 - 2 * margin) / I.size();
3429 
3430  // array with pads holding the histograms
3431  std::vector<std::vector<TPad*> > pad (I.size(), std::vector<TPad*>(I.size(), NULL));
3432 
3433  // position of pads
3434  double xlow, xup, ylow, yup;
3435  double margintop = 0.01;
3436  double marginbottom = margintop;
3437  double marginleft = margintop;
3438  double marginright = marginleft;
3439 
3440  TLatex ylabel;
3441  ylabel.SetTextSize(5e-2 / I.size());
3442  ylabel.SetTextAlign(22); // set to 32, if latex names too long
3443  ylabel.SetNDC();
3444  ylabel.SetTextAngle(90); // set to 80, if latex names too long
3445 
3446  TLatex xlabel;
3447  xlabel.SetTextSize(5e-2 / I.size());
3448  xlabel.SetTextAlign(22); // set to 12, if latex names too long
3449  xlabel.SetNDC();
3450  xlabel.SetTextAngle(0); // set to 350, if latex names too long
3451 
3452  // Box + Text for empty squares:
3453  TText text_na;
3454  text_na.SetTextAlign(22);
3455  text_na.SetTextSize(8e-1 / I.size());
3456  text_na.SetTextColor(kGray);
3457 
3458  // store histograms for persistency for ROOT until drawing is saved
3459  std::vector<BCHistogramBase*> bh;
3460 
3461  // drawing all histograms
3462  for (unsigned i = 0; i < I.size(); ++i) {
3463  xlow = i * padsize + margin;
3464  xup = xlow + padsize;
3465 
3466  for (unsigned j = 0; j < I.size(); ++j) {
3467  yup = 1. - j * padsize - margin;
3468  ylow = yup - padsize;
3469 
3470  // preparing the pad
3471  {
3473  pad[i][j] = new TPad(Form("pad_correlation_plots_%d_%d", i, j), "", xlow, ylow, xup, yup);
3474  // despite the guard, the pads are deleted before the trash
3475  // cleans up, which leads to a double-delete problem
3476  // fObjectTrash.Put(pad[i][j]);
3477  }
3478  pad[i][j]->SetMargin(marginleft, marginright, marginbottom, margintop);
3479  pad[i][j]->SetFillColor(kWhite);
3480  pad[i][j]->Draw();
3481  pad[i][j]->cd();
3482 
3483  if (i == j)
3484  bh.push_back(new BCH1D(GetMarginalized(I[i])));
3485  else {
3486  if (MarginalizedHistogramExists(I[i], I[j]))
3487  bh.push_back(new BCH2D(GetMarginalized(I[i], I[j])));
3488  else
3489  bh.push_back(NULL);
3490  }
3491  // bh = MarginalizedHistogramExists(I[i], I[j]) ? GetMarginalized(I[i], I[j]) : NULL;
3492 
3493  if (bh.back()) {
3494 
3495  bh.back()->GetHistogram()->GetXaxis()->SetLabelSize(0);
3496  bh.back()->GetHistogram()->GetYaxis()->SetLabelSize(0);
3497  bh.back()->GetHistogram()->GetXaxis()->SetTitleSize(0);
3498  bh.back()->GetHistogram()->GetYaxis()->SetTitleSize(0);
3499 
3500  if (bh.back()->GetHistogram()->GetDimension() == 1)
3501  bh.back()->CopyOptions(fBCH1DdrawingOptions);
3502  else if (bh.back()->GetHistogram()->GetDimension() == 2)
3503  bh.back()->CopyOptions(fBCH2DdrawingOptions);
3504  bh.back()->SetDrawLegend(false);
3505  bh.back()->SetStats(false);
3506  bh.back()->Draw();
3507 
3508  } else if (!(MarginalizedHistogramExists(I[j], I[i])) && I[i] >= I[j]) { // if the histogram is not available, draw "N/A"
3509  // pad[i][j]->SetFillColor(kWhite);
3510  text_na.DrawText(.5, .5, "N/A");
3511  }
3512 
3513  c.cd();
3514 
3515  if (i == 0) // y-axis labels
3516  ylabel.DrawLatex(margin * (1 - 8 * ylabel.GetTextSize()), yup - padsize / 2., GetVariable(I[j]).GetLatexNameWithUnits().data());
3517  if (j == I.size() - 1) // x-axis labels
3518  xlabel.DrawLatex(xlow + padsize / 2., margin * (1 - 8 * xlabel.GetTextSize()), GetVariable(I[i]).GetLatexNameWithUnits().data());
3519  }
3520  }
3521 
3522  // gPad->RedrawAxis();
3523  c.Print(filename.data());
3524 
3525  // delete BCHistogramBase objects
3526  for (unsigned i = 0; i < bh.size(); ++i)
3527  delete bh[i];
3528 
3529  return true;
3530 }
3531 
3532 // ---------------------------------------------------------
3533 bool BCEngineMCMC::PrintParameterLatex(const std::string& filename) const
3534 {
3535  // open file
3536  std::ofstream ofi(filename.data());
3537  ofi.precision(3);
3538 
3539  // check if file is open
3540  if (!ofi.is_open()) {
3541  BCLog::OutError("BCEngineMCMC::PrintParameterLatex : Couldn't open file " + filename + ".");
3542  return false;
3543  }
3544 
3545  const char* blank = "---";
3546  unsigned texwidth = 15;
3547 
3548  // print table
3549  ofi << "\\documentclass[11pt, a4paper]{article}\n\n"
3550  << "\\usepackage[landscape]{geometry}\n\n"
3551  << "\\begin{document}\n\n"
3552  << " \\begin{table}[ht!]\n\n"
3553  << " \\begin{center}\n\n"
3554  << " \\begin{tabular}{llllllll}\n\n"
3555  << " Parameter &\n"
3556  << Form(" %*s & %*s & %*s & %*s & %*s & %*s & %*s\\\\\n",
3557  texwidth, "Mean",
3558  texwidth, "RMS",
3559  texwidth, "Gl. Mode",
3560  texwidth, "Mode",
3561  texwidth, "Median",
3562  texwidth, "16\\% quant.",
3563  texwidth, "84\\% quant.")
3564  << " \\hline\n" << std::endl;
3565 
3566  for (unsigned i = 0; i < GetNVariables(); ++i) {
3567 
3568  if (i == GetNParameters()) // first user-defined observable
3569  ofi << " &\\\\\n"
3570  << " User-defined Observable &\n"
3571  << Form(" %*s & %*s & %*s & %*s & %*s & %*s & %*s\\\\\n",
3572  texwidth, "Mean",
3573  texwidth, "RMS",
3574  texwidth, "Gl. Mode",
3575  texwidth, "Mode",
3576  texwidth, "Median",
3577  texwidth, "16\\% quant.",
3578  texwidth, "84\\% quant.")
3579  << " \\hline\n" << std::endl;
3580 
3581  // formate LaTeX name for LaTeX ('#'->'\')
3582  std::string latexName(GetVariable(i).GetLatexNameWithUnits());
3583  std::replace(latexName.begin(), latexName.end(), '#', '\\');
3584 
3585  ofi << " \\ensuremath{" << latexName << "} &" << std::endl;
3586 
3587  unsigned prec = GetVariable(i).GetPrecision();
3588 
3589  // fixed parameter
3590  if (i < GetNParameters() && GetParameter(i).Fixed())
3591  ofi << Form(" \\multicolumn{7}{c}{--- fixed to %*.*g ---}\\\\\n", texwidth, prec, GetParameter(i).GetFixedValue()) << std::endl;
3592 
3593  // not fixed
3594  else {
3595  BCH1D bch1d = GetMarginalized(i);
3596 
3597  // marginalization exists
3598  if (bch1d.Valid())
3599  ofi << Form(" %*.*g & %*.*g & %*.*g & %*.*g & %*.*g & %*.*g & %*.*g\\\\\n",
3600  texwidth, prec, bch1d.GetHistogram()->GetMean(),
3601  texwidth, prec, bch1d.GetHistogram()->GetRMS(),
3602  texwidth, prec, GetBestFitParameters()[i],
3603  texwidth, prec, bch1d.GetLocalMode(0),
3604  texwidth, prec, bch1d.GetMedian(),
3605  texwidth, prec, bch1d.GetQuantile(0.16),
3606  texwidth, prec, bch1d.GetQuantile(0.84))
3607  << std::endl;
3608 
3609  // marginalization does not exist
3610  else
3611  ofi << Form(" %*s & %*s & %*.*g & %*s & %*s & %*s & %*s\\\\\n",
3612  texwidth, blank,
3613  texwidth, blank,
3614  texwidth, prec, GetBestFitParameters()[i],
3615  texwidth, blank,
3616  texwidth, blank,
3617  texwidth, blank,
3618  texwidth, blank)
3619  << std::endl;
3620  }
3621  }
3622 
3623  ofi << " \\hline\n" << std::endl
3624  << " \\end{tabular}\n" << std::endl
3625  << " \\caption{Summary of the parameter estimates.}\n" << std::endl
3626  << " \\end{center}\n" << std::endl
3627  << " \\end{table}" << std::endl
3628  << std::endl
3629  << "\\end{document}" << std::endl;
3630 
3631  // close file
3632  ofi.close();
3633 
3634  // no error
3635  return true;
3636 }
3637 
3638 // ---------------------------------------------------------
3639 unsigned BCEngineMCMC::UpdateFrequency(unsigned N) const
3640 {
3641  int n = N / 10;
3642  if (n < 100)
3643  return 100;
3644  if (n < 10000)
3645  return 1000;
3646  if (n < 100000)
3647  return 10000;
3648  return 100000;
3649 }
3650 
3651 // ---------------------------------------------------------
3652 BCEngineMCMC::ThreadLocalStorage::ThreadLocalStorage(unsigned dim) :
3653  parameters(dim, 0.0),
3654  log_prior(-std::numeric_limits<double>::infinity()),
3655  log_likelihood(-std::numeric_limits<double>::infinity()),
3656  log_probability(-std::numeric_limits<double>::infinity()),
3657  rng(new TRandom3(0)),
3658  yLocal(dim)
3659 {
3660 }
3661 
3662 // ---------------------------------------------------------
3663 BCEngineMCMC::ThreadLocalStorage::ThreadLocalStorage(const ThreadLocalStorage& other) :
3664  parameters(other.parameters),
3665  log_prior(other.log_prior),
3666  log_likelihood(other.log_likelihood),
3667  log_probability(other.log_probability),
3668  rng(new TRandom3(*other.rng)),
3669  yLocal(other.yLocal)
3670 {
3671 }
3672 
3673 // ---------------------------------------------------------
3674 BCEngineMCMC::ThreadLocalStorage& BCEngineMCMC::ThreadLocalStorage::operator = (ThreadLocalStorage other)
3675 {
3676  swap(*this, other);
3677  return *this;
3678 }
3679 
3680 void BCEngineMCMC::ThreadLocalStorage::swap(BCEngineMCMC::ThreadLocalStorage& A, BCEngineMCMC::ThreadLocalStorage& B)
3681 {
3682  std::swap(A.parameters, B.parameters);
3683  std::swap(A.log_prior, B.log_prior);
3684  std::swap(A.log_likelihood, B.log_likelihood);
3685  std::swap(A.log_probability, B.log_probability);
3686  std::swap(A.rng, B.rng);
3687  std::swap(A.yLocal, B.yLocal);
3688 }
3689 
3690 // ---------------------------------------------------------
3691 BCEngineMCMC::ThreadLocalStorage::~ThreadLocalStorage()
3692 {
3693  delete rng;
3694 }
3695 
3696 // ---------------------------------------------------------
3697 double BCEngineMCMC::ThreadLocalStorage::scale(double dof)
3698 {
3699  // when Z is normally distributed with expected value 0 and std deviation sigma
3700  // and V is chi-squared distributed with dof degrees of freedom
3701  // and Z and V are independent
3702  // then Z*sqrt(dof/V) is t-distributed with dof degrees of freedom and std deviation sigma
3703  if (dof <= 0)
3704  return 1;
3705  const double chi2 = BCMath::Random::Chi2(rng, dof);
3706  return sqrt(dof / chi2);
3707 }
3708 
3709 // ---------------------------------------------------------
3710 void BCEngineMCMC::SyncThreadStorage()
3711 {
3712  if (fMCMCNChains > fMCMCThreadLocalStorage.size())
3713  fRandom.Rndm(); // fix return value of GetSeed()
3714 
3715  // add storage until equal to number of chains
3716  fMCMCThreadLocalStorage.reserve(fMCMCNChains);
3717  while (fMCMCThreadLocalStorage.size() < fMCMCNChains)
3718  fMCMCThreadLocalStorage.push_back(ThreadLocalStorage(GetNParameters()));
3719 
3720  // remove storage until equal to number of chains
3721  while (fMCMCThreadLocalStorage.size() > fMCMCNChains)
3722  fMCMCThreadLocalStorage.pop_back();
3723 
3724  // reserve memory to map each thread to a chain. Initially all zero to
3725  // handle calling LogEval in a serial context.
3726  int nthreads = 1;
3727 #if THREAD_PARALLELIZATION
3728  nthreads = omp_get_max_threads();
3729 #endif
3730  fChainIndex.assign(nthreads, 0);
3731 
3732  // update for each chain
3733  for (unsigned i = 0; i < fMCMCThreadLocalStorage.size(); ++i) {
3734  // need full number of parameters, this is passed into user function
3735  fMCMCThreadLocalStorage[i].parameters.assign(GetNParameters(), 0.0);
3736  // need only free parameters, these ones are transformed by Cholesky
3737  fMCMCThreadLocalStorage[i].yLocal.ResizeTo(GetNFreeParameters());
3738 
3739  fMCMCThreadLocalStorage[i].log_prior = -std::numeric_limits<double>::infinity();
3740  fMCMCThreadLocalStorage[i].log_likelihood = -std::numeric_limits<double>::infinity();
3741  fMCMCThreadLocalStorage[i].log_probability = -std::numeric_limits<double>::infinity();
3742 
3743  // each chains gets a different seed. fRandom always returns same seed after the fixing done above
3744  fMCMCThreadLocalStorage[i].rng->SetSeed(fRandom.GetSeed() + i);
3745  fMCMCThreadLocalStorage[i].rng->Rndm();
3746  }
3747 }
3748 
3749 // ---------------------------------------------------------
3751 {
3752  int id = 0;
3753 #if THREAD_PARALLELIZATION
3754  id = omp_get_thread_num();
3755 #endif
3756  fChainIndex.at(id) = chain;
3757 }
3758 
3759 // ---------------------------------------------------------
3760 BCEngineMCMC::Statistics::Statistics(unsigned n_par, unsigned n_obs) :
3761  n_samples(0),
3762  mean(n_par + n_obs, 0),
3763  variance(mean.size(), 0),
3764  stderrpar(n_par, 0),
3765  stderrobs(n_obs, 0),
3766  covariance(mean.size(), std::vector<double>(mean.size(), 0)),
3767  minimum(mean.size(), +std::numeric_limits<double>::infinity()),
3768  maximum(mean.size(), -std::numeric_limits<double>::infinity()),
3769  probability_mean(0),
3770  probability_variance(0),
3771  modepar(n_par, 0),
3772  modeobs(n_obs, 0),
3773  probability_at_mode(-std::numeric_limits<double>::infinity()),
3774  n_samples_efficiency(0),
3775  efficiency(n_par, 0.)
3776 {
3777 }
3778 
3779 // ---------------------------------------------------------
3780 void BCEngineMCMC::Statistics::Clear(bool clear_mode, bool clear_efficiency)
3781 {
3782  n_samples = 0;
3783  mean.clear();
3784  variance.clear();
3785  stderrpar.clear();
3786  stderrobs.clear();
3787  covariance.clear();
3788  minimum.clear();
3789  maximum.clear();
3790  probability_mean = 0;
3792  if (clear_mode) {
3793  probability_at_mode = -std::numeric_limits<double>::infinity();
3794  modepar.clear();
3795  modeobs.clear();
3796  }
3797  if (clear_efficiency) {
3799  efficiency.clear();
3800  }
3801 }
3802 
3803 // ---------------------------------------------------------
3804 void BCEngineMCMC::Statistics::Init(unsigned n_par, unsigned n_obs)
3805 {
3806  n_samples = 0;
3807  mean.assign(n_par + n_obs, 0);
3808  variance.assign(mean.size(), 0);
3809  stderrpar.assign(n_par, 0);
3810  stderrobs.assign(n_obs, 0);
3811  covariance.assign(mean.size(), std::vector<double>(mean.size(), 0));
3812  minimum.assign(mean.size(), +std::numeric_limits<double>::infinity());
3813  maximum.assign(mean.size(), -std::numeric_limits<double>::infinity());
3814  probability_mean = 0;
3816  probability_at_mode = -std::numeric_limits<double>::infinity();
3817  modepar.assign(n_par, 0);
3818  modeobs.assign(n_obs, 0);
3820  efficiency.assign(n_par, 0.);
3821 }
3822 
3823 // ---------------------------------------------------------
3824 void BCEngineMCMC::Statistics::Reset(bool reset_mode, bool reset_efficiency)
3825 {
3826  n_samples = 0;
3827  mean.assign(mean.size(), 0);
3828  variance.assign(variance.size(), 0);
3829  stderrpar.assign(stderrpar.size(), 0);
3830  stderrobs.assign(stderrobs.size(), 0);
3831  covariance.assign(covariance.size(), std::vector<double>(covariance.front().size(), 0));
3832  minimum.assign(minimum.size(), +std::numeric_limits<double>::infinity());
3833  maximum.assign(maximum.size(), -std::numeric_limits<double>::infinity());
3834  probability_mean = 0;
3836  if (reset_mode) {
3837  probability_at_mode = -std::numeric_limits<double>::infinity();
3838  modepar.assign(modepar.size(), 0);
3839  modeobs.assign(modeobs.size(), 0);
3840  }
3841  if (reset_efficiency) {
3842  efficiency.assign(efficiency.size(), 0);
3844  }
3845 }
3846 
3847 // ---------------------------------------------------------
3849 {
3850  efficiency.assign(efficiency.size(), 0);
3852 }
3853 
3854 // ---------------------------------------------------------
3856 {
3857  if (mean.size() != cs.parameters.size() + cs.observables.size())
3858  return;
3859 
3860  // increment number of samples
3861  ++n_samples;
3862 
3863  // check mode
3865  modepar = cs.parameters;
3866  modeobs = cs.observables;
3868  }
3869 
3870  // update probability mean and variance
3871  double prob_delta = cs.log_probability - probability_mean;
3872  probability_mean += prob_delta / n_samples;
3873  probability_variance += (n_samples > 1) ? prob_delta * prob_delta / n_samples - probability_variance / (n_samples - 1) : 0;
3874 
3875  // update parameter means and (co)variances, and maxima and minima:
3876 
3877  // vector to store difference from current mean
3878  std::vector<double> delta(mean.size(), 0);
3879 
3880  // loop over values
3881  for (unsigned i = 0; i < mean.size(); ++i) {
3882  // get value
3883  double x = (i < cs.parameters.size()) ? cs.parameters[i] : cs.observables[i - cs.parameters.size()];
3884  // store difference to current mean
3885  delta[i] = x - mean[i];
3886  // update mean
3887  mean[i] += delta[i] / n_samples;
3888  // update variance
3889  variance[i] += (n_samples > 1) ? delta[i] * delta[i] / n_samples - variance[i] / (n_samples - 1.) : 0;
3890  // update minimum & maximum
3891  minimum[i] = std::min(minimum[i], x);
3892  maximum[i] = std::max(maximum[i], x);
3893  }
3894  // update covariances
3895  if (n_samples > 1) {
3896  for (unsigned i = 0; i < mean.size(); ++i)
3897  for (unsigned j = i; j < mean.size(); ++j)
3898  covariance[i][j] += delta[i] * delta[j] / n_samples - covariance[i][j] / (n_samples - 1);
3899  }
3900  // update stderrors
3901  for (unsigned i = 0; i < modepar.size(); ++i)
3902  stderrpar[i] = std::sqrt(variance[i]);
3903  for (unsigned i = 0; i < modeobs.size(); ++i)
3904  stderrobs[i] = std::sqrt(variance[stderrpar.size() + i]);
3905 }
3906 
3907 // ---------------------------------------------------------
3909 {
3910  // if rhs is empty
3911  if (rhs.n_samples == 0)
3912  return *this;
3913 
3914  // if this is empty
3915  if (n_samples == 0)
3916  return operator=(rhs);
3917 
3918  if (mean.size() != rhs.mean.size())
3919  return *this;
3920 
3921  // check mode:
3924  modepar = rhs.modepar;
3925  modeobs = rhs.modeobs;
3926  }
3927 
3928  double n = n_samples + rhs.n_samples;
3929  double N = (n > 0) ? n_samples * rhs.n_samples / n : 0;
3930 
3933 
3934  // parameter variables:
3935  for (unsigned i = 0; i < mean.size(); ++i) {
3936  // check minimum
3937  if (rhs.minimum[i] < minimum[i])
3938  minimum[i] = rhs.minimum[i];
3939  // check maximum
3940  if (rhs.maximum[i] > maximum[i])
3941  maximum[i] = rhs.maximum[i];
3942  // combine variances
3943  variance[i] = (variance[i] * (n_samples - 1) + rhs.variance[i] * (rhs.n_samples - 1) + (rhs.mean[i] - mean[i]) * (rhs.mean[i] - mean[i]) * N) / (n - 1);
3944  // combine covariances
3945  for (unsigned j = 0; j < covariance[i].size(); ++j)
3946  covariance[i][j] = (covariance[i][j] * (n_samples - 1) + rhs.covariance[i][j] * (rhs.n_samples - 1) + (rhs.mean[i] - mean[i]) * (rhs.mean[j] - mean[j]) * N) / (n - 1);
3947  // combine means
3948  mean[i] = (n_samples * mean[i] + rhs.n_samples * rhs.mean[i]) / n;
3949  }
3950  // update stderrors
3951  for (unsigned i = 0; i < stderrpar.size(); ++i)
3952  stderrpar[i] = std::sqrt(variance[i]);
3953  for (unsigned i = 0; i < stderrobs.size(); ++i)
3954  stderrobs[i] = std::sqrt(variance[stderrpar.size() + i]);
3955 
3956  // combine n_samples
3957  n_samples = n;
3958 
3959  // combine efficiencies
3960  double n_eff = n_samples_efficiency + rhs.n_samples_efficiency;
3961  if (n_eff > 0)
3962  for (unsigned i = 0; i < efficiency.size(); ++i)
3963  efficiency[i] = (n_samples_efficiency * efficiency[i] + rhs.n_samples_efficiency * rhs.efficiency[i]) / (n_eff);
3964 
3965  // combine efficiency samples
3966  n_samples_efficiency = n_eff;
3967 
3968  return *this;
3969 }
void SetProposeMultivariate(bool flag)
Set flag to true to turn on the multivariate proposal for MCMC based on (Haario et al...
Definition: BCEngineMCMC.h:859
BCEngineMCMC & operator=(const BCEngineMCMC &)
Copy-assignment operator.
std::vector< double > maximum
maximum value of variables
Definition: BCEngineMCMC.h:201
BCH2D fBCH2DdrawingOptions
A BCH2D (with no histogram) for storing BCH2D drawing options.
void ResetEfficiencies()
reset efficiencies
virtual void SetPrior(BCPrior *const prior)
Set prior.
virtual void ResetResults()
Reset the MCMC variables.
virtual TH1 * CreateH1(const std::string &name) const
Creates a 1D Histogram for this variable.
Definition: BCVariable.cxx:132
std::vector< TMatrixDSym > fMultivariateProposalFunctionCovariance
Covariance matrices used in multivariate proposal functions.
virtual std::vector< double > GetUniformRandomValues(TRandom *const R) const
Get vector of values uniformly distributed in parameter ranges (or at fixed values, if fixed)
bool MetropolisPreRun()
Runs a pre run for the Metropolis algorithm.
bool MarginalizedHistogramExists(unsigned index) const
Definition: BCEngineMCMC.h:511
void Reset(bool reset_mode=true, bool reset_efficiency=true)
reset all members
ChainState fMCMCTree_State
MC state object for storing into tree.
std::vector< std::vector< double > > fMCMCInitialPosition
The intial position of each Markov chain.
void SetName(const std::string &name)
Sets the name of the engine.
BCObservable & GetObservable(unsigned index)
Definition: BCEngineMCMC.h:685
BCObservableSet fObservables
User-calculated Observables Set.
void SetNLag(unsigned n)
Sets the lag of the Markov chains.
virtual void PrintSummary() const
Print summary of variable set to logs.
virtual unsigned Size() const
Number of variables contained.
double GetLocalMode()
Definition: BCH1D.h:78
void Update(const ChainState &cs)
update statistics given a new chain state
virtual void Remarginalize(bool autorange=true)
Marginalize from TTree.
bool fCorrectRValueForSamplingVariability
flag for correcting R value for initial sampling variability.
virtual bool Fix(double value)
Fix parameter to value (set prior to delta).
Definition: BCParameter.h:141
T * OwnClone(const T *o)
Create a clone of the input but avoid registering the object with ROOT so it cannot be deleted twice...
Definition: BCAux.h:189
unsigned n_samples
number of samples used to calculate statistics
Definition: BCEngineMCMC.h:194
void InChainFillTree()
Write all chain states to the tree.
virtual void CalculateObservables(const std::vector< double > &pars)
Evaluates user-defined observables.
unsigned GetNChains() const
Definition: BCEngineMCMC.h:279
virtual ~BCEngineMCMC()
Destructor.
Statistics(unsigned n_par=0, unsigned n_obs=0)
Constructor.
double GetQuantile(double probability)
Returns the quantile of the distribution.
Definition: BCH1D.cxx:68
A class to represent a split-Gaussian prior of a parameter.
virtual bool AddParameter(const std::string &name, double min, double max, const std::string &latexname="", const std::string &unitstring="")
void UpdateChainIndex(int chain)
Keep track of which chain is currently computed (within a thread).
TTree * fParameterTree
The tree containing the parameter information.
void LoadMCMC(const std::string &filename, std::string mcmcTreeName="", std::string parameterTreeName="", bool loadObservables=true)
Load previous MCMC run.
unsigned n_samples_efficiency
number of samples used to calculate efficiencies
Definition: BCEngineMCMC.h:207
virtual void MCMCUserIterationInterface()
Interface allowing to execute arbitrary code for each iteration of the MCMC while running the chains ...
bool GetNewPointMetropolis()
Generate a new point using the Metropolis algorithm for all chains.
static double RValue(const std::vector< double > &means, const std::vector< double > &variances, unsigned n, bool correctForSamplingVariability=true)
Calculate R value of set of batches of samples—represented by their means and variances, all batches containing the same number of samples—according to Brooks & Gelman, "General Methods for Monitoring Convergence of Iterative Simulations," (1988)
std::string fMCMCOutputFileOption
Output file open option for for writing MCMC Tree.
bool Metropolis()
Runs Metropolis algorithm.
virtual std::vector< std::pair< unsigned, unsigned > > GetH2DPrintOrder() const
A guard object to prevent ROOT from taking over ownership of TNamed objects.
Definition: BCAux.h:171
virtual void PrintBestFitSummary() const
Print best fit to log.
std::vector< std::vector< double > > fMCMCProposalFunctionScaleFactor
Scale factors for proposal functions.
std::string fMCMCOutputFilename
Output filename for for writing MCMC Tree.
BCParameter & GetParameter(unsigned index)
Definition: BCEngineMCMC.h:630
TTree * fMCMCTree
The tree containing the Markov chains.
const std::vector< double > & GetLocalModes(bool force_recalculation=false)
void WriteMarginalizedDistributions(const std::string &filename, const std::string &option, bool closeExistingFile=false)
Write marginalization histograms to file.
A class to represent the prior of a parameter by a formula through a TF1.
Definition: BCTF1Prior.h:32
unsigned fMultivariateCovarianceUpdates
Number of multivariate-proposal-function covariance updates performed.
unsigned PrintPlots(std::vector< BCH1D > &h1, std::vector< BCH2D > &h2, const std::string &filename, unsigned hdiv=1, unsigned vdiv=1)
Print plots.
Definition: BCAux.cxx:339
A class to represent the log of a prior of a parameter by a formula through a TF1.
Definition: BCTF1LogPrior.h:32
A class for handling 2D distributions.
Definition: BCH2D.h:37
double probability_mean
mean of probability
Definition: BCEngineMCMC.h:202
unsigned PrintParameterPlot(const std::string &filename, int npar=10, double interval_content=68e-2, std::vector< double > quantile_values=std::vector< double >(0), bool rescale_ranges=true) const
Print a summary plot for the parameters and user-defined observables.
A class representing a variable of a model.
Definition: BCVariable.h:35
void WriteMarkovChain(bool flag)
Turn on/off writing of Markov chain to root file.
void CalculateCholeskyDecompositions()
Calculate Cholesky decompositions needed for multivariate proposal function.
double fMCMCScaleFactorLowerLimit
Lower limit for scale factors.
void PrintParameters(const std::vector< double > &P, void(*output)(const std::string &)=BCLog::OutSummary) const
Print parameters.
BCH1D fBCH1DdrawingOptions
A BCH1D (with no histogram) for storing BCH1D drawing options.
std::vector< std::pair< int, int > > fRequestedH2
Vector of pairs of indices for which 2D histograms should be stored.
double log_prior
log(prior)
Definition: BCEngineMCMC.h:165
bool PrintCorrelationPlot(const std::string &filename="correlation.pdf", bool include_observables=true) const
Print a correlation plot for the parameters.
virtual double GetPriorVariance() const
virtual void CreateHistograms(bool rescale_ranges=false)
Create histograms from parameter and observable sets.
A class representing a variable of a model.
Definition: BCObservable.h:32
virtual double GetLowerLimit() const
Definition: BCVariable.h:97
randomly distribute according to factorized priors
Definition: BCEngineMCMC.h:86
std::vector< double > modepar
mode of parameters
Definition: BCEngineMCMC.h:204
bool GetProposalPointMetropolis(unsigned chain, std::vector< double > &x)
Return a proposal point for the Metropolis algorithm.
virtual bool IsWithinLimits(double value) const
Definition: BCVariable.h:250
std::vector< double > efficiency
efficiencies for each parameter (NB: not stored for observables)
Definition: BCEngineMCMC.h:208
virtual bool ParameterTreeMatchesModel(TTree *partree, bool checkObservables=true)
Check parameter tree against model.
bool PrintParameterLatex(const std::string &filename) const
Print a LaTeX table of the parameters.
unsigned fInitialPositionAttemptLimit
Maximum number of attempts to make to set the initial position.
virtual const std::string & GetPrefix() const
Definition: BCVariable.h:67
void SetPrior(unsigned index, TF1 &f, bool logL=true)
virtual bool IsWithinLimits(const std::vector< double > &x) const
Check if vector of values is within limits.
A class to represent a gaussian prior of a parameter.
TH2 * Transpose(const TH2 *const h, const std::string &name="")
Transpose a TH2.
Definition: BCAux.cxx:55
unsigned GetMaximumParameterNameLength(bool observables=true) const
Definition: BCEngineMCMC.h:592
virtual void MCMCCurrentPointInterface(const std::vector< double > &point, int ichain, bool accepted)
Interface allowing to execute arbitrary code for each new point of the MCMC whether it is accepted or...
double fMCMCProposalFunctionDof
Degree of freedom of Student&#39;s t proposal.
std::vector< double > observables
observables at parameter point
Definition: BCEngineMCMC.h:162
double fMCMCEfficiencyMax
The maximum allowed efficiency for MCMC.
bool DrawParameterPlot(unsigned i0, unsigned npar=0, double interval_content=68e-2, std::vector< double > quantile_values=std::vector< double >(0), bool rescale_ranges=true) const
Draw a summary plot for the parameters in the range provided to current pad.
virtual BCPrior * GetPrior()
Definition: BCParameter.h:91
unsigned GetNObservables() const
Definition: BCEngineMCMC.h:711
double fMCMCEfficiencyMin
The minimum required efficiency for MCMC.
virtual void MCMCUserInitialize()
User hook called from MCMCInitialize().
unsigned fMCMCNIterationsPreRunMin
Minimum number of iterations for the pre-run.
std::string SafeName(const std::string &name)
Convert a name into a safe name for use in ROOT object naming.
Definition: BCAux.cxx:111
void SetInitialPositionScheme(BCEngineMCMC::InitialPositionScheme scheme)
Sets flag which defines initial position.
Definition: BCEngineMCMC.h:835
std::string fName
Name of the engine.
void UpdateParameterTree()
Update Paramater TTree with scales and efficiencies.
virtual void FillHistograms(bool flag)
Set the filling of 1D and 2D histograms.
Definition: BCVariable.h:183
int fMCMCNIterationsConvergenceGlobal
Number of iterations needed for all chains to convergence simultaneously.
virtual double GetLogMaximum() const
Definition: BCEngineMCMC.h:729
void SetPrecision(BCEngineMCMC::Precision precision)
Set the precision for the MCMC run.
std::vector< double > fMCMCInitialScaleFactors
User-provided initial values of the scale factors of the factorized proposal function.
double GetMedian()
Definition: BCH1D.h:89
virtual std::vector< unsigned > GetH1DPrintOrder() const
BCAux::BCTrash< TObject > fObjectTrash
Storage for plot objects with proper clean-up.
initialize to user-provided points
Definition: BCEngineMCMC.h:85
void Clear(bool clear_mode=true, bool clear_efficiency=true)
clear all members.
bool fMCMCProposeMultivariate
Flag for using multivariate proposal function.
virtual void InitializeMarkovChainTree(bool replacetree=false, bool replacefile=false)
Initialize the trees containing the Markov chains and parameter info.
double fHistogramRescalePadding
factor for enlarging range of histograms when rescaling.
double fMultivariateEpsilon
multivariate-proposal-function cholesky-decomposition nudge.
virtual const std::vector< double > & GetBestFitParameterErrors() const
A struct for holding statistical information about samples.
Definition: BCEngineMCMC.h:187
std::vector< TMatrixD > fMultivariateProposalFunctionCholeskyDecomposition
Cholesky decompositions for multivariate proposal function.
int GetNIterationsConvergenceGlobal() const
Definition: BCEngineMCMC.h:301
bool fMCMCFlagWritePreRunToFile
Flag to write pre run to file.
virtual bool AddObservable(const std::string &name, double min, double max, const std::string &latexname="", const std::string &unitstring="")
select centers of parameter ranges
Definition: BCEngineMCMC.h:83
std::vector< double > variance
variances of all variables
Definition: BCEngineMCMC.h:196
virtual void PrintModelSummary() const
Print model summary to log.
virtual double GetUpperLimit() const
Definition: BCVariable.h:102
BCEngineMCMC::Statistics fMCMCStatistics_AllChains
Statistics across all Markov chains.
void SetNChains(unsigned n)
Sets the number of Markov chains which are run in parallel.
Definition: BCEngineMCMC.h:775
std::vector< double > stderrobs
sqrt(variance) of all observables
Definition: BCEngineMCMC.h:198
unsigned fMCMCPreRunCheckClear
Number of iterations between clearing of convergence stats in pre-run.
unsigned fMCMCNIterationsRun
Number of iterations for a Markov chain run.
A class representing a parameter of a model.
Definition: BCParameter.h:34
virtual bool FillH2() const
Definition: BCVariable.h:129
const std::string & GetName() const
Definition: BCEngineMCMC.h:269
unsigned PrintAllMarginalized(const std::string &filename, unsigned hdiv=1, unsigned vdiv=1) const
Print all marginalizations.
std::vector< double > parameters
parameter point
Definition: BCEngineMCMC.h:161
double Value() const
Definition: BCObservable.h:69
An engine class for Markov Chain Monte Carlo.
Definition: BCEngineMCMC.h:55
virtual double GetFixedValue() const
Definition: BCParameter.h:86
std::vector< BCH1D::BCH1DSmallestInterval > GetSmallestIntervals(std::vector< double > masses)
Definition: BCH1D.cxx:452
virtual void PrintMarginalizationSummary() const
Print marginalization to log.
std::vector< std::vector< TH2 * > > fH2Marginalized
Vector of 2D marginalized distributions.
std::string fSafeName
Safe name of the engine for use in naming ROOT objects.
double fMCMCScaleFactorUpperLimit
Upper limit for scale factors.
double log_probability
log(probability)
Definition: BCEngineMCMC.h:163
bool fMCMCTreeLoaded
flag for whether MCMC Tree successfully loaded.
std::vector< BCEngineMCMC::Statistics > fMCMCStatistics
Statistics for each Markov chain.
virtual double LogEval(const std::vector< double > &parameters)=0
Needs to be overloaded in the derived class.
std::vector< TH1 * > fH1Marginalized
Vector of 1D marginalized distributions.
bool fMCMCTreeReuseObservables
flag for whether to reuse MCMC Tree&#39;s observables.
virtual bool UpdateMultivariateProposalFunctionCovariances()
Update multivariate proposal function covariances.
unsigned fMCMCNChains
Number of Markov chains ran in parallel.
bool ValidParameterTree(TTree *tree) const
Check tree structure for parameter tree.
std::vector< double > mean
means of all variables
Definition: BCEngineMCMC.h:195
bool GetProposeMultivariate() const
Definition: BCEngineMCMC.h:403
void PrintSummary(const std::string &prefix="", unsigned prec=6, std::vector< double > intervals=std::vector< double >(0))
Print information to log.
Definition: BCH1D.cxx:408
std::vector< double > minimum
minimum value of variables
Definition: BCEngineMCMC.h:200
virtual void SetLimits(double lowerlimit=0, double upperlimit=1)
Set the limits of the variable values.
Definition: BCVariable.cxx:59
void LoadMCMCParameters(TTree &partree)
Load MCMC parameters from parameter tree: nchains, proposal function type, scales.
void WriteMarkovChainRun(bool flag)
Turn on/off writing of Markov chain to root file during run.
virtual bool Valid() const
Whether histogram has been set and filled.
virtual bool FillH1() const
Definition: BCVariable.h:124
virtual std::string GetLatexNameWithUnits() const
Definition: BCVariable.h:92
virtual bool Unfix()
Unfix parameter.
Definition: BCParameter.h:146
A class to represent the prior of a parameter by a TH1.
Definition: BCTH1Prior.h:30
virtual double PositionInRange(double x) const
return position in range of given value from 0 (at lower limit) to 1 (at upper limit) ...
Definition: BCVariable.h:228
std::vector< ChainState > fMCMCStates
The current states of each Markov chain.
void SetPriorGauss(unsigned index, double mean, double sigma)
void LoadParametersFromTree(TTree *partree, bool loadObservables=true)
Load parameters and observables from tree.
bool PrintCorrelationMatrix(const std::string &filename="matrix.pdf") const
Print a correlation matrix for the parameters.
const std::string & GetSafeName() const
Definition: BCEngineMCMC.h:274
virtual void SetLowerLimit(double limit)
Set the lower limit of the variable values.
Definition: BCVariable.h:159
TRandom3 fRandom
Random number generator.
std::vector< double > stderrpar
sqrt(variance) of all parameters
Definition: BCEngineMCMC.h:197
BCEngineMCMC::InitialPositionScheme fInitialPositionScheme
Variable which defines the initial position.
A class for handling 1D distributions.
Definition: BCH1D.h:34
void MCMCInitialize()
Resets all containers used in MCMC and initializes starting points.
unsigned GetNIterationsPreRun() const
virtual bool Fixed() const
Definition: BCParameter.h:81
void DefaultToPDF(std::string &filename)
Force file extension to be .pdf if not already .pdf or .ps.
Definition: BCAux.cxx:36
virtual unsigned GetNbins() const
Definition: BCVariable.h:134
void SetGlobalMode(double mode)
Set global mode.
Definition: BCH1D.h:151
virtual const std::vector< double > & GetBestFitParameters() const
BCParameterSet fParameters
Parameter settings.
void SetFillHistogram(int x, int y, bool flag)
Set whether to fill 2D histogram y vs x: positive indices for parameters; negative for observables...
virtual std::string GetBestFitSummary(unsigned i) const
Get string summarizing best fit for single variable.
void Init(unsigned n_par, unsigned n_obs)
init all members
bool fMCMCFlagWriteChainToFile
Flag to write Markov chains to file.
double log_likelihood
log(likelihood)
Definition: BCEngineMCMC.h:164
virtual std::vector< double > GetRangeCenters() const
Get range centers, leaving fixed parameters at fixed values.
double fMultivariateScaleMultiplier
factor to multiply or divide scale factors by in adjusting multivariate-proposal-function scales...
TH1 * GetMarginalizedHistogram(const std::string &name) const
Obtain the individual marginalized distributions with respect to one parameter as a ROOT TH1...
Definition: BCEngineMCMC.h:527
unsigned fMCMCNIterationsPreRunCheck
Number of iterations between scale adjustments and convergence checks in pre-run. ...
int fMCMCCurrentIteration
The current iteration number.
TFile * fMCMCOutputFile
Output file for for writing MCMC Tree.
virtual void EvaluateObservables()
Evaluates user-defined observables at current state of all chains and stores results in fMCMCState...
virtual void PrintSummary() const
Prints a summary to the logs.
void SetRandomSeed(unsigned seed)
Set the random number seed.
virtual void SetPrecision(unsigned precision)
Set the precision of the output of variable.
Definition: BCVariable.h:177
virtual unsigned MaxNameLength() const
bool fRescaleHistogramRangesAfterPreRun
flag for rescaling of histograms after pre-run.
Vector of intervals with information about total mass.
Definition: BCH1D.h:247
virtual const std::string & GetName() const
Definition: BCVariable.h:72
void WriteMarkovChainPreRun(bool flag)
Turn on/off writing of Markov chain to root file during prerun.
double fMCMCRValueParametersCriterion
The R-value criterion for convergence of parameters.
double fMultivariateCovarianceUpdateLambda
weighting parameter for multivariate-proposal-function covariance update.
Statistics & operator+=(const Statistics &rhs)
addition assignment operator.
virtual double ProposalFunction(unsigned ichain, unsigned ipar)
The default proposal function is a Breit-Wigner random walk.
virtual bool ApplyFixedValues(std::vector< double > &x) const
Change values to fixed values for fixed parameters.
unsigned fMCMCNLag
The lag for the Markov Chain.
virtual std::vector< double > GetRandomValuesAccordingToPriors(TRandom *const R) const
Get vector values distributed randomly by the parameter priors.
virtual void SetUpperLimit(double limit)
Set the upper limit of the variable values.
Definition: BCVariable.h:165
unsigned fMCMCNIterationsPreRunMax
Maximum number of iterations for a Markov chain prerun.
void InChainFillHistograms()
Fill marginalized distributions from all chain states.
unsigned GetNVariables() const
Definition: BCEngineMCMC.h:613
std::vector< double > fMCMCRValueParameters
The R-values for each parameter.
void PrepareToContinueMarginalization(const std::string &filename, const std::string &mcmcTreeName="", const std::string &parameterTreeName="", bool loadObservables=true, bool autorange=true)
Continue the marginalization already stored in another file.
bool AcceptOrRejectPoint(unsigned chain, unsigned parameter)
Accept or rejects a point for a chain and updates efficiency.
unsigned GetCurrentChain() const
virtual double GetRangeWidth() const
Returns the range width of the variable values.
Definition: BCVariable.h:109
virtual bool Empty() const
Whether container is empty.
double probability_variance
variance of probability
Definition: BCEngineMCMC.h:203
BCEngineMCMC(const std::string &name="model")
Default constructor.
Precision
An enumerator for the status of a test.
Definition: BCEngineMCMC.h:65
double probability_at_mode
mode of probability
Definition: BCEngineMCMC.h:206
std::vector< double > fLocalModes
Vector of local modes.
BCH1D GetMarginalized(const std::string &name) const
Obtain the individual marginalized distributions with respect to one parameter.
Definition: BCEngineMCMC.h:561
unsigned GetNParameters() const
Definition: BCEngineMCMC.h:656
std::vector< double > modeobs
mode of observables
Definition: BCEngineMCMC.h:205
virtual T & At(unsigned index)
Safe access, but slightly less efficient access to parameter.
BCVariable & GetVariable(unsigned index)
Definition: BCEngineMCMC.h:600
unsigned iteration
iteration number
Definition: BCEngineMCMC.h:160
BCParameterSet & GetParameters()
Definition: BCEngineMCMC.h:618
bool ValidMCMCTree(TTree *tree, bool checkObservables=true) const
Check tree structure for MCMC tree.
A struct for holding a state in a Markov chain.
Definition: BCEngineMCMC.h:159
void SetGlobalMode(double x, double y)
Set global mode.
Definition: BCH2D.h:171
std::vector< std::vector< double > > covariance
covariances of all pairs of variables
Definition: BCEngineMCMC.h:199
randomly distribute uniformly over parameter ranges
Definition: BCEngineMCMC.h:84
virtual unsigned GetPrecision() const
Definition: BCVariable.h:119
unsigned UpdateFrequency(unsigned N) const
return appropriate update interval
unsigned GetNFreeParameters() const
Definition: BCEngineMCMC.h:668
unsigned int fMCMCTree_Chain
Chain number for storing into tree.
BCEngineMCMC::Phase fMCMCPhase
The phase of the run.
void CloseOutputFile()
Close the root output file.
void SetInitialPositions(const std::vector< double > &x0s)
Sets the initial positions for all chains.