BAT  0.9.4
The Bayesian analysis toolkit
 All Classes Namespaces Functions Variables Enumerations
BCModel.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 "BCModel.h"
12 
13 #include "BCDataPoint.h"
14 #include "BCDataSet.h"
15 #include "BCGoFTest.h"
16 #include "BCH1D.h"
17 #include "BCH2D.h"
18 #include "BCLog.h"
19 #include "BCMath.h"
20 #include "BCModelOutput.h"
21 #include "BCParameter.h"
22 
23 #include <TCanvas.h>
24 #include <TF1.h>
25 #include <TGraph.h>
26 #include <TH2D.h>
27 #include <TMath.h>
28 #include <TRandom3.h>
29 #include <TTree.h>
30 
31 #include <fstream>
32 #include <iomanip>
33 #include <set>
34 
35 // ---------------------------------------------------------
36 BCModel::BCModel(const char * name) :
37  BCIntegrate(),
38  fName((char *) name),
39  fModelAPriori(0),
40  fModelAPosteriori(0),
41  fDataSet(0),
42  fDataPointLowerBoundaries(0),
43  fDataPointUpperBoundaries(0),
44  fPValue(-1),
45  fChi2NDoF(-1),
46  fPValueNDoF(-1),
47  flag_discrete(false),
48  fGoFNIterationsMax(100000),
49  fGoFNIterationsRun(2000),
50  fGoFNChains(5),
51  fPriorConstantAll(false)
52 {
53 }
54 
55 // ---------------------------------------------------------
56 BCModel::BCModel(const BCModel & bcmodel) : BCIntegrate(bcmodel)
57 {
58  Copy(bcmodel);
59 }
60 
61 // ---------------------------------------------------------
62 void BCModel::Copy(const BCModel & bcmodel)
63 {
64  // called for the second time in copy constructor? do copy-and-swap instead
65  // BCIntegrate::Copy(bcmodel);
66  fName = bcmodel.fName;
67  fModelAPriori = bcmodel.fModelAPriori;
69  if (fDataSet)
70  fDataSet = bcmodel.fDataSet;
71  else
72  fDataSet = 0;
73 
74  if (bcmodel.fDataPointLowerBoundaries)
76  else
78  if (bcmodel.fDataPointUpperBoundaries)
80  else
82 
83  fDataFixedValues = bcmodel.fDataFixedValues;
84 
85  fPValue = bcmodel.fPValue;
86  fChi2NDoF = bcmodel.fChi2NDoF;
87  fPValueNDoF = bcmodel.fPValueNDoF;
88  flag_discrete = bcmodel.flag_discrete;
91  fGoFNChains = bcmodel.fGoFNChains;
92  for (int i = 0; i < int(bcmodel.fPriorContainer.size()); ++i) {
93  if (bcmodel.fPriorContainer.at(i))
94  fPriorContainer.push_back(new TNamed(*bcmodel.fPriorContainer.at(i)));
95  else
96  fPriorContainer.push_back(0);
97  }
101 }
102 
103 // ---------------------------------------------------------
105 {
106  for (unsigned int i = 0; i < GetNParameters(); ++i)
107  delete fPriorContainer[i];
108  fPriorContainer.clear();
109 
112 }
113 
114 // ---------------------------------------------------------
116 {
117  Copy(bcmodel);
118 
119  return *this;
120 }
121 
122 // ---------------------------------------------------------
123 unsigned BCModel::GetNDataPoints() const
124 {
125  if (fDataSet)
126  return fDataSet->GetNDataPoints();
127  else
128  return 0;
129  }
130 
131 // ---------------------------------------------------------
132 BCDataPoint * BCModel::GetDataPoint(unsigned int index) const
133 {
134  if (fDataSet)
135  return fDataSet->GetDataPoint(index);
136 
137  BCLog::OutWarning("BCModel::GetDataPoint : No data set defined.");
138  return 0;
139 }
140 
141 // ---------------------------------------------------------
142 double BCModel::GetDataPointLowerBoundary(unsigned int index) const
143 {
144  return fDataPointLowerBoundaries -> GetValue(index);
145 }
146 
147 // ---------------------------------------------------------
148 double BCModel::GetDataPointUpperBoundary(unsigned int index) const
149 {
150  return fDataPointUpperBoundaries -> GetValue(index);
151 }
152 
153 // ---------------------------------------------------------
155 {
157  return false;
158 
160  return false;
161 
163  return false;
164 
166  return false;
167 
168  return true;
169 }
170 
171 // ---------------------------------------------------------
173 {
174  // create new data set consisting of a single data point
175  BCDataSet * dataset = new BCDataSet();
176 
177  // add the data point
178  dataset->AddDataPoint(datapoint);
179 
180  // set this new data set
181  SetDataSet(dataset);
182 }
183 
184 // ---------------------------------------------------------
185 void BCModel::SetSingleDataPoint(BCDataSet * dataset, unsigned int index)
186 {
187  if (index > dataset->GetNDataPoints())
188  return;
189 
190  SetSingleDataPoint(dataset->GetDataPoint(index));
191 }
192 
193 // ---------------------------------------------------------
194 void BCModel::SetDataBoundaries(unsigned int index, double lowerboundary, double upperboundary, bool fixed)
195 {
196  // check if data set exists
197  if (!fDataSet) {
198  BCLog::OutError("BCModel::SetDataBoundaries : Need to define data set first.");
199  return;
200  }
201 
202  // check if index is within range
203  if (index > fDataSet->GetDataPoint(0)->GetNValues()) {
204  BCLog::OutError("BCModel::SetDataBoundaries : Index out of range.");
205  return;
206  }
207 
208  // check if boundary data points exist
211 
214 
215  if (fDataFixedValues.size() == 0)
216  fDataFixedValues.assign(fDataSet->GetDataPoint(0)->GetNValues(), false);
217 
218  // set boundaries
219  fDataPointLowerBoundaries->SetValue(index, lowerboundary);
220  fDataPointUpperBoundaries->SetValue(index, upperboundary);
221  fDataFixedValues[index] = fixed;
222 }
223 
224 // ---------------------------------------------------------
226 {
227  if ( !BCEngineMCMC::AddParameter(parameter))
228  return 1;
229 
230  // add empty object to prior container
231  fPriorContainer.push_back(0);
232 
233  // don't interpolate the prior histogram by default
234  fPriorContainerInterpolate.push_back(false);
235 
236  // prior assumed to be non-constant in general case
237  fPriorContainerConstant.push_back(false);
238 
239  return 0;
240 }
241 
242 // ---------------------------------------------------------
243 double BCModel::ProbabilityNN(const std::vector<double> &params)
244 {
245  return exp(LogProbabilityNN(params) );
246 }
247 
248 // ---------------------------------------------------------
249 double BCModel::Probability(const std::vector<double> &parameter)
250 {
251  return exp(LogProbability(parameter));
252 }
253 
254 // ---------------------------------------------------------
255 double BCModel::LogProbability(const std::vector<double> &parameters)
256 {
257  // check if normalized
258  if (GetIntegral() <= 0.) {
259  BCLog::OutError("BCModel::LogProbability. Normalization not available or zero.");
260  return 0.;
261  }
262 
263  return LogProbabilityNN(parameters) - log(GetIntegral());
264 }
265 
266 // ---------------------------------------------------------
267 double BCModel::APrioriProbability(const std::vector<double> &parameters)
268 {
269  return exp(this->LogAPrioriProbability(parameters) );
270 }
271 
272 // ---------------------------------------------------------
273 double BCModel::LogAPrioriProbability(const std::vector<double> &parameters)
274 {
275  double logprob = 0;
276 
277  // loop over all parameters, assume prior factorizes
278  // into n independent parts
279  for (unsigned i = 0; i < fParameters.Size(); ++i) {
280  BCParameter * par = fParameters[i];
281 
282  // avoid fixed and zero-width parameters
283  if (par->Fixed() or not par->GetRangeWidth())
284  continue;
285 
286  if (fPriorContainerConstant[i]) {
287  logprob -= log(par->GetRangeWidth());
288  continue;
289  }
290 
291  if (fPriorContainer[i]) {
292  // check what type of object is stored
293  TF1 * f = dynamic_cast<TF1*>(fPriorContainer[i]);
294  TH1 * h = dynamic_cast<TH1*>(fPriorContainer[i]);
295 
296  if (f) // TF1
297  logprob += log(f->Eval(parameters[i]));
298  else if (h) { // TH1
300  logprob += log(h->Interpolate(parameters[i]));
301  else
302  logprob += log(h->GetBinContent(h->FindBin(parameters[i])));
303  }
304  else
305  BCLog::OutError(Form(
306  "BCModel::LogAPrioriProbability : Prior for parameter %s "
307  "is defined but not recognized.",
308  par->GetName().c_str())); // this should never happen
309  }
310  // use constant only if user has defined it
311  else {
312  BCLog::OutError(Form(
313  "BCModel::LogAPrioriProbability: Prior for parameter %s "
314  "is undefined. Using constant prior to proceed.",
315  par->GetName().c_str()));
316  logprob -= log(par->GetRangeWidth());
317  }
318  }
319 
320  return logprob;
321 }
322 
323 // ---------------------------------------------------------
324 double BCModel::Likelihood(const std::vector<double> &params)
325 {
326  return exp(LogLikelihood(params));
327 }
328 
329 // ---------------------------------------------------------
330 double BCModel::Eval(const std::vector<double> &parameters)
331 {
332  return exp(LogEval(parameters));
333 }
334 
335 // ---------------------------------------------------------
336 double BCModel::LogEval(const std::vector<double> &parameters)
337 {
338  return LogProbabilityNN(parameters);
339 }
340 
341 // ---------------------------------------------------------
342 double BCModel::SamplingFunction(const std::vector<double> & /*parameters*/)
343 {
344  double probability = 1;
345  for (unsigned i = 0 ; i < GetNParameters() ; ++i)
346  probability *= 1. / fParameters[i]->GetRangeWidth();
347  return probability;
348 }
349 
350 // ---------------------------------------------------------
351 double BCModel::GetPvalueFromChi2(const std::vector<double> &par, int sigma_index)
352 {
353  double ll = LogLikelihood(par);
354  int n = GetNDataPoints();
355 
356  double sum_sigma = 0;
357  for (int i = 0; i < n; i++)
358  sum_sigma += log(GetDataPoint(i)->GetValue(sigma_index));
359 
360  double chi2 = -2. * (ll + (double) n / 2. * log(2. * M_PI) + sum_sigma);
361 
362  fPValue = TMath::Prob(chi2, n);
363 
364  return fPValue;
365 }
366 
367 // ---------------------------------------------------------
368 std::vector<double> BCModel::GetChi2Runs(int /*dataIndex*/, int /*sigmaIndex*/)
369 {
370  std::vector<double> x;
371  return x;
372 }
373 
374 // ---------------------------------------------------------
375 double BCModel::GetPvalueFromChi2NDoF(std::vector<double> par, int sigma_index)
376 {
377  double ll = LogLikelihood(par);
378  int n = GetNDataPoints();
379  int npar = GetNParameters();
380 
381  double sum_sigma = 0;
382  for (int i = 0; i < n; i++)
383  sum_sigma += log(GetDataPoint(i)->GetValue(sigma_index));
384 
385  double chi2 = -2. * (ll + (double) n / 2. * log(2. * M_PI) + sum_sigma);
386 
387  fChi2NDoF = chi2 / double(n - npar);
388  fPValueNDoF = TMath::Prob(chi2, n - npar);
389 
390  return fPValueNDoF;
391 }
392 
393 // ---------------------------------------------------------
394 double BCModel::GetPvalueFromKolmogorov(const std::vector<double>& par,int index)
395 {
396  if (flag_discrete) {
397  BCLog::OutError(Form("BCModel::GetPvalueFromKolmogorov : "
398  "test defined only for continuous distributions."));
399  return -1.;
400  }
401 
402  //calculate the ECDF from the 1D data
403  std::vector<double> yData = fDataSet->GetDataComponents(index);
404  TH1D * ECDF = BCMath::ECDF(yData);
405 
406  int N = GetNDataPoints();
407 
408  // calculated expected CDF for unique points only
409  std::set<double> uniqueObservations;
410  for (int i = 0; i < N; i++)
411  uniqueObservations.insert(CDF(par, i, false));
412 
413  int nUnique = uniqueObservations.size();
414  if (nUnique != ECDF->GetNbinsX() + 1) {
415  BCLog::OutError(Form("BCModel::GetPvalueFromKolmogorov : "
416  "Number of unique data points doesn't match (%d vs %d)", nUnique,
417  ECDF->GetNbinsX() + 1));
418  return -1.;
419  }
420 
421  // find maximum distance
422  double distMax = 0.;
423 
424  // current distance
425  double dist = 0.;
426 
427  std::set<double>::const_iterator iter = uniqueObservations.begin();
428  for (int iBin = 0; iBin < nUnique; ++iBin) {
429  // distance between current points
430  dist = TMath::Abs(*iter - ECDF->GetBinContent(iBin + 1));
431  // update maximum if necessary
432  distMax = TMath::Max(dist, distMax);
433 
434  // advance to next entry in the set
435  ++iter;
436  }
437 
438  // correct for total #points, not unique #points.
439  // would need sqrt(n1*n2/(n1+n2)) if we had two experimental datasets
440  double z = distMax * sqrt(N);
441 
442  fPValue = TMath::KolmogorovProb(z);
443 
444  // clean up
445  delete ECDF;
446 
447  return fPValue;
448 }
449 
450 // ---------------------------------------------------------
451 BCH1D * BCModel::CalculatePValue(std::vector<double> par, bool flag_histogram)
452 {
453  BCH1D * hist = 0;
454 
455  // print log
456  BCLog::OutSummary("Do goodness-of-fit-test");
457 
458  // create model test
459  BCGoFTest * goftest = new BCGoFTest("modeltest");
460 
461  // set this model as the model to be tested
462  goftest->SetTestModel(this);
463 
464  // set the point in parameter space which is tested an initialize
465  // the model testing
466  if (!goftest->SetTestPoint(par))
467  return 0;
468 
469  // disable the creation of histograms to save _a lot_ of memory
470  // (histograms are not needed for p-value calculation)
471  goftest->MCMCSetFlagFillHistograms(false);
472 
473  // set parameters of the MCMC for the GoFTest
474  goftest->MCMCSetNChains(fGoFNChains);
475  goftest->MCMCSetNIterationsMax(fGoFNIterationsMax);
476  goftest->MCMCSetNIterationsRun(fGoFNIterationsRun);
477 
478  // get p-value
479  fPValue = goftest->GetCalculatedPValue(flag_histogram);
480 
481  // get histogram
482  if (flag_histogram) {
483  hist = new BCH1D();
484  hist->SetHistogram(goftest->GetHistogramLogProb());
485  }
486 
487  // delete model test
488  delete goftest;
489 
490  // return histogram
491  return hist;
492 }
493 
494 // ---------------------------------------------------------
495 void BCModel::CorrelateDataPointValues(std::vector<double> & /*x*/)
496 {
497  // ...
498 }
499 
500 // ---------------------------------------------------------
501 double BCModel::HessianMatrixElement(const BCParameter * par1, const BCParameter * par2, std::vector<double> point)
502 {
503  // check number of entries in vector
504  if (point.size() != GetNParameters()) {
505  BCLog::OutError("BCModel::HessianMatrixElement : Invalid number of entries in the vector.");
506  return -1;
507  }
508 
509  // define steps
510  double nsteps = 1e5;
511  double dx1 = par1->GetRangeWidth() / nsteps;
512  double dx2 = par2->GetRangeWidth() / nsteps;
513 
514  // define points at which to evaluate
515  std::vector<double> xpp = point;
516  std::vector<double> xpm = point;
517  std::vector<double> xmp = point;
518  std::vector<double> xmm = point;
519 
520  unsigned idx1 = fParameters.Index(par1->GetName());
521  unsigned idx2 = fParameters.Index(par2->GetName());
522 
523  xpp[idx1] += dx1;
524  xpp[idx2] += dx2;
525 
526  xpm[idx1] += dx1;
527  xpm[idx2] -= dx2;
528 
529  xmp[idx1] -= dx1;
530  xmp[idx2] += dx2;
531 
532  xmm[idx1] -= dx1;
533  xmm[idx2] -= dx2;
534 
535  // calculate probability at these points
536  double ppp = Likelihood(xpp);
537  double ppm = Likelihood(xpm);
538  double pmp = Likelihood(xmp);
539  double pmm = Likelihood(xmm);
540 
541  // return derivative
542  return (ppp + pmm - ppm - pmp) / (4. * dx1 * dx2);
543 }
544 
545 // ---------------------------------------------------------
546 void BCModel::SetDataPointLowerBoundary(int index, double lowerboundary)
547 {
548  fDataPointLowerBoundaries -> SetValue(index, lowerboundary);
549 }
550 
551 // ---------------------------------------------------------
552 void BCModel::SetDataPointUpperBoundary(int index, double upperboundary)
553 {
554  fDataPointUpperBoundaries -> SetValue(index, upperboundary);
555 }
556 
557 // ---------------------------------------------------------
558 int BCModel::SetPrior(int index, TF1 * f)
559 {
560  // check index range
561  if (index < 0 && index >= int(GetNParameters())) {
562  BCLog::OutError("BCModel::SetPrior : Index out of range.");
563  return 0;
564  }
565 
566  if (fPriorContainer[index])
567  delete fPriorContainer[index];
568 
569  // copy function
570  fPriorContainer[index] = new TF1(*f);
571 
572  fPriorContainerConstant[index] = false;
573 
574  // no error
575  return 1;
576 }
577 
578 // ---------------------------------------------------------
579 int BCModel::SetPrior(const char * name, TF1 * f)
580 {
581  // find index
582  int index = -1;
583  for (unsigned int i = 0; i < GetNParameters(); i++)
584  if (name == GetParameter(i)->GetName())
585  index = i;
586 
587  // set prior
588  return SetPrior(index, f);
589 }
590 
591 // ---------------------------------------------------------
592 int BCModel::SetPriorDelta(int index, double value)
593 {
594  // set range to value
595  GetParameter(index)->Fix(value);
596 
597  // set prior
598  return 1;
599 }
600 
601 // ---------------------------------------------------------
602 int BCModel::SetPriorDelta(const char* name, double value)
603 {
604  fParameters.Get(name)->Fix(value);
605 
606  return 1;
607 }
608 
609 // ---------------------------------------------------------
610 int BCModel::SetPriorGauss(int index, double mean, double sigma)
611 {
612  // check index range
613  if (index < 0 || index >= int(GetNParameters())) {
614  BCLog::OutError("BCModel::SetPriorGauss : Index out of range.");
615  return 0;
616  }
617 
618  // create new function
619  TF1 * f = new TF1(Form("prior_%s", GetParameter(index)->GetName().c_str()),
620  "1./sqrt(2.*TMath::Pi())/[1] * exp(- (x-[0])*(x-[0])/2./[1]/[1])",
621  GetParameter(index)->GetLowerLimit(),
622  GetParameter(index)->GetUpperLimit());
623  f->SetParameter(0, mean);
624  f->SetParameter(1, sigma);
625 
626  // set prior
627  return SetPrior(index, f);
628 }
629 
630 // ---------------------------------------------------------
631 int BCModel::SetPriorGauss(const char* name, double mean, double sigma)
632 {
633  // find index
634  int index = -1;
635  for (unsigned int i = 0; i < GetNParameters(); i++)
636  if (name == GetParameter(i)->GetName())
637  index = i;
638 
639  // set prior
640  return SetPriorGauss(index, mean, sigma);
641 }
642 
643 // ---------------------------------------------------------
644 int BCModel::SetPriorGauss(int index, double mean, double sigmadown, double sigmaup)
645 {
646  // check index range
647  if (index < 0 || index >= int(GetNParameters())) {
648  BCLog::OutError("BCModel::SetPriorGauss : Index out of range.");
649  return 0;
650  }
651 
652  // create new function
653  TF1 * f = new TF1(Form("prior_%s", GetParameter(index)->GetName().c_str()),
655  GetParameter(index)->GetLowerLimit(),
656  GetParameter(index)->GetUpperLimit(),
657  3);
658  f->SetParameter(0, mean);
659  f->SetParameter(1, sigmadown);
660  f->SetParameter(2, sigmaup);
661 
662  // set prior
663  return SetPrior(index, f);
664 
665  return 0;
666 }
667 
668 // ---------------------------------------------------------
669 int BCModel::SetPriorGauss(const char * name, double mean, double sigmadown, double sigmaup)
670 {
671  // find index
672  int index = -1;
673  for (unsigned int i = 0; i < GetNParameters(); i++)
674  if (name == GetParameter(i)->GetName())
675  index = i;
676 
677  // set prior
678  return SetPriorGauss(index, mean, sigmadown, sigmaup);
679 }
680 
681 // ---------------------------------------------------------
682 int BCModel::SetPrior(int index, TH1 * h, bool interpolate)
683 {
684  // check index range
685  if (index < 0 && index >= int(GetNParameters())) {
686  BCLog::OutError("BCModel::SetPrior : Index out of range.");
687  return 0;
688  }
689 
690  // if the histogram exists
691  if(h) {
692 
693  // check if histogram is 1d
694  if (h->GetDimension() != 1) {
695  BCLog::OutError(Form("BCModel::SetPrior : Histogram given for parameter %d is not 1D.",index));
696  return 0;
697  }
698 
699  // normalize the histogram
700  h->Scale(1./h->Integral("width"));
701 
702  if(fPriorContainer[index])
703  delete fPriorContainer[index];
704 
705  // set function
706  fPriorContainer[index] = (TNamed*) h->Clone();
707 
708  if (interpolate)
709  fPriorContainerInterpolate[index] = true;
710 
711  fPriorContainerConstant[index] = false;
712  }
713 
714  // no error
715  return 1;
716 }
717 
718 // ---------------------------------------------------------
719 int BCModel::SetPrior(const char * name, TH1 * h, bool interpolate)
720 {
721  // find index
722  int index = -1;
723  for (unsigned int i = 0; i < GetNParameters(); i++)
724  if (name == GetParameter(i)->GetName())
725  index = i;
726 
727  // set prior
728  return SetPrior(index, h, interpolate);
729 }
730 
731 // ---------------------------------------------------------
733 {
734  // check index range
735  if (index < 0 && index >= int(GetNParameters())) {
736  BCLog::OutError("BCModel::SetPriorConstant : Index out of range.");
737  return 0;
738  }
739 
740  if(fPriorContainer[index]) {
741  delete fPriorContainer[index];
742  fPriorContainer[index] = 0;
743  }
744 
745  // set prior to a constant
746  fPriorContainerConstant[index] = true;
747 
748  // no error
749  return 1;
750 }
751 
752 // ---------------------------------------------------------
754 {
755  if ( !fParameters.Size())
756  BCLog::OutWarning("BCModel::SetPriorConstantAll : No parameters defined.");
757 
758  // loop over all 1-d priors
759  for (unsigned i = 0; i < fParameters.Size(); ++i) {
760  if (fPriorContainer[i]) {
761  delete fPriorContainer[i];
762  fPriorContainer[i]=0;
763  }
764  fPriorContainerConstant[i] = true;
765  }
766 
767  // no error
768  return 1;
769 }
770 
771 // ---------------------------------------------------------
773 {
774  // model summary
775  BCLog::OutSummary(Form("Model : %s", fName.data()));
776  BCLog::OutSummary(Form("Number of parameters : %u", GetNParameters()));
777  BCLog::OutSummary("Parameters:");
778 
779  // parameter summary
780  for (unsigned i = 0; i < GetNParameters(); i++)
781  fParameters[i]->PrintSummary();
782 
783  // best fit parameters
784  if ( !GetBestFitParameters().empty()) {
785  BCLog::OutSummary(Form("Log of the maximum posterior: %f", GetLogMaximum()));
786  BCLog::OutSummary("Best fit parameters:");
787 
788  for (unsigned i = 0; i < GetNParameters(); i++) {
789  if ( fParameters[i]->Fixed() )
790  BCLog::OutSummary(Form(" %s = %f (fixed)", fParameters[i]->GetName().data(), GetBestFitParameter(i)));
791  else
792  BCLog::OutSummary(Form(" %s = %f (global)", fParameters[i]->GetName().data(), GetBestFitParameter(i)));
793 
794  if ( fMarginalModes.size() == GetNParameters())
795  BCLog::OutSummary(Form(" %s = %f (marginalized)", fParameters[i]->GetName().data(), GetBestFitParametersMarginalized()[i]));
796 
797  }
798  }
799 
800  // model testing
801  if (fPValue >= 0) {
802  double likelihood = Likelihood(GetBestFitParameters());
803  BCLog::OutSummary(" Model testing:");
804  BCLog::OutSummary(Form(" p(data|lambda*) = %f", likelihood));
805  BCLog::OutSummary(Form(" p-value = %f", fPValue));
806  }
807 
808  // normalization
809  if (GetIntegral() > 0) {
810  BCLog::OutSummary(" Evidence:");
811  BCLog::OutSummary(Form(" - evidence : %f", GetIntegral()));
812  }
813 }
814 
815 // ---------------------------------------------------------
816 void BCModel::PrintResults(const char * file)
817 {
818  // print summary of Markov Chain Monte Carlo
819 
820  // open file
821  std::ofstream ofi(file);
822 
823  // check if file is open
824  if (!ofi.is_open()) {
825  std::cerr << "Couldn't open file " << file << std::endl;
826  return;
827  }
828 
829  // number of parameters and chains
830  unsigned npar = GetNParameters();
831  unsigned nchains = MCMCGetNChains();
832 
833  // check convergence
834  bool flag_conv = MCMCGetNIterationsConvergenceGlobal() > 0;
835 
836  ofi << std::endl
837  << " -----------------------------------------------------" << std::endl
838  << " Summary" << std::endl
839  << " -----------------------------------------------------" << std::endl
840  << std::endl;
841 
842  ofi << " Model summary" << std::endl << " =============" << std::endl
843  << " Model: " << fName.data() << std::endl
844  << " Number of parameters: " << npar << std::endl
845  << " List of Parameters and ranges:" << std::endl;
846  for (unsigned i = 0; i < npar; ++i) {
847  ofi << " (" << i << ") Parameter \""
848  << fParameters[i]->GetName() << "\"" << ": "
849  << "[" << fParameters[i]->GetLowerLimit() << ", "
850  << fParameters[i]->GetUpperLimit() << "]";
851  if (fParameters[i]->Fixed()) {
852  ofi << " (fixed)";
853  }
854  ofi << std::endl;
855  }
856  ofi << std::endl;
857 
858  ofi << " Results of the optimization" << std::endl
859  << " ===========================" << std::endl
860  << " Optimization algorithm used: "
861  << DumpUsedOptimizationMethod()<< std::endl;
862 
863  if ( ! GetBestFitParameters().empty()) {
864  ofi << " Log of the maximum posterior: " << GetLogMaximum() << std::endl;
865  ofi << " List of parameters and global mode:" << std::endl;
866  for (unsigned i = 0; i < npar; ++i) {
867  ofi << " (" << i << ") Parameter \""
868  << fParameters[i]->GetName() << "\": "
869  << GetBestFitParameter(i);
870  if (fParameters[i]->Fixed()) {
871  ofi << " (fixed)";
872  }
873  else if (GetBestFitParameterErrors().size() == npar) {
874  if(GetBestFitParameterError(i) >= 0.)
875  ofi << " +- " << GetBestFitParameterError(i);
876  else
877  ofi << " (no error estimate available) ";
878  }
879  else {
880  ofi << " (no error estimate available) ";
881  }
882  ofi << std::endl;
883  }
884  ofi << std::endl;
885  }
886  else {
887  ofi << " No best fit information available." << std::endl;
888  ofi << std::endl;
889  }
890 
891  if (fPValue >= 0.) {
892  ofi << " Results of the model test" << std::endl
893  << " =========================" << std::endl
894  << " p-value: " << fPValue << std::endl;
895  if (fPValueNDoF >= 0)
896  ofi << " p-value corrected for degrees of freedom: " << fPValueNDoF << std::endl;
897 
898  ofi << std::endl;
899  }
900 
901  if (GetIntegral() >= 0.) {
902  ofi << " Results of the integration" << std::endl
903  << " ============================" << std::endl
904  << " Integration method used: "
905  << DumpUsedIntegrationMethod() << std::endl;
906  ofi << " Evidence: " << GetIntegral();
907  if (GetError() >= 0)
908  ofi << " +- " << GetError() << std::endl;
909  else
910  ofi << " (no error estimate available) " << std::endl;
911  ofi << std::endl;
912  }
913 
914  // give warning if MCMC did not converge
915  if (!flag_conv && fMCMCFlagRun)
916  ofi << " WARNING: the Markov Chain did not converge!" << std::endl
917  << " Be cautious using the following results!" << std::endl
918  << std::endl;
919 
920  // print results of marginalization (if MCMC was run)
921  if (fFlagMarginalized) {
922  ofi << " Results of the marginalization" << std::endl
923  << " ==============================" << std::endl
924  << " Marginalization algorithm used: "
925  << DumpUsedMarginalizationMethod() << std::endl
926  << " List of parameters and properties of the marginalized"
927  << std::endl << " distributions:" << std::endl;
928  for (unsigned i = 0; i < npar; ++i) {
929  if ( ! fParameters[i]->FillHistograms())
930  continue;
931 
932  // get marginalized histogram
933  BCH1D * bch1d = GetMarginalized(fParameters[i]);
934 
935  ofi << " (" << i << ") Parameter \""
936  << fParameters[i]->GetName() << "\":";
937 
938  if (!bch1d) {
939  ofi << " fixed (or histogram does not exist) " << std::endl;
940  continue;
941  }
942  else
943  ofi << std::endl;
944 
945  ofi << " Mean +- sqrt(V): " << std::setprecision(4)
946  << bch1d->GetMean() << " +- " << std::setprecision(4)
947  << bch1d->GetRMS() << std::endl
948 
949  << " Median +- central 68% interval: "
950  << std::setprecision(4) << bch1d->GetMedian() << " + "
951  << std::setprecision(4) << bch1d->GetQuantile(0.84) - bch1d->GetMedian()
952  << " - " << std::setprecision(4)
953  << bch1d->GetMedian() - bch1d->GetQuantile(0.16) << std::endl
954 
955  << " (Marginalized) mode: " << bch1d->GetMode() << std::endl;
956 
957  ofi << " 5% quantile: " << std::setprecision(4)
958  << bch1d->GetQuantile(0.05) << std::endl
959  << " 10% quantile: " << std::setprecision(4)
960  << bch1d->GetQuantile(0.10) << std::endl
961  << " 16% quantile: " << std::setprecision(4)
962  << bch1d->GetQuantile(0.16) << std::endl
963  << " 84% quantile: " << std::setprecision(4)
964  << bch1d->GetQuantile(0.85) << std::endl
965  << " 90% quantile: " << std::setprecision(4)
966  << bch1d->GetQuantile(0.90) << std::endl
967  << " 95% quantile: " << std::setprecision(4)
968  << bch1d->GetQuantile(0.95) << std::endl;
969 
970  std::vector<double> v;
971  v = bch1d->GetSmallestIntervals(0.68);
972  ofi << " Smallest interval(s) containing at least 68% and local mode(s):"
973  << std::endl;
974  for (unsigned j = 0; j < v.size(); j += 5)
975  ofi << " (" << v[j] << ", " << v[j + 1]
976  << ") (local mode at " << v[j + 3] << " with rel. height "
977  << v[j + 2] << "; rel. area " << v[j + 4] << ")"
978  << std::endl;
979  ofi << std::endl;
980  }
981  }
982  if (fMCMCFlagRun) {
983  ofi << " Status of the MCMC" << std::endl << " ==================" << std::endl
984  << " Convergence reached: " << (flag_conv ? "yes" : "no")
985  << std::endl;
986 
987  if (flag_conv)
988  ofi << " Number of iterations until convergence: "
989  << MCMCGetNIterationsConvergenceGlobal() << std::endl;
990  else
991  ofi << " WARNING: the Markov Chain did not converge! Be\n"
992  << " cautious using the following results!" << std::endl
993  << std::endl;
994  ofi << " Number of chains: " << MCMCGetNChains() << std::endl
995  << " Number of iterations per chain: " << MCMCGetNIterationsRun() << std::endl
996  << " Average pre-run efficiencies:" << std::endl;
997 
998  std::vector<double> efficiencies;
999  efficiencies.assign(npar, 0.);
1000 
1001  for (unsigned ipar = 0; ipar < npar; ++ipar)
1002  for (unsigned ichain = 0; ichain < nchains; ++ichain) {
1003  efficiencies[ipar] +=
1004  fMCMCEfficiencies[ichain*npar+ipar] / double(nchains) * 100.;
1005  }
1006 
1007  for (unsigned ipar = 0; ipar < npar; ++ipar)
1008  ofi << " (" << ipar << ") Parameter \""
1009  << fParameters[ipar]->GetName().data() << "\": "
1010  << efficiencies.at(ipar) << "%" << std::endl;
1011  ofi << std::endl;
1012  }
1013 
1014  ofi << " -----------------------------------------------------" << std::endl
1015  << " Notation:" << std::endl
1016  << " Mean : mean value of the marg. pdf" << std::endl
1017  << " Median : median of the marg. pdf" << std::endl
1018  << " Marg. mode : most probable value of the marg. pdf" << std::endl
1019  << " V : Variance of the marg. pdf" << std::endl
1020  << " Quantiles : most commonly used quantiles" <<std::endl
1021  << " -----------------------------------------------------" << std::endl
1022  << std::endl;
1023 
1024  // close file
1025  ofi.close();
1026 }
1027 
1028 // ---------------------------------------------------------
1030 {
1031  BCLog::OutSummary("---------------------------------------------------");
1032  BCLog::OutSummary(Form("Fit summary for model \'%s\':", GetName().data()));
1033  BCLog::OutSummary(Form(" Number of parameters: Npar = %i", GetNParameters()));
1034  if (GetNDataPoints()) {
1035  BCLog::OutSummary(Form(" Number of data points: Ndata = %i", GetNDataPoints()));
1036  BCLog::OutSummary(" Number of degrees of freedom:");
1037  BCLog::OutSummary(Form(" NDoF = Ndata - Npar = %i", GetNDataPoints() - GetNParameters()));
1038  }
1039  if (!GetBestFitParameters().empty())
1040  BCLog::OutSummary(" Best fit parameters (global):");
1041  for (unsigned int i = 0; i < GetNParameters(); ++i)
1042  BCLog::OutSummary(Form(" %s = %.3g", GetParameter(i)->GetName().data(), GetBestFitParameter(i)));
1043 
1044  if (GetPValue() >= 0) {
1045  BCLog::OutSummary(" Goodness-of-fit test:");
1046  BCLog::OutSummary(Form(" p-value = %.3g", GetPValue()));
1047  if (chi2flag) {
1048  BCLog::OutSummary(Form(" p-value corrected for NDoF = %.3g", GetPValueNDoF()));
1049  BCLog::OutSummary(Form(" chi2 / NDoF = %.3g", GetChi2NDoF()));
1050  }
1051  }
1052  BCLog::OutSummary("---------------------------------------------------");
1053 }
1054 
1055 // ---------------------------------------------------------
1056 void BCModel::PrintHessianMatrix(std::vector<double> parameters)
1057 {
1058  // check number of entries in vector
1059  if (parameters.size() != GetNParameters()) {
1060  BCLog::OutError("BCModel::PrintHessianMatrix : Invalid number of entries in the vector");
1061  return;
1062  }
1063 
1064  // print to screen
1065  BCLog::OutSummary("Hessian matrix elements: ");
1066  BCLog::OutSummary("Parameter values:");
1067 
1068  for (int i = 0; i < int(parameters.size()); i++)
1069  BCLog::OutSummary(Form("Parameter %d : %f", i, parameters.at(i)));
1070 
1071  BCLog::OutSummary("Hessian matrix:");
1072  // loop over all parameter pairs
1073  for (unsigned int i = 0; i < GetNParameters(); i++)
1074  for (unsigned int j = 0; j < i; j++) {
1075  // calculate Hessian matrix element
1076  double hessianmatrixelement = HessianMatrixElement(
1077  fParameters[i], fParameters[j], parameters);
1078 
1079  // print to screen
1080  BCLog::OutSummary(Form("%d %d : %f", i, j, hessianmatrixelement));
1081  }
1082 }
1083 
1084 // ---------------------------------------------------------
1085 BCDataPoint * BCModel::VectorToDataPoint(const std::vector<double> &data)
1086 {
1087  BCDataPoint * datapoint = new BCDataPoint(data.size());
1088  datapoint->SetValues(data);
1089  return datapoint;
1090 }
1091 
1092 // ---------------------------------------------------------
1093 int BCModel::CompareStrings(const char * string1, const char * string2)
1094 {
1095  int flag_same = 0;
1096 
1097  if (strlen(string1) != strlen(string2))
1098  return -1;
1099 
1100  for (int i = 0; i < int(strlen(string1)); i++)
1101  if (string1[i] != string2[i])
1102  flag_same = -1;
1103 
1104  return flag_same;
1105 }
void SetDataPointUpperBoundary(int index, double upperboundary)
Definition: BCModel.cxx:552
bool fPriorConstantAll
Definition: BCModel.h:566
int SetPriorGauss(int index, double mean, double sigma)
Definition: BCModel.cxx:610
std::vector< bool > fPriorContainerConstant
Definition: BCModel.h:570
void PrintShortFitSummary(int chi2flag=0)
Definition: BCModel.cxx:1029
double APrioriProbability(const std::vector< double > &parameters)
Definition: BCModel.cxx:267
double HessianMatrixElement(const BCParameter *parameter1, const BCParameter *parameter2, std::vector< double > point)
Definition: BCModel.cxx:501
virtual double Likelihood(const std::vector< double > &params)
Definition: BCModel.cxx:324
virtual double LogLikelihood(const std::vector< double > &params)=0
std::vector< bool > fPriorContainerInterpolate
Definition: BCModel.h:574
int SetTestPoint(std::vector< double > parameters)
Definition: BCGoFTest.cxx:123
double GetDataPointLowerBoundary(unsigned int index) const
Definition: BCModel.cxx:142
double Probability(const std::vector< double > &parameter)
Definition: BCModel.cxx:249
TH1D * GetHistogramLogProb()
Definition: BCGoFTest.h:62
double fModelAPriori
Definition: BCModel.h:514
A class representing a data point.
Definition: BCDataPoint.h:31
double GetRMS()
Definition: BCH1D.h:87
int SetPriorDelta(int index, double value)
Definition: BCModel.cxx:592
void SetTestModel(BCModel *testmodel)
Definition: BCGoFTest.h:77
int fGoFNChains
Definition: BCModel.h:558
unsigned int GetNValues() const
Definition: BCDataPoint.h:65
double SplitGaussian(double *x, double *par)
Definition: BCMath.cxx:296
A class for handling numerical operations for models.
void SetDataSet(BCDataSet *dataset)
Definition: BCModel.h:178
bool GetFlagBoundaries() const
Definition: BCModel.cxx:154
int SetPriorConstantAll()
Definition: BCModel.cxx:753
void PrintResults(const char *file)
Definition: BCModel.cxx:816
double GetRangeWidth() const
Definition: BCParameter.h:77
The base class for all user-defined models.
Definition: BCModel.h:50
double GetDataPointUpperBoundary(unsigned int index) const
Definition: BCModel.cxx:148
void SetValues(const std::vector< double > &values)
Definition: BCDataPoint.cxx:70
void SetSingleDataPoint(BCDataPoint *datapoint)
Definition: BCModel.cxx:172
void PrintHessianMatrix(std::vector< double > parameters)
Definition: BCModel.cxx:1056
double GetMean()
Definition: BCH1D.h:58
A class representing a set of data points.
Definition: BCDataSet.h:37
BCDataPoint * fDataPointLowerBoundaries
Definition: BCModel.h:526
std::vector< TNamed * > fPriorContainer
Definition: BCModel.h:562
double GetPvalueFromChi2(const std::vector< double > &par, int sigma_index)
Definition: BCModel.cxx:351
double LogProbabilityNN(const std::vector< double > &parameters)
Definition: BCModel.h:378
int fGoFNIterationsMax
Definition: BCModel.h:548
BCModel(const char *name="model")
Definition: BCModel.cxx:36
virtual double CDF(const std::vector< double > &, int, bool)
Definition: BCModel.h:502
double fModelAPosteriori
Definition: BCModel.h:518
double GetMedian()
Definition: BCH1D.h:67
BCDataPoint * GetDataPoint(unsigned int index) const
Definition: BCModel.cxx:132
std::vector< double > GetDataComponents(int index)
Definition: BCDataSet.cxx:116
double LogProbability(const std::vector< double > &parameter)
Definition: BCModel.cxx:255
void SetHistogram(TH1D *hist)
Definition: BCH1D.h:149
A class representing a parameter of a model.
Definition: BCParameter.h:28
double GetMode()
Definition: BCH1D.cxx:52
virtual int AddParameter(BCParameter *parameter)
Definition: BCModel.cxx:225
std::string fName
Definition: BCModel.h:510
unsigned GetNDataPoints() const
Definition: BCModel.cxx:123
double Eval(const std::vector< double > &parameters)
Definition: BCModel.cxx:330
bool flag_discrete
Definition: BCModel.h:543
int fGoFNIterationsRun
Definition: BCModel.h:553
void PrintSummary()
Definition: BCModel.cxx:772
virtual int AddParameter(const char *name, double min, double max, const char *latexname="")
double ProbabilityNN(const std::vector< double > &params)
Definition: BCModel.cxx:243
The class for testing model hypotheses.
Definition: BCGoFTest.h:34
virtual ~BCModel()
Definition: BCModel.cxx:104
double GetPvalueFromKolmogorov(const std::vector< double > &par, int index)
Definition: BCModel.cxx:394
double GetCalculatedPValue(bool flag_histogram=false)
Definition: BCGoFTest.cxx:227
A class for handling 1D distributions.
Definition: BCH1D.h:31
BCDataSet * fDataSet
Definition: BCModel.h:522
std::vector< double > GetSmallestIntervals(double content=0.68)
Definition: BCH1D.cxx:1008
int SetPriorConstant(int index)
Definition: BCModel.cxx:732
BCDataPoint * GetDataPoint(unsigned int index)
Definition: BCDataSet.cxx:98
virtual double LogEval(const std::vector< double > &parameters)
Definition: BCModel.cxx:336
double GetQuantile(double probablity)
Definition: BCH1D.cxx:58
unsigned int GetNDataPoints()
Definition: BCDataSet.cxx:79
virtual double SamplingFunction(const std::vector< double > &parameters)
Definition: BCModel.cxx:342
const std::string & GetName() const
Definition: BCParameter.h:54
int SetPrior(int index, TF1 *f)
Definition: BCModel.cxx:558
BCDataPoint * fDataPointUpperBoundaries
Definition: BCModel.h:530
double GetPValue()
Definition: BCModel.h:435
void Copy(const BCModel &bcmodel)
Definition: BCModel.cxx:62
void SetDataPointLowerBoundary(int index, double lowerboundary)
Definition: BCModel.cxx:546
double fPValue
Definition: BCModel.h:536
virtual double LogAPrioriProbability(const std::vector< double > &parameters)
Definition: BCModel.cxx:273
std::vector< double > GetChi2Runs(int dataIndex, int sigmaIndex)
Definition: BCModel.cxx:368
void AddDataPoint(BCDataPoint *datapoint)
Definition: BCDataSet.cxx:358
BCModel & operator=(const BCModel &bcmodel)
Definition: BCModel.cxx:115
void SetValue(unsigned index, double value)
Definition: BCDataPoint.cxx:54
virtual void CorrelateDataPointValues(std::vector< double > &x)
Definition: BCModel.cxx:495
const std::string & GetName() const
Definition: BCModel.h:85
TH1D * ECDF(const std::vector< double > &data)
Definition: BCMath.cxx:333