BayesianAnalysisToolkit  0.9.3
BCIntegrate.cxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2013, 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 "BCIntegrate.h"
13 #include "BCLog.h"
14 #include "BCMath.h"
15 #include "BCParameter.h"
16 #include "BCH2D.h"
17 #include "BCH1D.h"
18 
19 #include <TH1D.h>
20 #include <TH2D.h>
21 #include <TH3D.h>
22 #include <TCanvas.h>
23 #include <TFile.h>
24 #include <TMinuit.h>
25 #include <TRandom3.h>
26 #include <TString.h>
27 #include <TTree.h>
28 #include <TKey.h>
29 #include <TStyle.h>
30 
31 #ifdef HAVE_CUBA_H
32 #include <cuba.h>
33 #endif
34 
35 #include <math.h>
36 #include <limits>
37 
38 namespace
39 {
43  class BCIntegrateHolder
44  {
45  private:
46  BCIntegrate * global_this;
47 
48  public:
49 
50  BCIntegrateHolder() :
51  global_this(NULL)
52  {
53  }
54 
58  static BCIntegrate * instance(BCIntegrate * obj = NULL)
59  {
60  static BCIntegrateHolder result;
61  if (obj)
62  result.global_this = obj;
63 
64  return result.global_this;
65  }
66  };
67 }
68 
69 // ---------------------------------------------------------
71  fID(BCLog::GetHIndex()),
72  fMinuit(0),
73  fMinuitErrorFlag(0),
74  fFlagIgnorePrevOptimization(false),
75  fSAT0(100),
76  fSATmin(0.1),
77  fTreeSA(0),
78  fFlagWriteSAToFile(false),
79  fSANIterations(0),
80  fSATemperature(0),
81  fSALogProb(0),
82  fMarginalized1D(0),
83  fMarginalized2D(0),
84  fFlagMarginalized(false),
85  fOptimizationMethodCurrent(BCIntegrate::kOptDefault),
86  fOptimizationMethodUsed(BCIntegrate::kOptEmpty),
87  fIntegrationMethodCurrent(BCIntegrate::kIntDefault),
88  fIntegrationMethodUsed(BCIntegrate::kIntEmpty),
89  fMarginalizationMethodCurrent(BCIntegrate::kMargDefault),
90  fMarginalizationMethodUsed(BCIntegrate::kMargEmpty),
91  fSASchedule(BCIntegrate::kSACauchy),
92  fNIterationsMin(0),
93  fNIterationsMax(1000000),
94  fNIterationsPrecisionCheck(1000),
95  fNIterationsOutput(0),
96  fNIterations(0),
97  fLogMaximum(-std::numeric_limits<double>::max()),
98  fIntegral(-1),
99  fRelativePrecision(1e-2),
100  fAbsolutePrecision(1e-6),
101  fError(-999.),
102  fCubaIntegrationMethod(BCIntegrate::kCubaVegas)
103 {
104  fMinuitArglist[0] = 20000;
105  fMinuitArglist[1] = 0.01;
106 }
107 
108 // ---------------------------------------------------------
110 {
111  Copy(other);
112 }
113 
114 // ---------------------------------------------------------
116 {
117  Copy(other);
118  return *this;
119 }
120 
121 // ---------------------------------------------------------
122 void BCIntegrate::Copy(const BCIntegrate & other)
123 {
124  BCEngineMCMC::Copy(other);
125 
126  fID = other.fID;
129  fLogMaximum = other.fLogMaximum;
130  fMinuit = new TMinuit();
131  fMinuitArglist[0] = other.fMinuitArglist[0];
132  fMinuitArglist[1] = other.fMinuitArglist[1];
135  fSAT0 = other.fSAT0;
136  fSATmin = other.fSATmin;
137  fTreeSA = 0;
141  fSALogProb = other.fSALogProb;
142  fSAx = other.fSAx;
151  fSASchedule = other.fSASchedule;
156  fNIterations = other.fNIterations;
157  fIntegral = other.fIntegral;
160  fError = other.fError;
167 }
168 
169 // ---------------------------------------------------------
171 {
172  delete fMinuit;
173 }
174 
175 // ---------------------------------------------------------
176 double BCIntegrate::GetBestFitParameter(unsigned index) const
177 {
178  if( ! fParameters.ValidIndex(index))
179  return -1e+111;
180 
181  if(fBestFitParameters.empty()) {
182  BCLog::OutError("BCIntegrate::GetBestFitParameter : Mode finding not yet run, returning center of the range.");
183  return (fParameters[index]->GetUpperLimit() + fParameters[index]->GetLowerLimit() ) / 2.;
184  }
185 
186  return fBestFitParameters[index];
187 }
188 
189 // ---------------------------------------------------------
190 double BCIntegrate::GetBestFitParameterError(unsigned index) const
191 {
192  if( ! fParameters.ValidIndex(index)) {
193  BCLog::OutError("BCIntegrate::GetBestFitParameterError : Parameter index out of range, returning -1.");
194  return -1;
195  }
196 
197  /*
198  if(fBestFitParameterErrors.size()==0) {
199  BCLog::OutError("BCIntegrate::GetBestFitParameterError : Mode finding not yet run, returning -1.");
200  return -1.;
201  }
202 
203  if(fBestFitParameterErrors[index]<0.)
204  BCLog::OutWarning("BCIntegrate::GetBestFitParameterError : Parameter error not available, returning -1.");
205  */
206 
207  return fBestFitParameterErrors[index];
208 }
209 
210 // ---------------------------------------------------------
211 double BCIntegrate::Eval(const std::vector<double> & /*x*/)
212 {
213  BCLog::OutWarning( "BCIntegrate::Eval. No function. Function needs to be overloaded.");
214  return 0;
215 }
216 
217 // ---------------------------------------------------------
218 double BCIntegrate::LogEval(const std::vector<double> &x)
219 {
220  // this method should better also be overloaded
221  return log(Eval(x));
222 }
223 
224 // ---------------------------------------------------------
226 {
228 
229  fBestFitParameterErrors.clear();
230  fBestFitParameters.clear();
231  fLogMaximum = -std::numeric_limits<double>::max();
232 
233  // remove marginalized histograms
234  // set marginalization flag
235  fFlagMarginalized = false;
236 }
237 
238 // ---------------------------------------------------------
240  unsigned n = 0;
241  for(unsigned i = 0; i < fParameters.Size(); ++i)
242  if ( ! fParameters[i]->Fixed())
243  ++n;
244  return n;
245 }
246 
247 // ---------------------------------------------------------
249  double integrationVolume = -1.;
250 
251  for(unsigned i = 0; i < fParameters.Size(); i++)
252  if ( ! fParameters[i]->Fixed()) {
253  if (integrationVolume<0)
254  integrationVolume = 1;
255  integrationVolume *= fParameters[i]->GetRangeWidth();
256  }
257 
258  if (integrationVolume<0)
259  integrationVolume = 0;
260 
261  return integrationVolume;
262 }
263 
264 // ---------------------------------------------------------
266 {
267  // check if parameters are defined
268  if (fParameters.Size() < 1) {
269  BCLog::OutError("BCIntegrate::Integrate : No parameters defined. Aborting.");
270  return -1.;
271  }
272 
273  // output
275  BCLog::OutSummary(Form("Integrate using %s", DumpCurrentIntegrationMethod().c_str()));
276 
278  {
279 
280  // Empty
282  {
283  BCLog::OutWarning("BCIntegrate::Integrate : No integration method chosen.");
284  return 0;
285  }
286 
287 
288  // Monte Carlo Integration
290  {
291  std::vector<double> sums (2,0.0);
292  sums.push_back(CalculateIntegrationVolume());
297  sums);
298 
299  // set used integration method
301 
302  // return integral
303  return fIntegral;
304  }
305 
306  // CUBA library
308  {
310 
311  // set used integration method
313 
314  // return integral
315  return fIntegral;
316  }
317 
318  // CUBA library
320  {
322 
323  // set used integration method
325 
326  // return integral
327  return fIntegral;
328  }
329 
330  // default
332  {
333  if (GetNFreeParameters() <= 2)
335  else
336 #ifdef HAVE_CUBA_H
338 #else
340 #endif
341  return Integrate();
342  }
343 
344  default:
345  BCLog::OutError(TString::Format("BCIntegrate::Integrate : Invalid integration method: %d", fIntegrationMethodCurrent));
346  break;
347  }
348 
349  return 0;
350 }
351 
352 // ---------------------------------------------------------
354 {
355  // remember original method
357 
358  // set method
359  SetIntegrationMethod(intmethod);
360 
361  // run algorithm
362  double integral = Integrate();
363 
364  // re-set original method
365  SetIntegrationMethod(method_temp);
366 
367  // return integral
368  return integral;
369 
370 }
371 
372 // ---------------------------------------------------------
373 void BCIntegrate::SetBestFitParameters(const std::vector<double> &x, const double &new_value, double &old_value) {
374  if (new_value < old_value)
375  return;
376  old_value = new_value;
378 }
379 
380 // ---------------------------------------------------------
382 {
383  if (fNIterationsOutput > 0)
384  return fNIterationsOutput;
385  const unsigned nwrite = fNIterationsMax / 10;
386  if(nwrite < 10000)
387  return 1000;
388  if(nwrite < 100000)
389  return 10000;
390  if(nwrite < 1000000)
391  return 100000;
392  return 1000000;
393 }
394 
395 // ---------------------------------------------------------
397 {
398  const unsigned NVarNow = GetNIntegrationVariables();
399 
401 
402  if(fParameters.Size() != NVarNow) {
403 
404  level = BCLog::detail;
405  bool printed = false;
406 
407  if (type==kIntCuba)
408  {
409  BCLog::OutDetail(TString::Format("Running %s (%s) integration over %i dimensions out of %i.",
410  DumpIntegrationMethod(type).c_str(),
411  DumpCubaIntegrationMethod(cubatype).c_str(),
412  NVarNow, fParameters.Size()));
413  printed = true;
414  }
415 
416  if (not printed)
417  BCLog::OutDetail(TString::Format("Running %s integration over %i dimensions out of %i.",
418  DumpIntegrationMethod(type).c_str(),
419  NVarNow, fParameters.Size()));
420 
421  BCLog::OutDetail(" --> Fixed parameters:");
422  for(unsigned i = 0; i < fParameters.Size(); i++)
423  if(fParameters[i]->Fixed())
424  BCLog::OutDetail(TString::Format(" %3i : %g", i, fParameters[i]->GetFixedValue()));
425  }
426  else {
427  bool printed = false;
428 
429  if (type==kIntCuba) {
430  BCLog::OutDetail(TString::Format("Running %s (%s) integration over %i dimensions.",
431  DumpIntegrationMethod(type).c_str(),
432  DumpCubaIntegrationMethod(cubatype).c_str(),
433  NVarNow));
434  printed = true;
435  }
436 
437  if (not printed)
438  BCLog::OutDetail(TString::Format("Running %s integration over %i dimensions.",
439  DumpIntegrationMethod(type).c_str(),
440  NVarNow));
441  }
442 
443  if (GetNIterationsMin() > 0 && GetNIterationsMax() > 0 ) {
444  BCLog::Out(level, TString::Format(" --> Minimum number of iterations: %i", GetNIterationsMin()));
445  BCLog::Out(level, TString::Format(" --> Maximum number of iterations: %i", GetNIterationsMax()));
446  }
447  BCLog::Out(level, TString::Format(" --> Target relative precision: %e", GetRelativePrecision()));
448  BCLog::Out(level, TString::Format(" --> Target absolute precision: %e", GetAbsolutePrecision()));
449 }
450 
451 // ---------------------------------------------------------
452 void BCIntegrate::LogOutputAtEndOfIntegration(double integral, double absprecision, double relprecision, int nIterations)
453 {
454  BCLog::OutSummary(TString::Format(" --> Result of integration: %e +- %e", integral, absprecision));
455  BCLog::OutSummary(TString::Format(" --> Obtained relative precision: %e. ", relprecision));
456  if (nIterations >= 0)
457  BCLog::OutSummary(TString::Format(" --> Number of iterations: %i", nIterations));
458 }
459 
460 // ---------------------------------------------------------
461 void BCIntegrate::LogOutputAtIntegrationStatusUpdate(BCIntegrationMethod type, double integral, double absprecision, int nIterations)
462 {
463  BCLog::OutDetail(TString::Format("%s. Iteration %i, integral: %e +- %e.", DumpIntegrationMethod(type).c_str(), nIterations, integral, absprecision));
464 }
465 
466 // ---------------------------------------------------------
467 double BCIntegrate::Integrate(BCIntegrationMethod type, tRandomizer randomizer, tEvaluator evaluator, tIntegralUpdater updater,
468  std::vector<double> &sums)
469 {
471 
472  // reset variables
473  double pmax = 0.;
474  double integral = 0.;
475  double absprecision = 2.*fAbsolutePrecision;
476  double relprecision = 2.*fRelativePrecision;
477 
478  std::vector<double> randx (fParameters.Size(), 0.);
479 
480  // how often to print out the info line to screen
481  int nwrite = IntegrationOutputFrequency();
482 
483  // reset number of iterations
484  fNIterations = 0;
485  bool accepted;
486 
487  // iterate while number of iterations is lower than minimum number of iterations
488  // or precision is not reached and the number of iterations is lower than maximum number of iterations
489  while ((GetRelativePrecision() < relprecision and GetAbsolutePrecision() < absprecision and GetNIterations() < GetNIterationsMax())
491  {
492 
493  // get random numbers
494  (this->*randomizer)(randx);
495 
496  // evaluate function at sampled point
497  // updating sums & checking for maximum probability
498 
499  SetBestFitParameters(randx, (this->*evaluator)(sums,randx,accepted), pmax);
500 
501  // increase number of iterations
502  if (accepted)
503  fNIterations++;
504 
505  // update precisions
507  (*updater)(sums, fNIterations, integral, absprecision);
508  relprecision = absprecision / integral;
509  }
510 
511  // write status
512  if (fNIterations % nwrite == 0) {
513  double temp_integral;
514  double temp_absprecision;
515  (*updater)(sums, fNIterations, temp_integral, temp_absprecision);
516  LogOutputAtIntegrationStatusUpdate(type, temp_integral, temp_absprecision, fNIterations);
517  }
518  }
519 
520  // calculate integral
521  (*updater)(sums, fNIterations, integral, absprecision);
522  relprecision = absprecision / integral;
523 
524  if (unsigned(fNIterations) >= fMCMCNIterationsMax)
525  BCLog::OutWarning("BCIntegrate::Integrate: Did not converge within maximum number of iterations");
526 
527  // print to log
528  LogOutputAtEndOfIntegration(integral, absprecision, relprecision, fNIterations);
529 
530  fError = absprecision;
531  return integral;
532 }
533 
534 // ---------------------------------------------------------
535 double BCIntegrate::EvaluatorMC(std::vector<double> &sums, const std::vector<double> &point, bool &accepted) {
536  const double value = Eval(point);
537 
538  // all samples accepted in sample-mean integration
539  accepted = true;
540 
541  // add value to sum and sum of squares
542  sums[0] += value;
543  sums[1] += value * value;
544 
545  return value;
546 }
547 
548 // ---------------------------------------------------------
549 void BCIntegrate::IntegralUpdaterMC(const std::vector<double> &sums, const int &nIterations, double &integral, double &absprecision) {
550  // sample mean including the volume of the parameter space
551  integral = sums[2] * sums[0] / nIterations;
552 
553  // unbiased estimate
554  absprecision = sqrt((1.0 / (nIterations - 1)) * (sums[2] * sums[2] * sums[1] / double(nIterations) - integral * integral));
555 }
556 
557 // ---------------------------------------------------------
559  switch(type)
560  {
562  return false;
564  return true;
566  return true;
568  return true;
569  default:
570  BCLog::OutError(TString::Format("BCIntegrate::CheckMarginalizationAvailability. Invalid marginalization method: %d.", type));
571  break;
572  }
573  return false;
574 }
575 
576 // ---------------------------------------------------------
577 bool BCIntegrate::CheckMarginalizationIndices(TH1* hist, const std::vector<unsigned> &index) {
578  if (index.size()==0) {
579  BCLog::OutError("BCIntegrate::Marginalize : No marginalization parameters chosen.");
580  return false;
581  }
582 
583  if (index.size() >= 4 or index.size() > fParameters.Size()) {
584  BCLog::OutError("BCIntegrate::Marginalize : Too many marginalization parameters.");
585  return false;
586  }
587 
588  if ((int)index.size()<hist->GetDimension()) {
589  BCLog::OutError(TString::Format("BCIntegrate::Marginalize : Too few (%d) indices supplied for histogram dimension (%d)",(int)index.size(),hist->GetDimension()));
590  return false;
591  }
592 
593  for (unsigned i=0; i<index.size(); i++) {
594  // check if indices are in bounds
595  if ( ! fParameters.ValidIndex(index[i])) {
596  BCLog::OutError(TString::Format("BCIntegrate::Marginalize : Parameter index (%d) out of bound.",index[i]));
597  return false;
598  }
599  // check for duplicate indices
600  for (unsigned j=0; j<index.size(); j++)
601  if (i!=j and index[i]==index[j]) {
602  BCLog::OutError(TString::Format("BCIntegrate::Marginalize : Parameter index (%d) appears more than once",index[i]));
603  return false;
604  }
605  }
606  return true;
607 }
608 #if 0
609 // ---------------------------------------------------------
610 TH1D* BCIntegrate::Marginalize(BCIntegrationMethod type, unsigned index)
611 {
612  BCParameter * par = fParameters.Get(index);
613  if ( ! par)
614  return NULL;
615 
616  // create histogram
617  TH1D * hist = new TH1D(TString::Format("h1_%s", par->GetName().data()),
618  TString::Format(";%s;(unit %s)^{-1};", par->GetName().data(), par->GetName().data()),
619  par->GetNbins(), par->GetLowerLimit(), par->GetUpperLimit());
620 
621  // fill histogram
622  std::vector<unsigned> indices(1, index);
623  Marginalize(hist, type, indices);
624 
625  return hist;
626 }
627 
628 // ---------------------------------------------------------
629 TH2D* BCIntegrate::Marginalize(BCIntegrationMethod type, unsigned index1, unsigned index2)
630 {
631  BCParameter * par1 = fParameters.Get(index1);
632  BCParameter * par2 = fParameters.Get(index2);
633  if ( ! par1 || par2)
634  return NULL;
635 
636  // create histogram
637  TH2D * hist = new TH2D(TString::Format("h2_%s_%s", par1->GetName().data(), par2->GetName().data()),
638  TString::Format(";%s;%s;(unit %s)^{-1}(unit %s)^{-1}",
639  par1->GetName().data(), par2->GetName().data(),
640  par1->GetName().data(), par2->GetName().data()),
641  par1->GetNbins(), par1->GetLowerLimit(), par1->GetUpperLimit(),
642  par2->GetNbins(), par2->GetLowerLimit(), par2->GetUpperLimit());
643 
644  // fill histogram
645  std::vector<unsigned> indices;
646  indices.push_back(index1);
647  indices.push_back(index2);
648  Marginalize(hist,type,indices);
649 
650  return hist;
651 }
652 
653 // ---------------------------------------------------------
654 bool BCIntegrate::Marginalize(TH1* hist, BCIntegrationMethod type, const std::vector<unsigned> &index)
655 {
656  // debugKK: does this method really marginalize?
657 
658  // if (!CheckMarginalizationAvailability(type))
659  // return false;
660 
661  if (!CheckMarginalizationIndices(hist,index))
662  return false;
663 
664  // todo is this true?
665  // Currently this does not seem to work for Cuba integration beyond 1 dimension
666  if (type==kIntCuba and hist->GetDimension()>1) {
667  BCLog::OutError("BCIntegrate::Marginalize : Cuba integration currently only functions for 1D marginalization.");
668  return false;
669  }
670 
671  // generate string output
672  char * parnames = new char;
673  for (unsigned i=0; i<index.size(); i++) {
674  parnames = Form("%s %d (%s),",parnames,index[i],fParameters[i]->GetName().data());
675  }
676  if (index.size()==1)
677  BCLog::OutDebug(TString::Format(" --> Marginalizing model w/r/t parameter%s using %s.",parnames, DumpCurrentMarginalizationMethod().c_str()));
678  else
679  BCLog::OutDebug(TString::Format(" --> Marginalizing model w/r/t parameters%s using %s.",parnames, DumpCurrentMarginalizationMethod().c_str()));
680 
681  // Store original integration limits and fixed flags
682  // and unfix marginalization parameters;
683  std::vector<double> origMins, origMaxs;
684  std::vector<bool> origFix;
685  for (unsigned i=0; i<index.size(); i++) {
686  BCParameter * par = fParameters[index[i]];
687  origMins.push_back(par->GetLowerLimit());
688  origMaxs.push_back(par->GetUpperLimit());
689  origFix.push_back(par->Fixed());
690  par->Fix(false);
691  }
692 
693  // Set histogram title to indicate fixed variables
694  std::string title;
695  for (unsigned i=0; i < fParameters.Size(); ++i)
696  if (fParameters[i]->Fixed()) {
697  title += TString::Format(" (%s=%e)", fParameters[i]->GetName().data(), fParameters[i]->GetFixedValue());
698  }
699  if ( ! title.empty())
700  {
701  hist -> SetTitle(("Fixed: "+title).data());
702  }
703 
704  // get bin count
705  int N = hist->GetNbinsX() * hist->GetNbinsY() * hist->GetNbinsZ();
706 
707  // Store fNIterationsMax and change
708  int nIterationsMax = fNIterationsMax;
712 
713  // todo not thread safe!
714  // integrate each bin
715  for (int i=1; i<=hist->GetNbinsX(); i++) {
716  fParameters[index[0]]->SetLowerLimit(hist->GetXaxis()->GetBinLowEdge(i));
717  fParameters[index[0]]->SetUpperLimit(hist->GetXaxis()->GetBinLowEdge(i+1));
718  double binwidth1d = hist -> GetXaxis() -> GetBinWidth(i);
719  if (hist->GetDimension()>1)
720  for (int j=1; j<=hist->GetNbinsY(); j++) {
721  fParameters[index[1]]->SetLowerLimit(hist -> GetYaxis() -> GetBinLowEdge(j));
722  fParameters[index[1]]->SetUpperLimit(hist -> GetYaxis() -> GetBinLowEdge(j+1));
723  double binwidth2d = binwidth1d * hist->GetYaxis()->GetBinWidth(j);
724  if (hist->GetDimension()>2)
725  for (int k=1; k<=hist->GetNbinsZ(); k++) {
726  fParameters[index[2]]->SetLowerLimit(hist -> GetZaxis() -> GetBinLowEdge(k));
727  fParameters[index[2]]->SetUpperLimit(hist -> GetZaxis() -> GetBinLowEdge(k+1));
728  double binwidth3d = binwidth2d * hist->GetZaxis()->GetBinWidth(k);
729  hist -> SetBinContent(i, j, k, Integrate(type)/binwidth3d);
730  hist -> SetBinError (i, j, k, GetError()/binwidth3d);
731  }
732  else {
733  hist -> SetBinContent(i, j, Integrate(type)/binwidth2d);
734  hist -> SetBinError (i, j, GetError()/binwidth2d);
735  }
736  }
737  else {
738  hist -> SetBinContent(i, Integrate(type)/binwidth1d);
739  hist -> SetBinError (i, GetError()/binwidth1d);
740  }
741  }
742 
743  // restore original integration limits and fixed flags
744  for (unsigned i=0; i<index.size(); i++) {
745  fParameters[index[i]]->SetLowerLimit(origMins[i]);
746  fParameters[index[i]]->SetUpperLimit(origMaxs[i]);
747  fParameters[index[i]]->Fix(origFix[i]);
748  }
749 
750  // restore original fNIterationsMax
751  fNIterationsMax = nIterationsMax;
752 
753  return true;
754 }
755 #endif
756 
757 // ---------------------------------------------------------
759 {
760  // check if parameters are defined
761  if (fParameters.Size() < 1) {
762  BCLog::OutError("BCIntegrate::MarginalizeAll : No parameters defined. Aborting.");
763  return 0;
764  }
765 
766  // check if marginalization method is defined
768  BCLog::OutError(Form("BCIntegrate::MarginalizeAll : Marginalization method not implemented \'%s\'. Aborting.", DumpCurrentMarginalizationMethod().c_str()));
769  return 0;
770  }
771 
772  // output
774  BCLog::OutSummary(Form("Marginalize using %s", DumpCurrentMarginalizationMethod().c_str()));
775 
776  switch (GetMarginalizationMethod())
777  {
778 
779  // Empty
781  {
782  BCLog::OutWarning("BCIntegrate::MarginalizeAll : No marginalization method chosen.");
783  return 0;
784  }
785 
786  // Markov Chain Monte Carlo
788  {
789  // start preprocess
791 
792  // run the Markov chains
793  MCMCMetropolis();
794 
795  // start postprocess
797 
798  // set pointers to marginalized distributions
799  unsigned int npar = GetNParameters();
800 
801  fMarginalized1D.clear();
802  for (unsigned int i = 0; i < npar; ++i) {
804  }
805 
806  fMarginalized2D.clear();
807  if (npar > 1) {
808  for (unsigned int i = 0; i < npar; ++i) {
809  for (unsigned int j = 0; j < npar; ++j) {
810  if (i < j)
811  fMarginalized2D.push_back(MCMCGetH2Marginalized(i, j));
812  }
813  }
814  }
815 
816  // set used marginalization method
818 
819  // check if mode is better than previous one
825  }
826 
827  break;
828  }
829 
830  // Sample Mean
832  {
833  return 0;
834  }
835 
836  // Slice
838  {
839  std::vector<double> fixpoint(GetNParameters());
840  for (unsigned int i = 0; i < GetNParameters(); ++i) {
841  if (fParameters[i]->Fixed())
842  fixpoint[i] = fParameters[i]->GetFixedValue();
843  else
844  fixpoint[i] = 0;
845  }
846 
847  // start preprocess
849 
850  // store highest probability
851  double probmax = -std::numeric_limits<double>::infinity();
852  std::vector<double> bestfit_parameters(fParameters.Size(), -std::numeric_limits<double>::infinity());
853  // correct fixed parameter values
854  // the other should have been determined above
855  for (unsigned i = 0; i < fParameters.Size(); ++i)
856  if (fParameters[i]->Fixed())
857  bestfit_parameters[i] = fParameters[i]->GetFixedValue();
858 
859  fMarginalized1D.clear();
860  if (GetNFreeParameters() == 1) {
861  for (unsigned int i = 0; i < GetNParameters(); ++i) {
862  if (!fParameters[i]->Fixed()) {
863  // calculate slice
864  BCH1D* hist_temp = GetSlice(fParameters[i], fixpoint, 0);
865  fMarginalized1D.push_back(hist_temp);
866 
867  // remember best fit before it is normalized and the value is wrong
868  const int index = hist_temp->GetHistogram()->GetMaximumBin();
869  probmax = hist_temp->GetHistogram()->GetBinContent(index);
870  bestfit_parameters.at(i) = hist_temp->GetHistogram()->GetBinCenter(index);
871 
872  // normalize to unity
873  hist_temp->GetHistogram()->Scale(1./hist_temp->GetHistogram()->Integral());
874  }
875  else
876  fMarginalized1D.push_back(0);
877  }
878 
879  fMarginalized2D.clear();
880  for (unsigned int i = 0; i < GetNParameters(); ++i) {
881  for (unsigned int j = 0; j < GetNParameters(); ++j) {
882  if (i >= j)
883  continue;
884  else
885  fMarginalized2D.push_back(0);
886  }
887  }
888  }
889  else if (GetNFreeParameters() == 2) {
890  // create a 2D histogram
891 
892  BCH2D* hist2d_temp = 0;
893 
894  fMarginalized2D.clear();
895  for (unsigned int i = 0; i < GetNParameters(); ++i) {
896  for (unsigned int j = 0; j < GetNParameters(); ++j) {
897  if (i >= j)
898  continue;
899  if (!fParameters[i]->Fixed() && !fParameters[j]->Fixed()) {
900  // calculate slice
901  hist2d_temp = GetSlice(GetParameter(i), GetParameter(j), fixpoint, 0);
902  fMarginalized2D.push_back(hist2d_temp);
903 
904  // remember best fit before it is normalized and the value is wrong
905  int index1, index2, useless_index;
906  hist2d_temp->GetHistogram()->GetMaximumBin(index1, index2, useless_index);
907  probmax = hist2d_temp->GetHistogram()->GetBinContent(index1, index2, useless_index);
908  bestfit_parameters.at(i) = hist2d_temp->GetHistogram()->GetXaxis()->GetBinCenter(index1);
909  bestfit_parameters.at(j) = hist2d_temp->GetHistogram()->GetYaxis()->GetBinCenter(index2);
910 
911  // normalize to unity
912  hist2d_temp->GetHistogram()->Scale(1./hist2d_temp->GetHistogram()->Integral());
913  }
914  else
915  fMarginalized2D.push_back(0);
916  }
917  }
918 
919  // marginalize by projecting
920  fMarginalized1D.clear();
921  for (unsigned int i = 0; i < GetNParameters(); ++i)
922  fMarginalized1D.push_back(0);
923  for (unsigned int i = 0; i < GetNParameters(); ++i) {
924  for (unsigned int j = 0; j < GetNParameters(); ++j) {
925  if (i >= j)
926  continue;
927  if (!fParameters[i]->Fixed() && !fParameters[j]->Fixed()) {
928  BCH1D* hist_x = new BCH1D( hist2d_temp->GetHistogram()->ProjectionX() );
929  hist_x->GetHistogram()->UseCurrentStyle(); // reset style because histogram is created by a projection
930  hist_x->GetHistogram()->SetStats(kFALSE);
931  fMarginalized1D[i] = hist_x;
932  BCH1D* hist_y = new BCH1D( hist2d_temp->GetHistogram()->ProjectionY() );
933  hist_y->GetHistogram()->UseCurrentStyle(); // reset style because histogram is created by a projection
934  hist_y->GetHistogram()->SetStats(kFALSE);
935  fMarginalized1D[j] = hist_y;
936  }
937  }
938  }
939  }
940  else {
941  BCLog::OutWarning("BCIntegrate::MarginalizeAll : Option works for 1D and 2D problems.");
942  return 0;
943  }
944 
945  // save if improved the log posterior
946 
947  if (fBestFitParameters.empty() || probmax > fMCMCLogMaximum) {
948  fLogMaximum = probmax;
949  fBestFitParameters = bestfit_parameters;
950  fBestFitParameterErrors.assign(fBestFitParameters.size(), std::numeric_limits<double>::infinity());
951  // todo can't set this one yet
952  // fOptimizationMethodUsed =
953  }
954 
955  BCLog::OutDetail(" --> Global mode from Grid:");
956  BCLog::OutDebug(Form(" --> Posterior value: %g", probmax));
957  int ndigits = (int) log10(fParameters.Size());
958  for (unsigned i = 0; i < fParameters.Size(); ++i)
959  BCLog::OutDetail(TString::Format(" --> parameter %*i: %.4g", ndigits+1, i, bestfit_parameters[i]));
960 
961  // start postprocess
963 
964  // set used marginalization method
966 
967  break;
968  }
969 
970  // default
972  {
973  if ( GetNFreeParameters() <= 2 ) {
975  }
976  else {
978  }
979 
980  // call again
981  return MarginalizeAll();
982 
983  break;
984  }
985 
986  default:
987  BCLog::OutError(TString::Format("BCIntegrate::MarginalizeAll : Invalid marginalization method: %d", GetMarginalizationMethod()));
988  return 0;
989  break;
990  }
991 
992  // set flag
993  fFlagMarginalized = true;
994 
995  return 1;
996 }
997 
998 // ---------------------------------------------------------
1000 {
1001  // remember original method
1003 
1004  // set method
1005  SetMarginalizationMethod(margmethod);
1006 
1007  // run algorithm
1008  int result = MarginalizeAll();
1009 
1010  // re-set original method
1011  SetMarginalizationMethod(method_temp);
1012 
1013  // return result
1014  return result;
1015 }
1016 
1017 // ---------------------------------------------------------
1018 BCH1D * BCIntegrate::GetSlice(const BCParameter* parameter, const std::vector<double> parameters, int nbins, bool flag_norm)
1019 {
1020  // check if parameter exists
1021  if (!parameter) {
1022  BCLog::OutError("BCIntegrate::GetSlice : Parameter does not exist.");
1023  return 0;
1024  }
1025 
1026  // check if parameter is fixed
1027  if (parameter->Fixed())
1028  return 0;
1029 
1030  // create local copy of parameter set
1031  std::vector<double> parameters_temp;
1032  parameters_temp = parameters;
1033 
1034  // check if parameter set if defined
1035  if (parameters_temp.empty() && GetNParameters() == 1) {
1036  parameters_temp.push_back(0);
1037  }
1038  else if (parameters_temp.empty() && GetNParameters() != 1) {
1039  BCLog::OutError("BCIntegrate::GetSlice : No parameters defined.");
1040  return 0;
1041  }
1042 
1043  // calculate number of bins
1044  if (nbins <= 0)
1045  nbins = parameter->GetNbins();
1046 
1047  // create histogram
1048  TH1D * hist = new TH1D("", "", nbins, parameter->GetLowerLimit(), parameter->GetUpperLimit());
1049  hist->UseCurrentStyle();
1050 
1051  // set axis labels
1052  hist->SetXTitle(parameter->GetLatexName().data());
1053  if (GetNParameters() == 1)
1054  hist->SetYTitle(Form("p(%s|data)", parameter->GetLatexName().data()));
1055  else
1056  hist->SetYTitle(Form("p(%s|data, all other parameters fixed)", parameter->GetLatexName().data()));
1057  hist->SetStats(kFALSE);
1058 
1059  // fill histogram
1060  for (int i = 1; i <= nbins; ++i) {
1061  double par_temp = hist->GetBinCenter(i);
1062  parameters_temp[fParameters.Index(parameter->GetName())] = par_temp;
1063  double prob = Eval(parameters_temp);
1064  hist->SetBinContent(i, prob);
1065  }
1066 
1067  // normalize
1068  if (flag_norm)
1069  hist->Scale(1.0/hist->Integral());
1070 
1071  // set histogram
1072  BCH1D * hprob = new BCH1D();
1073  hprob->SetHistogram(hist);
1074 
1075  return hprob;
1076 }
1077 
1078 // ---------------------------------------------------------
1079 BCH2D* BCIntegrate::GetSlice(const BCParameter* parameter1, const BCParameter* parameter2, const std::vector<double> parameters, int nbins, bool flag_norm)
1080 {
1081  return GetSlice(parameter1->GetName().c_str(), parameter2->GetName().c_str(), parameters, nbins, flag_norm);
1082 }
1083 
1084 // ---------------------------------------------------------
1085 BCH2D* BCIntegrate::GetSlice(const char* name1, const char* name2, const std::vector<double> parameters, int nbins, bool flag_norm)
1086 {
1087  return GetSlice(fParameters.Index(name1), fParameters.Index(name2), parameters, nbins, flag_norm);
1088 }
1089 
1090 // ---------------------------------------------------------
1091 BCH2D* BCIntegrate::GetSlice(unsigned index1, unsigned index2, const std::vector<double> parameters, int nbins, bool flag_norm)
1092 {
1093  // check if parameters exists
1094  if (!fParameters.ValidIndex(index1) || !fParameters.ValidIndex(index2)) {
1095  BCLog::OutError("BCIntegrate::GetSlice : Parameter does not exist.");
1096  return 0;
1097  }
1098 
1099  // check if parameters are fixed
1100  if (fParameters[index1]->Fixed() || fParameters[index2]->Fixed())
1101  return 0;
1102 
1103  // create local copy of parameter set
1104  std::vector<double> parameters_temp;
1105  parameters_temp = parameters;
1106 
1107  // check number of dimensions
1108  if (GetNParameters() < 2) {
1109  BCLog::OutError("BCIntegrate::GetSlice : Number of parameters need to be at least 2.");
1110  }
1111 
1112  // check if parameter set if defined
1113  if (parameters_temp.size()==0 && GetNParameters()==2) {
1114  parameters_temp.push_back(0);
1115  parameters_temp.push_back(0);
1116  }
1117  else if (parameters_temp.size()==0 && GetNParameters()>2) {
1118  BCLog::OutError("BCIntegrate::GetSlice : No parameters defined.");
1119  return 0;
1120  }
1121 
1122  // calculate number of bins
1123  const BCParameter * p1 = fParameters.Get(index1);
1124  const BCParameter * p2 = fParameters.Get(index2);
1125  unsigned nbins1, nbins2;
1126  if (nbins <= 0) {
1127  nbins1 = p1->GetNbins();
1128  nbins2 = p2->GetNbins();
1129  } else {
1130  nbins1 = nbins2 = nbins;
1131  }
1132 
1133  // create histogram
1134  TH2D * hist = new TH2D("", "", nbins1, p1->GetLowerLimit(), p1->GetUpperLimit(),
1135  nbins2, p2->GetLowerLimit(), p2->GetUpperLimit());
1136  hist->UseCurrentStyle();
1137 
1138  // set axis labels
1139  hist->SetXTitle(Form("%s", p1->GetLatexName().data()));
1140  hist->SetYTitle(Form("%s", p2->GetLatexName().data()));
1141  hist->SetStats(kFALSE);
1142 
1143  // fill histogram
1144  for (unsigned int ix = 1; ix <= nbins1; ++ix) {
1145  for (unsigned int iy = 1; iy <= nbins2; ++iy) {
1146  double par_temp1 = hist->GetXaxis()->GetBinCenter(ix);
1147  double par_temp2 = hist->GetYaxis()->GetBinCenter(iy);
1148 
1149  parameters_temp[index1] = par_temp1;
1150  parameters_temp[index2] = par_temp2;
1151 
1152  double prob = Eval(parameters_temp);
1153  hist->SetBinContent(ix, iy, prob);
1154  }
1155  }
1156 
1157  // calculate normalization
1158  double norm = hist->Integral("width");
1159 
1160  // normalize
1161  if (flag_norm)
1162  hist->Scale(1.0/norm);
1163 
1164  // set histogram
1165  BCH2D * hprob = new BCH2D();
1166  hprob->SetHistogram(hist);
1167 
1168  // renormalize
1169  hist->Scale(norm / hist->Integral("width"));
1170 
1171  return hprob;
1172 }
1173 // ---------------------------------------------------------
1174 double BCIntegrate::GetRandomPoint(std::vector<double> &x)
1175 {
1177  return Eval(x);
1178 }
1179 
1180 // ---------------------------------------------------------
1181 void BCIntegrate::GetRandomVectorUnitHypercube(std::vector<double> &x) const
1182 {
1183  fRandom->RndmArray(x.size(), &x.front());
1184 }
1185 
1186 // ---------------------------------------------------------
1187 void BCIntegrate::GetRandomVectorInParameterSpace(std::vector<double> &x) const
1188 {
1190 
1191  for (unsigned i = 0; i < fParameters.Size(); i++){
1192  if (fParameters[i]->Fixed())
1193  x[i] = fParameters[i]->GetFixedValue();
1194  else
1195  x[i] = fParameters[i]->GetLowerLimit() + x[i] * fParameters[i]->GetRangeWidth();
1196  }
1197 }
1198 
1199 // ---------------------------------------------------------
1201 {
1202  if ( !parameter)
1203  return 0;
1204  return GetMarginalized(fParameters.Index(parameter->GetName()));
1205 }
1206 
1207 // ---------------------------------------------------------
1209 {
1210  // check if marginalized histogram exists
1211  if (fMarginalized1D.size() <= index)
1212  return 0;
1213 
1214  // get histogram
1215  BCH1D * htemp = fMarginalized1D.at(index);
1216 
1217  // check if histogram exists
1218  if (!htemp)
1219  return 0;
1220 
1221  // set global mode
1222  if (fBestFitParameters.size() == GetNParameters())
1223  htemp->SetGlobalMode(fBestFitParameters.at(index));
1224 
1225  // set axis labels
1226  htemp->GetHistogram()->SetName(Form("hist_%i_%s", fID, fParameters[index]->GetName().data()));
1227  htemp->GetHistogram()->SetYTitle(Form("p(%s|data)", fParameters[index]->GetLatexName().data()));
1228 
1229  // return histogram
1230  return htemp;
1231 }
1232 
1233  // ---------------------------------------------------------
1235 {
1236  TFile * froot = TFile::Open(file);
1237  if (!froot->IsOpen()) {
1238  BCLog::OutError(Form("BCIntegrate::ReadMarginalizedFromFile : Couldn't open file %s.", file));
1239  return 0;
1240  }
1241 
1242  // We reset the MCMCEngine here for the moment.
1243  // In the future maybe we only want to do this if the engine
1244  // wans't initialized at all or when there were some changes
1245  // in the model.
1246  // But maybe we want reset everything since we're overwriting
1247  // the marginalized distributions anyway.
1248  MCMCInitialize();
1249 
1250  int k = 0;
1251  int n = GetNParameters();
1252  for (int i = 0; i < n; i++) {
1253  const BCParameter * a = GetParameter(i);
1254  TKey * key = froot->GetKey(TString::Format("hist_%i_%s", fID, a->GetName().data()));
1255  if (key) {
1256  TH1D * h1 = (TH1D*) key->ReadObjectAny(TH1D::Class());
1257  h1->SetDirectory(0);
1258  if (SetMarginalized(i, h1))
1259  k++;
1260  }
1261  else
1263  Form("BCIntegrate::ReadMarginalizedFromFile : Couldn't read histogram \"hist_%i_%s\" from file %s.",
1264  fID, a->GetName().data(), file));
1265  }
1266 
1267  for (int i = 0; i < n - 1; i++) {
1268  for (int j = i + 1; j < n; j++) {
1269  const BCParameter * a = GetParameter(i);
1270  const BCParameter * b = GetParameter(j);
1271  TKey * key = froot->GetKey(
1272  TString::Format("hist_%i_%s_%s",fID, a->GetName().data(),b->GetName().data()));
1273  if (key) {
1274  TH2D * h2 = (TH2D*) key->ReadObjectAny(TH2D::Class());
1275  h2->SetDirectory(0);
1276  if (SetMarginalized(i, j, h2))
1277  k++;
1278  }
1279  else
1281  Form("BCIntegrate::ReadMarginalizedFromFile : Couldn't read histogram \"hist_%i_%s_%s\" from file %s.",
1282  fID, a->GetName().data(), b->GetName().data(), file));
1283  }
1284  }
1285 
1286  froot->Close();
1287 
1288  return k;
1289 }
1290 
1291 
1292 // ---------------------------------------------------------
1293 int BCIntegrate::PrintAllMarginalized1D(const char * filebase)
1294 {
1295  if (fMCMCH1Marginalized.size() == 0) {
1296  BCLog::OutError("BCIntegrate::PrintAllMarginalized : Marginalized distributions not available.");
1297  return 0;
1298  }
1299 
1300  int n = GetNParameters();
1301  for (int i = 0; i < n; i++) {
1302  const BCParameter * a = GetParameter(i);
1303  if (GetMarginalized(a))
1304  GetMarginalized(a)->Print(Form("%s_1D_%s.pdf", filebase, a->GetName().data()));
1305  }
1306 
1307  return n;
1308 }
1309 
1310 // ---------------------------------------------------------
1311 int BCIntegrate::PrintAllMarginalized2D(const char * filebase)
1312 {
1313  if (fMCMCH2Marginalized.size() == 0) {
1314  BCLog::OutError("BCIntegrate::PrintAllMarginalized : Marginalized distributions not available.");
1315  return 0;
1316  }
1317 
1318  int k = 0;
1319  int n = GetNParameters();
1320  for (int i = 0; i < n - 1; i++) {
1321  for (int j = i + 1; j < n; j++) {
1322  const BCParameter * a = GetParameter(i);
1323  const BCParameter * b = GetParameter(j);
1324 
1325  double meana = (a->GetLowerLimit() + a->GetUpperLimit()) / 2.;
1326  double deltaa = (a->GetUpperLimit() - a->GetLowerLimit());
1327  if (deltaa <= 1e-7 * meana)
1328  continue;
1329 
1330  double meanb = (b->GetLowerLimit() + b->GetUpperLimit()) / 2.;
1331  double deltab = (b->GetUpperLimit() - b->GetLowerLimit());
1332  if (deltab <= 1e-7 * meanb)
1333  continue;
1334 
1335  if (GetMarginalized(a, b))
1336  GetMarginalized(a, b)->Print(
1337  Form("%s_2D_%s_%s.pdf",filebase, a->GetName().data(), b->GetName().data()));
1338  k++;
1339  }
1340  }
1341 
1342  return k;
1343 }
1344 
1345 // ---------------------------------------------------------
1346 int BCIntegrate::PrintAllMarginalized(const char * file, std::string options1d, std::string options2d, unsigned int hdiv, unsigned int vdiv)
1347 {
1348  if (fMarginalized1D.size() == 0 and fMarginalized2D.size() == 0) {
1349  BCLog::OutError("BCIntegrate::PrintAllMarginalized : Marginalized distributions not available.");
1350  return 0;
1351  }
1352 
1353  // count all valid (non NULL) histograms
1354  int nvalid1D = 0;
1355  int nvalid2D = 0;
1356 
1357  for (unsigned i = 0 ; i < fMarginalized1D.size() ; ++i) {
1358  if (BCH1D * h = fMarginalized1D[i])
1359  if (h->GetHistogram())
1360  nvalid1D++;
1361  }
1362 
1363  for (unsigned i = 0 ; i < fMarginalized2D.size() ; ++i) {
1364  if (BCH2D * h = fMarginalized2D[i])
1365  if (h->GetHistogram())
1366  nvalid2D++;
1367  }
1368 
1369  std::string filename(file);
1370 
1371  // check if file extension does not exist or is not pdf or ps
1372  if ( (filename.find_last_of(".") == std::string::npos) or
1373  ((filename.substr(filename.find_last_of(".")+1) != "pdf") and
1374  (filename.substr(filename.find_last_of(".")+1) != "ps"))) {
1375  // make it a PDF file
1376  filename += ".pdf";
1377  }
1378 
1379  int c_width = gStyle->GetCanvasDefW(); // default canvas width
1380  int c_height = gStyle->GetCanvasDefH(); // default canvas height
1381 
1382  if (hdiv > vdiv) {
1383  if (hdiv > 3) {
1384  c_width = 1000;
1385  c_height = 700;
1386  }
1387  else {
1388  c_width = 800;
1389  c_height = 600;
1390  }
1391  }
1392  else if (hdiv < vdiv) {
1393  if (hdiv > 3) {
1394  c_height = 1000;
1395  c_width = 700;
1396  }
1397  else {
1398  c_height = 800;
1399  c_width = 600;
1400  }
1401  }
1402 
1403  const unsigned nplots = nvalid1D + nvalid2D;
1404 
1405  // give out warning if too many plots
1406  BCLog::OutSummary(Form("Printing all marginalized distributions (%d x 1D + %d x 2D = %d) into file %s",
1407  nvalid1D, nvalid2D, nplots, filename.c_str()));
1408  if (nplots > 100)
1409  BCLog::OutDetail("This can take a while...");
1410 
1411  // setup the canvas and file
1412  TCanvas c("c", "canvas", c_width, c_height);
1413  c.Divide(hdiv, vdiv);
1414 
1415  // for clean up later
1416  std::vector<BCH1D *> h1;
1417 
1418  // count plots
1419  unsigned n = 0;
1420  for (unsigned i = 0; i < fParameters.Size(); ++i) {
1421  BCH1D * h = GetMarginalized(i);
1422  h1.push_back(h);
1423 
1424  // check if histogram exists
1425  if ( !h)
1426  continue;
1427 
1428  // if current page is full, switch to new page
1429  if (n != 0 && n % (hdiv * vdiv) == 0) {
1430  if ( n <= (hdiv * vdiv)) {
1431  c.Print(std::string( filename + "(").c_str());
1432  }
1433  else {
1434  c.Print(filename.c_str());
1435  }
1436  }
1437 
1438  // go to next pad
1439  c.cd(n % (hdiv * vdiv) + 1);
1440 
1441  h->Draw(options1d);
1442 
1443  if (++n % 100 == 0)
1444  BCLog::OutDetail(Form(" --> %d plots done", n));
1445  }
1446 
1447  // for clean up later
1448  std::vector<BCH2D *> h2;
1449 
1450  // check how many 2D plots are actually drawn, despite no histogram filling or delta prior
1451  unsigned k = 0;
1452  for (unsigned i = 0; i < fParameters.Size() - 1; ++i) {
1453  for (unsigned j = i + 1; j < fParameters.Size(); ++j) {
1454  // check if histogram exists, or skip if one par has a delta prior
1455  h2.push_back(GetMarginalized(i, j));
1456  if ( !h2.back())
1457  continue;
1458 
1459  // get corresponding parameters
1460  BCParameter * a = GetParameter(i);
1461  BCParameter * b = GetParameter(j);
1462 
1463  // if current page is full, switch to new page, but only if there is data to plot
1464  if ((k != 0 && k % (hdiv * vdiv) == 0) || k == 0) {
1465  c.Print(filename.c_str());
1466  }
1467 
1468  // go to next pad
1469  c.cd(k % (hdiv * vdiv) + 1);
1470 
1471  const double meana = (a->GetLowerLimit() + a->GetUpperLimit()) / 2.;
1472  if (a->GetRangeWidth() <= 1e-7 * meana)
1473  continue;
1474 
1475  const double meanb = (b->GetLowerLimit() + b->GetUpperLimit()) / 2.;
1476  if (b->GetRangeWidth() <= 1e-7 * meanb)
1477  continue;
1478 
1479  h2.back()->Draw(options2d);
1480  k++;
1481 
1482  if ((n + k) % 100 == 0)
1483  BCLog::OutDetail(Form(" --> %d plots done", n + k));
1484  }
1485  }
1486 
1487  if ((n + k) > 100 && (n + k) % 100 != 0)
1488  BCLog::OutDetail(Form(" --> %d plots done", n + k));
1489 
1490  c.Print(std::string( filename + ")").c_str());
1491 
1492  // return total number of drawn histograms
1493  return n + k;
1494 }
1495 
1496 // ---------------------------------------------------------
1498 {
1499  if ( !par1 or !par2 or (par1 == par2) )
1500  return 0;
1501 
1502  return GetMarginalized(fParameters.Index(par1->GetName()), fParameters.Index(par2->GetName()));
1503 }
1504 
1505 // ---------------------------------------------------------
1506 BCH2D * BCIntegrate::GetMarginalized(unsigned index1, unsigned index2)
1507 {
1508  // swap indices if necessary
1509  if (index1 > index2) {
1510  unsigned indexTemp = index1;
1511  index1 = index2;
1512  index2 = indexTemp;
1513  }
1514 
1515  // check if marginalized histogram exists
1516  if (fMarginalized2D.size() <= GetNParameters() * index1 - (index1 * index1 + 3 * index1) / 2 + index2 - 1)
1517  return 0;
1518 
1519  // get histogram
1520  BCH2D * htemp = fMarginalized2D.at(GetNParameters() * index1 - (index1 * index1 + 3 * index1) / 2 + index2 - 1);
1521 
1522  // check if histogram exists
1523  if ( !htemp)
1524  return 0;
1525 
1526  // set global mode
1527  if (fBestFitParameters.size() == GetNParameters()) {
1528  double gmode[] = { fBestFitParameters.at(index1), fBestFitParameters.at(index2) };
1529  htemp->SetGlobalMode(gmode);
1530  }
1531 
1532  // set name
1533  htemp->GetHistogram()->SetName(Form("hist_%i_%s_%s", fID,
1534  fParameters[index1]->GetName().data(),
1535  fParameters[index2]->GetName().data()));
1536 
1537  // return histogram
1538  return htemp;
1539 }
1540 
1541 // ---------------------------------------------------------
1542 std::vector<double> BCIntegrate::FindMode(std::vector<double> start)
1543 {
1544  if (fParameters.Size() < 1) {
1545  BCLog::OutError("FindMode : No parameters defined. Aborting.");
1546  return std::vector<double>();
1547  }
1548 
1549  if (start.empty() && fBestFitParameters.size() == fParameters.Size())
1550  start = fBestFitParameters;
1551 
1552  std::vector<double> mode_temp(GetNParameters());
1553  std::vector<double> errors_temp(GetNParameters());
1555 
1556  // output
1558  BCLog::OutSummary(Form("Finding mode using %s", DumpCurrentOptimizationMethod().c_str()));
1559 
1561  {
1563  {
1564  BCLog::OutWarning("BCIntegrate::FindMode : No optimization method chosen.");
1565  return std::vector<double>();
1566  }
1568  {
1569  FindModeSA(mode_temp, errors_temp, start);
1570 
1571  break;
1572  }
1573 
1575  {
1576  int printlevel = -1;
1578  printlevel = 0;
1580  printlevel = 1;
1581 
1582  BCIntegrate::FindModeMinuit(mode_temp, errors_temp, start, printlevel);
1583 
1584  break;
1585  }
1586 
1588  {
1589  FindModeMCMC(mode_temp, errors_temp);
1590 
1591  break;
1592  }
1594  {
1596 
1597  return FindMode(start);
1598  }
1599 
1600  default:
1601  BCLog::OutError(Form("BCIntegrate::FindMode : Invalid mode finding method: %d", GetOptimizationMethod()));
1602  return std::vector<double>();
1603  }
1604 
1605  // calculate function at new mode
1606  double fcnatmode_temp = Eval(mode_temp);
1607 
1608  // check if the mode found mode is better than the previous estimate
1609  if ( (!fFlagIgnorePrevOptimization) && (fcnatmode_temp < fLogMaximum) ) {
1610  // set best fit parameters
1611  if (mode_temp.size() == fBestFitParameters.size())
1612  mode_temp = fBestFitParameters;
1613  else
1614  BCLog::OutError("BCIntegrate::FindMode : previous mode has a different number of parameters than current.");
1615 
1616  if (errors_temp.size() == fBestFitParameterErrors.size())
1617  errors_temp = fBestFitParameterErrors;
1618  else
1619  BCLog::OutError("BCIntegrate::FindMode : previous error estimate has a different number of parameters than current.");
1620 
1621  fcnatmode_temp = fLogMaximum;
1622  method_temp = fOptimizationMethodUsed;
1623  }
1624 
1625  // set the best-fit parameters
1626  fBestFitParameters = mode_temp;
1627  fBestFitParameterErrors = errors_temp;
1628  fLogMaximum = fcnatmode_temp;
1629 
1630  // set used optimization method
1631  fOptimizationMethodUsed = method_temp;
1632 
1633  // return the new mode
1634  return mode_temp;
1635 
1636 }
1637 
1638 // ---------------------------------------------------------
1639 std::vector<double> BCIntegrate::FindMode(BCIntegrate::BCOptimizationMethod optmethod, std::vector<double> start)
1640 {
1641  // remember original method
1643 
1644  // set method
1645  SetOptimizationMethod(optmethod);
1646 
1647  // run algorithm
1648  std::vector<double> mode = FindMode(start);
1649 
1650  // re-set original method
1651  SetOptimizationMethod(method_temp);
1652 
1653  // return mode
1654  return mode;
1655 }
1656 
1657 // ---------------------------------------------------------
1659 {
1660  if (!fMinuit)
1661  fMinuit = new TMinuit();
1662 
1663  return fMinuit;
1664 }
1665 
1666 // ---------------------------------------------------------
1667 std::vector<double> BCIntegrate::FindModeMinuit(std::vector<double> &mode, std::vector<double> &errors, std::vector<double> start, int printlevel)
1668 {
1669  if (fParameters.Size() < 1) {
1670  BCLog::OutError("BCIntegrate::FindModeMinuit : No parameters defined. Aborting.");
1671  return std::vector<double>();
1672  }
1673 
1674  bool have_start = true;
1675 
1676  // check start values
1677  if (start.size() == 0)
1678  have_start = false;
1679  else if (start.size() != fParameters.Size()) {
1680  have_start = false;
1681  BCLog::OutWarning("BCIntegrate::FindModeMinuit : Start point not valid (mismatch of dimensions), set to center.");
1682  }
1683 
1684  // check if point is allowed
1685  if (have_start) {
1686  for (unsigned int i = 0; i <fParameters.Size(); ++i) {
1687  if (!fParameters[i]->IsValid(start[i]))
1688  have_start = false;
1689  if (fParameters[i]->Fixed() && start[i] != fParameters[i]->GetFixedValue())
1690  have_start = false;
1691  }
1692  if (!have_start)
1693  BCLog::OutWarning("BCIntegrate::FindModeMinuit : Start point not valid (parameter not inside valid range), set to center.");
1694  }
1695 
1696  // set global this
1697  ::BCIntegrateHolder::instance(this);
1698 
1699  // define minuit
1700  if (fMinuit)
1701  delete fMinuit;
1702  fMinuit = new TMinuit(fParameters.Size());
1703 
1704  // set print level
1705  fMinuit->SetPrintLevel(printlevel);
1706 
1707  // set function
1709 
1710  // set UP for likelihood
1711  fMinuit->SetErrorDef(0.5);
1712 
1713  // set parameters
1714  int flag;
1715  for (unsigned i = 0; i < fParameters.Size(); i++) {
1716  double starting_point = (fParameters[i]->GetUpperLimit() + fParameters[i]->GetLowerLimit()) / 2.;
1717  if(have_start)
1718  starting_point = start[i];
1719  if (fParameters[i]->Fixed())
1720  starting_point = fParameters[i]->GetFixedValue();
1721  fMinuit->mnparm(i,
1722  fParameters[i]->GetName().data(),
1723  starting_point,
1724  fParameters[i]->GetRangeWidth() / 100.,
1725  fParameters[i]->GetLowerLimit(),
1726  fParameters[i]->GetUpperLimit(),
1727  flag);
1728  }
1729 
1730  for (unsigned i = 0; i < fParameters.Size(); i++)
1731  if (fParameters[i]->Fixed())
1732  fMinuit->FixParameter(i);
1733 
1734  // do mcmc minimization
1735  // fMinuit->mnseek();
1736 
1737  // do minimization
1738  fMinuit->mnexcm("MIGRAD", fMinuitArglist, 2, flag);
1739 
1740  // improve search for local minimum
1741  // fMinuit->mnimpr();
1742 
1743  // copy flag and result
1744  fMinuitErrorFlag = flag;
1745  // std::vector<double> localMode(fParameters.Size(), 0);
1746  // std::vector<double> errors(fParameters.Size(), 0);
1747  for (unsigned i = 0; i < fParameters.Size(); i++) {
1748  fMinuit->GetParameter(i, mode[i], errors[i]);
1749  }
1750 
1751  // delete minuit
1752  delete fMinuit;
1753  fMinuit = 0;
1754 
1755  return mode;
1756 }
1757 
1758 // ---------------------------------------------------------
1760 {
1761  if (fTreeSA)
1762  delete fTreeSA;
1763  fTreeSA = new TTree("SATree", "SATree");
1764 
1765  fTreeSA->Branch("Iteration", &fSANIterations, "iteration/I");
1766  // todo make consistent with examples and test
1767  // remove because would require fixed number of parameters, and just superfluous info
1768 // fTreeSA->Branch("NParameters", &fNvar, "parameters/I");
1769  fTreeSA->Branch("Temperature", &fSATemperature, "temperature/D");
1770  fTreeSA->Branch("LogProbability", &fSALogProb, "log(probability)/D");
1771 
1772  for (unsigned i = 0; i < fParameters.Size(); ++i)
1773  fTreeSA->Branch(TString::Format("Parameter%i", i), &fSAx[i], TString::Format("parameter %i/D", i));
1774 }
1775 
1776 // ---------------------------------------------------------
1777 std::vector<double> BCIntegrate::FindModeSA(std::vector<double> &mode, std::vector<double> &errors, std::vector<double> start)
1778 {
1779  // note: if f(x) is the function to be minimized, then
1780  // f(x) := - LogEval(parameters)
1781 
1782  bool have_start = true;
1783  std::vector<double> x, y; // vectors for current state, new proposed state and best fit up to now
1784  double fval_x, fval_y, fval_mode; // function values at points x, y and mode (we save them rather than to re-calculate them every time)
1785  int t = 1; // time iterator
1786 
1787  // check start values
1788  if (start.size() == 0)
1789  have_start = false;
1790  else if (start.size() != fParameters.Size()) {
1791  have_start = false;
1792  BCLog::OutWarning("BCIntegrate::FindModeSA : Start point not valid (mismatch of dimensions), set to center.");
1793  }
1794 
1795  // check if point is allowed
1796  if (have_start) {
1797  for (unsigned int i = 0; i <fParameters.Size(); ++i) {
1798  if (!fParameters[i]->IsValid(start[i]))
1799  have_start = false;
1800  if (fParameters[i]->Fixed() && start[i] != fParameters[i]->GetFixedValue())
1801  have_start = false;
1802  }
1803  if (!have_start)
1804  BCLog::OutWarning("BCIntegrate::FindModeSA : Start point not valid (parameter not inside valid range), set to center.");
1805  }
1806 
1807  // if no starting point is given, set to center of parameter space
1808  if ( !have_start ) {
1809  start.clear();
1810  for (unsigned i=0; i<fParameters.Size(); i++)
1811  if (fParameters[i]->Fixed())
1812  start.push_back(fParameters[i]->GetFixedValue());
1813  else
1814  start.push_back((fParameters[i]->GetLowerLimit() + fParameters[i]->GetUpperLimit()) / 2.);
1815  }
1816 
1817  // set current state and best fit to starting point
1818  x = start;
1819  mode = start;
1820 
1821  // calculate function value at starting point
1822  fval_x = fval_mode = LogEval(x);
1823 
1824  // run while still "hot enough"
1825  while ( SATemperature(t) > fSATmin ) {
1826  // generate new state
1827  y = GetProposalPointSA(x, t);
1828 
1829  // check if the proposed point is inside the phase space
1830  // if not, reject it
1831  bool in_range = true;
1832 
1833  for (unsigned i = 0; i < fParameters.Size(); i++)
1834  if ( !fParameters[i]->IsValid(y[i]))
1835  in_range = false;
1836 
1837  if ( in_range ){
1838  // calculate function value at new point
1839  fval_y = LogEval(y);
1840 
1841  // is it better than the last one?
1842  // if so, update state and chef if it is the new best fit...
1843  if (fval_y >= fval_x) {
1844  x = y;
1845 
1846  fval_x = fval_y;
1847 
1848  if (fval_y > fval_mode) {
1849  mode = y;
1850  fval_mode = fval_y;
1851  }
1852  }
1853  // ...else, only accept new state w/ certain probability
1854  else {
1855  if (fRandom->Rndm() <= exp( (fval_y - fval_x) / SATemperature(t) )) {
1856  x = y;
1857  fval_x = fval_y;
1858  }
1859  }
1860  }
1861 
1862  // update tree variables
1863  fSANIterations = t;
1865  fSALogProb = fval_x;
1866  fSAx = x;
1867 
1868  // fill tree
1869  if (fFlagWriteSAToFile && fTreeSA)
1870  fTreeSA->Fill();
1871 
1872  // increate t
1873  t++;
1874  }
1875 
1876  // calculate uncertainty
1877  errors.assign(fParameters.Size(),-1);
1878 
1879  return mode;
1880 }
1881 
1882 // ---------------------------------------------------------
1884 {
1885  // do we have Cauchy (default), Boltzmann or custom annealing schedule?
1887  return SATemperatureBoltzmann(t);
1888  else if (fSASchedule == BCIntegrate::kSACauchy)
1889  return SATemperatureCauchy(t);
1890  else
1891  return SATemperatureCustom(t);
1892 }
1893 
1894 // ---------------------------------------------------------
1896 {
1897  return fSAT0 / log((double)(t + 1));
1898 }
1899 
1900 // ---------------------------------------------------------
1902 {
1903  return fSAT0 / (double)t;
1904 }
1905 
1906 // ---------------------------------------------------------
1908 {
1909  BCLog::OutError("BCIntegrate::SATemperatureCustom : No custom temperature schedule defined");
1910  return 0.;
1911 }
1912 
1913 // ---------------------------------------------------------
1914 std::vector<double> BCIntegrate::GetProposalPointSA(const std::vector<double> &x, int t)
1915 {
1916  // do we have Cauchy (default), Boltzmann or custom annealing schedule?
1918  return GetProposalPointSABoltzmann(x, t);
1919  else if (fSASchedule == BCIntegrate::kSACauchy)
1920  return GetProposalPointSACauchy(x, t);
1921  else
1922  return GetProposalPointSACustom(x, t);
1923 }
1924 
1925 // ---------------------------------------------------------
1926 std::vector<double> BCIntegrate::GetProposalPointSABoltzmann(const std::vector<double> &x, int t)
1927 {
1928  std::vector<double> y;
1929  y.clear();
1930  double new_val, norm;
1931 
1932  for (unsigned i = 0; i < fParameters.Size(); i++) {
1933  if (fParameters[i]->Fixed()) {
1934  y.push_back(fParameters[i]->GetFixedValue());
1935  }
1936  else {
1937  norm = fParameters[i]->GetRangeWidth() * SATemperature(t) / 2.;
1938  new_val = x[i] + norm * fRandom->Gaus();
1939  y.push_back(new_val);
1940  }
1941  }
1942 
1943  return y;
1944 }
1945 
1946 // ---------------------------------------------------------
1947 std::vector<double> BCIntegrate::GetProposalPointSACauchy(const std::vector<double> &x, int t)
1948 {
1949  std::vector<double> y;
1950  y.clear();
1951 
1952  if (fParameters.Size() == 1) {
1953  double cauchy, new_val, norm;
1954 
1955  if (fParameters[0]->Fixed()) {
1956  y.push_back(fParameters[0]->GetFixedValue());
1957  }
1958  else {
1959  norm = fParameters[0]->GetRangeWidth() * SATemperature(t) / 2.;
1960  cauchy = tan(3.14159 * (fRandom->Rndm() - 0.5));
1961  new_val = x[0] + norm * cauchy;
1962  y.push_back(new_val);
1963  }
1964  }
1965  else {
1966  // use sampling to get radial n-dim Cauchy distribution
1967 
1968  // first generate a random point uniformly distributed on a
1969  // fNvar-dimensional hypersphere
1971 
1972  // scale the vector by a random factor determined by the radial
1973  // part of the fNvar-dimensional Cauchy distribution
1974  double radial = SATemperature(t) * SAHelperGetRadialCauchy();
1975 
1976  // scale y by radial part and the size of dimension i in phase space
1977  // afterwards, move by x
1978  for (unsigned i = 0; i < fParameters.Size(); i++) {
1979  if (fParameters[i]->Fixed()) {
1980  y[i] = fParameters[i]->GetFixedValue(); }
1981  else {
1982  y[i] = fParameters[i]->GetRangeWidth() * y[i] * radial / 2. + x[i];
1983  }
1984  }
1985  }
1986 
1987  return y;
1988 }
1989 
1990 // ---------------------------------------------------------
1991 std::vector<double> BCIntegrate::GetProposalPointSACustom(const std::vector<double> & /*x*/, int /*t*/)
1992 {
1993  BCLog::OutError("BCIntegrate::GetProposalPointSACustom : No custom proposal function defined");
1994  return std::vector<double>(fParameters.Size());
1995 }
1996 
1997 // ---------------------------------------------------------
1999 {
2000  std::vector<double> rand_point(fParameters.Size());
2001 
2002  // This method can only be called with fNvar >= 2 since the 1-dim case
2003  // is already hard wired into the Cauchy annealing proposal function.
2004  // To speed things up, hard-code fast method for 2 and dimensions.
2005  // The algorithm for 2D can be found at
2006  // http://mathworld.wolfram.com/CirclePointPicking.html
2007  // For 3D just using ROOT's algorithm.
2008  if (fParameters.Size() == 2) {
2009  double x1, x2, s;
2010  do {
2011  x1 = fRandom->Rndm() * 2. - 1.;
2012  x2 = fRandom->Rndm() * 2. - 1.;
2013  s = x1*x1 + x2*x2;
2014  }
2015  while (s >= 1);
2016 
2017  rand_point[0] = (x1*x1 - x2*x2) / s;
2018  rand_point[1] = (2.*x1*x2) / s;
2019  }
2020  else if (fParameters.Size() == 3) {
2021  fRandom->Sphere(rand_point[0], rand_point[1], rand_point[2], 1.0);
2022  }
2023  else {
2024  double s = 0.,
2025  gauss_num;
2026 
2027  for (unsigned i = 0; i < fParameters.Size(); i++) {
2028  gauss_num = fRandom->Gaus();
2029  rand_point[i] = gauss_num;
2030  s += gauss_num * gauss_num;
2031  }
2032  s = sqrt(s);
2033 
2034  for (unsigned i = 0; i < fParameters.Size(); i++)
2035  rand_point[i] = rand_point[i] / s;
2036  }
2037 
2038  return rand_point;
2039 }
2040 
2041 // ---------------------------------------------------------
2043 {
2044  // theta is sampled from a rather complicated distribution,
2045  // so first we create a lookup table with 10000 random numbers
2046  // once and then, each time we need a new random number,
2047  // we just look it up in the table.
2048  double theta;
2049 
2050  // static vectors for theta-sampling-map
2051  static double map_u[10001];
2052  static double map_theta[10001];
2053  static bool initialized = false;
2054  static unsigned map_dimension = 0;
2055 
2056  // is the lookup-table already initialized? if not, do it!
2057  if (!initialized or map_dimension != fParameters.Size()) {
2058  double init_theta;
2059  double beta = SAHelperSinusToNIntegral(fParameters.Size() - 1, 1.57079632679);
2060 
2061  for (int i = 0; i <= 10000; i++) {
2062  init_theta = 3.14159265 * (double)i / 5000.;
2063  map_theta[i] = init_theta;
2064 
2065  map_u[i] = SAHelperSinusToNIntegral(fParameters.Size() - 1, init_theta) / beta;
2066  }
2067 
2068  map_dimension = fParameters.Size();
2069  initialized = true;
2070  } // initializing is done.
2071 
2072  // generate uniform random number for sampling
2073  double u = fRandom->Rndm();
2074 
2075  // Find the two elements just greater than and less than u
2076  // using a binary search (O(log(N))).
2077  int lo = 0;
2078  int up = 10000;
2079  int mid;
2080 
2081  while (up != lo) {
2082  mid = ((up - lo + 1) / 2) + lo;
2083 
2084  if (u >= map_u[mid])
2085  lo = mid;
2086  else
2087  up = mid - 1;
2088  }
2089  up++;
2090 
2091  // perform linear interpolation:
2092  theta = map_theta[lo] + (u - map_u[lo]) / (map_u[up] - map_u[lo]) * (map_theta[up] - map_theta[lo]);
2093 
2094  return tan(theta);
2095 }
2096 
2097 // ---------------------------------------------------------
2098 double BCIntegrate::SAHelperSinusToNIntegral(int dim, double theta)
2099 {
2100  if (dim < 1)
2101  return theta;
2102  else if (dim == 1)
2103  return (1. - cos(theta));
2104  else if (dim == 2)
2105  return 0.5 * (theta - sin(theta) * cos(theta));
2106  else if (dim == 3)
2107  return (2. - sin(theta) * sin(theta) * cos(theta) - 2. * cos(theta)) / 3.;
2108  else
2109  return - pow(sin(theta), (double)(dim - 1)) * cos(theta) / (double)dim
2110  + (double)(dim - 1) / (double)dim
2111  * SAHelperSinusToNIntegral(dim - 2, theta);
2112 }
2113 
2114 // ---------------------------------------------------------
2115 void BCIntegrate::FCNLikelihood(int & /*npar*/, double * /*grad*/, double &fval, double * par, int /*flag*/)
2116 {
2117  // copy parameters
2118  static std::vector<double> parameters;
2119 
2120  // calculate number of active + fixed parameters
2121  // remember: npar is just the number of _active_ parameters while
2122  // par is a vector of _all_ parameters
2123  int nparameters = ::BCIntegrateHolder::instance()->GetNParameters();
2124 
2125  // adjust size if needed
2126  parameters.resize(nparameters, 0.0);
2127 
2128  // copy values
2129  std::copy(par, par + nparameters, parameters.begin());
2130 
2131  // evaluate, for efficiency don't check if npar matches
2132  fval = - ::BCIntegrateHolder::instance()->LogEval(parameters);
2133 }
2134 
2135 // ---------------------------------------------------------
2136 std::vector<double> BCIntegrate::FindModeMCMC(std::vector<double> &mode, std::vector<double> &errors)
2137 {
2138  // call PreRun
2140 
2141  // loop over all chains and find the maximum point
2142  double logProb = -std::numeric_limits<double>::max();
2143  unsigned index = 0;
2144  for (unsigned i = 0; i < fMCMCNChains; ++i) {
2145  if (MCMCGetMaximumLogProb().at(i) > logProb){
2146  index = i;
2147  logProb = MCMCGetMaximumLogProb().at(i);
2148  }
2149  }
2150 
2151  mode = MCMCGetMaximumPoint(index);
2152  errors.assign(fParameters.Size(),-1.);
2153 
2154  return mode;
2155 }
2156 
2157 // ---------------------------------------------------------
2159 {
2160  if (method >= BCIntegrate::NIntMethods) {
2161  BCLog::OutError(Form("BCIntegrate::SetIntegrationMethod: Invalid method '%d' ", method));
2162  return;
2163  }
2164  if (method == BCIntegrate::kIntCuba) {
2165 #ifndef HAVE_CUBA_H
2166  BCLog::OutError("BCIntegrate::SetIntegrationMethod: Cuba not enabled during configure");
2167 #endif
2168  }
2169  fIntegrationMethodCurrent = method;
2170 }
2171 
2172 // ---------------------------------------------------------
2174 {
2175 #ifdef HAVE_CUBA_H
2176  switch(type) {
2181  fCubaIntegrationMethod = type;
2182  return;
2183  default:
2184  BCLog::OutError(TString::Format("Integration method of type %d is not defined for Cuba",type));
2185  return;
2186  }
2187 #else
2188  (void) type; // suppress compiler warning about unused parameters
2189  BCLog::OutError("SetCubaIntegrationMethod: Cuba not enabled during configure");
2190 #endif
2191 }
2192 
2193 // ---------------------------------------------------------
2194 int BCIntegrate::CubaIntegrand(const int * ndim, const double xx[],
2195  const int * /*ncomp*/, double ff[], void * userdata)
2196 {
2197  BCIntegrate * local_this = static_cast<BCIntegrate *>(userdata);
2198 
2199  // scale variables
2200  double jacobian = 1.0;
2201 
2202  // create local parameter vector
2203  // important for thread safety, though not super efficient
2204  std::vector<double> scaled_parameters(local_this->fParameters.Size());
2205 
2206  // stay in sync with the possible lower number of parameters
2207  // that cuba sees due to fixing in BAT
2208  unsigned cubaIndex = 0;
2209  unsigned batIndex = 0;
2210  for (batIndex = 0; batIndex < local_this->fParameters.Size(); ++batIndex) {
2211  const BCParameter * p = local_this->fParameters[batIndex];
2212 
2213  // get the scaled parameter value
2214  if (p->Fixed())
2215  scaled_parameters[batIndex] = p->GetFixedValue();
2216  else {
2217  // convert from unit hypercube to actual parameter hyperrectangle
2218  scaled_parameters[batIndex] = p->GetLowerLimit() + xx[cubaIndex] * p->GetRangeWidth();
2219 
2220  // multiply range to jacobian
2221  jacobian *= p->GetRangeWidth();
2222 
2223  // one more parameter that cuba varies
2224  ++cubaIndex;
2225  }
2226  }
2227 
2228  if (cubaIndex != unsigned(*ndim))
2229  BCLog::OutError(Form("BCIntegrate::CubaIntegrand: mismatch between variable parameters"
2230  "in BAT (%d) and Cuba(%d)", batIndex, cubaIndex));
2231 
2232  // call function to integrate
2233  ff[0] = local_this->Eval(scaled_parameters);
2234 
2235  // multiply jacobian
2236  ff[0] *= jacobian;
2237 
2238  return 0;
2239 }
2240 
2241 // ---------------------------------------------------------
2243 #if HAVE_CUBA_H
2245 
2246  // integrand has only one component
2247  static const int ncomp = 1;
2248 
2249  // don't store integration in a slot for reuse
2250  static const int gridno = -1;
2251 
2252  // we don't want dumps of internal state
2253  static const char * statefile = "";
2254 
2255  // cuba returns info in these variables
2256  int fail = 0;
2257  int nregions = 0;
2258  std::vector<double> integral(ncomp, -1);
2259  std::vector<double> error(ncomp, -1);
2260  std::vector<double> prob(ncomp, -1);
2261 
2262  // reset number of iterations
2263  fNIterations = 0;
2264 
2265  // Cuba needs int variable
2266  int nIntegrationVariables = GetNIntegrationVariables();
2267 
2268  switch (cubatype) {
2269 
2271  Vegas(nIntegrationVariables, ncomp,
2272  &BCIntegrate::CubaIntegrand, static_cast<void *>(this),
2274  fCubaVegasOptions.flags, fRandom->GetSeed(),
2277  gridno, statefile,
2278  &fNIterations, &fail,
2279  &integral[0], &error[0], &prob[0]);
2280  break;
2281 
2283  Suave(nIntegrationVariables, ncomp,
2284  &BCIntegrate::CubaIntegrand, static_cast<void *>(this),
2286  fCubaSuaveOptions.flags, fRandom->GetSeed(),
2289  statefile,
2290  &nregions, &fNIterations, &fail,
2291  &integral[0], &error[0], &prob[0]);
2292  break;
2293 
2295  if (nIntegrationVariables < 2 or nIntegrationVariables > 33)
2296  BCLog::OutError("BCIntegrate::IntegrateCuba(Divonne): Divonne only works in 1 < d < 34");
2297  else {
2298  // no extra info supported
2299  static const int ngiven = 0;
2300  static const int nextra = ngiven;
2301  Divonne(nIntegrationVariables, ncomp,
2302  &BCIntegrate::CubaIntegrand, static_cast<void *>(this),
2304  fCubaDivonneOptions.flags, fRandom->GetSeed(),
2309  ngiven, nIntegrationVariables /*ldxgiven*/, NULL, nextra, NULL,
2310  statefile,
2311  &nregions, &fNIterations, &fail,
2312  &integral[0], &error[0], &prob[0]);
2313  }
2314  break;
2315 
2317  if (nIntegrationVariables < 2)
2318  BCLog::OutError("BCIntegrate::IntegrateCuba(Cuhre): Cuhre(cubature) only works in d > 1");
2319 
2320  Cuhre(nIntegrationVariables, ncomp,
2321  &BCIntegrate::CubaIntegrand, static_cast<void *>(this),
2323  fCubaCuhreOptions.flags, fNIterationsMin, fNIterationsMax,
2325  statefile,
2326  &nregions, &fNIterations, &fail,
2327  &integral[0], &error[0], &prob[0]);
2328  break;
2329 
2331  default:
2332  BCLog::OutError("Cuba integration method not set.");
2333  error[0] = -1;
2334  integral[0] = -1;
2335  break;
2336  }
2337 
2338  fError = error[0];
2339  double result = integral[0];
2340 
2341  if (fail != 0) {
2342  BCLog::OutWarning(" Warning, integral did not converge with the given set of parameters. ");
2343  BCLog::OutWarning(TString::Format(" neval = %d", fNIterations));
2344  BCLog::OutWarning(TString::Format(" fail = %d", fail));
2345  BCLog::OutWarning(TString::Format(" integral = %e", result));
2346  BCLog::OutWarning(TString::Format(" error = %e", fError));
2347  BCLog::OutWarning(TString::Format(" prob = %e", prob[0]));
2348 
2349  // handle cases in which cuba does not alter integral
2350  if (fNIterations == 0)
2351  {
2352  fError = -1;
2353  result = -1;
2354  }
2355 
2356  } else
2358 
2359  return result;
2360 #else
2361  (void) cubatype; // suppress compiler warning about unused parameters
2362  BCLog::OutError("IntegrateCuba: Cuba not enabled during configure");
2363  return -1;
2364 #endif
2365 }
2366 
2367 // ---------------------------------------------------------
2369 {
2370  // print to log
2372 
2373  double integral = -1;
2374  double absprecision = -1;
2375  double relprecision = -1;
2376  fError = -1;
2377 
2378  // calculate values are which the function should be evaluated
2379  std::vector<double> fixpoint(GetNParameters());
2380  for (unsigned int i = 0; i < GetNParameters(); ++i) {
2381  if (fParameters[i]->Fixed())
2382  fixpoint[i] = fParameters[i]->GetFixedValue();
2383  else
2384  fixpoint[i] = 0;
2385  }
2386 
2387  if (GetNFreeParameters() == 1) {
2388  for (unsigned int i = 0; i < GetNParameters(); ++i) {
2389  if (!fParameters[i]->Fixed()) {
2390  // calculate slice
2391  BCH1D* hist_temp = GetSlice(fParameters[i], fixpoint, 0, false);
2392 
2393  // calculate integral
2394  integral = hist_temp->GetHistogram()->Integral("width");
2395 
2396  // free memory
2397  delete hist_temp;
2398  }
2399  }
2400  }
2401  else if (GetNFreeParameters() == 2) {
2402  for (unsigned int i = 0; i < GetNParameters(); ++i) {
2403  for (unsigned int j = 0; j < GetNParameters(); ++j) {
2404  if (i >= j)
2405  continue;
2406  if (!fParameters[i]->Fixed() && !fParameters[j]->Fixed()) {
2407  // calculate slice
2408  BCH2D* hist_temp = GetSlice(GetParameter(i), GetParameter(j), fixpoint, 0, false);
2409 
2410  // calculate integral
2411  integral = hist_temp->GetHistogram()->Integral("width");
2412 
2413  // free memory
2414  delete hist_temp;
2415  }
2416  }
2417  }
2418  }
2419  else {
2420  BCLog::OutWarning("BCIntegrate::IntegrateSlice: Method only implemented for 1D and 2D problems. Return -1.");
2421 
2422  integral = -1;
2423  }
2424 
2425  // print to log
2426  LogOutputAtEndOfIntegration(integral, absprecision, relprecision, -1);
2427 
2428  return integral;
2429 }
2430 
2431 // ---------------------------------------------------------
2433 {
2434  fSAx.clear();
2435  fSAx.assign(fParameters.Size(), 0.0);
2436 }
2437 
2438 // ---------------------------------------------------------
2440 {
2441  switch(type) {
2443  return "Empty";
2445  return "Sample Mean Monte Carlo";
2446  case BCIntegrate::kIntCuba:
2447  return "Cuba";
2448  case BCIntegrate::kIntGrid:
2449  return "Grid";
2450  default:
2451  return "Undefined";
2452  }
2453 }
2454 
2455 // ---------------------------------------------------------
2457 {
2458  switch(type) {
2460  return "Empty";
2462  return "Sample Mean Monte Carlo";
2464  return "Metropolis";
2466  return "Grid";
2468  return "Default";
2469  default:
2470  return "Undefined";
2471  }
2472 }
2473 
2474 // ---------------------------------------------------------
2476 {
2477  switch(type) {
2479  return "Empty";
2481  return "Simulated Annealing";
2483  return "Metropolis MCMC";
2485  return "Minuit";
2487  return "Default";
2488  default:
2489  return "Undefined";
2490  }
2491 }
2492 
2493 // ---------------------------------------------------------
2495 {
2496  switch(type) {
2498  return "Vegas";
2500  return "Suave";
2502  return "Divonne";
2504  return "Cuhre";
2505  default:
2506  return "Undefined";
2507  }
2508 }
2509 
2510 namespace BCCubaOptions
2511 {
2513  ncomp(1),
2514  flags(0),
2515  nregions(0),
2516  neval(0),
2517  fail(0),
2518  error(0),
2519  prob(0)
2520 {}
2521 
2523 {}
2524 
2525 /*
2526  * copy values from demo-c.c shipping with cuba 3.2
2527  * for three-dimensionsal examples.
2528  */
2529 
2531  General(),
2532  nstart(1000),
2533  nincrease(500),
2534  nbatch(1000),
2535  gridno(0)
2536 {}
2537 
2539  General(),
2540  nnew(1000),
2541  flatness(25)
2542 {}
2543 
2545  General(),
2546  key1(47),
2547  key2(1),
2548  key3(1),
2549  maxpass(5),
2550  border(0),
2551  maxchisq(10),
2552  mindeviation(0.25)
2553 {}
2554 
2556  General(),
2557  key(0) // let cuba choose default cubature rule
2558 {}
2559 }