HFitInterface.cxx

Go to the documentation of this file.
00001 // @(#)root/hist:$Id: HFitInterface.cxx 38150 2011-02-18 16:29:46Z moneta $
00002 // Author: L. Moneta Thu Aug 31 10:40:20 2006
00003 
00004 /**********************************************************************
00005  *                                                                    *
00006  * Copyright (c) 2006  LCG ROOT Math Team, CERN/PH-SFT                *
00007  *                                                                    *
00008  *                                                                    *
00009  **********************************************************************/
00010 
00011 // Implementation file for class TH1Interface
00012 
00013 #include "HFitInterface.h"
00014 
00015 #include "Fit/BinData.h"
00016 #include "Fit/SparseData.h"
00017 #include "Fit/FitResult.h"
00018 #include "Math/IParamFunction.h"
00019 
00020 #include <vector>
00021 
00022 #include <cassert> 
00023 #include <cmath>
00024 
00025 #include "TH1.h"
00026 #include "THnSparse.h"
00027 #include "TF1.h"
00028 #include "TGraph2D.h"
00029 #include "TGraph.h" 
00030 #include "TGraphErrors.h" 
00031 // #include "TGraphErrors.h" 
00032 // #include "TGraphBentErrors.h" 
00033 // #include "TGraphAsymmErrors.h" 
00034 #include "TMultiGraph.h" 
00035 #include "TList.h"
00036 #include "TError.h"
00037 
00038 
00039 //#define DEBUG
00040 #ifdef DEBUG
00041 #include "TClass.h"
00042 #include <iostream> 
00043 #endif
00044 
00045 
00046 namespace ROOT { 
00047 
00048 namespace Fit { 
00049 
00050 // add a namespace to distinguish from the Graph functions 
00051 namespace HFitInterface { 
00052 
00053 
00054 bool IsPointOutOfRange(const TF1 * func, const double * x) { 
00055    // function to check if a point is outside range
00056    if (func ==0) return false; 
00057    return !func->IsInside(x);       
00058 }
00059 
00060 bool AdjustError(const DataOptions & option, double & error, double value = 1) {
00061    // adjust the given error according to the option
00062    // return false when point must be skipped.
00063    // When point error = 0, the point is kept if the option UseEmpty is set or if 
00064    // fErrors1 is set and the point value is not zero.
00065    // The value should be used only for points representing counts (histograms), not for the graph. 
00066    // In the graph points with zero errors are by default skipped indepentently of the value. 
00067    // If one wants to keep the points, the option fUseEmpty must be set
00068 
00069    if (error <= 0) { 
00070       if (option.fUseEmpty || (option.fErrors1 && std::abs(value) > 0 ) ) 
00071          error = 1.; // set error to 1 
00072       else
00073          return false;   // skip  bins with zero errors or empty
00074    } else if (option.fErrors1) 
00075       error = 1;   // set all error to 1 for non-empty bins
00076    return true; 
00077 }
00078 
00079 void ExamineRange(TAxis * axis, std::pair<double,double> range,int &hxfirst,int &hxlast) {
00080    // examine the range given with the pair on the given histogram axis
00081    // correct in case the bin values hxfirst hxlast
00082    double xlow   = range.first; 
00083    double xhigh  = range.second; 
00084 #ifdef DEBUG
00085    std::cout << "xlow " << xlow << " xhigh = " << xhigh << std::endl;
00086 #endif
00087    // ignore ranges specified outside histogram range
00088    int ilow = axis->FindBin(xlow);
00089    int ihigh = axis->FindBin(xhigh);
00090    if (ilow > hxlast || ihigh < hxfirst) { 
00091       Warning("ROOT::Fit::FillData","fit range is outside histogram range, no fit data for %s",axis->GetName()); 
00092    } 
00093    // consider only range defined with-in histogram not oustide. Always exclude underflow/overflow
00094    hxfirst =  std::min( std::max( ilow, hxfirst), hxlast+1) ;
00095    hxlast  =  std::max( std::min( ihigh, hxlast), hxfirst-1) ;
00096    // exclude bins where range coverage is less than half bin width
00097    if (hxfirst < hxlast) { 
00098       if ( axis->GetBinCenter(hxfirst) < xlow)  hxfirst++;
00099       if ( axis->GetBinCenter(hxlast)  > xhigh) hxlast--;
00100    }
00101 }
00102 
00103 
00104 } // end namespace HFitInterface
00105 
00106 void FillData(BinData & dv, const TH1 * hfit, TF1 * func) 
00107 {
00108    // Function to fill the binned Fit data structure from a TH1 
00109    // The dimension of the data is the same of the histogram dimension
00110    // The function pointer is need in case of integral is used and to reject points 
00111    // rejected in the function
00112 
00113    // the TF1 pointer cannot be constant since EvalPar and InitArgs are not const methods
00114    
00115    // get fit option 
00116    const DataOptions & fitOpt = dv.Opt();
00117 
00118 
00119    // store instead of bin center the bin edges 
00120    bool useBinEdges = fitOpt.fIntegral || fitOpt.fBinVolume;
00121    
00122    assert(hfit != 0); 
00123    
00124    //std::cout << "creating Fit Data from histogram " << hfit->GetName() << std::endl; 
00125 
00126    int hxfirst = hfit->GetXaxis()->GetFirst();
00127    int hxlast  = hfit->GetXaxis()->GetLast();
00128 
00129    int hyfirst = hfit->GetYaxis()->GetFirst();
00130    int hylast  = hfit->GetYaxis()->GetLast();
00131 
00132    int hzfirst = hfit->GetZaxis()->GetFirst();
00133    int hzlast  = hfit->GetZaxis()->GetLast();
00134 
00135    // function by default has same range (use that one if requested otherwise use data one)
00136 
00137    
00138    //  get the range (add the function range ??)
00139    // to check if inclusion/exclusion at end/point
00140    const DataRange & range = dv.Range(); 
00141    if (range.Size(0) != 0) { 
00142       HFitInterface::ExamineRange( hfit->GetXaxis(), range(0), hxfirst, hxlast); 
00143       if (range.Size(0) > 1  ) { 
00144          Warning("ROOT::Fit::FillData","support only one range interval for X coordinate"); 
00145       }
00146    }
00147          
00148    if (hfit->GetDimension() > 1 && range.Size(1) != 0) { 
00149       HFitInterface::ExamineRange( hfit->GetYaxis(), range(1), hyfirst, hylast); 
00150       if (range.Size(1) > 1  ) 
00151          Warning("ROOT::Fit::FillData","support only one range interval for Y coordinate"); 
00152    }
00153 
00154    if (hfit->GetDimension() > 2 && range.Size(2) != 0) { 
00155       HFitInterface::ExamineRange( hfit->GetZaxis(), range(2), hzfirst, hzlast); 
00156       if (range.Size(2) > 1  ) 
00157          Warning("ROOT::Fit::FillData","support only one range interval for Z coordinate"); 
00158    }
00159    
00160    
00161    int n = (hxlast-hxfirst+1)*(hylast-hyfirst+1)*(hzlast-hzfirst+1); 
00162    
00163 #ifdef DEBUG
00164    std::cout << "THFitInterface: ifirst = " << hxfirst << " ilast =  " << hxlast 
00165              << " total bins  " << n  
00166              << std::endl; 
00167 #endif
00168    
00169    // reserve n for more efficient usage
00170    //dv.Data().reserve(n);
00171    
00172    int hdim =  hfit->GetDimension();
00173    int ndim = hdim; 
00174    // case of function dimension less than histogram 
00175    if (func !=0 && func->GetNdim() == hdim-1) ndim = hdim-1;
00176    assert( ndim > 0 );
00177    //typedef  BinPoint::CoordData CoordData; 
00178    //CoordData x = CoordData( hfit->GetDimension() );
00179    dv.Initialize(n,ndim); 
00180 
00181    double x[3];
00182    double s[3];
00183 
00184    int binx = 0; 
00185    int biny = 0; 
00186    int binz = 0; 
00187 
00188    TAxis *xaxis  = hfit->GetXaxis();
00189    TAxis *yaxis  = hfit->GetYaxis();
00190    TAxis *zaxis  = hfit->GetZaxis();
00191 
00192    for ( binx = hxfirst; binx <= hxlast; ++binx) {
00193       if (useBinEdges) {
00194          x[0] = xaxis->GetBinLowEdge(binx);       
00195          s[0] = xaxis->GetBinUpEdge(binx);
00196       }
00197       else
00198          x[0] = xaxis->GetBinCenter(binx);
00199       
00200 
00201       for ( biny = hyfirst; biny <= hylast; ++biny) {
00202          if (useBinEdges) {
00203             x[1] = yaxis->GetBinLowEdge(biny);
00204             s[1] = yaxis->GetBinUpEdge(biny);
00205          }
00206          else
00207             x[1] = yaxis->GetBinCenter(biny);
00208             
00209          for ( binz = hzfirst; binz <= hzlast; ++binz) {
00210             if (useBinEdges) {
00211                x[2] = zaxis->GetBinLowEdge(binz);
00212                s[2] = zaxis->GetBinUpEdge(binz);
00213             }
00214             else
00215                x[2] = zaxis->GetBinCenter(binz);
00216 
00217             // need to evaluate function to know about rejected points
00218             // hugly but no other solutions
00219             if (func != 0) { 
00220                func->RejectPoint(false);
00221                (*func)( &x[0] );  // evaluate using stored function parameters
00222                if (func->RejectedPoint() ) continue; 
00223             }
00224 
00225 
00226             double value =  hfit->GetBinContent(binx, biny, binz);
00227             double error =  hfit->GetBinError(binx, biny, binz); 
00228             if (!HFitInterface::AdjustError(fitOpt,error,value) ) continue; 
00229 
00230             if (ndim == hdim -1) { 
00231                // case of fitting a function with  dimension -1
00232                // point error is bin width y / sqrt(N) where N is nuber of entries in the bin
00233                // normalization of error will be wrong - but they will be rescaled in the fit
00234                if (hdim == 2)  dv.Add(  x,  x[1],  yaxis->GetBinWidth(biny) / error  );
00235                if (hdim == 3)  dv.Add(  x,  x[2],  zaxis->GetBinWidth(binz) / error  );
00236             } else { 
00237                dv.Add(   x,  value, error  );
00238                if (useBinEdges) { 
00239                   dv.AddBinUpEdge( s ); 
00240                }
00241             }
00242 
00243            
00244 #ifdef DEBUG
00245             std::cout << "bin " << binx << " add point " << x[0] << "  " << hfit->GetBinContent(binx) << std::endl;
00246 #endif
00247 
00248          }  // end loop on z bins
00249       }  // end loop on y bins
00250    }   // end loop on x axis 
00251    
00252    
00253 #ifdef DEBUG
00254    std::cout << "THFitInterface::FillData: Hist FitData size is " << dv.Size() << std::endl;
00255 #endif
00256    
00257 }
00258 
00259 //______________________________________________________________________________
00260 void InitExpo(const ROOT::Fit::BinData & data, TF1 * f1)
00261 {
00262    //   -*-*-*-*Compute rough values of parameters for an  exponential
00263    //           ===================================================
00264 
00265    unsigned int n = data.Size();
00266    if (n == 0) return; 
00267 
00268    // find xmin and xmax of the data
00269    double valxmin;
00270    double xmin = *(data.GetPoint(0,valxmin));
00271    double xmax = xmin;
00272    double valxmax = valxmin;    
00273 
00274    for (unsigned int i = 1; i < n; ++ i) { 
00275       double val; 
00276       double x = *(data.GetPoint(i,val) );
00277       if (x < xmin) { 
00278          xmin = x; 
00279          valxmin = val; 
00280       }
00281       else if (x > xmax) { 
00282          xmax = x; 
00283          valxmax = val; 
00284       }
00285    }
00286 
00287    // avoid negative values of valxmin/valxmax
00288    if (valxmin <= 0 && valxmax > 0 ) valxmin = valxmax; 
00289    else if (valxmax <=0 && valxmin > 0) valxmax = valxmin; 
00290    else if (valxmin <=0 && valxmax <= 0) { valxmin = 1; valxmax = 1; }
00291 
00292    double slope = std::log( valxmax/valxmin) / (xmax - xmin); 
00293    double constant = std::log(valxmin) - slope * xmin;
00294    f1->SetParameters(constant, slope);
00295 }
00296 
00297 
00298 //______________________________________________________________________________
00299 void InitGaus(const ROOT::Fit::BinData & data, TF1 * f1)
00300 {
00301    //   -*-*-*-*Compute Initial values of parameters for a gaussian
00302    //           derivaed from function H1InitGaus defined in TH1.cxx  
00303    //           ===================================================
00304    
00305 
00306    static const double sqrtpi = 2.506628;
00307 
00308    //   - Compute mean value and RMS of the data
00309    unsigned int n = data.Size();
00310    if (n == 0) return; 
00311    double sumx = 0; 
00312    double sumx2 = 0; 
00313    double allcha = 0;
00314    double valmax = 0; 
00315    double rangex = data.Coords(n-1)[0] - data.Coords(0)[0];
00316    // to avoid binwidth = 0 set arbitrarly to 1
00317    double binwidth = 1;
00318    if ( rangex > 0) binwidth = rangex; 
00319    double x0 = 0;
00320    for (unsigned int i = 0; i < n; ++ i) { 
00321       double val; 
00322       double x = *(data.GetPoint(i,val) );
00323       sumx  += val*x; 
00324       sumx2 += val*x*x; 
00325       allcha += val; 
00326       if (val > valmax) valmax = val; 
00327       if (i > 0) { 
00328          double dx = x - x0; 
00329          if (dx < binwidth) binwidth = dx; 
00330       }         
00331       x0 = x; 
00332    }
00333 
00334    if (allcha <= 0) return;
00335    double mean = sumx/allcha;
00336    double rms  = sumx2/allcha - mean*mean;
00337 
00338 
00339    if (rms > 0) 
00340       rms  = std::sqrt(rms);
00341    else
00342       rms  = binwidth*n/4;
00343 
00344 
00345     //if the distribution is really gaussian, the best approximation
00346    //is binwidx*allcha/(sqrtpi*rms)
00347    //However, in case of non-gaussian tails, this underestimates
00348    //the normalisation constant. In this case the maximum value
00349    //is a better approximation.
00350    //We take the average of both quantities
00351 
00352 //   printf("valmax %f other %f bw %f allcha %f rms %f  \n",valmax, binwidth*allcha/(sqrtpi*rms), 
00353 //          binwidth, allcha,rms  );
00354 
00355    double constant = 0.5*(valmax+ binwidth*allcha/(sqrtpi*rms));
00356 
00357 
00358    //In case the mean value is outside the histo limits and
00359    //the RMS is bigger than the range, we take
00360    //  mean = center of bins
00361    //  rms  = half range
00362 //    Double_t xmin = curHist->GetXaxis()->GetXmin();
00363 //    Double_t xmax = curHist->GetXaxis()->GetXmax();
00364 //    if ((mean < xmin || mean > xmax) && rms > (xmax-xmin)) {
00365 //       mean = 0.5*(xmax+xmin);
00366 //       rms  = 0.5*(xmax-xmin);
00367 //    }
00368 
00369    f1->SetParameter(0,constant);
00370    f1->SetParameter(1,mean);
00371    f1->SetParameter(2,rms);
00372    f1->SetParLimits(2,0,10*rms);
00373 
00374 
00375 #ifdef DEBUG
00376    std::cout << "Gaussian initial par values" << constant << "   " << mean << "  " << rms << std::endl;
00377 #endif
00378 
00379 }
00380 
00381 //______________________________________________________________________________
00382 void Init2DGaus(const ROOT::Fit::BinData & data, TF1 * f1)
00383 {
00384    //   -*-*-*-*Compute Initial values of parameters for a gaussian
00385    //           derivaed from function H1InitGaus defined in TH1.cxx  
00386    //           ===================================================
00387 
00388 
00389    static const double sqrtpi = 2.506628;
00390 
00391    //   - Compute mean value and RMS of the data
00392    unsigned int n = data.Size();
00393    if (n == 0) return; 
00394    double sumx = 0, sumy = 0;
00395    double sumx2 = 0, sumy2 = 0; 
00396    double allcha = 0;
00397    double valmax = 0; 
00398    double rangex = data.Coords(n-1)[0] - data.Coords(0)[0];
00399    double rangey = data.Coords(n-1)[1] - data.Coords(0)[1];
00400    // to avoid binwidthx = 0 set arbitrarly to 1
00401    double binwidthx = 1, binwidthy = 1;
00402    if ( rangex > 0) binwidthx = rangex; 
00403    if ( rangey > 0) binwidthy = rangey; 
00404    double x0 = 0, y0 = 0;
00405    for (unsigned int i = 0; i < n; ++i) { 
00406       double val; 
00407       const double *coords = data.GetPoint(i,val);
00408       double x = coords[0], y = coords[1];
00409       sumx  += val*x; 
00410       sumy  += val*y;
00411       sumx2 += val*x*x; 
00412       sumy2 += val*y*y;
00413       allcha += val; 
00414       if (val > valmax) valmax = val; 
00415       if (i > 0) { 
00416          double dx = x - x0; 
00417          if (dx < binwidthx) binwidthx = dx; 
00418          double dy = y - y0;
00419          if (dy < binwidthy) binwidthy = dy; 
00420       }         
00421       x0 = x; 
00422       y0 = y;
00423    }
00424 
00425    if (allcha <= 0) return;
00426    double meanx = sumx/allcha, meany = sumy/allcha;
00427    double rmsx  = sumx2/allcha - meanx*meanx;
00428    double rmsy  = sumy2/allcha - meany*meany;
00429 
00430 
00431    if (rmsx > 0) 
00432       rmsx  = std::sqrt(rmsx);
00433    else
00434       rmsx  = binwidthx*n/4;
00435 
00436    if (rmsy > 0) 
00437       rmsy  = std::sqrt(rmsy);
00438    else
00439       rmsy  = binwidthy*n/4;
00440 
00441 
00442     //if the distribution is really gaussian, the best approximation
00443    //is binwidx*allcha/(sqrtpi*rmsx)
00444    //However, in case of non-gaussian tails, this underestimates
00445    //the normalisation constant. In this case the maximum value
00446    //is a better approximation.
00447    //We take the average of both quantities
00448 
00449    double constant = 0.5 * (valmax+ binwidthx*allcha/(sqrtpi*rmsx))*
00450                            (valmax+ binwidthy*allcha/(sqrtpi*rmsy));
00451 
00452    f1->SetParameter(0,constant);
00453    f1->SetParameter(1,meanx);
00454    f1->SetParameter(2,rmsx);
00455    f1->SetParLimits(2,0,10*rmsx);
00456    f1->SetParameter(3,meany);
00457    f1->SetParameter(4,rmsy);
00458    f1->SetParLimits(4,0,10*rmsy);
00459 
00460 #ifdef DEBUG
00461    std::cout << "2D Gaussian initial par values" 
00462              << constant << "   " 
00463              << meanx    << "   " 
00464              << rmsx
00465              << meany    << "   " 
00466              << rmsy
00467              << std::endl;
00468 #endif
00469 
00470 }
00471 
00472 // filling fit data from TGraph objects
00473 
00474 BinData::ErrorType GetDataType(const TGraph * gr, const DataOptions & fitOpt) { 
00475    // get type of data for TGraph objects
00476    double *ex = gr->GetEX();
00477    double *ey = gr->GetEY();
00478    double * eyl = gr->GetEYlow();
00479    double * eyh = gr->GetEYhigh();
00480  
00481   
00482    // default case for graphs (when they have errors) 
00483    BinData::ErrorType type = BinData::kValueError; 
00484    // if all errors are zero set option of using errors to 1
00485    if (fitOpt.fErrors1 || ( ey == 0 && ( eyl == 0 || eyh == 0 ) ) ) { 
00486       type =  BinData::kNoError; 
00487    }
00488    // need to treat case when all errors are zero 
00489    else if ( ex != 0 && fitOpt.fCoordErrors)  { 
00490       // check that all errors are not zero
00491       int i = 0; 
00492       while (i < gr->GetN() && type != BinData::kCoordError) { 
00493          if (ex[i] > 0) type = BinData::kCoordError; 
00494          ++i;
00495       }
00496    }
00497    else if ( ( eyl != 0 && eyh != 0)  && fitOpt.fAsymErrors)  { 
00498       // check also if that all errors are non zero's
00499       int i = 0; 
00500       bool zeroError = true;
00501       while (i < gr->GetN() && zeroError) { 
00502          double e2X = ( gr->GetErrorXlow(i) + gr->GetErrorXhigh(i) );
00503          double e2Y = eyl[i] + eyh[i];
00504          if ( e2X > 0 || e2Y > 0) zeroError = false; 
00505          ++i;
00506       }
00507       if (zeroError) 
00508          type = BinData::kNoError;
00509       else 
00510          type = BinData::kAsymError; 
00511    }
00512 
00513    // need to look also a case when all errors in y are zero 
00514    if ( ey != 0 && type != BinData::kCoordError )  { 
00515       int i = 0; 
00516       bool zeroError = true;
00517       while (i < gr->GetN() && zeroError) { 
00518          if (ey[i] > 0) zeroError = false;; 
00519          ++i;
00520       }
00521       if (zeroError) type = BinData::kNoError;
00522    }
00523 
00524 
00525 #ifdef DEBUG
00526    std::cout << "type is " << type << " graph type is " << gr->IsA()->GetName() << std::endl; 
00527 #endif
00528 
00529    return type; 
00530 }
00531 
00532 BinData::ErrorType GetDataType(const TGraph2D * gr, const DataOptions & fitOpt) { 
00533    // get type of data for TGraph2D object
00534    double *ex = gr->GetEX();
00535    double *ey = gr->GetEY();
00536    double *ez = gr->GetEZ();
00537   
00538    // default case for graphs (when they have errors) 
00539    BinData::ErrorType type = BinData::kValueError; 
00540    // if all errors are zero set option of using errors to 1
00541    if (ez == 0 ) { 
00542       type =  BinData::kNoError; 
00543    }
00544    else if ( ex != 0 && ey!=0 && fitOpt.fCoordErrors)  { 
00545       // check that all errors are not zero
00546       int i = 0; 
00547       while (i < gr->GetN() && type != BinData::kCoordError) { 
00548          if (ex[i] > 0 || ey[i] > 0) type = BinData::kCoordError; 
00549          ++i;
00550       }
00551    }
00552 
00553 
00554 #ifdef DEBUG
00555    std::cout << "type is " << type << " graph2D type is " << gr->IsA()->GetName() << std::endl; 
00556 #endif
00557 
00558    return type; 
00559 }
00560 
00561 
00562 
00563 void DoFillData ( BinData  & dv,  const TGraph * gr,  BinData::ErrorType type, TF1 * func ) {  
00564    // internal method to do the actual filling of the data
00565    // given a graph and a multigraph
00566 
00567    // get fit option 
00568    DataOptions & fitOpt = dv.Opt();
00569       
00570    int  nPoints = gr->GetN();
00571    double *gx = gr->GetX();
00572    double *gy = gr->GetY();
00573 
00574    const DataRange & range = dv.Range(); 
00575    bool useRange = ( range.Size(0) > 0);
00576    double xmin = 0; 
00577    double xmax = 0; 
00578    range.GetRange(xmin,xmax); 
00579 
00580    dv.Initialize(nPoints,1, type); 
00581 
00582 #ifdef DEBUG
00583    std::cout << "DoFillData: graph npoints = " << nPoints << " type " << type << std::endl;
00584    if (func) { 
00585       double a1,a2; func->GetRange(a1,a2); std::cout << "func range " << a1 << "  " << a2 << std::endl;
00586    }
00587 #endif
00588 
00589    double x[1]; 
00590    for ( int i = 0; i < nPoints; ++i) { 
00591       
00592       x[0] = gx[i];
00593 
00594       
00595       if (useRange && (  x[0] < xmin || x[0] > xmax) ) continue;   
00596 
00597       // need to evaluate function to know about rejected points
00598       // hugly but no other solutions
00599       if (func) { 
00600          func->RejectPoint(false);
00601          (*func)( x ); // evaluate using stored function parameters 
00602          if (func->RejectedPoint() ) continue; 
00603       }
00604 
00605 
00606       if (fitOpt.fErrors1)  
00607          dv.Add( gx[i], gy[i] ); 
00608 
00609       // for the errors use the getters by index to avoid cases when the arrays are zero 
00610       // (like in a case of a graph)
00611       else if (type == BinData::kValueError)  { 
00612          double errorY =  gr->GetErrorY(i);    
00613          // should consider error = 0 as 1 ? Decide to skip points with zero errors 
00614          // in case want to keep points with error = 0 as errrors=1 need to set the option UseEmpty
00615          if (!HFitInterface::AdjustError(fitOpt,errorY) ) continue; 
00616          dv.Add( gx[i], gy[i], errorY );
00617 
00618 #ifdef DEBUG
00619          std::cout << "Point " << i << "  " << gx[i] <<  "  " << gy[i]  << "  " << errorY << std::endl; 
00620 #endif
00621 
00622 
00623       }
00624       else { // case use error in x or asym errors 
00625          double errorX = 0; 
00626          if (fitOpt.fCoordErrors)  
00627             // shoulkd take combined average (sqrt(0.5(e1^2+e2^2))  or math average ? 
00628             // gr->GetErrorX(i) returns combined average
00629             // use math average for same behaviour as before 
00630             errorX =  std::max( 0.5 * ( gr->GetErrorXlow(i) + gr->GetErrorXhigh(i) ) , 0. ) ;
00631          
00632 
00633          // adjust error in y according to option 
00634          double errorY = std::max(gr->GetErrorY(i), 0.); 
00635          HFitInterface::AdjustError(fitOpt, errorY); 
00636 
00637          // skip points with totla error = 0
00638          if ( errorX <=0 && errorY <= 0 ) continue; 
00639          
00640          if (type == BinData::kAsymError)   { 
00641             // asymmetric errors 
00642             dv.Add( gx[i], gy[i], errorX, gr->GetErrorYlow(i), gr->GetErrorYhigh(i) );            
00643          }
00644          else {             
00645             // case symmetric Y errors
00646             dv.Add( gx[i], gy[i], errorX, errorY );
00647          }
00648       }
00649                         
00650    }    
00651 
00652 #ifdef DEBUG
00653    std::cout << "TGraphFitInterface::FillData Graph FitData size is " << dv.Size() << std::endl;
00654 #endif
00655   
00656 }
00657 
00658 void FillData(SparseData & dv, const TH1 * h1, TF1 * /*func*/) 
00659 {
00660    const int dim = h1->GetDimension();
00661    std::vector<double> min(dim);
00662    std::vector<double> max(dim);
00663    
00664    const TArray *array(dynamic_cast<const TArray*>(h1));
00665    assert(array && "THIS SHOULD NOT HAPPEN!");
00666    for ( int i = 0; i < array->GetSize(); ++i ) {
00667 //       printf("i: %d; OF: %d; UF: %d; C: %f\n"
00668 //              , i
00669 //              , h1->IsBinOverflow(i) , h1->IsBinUnderflow(i)
00670 //              , h1->GetBinContent(i));
00671       if ( !( h1->IsBinOverflow(i) || h1->IsBinUnderflow(i) )
00672            && h1->GetBinContent(i))
00673       {
00674          int x,y,z;
00675          h1->GetBinXYZ(i, x, y, z);
00676          
00677 //          cout << "FILLDATA: h1(" << i << ")"
00678 //               << "[" << h1->GetXaxis()->GetBinLowEdge(x) << "-" << h1->GetXaxis()->GetBinUpEdge(x) << "]";
00679 //          if ( dim >= 2 )
00680 //             cout   << "[" << h1->GetYaxis()->GetBinLowEdge(y) << "-" << h1->GetYaxis()->GetBinUpEdge(y) << "]";
00681 //          if ( dim >= 3 )
00682 //             cout   << "[" << h1->GetZaxis()->GetBinLowEdge(z) << "-" << h1->GetZaxis()->GetBinUpEdge(z) << "]";
00683 
00684 //          cout << h1->GetBinContent(i) << endl;
00685          
00686          min[0] = h1->GetXaxis()->GetBinLowEdge(x);
00687          max[0] = h1->GetXaxis()->GetBinUpEdge(x);
00688          if ( dim >= 2 )
00689          {
00690             min[1] = h1->GetYaxis()->GetBinLowEdge(y);
00691             max[1] = h1->GetYaxis()->GetBinUpEdge(y);
00692          } 
00693          if ( dim >= 3 ) {
00694             min[2] = h1->GetZaxis()->GetBinLowEdge(z);
00695             max[2] = h1->GetZaxis()->GetBinUpEdge(z);
00696          }
00697 
00698          dv.Add(min, max, h1->GetBinContent(i), h1->GetBinError(i));
00699       }
00700    }
00701 }
00702 
00703 void FillData(SparseData & dv, const THnSparse * h1, TF1 * /*func*/) 
00704 {
00705    const int dim = h1->GetNdimensions();
00706    std::vector<double> min(dim);
00707    std::vector<double> max(dim);
00708    std::vector<Int_t>  coord(dim);
00709 
00710    ULong64_t nEntries = h1->GetNbins();
00711    for ( ULong64_t i = 0; i < nEntries; i++ )
00712    {
00713       double value = h1->GetBinContent( i, &coord[0] );
00714       if ( !value ) continue;
00715 
00716 //       cout << "FILLDATA(SparseData): h1(" << i << ")";
00717 
00718       // Exclude underflows and oveflows! (defect behaviour with the TH1*)
00719       bool insertBox = true;
00720       for ( int j = 0; j < dim && insertBox; ++j )
00721       {
00722          TAxis* axis = h1->GetAxis(j);
00723          if ( ( axis->GetBinLowEdge(coord[j]) < axis->GetXmin() ) ||
00724               ( axis->GetBinUpEdge(coord[j])  > axis->GetXmax() ) ) {
00725             insertBox = false;
00726          }
00727          min[j] = h1->GetAxis(j)->GetBinLowEdge(coord[j]);
00728          max[j] = h1->GetAxis(j)->GetBinUpEdge(coord[j]);
00729       }
00730       if ( !insertBox ) { 
00731 //          cout << "NOT INSERTED!"<< endl; 
00732          continue; 
00733       }
00734 
00735 //       for ( int j = 0; j < dim; ++j )
00736 //       {
00737 //          cout << "[" << h1->GetAxis(j)->GetBinLowEdge(coord[j]) 
00738 //               << "-" << h1->GetAxis(j)->GetBinUpEdge(coord[j]) << "]";
00739 //       }
00740 //       cout << h1->GetBinContent(i) << endl;
00741 
00742       dv.Add(min, max, value, h1->GetBinError(i));
00743    }
00744 }
00745 
00746 void FillData(BinData & dv, const THnSparse * s1, TF1 * func) 
00747 {
00748    // Fill the Range of the THnSparse
00749    unsigned int const ndim = s1->GetNdimensions();
00750    std::vector<double> xmin(ndim);
00751    std::vector<double> xmax(ndim);
00752    for ( unsigned int i = 0; i < ndim; ++i ) {
00753       TAxis* axis = s1->GetAxis(i);
00754       xmin[i] = axis->GetXmin();
00755       xmax[i] = axis->GetXmax();
00756    }
00757 
00758    // Put default options, needed for the likelihood fitting of sparse
00759    // data.
00760    ROOT::Fit::DataOptions& dopt = dv.Opt();
00761    dopt.fUseEmpty = true;
00762    // when using sparse data need to set option bin volume
00763    //if (!dopt.fIntegral) dopt.fBinVolume = true; 
00764    dopt.fBinVolume = true;
00765 
00766    // Get the sparse data
00767    ROOT::Fit::SparseData d(ndim, &xmin[0], &xmax[0]);
00768    ROOT::Fit::FillData(d, s1, func);
00769 
00770 //    cout << "FillData(BinData & dv, const THnSparse * s1, TF1 * func) (1)" << endl;
00771 
00772    // Create the bin data from the sparse data
00773    d.GetBinDataIntegral(dv);
00774 
00775 }
00776 
00777 void FillData ( BinData  & dv, const TGraph * gr,  TF1 * func ) {  
00778    //  fill the data vector from a TGraph. Pass also the TF1 function which is 
00779    // needed in case to exclude points rejected by the function
00780    assert(gr != 0); 
00781 
00782    // get fit option 
00783    DataOptions & fitOpt = dv.Opt();
00784 
00785    BinData::ErrorType type = GetDataType(gr,fitOpt); 
00786    // adjust option according to type
00787    fitOpt.fErrors1 = (type == BinData::kNoError);
00788    // set this if we want to have error=1 for points with zero errors (by default they are skipped)
00789    // fitOpt.fUseEmpty = true;
00790    fitOpt.fCoordErrors = (type ==  BinData::kCoordError);
00791    fitOpt.fAsymErrors = (type ==  BinData::kAsymError);
00792 
00793 
00794    // if sata are filled already check if there are consistent - otherwise do nothing
00795    if (dv.Size() > 0 && dv.NDim() == 1 ) { 
00796       // check if size is correct otherwise flag an errors 
00797       if (dv.PointSize() == 2 && type != BinData::kNoError ) {
00798          Error("FillData","Inconsistent TGraph with previous data set- skip all graph data"); 
00799          return;
00800       }
00801       if (dv.PointSize() == 3 && type != BinData::kValueError ) {
00802          Error("FillData","Inconsistent TGraph with previous data set- skip all graph data"); 
00803          return;
00804       }
00805       if (dv.PointSize() == 4 && type != BinData::kCoordError ) {
00806          Error("FillData","Inconsistent TGraph with previous data set- skip all graph data"); 
00807          return;
00808       }
00809    } 
00810 
00811    DoFillData(dv, gr, type, func); 
00812 
00813 }
00814 
00815 void FillData ( BinData  & dv, const TMultiGraph * mg, TF1 * func ) {  
00816    //  fill the data vector from a TMultiGraph. Pass also the TF1 function which is 
00817    // needed in case to exclude points rejected by the function
00818    assert(mg != 0);
00819 
00820    TList * grList = mg->GetListOfGraphs(); 
00821    assert(grList != 0);
00822 
00823 #ifdef DEBUG
00824 //   grList->Print();
00825    TIter itr(grList, kIterBackward);
00826    TObject *obj;
00827    std::cout << "multi-graph list of graps: " << std::endl;
00828    while ((obj = itr())) {
00829       std::cout << obj->IsA()->GetName() << std::endl; 
00830    }
00831 
00832 #endif
00833 
00834    // get fit option 
00835    DataOptions & fitOpt = dv.Opt();
00836 
00837    // loop on the graphs to get the data type (use maximum)
00838    TIter next(grList);   
00839    
00840    BinData::ErrorType type = BinData::kNoError; 
00841    TGraph *gr = 0;
00842    while ((gr = (TGraph*) next())) {
00843       BinData::ErrorType t = GetDataType(gr,fitOpt); 
00844       if (t > type ) type = t; 
00845    }
00846    // adjust option according to type
00847    fitOpt.fErrors1 = (type == BinData::kNoError);
00848    fitOpt.fCoordErrors = (type ==  BinData::kCoordError);
00849    fitOpt.fAsymErrors = (type ==  BinData::kAsymError);
00850 
00851 
00852 #ifdef DEBUG
00853    std::cout << "Fitting MultiGraph of type  " << type << std::endl; 
00854 #endif
00855 
00856    // fill the data now
00857    next = grList; 
00858    while ((gr = (TGraph*) next())) {
00859       DoFillData( dv, gr, type, func); 
00860    }
00861 
00862 #ifdef DEBUG
00863    std::cout << "TGraphFitInterface::FillData MultiGraph FitData size is " << dv.Size() << std::endl;
00864 #endif
00865  
00866 }
00867 
00868 void FillData ( BinData  & dv, const TGraph2D * gr, TF1 * func ) {  
00869    //  fill the data vector from a TGraph2D. Pass also the TF1 function which is 
00870    // needed in case to exclude points rejected by the function
00871    // in case of a pure TGraph 
00872    assert(gr != 0); 
00873 
00874    // get fit option 
00875    DataOptions & fitOpt = dv.Opt();
00876    BinData::ErrorType type = GetDataType(gr,fitOpt); 
00877    // adjust option according to type
00878    fitOpt.fErrors1 = (type == BinData::kNoError);
00879    fitOpt.fCoordErrors = (type ==  BinData::kCoordError);
00880    fitOpt.fAsymErrors = false; // a TGraph2D with asymmetric errors does not exist
00881    
00882    int  nPoints = gr->GetN();
00883    double *gx = gr->GetX();
00884    double *gy = gr->GetY();
00885    double *gz = gr->GetZ();
00886    
00887    // if all errors are zero set option of using errors to 1
00888    if ( gr->GetEZ() == 0) fitOpt.fErrors1 = true;
00889    
00890    double x[2]; 
00891    double ex[2]; 
00892 
00893    // look at data  range
00894    const DataRange & range = dv.Range(); 
00895    bool useRangeX = ( range.Size(0) > 0);
00896    bool useRangeY = ( range.Size(1) > 0);
00897    double xmin = 0; 
00898    double xmax = 0; 
00899    double ymin = 0; 
00900    double ymax = 0; 
00901    range.GetRange(xmin,xmax,ymin,ymax); 
00902 
00903    dv.Initialize(nPoints,2, type); 
00904    
00905    for ( int i = 0; i < nPoints; ++i) { 
00906       
00907       x[0] = gx[i];
00908       x[1] = gy[i];
00909 
00910       //if (fitOpt.fUseRange && HFitInterface::IsPointOutOfRange(func, x) ) continue;
00911       if (useRangeX && (  x[0] < xmin || x[0] > xmax) ) continue;   
00912       if (useRangeY && (  x[1] < ymin || x[1] > ymax) ) continue;   
00913 
00914       // need to evaluate function to know about rejected points
00915       // hugly but no other solutions
00916       if (func) { 
00917          func->RejectPoint(false);
00918          (*func)( x ); // evaluate using stored function parameters 
00919          if (func->RejectedPoint() ) continue; 
00920       }
00921 
00922 
00923       if (type == BinData::kNoError) {   
00924          dv.Add( x, gz[i] ); 
00925          continue; 
00926       }
00927 
00928       double errorZ = gr->GetErrorZ(i); 
00929       if (!HFitInterface::AdjustError(fitOpt,errorZ) ) continue; 
00930       
00931       if (type == BinData::kValueError)  { 
00932          dv.Add( x, gz[i], errorZ );      
00933       }
00934       else if (type == BinData::kCoordError) { // case use error in coordinates (x and y) 
00935          ex[0] = std::max(gr->GetErrorX(i), 0.);
00936          ex[1] = std::max(gr->GetErrorY(i), 0.);
00937          dv.Add( x, gz[i], ex, errorZ );      
00938       }         
00939       else 
00940          assert(0); // should not go here
00941 
00942 #ifdef DEBUG
00943          std::cout << "Point " << i << "  " << gx[i] <<  "  " << gy[i]  << "  " << errorZ << std::endl; 
00944 #endif
00945 
00946    }
00947 
00948 #ifdef DEBUG
00949    std::cout << "THFitInterface::FillData Graph2D FitData size is " << dv.Size() << std::endl;
00950 #endif
00951 
00952 }
00953 
00954 
00955 // confidence intervals
00956 bool GetConfidenceIntervals(const TH1 * h1, const ROOT::Fit::FitResult  & result, TGraphErrors * gr, double cl ) { 
00957    if (h1->GetDimension() != 1) { 
00958       Error("GetConfidenceIntervals","Invalid object used for storing confidence intervals"); 
00959       return false; 
00960    }
00961    // fill fit data sets with points to estimate cl. 
00962    BinData d;
00963    FillData(d,h1,0);
00964    gr->Set(d.NPoints() );
00965    double * ci = gr->GetEY(); // make CL values error of the graph
00966    result.GetConfidenceIntervals(d,ci,cl);
00967    // put function value as abscissa of the graph
00968    for (unsigned int ipoint = 0; ipoint < d.NPoints(); ++ipoint) { 
00969       const double * x = d.Coords(ipoint);
00970       const ROOT::Math::IParamMultiFunction * func = result.FittedFunction();
00971       gr->SetPoint(ipoint, x[0], (*func)(x) );
00972    }
00973    return true;
00974 }
00975 
00976 
00977 } // end namespace Fit
00978 
00979 } // end namespace ROOT
00980 

Generated on Tue Jul 5 14:24:15 2011 for ROOT_528-00b_version by  doxygen 1.5.1