| 14 |
|
|
| 15 |
#include "Fit/FitConfig.h" |
#include "Fit/FitConfig.h" |
| 16 |
|
|
| 17 |
|
#include "Fit/BinData.h" |
| 18 |
|
|
| 19 |
#include "Math/Minimizer.h" |
#include "Math/Minimizer.h" |
| 20 |
|
|
| 21 |
#include "Math/IParamFunction.h" |
#include "Math/IParamFunction.h" |
| 22 |
|
#include "Math/OneDimFunctionAdapter.h" |
| 23 |
|
|
| 24 |
#include "Math/DistFunc.h" |
#include "Math/DistFunc.h" |
| 25 |
|
|
| 26 |
|
#include "TMath.h" |
| 27 |
|
#include "Math/RichardsonDerivator.h" |
| 28 |
|
#include "Math/Error.h" |
| 29 |
|
|
| 30 |
#include <cassert> |
#include <cassert> |
| 31 |
#include <cmath> |
#include <cmath> |
| 32 |
|
#include <iostream> |
| 33 |
|
#include <iomanip> |
| 34 |
|
|
| 35 |
namespace ROOT { |
namespace ROOT { |
| 36 |
|
|
| 38 |
|
|
| 39 |
|
|
| 40 |
FitResult::FitResult() : |
FitResult::FitResult() : |
| 41 |
fValid(false), fNormalized(false), fVal(0), fEdm(0), fChi2(0), fNdf(0), fNCalls(0), fDataSize(0), fFitFunc(0) |
fValid(false), fNormalized(false), fNFree(0), fNdf(0), fNCalls(0), |
| 42 |
|
fStatus(-1), fVal(0), fEdm(0), fChi2(0), fFitFunc(0) |
| 43 |
{ |
{ |
| 44 |
// Default constructor implementation. |
// Default constructor implementation. |
| 45 |
} |
} |
| 46 |
|
|
| 47 |
FitResult::FitResult(ROOT::Math::Minimizer & min, const FitConfig & fconfig, const IModelFunction & func, bool isValid, unsigned int sizeOfData, const ROOT::Math::IMultiGenFunction * chi2func, bool minosErr, unsigned int ncalls ) : |
FitResult::FitResult(ROOT::Math::Minimizer & min, const FitConfig & fconfig, IModelFunction & func, bool isValid, unsigned int sizeOfData, const ROOT::Math::IMultiGenFunction * chi2func, bool minosErr, unsigned int ncalls ) : |
| 48 |
fValid(isValid), |
fValid(isValid), |
| 49 |
fNormalized(false), |
fNormalized(false), |
| 50 |
|
fNFree(min.NFree() ), |
| 51 |
|
fNCalls(min.NCalls()), |
| 52 |
|
fStatus(min.Status() ), |
| 53 |
fVal (min.MinValue()), |
fVal (min.MinValue()), |
| 54 |
fEdm (min.Edm()), |
fEdm (min.Edm()), |
| 55 |
fNCalls(min.NCalls()), |
fFitFunc(&func), |
| 56 |
fParams(std::vector<double>(min.X(), min.X() + min.NDim() ) ), |
fParams(std::vector<double>(min.X(), min.X() + min.NDim() ) ) |
|
fFitFunc(&func) |
|
| 57 |
{ |
{ |
| 58 |
// Constructor from a minimizer, fill the data |
// Constructor from a minimizer, fill the data. ModelFunction is passed as non const |
| 59 |
|
// since it will be managed by the FitResult |
| 60 |
|
|
| 61 |
if (sizeOfData > 0) fNdf = sizeOfData - min.NFree(); |
if (sizeOfData > 0) fNdf = sizeOfData - min.NFree(); |
| 62 |
|
|
| 63 |
|
// set right parameters in function (in case minimizer did not do before) |
| 64 |
|
// do also when fit is not valid |
| 65 |
|
fFitFunc->SetParameters(&fParams.front()); |
| 66 |
|
|
| 67 |
if (min.Errors() != 0) |
if (min.Errors() != 0) |
| 68 |
fErrors = std::vector<double>(min.Errors(), min.Errors() + min.NDim() ) ; |
fErrors = std::vector<double>(min.Errors(), min.Errors() + min.NDim() ) ; |
| 69 |
|
|
| 70 |
|
// check for fixed or limited parameters |
| 71 |
|
for (unsigned int ipar = 0; ipar < fParams.size(); ++ipar) { |
| 72 |
|
const ParameterSettings & par = fconfig.ParSettings(ipar); |
| 73 |
|
if (par.IsFixed() ) fFixedParams.push_back(ipar); |
| 74 |
|
if (par.IsBound() ) fBoundParams.push_back(ipar); |
| 75 |
|
} |
| 76 |
|
|
| 77 |
if (chi2func == 0) |
if (chi2func == 0) |
| 78 |
fChi2 = fVal; |
fChi2 = fVal; |
| 79 |
else { |
else { |
| 89 |
// // fill error matrix |
// // fill error matrix |
| 90 |
// cov matrix rank |
// cov matrix rank |
| 91 |
if (fValid) { |
if (fValid) { |
| 92 |
|
|
| 93 |
unsigned int r = n * ( n + 1 )/2; |
unsigned int r = n * ( n + 1 )/2; |
| 94 |
fCovMatrix.reserve(r); |
fCovMatrix.reserve(r); |
| 95 |
for (unsigned int i = 0; i < n; ++i) |
for (unsigned int i = 0; i < n; ++i) |
| 97 |
fCovMatrix.push_back(min.CovMatrix(i,j) ); |
fCovMatrix.push_back(min.CovMatrix(i,j) ); |
| 98 |
|
|
| 99 |
assert (fCovMatrix.size() == r ); |
assert (fCovMatrix.size() == r ); |
| 100 |
} |
|
| 101 |
|
// normalize errors if requested in configuration |
| 102 |
|
if (fconfig.NormalizeErrors() ) NormalizeErrors(); |
| 103 |
|
|
| 104 |
// minos errors |
// minos errors |
| 105 |
if (minosErr) { |
if (minosErr) { |
| 112 |
} |
} |
| 113 |
} |
} |
| 114 |
|
|
| 115 |
|
// globalCC |
| 116 |
|
fGlobalCC.reserve(n); |
| 117 |
|
for (unsigned int i = 0; i < n; ++i) { |
| 118 |
|
double globcc = min.GlobalCC(i); |
| 119 |
|
if (globcc < 0) break; // it is not supported by that minimizer |
| 120 |
|
fGlobalCC.push_back(globcc); |
| 121 |
|
} |
| 122 |
|
|
| 123 |
|
} |
| 124 |
|
|
| 125 |
fMinimType = fconfig.MinimizerType(); |
fMinimType = fconfig.MinimizerType(); |
| 126 |
|
|
| 127 |
|
// append algorithm name for minimizer that support it |
| 128 |
|
if ( (fMinimType.find("Fumili") == std::string::npos) && |
| 129 |
|
(fMinimType.find("GSLMultiFit") == std::string::npos) |
| 130 |
|
) { |
| 131 |
if (fconfig.MinimizerAlgoType() != "") fMinimType += " / " + fconfig.MinimizerAlgoType(); |
if (fconfig.MinimizerAlgoType() != "") fMinimType += " / " + fconfig.MinimizerAlgoType(); |
| 132 |
} |
} |
| 133 |
|
|
| 134 |
|
} |
| 135 |
|
|
| 136 |
|
FitResult::FitResult(const FitResult &rhs) { |
| 137 |
|
// Implementation of copy constructor |
| 138 |
|
(*this) = rhs; |
| 139 |
|
} |
| 140 |
|
|
| 141 |
|
FitResult & FitResult::operator = (const FitResult &rhs) { |
| 142 |
|
// Implementation of assignment operator. |
| 143 |
|
if (this == &rhs) return *this; // time saving self-test |
| 144 |
|
|
| 145 |
|
// Manages the fitted function |
| 146 |
|
if (fFitFunc) delete fFitFunc; |
| 147 |
|
fFitFunc = 0; |
| 148 |
|
if (rhs.fFitFunc != 0 ) { |
| 149 |
|
fFitFunc = dynamic_cast<IModelFunction *>( (rhs.fFitFunc)->Clone() ); |
| 150 |
|
assert(fFitFunc != 0); |
| 151 |
|
} |
| 152 |
|
|
| 153 |
|
// copy all other data members |
| 154 |
|
fValid = rhs.fValid; |
| 155 |
|
fNormalized = rhs.fNormalized; |
| 156 |
|
fNFree = rhs.fNFree; |
| 157 |
|
fNdf = rhs.fNdf; |
| 158 |
|
fNCalls = rhs.fNCalls; |
| 159 |
|
fStatus = rhs.fStatus; |
| 160 |
|
fVal = rhs.fVal; |
| 161 |
|
fEdm = rhs.fEdm; |
| 162 |
|
fChi2 = rhs.fChi2; |
| 163 |
|
|
| 164 |
|
fFixedParams = rhs.fFixedParams; |
| 165 |
|
fBoundParams = rhs.fBoundParams; |
| 166 |
|
fParams = rhs.fParams; |
| 167 |
|
fErrors = rhs.fErrors; |
| 168 |
|
fCovMatrix = rhs.fCovMatrix; |
| 169 |
|
fGlobalCC = rhs.fGlobalCC; |
| 170 |
|
fMinosErrors = rhs.fMinosErrors; |
| 171 |
|
|
| 172 |
|
fMinimType = rhs.fMinimType; |
| 173 |
|
|
| 174 |
|
return *this; |
| 175 |
|
|
| 176 |
|
} |
| 177 |
|
|
| 178 |
|
|
| 179 |
void FitResult::NormalizeErrors() { |
void FitResult::NormalizeErrors() { |
| 180 |
// normalize errors and covariance matrix according to chi2 value |
// normalize errors and covariance matrix according to chi2 value |
| 181 |
if (fNdf == 0 || fChi2 <= 0) return; |
if (fNdf == 0 || fChi2 <= 0) return; |
| 203 |
return -1; // case name is not found |
return -1; // case name is not found |
| 204 |
} |
} |
| 205 |
|
|
| 206 |
|
bool FitResult::IsParameterBound(unsigned int ipar) const { |
| 207 |
|
for (unsigned int i = 0; i < fBoundParams.size() ; ++i) |
| 208 |
|
if ( fBoundParams[i] == ipar) return true; |
| 209 |
|
return false; |
| 210 |
|
} |
| 211 |
|
|
| 212 |
|
bool FitResult::IsParameterFixed(unsigned int ipar) const { |
| 213 |
|
for (unsigned int i = 0; i < fFixedParams.size() ; ++i) |
| 214 |
|
if ( fFixedParams[i] == ipar) return true; |
| 215 |
|
return false; |
| 216 |
|
} |
| 217 |
|
|
| 218 |
void FitResult::Print(std::ostream & os, bool doCovMatrix) const { |
void FitResult::Print(std::ostream & os, bool doCovMatrix) const { |
| 219 |
// print the result in the given stream |
// print the result in the given stream |
| 220 |
|
// need to add minos errors , globalCC, etc.. |
| 221 |
if (!fValid) { |
if (!fValid) { |
| 222 |
os << "\n****************************************\n"; |
os << "\n****************************************\n"; |
| 223 |
os << " Invalid FitResult "; |
os << " Invalid FitResult "; |
| 226 |
} |
} |
| 227 |
|
|
| 228 |
os << "\n****************************************\n"; |
os << "\n****************************************\n"; |
| 229 |
os << " FitResult \n\n"; |
//os << " FitResult \n\n"; |
| 230 |
os << "Minimizer is " << fMinimType << std::endl; |
os << "Minimizer is " << fMinimType << std::endl; |
| 231 |
unsigned int npar = fParams.size(); |
unsigned int npar = fParams.size(); |
| 232 |
os << "Chi2/Likelihood =\t" << fVal << std::endl; |
const unsigned int nw = 25; |
| 233 |
if (fVal != fChi2) |
if (fVal != fChi2) |
| 234 |
os << "Chi2 =\t" << fChi2<< std::endl; |
os << std::setw(nw) << std::left << "Likelihood" << " =\t" << fVal << std::endl; |
| 235 |
os << "NDf =\t" << fNdf << std::endl; |
os << std::setw(nw) << std::left << "Chi2" << " =\t" << fChi2<< std::endl; |
| 236 |
os << "Edm =\t" << fEdm << std::endl; |
os << std::setw(nw) << std::left << "NDf" << " =\t" << fNdf << std::endl; |
| 237 |
os << "NCalls =\t" << fNCalls << std::endl; |
if (fMinimType.find("Linear") == std::string::npos) { // no need to print this for linear fits |
| 238 |
|
os << std::setw(nw) << std::left << "Edm" << " =\t" << fEdm << std::endl; |
| 239 |
|
os << std::setw(nw) << std::left << "NCalls" << " =\t" << fNCalls << std::endl; |
| 240 |
|
} |
| 241 |
assert(fFitFunc != 0); |
assert(fFitFunc != 0); |
| 242 |
for (unsigned int i = 0; i < npar; ++i) { |
for (unsigned int i = 0; i < npar; ++i) { |
| 243 |
os << fFitFunc->ParameterName(i) << "\t\t =\t" << fParams[i] << " \t+/-\t" << fErrors[i] << std::endl; |
os << std::setw(nw) << std::left << fFitFunc->ParameterName(i) << " =\t" << fParams[i]; |
| 244 |
|
if (IsParameterFixed(i) ) |
| 245 |
|
os << " \t(fixed)"; |
| 246 |
|
else { |
| 247 |
|
if (fErrors.size() != 0) |
| 248 |
|
os << " \t+/-\t" << fErrors[i]; |
| 249 |
|
if (IsParameterBound(i) ) |
| 250 |
|
os << " \t (limited)"; |
| 251 |
|
} |
| 252 |
|
os << std::endl; |
| 253 |
} |
} |
| 254 |
|
|
| 255 |
if (doCovMatrix) PrintCovMatrix(os); |
if (doCovMatrix) PrintCovMatrix(os); |
| 258 |
void FitResult::PrintCovMatrix(std::ostream &os) const { |
void FitResult::PrintCovMatrix(std::ostream &os) const { |
| 259 |
// print the covariance and correlation matrix |
// print the covariance and correlation matrix |
| 260 |
if (!fValid) return; |
if (!fValid) return; |
| 261 |
os << "\n****************************************\n"; |
if (fCovMatrix.size() == 0) return; |
| 262 |
|
// os << "****************************************\n"; |
| 263 |
os << "\n Covariance Matrix \n\n"; |
os << "\n Covariance Matrix \n\n"; |
| 264 |
unsigned int npar = fParams.size(); |
unsigned int npar = fParams.size(); |
| 265 |
const int kPrec = 8; |
const int kPrec = 5; |
| 266 |
const int kWidth = 12; |
const int kWidth = 10; |
| 267 |
|
const int parw = 12; |
| 268 |
|
const int matw = kWidth+4; |
| 269 |
|
os << std::setw(parw) << " " << "\t"; |
| 270 |
|
for (unsigned int i = 0; i < npar; ++i) |
| 271 |
|
if (!IsParameterFixed(i) ) { |
| 272 |
|
os << std::setw(matw) << fFitFunc->ParameterName(i) ; |
| 273 |
|
} |
| 274 |
|
os << std::endl; |
| 275 |
for (unsigned int i = 0; i < npar; ++i) { |
for (unsigned int i = 0; i < npar; ++i) { |
| 276 |
for (unsigned int j = 0; j <= i; ++j) { |
if (!IsParameterFixed(i) ) { |
| 277 |
os.precision(kPrec); os.width(kWidth); os << CovMatrix(i,j); |
os << std::setw(parw) << std::left << fFitFunc->ParameterName(i) << "\t"; |
| 278 |
|
for (unsigned int j = 0; j < npar; ++j) { |
| 279 |
|
if (!IsParameterFixed(j) ) { |
| 280 |
|
os.precision(kPrec); os.width(kWidth); os << std::setw(matw) << CovMatrix(i,j); |
| 281 |
|
} |
| 282 |
} |
} |
| 283 |
os << std::endl; |
os << std::endl; |
| 284 |
} |
} |
| 285 |
|
} |
| 286 |
|
// os << "****************************************\n"; |
| 287 |
os << "\n Correlation Matrix \n\n"; |
os << "\n Correlation Matrix \n\n"; |
| 288 |
|
os << std::setw(parw) << " " << "\t"; |
| 289 |
|
for (unsigned int i = 0; i < npar; ++i) |
| 290 |
|
if (!IsParameterFixed(i) ) { |
| 291 |
|
os << std::setw(matw) << fFitFunc->ParameterName(i) ; |
| 292 |
|
} |
| 293 |
|
os << std::endl; |
| 294 |
for (unsigned int i = 0; i < npar; ++i) { |
for (unsigned int i = 0; i < npar; ++i) { |
| 295 |
for (unsigned int j = 0; j <= i; ++j) { |
if (!IsParameterFixed(i) ) { |
| 296 |
os.precision(kPrec); os.width(kWidth); os << Correlation(i,j); |
os << std::setw(parw) << std::left << fFitFunc->ParameterName(i) << "\t"; |
| 297 |
|
for (unsigned int j = 0; j < npar; ++j) { |
| 298 |
|
if (!IsParameterFixed(j) ) { |
| 299 |
|
os.precision(kPrec); os.width(kWidth); os << std::setw(matw) << Correlation(i,j); |
| 300 |
|
} |
| 301 |
} |
} |
| 302 |
os << std::endl; |
os << std::endl; |
| 303 |
} |
} |
| 304 |
} |
} |
| 305 |
|
} |
| 306 |
|
|
| 307 |
|
void FitResult::GetConfidenceIntervals(unsigned int n, unsigned int stride1, unsigned int stride2, const double * x, double * ci, double cl ) const { |
| 308 |
|
// stride1 stride in coordinate stride2 stride in dimension space |
| 309 |
|
// i.e. i-th point in k-dimension is x[ stride1 * i + stride2 * k] |
| 310 |
|
// compute the confidence interval of the fit on the given data points |
| 311 |
|
// the dimension of the data points must match the dimension of the fit function |
| 312 |
|
// confidence intervals are returned in array ci |
| 313 |
|
|
| 314 |
|
// use student quantile |
| 315 |
|
//double t = - TMath::StudentQuantile((1.-cl)/2, f->GetNDF()); |
| 316 |
|
double t = TMath::StudentQuantile(0.5 + cl/2, fNdf); |
| 317 |
|
double chidf = TMath::Sqrt(fChi2/fNdf); |
| 318 |
|
|
| 319 |
|
if (!fFitFunc) { |
| 320 |
|
MATH_ERROR_MSG("FitResult::GetConfidenceIntervals","cannot compute Confidence Intervals without fitter function"); |
| 321 |
|
return; |
| 322 |
|
} |
| 323 |
|
|
| 324 |
|
unsigned int ndim = fFitFunc->NDim(); |
| 325 |
|
unsigned int npar = fFitFunc->NPar(); |
| 326 |
|
|
| 327 |
|
std::vector<double> xpoint(ndim); |
| 328 |
|
std::vector<double> grad(npar); |
| 329 |
|
std::vector<double> vsum(npar); |
| 330 |
|
|
| 331 |
|
// loop on the points |
| 332 |
|
for (unsigned int ipoint = 0; ipoint < n; ++ipoint) { |
| 333 |
|
|
| 334 |
|
for (unsigned int kdim = 0; kdim < ndim; ++kdim) { |
| 335 |
|
unsigned int i = ipoint * stride1 + kdim * stride2; |
| 336 |
|
assert(i < ndim*n); |
| 337 |
|
xpoint[kdim] = x[ipoint * stride1 + kdim * stride2]; |
| 338 |
|
} |
| 339 |
|
|
| 340 |
|
// calculate gradient of fitted function w.r.t the parameters |
| 341 |
|
|
| 342 |
|
// check first if fFitFunction provides parameter gradient or not |
| 343 |
|
|
| 344 |
|
// does not provide gradient |
| 345 |
|
// t.b.d : skip calculation for fixed parameters |
| 346 |
|
ROOT::Math::RichardsonDerivator d; |
| 347 |
|
for (unsigned int ipar = 0; ipar < npar; ++ipar) { |
| 348 |
|
ROOT::Math::OneDimParamFunctionAdapter<const ROOT::Math::IParamMultiFunction &> fadapter(*fFitFunc,&xpoint.front(),&fParams.front(),ipar); |
| 349 |
|
d.SetFunction(fadapter); |
| 350 |
|
grad[ipar] = d(fParams[ipar] ); // evaluate df/dp |
| 351 |
|
} |
| 352 |
|
|
| 353 |
|
// multiply covariance matrix with gradient |
| 354 |
|
vsum.assign(npar,0.0); |
| 355 |
|
for (unsigned int ipar = 0; ipar < npar; ++ipar) { |
| 356 |
|
for (unsigned int jpar = 0; jpar < npar; ++jpar) { |
| 357 |
|
vsum[ipar] += CovMatrix(ipar,jpar) * grad[jpar]; |
| 358 |
|
} |
| 359 |
|
} |
| 360 |
|
// multiply gradient by vsum |
| 361 |
|
double r2 = 0; |
| 362 |
|
for (unsigned int ipar = 0; ipar < npar; ++ipar) { |
| 363 |
|
r2 += grad[ipar] * vsum[ipar]; |
| 364 |
|
} |
| 365 |
|
double r = std::sqrt(r2); |
| 366 |
|
ci[ipoint] = r * t * chidf; |
| 367 |
|
} |
| 368 |
|
} |
| 369 |
|
|
| 370 |
|
void FitResult::GetConfidenceIntervals(const BinData & data, double * ci, double cl ) const { |
| 371 |
|
// implement confidence intervals from a given bin data sets |
| 372 |
|
// currently copy the data from Bindata. |
| 373 |
|
// could implement otherwise directly |
| 374 |
|
unsigned int ndim = data.NDim(); |
| 375 |
|
unsigned int np = data.NPoints(); |
| 376 |
|
std::vector<double> xdata( ndim * np ); |
| 377 |
|
for (unsigned int i = 0; i < np ; ++i) { |
| 378 |
|
const double * x = data.Coords(i); |
| 379 |
|
std::vector<double>::iterator itr = xdata.begin()+ ndim * i; |
| 380 |
|
std::copy(x,x+ndim,itr); |
| 381 |
|
} |
| 382 |
|
// points are arraned as x0,y0,z0, ....xN,yN,zN (stride1=ndim, stride2=1) |
| 383 |
|
GetConfidenceIntervals(np,ndim,1,&xdata.front(),ci,cl); |
| 384 |
|
} |
| 385 |
|
|
| 386 |
} // end namespace Fit |
} // end namespace Fit |
| 387 |
|
|