BCFitter.cxx
1 /*
2  * Copyright (C) 2007-2018, the BAT core developer team
3  * All rights reserved.
4  *
5  * For the licensing terms see doc/COPYING.
6  * For documentation see http://mpp.mpg.de/bat
7  */
8 
9 // ---------------------------------------------------------
10 #include <config.h>
11 
12 #include "BCFitter.h"
13 
14 #include <BAT/BCDataPoint.h>
15 #include <BAT/BCH1D.h>
16 #include <BAT/BCLog.h>
17 #include <BAT/BCModel.h>
18 
19 #include <TF1.h>
20 #include <TFile.h>
21 #include <TGraph.h>
22 #include <TH1D.h>
23 #include <TH2D.h>
24 
25 #include <stdexcept>
26 
27 // ---------------------------------------------------------
28 BCFitter::BCFitter(const TF1& f, const std::string& name)
29  : BCModel(name),
30  fFitFunction(1, f),
31  fFlagFillErrorBand(true),
32  fFitFunctionIndexX(-1),
33  fFitFunctionIndexY(-1),
34  fErrorBandContinuous(true),
35  fErrorBandNbinsX(100),
36  fErrorBandNbinsY(500),
37  fErrorBandExtensionLowEdgeX(0),
38  fErrorBandExtensionUpEdgeX(0),
39  fErrorBandExtensionLowEdgeY(0),
40  fErrorBandExtensionUpEdgeY(0)
41 {
42  if (f.GetNdim() != 1)
43  throw std::invalid_argument("BCFitter and descendants only support 1D problems");
44 
45  // set name if name empty
46  if (name.empty())
47  SetName(std::string("fitter_model_") + fFitFunction.front().GetName());
48 
49  // fill parameter set
51  for (int i = 0; i < fFitFunction.front().GetNpar(); ++i) {
52  double xmin;
53  double xmax;
54 
55  fFitFunction.front().GetParLimits(i, xmin, xmax);
56 
57  AddParameter(fFitFunction.front().GetParName(i), xmin, xmax);
58  }
59 
60  // create a data set. this is necessary in order to calculate the
61  // error band.
63 
64  // by default set all priors constant
66 }
67 
68 // ---------------------------------------------------------
70 {
71 }
72 
73 // ---------------------------------------------------------
75 {
76  // add or remove copies
77  fFitFunction.resize(fMCMCNChains, fFitFunction.front());
78 }
79 
80 // ---------------------------------------------------------
82 {
83  // fill error band
85  FillErrorBand();
86 }
87 
88 // ---------------------------------------------------------
90 {
91  // prepare function fitting
92  double dx = 0.;
93  double dy = 0.;
94 
95  if (GetDataSet() && fFitFunctionIndexX >= 0 && fFitFunctionIndexY >= 0) {
96 
101 
102 
106 
108  double xRangeHigh = GetDataSet()->GetUpperBound(fFitFunctionIndexX) + fErrorBandExtensionUpEdgeX + dx / 2;
109 
111  double yRangeHigh = GetDataSet()->GetUpperBound(fFitFunctionIndexY) + fErrorBandExtensionUpEdgeY + dy / 2;
112 
113  fErrorBandXY = TH2D(TString::Format("errorbandxy_%s", GetSafeName().data()), "",
115  xRangeLow,
116  xRangeHigh,
118  yRangeLow,
119  yRangeHigh);
120  fErrorBandXY.SetStats(kFALSE);
121 
122  // why are we doing this?
123  for (unsigned ix = 1; ix <= fErrorBandNbinsX; ++ix)
124  for (unsigned iy = 1; iy <= fErrorBandNbinsX; ++iy)
125  fErrorBandXY.SetBinContent(ix, iy, 0.);
126  }
127 
128 }
129 
130 // ---------------------------------------------------------
132 {
133  // function fitting
134  if (fFitFunctionIndexX < 0)
135  return;
136 
137  // loop over all possible x values ...
138  if (fErrorBandContinuous) {
139  double x = 0;
140  for (unsigned ix = 1; ix <= fErrorBandNbinsX; ++ix) {
141  // calculate x
142  x = fErrorBandXY.GetXaxis()->GetBinCenter(ix);
143 
144  // calculate y
145  std::vector<double> xvec;
146  xvec.push_back(x);
147 
148  // loop over all chains
149  for (unsigned ichain = 0; ichain < GetNChains(); ++ichain) {
150  // calculate y
151  double y = FitFunction(xvec, Getx(ichain));
152 
153  // fill histogram
154  fErrorBandXY.Fill(x, y);
155  }
156 
157  xvec.clear();
158  }
159  }
160  // ... or evaluate at the data point x-values
161  else {
162  unsigned ndatapoints = fErrorBandX.size();
163  double x = 0;
164 
165  for (unsigned ix = 0; ix < ndatapoints; ++ix) {
166  // calculate x
167  x = fErrorBandX.at(ix);
168 
169  // calculate y
170  std::vector<double> xvec;
171  xvec.push_back(x);
172 
173  // loop over all chains
174  for (unsigned ichain = 0; ichain < GetNChains(); ++ichain) {
175  // calculate y
176  double y = FitFunction(xvec, Getx(ichain));
177 
178  // fill histogram
179  fErrorBandXY.Fill(x, y);
180  }
181 
182  xvec.clear();
183  }
184  }
185 }
186 
187 // ---------------------------------------------------------
188 double BCFitter::FitFunction(const std::vector<double>& x, const std::vector<double>& params)
189 {
190  // update parameters in right TF1 and evaluate
191  TF1& f = GetFitFunction();
192  f.SetParameters(&params[0]);
193  return f.Eval(x[0]);
194 }
195 
196 double BCFitter::Integral(const std::vector<double>& params, const double xmin, const double xmax)
197 {
198  TF1& f = GetFitFunction();
199 
200  f.SetParameters(&params[0]);
201 
202  // use ROOT's TH1::Integral method
203  if (fFlagIntegration) {
204  return f.Integral(xmin, xmax);
205  } // use linear interpolation
206  else {
207  return (f.Eval(xmin) + f.Eval(xmax)) * (xmax - xmin) / 2.;
208  }
209 }
210 
211 // ---------------------------------------------------------
213 {
215  if (GetPValue() >= 0) {
216  BCLog::OutSummary(" Goodness-of-fit test:");
217  BCLog::OutSummary(Form(" p-value = %.3g", GetPValue()));
218  BCLog::OutSummary("---------------------------------------------------");
219  }
220 }
221 
222 // ---------------------------------------------------------
223 std::vector<double> BCFitter::GetErrorBand(double level) const
224 {
225  std::vector<double> errorband;
226 
227  int nx = fErrorBandXY.GetNbinsX();
228  errorband.assign(nx, 0.);
229 
230  // loop over x and y bins
231  for (int ix = 1; ix <= nx; ix++) {
232  TH1D* temphist = fErrorBandXY.ProjectionY("temphist", ix, ix);
233 
234  int nprobSum = 1;
235  double q[1];
236  double probSum[1];
237  probSum[0] = level;
238 
239  temphist->GetQuantiles(nprobSum, q, probSum);
240 
241  errorband[ix - 1] = q[0];
242  delete temphist;
243  }
244 
245  return errorband;
246 }
247 
248 // ---------------------------------------------------------
249 TGraph* BCFitter::GetErrorBandGraph(double level1, double level2) const
250 {
251  // define new graph
252  int nx = fErrorBandXY.GetNbinsX();
253 
254  TGraph* graph = new TGraph(2 * nx);
255  graph->SetFillStyle(1001);
256  graph->SetFillColor(kYellow);
257  graph->SetLineWidth(0);
258 
259  // get error bands
260  std::vector<double> ymin = GetErrorBand(level1);
261  std::vector<double> ymax = GetErrorBand(level2);
262 
263  for (int i = 0; i < nx; i++) {
264  graph->SetPoint(i, fErrorBandXY.GetXaxis()->GetBinCenter(i + 1),
265  ymin[i] * GraphCorrection(i + 1));
266  graph->SetPoint(nx + i, fErrorBandXY.GetXaxis()->GetBinCenter(nx - i),
267  ymax[nx - i - 1] * GraphCorrection(i + 1));
268  }
269 
270  return graph;
271 }
272 
273 // ---------------------------------------------------------
274 TH2* BCFitter::GetGraphicalErrorBandXY(double level, int nsmooth, bool overcoverage) const
275 {
276  int nx = fErrorBandXY.GetNbinsX();
277  int ny = fErrorBandXY.GetNbinsY();
278 
279  // copy existing histogram
280  TH2* hist_tempxy = (TH2*) fErrorBandXY.Clone(TString::Format("%s_sub_%f.2", fErrorBandXY.GetName(), level));
281  hist_tempxy->Reset();
282  hist_tempxy->SetFillColor(kYellow);
283 
284  // loop over x bins
285  for (int ix = 1; ix < nx; ix++) {
286  BCH1D hist_temp(fErrorBandXY.ProjectionY("temphist", ix, ix));
287  if (nsmooth > 0)
288  hist_temp.Smooth(nsmooth);
289  std::vector<std::pair<double, double> > bound = hist_temp.GetSmallestIntervalBounds(std::vector<double>(1, level), overcoverage);
290  for (int iy = 1; iy <= ny; ++iy)
291  if (hist_temp.GetHistogram()->GetBinContent(iy) >= bound.front().first)
292  hist_tempxy->SetBinContent(ix, iy, 1);
293  }
294 
295  return hist_tempxy;
296 }
297 
298 
299 // ---------------------------------------------------------
300 TGraph* BCFitter::GetFitFunctionGraph(const std::vector<double>& parameters)
301 {
302  // define new graph
303  const int nx = fErrorBandXY.GetNbinsX();
304  TGraph* graph = new TGraph(nx);
305 
306  std::vector<double> xvec(1);
307 
308  // loop over x values
309  for (int i = 0; i < nx; i++) {
310  xvec[0] = fErrorBandXY.GetXaxis()->GetBinCenter(i + 1);
311  const double y = FitFunction(xvec, parameters) * GraphCorrection(i + 1);
312 
313  graph->SetPoint(i, xvec[0], y);
314  }
315 
316  return graph;
317 }
318 
319 // ---------------------------------------------------------
320 TGraph* BCFitter::GetFitFunctionGraph(const std::vector<double>& parameters, double xmin, double xmax, int n)
321 {
322  // define new graph
323  TGraph* graph = new TGraph(n + 1);
324 
325  double dx = (xmax - xmin) / (double) n;
326  std::vector<double> xvec(1);
327 
328  // loop over x values
329  for (int i = 0; i <= n; i++) {
330  xvec[0] = (double) i * dx + xmin;
331  const double y = FitFunction(xvec, parameters) * GraphCorrection(i + 1);
332 
333  graph->SetPoint(i, xvec[0], y);
334  }
335 
336  return graph;
337 }
338 
339 // ---------------------------------------------------------
340 void BCFitter::FixDataAxis(unsigned int index, bool fixed)
341 {
342  fFitterDataSet.Fix(index, fixed);
343 }
344 
345 // ---------------------------------------------------------
346 bool BCFitter::GetFixedDataAxis(unsigned int index) const
347 {
348  return fFitterDataSet.IsFixed(index);
349 }
350 
351 // ---------------------------------------------------------
353 {
354  fErrorBandContinuous = flag;
355 
356  if (flag)
357  return;
358 
359  // copy data x-values
361 }
TH2D fErrorBandXY
The error band histogram.
Definition: BCFitter.h:289
void PrintShortFitSummary()
Prints a short summary of the fit results on the screen.
Definition: BCFitter.cxx:212
unsigned fErrorBandNbinsX
Number of X bins of the error band histogram.
Definition: BCFitter.h:277
double fErrorBandExtensionUpEdgeX
extends the upper edge of x range by the given value
Definition: BCFitter.h:304
double GetPValue() const
Definition: BCFitter.h:110
void SetName(const std::string &name)
Sets the name of the engine.
double fErrorBandExtensionUpEdgeY
extends the upper edge of y range by the given value
Definition: BCFitter.h:312
std::vector< double > GetErrorBand(double level) const
Returns a vector of y-values at a certain probability level.
Definition: BCFitter.cxx:223
void FixDataAxis(unsigned int index, bool fixed)
Toggle the data axis defined by index to be fixed.
Definition: BCFitter.cxx:340
TF1 & GetFitFunction()
Get fit function.
Definition: BCFitter.h:55
unsigned GetNChains() const
Definition: BCEngineMCMC.h:279
virtual void MarginalizePreprocess()
Overloaded from BCIntegrate.
Definition: BCFitter.cxx:89
virtual bool AddParameter(const std::string &name, double min, double max, const std::string &latexname="", const std::string &unitstring="")
TGraph * GetErrorBandGraph(double level1, double level2) const
Definition: BCFitter.cxx:249
TH2 * GetGraphicalErrorBandXY(double level=.68, int nsmooth=0, bool overcoverage=true) const
Definition: BCFitter.cxx:274
Wrapper to allow access by name into list of BCParameter.
bool GetFixedDataAxis(unsigned int index) const
Definition: BCFitter.cxx:346
void SetDataSet(BCDataSet *dataset)
Sets the data set.
Definition: BCModel.h:145
The base class for all user-defined models.
Definition: BCModel.h:39
std::vector< double > GetDataComponents(unsigned index) const
Viewing the data set as a table with one row per point, this method returns a specified column...
Definition: BCDataSet.cxx:37
int fFitFunctionIndexY
The index for function fits in y direction.
Definition: BCFitter.h:265
void PrintShortFitSummary()
Prints a short summary of the fit results on the screen.
Definition: BCModel.cxx:178
double GetLowerBound(unsigned index) const
Return user-set lower bound on data, if set, otherwise actual lower bound.
Definition: BCDataSet.cxx:64
bool fFlagFillErrorBand
Flag whether or not to fill the error band.
Definition: BCFitter.h:258
double GetRangeWidth(unsigned index) const
Return upper-bound minus lower-bound for data axis, using user-set bounds, if provided, other actual bounds.
Definition: BCDataSet.h:149
void Smooth(int n=-1)
Applying ROOT smoothing to histogram, and renormalize.
virtual void MCMCUserIterationInterface()
Overloaded from BCEngineMCMC.
Definition: BCFitter.cxx:81
TGraph * GetFitFunctionGraph()
Definition: BCFitter.h:91
void Fix(unsigned i, bool b=true)
Set fixed flag of a data axis.
Definition: BCDataSet.h:182
void FillErrorBand()
Fill error band histogram for current iteration.
Definition: BCFitter.cxx:131
double fErrorBandExtensionLowEdgeX
extends the lower edge of x range by the given value
Definition: BCFitter.h:301
bool fErrorBandContinuous
A flag for single point evaluation of the error "band".
Definition: BCFitter.h:269
void SetErrorBandContinuous(bool flag)
Sets the error band flag to continuous function.
Definition: BCFitter.cxx:352
unsigned fMCMCNChains
Number of Markov chains ran in parallel.
double fErrorBandExtensionLowEdgeY
extends the upper edge of y range by the given value
Definition: BCFitter.h:308
virtual void SetPriorConstantAll()
Set all priors to constant.
int fFitFunctionIndexX
The index for function fits in x direction.
Definition: BCFitter.h:262
unsigned fErrorBandNbinsY
Number of Y bins of the error band histogram.
Definition: BCFitter.h:281
const std::vector< double > & Getx(unsigned c) const
Definition: BCEngineMCMC.h:370
virtual double GraphCorrection(unsigned) const
Take care of bin width when creating a graph from the fit function.
Definition: BCFitter.h:320
BCDataSet fFitterDataSet
Needed for uncertainty propagation.
Definition: BCFitter.h:292
const std::string & GetSafeName() const
Definition: BCEngineMCMC.h:274
double Integral(const std::vector< double > &parameters, double xmin, double xmax)
Compute the integral of the fit function between xmin and xmax.
Definition: BCFitter.cxx:196
A class for handling 1D distributions.
Definition: BCH1D.h:34
BCDataSet * fDataSet
A data set.
Definition: BCModel.h:291
virtual void MCMCUserInitialize()
Create enough TF1 copies for thread safety.
Definition: BCFitter.cxx:74
BCParameterSet fParameters
Parameter settings.
double GetUpperBound(unsigned index) const
Return user-set upper bound on data, if set, otherwise actual upper bound.
Definition: BCDataSet.cxx:76
BCFitter(const TF1 &f, const std::string &name="fitter_model")
Constructor.
Definition: BCFitter.cxx:28
std::vector< double > fErrorBandX
The x positions where the error is calculated.
Definition: BCFitter.h:273
virtual ~BCFitter()=0
The default destructor.
Definition: BCFitter.cxx:69
virtual double FitFunction(const std::vector< double > &x, const std::vector< double > &parameters)
Defines a fit function.
Definition: BCFitter.cxx:188
bool IsFixed(unsigned index) const
Return wether data axis is fixed.
Definition: BCDataSet.h:156
BCDataSet * GetDataSet()
Definition: BCModel.h:78
bool fFlagIntegration
Flag for using the ROOT TH1::Integral method (true), or linear interpolation (false) ...
Definition: BCFitter.h:297