00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <TGraphErrors.h>
00011 #include <TF1.h>
00012 #include <TString.h>
00013 #include <TPad.h>
00014 #include <TLegend.h>
00015 #include <Math/ProbFuncMathCore.h>
00016
00017 #include "BAT/BCLog.h"
00018 #include "BAT/BCDataSet.h"
00019 #include "BAT/BCDataPoint.h"
00020 #include "BAT/BCMath.h"
00021
00022 #include "BCGraphFitter.h"
00023
00024
00025
00026 BCGraphFitter::BCGraphFitter() : BCModel("GraphFitter")
00027 {
00028 fGraph = 0;
00029 fFitFunction = 0;
00030 fErrorBand = 0;
00031 fGraphFitFunction = 0;
00032
00033 this -> MCMCSetNIterationsRun(2000);
00034
00035 this -> SetFillErrorBand();
00036 }
00037
00038
00039
00040 BCGraphFitter::BCGraphFitter(TGraphErrors * graph, TF1 * func) : BCModel("GraphFitter")
00041 {
00042 fGraph = 0;
00043 fFitFunction = 0;
00044 fErrorBand = 0;
00045 fGraphFitFunction = 0;
00046
00047 this -> MCMCSetNIterationsRun(2000);
00048
00049 this -> SetGraph(graph);
00050 this -> SetFitFunction(func);
00051
00052 this -> SetFillErrorBand();
00053 }
00054
00055
00056
00057 int BCGraphFitter::SetGraph(TGraphErrors * graph)
00058 {
00059 if(!graph)
00060 {
00061 BCLog::Out(BCLog::error,BCLog::error,"BCGraphFitter::SetGraph() : TGraphErrors not created.");
00062 return 0;
00063 }
00064
00065 int npoints = graph -> GetN();
00066 if(!npoints)
00067 {
00068 BCLog::Out(BCLog::error,BCLog::error,"BCGraphFitter::SetGraph() : TGraphErrors is empty.");
00069 return 0;
00070 }
00071 else if(npoints==1)
00072 {
00073 BCLog::Out(BCLog::error,BCLog::error,"BCGraphFitter::SetGraph() : TGraphErrors has only one point. Not able to fit.");
00074 return 0;
00075 }
00076
00077 fGraph = graph;
00078
00079 double * x = fGraph -> GetX();
00080 double * y = fGraph -> GetY();
00081 double * ex = fGraph -> GetEX();
00082 double * ey = fGraph -> GetEY();
00083
00084 if(!ey)
00085 {
00086 BCLog::Out(BCLog::error,BCLog::error,"BCGraphFitter::SetGraph() : TGraphErrors has NO errors set on Y. Not able to fit.");
00087 return 0;
00088 }
00089
00090 BCDataSet * ds = new BCDataSet();
00091
00092
00093
00094 double xmin=x[0];
00095 double xmax=x[0];
00096 double ymin=y[0];
00097 double ymax=y[0];
00098 for (int i = 0; i < npoints; ++i)
00099 {
00100
00101 double errx = ex ? ex[i] : 0.;
00102
00103
00104 BCDataPoint * dp = new BCDataPoint(4);
00105 dp -> SetValue(0, x[i]);
00106 dp -> SetValue(1, y[i]);
00107 dp -> SetValue(2, errx);
00108 dp -> SetValue(3, ey[i]);
00109 ds -> AddDataPoint(dp);
00110
00111 if(x[i]-errx < xmin)
00112 xmin = x[i]-errx;
00113 else if(x[i]+errx > xmax)
00114 xmax = x[i]+errx;
00115
00116 if(y[i] - 5.*ey[i] < ymin)
00117 ymin = y[i] - 5.*ey[i];
00118 else if(y[i] + 5.*ey[i] > ymax)
00119 ymax = y[i] + 5.*ey[i];
00120 }
00121
00122 this -> SetDataSet(ds);
00123
00124
00125 this -> SetDataBoundaries(0, xmin, xmax);
00126 this -> SetDataBoundaries(1, ymin, ymax);
00127
00128 this -> SetFitFunctionIndices(0, 1);
00129
00130 return this -> GetNDataPoints();
00131 }
00132
00133
00134
00135 int BCGraphFitter::SetFitFunction(TF1 * func)
00136 {
00137 if(!func)
00138 {
00139 BCLog::Out(BCLog::error,BCLog::error,"BCGraphFitter::SetFitFunction() : TF1 not created.");
00140 return 0;
00141 }
00142
00143
00144 int npar = func -> GetNpar();
00145 if(!npar)
00146 {
00147 BCLog::Out(BCLog::error,BCLog::error,"BCGraphFitter::SetFitFunction() : TF1 has zero parameters. Not able to fit.");
00148 return 0;
00149 }
00150
00151
00152 fFitFunction = func;
00153
00154
00155 this -> SetName(TString::Format("GraphFitter with %s",fFitFunction->GetName()));
00156
00157
00158 fParameterSet -> clear();
00159
00160
00161 for (int i = 0; i < npar; ++i)
00162 {
00163 double xmin;
00164 double xmax;
00165 fFitFunction -> GetParLimits(i, xmin, xmax);
00166
00167 this -> AddParameter(fFitFunction->GetParName(i), xmin, xmax);
00168 }
00169
00170 return this -> GetNParameters();
00171 }
00172
00173
00174
00175 BCGraphFitter::~BCGraphFitter()
00176 {}
00177
00178
00179
00180 double BCGraphFitter::LogAPrioriProbability(std::vector <double> parameters)
00181 {
00182
00183 double logprob = 0.;
00184 for(unsigned int i=0; i < this -> GetNParameters(); i++)
00185 logprob -= log(this -> GetParameter(i) -> GetRangeWidth());
00186
00187 return logprob;
00188 }
00189
00190
00191
00192 double BCGraphFitter::LogLikelihood(std::vector <double> params)
00193 {
00194
00195 double logl = 0.;
00196
00197
00198
00199
00200
00201
00202
00203 fFitFunction -> SetParameters(¶ms[0]);
00204
00205
00206 for (int i = 0; i < this -> GetNDataPoints(); i++)
00207 {
00208 std::vector <double> x = GetDataPoint(i) -> GetValues();
00209
00210
00211
00212 double y = x[1];
00213 double yerr = x[3];
00214 double yexp = this -> FitFunction(x,params);
00215
00216
00217
00218 logl += BCMath::LogGaus(y, yexp, yerr, true);
00219 }
00220
00221 return logl;
00222 }
00223
00224
00225
00226 double BCGraphFitter::FitFunction(std::vector <double> x, std::vector <double> params)
00227 {
00228
00229 fFitFunction -> SetParameters(¶ms[0]);
00230
00231 return fFitFunction -> Eval(x[0]);
00232 }
00233
00234
00235
00236 int BCGraphFitter::Fit(TGraphErrors * graph, TF1 * func)
00237 {
00238
00239 if (!this -> SetGraph(graph))
00240 return 0;
00241
00242
00243 if (!this -> SetFitFunction(func))
00244 return 0;
00245
00246
00247 BCLog::Out(BCLog::detail,BCLog::detail,
00248 Form("Fitting %d data points with function of %d parameters",GetNDataPoints(),GetNParameters()));
00249 if(GetNDataPoints() <= (int)GetNParameters())
00250 {
00251 BCLog::Out(BCLog::warning,BCLog::warning,
00252 Form("Number of parameters (%d) lower than or equal to number of points (%d)."
00253 , GetNParameters(), GetNDataPoints()));
00254 BCLog::Out(BCLog::warning,BCLog::warning,"Fit doesn't have much meaning.");
00255 }
00256
00257
00258 this -> MarginalizeAll();
00259
00260
00261
00262 this -> FindModeMinuit( this -> GetBestFitParameters(), -1);
00263
00264
00265
00266
00267 this -> GetPvalueFromChi2(this -> GetBestFitParameters(), 3);
00268 this -> GetPvalueFromChi2NDoF(this -> GetBestFitParameters(), 3);
00269
00270
00271 this -> PrintShortFitSummary(1);
00272
00273 return 1;
00274 }
00275
00276
00277
00278 void BCGraphFitter::DrawFit(const char * options, bool flaglegend)
00279 {
00280 if (!fGraph)
00281 {
00282 BCLog::Out(BCLog::error, BCLog::error,"BCGraphFitter::DrawFit() : TGraphErrors not defined.");
00283 return;
00284 }
00285
00286 if (!fFitFunction)
00287 {
00288 BCLog::Out(BCLog::error, BCLog::error,"BCGraphFitter::DrawFit() : Fit function not defined.");
00289 return;
00290 }
00291
00292
00293 TString opt = options;
00294 opt.ToLower();
00295
00296
00297 if(!opt.Contains("same"))
00298 fGraph -> Draw("ap");
00299
00300
00301 fErrorBand = this -> GetErrorBandGraph(0.16, 0.84);
00302 fErrorBand -> Draw("f same");
00303
00304
00305 fGraphFitFunction = this -> GetFitFunctionGraph( this->GetBestFitParameters() );
00306 fGraphFitFunction -> SetLineColor(kRed);
00307 fGraphFitFunction -> SetLineWidth(2);
00308 fGraphFitFunction -> Draw("l same");
00309
00310
00311
00312 fGraph -> Draw("p same");
00313
00314
00315 if (flaglegend)
00316 {
00317 TLegend * legend = new TLegend(0.25, 0.75, 0.55, 0.95);
00318 legend -> SetBorderSize(0);
00319 legend -> SetFillColor(kWhite);
00320 legend -> AddEntry(fGraph, "Data", "P");
00321 legend -> AddEntry(fGraphFitFunction, "Best fit", "L");
00322 legend -> AddEntry(fErrorBand, "Error band", "F");
00323 legend -> Draw();
00324 }
00325
00326 gPad -> RedrawAxis();
00327 }
00328
00329 double BCGraphFitter::CDF(const std::vector<double> & parameters, int index, bool lower) {
00330
00331
00332 std::vector<double> values = fDataSet->GetDataPoint(index)->GetValues();
00333
00334 if (values.at(2))
00335 BCLog::OutWarning("BCGraphFitter::CDF: Non-zero errors in x-direction are ignored!");
00336
00337
00338 double yObs = values.at(1);
00339
00340
00341 double yExp = FitFunction(values, parameters);
00342
00343 return ROOT::Math::normal_cdf(yObs, values.at(3), yExp);
00344 }
00345
00346
00347
00348