• 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    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    // 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    this -> SetDataSet(ds);
00123 
00124    // set boundaries for the error band calculation
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    // 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    this -> 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       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    // using flat probability in all parameters
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    // initialize probability
00195    double logl = 0.;
00196 
00197    // set the parameters of the function
00198    // passing the pointer to first element of the vector is
00199    // not completely safe as there might be an implementation where
00200    // the vector elements are not stored consecutively in memory.
00201    // however it is much faster than copying the contents, especially
00202    // for large number of parameters
00203    fFitFunction -> SetParameters(&params[0]);
00204 
00205    // loop over all data points
00206    for (int i = 0; i < this -> GetNDataPoints(); i++)
00207    {
00208       std::vector <double> x = GetDataPoint(i) -> GetValues();
00209 
00210       // her we ignore the errors on x even when they're available
00211       // i.e. we treat them just as the region specifiers
00212       double y = x[1];
00213       double yerr = x[3];
00214       double yexp = this -> FitFunction(x,params);
00215 
00216       // calculate log of probability assuming
00217       // a Gaussian distribution for each point
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    // set the parameters of the function
00229    fFitFunction -> SetParameters(&params[0]);
00230 
00231    return fFitFunction -> Eval(x[0]);
00232 }
00233 
00234 // ---------------------------------------------------------
00235 
00236 int BCGraphFitter::Fit(TGraphErrors * graph, TF1 * func)
00237 {
00238    // set graph
00239    if (!this -> SetGraph(graph))
00240       return 0;
00241 
00242    // set function
00243    if (!this -> SetFitFunction(func))
00244       return 0;
00245 
00246    // check setup
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    // perform marginalization
00258    this -> MarginalizeAll();
00259 
00260    // maximize posterior probability, using the best-fit values close
00261    // to the global maximum from the MCMC
00262    this -> FindModeMinuit( this -> GetBestFitParameters(), -1);
00263 
00264    // calculate p-value from the chi2 probability
00265    // this is only valid for a product of gaussiang which is the case for
00266    // the BCGraphFitter
00267    this -> GetPvalueFromChi2(this -> GetBestFitParameters(), 3);
00268    this -> GetPvalueFromChi2NDoF(this -> GetBestFitParameters(), 3);
00269 
00270    // print summary to screen
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    // check wheather options contain "same"
00293    TString opt = options;
00294    opt.ToLower();
00295 
00296    // if not same, draw the histogram first to get the axes
00297    if(!opt.Contains("same"))
00298       fGraph -> Draw("ap");
00299 
00300    // draw the error band as central 68% probability interval
00301    fErrorBand = this -> GetErrorBandGraph(0.16, 0.84);
00302    fErrorBand -> Draw("f same");
00303 
00304    // draw the fit function on top
00305    fGraphFitFunction = this -> GetFitFunctionGraph( this->GetBestFitParameters() );
00306    fGraphFitFunction -> SetLineColor(kRed);
00307    fGraphFitFunction -> SetLineWidth(2);
00308    fGraphFitFunction -> Draw("l same");
00309 
00310    // now draw the histogram again since it was covered by the band and
00311    // the best fit
00312    fGraph -> Draw("p same");
00313 
00314    // draw legend
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    //format: x y error_x error_y
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    // get the observed value
00338    double yObs = values.at(1);
00339 
00340    // expectation value
00341    double yExp = FitFunction(values, parameters);
00342 
00343    return ROOT::Math::normal_cdf(yObs, values.at(3), yExp);
00344 }
00345 
00346 // ---------------------------------------------------------
00347 
00348 // ---------------------------------------------------------

Generated on Mon Aug 30 2010 22:14:54 for Bayesian Analysis Toolkit by  doxygen 1.7.1