00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
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
00064 fMinimType = fconfig.MinimizerType();
00065
00066
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
00074 if (fNCalls == 0) fNCalls = ncalls;
00075
00076
00077
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
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
00093
00094 if (func ) {
00095 fFitFunc = dynamic_cast<IModelFunction *>( func->Clone() );
00096 assert(fFitFunc);
00097 fFitFunc->SetParameters(&fParams.front());
00098 }
00099 else {
00100
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
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
00120 fChi2 = (*chi2func)(&fParams[0]);
00121 }
00122 }
00123
00124
00125
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
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
00151 fGlobalCC.reserve(npar);
00152 for (unsigned int i = 0; i < npar; ++i) {
00153 double globcc = min.GlobalCC(i);
00154 if (globcc < 0) break;
00155 fGlobalCC.push_back(globcc);
00156 }
00157
00158 }
00159
00160 }
00161
00162 FitResult::~FitResult() {
00163
00164 if (fFitFunc) delete fFitFunc;
00165 }
00166
00167 FitResult::FitResult(const FitResult &rhs) :
00168 fFitFunc(0)
00169 {
00170
00171 (*this) = rhs;
00172 }
00173
00174 FitResult & FitResult::operator = (const FitResult &rhs) {
00175
00176 if (this == &rhs) return *this;
00177
00178
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
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
00215
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
00227 if (fNFree != min.NFree() ) {
00228 MATH_ERROR_MSG("FitResult::Update","Configuration has changed ");
00229 return false;
00230 }
00231
00232 fValid = isValid;
00233
00234 fVal = min.MinValue();
00235 fEdm = min.Edm();
00236 fStatus = min.Status();
00237 fCovStatus = min.CovMatrixStatus();
00238
00239
00240 if ( min.NCalls() > 0) fNCalls = min.NCalls();
00241 else fNCalls = ncalls;
00242
00243
00244 std::copy(min.X(), min.X() + npar, fParams.begin());
00245
00246
00247
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
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
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;
00273 }
00274 fGlobalCC[i] = globcc;
00275 }
00276
00277 }
00278 return true;
00279 }
00280
00281 void FitResult::NormalizeErrors() {
00282
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
00297 return ROOT::Math::chisquared_cdf_c(fChi2, static_cast<double>(fNdf) );
00298 }
00299
00300 double FitResult::LowerError(unsigned int i) const {
00301
00302
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
00309
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
00316 fMinosErrors[i] = std::make_pair(elow,eup);
00317 }
00318
00319 int FitResult::Index(const std::string & name) const {
00320
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;
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
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
00350
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
00363 os << "Minimizer is " << fMinimType << std::endl;
00364 const unsigned int nw = 25;
00365 const unsigned int nn = 12;
00366 const std::ios_base::fmtflags prFmt = os.setf(std::ios::left,std::ios::adjustfield);
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) {
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
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
00399 if (!fValid) return;
00400 if (fCovMatrix.size() == 0) return;
00401
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
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
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
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
00458
00459
00460
00461
00462
00463 if (!fFitFunc) {
00464 MATH_ERROR_MSG("FitResult::GetConfidenceIntervals","Cannot compute Confidence Intervals without fitter function");
00465 return;
00466 }
00467
00468
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
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
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
00496
00497
00498
00499
00500
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] );
00506 }
00507
00508
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
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
00527
00528
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
00538 GetConfidenceIntervals(np,ndim,1,&xdata.front(),ci,cl,norm);
00539 }
00540
00541 }
00542
00543 }
00544