• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

BCGraphFitter.cxx

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008-2012, Daniel Kollar and Kevin Kroeninger.
00003  * All rights reserved.
00004  *
00005  * For the licensing terms see doc/COPYING.
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()
00027  : BCModel()
00028  , fGraph(0)
00029  , fFitFunction(0)
00030  , fErrorBand(0)
00031  , fGraphFitFunction(0)
00032 {
00033    MCMCSetNIterationsRun(2000);
00034 
00035    SetFillErrorBand();
00036 }
00037 
00038 // ---------------------------------------------------------
00039 
00040 BCGraphFitter::BCGraphFitter(const char * name)
00041  : BCModel(name)
00042  , fGraph(0)
00043  , fFitFunction(0)
00044  , fErrorBand(0)
00045  , fGraphFitFunction(0)
00046 {
00047    MCMCSetNIterationsRun(2000);
00048 
00049    SetFillErrorBand();
00050 }
00051 
00052 // ---------------------------------------------------------
00053 
00054 BCGraphFitter::BCGraphFitter(TGraphErrors * graph, TF1 * func)
00055  : BCModel()
00056  , fGraph(0)
00057  , fFitFunction(0)
00058  , fErrorBand(0)
00059  , fGraphFitFunction(0)
00060 {
00061    MCMCSetNIterationsRun(2000);
00062 
00063    SetGraph(graph);
00064    SetFitFunction(func);
00065 
00066    SetFillErrorBand();
00067 }
00068 
00069 // ---------------------------------------------------------
00070 
00071 BCGraphFitter::BCGraphFitter(const char * name, TGraphErrors * graph, TF1 * func)
00072  : BCModel(name)
00073  , fGraph(0)
00074  , fFitFunction(0)
00075  , fErrorBand(0)
00076  , fGraphFitFunction(0)
00077 {
00078    MCMCSetNIterationsRun(2000);
00079 
00080    SetGraph(graph);
00081    SetFitFunction(func);
00082 
00083    SetFillErrorBand();
00084 }
00085 
00086 // ---------------------------------------------------------
00087 
00088 int BCGraphFitter::SetGraph(TGraphErrors * graph)
00089 {
00090    if(!graph) {
00091       BCLog::Out(BCLog::error,BCLog::error,"BCGraphFitter::SetGraph() : TGraphErrors not created.");
00092       return 0;
00093    }
00094 
00095    int npoints = graph->GetN();
00096    if(!npoints)
00097    {
00098       BCLog::Out(BCLog::error,BCLog::error,"BCGraphFitter::SetGraph() : TGraphErrors is empty.");
00099       return 0;
00100    }
00101    else if(npoints==1)
00102    {
00103       BCLog::Out(BCLog::error,BCLog::error,"BCGraphFitter::SetGraph() : TGraphErrors has only one point. Not able to fit.");
00104       return 0;
00105    }
00106 
00107    fGraph = graph;
00108 
00109    double * x = fGraph->GetX();
00110    double * y = fGraph->GetY();
00111    double * ex = fGraph->GetEX();
00112    double * ey = fGraph->GetEY();
00113 
00114    if(!ey)
00115    {
00116       BCLog::Out(BCLog::error,BCLog::error,"BCGraphFitter::SetGraph() : TGraphErrors has NO errors set on Y. Not able to fit.");
00117       return 0;
00118    }
00119 
00120    BCDataSet * ds = new BCDataSet();
00121 
00122    // fill the dataset
00123    // find x and y boundaries for the error band calculation
00124    double xmin=x[0];
00125    double xmax=x[0];
00126    double ymin=y[0];
00127    double ymax=y[0];
00128    for (int i = 0; i < npoints; ++i)
00129    {
00130       // if x errors are not set, set them to zero
00131       double errx = ex ? ex[i] : 0.;
00132 
00133       // create the data point
00134       BCDataPoint * dp = new BCDataPoint(4);
00135       dp->SetValue(0, x[i]);
00136       dp->SetValue(1, y[i]);
00137       dp->SetValue(2, errx);
00138       dp->SetValue(3, ey[i]);
00139       ds->AddDataPoint(dp);
00140 
00141       if(x[i]-errx < xmin)
00142          xmin = x[i]-errx;
00143       else if(x[i]+errx > xmax)
00144          xmax = x[i]+errx;
00145 
00146       if(y[i] - 5.*ey[i] < ymin)
00147          ymin = y[i] - 5.*ey[i];
00148       else if(y[i] + 5.*ey[i] > ymax)
00149          ymax = y[i] + 5.*ey[i];
00150    }
00151 
00152    SetDataSet(ds);
00153 
00154    // set boundaries for the error band calculation
00155    SetDataBoundaries(0, xmin, xmax);
00156    SetDataBoundaries(1, ymin, ymax);
00157 
00158    SetFitFunctionIndices(0, 1);
00159 
00160    return GetNDataPoints();
00161 }
00162 
00163 // ---------------------------------------------------------
00164 
00165 int BCGraphFitter::SetFitFunction(TF1 * func)
00166 {
00167    if(!func)
00168    {
00169       BCLog::Out(BCLog::error,BCLog::error,"BCGraphFitter::SetFitFunction() : TF1 not created.");
00170       return 0;
00171    }
00172 
00173    // get the new number of parameters
00174    int npar = func->GetNpar();
00175    if(!npar)
00176    {
00177       BCLog::Out(BCLog::error,BCLog::error,"BCGraphFitter::SetFitFunction() : TF1 has zero parameters. Not able to fit.");
00178       return 0;
00179    }
00180 
00181    // set the function
00182    fFitFunction = func;
00183 
00184    // update the model name to contain the function name
00185    if(fName=="model")
00186       SetName(TString::Format("GraphFitter with %s",fFitFunction->GetName()));
00187 
00188    // reset parameters
00189    fParameterSet->clear();
00190 
00191    // add parameters
00192    for (int i = 0; i < npar; ++i)
00193    {
00194       double xmin;
00195       double xmax;
00196       fFitFunction->GetParLimits(i, xmin, xmax);
00197 
00198       AddParameter(fFitFunction->GetParName(i), xmin, xmax);
00199    }
00200 
00201    // set flat prior for all parameters by default
00202    SetPriorConstantAll();
00203 
00204    return GetNParameters();
00205 }
00206 
00207 // ---------------------------------------------------------
00208 
00209 BCGraphFitter::~BCGraphFitter()
00210 {}
00211 
00212 // ---------------------------------------------------------
00213 
00214 /*
00215 double BCGraphFitter::LogAPrioriProbability(std::vector<double> parameters)
00216 {
00217    // using flat probability in all parameters
00218    double logprob = 0.;
00219    for(unsigned int i=0; i < GetNParameters(); i++)
00220       logprob -= log(GetParameter(i)->GetRangeWidth());
00221 
00222    return logprob;
00223 }
00224 */
00225 
00226 // ---------------------------------------------------------
00227 
00228 double BCGraphFitter::LogLikelihood(const std::vector<double> & params)
00229 {
00230    // initialize probability
00231    double logl = 0.;
00232 
00233    // set the parameters of the function
00234    // passing the pointer to first element of the vector is
00235    // not completely safe as there might be an implementation where
00236    // the vector elements are not stored consecutively in memory.
00237    // however it is much faster than copying the contents, especially
00238    // for large number of parameters
00239    fFitFunction->SetParameters(&params[0]);
00240 
00241    // loop over all data points
00242    for (int i = 0; i < GetNDataPoints(); i++)
00243    {
00244       std::vector<double> x = GetDataPoint(i)->GetValues();
00245 
00246       // her we ignore the errors on x even when they're available
00247       // i.e. we treat them just as the region specifiers
00248       double y = x[1];
00249       double yerr = x[3];
00250       double yexp = fFitFunction->Eval(x[0]);
00251 
00252       // calculate log of probability assuming
00253       // a Gaussian distribution for each point
00254       logl += BCMath::LogGaus(y, yexp, yerr, true);
00255    }
00256 
00257    return logl;
00258 }
00259 
00260 // ---------------------------------------------------------
00261 
00262 double BCGraphFitter::FitFunction(const std::vector<double> & x, const std::vector<double> & params)
00263 {
00264    // set the parameters of the function
00265    // passing the pointer to first element of the vector is
00266    // not completely safe as there might be an implementation where
00267    // the vector elements are not stored consecutively in memory.
00268    // however it is much faster than copying the contents, especially
00269    // for large number of parameters
00270    fFitFunction->SetParameters(&params[0]);
00271 
00272    return fFitFunction->Eval(x[0]);
00273 }
00274 
00275 // ---------------------------------------------------------
00276 
00277 int BCGraphFitter::Fit(TGraphErrors * graph, TF1 * func)
00278 {
00279    // set graph
00280    if (!SetGraph(graph)) {
00281       BCLog::OutError("BCEfficiencyFitter::Fit : Graph not defined.");
00282       return 0;
00283    }
00284 
00285    // set function
00286    if (!SetFitFunction(func)) {
00287       return 0;
00288       BCLog::OutError("BCEfficiencyFitter::Fit : Fit function not defined.");
00289    }
00290 
00291    return Fit();
00292 }
00293 
00294 // ---------------------------------------------------------
00295 
00296 int BCGraphFitter::Fit()
00297 {
00298    // set graph
00299    if (!fGraph) {
00300       BCLog::OutError("BCEfficiencyFitter::Fit : Graph not defined.");
00301       return 0;
00302    }
00303 
00304    // set function
00305    if (!fFitFunction) {
00306       BCLog::OutError("BCEfficiencyFitter::Fit : Fit function not defined.");
00307       return 0;
00308    }
00309 
00310    // check setup
00311    BCLog::Out(BCLog::detail,BCLog::detail,
00312          Form("Fitting %d data points with function of %d parameters",GetNDataPoints(),GetNParameters()));
00313    if(GetNDataPoints() <= (int)GetNParameters())
00314    {
00315       BCLog::Out(BCLog::warning,BCLog::warning,
00316             Form("Number of parameters (%d) lower than or equal to number of points (%d)."
00317             , GetNParameters(), GetNDataPoints()));
00318       BCLog::Out(BCLog::warning,BCLog::warning,"Fit doesn't have much meaning.");
00319    }
00320 
00321    // perform marginalization
00322    MarginalizeAll();
00323 
00324    // maximize posterior probability, using the best-fit values close
00325    // to the global maximum from the MCMC
00326    FindModeMinuit( GetBestFitParameters(), -1);
00327 
00328    // calculate p-value from the chi2 probability
00329    // this is only valid for a product of gaussiang which is the case for
00330    // the BCGraphFitter
00331    GetPvalueFromChi2(GetBestFitParameters(), 3);
00332    GetPvalueFromChi2NDoF(GetBestFitParameters(), 3);
00333 
00334    // print summary to screen
00335    PrintShortFitSummary(1);
00336 
00337    return 1;
00338 }
00339 
00340 // ---------------------------------------------------------
00341 
00342 void BCGraphFitter::DrawFit(const char * options, bool flaglegend)
00343 {
00344    if (!fGraph)
00345    {
00346       BCLog::Out(BCLog::error, BCLog::error,"BCGraphFitter::DrawFit() : TGraphErrors not defined.");
00347       return;
00348    }
00349 
00350    if (!fFitFunction)
00351    {
00352       BCLog::Out(BCLog::error, BCLog::error,"BCGraphFitter::DrawFit() : Fit function not defined.");
00353       return;
00354    }
00355 
00356    // check wheather options contain "same"
00357    TString opt = options;
00358    opt.ToLower();
00359 
00360    // if not same, draw the histogram first to get the axes
00361    if(!opt.Contains("same"))
00362       fGraph->Draw("ap");
00363 
00364    // draw the error band as central 68% probability interval
00365    fErrorBand = GetErrorBandGraph(0.16, 0.84);
00366    fErrorBand->Draw("f same");
00367 
00368    // draw the fit function on top
00369    fGraphFitFunction = GetFitFunctionGraph( GetBestFitParameters() );
00370    fGraphFitFunction->SetLineColor(kRed);
00371    fGraphFitFunction->SetLineWidth(2);
00372    fGraphFitFunction->Draw("l same");
00373 
00374    // now draw the histogram again since it was covered by the band and
00375    // the best fit
00376    fGraph->Draw("p same");
00377 
00378    // draw legend
00379    if (flaglegend)
00380    {
00381       TLegend * legend = new TLegend(0.25, 0.75, 0.55, 0.95);
00382       legend->SetBorderSize(0);
00383       legend->SetFillColor(kWhite);
00384       legend->AddEntry(fGraph, "Data", "P");
00385       legend->AddEntry(fGraphFitFunction, "Best fit", "L");
00386       legend->AddEntry(fErrorBand, "Error band", "F");
00387       legend->Draw();
00388    }
00389 
00390    gPad->RedrawAxis();
00391 }
00392 
00393 // ---------------------------------------------------------
00394 
00395 double BCGraphFitter::CDF(const std::vector<double> & parameters,  int index, bool /*lower*/) {
00396 
00397    //format: x y error_x error_y
00398    std::vector<double> values = fDataSet->GetDataPoint(index)->GetValues();
00399 
00400    if (values.at(2))
00401       BCLog::OutWarning("BCGraphFitter::CDF: Non-zero errors in x-direction are ignored!");
00402 
00403    // get the observed value
00404    double yObs = values.at(1);
00405 
00406    // expectation value
00407    double yExp = FitFunction(values, parameters);
00408 
00409    return ROOT::Math::normal_cdf(yObs, values.at(3), yExp);
00410 }
00411 
00412 // ---------------------------------------------------------

Generated by  doxygen 1.7.1