BAT  0.9.4
The Bayesian analysis toolkit
 All Classes Namespaces Functions Variables Enumerations
BCEngineMCMC.cxx
1 /*
2  * Copyright (C) 2007-2014, 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 
11 #include "BCEngineMCMC.h"
12 
13 #include "BCH1D.h"
14 #include "BCH2D.h"
15 #include "BCLog.h"
16 #include "BCMath.h"
17 #include "BCParameter.h"
18 
19 #include <TH1D.h>
20 #include <TH2D.h>
21 #include <TRandom3.h>
22 #include <TTree.h>
23 
24 #include <math.h>
25 #include <limits>
26 
27 // ---------------------------------------------------------
29 {
30  // set default parameters for the mcmc
32 
33  // initialize random number generator
34  fRandom = new TRandom3();
36 }
37 
38 // ---------------------------------------------------------
40 {
43  fMCMCFlagPreRun = true;
44  fMCMCFlagRun = false;
45  fMCMCEfficiencyMin = 0.15;
46  fMCMCEfficiencyMax = 0.50;
48  fMCMCNLag = 1;
50  fMCMCCurrentChain = -1;
51  fMCMCLogMaximum = -std::numeric_limits<double>::max();
52 
54 }
55 
56 // ---------------------------------------------------------
58 {
59  fMCMCNChains = 2;
60  fMCMCNIterationsMax = 10000;
61  fMCMCNIterationsRun = 10000;
64  fMCMCRValueUseStrict = false;
69  fMCMCRValue = 100;
74  fMCMCCurrentChain = -1;
75 }
76 
77 // ---------------------------------------------------------
79 {
80  fMCMCNChains = 5;
81  fMCMCNIterationsMax = 1000000;
82  fMCMCNIterationsRun = 100000;
85  fMCMCRValueUseStrict = false;
90  fMCMCRValue = 100;
95  fMCMCCurrentChain = -1;
96 }
97 
98 // ---------------------------------------------------------
100 {
101  switch(precision) {
102  case BCEngineMCMC::kLow:
103  fMCMCNChains = 1;
104  fMCMCNLag = 1;
105  fMCMCNIterationsMax = 10000;
106  fMCMCNIterationsRun = 10000;
108  fMCMCNIterationsUpdate = 1000;
110  fMCMCRValueCriterion = 0.1;
112  fMCMCRValue = 100;
113  break;
114  case BCEngineMCMC::kMedium:
115  fMCMCNChains = 5;
116  fMCMCNLag = 1;
117  fMCMCNIterationsMax = 100000;
118  fMCMCNIterationsRun = 100000;
120  fMCMCNIterationsUpdate = 1000;
122  fMCMCRValueCriterion = 0.1;
124  fMCMCRValue = 100;
125  break;
126  case BCEngineMCMC::kHigh:
127  fMCMCNChains = 10;
128  fMCMCNLag = 10;
129  fMCMCNIterationsMax = 1000000;
130  fMCMCNIterationsRun = 1000000;
132  fMCMCNIterationsUpdate = 1000;
134  fMCMCRValueCriterion = 0.1;
136  fMCMCRValue = 100;
137  break;
138  case BCEngineMCMC::kVeryHigh:
139  fMCMCNChains = 10;
140  fMCMCNLag = 10;
141  fMCMCNIterationsMax = 10000000;
142  fMCMCNIterationsRun = 10000000;
144  fMCMCNIterationsUpdate = 1000;
146  fMCMCRValueCriterion = 0.1;
148  fMCMCRValue = 100;
149  break;
150  }
151 
152  // re-initialize
153  MCMCInitialize();
154 }
155 
156 // ---------------------------------------------------------
158 {
159  // delete random number generator
160  delete fRandom;
161 
162  // delete 1-d marginalized distributions
163  for (unsigned i = 0; i < fMCMCH1Marginalized.size(); ++i)
164  delete fMCMCH1Marginalized[i];
165  fMCMCH1Marginalized.clear();
166 
167  // delete 2-d marginalized distributions
168  for (unsigned i = 0; i < fMCMCH2Marginalized.size(); ++i)
169  delete fMCMCH2Marginalized[i];
170  fMCMCH2Marginalized.clear();
171 }
172 
173 // ---------------------------------------------------------
175 {
176  Copy(other);
177 }
178 
179 // ---------------------------------------------------------
180 void BCEngineMCMC::Copy(const BCEngineMCMC & other)
181 {
182  fMCMCPointerToGetProposalPoint = other.fMCMCPointerToGetProposalPoint;
183  fMCMCNChains = other.fMCMCNChains;
184  fMCMCNLag = other.fMCMCNLag;
196  fMCMCNTrials = other.fMCMCNTrials;
202  fMCMCFlagRun = other.fMCMCFlagRun;
209  fMCMCPhase = other.fMCMCPhase;
210  fMCMCx = other.fMCMCx;
211  fMCMCxMax = other.fMCMCxMax;
212  fMCMCxMean = other.fMCMCxMean;
213  fMCMCxVar = other.fMCMCxVar;
214  fMCMCprob = other.fMCMCprob;
215  fMCMCprobMax = other.fMCMCprobMax;
217  fMCMCprobVar = other.fMCMCprobVar;
221  fMCMCRValue = other.fMCMCRValue;
223  if (other.fRandom)
224  {
225  fRandom = new TRandom3(*other.fRandom);
226  }
227  else
228  {
229  fRandom = NULL;
230  }
231 
232  fMCMCThreadLocalStorage = other.fMCMCThreadLocalStorage;
233 
234  for (unsigned i = 0; i < other.fMCMCH1Marginalized.size(); ++i) {
235  if (other.fMCMCH1Marginalized.at(i))
236  fMCMCH1Marginalized.push_back(new TH1D(*(other.fMCMCH1Marginalized.at(i))));
237  else
238  fMCMCH1Marginalized.push_back(0);
239  }
240 
241  for (unsigned i = 0; i < other.fMCMCH2Marginalized.size(); ++i) {
242  if (other.fMCMCH2Marginalized.at(i))
243  fMCMCH2Marginalized.push_back(new TH2D(*(other.fMCMCH2Marginalized.at(i))));
244  else
245  fMCMCH2Marginalized.push_back(0);
246  }
247 
248  for (unsigned i = 0; i < other.fMCMCTrees.size(); ++i) {
249  fMCMCTrees.push_back(0);
250  }
251 
255 }
256 
257 // ---------------------------------------------------------
259 {
260  Copy(enginemcmc);
261  return *this;
262 }
263 
264 // --------------------------------------------------------
266 {
267  return (GetNParameters() - GetNFixedParameters());
268 }
269 
270 // --------------------------------------------------------
272 {
273  int n = 0;
274  for (unsigned int i = 0; i < fParameters.Size(); ++i) {
275  if (fParameters[i]->Fixed())
276  ++n;
277  }
278 
279  return n;
280 }
281 
282 // --------------------------------------------------------
283 void BCEngineMCMC::SetNbins(unsigned int nbins)
284 {
285  for (unsigned i = 0 ; i < fParameters.Size() ; ++i)
286  fParameters[i]->SetNbins(nbins);
287 }
288 
289 // --------------------------------------------------------
291 {
292  if ( !fParameters.ValidIndex(index)) {
293  BCLog::OutError(Form("BCEngineMCMC::MCMCGetH1Marginalized. Index %u out of range.", index));
294  return 0;
295  }
296 
297  // use when BCIntegrate acts MCMC marginalization and only some marginals have been computed
298  if (!fMCMCH1Marginalized[index]) {
299  BCLog::OutWarning(Form("BCEngineMCMC::MCMCGetH1Marginalized: marginal distribution not computed/stored for par. %d", index));
300  return 0;
301  }
302 
303  // set histogram
304  BCH1D * hprob = new BCH1D();
305  hprob->SetHistogram(fMCMCH1Marginalized[index]);
306 
307  if (fMarginalModes.empty())
308  fMarginalModes.assign(fParameters.Size(), 0.0);
309  fMarginalModes[index] = hprob->GetMode();
310 
311  return hprob;
312 }
313 
314 // --------------------------------------------------------
316 {
317  if ( !fParameters.ValidIndex(i)) {
318  BCLog::OutError(Form("BCEngineMCMC::MCMCGetH2Marginalized. Index %u out of range.", i));
319  return 0;
320  }
321  if ( !fParameters.ValidIndex(j)) {
322  BCLog::OutError(Form("BCEngineMCMC::MCMCGetH2Marginalized. Index %u out of range.", j));
323  return 0;
324  }
325  if (i == j) {
326  BCLog::OutError(Form("BCEngineMCMC::MCMCGetH2Marginalized. Called with identical indices %u.", i));
327  return 0;
328  }
329 
330  // swap indices
331  if (i > j) {
332  unsigned indexTemp = i;
333  i = j;
334  j = indexTemp;
335  }
336 
337  // memory layout for n parameters and indices i, j:
338  // first (n-1) elements for first parameter vs. all other parameters
339  // then (n-2) elements for second parameter and all others etc
340  // so the first combination for which i is the lower index is at n*i - i(i+1)/2
341  // and the offset is given by (j-i-1)
342  TH2D * h = fMCMCH2Marginalized.at(GetNParameters() * i - (i * i + 3 * i) / 2 + j - 1);
343  if ( !h)
344  return 0;
345 
346  BCH2D * hprob = new BCH2D();
347  hprob->SetHistogram(h);
348 
349  return hprob;
350 }
351 
352 // ---------------------------------------------------------
353 const std::vector<double> & BCEngineMCMC::GetBestFitParametersMarginalized() const
354 {
355  if(fMarginalModes.empty())
356  BCLog::OutError("BCIntegrate::GetBestFitParameterMarginalized : MCMC not yet run, returning center of the range.");
357 
358  return fMarginalModes;
359 }
360 
361 // --------------------------------------------------------
362 std::vector<double> BCEngineMCMC::MCMCGetMaximumPoint(unsigned i) const
363 {
364  // create a new vector with the length of fMCMCNParameters
365  std::vector<double> x;
366 
367  // check if i is in range
368  if (i >= fMCMCNChains)
369  return x;
370 
371  // copy the point in the ith chain into the temporary vector
372  for (unsigned j = 0; j < fParameters.Size(); ++j)
373  x.push_back(fMCMCxMax.at(i * fParameters.Size() + j));
374 
375  return x;
376 }
377 
378 // --------------------------------------------------------
380 {
381  fMCMCNChains = n;
382 
383  // re-initialize
384  MCMCInitialize();
385 }
386 
387 // --------------------------------------------------------
388 void BCEngineMCMC::MCMCSetInitialPositions(const std::vector<double> & x0s)
389 {
390  // clear the existing initial position vector
391  fMCMCInitialPosition.clear();
392 
393  // copy the initial positions
394  unsigned n = x0s.size();
395 
396  for (unsigned i = 0; i < n; ++i)
397  fMCMCInitialPosition.push_back(x0s.at(i));
398 
399  // use these initial positions for the Markov chain
401 }
402 
403 // --------------------------------------------------------
404 void BCEngineMCMC::MCMCSetInitialPositions(std::vector< std::vector<double> > x0s)
405 {
406  // create new vector
407  std::vector<double> y0s;
408 
409  // loop over vector elements
410  for (unsigned i = 0; i < x0s.size(); ++i)
411  for (unsigned j = 0; j < x0s.at(i).size(); ++j)
412  y0s.push_back((x0s.at(i)).at(j));
413 
415 }
416 
417 // --------------------------------------------------------
419 {
420  for (unsigned i = 0; i < fParameters.Size(); ++i)
421  fParameters[i]->FillHistograms(flag);
422 }
423 
424 // --------------------------------------------------------
425 void BCEngineMCMC::MCMCSetMarkovChainTrees(const std::vector<TTree *> & trees)
426 {
427  // clear vector
428  fMCMCTrees.clear();
429 
430  // copy tree
431  for (unsigned i = 0; i < trees.size(); ++i)
432  fMCMCTrees.push_back(trees[i]);
433 }
434 
436 {
437  if (!fRandom)
438  fRandom = new TRandom3();
439 
440  // set main generator
441  fRandom->SetSeed(seed);
442 
443  // call once so return value of GetSeed() fixed
444  fRandom->Rndm();
445 
446  SyncThreadStorage();
447 
448  // type conversion to avoid compiler warnings
449  if (size_t(fMCMCNChains) != fMCMCThreadLocalStorage.size())
450  BCLog::OutError(Form("#chains does not match #(thread local storages): %d vs %u",
451  fMCMCNChains, unsigned(fMCMCThreadLocalStorage.size())));
452 
453  // set all single chain generators
454  for (unsigned i = 0; i < fMCMCNChains ; ++i){
455  // call once so return value of GetSeed() fixed
456  fMCMCThreadLocalStorage[i].rng->SetSeed(fRandom->GetSeed() + i);
457  fMCMCThreadLocalStorage[i].rng->Rndm();
458  }
459 }
460 
461 // --------------------------------------------------------
463 {
464  // clear vector
465  fMCMCTrees.clear();
466 
467  // create new trees
468  for (unsigned i = 0; i < fMCMCNChains; ++i) {
469  fMCMCTrees.push_back(new TTree(TString::Format("MarkovChainTree_%i", i), "MarkovChainTree"));
470  fMCMCTrees[i]->Branch("Iteration", &fMCMCNIterations[i], "iteration/i");
471  // todo check example and parallel_TEST how to automatically determine #parameters
472 // fMCMCTrees[i]->Branch("NParameters", fParameters.Size(), "parameters/I");
473  fMCMCTrees[i]->Branch("LogProbability", &fMCMCprob[i], "log(probability)/D");
474  fMCMCTrees[i]->Branch("Phase", &fMCMCPhase, "phase/I");
475 
476  for (unsigned j = 0; j < fParameters.Size(); ++j)
477  fMCMCTrees[i]->Branch(TString::Format("Parameter%i", j),
478  &fMCMCx[i * fParameters.Size() + j],
479  TString::Format("parameter %i/D", j));
480  }
481 }
482 
483 // --------------------------------------------------------
484 void BCEngineMCMC::MCMCTrialFunction(unsigned ichain, std::vector<double> &x)
485 {
486  // call MCMCTrialFunctionSingle() for all parameters by default
487  for (unsigned i = 0; i < fParameters.Size(); ++i)
488  x[i] = MCMCTrialFunctionSingle(ichain, i);
489 }
490 
491 // --------------------------------------------------------
492 double BCEngineMCMC::MCMCTrialFunctionSingle(unsigned ichain, unsigned iparameter)
493 {
494  // no check of range for performance reasons
495 
496  // use uniform distribution
497  // return = fMCMCTrialFunctionScaleFactor[ichain * fMCMCNParameters + iparameter] * 2.0 * (0.5 - fRandom->Rndm());
498 
499  // Breit-Wigner width adjustable width
500  return fMCMCThreadLocalStorage[ichain].rng->BreitWigner(0.0,
501  fMCMCTrialFunctionScaleFactor[ichain * fParameters.Size() + iparameter]);
502 }
503 
504 // --------------------------------------------------------
505 std::vector<double> BCEngineMCMC::MCMCGetTrialFunctionScaleFactor(unsigned ichain) const
506 {
507  // create a new vector with the length of fParameters
508  std::vector<double> x;
509 
510  // check if ichain is in range
511  if (ichain >= fMCMCNChains)
512  return x;
513 
514  // copy the scale factors into the temporary vector
515  for (unsigned j = 0; j < fParameters.Size(); ++j)
516  x.push_back(fMCMCTrialFunctionScaleFactor.at(ichain * fParameters.Size() + j));
517 
518  return x;
519 }
520 
521 // --------------------------------------------------------
522 double BCEngineMCMC::MCMCGetTrialFunctionScaleFactor(unsigned ichain, unsigned ipar)
523 {
524  // check if ichain is in range
525  if (ichain >= fMCMCNChains)
526  return 0;
527 
528  // check if ipar is in range
529  if (ipar >= fParameters.Size())
530  return 0;
531 
532  // return component of ipar point in the ichain chain
533  return fMCMCTrialFunctionScaleFactor.at(ichain * fMCMCNChains + ipar);
534 }
535 
536 // --------------------------------------------------------
537 std::vector<double> BCEngineMCMC::MCMCGetx(unsigned ichain)
538 {
539  // create a new vector with the length of fParameters.Size()
540  std::vector<double> x;
541 
542  // check if ichain is in range
543  if (ichain >= fMCMCNChains)
544  return x;
545 
546  // copy the point in the ichain chain into the temporary vector
547  for (unsigned j = 0; j < fParameters.Size(); ++j)
548  x.push_back(fMCMCx.at(ichain * fParameters.Size() + j));
549 
550  return x;
551 }
552 
553 // --------------------------------------------------------
554 double BCEngineMCMC::MCMCGetx(unsigned ichain, unsigned ipar) const
555 {
556  // check if ichain is in range
557  if (ichain >= fMCMCNChains)
558  return 0;
559 
560  // check if ipar is in range
561  if (ipar >= fParameters.Size())
562  return 0;
563 
564  // return component of jth point in the ith chain
565  return fMCMCx.at(ichain * fParameters.Size() + ipar);
566 }
567 
568 // --------------------------------------------------------
569 double BCEngineMCMC::MCMCGetLogProbx(unsigned ichain)
570 {
571  // check if ichain is in range
572  if (ichain >= fMCMCNChains)
573  return -1;
574 
575  // return log of the probability at the current point in the ith chain
576  return fMCMCprob.at(ichain);
577 }
578 
579 // --------------------------------------------------------
580 bool BCEngineMCMC::MCMCGetProposalPointMetropolis(unsigned chain, std::vector<double> &x)
581 {
582  // get unscaled random point. this point might not be in the correct volume.
583  MCMCTrialFunction(chain, x);
584 
585  // get a proposal point from the trial function and scale it
586  for (unsigned i = 0; i < fParameters.Size(); ++i) {
587  // check if parameter is fixed
588  if (fParameters[i]->Fixed()) {
589  x[i] = 0;
590  }
591  x[i] = fMCMCx[chain * fParameters.Size() + i] + x[i] * fParameters[i]->GetRangeWidth();
592  }
593 
594  // check if the point is in the correct volume.
595  for (unsigned i = 0; i < fParameters.Size(); ++i)
596  if (!fParameters[i]->IsValid(x[i]))
597  return false;
598 
599  return true;
600 }
601 
602 // --------------------------------------------------------
603 bool BCEngineMCMC::MCMCGetProposalPointMetropolis(unsigned ichain, unsigned ipar, std::vector<double> &x)
604 {
605  // copy the old point into the new
606  for (unsigned i = 0; i < fParameters.Size(); ++i)
607  x[i] = fMCMCx[ichain * fParameters.Size() + i];
608 
609  // check if parameter is fixed
610  if (fParameters[ipar]->Fixed()) {
611  x[ipar] = fParameters[ipar]->GetFixedValue();
612  return true; // assume that value is inside allowed region
613  }
614 
615  // get unscaled random point in the dimension of the chosen
616  // parameter. this point might not be in the correct volume.
617  double proposal = MCMCTrialFunctionSingle(ichain, ipar);
618 
619  // modify the parameter under study
620  x[ipar] += proposal * fParameters[ipar]->GetRangeWidth();
621 
622  // check if the point is in the correct volume.
623  if (fParameters[ipar]->IsValid(x[ipar]))
624  return true;
625 
626  return false;
627 }
628 
629 // --------------------------------------------------------
630 bool BCEngineMCMC::MCMCGetNewPointMetropolis(unsigned chain, unsigned parameter)
631 {
632  // calculate index
633  unsigned index = chain * fParameters.Size();
634 
635  fMCMCCurrentChain = chain;
636 
637  // increase counter
638  fMCMCNIterations[chain]++;
639 
640  // get proposal point
641  if (!MCMCGetProposalPointMetropolis(chain, parameter, fMCMCThreadLocalStorage[chain].xLocal))
642  {
643  // execute user code for every point
644  MCMCCurrentPointInterface(fMCMCThreadLocalStorage[chain].xLocal, chain, false);
645 
646  return false;
647  }
648 
649  // calculate probabilities of the old and new points
650  double p0 = fMCMCprob[chain];
651  double p1 = LogEval(fMCMCThreadLocalStorage[chain].xLocal);
652 
653  // flag for accept
654  bool accept = false;
655 
656  // if the new point is more probable, keep it ...
657  if (p1 >= p0)
658  accept = true;
659  // ... or else throw dice.
660  else
661  {
662  double r = log(fMCMCThreadLocalStorage[chain].rng->Rndm());
663 
664  if(r < p1 - p0)
665  accept = true;
666  }
667 
668  // fill the new point
669  if(accept)
670  {
671  // increase counter
672  fMCMCNTrialsTrue[chain * fParameters.Size() + parameter]++;
673 
674  // copy the point
675  for(unsigned i = 0; i < fParameters.Size(); ++i)
676  {
677  // save the point
678  fMCMCx[index + i] = fMCMCThreadLocalStorage[chain].xLocal[i];
679 
680  // save the probability of the point
681  fMCMCprob[chain] = p1;
682  }
683  }
684 
685  // execute user code for every point
686  MCMCCurrentPointInterface(fMCMCThreadLocalStorage[chain].xLocal, chain, accept);
687 
688  return accept;
689 }
690 
691 // --------------------------------------------------------
693 {
694  // calculate index
695  unsigned index = chain * fParameters.Size();
696 
697  fMCMCCurrentChain = chain;
698 
699  // increase counter
700  fMCMCNIterations[chain]++;
701 
702  // get proposal point
703  if (!MCMCGetProposalPointMetropolis(chain, fMCMCThreadLocalStorage[chain].xLocal))
704  {
705  // execute user code for every point
706  MCMCCurrentPointInterface(fMCMCThreadLocalStorage[chain].xLocal, chain, false);
707 
708  return false;
709  }
710 
711  // calculate probabilities of the old and new points
712  double p0 = fMCMCprob[chain];
713  double p1 = LogEval(fMCMCThreadLocalStorage[chain].xLocal);
714 
715  // flag for accept
716  bool accept = false;
717 
718  // if the new point is more probable, keep it ...
719  if (p1 >= p0)
720  accept = true;
721 
722  // ... or else throw dice.
723  else
724  {
725  double r = log(fMCMCThreadLocalStorage[chain].rng->Rndm());
726 
727  if(r < p1 - p0)
728  accept = true;
729  }
730 
731  // fill the new point
732  if(accept)
733  {
734  // increase counter
735  for (unsigned i = 0; i < fParameters.Size(); ++i)
736  fMCMCNTrialsTrue[chain * fParameters.Size() + i]++;
737 
738  // copy the point
739  for(unsigned i = 0; i < fParameters.Size(); ++i)
740  {
741  // save the point
742  fMCMCx[index + i] = fMCMCThreadLocalStorage[chain].xLocal[i];
743 
744  // save the probability of the point
745  fMCMCprob[chain] = p1;
746  }
747  }
748 
749  // execute user code for every point
750  MCMCCurrentPointInterface(fMCMCThreadLocalStorage[chain].xLocal, chain, accept);
751 
752  return accept;
753 }
754 
755 // --------------------------------------------------------
757 {
758  // loop over all chains
759  for (unsigned i = 0; i < fMCMCNChains; ++i)
760  {
761  // check if new maximum is found or chain is at the beginning
762  if (fMCMCprob[i] > fMCMCprobMax[i] || fMCMCNIterations[i] == 1)
763  {
764  // copy maximum value
765  fMCMCprobMax[i] = fMCMCprob[i];
766 
767  // copy mode of chain
768  for (unsigned j = 0; j < fParameters.Size(); ++j)
769  fMCMCxMax[i * fParameters.Size() + j] = fMCMCx[i * fParameters.Size() + j];
770  }
771  }
772 }
773 
774 // --------------------------------------------------------
776 {
777  // length of vectors
778  unsigned nentries = fParameters.Size() * fMCMCNChains;
779 
780  // loop over all parameters of all chains
781  for (unsigned i = 0; i < nentries; ++i) {
782  // calculate mean value of each parameter in the chain for this part
783  fMCMCxMean[i] += (fMCMCx[i] - fMCMCxMean[i]) / double(fMCMCNTrials);
784 
785  // calculate variance of each chain for this part
786  if (fMCMCNTrials > 1)
787  fMCMCxVar[i] = (1.0 - 1./double(fMCMCNTrials)) * fMCMCxVar[i]
788  + (fMCMCx[i] - fMCMCxMean[i]) * (fMCMCx[i] - fMCMCxMean[i]) / double(fMCMCNTrials - 1);
789  }
790 
791  // loop over chains
792  for (unsigned i = 0; i < fMCMCNChains; ++i) {
793  // calculate mean value of each chain for this part
794  fMCMCprobMean[i] += (fMCMCprob[i] - fMCMCprobMean[i]) / double(fMCMCNTrials);
795 
796  // calculate variance of each chain for this part
797  if (fMCMCNTrials > 1)
798  fMCMCprobVar[i] = (1.0 - 1/double(fMCMCNTrials)) * fMCMCprobVar[i]
799  + (fMCMCprob[i] - fMCMCprobMean[i]) * (fMCMCprob[i] - fMCMCprobMean[i]) / double(fMCMCNTrials - 1);
800  }
801 
802 }
803 
804 // --------------------------------------------------------
806 {
807  // loop over chains
808  for (unsigned i = 0; i < fMCMCNChains; ++i)
809  {
810  // fill each 1-dimensional histogram (if supposed to be filled)
811  for (unsigned j = 0; j < fParameters.Size(); ++j)
812  if (TH1 * h = fMCMCH1Marginalized[j])
813  h->Fill(fMCMCx[i * fParameters.Size() + j]);
814 
815  // fill each 2-dimensional histogram (if supposed to be filled)
816  unsigned counter = 0;
817 
818  for (unsigned j = 0; j < fParameters.Size(); ++j)
819  for (unsigned k = j+1; k < fParameters.Size(); ++k)
820  {
821  if (TH2D * h = fMCMCH2Marginalized[counter])
822  h->Fill(fMCMCx[i*fParameters.Size()+j],fMCMCx[i* fParameters.Size()+k]);
823  counter ++;
824  }
825  }
826 }
827 
828 // --------------------------------------------------------
830 {
831  if (fMCMCNChains > 1 && fMCMCNTrials > 1)
832  {
833  // define flag for convergence
834  bool flag_convergence = true;
835 
836  // extract means and variances
837  std::vector<double> means(fMCMCNChains);
838  std::vector<double> variances(fMCMCNChains);
839 
840  // loop over parameters
841  for (unsigned iparameters = 0; iparameters < fParameters.Size(); ++iparameters){
842  if (fParameters[iparameters]->Fixed())
843  continue;
844 
845  // loop over chains
846  for (unsigned ichains = 0; ichains < fMCMCNChains; ++ichains) {
847  // get parameter index
848  unsigned index = ichains * fParameters.Size() + iparameters;
849  means[ichains] = fMCMCxMean[index];
850  variances[ichains] = fMCMCxVar[index];
851  }
852  fMCMCRValueParameters[iparameters] = BCMath::Rvalue(means, variances, fMCMCNTrials, fMCMCRValueUseStrict);
853 
854  // set flag to false if convergence criterion is not fulfilled for the parameter
855  if (! ((fMCMCRValueParameters[iparameters]-1.0) < fMCMCRValueParametersCriterion))
856  flag_convergence = false;
857 
858  // else: leave convergence flag true for that parameter
859  }
860 
862 
863  // set flag to false if convergence criterion is not fulfilled for the log-likelihood
864  if (!((fMCMCRValue - 1.0) < fMCMCRValueCriterion))
865  flag_convergence = false;
866 
867  // remember number of iterations needed to converge
868  if (fMCMCNIterationsConvergenceGlobal == -1 && flag_convergence == true)
870  }
871 }
872 // --------------------------------------------------------
874 {
875  // loop over all chains
876  for (unsigned i = 0; i < fMCMCNChains; ++i)
877  fMCMCTrees[i]->Fill();
878 }
879 
880 // --------------------------------------------------------
881 double BCEngineMCMC::LogEval(const std::vector<double> & /*parameters*/)
882 {
883  // test function for now
884  // this will be overloaded by the user
885  return 0.0;
886 }
887 
888 // --------------------------------------------------------
890 {
891  // print on screen
892  BCLog::OutSummary("Pre-run Metropolis MCMC...");
893 
894  // initialize Markov chain
895  MCMCInitialize();
897 
898  // helper variable containing number of digits in the number of parameters
899  int ndigits = (int)log10(fParameters.Size()) +1;
900  if(ndigits<4)
901  ndigits=4;
902 
903  // reset run statistics
906 
907  // perform run
908  BCLog::OutSummary(Form(" --> Perform MCMC pre-run with %i chains, each with maximum %i iterations", fMCMCNChains, fMCMCNIterationsMax));
909 
910  // don't write to file during pre run
911  bool tempflag_writetofile = fMCMCFlagWriteChainToFile;
913 
914  // initialize counter variables and flags
915  fMCMCCurrentIteration = 1; // counts the number of iterations
916  unsigned counterupdate = 1; // after how many iterations is an update needed?
917  bool convergence = false; // convergence reached?
918  bool flagefficiency = false; // efficiency reached?
919 
920  // array of efficiencies
921  // std::vector<double> efficiency;
922  fMCMCEfficiencies.clear();
924 
925  // how often to check convergence and efficiencies?
926  // it's either every fMCMCNParameters*nMCMCNIterationsUpdate (for 5 parameters the default would be 5000)
927  // or it's fMCMCNIterationsUpdateMax (10000 by default)
928  // whichever of the two is smaller
931 
932  // loop over chains
933  for (unsigned ichains = 0; ichains < fMCMCNChains; ++ichains) {
934  // loop over parameters
935  for (unsigned iparameter = 0; iparameter < fParameters.Size(); ++iparameter){
936  // global index of the parameter (throughout all the chains)
937  unsigned index = ichains * fParameters.Size() + iparameter;
938  // reset counters
939  fMCMCxMean[index] = fMCMCx[index];
940  }
941  fMCMCprobMean[ichains] = fMCMCprob[ichains];
942  }
943 
944  // set phase and cycle number
945  fMCMCPhase = 1;
946 
947  // run chain ...
948  // (a) for at least a minimum number of iterations,
949  // (b) until a maximum number of iterations is reached,
950  // (c) or until convergence is reached and the efficiency is in the
951  // specified region
953  (fMCMCCurrentIteration < int(fMCMCNIterationsMax) && !(convergence && flagefficiency)))
954  {
955  //-------------------------------------------
956  // reset flags and counters
957  //-------------------------------------------
958 
959  // set convergence to false by default
960  convergence = false;
961 
962  // set number of iterations needed to converge to negative
964 
965  //-------------------------------------------
966  // get new point in n-dim space
967  //-------------------------------------------
968 
969  ++fMCMCNTrials;
970 
971  // if the flag is set then run over the parameters one after the other.
973  {
974  // loop over parameters
975  {
976  for (unsigned iparameters = 0; iparameters < fParameters.Size(); ++iparameters)
977  {
978  if (fParameters[iparameters]->Fixed())
979  continue;
980  // loop over chains
981 
982  unsigned chunk = 1; (void) chunk;
983  unsigned ichains; (void) ichains;
984 #pragma omp parallel for shared(chunk) private(ichains) schedule(static, chunk)
985  for (ichains = 0; ichains < fMCMCNChains; ++ichains){
986  MCMCGetNewPointMetropolis(ichains, iparameters);
987  }
988  // search for global maximum
990  }
991  }
992  }
993 
994  // if the flag is not set then run over the parameters at the same time.
995  else
996  {
997  // loop over chains
998  {
999  unsigned chunk = 1; (void) chunk;
1000  unsigned ichains; (void) ichains;
1001 #pragma omp parallel for shared(chunk) private(ichains) schedule(static, chunk)
1002  for (ichains = 0; ichains < fMCMCNChains; ++ichains){
1003  MCMCGetNewPointMetropolis(ichains);
1004  }
1005  }
1006  // search for global maximum
1008  }
1009 
1010  //-------------------------------------------
1011  // print out message to log
1012  //-------------------------------------------
1013 
1014  // progress printout
1016  BCLog::OutDetail(Form(" --> Iteration %i", fMCMCNIterations[0] / GetNFreeParameters()));
1017 
1018  //-------------------------------------------
1019  // update statistics
1020  //-------------------------------------------
1021 
1022  if (counterupdate > 1)
1024 
1025  //-------------------------------------------
1026  // update scale factors and check convergence
1027  //-------------------------------------------
1028 
1029  // debugKK
1030  // check if this line makes sense
1031  if ( counterupdate % updateLimit == 0 && counterupdate > 0 && fMCMCCurrentIteration >= int(fMCMCNIterationsPreRunMin))
1032  {
1033  // -----------------------------
1034  // reset flags and counters
1035  // -----------------------------
1036 
1037  bool rvalues_ok = true;
1038 
1039  static bool has_converged = false;
1040 
1041  // reset the number of iterations needed for convergence to
1042  // negative
1044 
1045  // -----------------------------
1046  // check convergence status
1047  // -----------------------------
1048 
1049  // test convergence
1051 
1052  // set convergence flag
1054  convergence = true;
1055 
1056  // print convergence status:
1057  if (convergence && fMCMCNChains > 1)
1058  BCLog::OutDetail(Form(" * Convergence status: Set of %i Markov chains converged within %i iterations.", fMCMCNChains, fMCMCNIterationsConvergenceGlobal));
1059  else if (!convergence && fMCMCNChains > 1)
1060  {
1061  BCLog::OutDetail(Form(" * Convergence status: Set of %i Markov chains did not converge after %i iterations.", fMCMCNChains, fMCMCCurrentIteration));
1062 
1063  BCLog::OutDetail(" - R-Values:");
1064  for (unsigned iparameter = 0; iparameter < fParameters.Size(); ++iparameter)
1065  {
1066  if (fParameters[iparameter]->Fixed())
1067  continue;
1068  if(fabs(fMCMCRValueParameters[iparameter]-1.) < fMCMCRValueParametersCriterion)
1069  BCLog::OutDetail(TString::Format(" parameter %*i : %.06f",ndigits, iparameter, fMCMCRValueParameters.at(iparameter)));
1070  else
1071  {
1072  if ( fMCMCRValueParameters.at(iparameter) != std::numeric_limits<double>::max() )
1073  BCLog::OutDetail(TString::Format(" parameter %*i : %.06f <--",ndigits, iparameter, fMCMCRValueParameters.at(iparameter)));
1074  else
1075  BCLog::OutDetail(TString::Format(" parameter %*i : MAX_DOUBLE <--",ndigits, iparameter));
1076  rvalues_ok = false;
1077  }
1078  }
1079  if(fabs(fMCMCRValue-1.) < fMCMCRValueCriterion)
1080  BCLog::OutDetail(Form(" log-likelihood : %.06f", fMCMCRValue));
1081  else
1082  {
1083  if ( fMCMCRValue != std::numeric_limits<double>::max() )
1084  BCLog::OutDetail(Form(" log-likelihood : %.06f <--", fMCMCRValue));
1085  else
1086  BCLog::OutDetail(" log-likelihood : MAX_DOUBLE <--");
1087  rvalues_ok = false;
1088  }
1089  }
1090 
1091  // set convergence flag
1092  if(!has_converged)
1093  if(rvalues_ok)
1094  has_converged = true;
1095 
1096  // -----------------------------
1097  // check efficiency status
1098  // -----------------------------
1099 
1100  // set flag
1101  flagefficiency = true;
1102 
1103  bool flagprintefficiency = true;
1104 
1105  // loop over chains
1106  for (unsigned ichains = 0; ichains < fMCMCNChains; ++ichains)
1107  {
1108  // loop over parameters
1109  for (unsigned iparameter = 0; iparameter < fParameters.Size(); ++iparameter)
1110  {
1111  if (fParameters[iparameter]->Fixed())
1112  continue;
1113 
1114  // global index of the parameter (throughout all the chains)
1115  unsigned index = ichains * fParameters.Size() + iparameter;
1116 
1117  // calculate efficiency
1118  fMCMCEfficiencies[index] = double(fMCMCNTrialsTrue[index]) / double(fMCMCNTrials);
1119 
1120  // adjust scale factors if efficiency is too low
1122  {
1123  if (flagprintefficiency)
1124  {
1125  BCLog::OutDetail(Form(" * Efficiency status: Efficiencies not within pre-defined range."));
1126  BCLog::OutDetail(Form(" - Efficiencies:"));
1127  flagprintefficiency = false;
1128  }
1129 
1130  double fscale=2.;
1131  if(has_converged && fMCMCEfficiencyMin/fMCMCEfficiencies[index] > 2.)
1132  fscale = 4.;
1133  fMCMCTrialFunctionScaleFactor[index] /= fscale;
1134 
1135  BCLog::OutDetail(Form(" Efficiency of parameter %i dropped below %.2f%% (eps = %.2f%%) in chain %i. Set scale to %.4g",
1136  iparameter, 100. * fMCMCEfficiencyMin, 100. * fMCMCEfficiencies[index], ichains, fMCMCTrialFunctionScaleFactor[index]));
1137  }
1138 
1139  // adjust scale factors if efficiency is too high
1140  else if (fMCMCEfficiencies[index] > fMCMCEfficiencyMax && fMCMCTrialFunctionScaleFactor[index] < 1.0)
1141  {
1142  if (flagprintefficiency)
1143  {
1144  BCLog::OutDetail(Form(" * Efficiency status: Efficiencies not within pre-defined ranges."));
1145  BCLog::OutDetail(Form(" - Efficiencies:"));
1146  flagprintefficiency = false;
1147  }
1148 
1149  fMCMCTrialFunctionScaleFactor[index] *= 2.;
1150 
1151  BCLog::OutDetail(Form(" Efficiency of parameter %i above %.2f%% (eps = %.2f%%) in chain %i. Set scale to %.4g",
1152  iparameter, 100.0 * fMCMCEfficiencyMax, 100.0 * fMCMCEfficiencies[index], ichains, fMCMCTrialFunctionScaleFactor[index]));
1153  }
1154 
1155  // check flag
1158  flagefficiency = false;
1159  } // end of running over all parameters
1160  } // end of running over all chains
1161 
1162  // print to screen
1163  if (flagefficiency)
1164  BCLog::OutDetail(Form(" * Efficiency status: Efficiencies within pre-defined ranges."));
1165 
1166  // -----------------------------
1167  // reset counters
1168  // -----------------------------
1169 
1170  counterupdate = 0;
1171 
1172  // loop over chains
1173  fMCMCNTrials = 0;
1174  for (unsigned ichains = 0; ichains < fMCMCNChains; ++ichains) {
1175  // loop over parameters
1176  for (unsigned iparameter = 0; iparameter < fParameters.Size(); ++iparameter){
1177  // global index of the parameter (throughout all the chains)
1178  unsigned index = ichains * fParameters.Size() + iparameter;
1179  // reset counters
1180  fMCMCNTrialsTrue[index] = 0;
1181  fMCMCxMean[index] = fMCMCx[index];
1182  fMCMCxVar[index] = 0;
1183  }
1184  fMCMCprobMean[ichains] = fMCMCprob[ichains];
1185  fMCMCprobVar[ichains] = 0;
1186  }
1187  } // end if update scale factors and check convergence
1188 
1189  //-------------------------------------------
1190  // write chain to file
1191  //-------------------------------------------
1192 
1193  // write chain to file
1196 
1197  //-------------------------------------------
1198  // increase counters
1199  //-------------------------------------------
1201  counterupdate++;
1202 
1203  } // end of running
1204 
1205  // did we check convergence at least once ?
1206  if (fMCMCCurrentIteration < int(updateLimit))
1207  {
1208  BCLog::OutWarning(" Convergence never checked !");
1209  BCLog::OutWarning(" Increase maximum number of iterations in the pre-run /MCMCSetNIterationsMax()/");
1210  BCLog::OutWarning(" or decrease maximum number of iterations for update /MCMCSetNIterationsUpdateMax()/");
1211  }
1212 
1213  // ---------------
1214  // after chain run
1215  // ---------------
1216 
1217  // define convergence status
1220  else
1222 
1223  // print convergence status
1224  if (fMCMCFlagConvergenceGlobal && fMCMCNChains > 1 && !flagefficiency)
1225  BCLog::OutSummary(Form(" --> Set of %i Markov chains converged within %i iterations but could not adjust scales.", fMCMCNChains, fMCMCNIterationsConvergenceGlobal));
1226 
1227  else if (fMCMCFlagConvergenceGlobal && fMCMCNChains > 1 && flagefficiency)
1228  BCLog::OutSummary(Form(" --> Set of %i Markov chains converged within %i iterations and all scales are adjusted.", fMCMCNChains, fMCMCNIterationsConvergenceGlobal));
1229 
1230  else if (!fMCMCFlagConvergenceGlobal && (fMCMCNChains > 1) && flagefficiency)
1231  BCLog::OutSummary(Form(" --> Set of %i Markov chains did not converge within %i iterations.", fMCMCNChains, fMCMCNIterationsMax));
1232 
1233  else if (!fMCMCFlagConvergenceGlobal && (fMCMCNChains > 1) && !flagefficiency)
1234  BCLog::OutSummary(Form(" --> Set of %i Markov chains did not converge within %i iterations and could not adjust scales.", fMCMCNChains, fMCMCNIterationsMax));
1235 
1236  else if(fMCMCNChains == 1)
1237  BCLog::OutSummary(" --> No convergence criterion for a single chain defined.");
1238 
1239  else
1240  BCLog::OutSummary(" --> Only one Markov chain. No global convergence criterion defined.");
1241 
1242  BCLog::OutSummary(Form(" --> Markov chains ran for %i iterations.", fMCMCCurrentIteration));
1243 
1244 
1245  // print efficiencies
1246  std::vector<double> efficiencies;
1247 
1248  for (unsigned i = 0; i < fParameters.Size(); ++i)
1249  efficiencies.push_back(0.);
1250 
1251  BCLog::OutDetail(" --> Average efficiencies:");
1252  for (unsigned i = 0; i < fParameters.Size(); ++i)
1253  {
1254  if (fParameters[i]->Fixed())
1255  continue;
1256 
1257  for (unsigned j = 0; j < fMCMCNChains; ++j)
1258  efficiencies[i] += fMCMCEfficiencies[j * fParameters.Size() + i] / double(fMCMCNChains);
1259 
1260  BCLog::OutDetail(TString::Format(" --> parameter %*d : %.02f%%",ndigits, i, 100. * efficiencies[i]));
1261  }
1262 
1263 
1264  // print scale factors
1265  std::vector<double> scalefactors;
1266 
1267  for (unsigned i = 0; i < fParameters.Size(); ++i)
1268  scalefactors.push_back(0.0);
1269 
1270  BCLog::OutDetail(" --> Average scale factors:");
1271  for (unsigned i = 0; i < fParameters.Size(); ++i)
1272  {
1273  if (fParameters[i]->Fixed())
1274  continue;
1275  for (unsigned j = 0; j < fMCMCNChains; ++j)
1276  scalefactors[i] += fMCMCTrialFunctionScaleFactor[j * fParameters.Size() + i] / double(fMCMCNChains);
1277 
1278  BCLog::OutDetail(TString::Format(" --> parameter %*i : %.02f%%",ndigits, i, 100. * scalefactors[i]));
1279  }
1280 
1281  // reset flag
1282  fMCMCFlagWriteChainToFile = tempflag_writetofile;
1283 
1284  // reset current iteration
1285  fMCMCCurrentIteration = -1;
1286 
1287  // reset current chain
1288  fMCMCCurrentChain = -1;
1289 
1290  // no error
1291  return 1;
1292 }
1293 
1294 // --------------------------------------------------------
1296 {
1297  // check the number of free parameters
1298  if (GetNFreeParameters() <= 0) {
1299  BCLog::OutWarning("BCEngineMCMC::MCMCMetropolis. Number of free parameters <= 0. Do not run Metropolis.");
1300  return 0;
1301  }
1302 
1303  // check if prerun should be performed
1304  if (fMCMCFlagPreRun)
1306  else
1307  BCLog::OutWarning("BCEngineMCMC::MCMCMetropolis. Not running prerun. This can cause trouble if the data have changed.");
1308 
1309  // print to screen
1310  BCLog::OutSummary( "Run Metropolis MCMC...");
1311 
1312  // reset run statistics
1314 
1315  // set phase and cycle number
1316  fMCMCPhase = 2;
1317 
1318  // perform run
1319  BCLog::OutSummary(Form(" --> Perform MCMC run with %i chains, each with %i iterations.", fMCMCNChains, fMCMCNIterationsRun));
1320 
1321  int nwrite = fMCMCNIterationsRun/10;
1322  if(nwrite < 100)
1323  nwrite=100;
1324  else if(nwrite < 500)
1325  nwrite=1000;
1326  else if(nwrite < 10000)
1327  nwrite=1000;
1328  else
1329  nwrite=10000;
1330 
1331  // start the run
1333  {
1334  if ( (fMCMCCurrentIteration)%nwrite == 0 )
1335  BCLog::OutDetail(Form(" --> iteration number %i (%.2f%%)", fMCMCCurrentIteration, (double)(fMCMCCurrentIteration)/(double)fMCMCNIterationsRun*100.));
1336 
1337  // if the flag is set then run over the parameters one after the other.
1339  {
1340  // loop over parameters
1341  for (unsigned iparameters = 0; iparameters < fParameters.Size(); ++iparameters)
1342  {
1343  if (fParameters[iparameters]->Fixed())
1344  continue;
1345 
1346  // loop over chains
1347  {
1348  unsigned chunk = 1; (void) chunk;
1349  unsigned ichains; (void) ichains;
1350 #pragma omp parallel for shared(chunk) private(ichains) schedule(static, chunk)
1351  for (unsigned ichains = 0; ichains < fMCMCNChains; ++ichains)
1352  {
1353  MCMCGetNewPointMetropolis(ichains, iparameters);
1354  }
1355  }
1356  // reset current chain
1357  fMCMCCurrentChain = -1;
1358 
1359  // update search for maximum
1361 
1362  } // end loop over all parameters
1363 
1364  // check if the current iteration is consistent with the lag
1365  if ( fMCMCCurrentIteration % fMCMCNLag == 0)
1366  {
1367  // do anything interface
1369 
1370  // fill histograms
1371  if ( ! fMCMCH1Marginalized.empty() or ! fMCMCH2Marginalized.empty())
1373 
1374  // write chain to file
1377  }
1378  }
1379  // if the flag is not set then run over the parameters at the same time.
1380  else
1381  {
1382  // loop over chains
1383  {
1384  unsigned chunk = 1; (void) chunk;
1385  unsigned ichains; (void) ichains;
1386 #pragma omp parallel for shared(chunk) private(ichains) schedule(static, chunk)
1387  for (unsigned ichains = 0; ichains < fMCMCNChains; ++ichains)
1388  {
1389  // get new point
1390  MCMCGetNewPointMetropolis(ichains);
1391  }
1392  }
1393  // reset current chain
1394  fMCMCCurrentChain = -1;
1395 
1396  // update search for maximum
1398 
1399  // check if the current iteration is consistent with the lag
1400  if (fMCMCCurrentIteration % fMCMCNLag == 0)
1401  {
1402  // do anything interface
1404 
1405  // fill histograms
1406  if ( ! fMCMCH1Marginalized.empty() or ! fMCMCH2Marginalized.empty())
1408 
1409  // write chain to file
1412  }
1413  }
1414 
1415  } // end run
1416 
1417  // print convergence status
1418  BCLog::OutSummary(Form(" --> Markov chains ran for %i iterations.", fMCMCNIterationsRun));
1419 
1420  // print modes
1421 
1422  // find global maximum
1423  double probmax = fMCMCprobMax.at(0);
1424  unsigned probmaxindex = 0;
1425 
1426  // loop over all chains and find the maximum point
1427  for (unsigned i = 1; i < fMCMCNChains; ++i) {
1428  if (fMCMCprobMax.at(i) > probmax)
1429  {
1430  probmax = fMCMCprobMax.at(i);
1431  probmaxindex = i;
1432  }
1433  }
1434 
1435  // save if improved the log posterior
1436  if (fMCMCBestFitParameters.empty() || probmax > fMCMCLogMaximum) {
1437  fMCMCLogMaximum = probmax;
1438  fMCMCBestFitParameters.assign(fParameters.Size(), 0.0);
1439  for (unsigned i = 0; i < fParameters.Size(); ++i)
1440  fMCMCBestFitParameters[i] = fMCMCxMax[probmaxindex * fParameters.Size() + i];
1441  }
1442 
1443  BCLog::OutDetail(" --> Global mode from MCMC:");
1444  BCLog::OutDebug(Form(" --> Posterior value: %g", probmax));
1445  int ndigits = (int) log10(fParameters.Size());
1446  for (unsigned i = 0; i < fParameters.Size(); ++i)
1447  BCLog::OutDetail(TString::Format(" --> parameter %*i: %.4g", ndigits+1, i, fMCMCBestFitParameters[i]));
1448 
1449  // reset counter
1450  fMCMCCurrentIteration = -1;
1451 
1452  // reset current chain
1453  fMCMCCurrentChain = -1;
1454 
1455  // set flags
1456  fMCMCFlagRun = true;
1457 
1458  return 1;
1459 }
1460 
1461 // --------------------------------------------------------
1463 {
1464  fMCMCNTrials = 0;
1465 
1466  for (unsigned j = 0; j < fMCMCNChains; ++j)
1467  {
1468  fMCMCNIterations[j] = 0;
1469  fMCMCprobMean[j] = 0;
1470  fMCMCprobVar[j] = 0;
1471 
1472  for (unsigned k = 0; k < fParameters.Size(); ++k)
1473  {
1474  fMCMCNTrialsTrue[j * fParameters.Size() + k] = 0;
1475  }
1476  }
1477 
1478  // reset marginalized distributions
1479  for (unsigned i = 0; i < fMCMCH1Marginalized.size(); ++i)
1480  if (fMCMCH1Marginalized[i])
1481  fMCMCH1Marginalized[i]->Reset();
1482 
1483  for (unsigned i = 0; i < fMCMCH2Marginalized.size(); ++i)
1484  if (fMCMCH2Marginalized[i])
1485  fMCMCH2Marginalized[i]->Reset();
1486 
1487  fMCMCRValue = 100;
1488 }
1489 
1490 // --------------------------------------------------------
1491 int BCEngineMCMC::AddParameter(const char * name, double min, double max, const char * latexname)
1492 {
1493  // todo memory leak:
1494  // ==8243== 64 (44 direct, 20 indirect) bytes in 1 blocks are definitely lost in loss record 20,913 of 29,122
1495  // ==8243== at 0x402C9B4: operator new(unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
1496  // ==8243== by 0x409DED1: BCEngineMCMC::AddParameter(char const*, double, double) (BCEngineMCMC.cxx:1480)
1497  return AddParameter(new BCParameter(name, min, max, latexname));
1498 }
1499 
1500 // --------------------------------------------------------
1502 {
1503  return fParameters.Add(par);
1504 }
1505 
1506 // --------------------------------------------------------
1508 {
1509  // evaluate function at the starting point
1510  std::vector<double> x0;
1511 
1512  for (unsigned j = 0; j < fMCMCNChains; ++j)
1513  {
1514  x0.clear();
1515  for (unsigned i = 0; i < fParameters.Size(); ++i)
1516  x0.push_back(fMCMCx[j * fParameters.Size() + i]);
1517  fMCMCprob[j] = LogEval(x0);
1518  }
1519 
1520  x0.clear();
1521 }
1522 
1523 // --------------------------------------------------------
1525 {
1526  // reset variables
1527  fMCMCNIterations.clear();
1528  fMCMCNTrialsTrue.clear();
1529  fMCMCNTrials = 0;
1531  fMCMCprobMean.clear();
1532  fMCMCprobVar.clear();
1533  fMCMCxMean.clear();
1534  fMCMCxVar.clear();
1535  fMCMCx.clear();
1536  fMCMCprob.clear();
1537  fMCMCxMax.clear();
1538  fMCMCprobMax.clear();
1540  fMCMCRValueParameters.clear();
1541 
1542  for (unsigned i = 0; i < fMCMCH1Marginalized.size(); ++i)
1543  if (fMCMCH1Marginalized[i])
1544  delete fMCMCH1Marginalized[i];
1545 
1546  for (unsigned i = 0; i < fMCMCH2Marginalized.size(); ++i)
1547  if (fMCMCH2Marginalized[i])
1548  delete fMCMCH2Marginalized[i];
1549 
1550  // clear plots
1551  fMCMCH1Marginalized.clear();
1552  fMCMCH2Marginalized.clear();
1553 
1554  // reset flags
1555  fMCMCFlagPreRun = true;
1556  fMCMCFlagRun = false;
1558 
1559  fMCMCBestFitParameters.clear();
1560  fMCMCLogMaximum = -std::numeric_limits<double>::max();
1561  fMarginalModes.clear();
1562 }
1563 
1564 // --------------------------------------------------------
1566 {
1567  // resource allocation must be done only by one thread
1568  // reset values
1569  ResetResults();
1570 
1571  // free memory for vectors
1572  fMCMCNIterations.assign(fMCMCNChains, 0);
1573  fMCMCprobMean.assign(fMCMCNChains, 0);
1574  fMCMCprobVar.assign(fMCMCNChains, 0);
1575  fMCMCprob.assign(fMCMCNChains, -1.0);
1576  fMCMCprobMax.assign(fMCMCNChains, -1.0);
1577 
1579  fMCMCNTrials = 0;
1580  fMCMCxMax.assign(fMCMCNChains * fParameters.Size(), 0.);
1581  fMCMCxMean.assign(fMCMCNChains * fParameters.Size(), 0);
1582  fMCMCxVar.assign(fMCMCNChains * fParameters.Size(), 0);
1583 
1584  fMCMCRValueParameters.assign(fParameters.Size(), 0.);
1585 
1586  SyncThreadStorage();
1587 
1588  if (fMCMCTrialFunctionScaleFactorStart.size() == 0)
1590  else
1591  for (unsigned i = 0; i < fMCMCNChains; ++i)
1592  for (unsigned j = 0; j < fParameters.Size(); ++j)
1594 
1595  // set initial position
1596  if (fMCMCFlagInitialPosition == 2) // user defined points
1597  {
1598  // define flag
1599  bool flag = true;
1600 
1601  // check the length of the array of initial positions
1602  if (fMCMCInitialPosition.size() != (fMCMCNChains * fParameters.Size()))
1603  {
1604  BCLog::OutError("BCEngine::MCMCInitialize : Length of vector containing initial positions does not have required length.");
1605  flag = false;
1606  }
1607 
1608  // check the boundaries
1609  if (flag)
1610  {
1611  for (unsigned j = 0; j < fMCMCNChains; ++j)
1612  for (unsigned i = 0; i < fParameters.Size(); ++i)
1613  if (!fParameters[i]->IsValid(fMCMCInitialPosition[j * fParameters.Size() + i]))
1614  {
1615  BCLog::OutError("BCEngine::MCMCInitialize : Initial position out of boundaries.");
1616  flag = false;
1617  }
1618  }
1619 
1620  // check flag
1621  if (!flag)
1623  }
1624 
1625  if (fMCMCFlagInitialPosition == 0) // center of the interval
1626  for (unsigned j = 0; j < fMCMCNChains; ++j)
1627  for (unsigned i = 0; i < fParameters.Size(); ++i) {
1628  if (fParameters[i]->Fixed())
1629  fMCMCx.push_back(fParameters[i]->GetFixedValue());
1630  else
1631  fMCMCx.push_back(fParameters[i]->GetLowerLimit() + .5 * fParameters[i]->GetRangeWidth());
1632  }
1633 
1634  else if (fMCMCFlagInitialPosition == 2) // user defined
1635  {
1636  for (unsigned j = 0; j < fMCMCNChains; ++j)
1637  for (unsigned i = 0; i < fParameters.Size(); ++i) {
1638  if (fParameters[i]->Fixed()) {
1639  fMCMCx.push_back(fParameters[i]->GetFixedValue());
1640  BCLog::OutWarning("BCEngineMCMC::MCMCInitialize. Inconsisten start value. Changed parameter value to fixed value.");
1641  }
1642  else
1643  fMCMCx.push_back(fMCMCInitialPosition.at(j * fParameters.Size() + i));
1644  }
1645  }
1646 
1647  else
1648  {
1649  for (unsigned j = 0; j < fMCMCNChains; ++j) // random number (default)
1650  for (unsigned i = 0; i < fParameters.Size(); ++i) {
1651  if (fParameters[i]->Fixed())
1652  fMCMCx.push_back(fParameters[i]->GetFixedValue());
1653  else
1654  fMCMCx.push_back(fParameters[i]->GetLowerLimit() + fMCMCThreadLocalStorage[j].rng->Rndm() * fParameters[i]->GetRangeWidth());
1655  }
1656  }
1657 
1658  // copy the point of the first chain
1659  std::copy(fMCMCx.begin(), fMCMCx.begin() + fParameters.Size(), fMCMCThreadLocalStorage.at(0).xLocal.begin());
1660 
1661  // define 1-dimensional histograms for marginalization
1662  bool fillAny=false;
1663  for(unsigned i = 0; i < fParameters.Size(); ++i)
1664  {
1665  const BCParameter * p = fParameters[i];
1666  TH1D * h1 = NULL;
1667  if (p->FillHistograms() && ! p->Fixed()) {
1668  h1 = new TH1D(TString::Format("h1_%d_parameter_%i", BCLog::GetHIndex() ,i),
1669  TString::Format(";%s;", p->GetLatexName().c_str()),
1670  p->GetNbins(), p->GetLowerLimit(), p->GetUpperLimit());
1671  h1->SetStats(kFALSE);
1672 
1673  fillAny = true;
1674  }
1675  fMCMCH1Marginalized.push_back(h1);
1676  }
1677  // if filling no histograms, set H1 vector to zero size, implies no 2D histograms either
1678  if (!fillAny) {
1679  fMCMCH1Marginalized.clear();
1680  }
1681  else {
1682  // define 2-dimensional histograms for marginalization
1683  for(unsigned i = 0; i < fParameters.Size(); ++i) {
1684  BCParameter * p1 = fParameters[i];
1685  for (unsigned j = i + 1; j < fParameters.Size(); ++j) {
1686  TH2D * h2 = 0;
1687  BCParameter * p2 = fParameters[j];
1688  if (p2->FillHistograms() && p1->FillHistograms() && ! p2->Fixed() && ! p1->Fixed()) {
1689  h2 = new TH2D(Form("h2_%d_parameters_%i_vs_%i", BCLog::GetHIndex(), i, j), "",
1690  p1->GetNbins(), p1->GetLowerLimit(), p1->GetUpperLimit(),
1691  p2->GetNbins(), p2->GetLowerLimit(), p2->GetUpperLimit());
1692 
1693  // decorate histogram
1694  h2->SetXTitle(Form("%s", p1->GetLatexName().data()));
1695  h2->SetYTitle(Form("%s", p2->GetLatexName().data()));
1696  h2->SetStats(kFALSE);
1697  }
1698  fMCMCH2Marginalized.push_back(h2);
1699  }
1700  }
1701  }
1702  return 1;
1703 }
1704 
1705 // ---------------------------------------------------------
1707 {
1708  // do user defined stuff
1710 }
1711 
1712 // ---------------------------------------------------------
1713 int BCEngineMCMC::SetMarginalized(unsigned index, TH1D * h)
1714 {
1715  if(fMCMCH1Marginalized.size() <= index)
1716  return 0;
1717 
1718  if(h==0)
1719  return 0;
1720 
1721  if(fMCMCH1Marginalized.size() == index)
1722  fMCMCH1Marginalized.push_back(h);
1723  else
1724  fMCMCH1Marginalized[index]=h;
1725 
1726  return index;
1727 }
1728 
1729 // ---------------------------------------------------------
1730 int BCEngineMCMC::SetMarginalized(unsigned index1, unsigned index2, TH2D * h)
1731 {
1732  unsigned counter = 0;
1733  unsigned index = 0;
1734 
1735  // search for correct combination
1736  for(unsigned i = 0; i < fParameters.Size(); i++)
1737  for (unsigned j = 0; j < i; ++j)
1738  {
1739  if(j == index1 && i == index2)
1740  index = counter;
1741  counter++;
1742  }
1743 
1744  if(fMCMCH2Marginalized.size()<=index)
1745  return 0;
1746 
1747  if(h==0)
1748  return 0;
1749 
1750  if(fMCMCH2Marginalized.size()==index)
1751  fMCMCH2Marginalized.push_back(h);
1752  else
1753  fMCMCH2Marginalized[index]=h;
1754 
1755  return index;
1756 }
1757 
1758 // ---------------------------------------------------------
1759 BCEngineMCMC::MCMCThreadLocalStorage::MCMCThreadLocalStorage(const unsigned & dim) :
1760  xLocal(dim, 0.0),
1761  rng(new TRandom3(0))
1762 {
1763 }
1764 
1765 // ---------------------------------------------------------
1766 BCEngineMCMC::MCMCThreadLocalStorage::MCMCThreadLocalStorage(const MCMCThreadLocalStorage & other) :
1767  xLocal(other.xLocal),
1768  rng(new TRandom3(*other.rng))
1769 {
1770 }
1771 
1772 // ---------------------------------------------------------
1773 BCEngineMCMC::MCMCThreadLocalStorage & BCEngineMCMC::MCMCThreadLocalStorage::operator = (const MCMCThreadLocalStorage & other)
1774 {
1775  xLocal = other.xLocal;
1776  if (rng)
1777  {
1778  // call = operator
1779  *rng = *other.rng;
1780  }
1781  else
1782  rng = new TRandom3(*other.rng);
1783 
1784  return *this;
1785 }
1786 
1787 // ---------------------------------------------------------
1788 BCEngineMCMC::MCMCThreadLocalStorage::~MCMCThreadLocalStorage()
1789 {
1790  delete rng;
1791 }
1792 
1793 void BCEngineMCMC::SyncThreadStorage()
1794 {
1795  // always need as many local storage as #chains
1796  const int n = fMCMCThreadLocalStorage.size() - fMCMCNChains;
1797  if (n < 0)
1798  {
1799  // fix return value of GetSeed()
1800  fRandom->Rndm();
1801 
1802  for (int i = 0; i < -n; ++i){
1803  // append one new storage
1804  fMCMCThreadLocalStorage.push_back(MCMCThreadLocalStorage(fParameters.Size()));
1805  // each chains gets a different seed
1806  // We assume that fRandom always returns same seed, presumably as it has generated at least one random number
1807  fMCMCThreadLocalStorage.back().rng->SetSeed(fRandom->GetSeed() + fMCMCThreadLocalStorage.size());
1808  }
1809  }
1810  else if (n > 0)
1811  {
1812  for (int i = 0; i < n; ++i){
1813  fMCMCThreadLocalStorage.pop_back();
1814  }
1815  }
1816 
1817  // update parameter size for each chain
1818  for (unsigned i = 0 ; i < fMCMCThreadLocalStorage.size(); ++i)
1819  fMCMCThreadLocalStorage[i].xLocal.assign(fParameters.Size(), 0.0);
1820 }
void MCMCSetValuesDetail()
std::vector< double > MCMCGetMaximumPoint(unsigned i) const
int SetMarginalized(unsigned index, TH1D *h)
virtual void ResetResults()
std::vector< double > fMCMCBestFitParameters
Definition: BCEngineMCMC.h:925
int fMCMCFlagInitialPosition
Definition: BCEngineMCMC.h:830
double GetLowerLimit() const
Definition: BCParameter.h:65
void MCMCSetRandomSeed(unsigned seed)
virtual void MCMCTrialFunction(unsigned ichain, std::vector< double > &x)
bool Add(BCParameter *par)
bool ValidIndex(unsigned index, const std::string caller="CheckIndex") const
virtual ~BCEngineMCMC()
BCH2D * MCMCGetH2Marginalized(unsigned i, unsigned j)
int MCMCMetropolisPreRun()
virtual void MCMCUserIterationInterface()
Definition: BCEngineMCMC.h:651
void MCMCResetRunStatistics()
const std::vector< double > & MCMCGetx() const
Definition: BCEngineMCMC.h:181
void MCMCInitializeMarkovChains()
std::vector< double > fMCMCx
Definition: BCEngineMCMC.h:848
std::vector< double > fMCMCInitialPosition
Definition: BCEngineMCMC.h:812
int fMCMCCurrentChain
Definition: BCEngineMCMC.h:742
unsigned fMCMCNIterationsUpdate
Definition: BCEngineMCMC.h:746
std::vector< unsigned > fMCMCNIterations
Definition: BCEngineMCMC.h:732
unsigned int GetNFreeParameters()
void MCMCInChainCheckMaximum()
A class for handling 2D distributions.
Definition: BCH2D.h:37
std::vector< double > fMCMCprobMean
Definition: BCEngineMCMC.h:879
double fMCMCLogMaximum
Definition: BCEngineMCMC.h:929
const std::vector< double > & GetBestFitParametersMarginalized() const
TRandom3 * fRandom
Definition: BCEngineMCMC.h:911
virtual double LogEval(const std::vector< double > &parameters)
void MCMCSetInitialPositions(const std::vector< double > &x0s)
void MCMCInChainTestConvergenceAllChains()
std::vector< double > fMCMCprobVar
Definition: BCEngineMCMC.h:884
static int GetHIndex()
Definition: BCLog.h:164
double fMCMCEfficiencyMax
Definition: BCEngineMCMC.h:824
void MCMCSetFlagFillHistograms(bool flag)
void MCMCSetFlagInitialPosition(int flag)
Definition: BCEngineMCMC.h:404
double fMCMCEfficiencyMin
Definition: BCEngineMCMC.h:820
unsigned fMCMCNIterationsPreRunMin
Definition: BCEngineMCMC.h:771
BCEngineMCMC & operator=(const BCEngineMCMC &engineMCMC)
int fMCMCNIterationsConvergenceGlobal
Definition: BCEngineMCMC.h:755
void SetHistogram(TH2D *hist)
Definition: BCH2D.cxx:99
void MCMCInitializeMarkovChainTrees()
void Copy(const BCEngineMCMC &enginemcmc)
void SetNbins(unsigned int nbins)
bool fMCMCFlagWritePreRunToFile
Definition: BCEngineMCMC.h:788
bool fMCMCFlagPreRun
Definition: BCEngineMCMC.h:801
void SetHistogram(TH1D *hist)
Definition: BCH1D.h:149
unsigned fMCMCNIterationsRun
Definition: BCEngineMCMC.h:767
A class representing a parameter of a model.
Definition: BCParameter.h:28
virtual double MCMCTrialFunctionSingle(unsigned ichain, unsigned ipar)
double GetMode()
Definition: BCH1D.cxx:52
std::vector< double > fMCMCxMean
Definition: BCEngineMCMC.h:859
unsigned fMCMCNIterationsUpdateMax
Definition: BCEngineMCMC.h:750
std::vector< double > fMarginalModes
Definition: BCEngineMCMC.h:933
bool fMCMCRValueUseStrict
Definition: BCEngineMCMC.h:892
An engine class for Markov Chain Monte Carlo.
Definition: BCEngineMCMC.h:41
bool MCMCGetProposalPointMetropolis(unsigned chain, std::vector< double > &x)
unsigned int GetNFixedParameters()
std::vector< double > fMCMCEfficiencies
Definition: BCEngineMCMC.h:816
void MCMCInChainFillHistograms()
unsigned int GetNParameters() const
Definition: BCEngineMCMC.h:302
unsigned fMCMCNChains
Definition: BCEngineMCMC.h:723
const std::vector< double > & MCMCGetLogProbx() const
Definition: BCEngineMCMC.h:197
unsigned fMCMCNIterationsMax
Definition: BCEngineMCMC.h:763
bool fMCMCFlagConvergenceGlobal
Definition: BCEngineMCMC.h:759
virtual int AddParameter(const char *name, double min, double max, const char *latexname="")
const std::string & GetLatexName() const
Definition: BCParameter.h:60
std::vector< double > fMCMCxVar
Definition: BCEngineMCMC.h:864
unsigned Size() const
BCH1D * MCMCGetH1Marginalized(unsigned i)
void MCMCSetNChains(unsigned n)
double GetUpperLimit() const
Definition: BCParameter.h:70
A class for handling 1D distributions.
Definition: BCH1D.h:31
virtual void MCMCCurrentPointInterface(std::vector< double > &, int, bool)
Definition: BCEngineMCMC.h:662
BCParameterSet fParameters
Definition: BCEngineMCMC.h:719
void MCMCSetValuesQuick()
bool fMCMCFlagWriteChainToFile
Definition: BCEngineMCMC.h:784
void MCMCSetMarkovChainTrees(const std::vector< TTree * > &trees)
double Rvalue(const std::vector< double > &chain_means, const std::vector< double > &chain_variances, const unsigned &chain_length, const bool &strict)
Definition: BCMath.cxx:551
int fMCMCCurrentIteration
Definition: BCEngineMCMC.h:737
std::vector< double > fMCMCTrialFunctionScaleFactorStart
Definition: BCEngineMCMC.h:797
std::vector< int > fMCMCNTrialsTrue
Definition: BCEngineMCMC.h:776
std::vector< TTree * > fMCMCTrees
Definition: BCEngineMCMC.h:921
virtual void MCMCIterationInterface()
void MCMCSetValuesDefault()
std::vector< double > fMCMCprobMax
Definition: BCEngineMCMC.h:874
double fMCMCRValueParametersCriterion
Definition: BCEngineMCMC.h:900
double fMCMCRValue
Definition: BCEngineMCMC.h:904
std::vector< double > fMCMCxMax
Definition: BCEngineMCMC.h:854
const std::vector< double > & MCMCGetTrialFunctionScaleFactor() const
Definition: BCEngineMCMC.h:165
bool fMCMCFlagOrderParameters
Definition: BCEngineMCMC.h:835
unsigned fMCMCNLag
Definition: BCEngineMCMC.h:727
std::vector< double > fMCMCRValueParameters
Definition: BCEngineMCMC.h:907
void MCMCInChainUpdateStatistics()
void MCMCInChainWriteChains()
double fMCMCRValueCriterion
Definition: BCEngineMCMC.h:896
std::vector< TH1D * > fMCMCH1Marginalized
Definition: BCEngineMCMC.h:915
std::vector< double > fMCMCTrialFunctionScaleFactor
Definition: BCEngineMCMC.h:793
void MCMCSetPrecision(BCEngineMCMC::Precision precision)
std::vector< double > fMCMCprob
Definition: BCEngineMCMC.h:869
bool MCMCGetNewPointMetropolis(unsigned chain=0)
unsigned fMCMCNTrials
Definition: BCEngineMCMC.h:780