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

BCGraphFitter.cxx

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008, 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() : BCModel("GraphFitter")
00027 {
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(TGraphErrors * graph, TF1 * func) : BCModel("GraphFitter")
00041 {
00042    fGraph = 0;
00043    fFitFunction = 0;
00044    fErrorBand = 0;
00045    fGraphFitFunction = 0;
00046 
00047    MCMCSetNIterationsRun(2000);
00048 
00049    SetGraph(graph);
00050    SetFitFunction(func);
00051 
00052    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    // fill the dataset
00093    // find x and y boundaries for the error band calculation
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       // if x errors are not set, set them to zero
00101       double errx = ex ? ex[i] : 0.;
00102 
00103       // create the data point
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    SetDataSet(ds);
00123 
00124    // set boundaries for the error band calculation
00125    SetDataBoundaries(0, xmin, xmax);
00126    SetDataBoundaries(1, ymin, ymax);
00127 
00128    SetFitFunctionIndices(0, 1);
00129 
00130    return 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    // get the new number of parameters
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    // set the function
00152    fFitFunction = func;
00153 
00154    // update the model name to contain the function name
00155    SetName(TString::Format("GraphFitter with %s",fFitFunction->GetName()));
00156 
00157    // reset parameters
00158    fParameterSet->clear();
00159 
00160    // add parameters
00161    for (int i = 0; i < npar; ++i)
00162    {
00163       double xmin;
00164       double xmax;
00165       fFitFunction->GetParLimits(i, xmin, xmax);
00166 
00167       AddParameter(fFitFunction->GetParName(i), xmin, xmax);
00168    }
00169 
00170    // set flat prior for all parameters by default
00171    SetPriorConstantAll();
00172 
00173    return GetNParameters();
00174 }
00175 
00176 // ---------------------------------------------------------
00177 
00178 BCGraphFitter::~BCGraphFitter()
00179 {}
00180 
00181 // ---------------------------------------------------------
00182 
00183 /*
00184 double BCGraphFitter::LogAPrioriProbability(std::vector <double> parameters)
00185 {
00186    // using flat probability in all parameters
00187    double logprob = 0.;
00188    for(unsigned int i=0; i < GetNParameters(); i++)
00189       logprob -= log(GetParameter(i)->GetRangeWidth());
00190 
00191    return logprob;
00192 }
00193 */
00194 
00195 // ---------------------------------------------------------
00196 
00197 double BCGraphFitter::LogLikelihood(std::vector <double> params)
00198 {
00199    // initialize probability
00200    double logl = 0.;
00201 
00202    // set the parameters of the function
00203    // passing the pointer to first element of the vector is
00204    // not completely safe as there might be an implementation where
00205    // the vector elements are not stored consecutively in memory.
00206    // however it is much faster than copying the contents, especially
00207    // for large number of parameters
00208    fFitFunction->SetParameters(&params[0]);
00209 
00210    // loop over all data points
00211    for (int i = 0; i < GetNDataPoints(); i++)
00212    {
00213       std::vector <double> x = GetDataPoint(i)->GetValues();
00214 
00215       // her we ignore the errors on x even when they're available
00216       // i.e. we treat them just as the region specifiers
00217       double y = x[1];
00218       double yerr = x[3];
00219       double yexp = FitFunction(x,params);
00220 
00221       // calculate log of probability assuming
00222       // a Gaussian distribution for each point
00223       logl += BCMath::LogGaus(y, yexp, yerr, true);
00224    }
00225 
00226    return logl;
00227 }
00228 
00229 // ---------------------------------------------------------
00230 
00231 double BCGraphFitter::FitFunction(std::vector <double> x, std::vector <double> params)
00232 {
00233    // set the parameters of the function
00234    fFitFunction->SetParameters(&params[0]);
00235 
00236    return fFitFunction->Eval(x[0]);
00237 }
00238 
00239 // ---------------------------------------------------------
00240 
00241 int BCGraphFitter::Fit(TGraphErrors * graph, TF1 * func)
00242 {
00243    // set graph
00244    if (!SetGraph(graph)) {
00245       BCLog::OutError("BCEfficiencyFitter::Fit : Graph not defined.");
00246       return 0;
00247    }
00248 
00249    // set function
00250    if (!SetFitFunction(func)) {
00251       return 0;
00252       BCLog::OutError("BCEfficiencyFitter::Fit : Fit function not defined.");
00253    }
00254 
00255    return Fit();
00256 }
00257 
00258 // ---------------------------------------------------------
00259 
00260 int BCGraphFitter::Fit()
00261 {
00262    // set graph
00263    if (!fGraph) {
00264       BCLog::OutError("BCEfficiencyFitter::Fit : Graph not defined.");
00265       return 0;
00266    }
00267 
00268    // set function
00269    if (!fFitFunction) {
00270       BCLog::OutError("BCEfficiencyFitter::Fit : Fit function not defined.");
00271       return 0;
00272    }
00273 
00274    // check setup
00275    BCLog::Out(BCLog::detail,BCLog::detail,
00276          Form("Fitting %d data points with function of %d parameters",GetNDataPoints(),GetNParameters()));
00277    if(GetNDataPoints() <= (int)GetNParameters())
00278    {
00279       BCLog::Out(BCLog::warning,BCLog::warning,
00280             Form("Number of parameters (%d) lower than or equal to number of points (%d)."
00281             , GetNParameters(), GetNDataPoints()));
00282       BCLog::Out(BCLog::warning,BCLog::warning,"Fit doesn't have much meaning.");
00283    }
00284 
00285    // perform marginalization
00286    MarginalizeAll();
00287 
00288    // maximize posterior probability, using the best-fit values close
00289    // to the global maximum from the MCMC
00290    FindModeMinuit( GetBestFitParameters(), -1);
00291 
00292    // calculate p-value from the chi2 probability
00293    // this is only valid for a product of gaussiang which is the case for
00294    // the BCGraphFitter
00295    GetPvalueFromChi2(GetBestFitParameters(), 3);
00296    GetPvalueFromChi2NDoF(GetBestFitParameters(), 3);
00297 
00298    // print summary to screen
00299    PrintShortFitSummary(1);
00300 
00301    return 1;
00302 }
00303 
00304 // ---------------------------------------------------------
00305 
00306 void BCGraphFitter::DrawFit(const char * options, bool flaglegend)
00307 {
00308    if (!fGraph)
00309    {
00310       BCLog::Out(BCLog::error, BCLog::error,"BCGraphFitter::DrawFit() : TGraphErrors not defined.");
00311       return;
00312    }
00313 
00314    if (!fFitFunction)
00315    {
00316       BCLog::Out(BCLog::error, BCLog::error,"BCGraphFitter::DrawFit() : Fit function not defined.");
00317       return;
00318    }
00319 
00320    // check wheather options contain "same"
00321    TString opt = options;
00322    opt.ToLower();
00323 
00324    // if not same, draw the histogram first to get the axes
00325    if(!opt.Contains("same"))
00326       fGraph->Draw("ap");
00327 
00328    // draw the error band as central 68% probability interval
00329    fErrorBand = GetErrorBandGraph(0.16, 0.84);
00330    fErrorBand->Draw("f same");
00331 
00332    // draw the fit function on top
00333    fGraphFitFunction = GetFitFunctionGraph( GetBestFitParameters() );
00334    fGraphFitFunction->SetLineColor(kRed);
00335    fGraphFitFunction->SetLineWidth(2);
00336    fGraphFitFunction->Draw("l same");
00337 
00338    // now draw the histogram again since it was covered by the band and
00339    // the best fit
00340    fGraph->Draw("p same");
00341 
00342    // draw legend
00343    if (flaglegend)
00344    {
00345       TLegend * legend = new TLegend(0.25, 0.75, 0.55, 0.95);
00346       legend->SetBorderSize(0);
00347       legend->SetFillColor(kWhite);
00348       legend->AddEntry(fGraph, "Data", "P");
00349       legend->AddEntry(fGraphFitFunction, "Best fit", "L");
00350       legend->AddEntry(fErrorBand, "Error band", "F");
00351       legend->Draw();
00352    }
00353 
00354    gPad->RedrawAxis();
00355 }
00356 
00357 // ---------------------------------------------------------
00358 
00359 double BCGraphFitter::CDF(const std::vector<double> & parameters,  int index, bool lower) {
00360 
00361    //format: x y error_x error_y
00362    std::vector<double> values = fDataSet->GetDataPoint(index)->GetValues();
00363 
00364    if (values.at(2))
00365       BCLog::OutWarning("BCGraphFitter::CDF: Non-zero errors in x-direction are ignored!");
00366 
00367    // get the observed value
00368    double yObs = values.at(1);
00369 
00370    // expectation value
00371    double yExp = FitFunction(values, parameters);
00372 
00373    return ROOT::Math::normal_cdf(yObs, values.at(3), yExp);
00374 }
00375 
00376 // ---------------------------------------------------------

Generated on Fri Nov 19 2010 17:02:52 for Bayesian Analysis Toolkit by  doxygen 1.7.1