FitResult.cxx

Go to the documentation of this file.
00001 // @(#)root/mathcore:$Id: FitResult.cxx 38241 2011-02-28 11:05:04Z moneta $
00002 // Author: L. Moneta Wed Aug 30 11:05:34 2006
00003 
00004 /**********************************************************************
00005  *                                                                    *
00006  * Copyright (c) 2006  LCG ROOT Math Team, CERN/PH-SFT                *
00007  *                                                                    *
00008  *                                                                    *
00009  **********************************************************************/
00010 
00011 // Implementation file for class FitResult
00012 
00013 #include "Fit/FitResult.h"
00014 
00015 #include "Fit/FitConfig.h"
00016 
00017 #include "Fit/BinData.h"
00018 
00019 #include "Math/Minimizer.h"
00020 
00021 #include "Math/IParamFunction.h"
00022 #include "Math/OneDimFunctionAdapter.h"
00023 
00024 #include "Math/ProbFuncMathCore.h"
00025 #include "Math/QuantFuncMathCore.h"
00026 
00027 #include "TMath.h"  
00028 #include "Math/RichardsonDerivator.h"
00029 #include "Math/Error.h"
00030 
00031 #include <cassert>
00032 #include <cmath>
00033 #include <iostream>
00034 #include <iomanip>
00035 
00036 namespace ROOT { 
00037 
00038    namespace Fit { 
00039 
00040 
00041 FitResult::FitResult() : 
00042    fValid(false), fNormalized(false), fNFree(0), fNdf(0), fNCalls(0), 
00043    fStatus(-1), fCovStatus(0), fVal(0), fEdm(0), fChi2(-1), fFitFunc(0)
00044 {
00045    // Default constructor implementation.
00046 }
00047 
00048 FitResult::FitResult(ROOT::Math::Minimizer & min, const FitConfig & fconfig, const IModelFunction * func,  bool isValid,  unsigned int sizeOfData, bool binnedFit, const  ROOT::Math::IMultiGenFunction * chi2func, unsigned int ncalls ) : 
00049    fValid(isValid),
00050    fNormalized(false),
00051    fNFree(min.NFree() ),
00052    fNdf(0),
00053    fNCalls(min.NCalls()),
00054    fStatus(min.Status() ),
00055    fCovStatus(min.CovMatrixStatus() ),
00056    fVal (min.MinValue()),  
00057    fEdm (min.Edm()), 
00058    fChi2(-1),
00059    fFitFunc(0), 
00060    fParams(std::vector<double>( min.NDim() ) )
00061 {
00062 
00063    // set minimizer type 
00064    fMinimType = fconfig.MinimizerType();
00065 
00066    // append algorithm name for minimizer that support it  
00067    if ( (fMinimType.find("Fumili") == std::string::npos) &&
00068         (fMinimType.find("GSLMultiFit") == std::string::npos) 
00069       ) { 
00070       if (fconfig.MinimizerAlgoType() != "") fMinimType += " / " + fconfig.MinimizerAlgoType(); 
00071    }
00072 
00073    // replace ncalls if minimizer does not support it (they are taken then from the FitMethodFunction)
00074    if (fNCalls == 0) fNCalls = ncalls;
00075 
00076    // Constructor from a minimizer, fill the data. ModelFunction  is passed as non const 
00077    // since it will be managed by the FitResult
00078    const unsigned int npar = fParams.size();
00079    if (npar == 0) return;
00080 
00081    if (min.X() ) std::copy(min.X(), min.X() + npar, fParams.begin());
00082    else { 
00083       // case minimizer does not provide minimum values (it failed) take from configuration
00084       for (unsigned int i = 0; i < npar; ++i ) {
00085          fParams[i] = ( fconfig.ParSettings(i).Value() );
00086       }
00087    }
00088 
00089    if (sizeOfData >  min.NFree() ) fNdf = sizeOfData - min.NFree(); 
00090 
00091 
00092    // set right parameters in function (in case minimizer did not do before)
00093    // do also when fit is not valid
00094    if (func ) { 
00095       fFitFunc = dynamic_cast<IModelFunction *>( func->Clone() ); 
00096       assert(fFitFunc);
00097       fFitFunc->SetParameters(&fParams.front());
00098    }
00099    else { 
00100       // when no fFitFunc is present take parameters from FitConfig
00101       fParNames.reserve( npar );
00102       for (unsigned int i = 0; i < npar; ++i ) {
00103          fParNames.push_back( fconfig.ParSettings(i).Name() );
00104       }
00105    }
00106 
00107 
00108    // check for fixed or limited parameters
00109    for (unsigned int ipar = 0; ipar < npar; ++ipar) { 
00110       const ParameterSettings & par = fconfig.ParSettings(ipar); 
00111       if (par.IsFixed() ) fFixedParams.push_back(ipar); 
00112       if (par.IsBound() ) fBoundParams.push_back(ipar); 
00113    } 
00114 
00115    if (binnedFit) { 
00116       if (chi2func == 0) 
00117          fChi2 = fVal;
00118       else { 
00119          // compute chi2 equivalent for likelihood fits
00120          fChi2 = (*chi2func)(&fParams[0]); 
00121       }
00122    }
00123       
00124    // fill error matrix 
00125    // if minimizer provides error provides also error matrix
00126    if (min.Errors() != 0) {
00127 
00128       fErrors = std::vector<double>(min.Errors(), min.Errors() + npar ) ; 
00129 
00130       if (fCovStatus != 0) { 
00131          unsigned int r = npar * (  npar + 1 )/2;  
00132          fCovMatrix.reserve(r);
00133          for (unsigned int i = 0; i < npar; ++i) 
00134             for (unsigned int j = 0; j <= i; ++j)
00135                fCovMatrix.push_back(min.CovMatrix(i,j) );
00136       }
00137 
00138       // minos errors 
00139       if (fValid && fconfig.MinosErrors()) { 
00140          const std::vector<unsigned int> & ipars = fconfig.MinosParams(); 
00141          unsigned int n = (ipars.size() > 0) ? ipars.size() : npar; 
00142          for (unsigned int i = 0; i < n; ++i) {
00143           double elow, eup;
00144           unsigned int index = (ipars.size() > 0) ? ipars[i] : i; 
00145           bool ret = min.GetMinosError(index, elow, eup);
00146           if (ret) SetMinosError(index, elow, eup); 
00147          }
00148       }
00149 
00150       // globalCC
00151       fGlobalCC.reserve(npar);
00152       for (unsigned int i = 0; i < npar; ++i) { 
00153          double globcc = min.GlobalCC(i); 
00154          if (globcc < 0) break; // it is not supported by that minimizer
00155          fGlobalCC.push_back(globcc); 
00156       }
00157       
00158    }
00159 
00160 }
00161 
00162 FitResult::~FitResult() { 
00163    // destructor. FitResult manages the fit Function pointer
00164    if (fFitFunc) delete fFitFunc;   
00165 }
00166 
00167 FitResult::FitResult(const FitResult &rhs) : 
00168    fFitFunc(0) 
00169 { 
00170    // Implementation of copy constructor
00171    (*this) = rhs; 
00172 }
00173 
00174 FitResult & FitResult::operator = (const FitResult &rhs) { 
00175    // Implementation of assignment operator.
00176    if (this == &rhs) return *this;  // time saving self-test
00177 
00178    // Manages the fitted function 
00179    if (fFitFunc) delete fFitFunc;
00180    fFitFunc = 0; 
00181    if (rhs.fFitFunc != 0 ) {
00182       fFitFunc = dynamic_cast<IModelFunction *>( (rhs.fFitFunc)->Clone() ); 
00183       assert(fFitFunc != 0); 
00184    }
00185 
00186    // copy all other data members 
00187    fValid = rhs.fValid; 
00188    fNormalized = rhs.fNormalized;
00189    fNFree = rhs.fNFree; 
00190    fNdf = rhs.fNdf; 
00191    fNCalls = rhs.fNCalls; 
00192    fCovStatus = rhs.fCovStatus;
00193    fStatus = rhs.fStatus; 
00194    fVal = rhs.fVal;  
00195    fEdm = rhs.fEdm; 
00196    fChi2 = rhs.fChi2;
00197 
00198    fFixedParams = rhs.fFixedParams;
00199    fBoundParams = rhs.fBoundParams;
00200    fParams = rhs.fParams; 
00201    fErrors = rhs.fErrors; 
00202    fCovMatrix = rhs.fCovMatrix; 
00203    fGlobalCC = rhs.fGlobalCC;
00204    fMinosErrors = rhs.fMinosErrors; 
00205 
00206    fMinimType = rhs.fMinimType;
00207    fParNames = rhs.fParNames; 
00208    
00209    return *this; 
00210 
00211 }  
00212 
00213 bool FitResult::Update(const ROOT::Math::Minimizer & min, bool isValid, unsigned int ncalls) { 
00214    // update fit result with new status from minimizer 
00215    // nclass if is not zero is added to the total function calls
00216 
00217    const unsigned int npar = fParams.size();
00218    if (min.NDim() != npar ) { 
00219       MATH_ERROR_MSG("FitResult::Update","Wrong minimizer status ");
00220       return false; 
00221    }
00222    if (min.X() == 0 ) { 
00223       MATH_ERROR_MSG("FitResult::Update","Invalid minimizer status ");
00224       return false; 
00225    }
00226    //fNFree = min.NFree(); 
00227    if (fNFree != min.NFree() ) { 
00228       MATH_ERROR_MSG("FitResult::Update","Configuration has changed  ");
00229       return false; 
00230    }
00231 
00232    fValid = isValid; 
00233    // update minimum value
00234    fVal = min.MinValue(); 
00235    fEdm = min.Edm(); 
00236    fStatus = min.Status(); 
00237    fCovStatus = min.CovMatrixStatus();
00238 
00239    // update number of function calls
00240    if ( min.NCalls() > 0)   fNCalls = min.NCalls();
00241    else fNCalls = ncalls;
00242 
00243    // copy parameter value and errors 
00244    std::copy(min.X(), min.X() + npar, fParams.begin());
00245 
00246 
00247    // set parameters  in fit model function 
00248    if (fFitFunc) fFitFunc->SetParameters(&fParams.front());
00249    
00250    if (min.Errors() != 0)  { 
00251    
00252       std::copy(min.Errors(), min.Errors() + npar, fErrors.begin() ) ; 
00253 
00254       if (fCovStatus != 0) { 
00255 
00256          // update error matrix
00257          unsigned int r = npar * (  npar + 1 )/2;  
00258          if (fCovMatrix.size() != r) fCovMatrix.resize(r);
00259          unsigned int l = 0; 
00260          for (unsigned int i = 0; i < npar; ++i) {
00261             for (unsigned int j = 0; j <= i; ++j)  
00262                fCovMatrix[l++] = min.CovMatrix(i,j);
00263          }
00264       }
00265                
00266       // update global CC       
00267       if (fGlobalCC.size() != npar) fGlobalCC.resize(npar);
00268       for (unsigned int i = 0; i < npar; ++i) { 
00269          double globcc = min.GlobalCC(i); 
00270          if (globcc < 0) { 
00271             fGlobalCC.clear(); 
00272             break; // it is not supported by that minimizer
00273          }
00274          fGlobalCC[i] = globcc; 
00275       }
00276     
00277    }
00278    return true;
00279 }
00280  
00281 void FitResult::NormalizeErrors() { 
00282    // normalize errors and covariance matrix according to chi2 value
00283    if (fNdf == 0 || fChi2 <= 0) return; 
00284    double s2 = fChi2/fNdf; 
00285    double s = std::sqrt(fChi2/fNdf); 
00286    for (unsigned int i = 0; i < fErrors.size() ; ++i) 
00287       fErrors[i] *= s; 
00288    for (unsigned int i = 0; i < fCovMatrix.size() ; ++i) 
00289       fCovMatrix[i] *= s2; 
00290 
00291    fNormalized = true; 
00292 } 
00293 
00294 
00295 double FitResult::Prob() const { 
00296    // fit probability
00297    return ROOT::Math::chisquared_cdf_c(fChi2, static_cast<double>(fNdf) ); 
00298 }
00299 
00300 double FitResult::LowerError(unsigned int i) const { 
00301    // return lower Minos error for parameter i 
00302    //  return the parabolic error if Minos error has not been calculated for the parameter i 
00303    std::map<unsigned int, std::pair<double,double> >::const_iterator itr = fMinosErrors.find(i); 
00304    return ( itr != fMinosErrors.end() ) ? itr->second.first : Error(i) ;  
00305 }
00306 
00307 double FitResult::UpperError(unsigned int i) const { 
00308    // return upper Minos error for parameter i
00309    //  return the parabolic error if Minos error has not been calculated for the parameter i 
00310    std::map<unsigned int, std::pair<double,double> >::const_iterator itr = fMinosErrors.find(i); 
00311    return ( itr != fMinosErrors.end() ) ? itr->second.second : Error(i) ;  
00312 }
00313 
00314 void FitResult::SetMinosError(unsigned int i, double elow, double eup) { 
00315    // set the Minos error for parameter i 
00316    fMinosErrors[i] = std::make_pair(elow,eup);
00317 }
00318 
00319 int FitResult::Index(const std::string & name) const { 
00320    // find index for given parameter name
00321    if (! fFitFunc) return -1;
00322    unsigned int npar = fParams.size(); 
00323    for (unsigned int i = 0; i < npar; ++i) 
00324       if ( fFitFunc->ParameterName(i) == name) return i; 
00325    
00326    return -1; // case name is not found
00327 } 
00328 
00329 bool FitResult::IsParameterBound(unsigned int ipar) const { 
00330    for (unsigned int i = 0; i < fBoundParams.size() ; ++i) 
00331       if ( fBoundParams[i] == ipar) return true; 
00332    return false; 
00333 }
00334 
00335 bool FitResult::IsParameterFixed(unsigned int ipar) const { 
00336    for (unsigned int i = 0; i < fFixedParams.size() ; ++i) 
00337       if ( fFixedParams[i] == ipar) return true; 
00338    return false; 
00339 }
00340 
00341 std::string FitResult::ParName(unsigned int ipar) const {
00342    // return parameter name
00343    if (fFitFunc) return fFitFunc->ParameterName(ipar); 
00344    else if (ipar < fParNames.size() ) return fParNames[ipar];
00345    return "param_" + ROOT::Math::Util::ToString(ipar);
00346 }
00347 
00348 void FitResult::Print(std::ostream & os, bool doCovMatrix) const { 
00349    // print the result in the given stream 
00350    // need to add also minos errors , globalCC, etc..
00351    unsigned int npar = fParams.size(); 
00352    if (npar == 0) { 
00353       std::cout << "Error: Empty  FitResult  ! " << std::endl;
00354       return;
00355    }
00356    os << "\n****************************************\n";
00357    if (!fValid) { 
00358       os << "            Invalid FitResult            ";
00359       os << "\n****************************************\n";
00360    }
00361    
00362    //os << "            FitResult                   \n\n";
00363    os << "Minimizer is " << fMinimType << std::endl;
00364    const unsigned int nw = 25; // spacing for text  
00365    const unsigned int nn = 12; // spacing for numbers 
00366    const std::ios_base::fmtflags prFmt = os.setf(std::ios::left,std::ios::adjustfield); // set left alignment
00367 
00368    if (fVal != fChi2 || fChi2 < 0) 
00369       os << std::left << std::setw(nw) << "MinFCN" << " = " << std::right << std::setw(nn) << fVal << std::endl;
00370    if (fChi2 >= 0) 
00371       os << std::left << std::setw(nw) <<  "Chi2"         << " = " << std::right << std::setw(nn) << fChi2 << std::endl;
00372    os << std::left << std::setw(nw) << "NDf"              << " = " << std::right << std::setw(nn) << fNdf << std::endl; 
00373    if (fMinimType.find("Linear") == std::string::npos) {  // no need to print this for linear fits
00374       os << std::left << std::setw(nw) << "Edm"    << " = " << std::right << std::setw(nn) << fEdm << std::endl; 
00375       os << std::left << std::setw(nw) << "NCalls" << " = " << std::right << std::setw(nn) << fNCalls << std::endl; 
00376    }
00377    for (unsigned int i = 0; i < npar; ++i) { 
00378       os << std::left << std::setw(nw) << GetParameterName(i); 
00379       os << " = " << std::right << std::setw(nn) << fParams[i]; 
00380       if (IsParameterFixed(i) ) 
00381          os << std::setw(9) << " "  << std::setw(nn) << " " << " \t (fixed)";
00382       else {
00383          if (fErrors.size() != 0)
00384             os << "   +/-   " << std::left << std::setw(nn) << fErrors[i] << std::right; 
00385          if (IsParameterBound(i) ) 
00386             os << " \t (limited)"; 
00387       }
00388       os << std::endl; 
00389    }
00390 
00391    // restore stremam adjustfield
00392    if (prFmt != os.flags() ) os.setf(prFmt, std::ios::adjustfield);
00393 
00394    if (doCovMatrix) PrintCovMatrix(os); 
00395 }
00396 
00397 void FitResult::PrintCovMatrix(std::ostream &os) const { 
00398    // print the covariance and correlation matrix 
00399    if (!fValid) return;
00400    if (fCovMatrix.size() == 0) return; 
00401 //   os << "****************************************\n";
00402    os << "\nCovariance Matrix:\n\n";
00403    unsigned int npar = fParams.size(); 
00404    const int kPrec = 5; 
00405    const int kWidth = 8; 
00406    const int parw = 12; 
00407    const int matw = kWidth+4;
00408 
00409    // query previous precision and format flags
00410    int prevPrec = os.precision(kPrec);
00411    const std::ios_base::fmtflags prevFmt = os.flags();   
00412 
00413    os << std::setw(parw) << " " << "\t"; 
00414    for (unsigned int i = 0; i < npar; ++i) {
00415       if (!IsParameterFixed(i) ) { 
00416          os << std::right  << std::setw(matw)  << GetParameterName(i) ;
00417       }
00418    }
00419    os << std::endl;   
00420    for (unsigned int i = 0; i < npar; ++i) {
00421       if (!IsParameterFixed(i) ) { 
00422          os << std::left << std::setw(parw) << GetParameterName(i) << "\t";
00423          for (unsigned int j = 0; j < npar; ++j) {
00424             if (!IsParameterFixed(j) ) { 
00425                os.precision(kPrec); os.width(kWidth);  os << std::right << std::setw(matw) << CovMatrix(i,j); 
00426             }
00427          }
00428          os << std::endl;
00429       }
00430    }
00431 //   os << "****************************************\n";
00432    os << "\nCorrelation Matrix:\n\n";
00433    os << std::setw(parw) << " " << "\t"; 
00434    for (unsigned int i = 0; i < npar; ++i) {
00435       if (!IsParameterFixed(i) ) { 
00436          os << std::right << std::setw(matw)  << GetParameterName(i) ;
00437       }
00438    }
00439    os << std::endl;   
00440    for (unsigned int i = 0; i < npar; ++i) {
00441       if (!IsParameterFixed(i) ) { 
00442          os << std::left << std::setw(parw) << std::left << GetParameterName(i) << "\t";
00443          for (unsigned int j = 0; j < npar; ++j) {
00444             if (!IsParameterFixed(j) ) {
00445                os.precision(kPrec); os.width(kWidth);  os << std::right << std::setw(matw) << Correlation(i,j); 
00446             }
00447          }
00448          os << std::endl;
00449       }
00450    }
00451    // restore alignment and precision
00452    os.setf(prevFmt, std::ios::adjustfield);
00453    os.precision(prevPrec);
00454 }
00455 
00456 void FitResult::GetConfidenceIntervals(unsigned int n, unsigned int stride1, unsigned int stride2, const double * x, double * ci, double cl, bool norm ) const {     
00457    // stride1 stride in coordinate  stride2 stride in dimension space
00458    // i.e. i-th point in k-dimension is x[ stride1 * i + stride2 * k]
00459    // compute the confidence interval of the fit on the given data points
00460    // the dimension of the data points must match the dimension of the fit function
00461    // confidence intervals are returned in array ci
00462 
00463    if (!fFitFunc) {
00464       MATH_ERROR_MSG("FitResult::GetConfidenceIntervals","Cannot compute Confidence Intervals without fitter function");
00465       return;
00466    }
00467 
00468    // use student quantile in case of normalized errors 
00469    double corrFactor = 1; 
00470    if (fChi2 <= 0 || fNdf == 0) norm = false;
00471    if (norm) 
00472       corrFactor = TMath::StudentQuantile(0.5 + cl/2, fNdf) * std::sqrt( fChi2/fNdf ); 
00473    else 
00474       // value to go up in chi2 (1: 1 sigma error(CL=0.683) , 4: 2 sigma errors
00475       corrFactor = ROOT::Math::chisquared_quantile(cl, 1);
00476 
00477 
00478 
00479    unsigned int ndim = fFitFunc->NDim(); 
00480    unsigned int npar = fFitFunc->NPar(); 
00481 
00482    std::vector<double> xpoint(ndim); 
00483    std::vector<double> grad(npar); 
00484    std::vector<double> vsum(npar); 
00485 
00486    // loop on the points
00487    for (unsigned int ipoint = 0; ipoint < n; ++ipoint) { 
00488 
00489       for (unsigned int kdim = 0; kdim < ndim; ++kdim) { 
00490          unsigned int i = ipoint * stride1 + kdim * stride2; 
00491          assert(i < ndim*n); 
00492          xpoint[kdim] = x[ipoint * stride1 + kdim * stride2]; 
00493       }
00494 
00495       // calculate gradient of fitted function w.r.t the parameters
00496 
00497       // check first if fFitFunction provides parameter gradient or not 
00498       
00499       // does not provide gradient
00500       // t.b.d : skip calculation for fixed parameters
00501       ROOT::Math::RichardsonDerivator d; 
00502       for (unsigned int ipar = 0; ipar < npar; ++ipar) { 
00503          ROOT::Math::OneDimParamFunctionAdapter<const ROOT::Math::IParamMultiFunction &> fadapter(*fFitFunc,&xpoint.front(),&fParams.front(),ipar);
00504          d.SetFunction(fadapter); 
00505          grad[ipar] = d(fParams[ipar] ); // evaluate df/dp
00506       }
00507 
00508       // multiply covariance matrix with gradient
00509       vsum.assign(npar,0.0);
00510       for (unsigned int ipar = 0; ipar < npar; ++ipar) { 
00511          for (unsigned int jpar = 0; jpar < npar; ++jpar) {
00512              vsum[ipar] += CovMatrix(ipar,jpar) * grad[jpar]; 
00513          }
00514       }
00515       // multiply gradient by vsum
00516       double r2 = 0; 
00517       for (unsigned int ipar = 0; ipar < npar; ++ipar) { 
00518          r2 += grad[ipar] * vsum[ipar]; 
00519       }
00520       double r = std::sqrt(r2); 
00521       ci[ipoint] = r * corrFactor;  
00522    }
00523 }
00524 
00525       void FitResult::GetConfidenceIntervals(const BinData & data, double * ci, double cl, bool norm ) const { 
00526    // implement confidence intervals from a given bin data sets
00527    // currently copy the data from Bindata. 
00528    // could implement otherwise directly
00529    unsigned int ndim = data.NDim(); 
00530    unsigned int np = data.NPoints(); 
00531    std::vector<double> xdata( ndim * np ); 
00532    for (unsigned int i = 0; i < np ; ++i) { 
00533       const double * x = data.Coords(i); 
00534       std::vector<double>::iterator itr = xdata.begin()+ ndim * i;
00535       std::copy(x,x+ndim,itr);
00536    }
00537    // points are arraned as x0,y0,z0, ....xN,yN,zN  (stride1=ndim, stride2=1)
00538    GetConfidenceIntervals(np,ndim,1,&xdata.front(),ci,cl,norm);
00539 }
00540 
00541    } // end namespace Fit
00542 
00543 } // end namespace ROOT
00544 

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