43 const int gInitialResultStatus = -99;
45 FitResult::FitResult() :
46 fValid(false), fNormalized(false), fNFree(0), fNdf(0), fNCalls(0),
47 fStatus(-1), fCovStatus(0), fVal(0), fEdm(-1), fChi2(-1)
52 FitResult::FitResult(
const FitConfig & fconfig) :
58 fStatus(gInitialResultStatus),
64 fParams(std::vector<double>( fconfig.NPar() ) ),
65 fErrors(std::vector<double>( fconfig.NPar() ) ),
66 fParNames(std::vector<std::string> ( fconfig.NPar() ) )
73 fMinimType = fconfig.MinimizerType();
75 if ( (fMinimType.find(
"Fumili") == std::string::npos) &&
76 (fMinimType.find(
"GSLMultiFit") == std::string::npos)
78 if (fconfig.MinimizerAlgoType() !=
"") fMinimType +=
" / " + fconfig.MinimizerAlgoType();
82 unsigned int npar = fconfig.NPar();
83 for (
unsigned int i = 0; i < npar; ++i ) {
84 const ParameterSettings & par = fconfig.ParSettings(i);
85 fParams[i] = par.Value();
86 fErrors[i] = par.StepSize();
87 fParNames[i] = par.Name();
88 if (par.IsFixed() ) fFixedParams[i] =
true;
91 double lower = (par.HasLowerLimit()) ? par.LowerLimit() : - std::numeric_limits<double>::infinity() ;
92 double upper = (par.HasUpperLimit()) ? par.UpperLimit() : std::numeric_limits<double>::infinity() ;
93 fBoundParams[i] = fParamBounds.size();
94 fParamBounds.push_back(std::make_pair(lower,upper));
97 std::cout <<
"create fit result from config - nfree " << fNFree << std::endl;
100 void FitResult::FillResult(
const std::shared_ptr<ROOT::Math::Minimizer> & min,
const FitConfig & fconfig,
const std::shared_ptr<IModelFunction> & func,
101 bool isValid,
unsigned int sizeOfData,
bool binnedFit,
const ROOT::Math::IMultiGenFunction * chi2func,
unsigned int ncalls )
109 fNFree= min->NFree();
110 fNCalls = min->NCalls();
111 fStatus = min->Status();
112 fCovStatus= min->CovMatrixStatus();
113 fVal = min->MinValue();
119 fMinimType = fconfig.MinimizerName();
122 if (fNCalls == 0) fNCalls = ncalls;
124 const unsigned int npar = min->NDim();
125 if (npar == 0)
return;
128 fParams = std::vector<double>(min->X(), min->X() + npar);
131 fParams.resize(npar);
132 for (
unsigned int i = 0; i < npar; ++i ) {
133 fParams[i] = ( fconfig.ParSettings(i).Value() );
137 if (sizeOfData > min->NFree() ) fNdf = sizeOfData - min->NFree();
146 fFitFunc->SetParameters(&fParams.front());
150 fParNames.reserve( npar );
151 for (
unsigned int i = 0; i < npar; ++i ) {
152 fParNames.push_back( fconfig.ParSettings(i).Name() );
158 unsigned int nfree = 0;
159 for (
unsigned int ipar = 0; ipar < npar; ++ipar) {
160 const ParameterSettings & par = fconfig.ParSettings(ipar);
161 if (par.IsFixed() ) fFixedParams[ipar] =
true;
163 if (par.IsBound() ) {
164 double lower = (par.HasLowerLimit()) ? par.LowerLimit() : - std::numeric_limits<double>::infinity() ;
165 double upper = (par.HasUpperLimit()) ? par.UpperLimit() : std::numeric_limits<double>::infinity() ;
166 fBoundParams[ipar] = fParamBounds.size();
167 fParamBounds.push_back(std::make_pair(lower,upper));
171 if (nfree != fNFree ) {
172 MATH_ERROR_MSG(
"FitResult",
"FitConfiguration and Minimizer result are not consistent");
173 std::cout <<
"Number of free parameters from FitConfig = " << nfree << std::endl;
174 std::cout <<
"Number of free parameters from Minimizer = " << fNFree << std::endl;
184 fChi2 = (*chi2func)(&fParams[0]);
190 if (min->Errors() != 0) {
192 fErrors = std::vector<double>(min->Errors(), min->Errors() + npar ) ;
194 if (fCovStatus != 0) {
195 unsigned int r = npar * ( npar + 1 )/2;
196 fCovMatrix.reserve(r);
197 for (
unsigned int i = 0; i < npar; ++i)
198 for (
unsigned int j = 0; j <= i; ++j)
199 fCovMatrix.push_back(min->CovMatrix(i,j) );
203 if (fValid && fconfig.MinosErrors()) {
204 const std::vector<unsigned int> & ipars = fconfig.MinosParams();
205 unsigned int n = (ipars.size() > 0) ? ipars.size() : npar;
206 for (
unsigned int i = 0; i < n; ++i) {
208 unsigned int index = (ipars.size() > 0) ? ipars[i] : i;
209 bool ret = min->GetMinosError(index, elow, eup);
210 if (ret) SetMinosError(index, elow, eup);
215 fGlobalCC.reserve(npar);
216 for (
unsigned int i = 0; i < npar; ++i) {
217 double globcc = min->GlobalCC(i);
218 if (globcc < 0)
break;
219 fGlobalCC.push_back(globcc);
226 FitResult::~FitResult() {
231 FitResult::FitResult(
const FitResult &rhs) :
238 FitResult & FitResult::operator = (
const FitResult &rhs) {
240 if (
this == &rhs)
return *
this;
252 fNormalized = rhs.fNormalized;
255 fNCalls = rhs.fNCalls;
256 fCovStatus = rhs.fCovStatus;
257 fStatus = rhs.fStatus;
261 fMinimizer = rhs.fMinimizer;
262 fObjFunc = rhs.fObjFunc;
263 fFitFunc = rhs.fFitFunc;
265 fFixedParams = rhs.fFixedParams;
266 fBoundParams = rhs.fBoundParams;
267 fParamBounds = rhs.fParamBounds;
268 fParams = rhs.fParams;
269 fErrors = rhs.fErrors;
270 fCovMatrix = rhs.fCovMatrix;
271 fGlobalCC = rhs.fGlobalCC;
272 fMinosErrors = rhs.fMinosErrors;
274 fMinimType = rhs.fMinimType;
275 fParNames = rhs.fParNames;
281 bool FitResult::Update(
const std::shared_ptr<ROOT::Math::Minimizer> & min,
const ROOT::Fit::FitConfig & fconfig,
bool isValid,
unsigned int ncalls) {
288 fMinimType = fconfig.MinimizerName();
290 const unsigned int npar = fParams.size();
291 if (min->NDim() != npar ) {
292 MATH_ERROR_MSG(
"FitResult::Update",
"Wrong minimizer status ");
295 if (min->X() == 0 ) {
296 MATH_ERROR_MSG(
"FitResult::Update",
"Invalid minimizer status ");
300 if (fNFree != min->NFree() ) {
301 MATH_ERROR_MSG(
"FitResult::Update",
"Configuration has changed ");
307 fVal = min->MinValue();
309 fStatus = min->Status();
310 fCovStatus = min->CovMatrixStatus();
313 if ( min->NCalls() > 0) fNCalls = min->NCalls();
314 else fNCalls = ncalls;
317 std::copy(min->X(), min->X() + npar, fParams.begin());
321 if (fFitFunc) fFitFunc->SetParameters(&fParams.front());
323 if (min->Errors() != 0) {
325 if (fErrors.size() != npar) fErrors.resize(npar);
327 std::copy(min->Errors(), min->Errors() + npar, fErrors.begin() ) ;
329 if (fCovStatus != 0) {
332 unsigned int r = npar * ( npar + 1 )/2;
333 if (fCovMatrix.size() != r) fCovMatrix.resize(r);
335 for (
unsigned int i = 0; i < npar; ++i) {
336 for (
unsigned int j = 0; j <= i; ++j)
337 fCovMatrix[l++] = min->CovMatrix(i,j);
342 if (fGlobalCC.size() != npar) fGlobalCC.resize(npar);
343 for (
unsigned int i = 0; i < npar; ++i) {
344 double globcc = min->GlobalCC(i);
349 fGlobalCC[i] = globcc;
356 void FitResult::NormalizeErrors() {
358 if (fNdf == 0 || fChi2 <= 0)
return;
359 double s2 = fChi2/fNdf;
360 double s = std::sqrt(fChi2/fNdf);
361 for (
unsigned int i = 0; i < fErrors.size() ; ++i)
363 for (
unsigned int i = 0; i < fCovMatrix.size() ; ++i)
370 double FitResult::Prob()
const {
372 return ROOT::Math::chisquared_cdf_c(fChi2, static_cast<double>(fNdf) );
375 bool FitResult::HasMinosError(
unsigned int i)
const {
377 std::map<unsigned int, std::pair<double,double> >::const_iterator itr = fMinosErrors.find(i);
378 return (itr != fMinosErrors.end() );
382 double FitResult::LowerError(
unsigned int i)
const {
385 std::map<unsigned int, std::pair<double,double> >::const_iterator itr = fMinosErrors.find(i);
386 return ( itr != fMinosErrors.end() ) ? itr->second.first : Error(i) ;
389 double FitResult::UpperError(
unsigned int i)
const {
392 std::map<unsigned int, std::pair<double,double> >::const_iterator itr = fMinosErrors.find(i);
393 return ( itr != fMinosErrors.end() ) ? itr->second.second : Error(i) ;
396 void FitResult::SetMinosError(
unsigned int i,
double elow,
double eup) {
398 fMinosErrors[i] = std::make_pair(elow,eup);
401 int FitResult::Index(
const std::string & name)
const {
403 if (! fFitFunc)
return -1;
404 unsigned int npar = fParams.size();
405 for (
unsigned int i = 0; i < npar; ++i)
406 if ( fFitFunc->ParameterName(i) == name)
return i;
411 bool FitResult::IsParameterBound(
unsigned int ipar)
const {
412 return fBoundParams.find(ipar) != fBoundParams.end();
415 bool FitResult::IsParameterFixed(
unsigned int ipar)
const {
416 return fFixedParams.find(ipar) != fFixedParams.end();
419 bool FitResult::ParameterBounds(
unsigned int ipar,
double & lower,
double & upper)
const {
420 std::map<unsigned int, unsigned int>::const_iterator itr = fBoundParams.find(ipar);
421 if (itr == fBoundParams.end() ) {
422 lower = -std::numeric_limits<Double_t>::infinity();
423 upper = std::numeric_limits<Double_t>::infinity();
426 assert(itr->second < fParamBounds.size() );
427 lower = fParamBounds[itr->second].first;
428 upper = fParamBounds[itr->second].second;
432 std::string FitResult::ParName(
unsigned int ipar)
const {
434 if (fFitFunc)
return fFitFunc->ParameterName(ipar);
435 else if (ipar < fParNames.size() )
return fParNames[ipar];
436 return "param_" + ROOT::Math::Util::ToString(ipar);
439 void FitResult::Print(std::ostream & os,
bool doCovMatrix)
const {
442 unsigned int npar = fParams.size();
444 os <<
"<Empty FitResult>\n";
447 os <<
"\n****************************************\n";
449 if (fStatus != gInitialResultStatus) {
450 os <<
" Invalid FitResult";
451 os <<
" (status = " << fStatus <<
" )";
454 os <<
" FitResult before fitting";
456 os <<
"\n****************************************\n";
460 os <<
"Minimizer is " << fMinimType << std::endl;
461 const unsigned int nw = 25;
462 const unsigned int nn = 12;
463 const std::ios_base::fmtflags prFmt = os.setf(std::ios::left,std::ios::adjustfield);
465 if (fVal != fChi2 || fChi2 < 0)
466 os << std::left << std::setw(nw) <<
"MinFCN" <<
" = " << std::right << std::setw(nn) << fVal << std::endl;
468 os << std::left << std::setw(nw) <<
"Chi2" <<
" = " << std::right << std::setw(nn) << fChi2 << std::endl;
469 os << std::left << std::setw(nw) <<
"NDf" <<
" = " << std::right << std::setw(nn) << fNdf << std::endl;
470 if (fMinimType.find(
"Linear") == std::string::npos) {
471 if (fEdm >=0) os << std::left << std::setw(nw) <<
"Edm" <<
" = " << std::right << std::setw(nn) << fEdm << std::endl;
472 os << std::left << std::setw(nw) <<
"NCalls" <<
" = " << std::right << std::setw(nn) << fNCalls << std::endl;
474 for (
unsigned int i = 0; i < npar; ++i) {
475 os << std::left << std::setw(nw) << GetParameterName(i);
476 os <<
" = " << std::right << std::setw(nn) << fParams[i];
477 if (IsParameterFixed(i) )
478 os << std::setw(9) <<
" " << std::setw(nn) <<
" " <<
" \t (fixed)";
480 if (fErrors.size() != 0)
481 os <<
" +/- " << std::left << std::setw(nn) << fErrors[i] << std::right;
482 if (IsParameterBound(i) )
483 os <<
" \t (limited)";
489 if (prFmt != os.flags() ) os.setf(prFmt, std::ios::adjustfield);
491 if (doCovMatrix) PrintCovMatrix(os);
494 void FitResult::PrintCovMatrix(std::ostream &os)
const {
497 if (fCovMatrix.size() == 0)
return;
499 os <<
"\nCovariance Matrix:\n\n";
500 unsigned int npar = fParams.size();
502 const int kWidth = 8;
504 const int matw = kWidth+4;
507 int prevPrec = os.precision(kPrec);
508 const std::ios_base::fmtflags prevFmt = os.flags();
510 os << std::setw(parw) <<
" " <<
"\t";
511 for (
unsigned int i = 0; i < npar; ++i) {
512 if (!IsParameterFixed(i) ) {
513 os << std::right << std::setw(matw) << GetParameterName(i) ;
517 for (
unsigned int i = 0; i < npar; ++i) {
518 if (!IsParameterFixed(i) ) {
519 os << std::left << std::setw(parw) << GetParameterName(i) <<
"\t";
520 for (
unsigned int j = 0; j < npar; ++j) {
521 if (!IsParameterFixed(j) ) {
522 os.precision(kPrec); os.width(kWidth); os << std::right << std::setw(matw) << CovMatrix(i,j);
529 os <<
"\nCorrelation Matrix:\n\n";
530 os << std::setw(parw) <<
" " <<
"\t";
531 for (
unsigned int i = 0; i < npar; ++i) {
532 if (!IsParameterFixed(i) ) {
533 os << std::right << std::setw(matw) << GetParameterName(i) ;
537 for (
unsigned int i = 0; i < npar; ++i) {
538 if (!IsParameterFixed(i) ) {
539 os << std::left << std::setw(parw) << std::left << GetParameterName(i) <<
"\t";
540 for (
unsigned int j = 0; j < npar; ++j) {
541 if (!IsParameterFixed(j) ) {
542 os.precision(kPrec); os.width(kWidth); os << std::right << std::setw(matw) << Correlation(i,j);
549 os.setf(prevFmt, std::ios::adjustfield);
550 os.precision(prevPrec);
553 void FitResult::GetConfidenceIntervals(
unsigned int n,
unsigned int stride1,
unsigned int stride2,
const double * x,
double * ci,
double cl,
bool norm )
const {
562 MATH_ERROR_MSG(
"FitResult::GetConfidenceIntervals",
"Cannot compute Confidence Intervals without fit model function");
568 double corrFactor = 1;
569 if (fChi2 <= 0 || fNdf == 0) norm =
false;
571 corrFactor = TMath::StudentQuantile(0.5 + cl/2, fNdf) * std::sqrt( fChi2/fNdf );
574 corrFactor = ROOT::Math::chisquared_quantile(cl, 1);
578 unsigned int ndim = fFitFunc->NDim();
579 unsigned int npar = fFitFunc->NPar();
581 std::vector<double> xpoint(ndim);
582 std::vector<double> grad(npar);
583 std::vector<double> vsum(npar);
586 for (
unsigned int ipoint = 0; ipoint < n; ++ipoint) {
588 for (
unsigned int kdim = 0; kdim < ndim; ++kdim) {
589 unsigned int i = ipoint * stride1 + kdim * stride2;
595 ROOT::Math::RichardsonDerivator d;
596 for (
unsigned int ipar = 0; ipar < npar; ++ipar) {
597 if (!IsParameterFixed(ipar)) {
598 ROOT::Math::OneDimParamFunctionAdapter<const ROOT::Math::IParamMultiFunction &> fadapter(*fFitFunc,&xpoint.front(),&fParams.front(),ipar);
599 d.SetFunction(fadapter);
602 if ( fErrors[ipar] > 0 )
603 d.SetStepSize( std::max( fErrors[ipar]*1.E-5, 1.E-15) );
605 d.SetStepSize( std::min(std::max(fParams[ipar]*1.E-5, 1.E-15), 0.0001 ) );
607 grad[ipar] = d(fParams[ipar] );
614 vsum.assign(npar,0.0);
615 for (
unsigned int ipar = 0; ipar < npar; ++ipar) {
616 for (
unsigned int jpar = 0; jpar < npar; ++jpar) {
617 vsum[ipar] += CovMatrix(ipar,jpar) * grad[jpar];
622 for (
unsigned int ipar = 0; ipar < npar; ++ipar) {
623 r2 += grad[ipar] * vsum[ipar];
625 double r = std::sqrt(r2);
626 ci[ipoint] = r * corrFactor;
630 void FitResult::GetConfidenceIntervals(
const BinData & data,
double * ci,
double cl,
bool norm )
const {
634 unsigned int ndim = data.NDim();
635 unsigned int np = data.NPoints();
636 std::vector<double> xdata( ndim * np );
637 for (
unsigned int i = 0; i < np ; ++i) {
638 const double * x = data.Coords(i);
639 std::vector<double>::iterator itr = xdata.begin()+ ndim * i;
640 std::copy(x,x+ndim,itr);
643 GetConfidenceIntervals(np,ndim,1,&xdata.front(),ci,cl,norm);
646 std::vector<double> FitResult::GetConfidenceIntervals(
double cl,
bool norm )
const {
649 const BinData * data = FittedBinData();
650 std::vector<double> result;
652 result.resize(data->NPoints() );
653 GetConfidenceIntervals(*data, result.data(), cl, norm);
656 MATH_ERROR_MSG(
"FitResult::GetConfidenceIntervals",
"Cannot compute Confidence Intervals without the fit bin data");
678 const BinData * FitResult::FittedBinData()
const {
679 return dynamic_cast<const BinData*
> ( fFitData.get() );
686 bool FitResult::Scan(
unsigned int ipar,
unsigned int &npoints,
double *pntsx,
double *pntsy,
double xmin,
double xmax)
688 if (!pntsx || !pntsy || !npoints)
692 MATH_ERROR_MSG(
"FitResult::Scan",
"Minimizer is not available - cannot Scan");
696 return fMinimizer->Scan(ipar, npoints, pntsx, pntsy, xmin, xmax);
707 bool FitResult::Contour(
unsigned int ipar,
unsigned int jpar,
unsigned int &npoints,
double *pntsx,
double *pntsy,
double confLevel)
709 if (!pntsx || !pntsy || !npoints)
713 MATH_ERROR_MSG(
"FitResult::Contour",
"Minimizer is not available - cannot produce Contour");
718 double upScale = fMinimizer->ErrorDef();
720 double upVal = TMath::ChisquareQuantile(confLevel, 2);
723 fMinimizer->SetErrorDef(upScale * upVal);
725 bool ret = fMinimizer->Contour(ipar, jpar, npoints, pntsx, pntsy);
728 fMinimizer->SetErrorDef(upScale);