17 #include "analysis/OrcaKinFit/BaseFitObject.h"
18 #include <framework/logging/Logger.h>
28 #include <gsl/gsl_matrix.h>
29 #include <gsl/gsl_linalg.h>
36 namespace OrcaKinFit {
38 BaseFitObject::BaseFitObject(): name(nullptr), par{}, mpar{}, measured{}, fixed{}, globalParNum{}, cov{}, covinv{}, covinvvalid(
45 for (
int ilocal = 0; ilocal < BaseDefs::MAXPAR; ++ilocal) {
46 globalParNum[ilocal] = -1;
47 fixed[ilocal] =
false;
48 for (
int jlocal = 0; jlocal < BaseDefs::MAXPAR; ++jlocal)
49 cov[ilocal][jlocal] = 0;
54 BaseFitObject::BaseFitObject(
const BaseFitObject& rhs)
55 : name(nullptr), par{}, mpar{}, measured{}, fixed{}, globalParNum{}, cov{}, covinv{}, covinvvalid(
false), cachevalid(
false)
57 BaseFitObject::assign(rhs);
60 BaseFitObject& BaseFitObject::operator= (
const BaseFitObject& rhs)
68 BaseFitObject& BaseFitObject::assign(
const BaseFitObject& source)
70 if (&source !=
this) {
73 for (
int i = 0; i < BaseDefs::MAXPAR; ++i) {
74 par[i] = source.par[i];
75 mpar[i] = source.mpar[i];
76 measured[i] = source.measured[i];
77 fixed[i] = source.fixed[i];
78 globalParNum[i] = source.globalParNum[i];
79 for (
int j = 0; j < BaseDefs::MAXPAR; ++j) {
80 cov[i][j] = source.cov[i][j];
81 covinv[i][j] = source.covinv[i][j];
91 BaseFitObject::~BaseFitObject()
96 const double BaseFitObject::eps2 = 0.0001;
98 void BaseFitObject::setName(
const char* name_)
100 if (name_ ==
nullptr)
return;
101 size_t l = strlen(name_);
102 if (name)
delete[] name;
103 name =
new char[l + 1];
107 const char* BaseFitObject::getName()
const
109 return name ? name :
"???";
112 int BaseFitObject::getNMeasured()
const
115 for (
int i = 0; i < getNPar(); ++i)
if (isParamMeasured(i) && !isParamFixed(i)) ++nmeasured;
118 int BaseFitObject::getNUnmeasured()
const
121 for (
int i = 0; i < getNPar(); ++i)
if (!isParamMeasured(i) && !isParamFixed(i)) ++nunmeasrd;
124 int BaseFitObject::getNFree()
const
127 for (
int i = 0; i < getNPar(); ++i)
if (!isParamFixed(i)) ++nfree;
130 int BaseFitObject::getNFixed()
const
133 for (
int i = 0; i < getNPar(); ++i)
if (isParamFixed(i)) ++nfixed;
137 std::ostream& BaseFitObject::printParams(std::ostream& os)
const
140 for (
int i = 0; i < getNPar(); ++i) {
141 if (i > 0) os <<
", ";
142 os <<
" " << getParam(i);
143 if (isParamFixed(i)) os <<
" fix";
145 else if (getError(i) > 0) os <<
" +- " << getError(i);
151 std::ostream& BaseFitObject::printRhoValues(std::ostream& os)
const
154 for (
int i = 0; i < getNPar(); ++i) {
155 for (
int j = 0; j < getNPar(); ++j) {
156 if (i > 0 && j == 0) os <<
",";
157 os <<
" " << getRho(i, j);
160 os <<
"}" << std::endl;
164 std::ostream& BaseFitObject::print1stDerivatives(std::ostream& os)
const
168 for (
int i = 0; i < BaseDefs::nMetaVars[metaSet]; ++i) {
169 for (
int j = 0; j < getNPar(); ++j) {
170 if (i > 0 && j == 0) os <<
",";
171 os <<
" " << getFirstDerivative_Meta_Local(i, j, metaSet);
174 os <<
"#" << std::endl;
178 std::ostream& BaseFitObject::print2ndDerivatives(std::ostream& os)
const
182 for (
int i = 0; i < BaseDefs::nMetaVars[metaSet]; ++i) {
183 if (i > 0) os << std::endl <<
" ";
184 for (
int j = 0; j < getNPar(); ++j) {
185 for (
int k = 0; k < getNPar(); ++k) {
187 os <<
" " << getSecondDerivative_Meta_Local(i, j, k, metaSet);
188 if (k == getNPar() - 1) os <<
",";
192 os <<
"##" << std::endl;
196 bool BaseFitObject::updateParams(
double p[],
int idim)
200 for (
int ilocal = 0; ilocal < getNPar(); ++ilocal) {
201 if (!isParamFixed(ilocal)) {
202 int iglobal = getGlobalParNum(ilocal);
203 assert(iglobal >= 0 && iglobal < idim);
207 bool thisresult = setParam(ilocal, p[iglobal]);
208 result = result || thisresult;
211 p[iglobal] = getParam(ilocal);
217 void BaseFitObject::addToGlobCov(
double* globCov,
int idim)
const
219 for (
int ilocal = 0; ilocal < getNPar(); ++ilocal) {
220 if (!isParamFixed(ilocal) && isParamMeasured(ilocal)) {
221 int iglobal = getGlobalParNum(ilocal);
222 assert(iglobal >= 0 && iglobal < idim);
223 int ioffs = idim * iglobal;
224 for (
int jlocal = 0; jlocal < getNPar(); ++jlocal) {
225 if (!isParamFixed(jlocal) && isParamMeasured(jlocal)) {
226 int jglobal = getGlobalParNum(jlocal);
227 assert(jglobal >= 0 && jglobal < idim);
228 globCov[ioffs + jglobal] += getCov(ilocal, jlocal);
235 bool BaseFitObject::calculateCovInv()
const
242 gsl_matrix* covm = gsl_matrix_alloc(n, n);
243 gsl_matrix_set_identity(covm);
245 for (
int i = 0; i < n; ++i) {
246 if (isParamMeasured(i)) {
247 for (
int j = 0; j < n; ++j) {
248 if (isParamMeasured(j)) {
249 gsl_matrix_set(covm, i, j, cov[i][j]);
254 gsl_error_handler_t*
e = gsl_set_error_handler_off();
255 int result = gsl_linalg_cholesky_decomp(covm);
256 if (result == 0) result = gsl_linalg_cholesky_invert(covm);
257 gsl_set_error_handler(e);
259 for (
int i = 0; i < n; ++i) {
260 for (
int j = 0; j < i; ++j) {
261 covinv[i][j] = covinv[j][i] = gsl_matrix_get(covm, i, j);
263 covinv[i][i] = gsl_matrix_get(covm, i, i);
266 gsl_matrix_free(covm);
267 covinvvalid = (result == 0);
270 B2WARNING(
"ERROR, COULD NOT INVERT COV MATR!");
273 for (
int i = 0; i < n; ++i) {
274 if (isParamMeasured(i)) {
275 for (
int j = 0; j < n; ++j) {
276 if (isParamMeasured(j)) {
277 B2INFO(cov[i][j] <<
" ");
284 for (
int i = 0; i < n; ++i) {
285 if (isParamMeasured(i)) {
286 for (
int j = 0; j < n; ++j) {
287 if (isParamMeasured(j)) {
288 B2INFO(cov[i][j] / sqrt(cov[i][i]*cov[j][j]) <<
" ");
299 bool BaseFitObject::setParam(
int ilocal,
double par_,
300 bool measured_,
bool fixed_)
302 assert(ilocal >= 0 && ilocal < getNPar());
303 if (measured[ilocal] != measured_ || fixed[ilocal] != fixed_) invalidateCache();
304 measured[ilocal] = measured_;
305 fixed[ilocal] = fixed_;
306 return setParam(ilocal, par_);
309 bool BaseFitObject::setParam(
int ilocal,
double par_)
311 if (!isfinite(par_))
return true;
312 assert(ilocal >= 0 && ilocal < getNPar());
313 if (par[ilocal] == par_)
return false;
315 bool result = pow((par_ - par[ilocal]) , 2) > eps2 * cov[ilocal][ilocal];
320 bool BaseFitObject::setMParam(
int ilocal,
double mpar_)
322 if (!isfinite(mpar_))
return false;
323 assert(ilocal >= 0 && ilocal < getNPar());
324 if (mpar[ilocal] == mpar_)
return true;
326 mpar[ilocal] = mpar_;
330 bool BaseFitObject::setError(
int ilocal,
double err_)
332 if (!isfinite(err_))
return false;
333 assert(ilocal >= 0 && ilocal < getNPar());
336 cov[ilocal][ilocal] = err_ * err_;
340 bool BaseFitObject::setCov(
int ilocal,
int jlocal,
double cov_)
342 if (!isfinite(cov_))
return false;
343 assert(ilocal >= 0 && ilocal < getNPar());
344 assert(jlocal >= 0 && jlocal < getNPar());
347 cov[ilocal][jlocal] = cov[jlocal][ilocal] = cov_;
352 bool BaseFitObject::fixParam(
int ilocal,
bool fix)
354 assert(ilocal >= 0 && ilocal < getNPar());
355 return fixed [ilocal] = fix;
358 bool BaseFitObject::setGlobalParNum(
int ilocal,
int iglobal)
360 if (ilocal < 0 || ilocal >= getNPar())
return false;
361 globalParNum[ilocal] = iglobal;
365 int BaseFitObject::getGlobalParNum(
int ilocal)
const
367 if (ilocal < 0 || ilocal >= getNPar())
return -1;
368 return globalParNum[ilocal];
371 double BaseFitObject::getParam(
int ilocal)
const
373 assert(ilocal >= 0 && ilocal < getNPar());
377 double BaseFitObject::getMParam(
int ilocal)
const
379 assert(ilocal >= 0 && ilocal < getNPar());
383 double BaseFitObject::getError(
int ilocal)
const
385 assert(ilocal >= 0 && ilocal < getNPar());
386 return std::sqrt(cov[ilocal][ilocal]);
389 double BaseFitObject::getCov(
int ilocal,
int jlocal)
const
391 assert(ilocal >= 0 && ilocal < getNPar());
392 assert(jlocal >= 0 && jlocal < getNPar());
393 return cov[ilocal][jlocal];
396 double BaseFitObject::getRho(
int ilocal,
int jlocal)
const
398 assert(ilocal >= 0 && ilocal < getNPar());
399 assert(jlocal >= 0 && jlocal < getNPar());
400 return cov[ilocal][jlocal] / std::sqrt(cov[ilocal][ilocal] * cov[jlocal][jlocal]);
402 bool BaseFitObject::isParamMeasured(
int ilocal)
const
404 assert(ilocal >= 0 && ilocal < getNPar());
405 return measured[ilocal];
408 bool BaseFitObject::isParamFixed(
int ilocal)
const
410 assert(ilocal >= 0 && ilocal < getNPar());
411 return fixed[ilocal];
414 double BaseFitObject::getChi2()
const
416 if (not covinvvalid and not calculateCovInv())
return -1;
418 static double resid[BaseDefs::MAXPAR];
419 static bool chi2contr[BaseDefs::MAXPAR];
420 for (
int i = 0; i < getNPar(); ++i) {
421 resid[i] = par[i] - mpar[i];
423 B2INFO(
" BaseFitObject::getChi2() " << i <<
" " << resid[i] <<
" " << covinv[i][i]);
425 if ((chi2contr[i] = (isParamMeasured(i) && !isParamFixed(i)))) {
426 chi2 += resid[i] * covinv[i][i] * resid[i];
427 for (
int j = 0; j < getNPar(); ++j) {
428 if (j < i && chi2contr[j]) chi2 += 2 * resid[i] * covinv[i][j] * resid[j];
435 double BaseFitObject::getDChi2DParam(
int ilocal)
const
437 assert(ilocal >= 0 && ilocal < getNPar());
438 if (isParamFixed(ilocal) || !isParamMeasured(ilocal))
return 0;
440 if (not covinvvalid and not calculateCovInv())
return 0;
443 for (
int jlocal = 0; jlocal < getNPar(); jlocal++)
444 if (!isParamFixed(jlocal) && isParamMeasured(jlocal))
445 result += covinv[ilocal][jlocal] * (par[jlocal] - mpar[jlocal]);
449 double BaseFitObject::getD2Chi2DParam2(
int ilocal,
int jlocal)
const
451 assert(ilocal >= 0 && ilocal < getNPar());
452 assert(jlocal >= 0 && jlocal < getNPar());
453 if (isParamFixed(ilocal) || !isParamMeasured(ilocal) ||
454 isParamFixed(jlocal) || !isParamMeasured(jlocal))
456 if (not covinvvalid and not calculateCovInv())
return 0;
457 return 2 * covinv[ilocal][jlocal];
462 void BaseFitObject::addToGlobalChi2DerMatrix(
double* M,
int idim)
const
464 if (!covinvvalid) calculateCovInv();
465 for (
int ilocal = 0; ilocal < getNPar(); ++ilocal) {
466 if (!isParamFixed(ilocal) && isParamMeasured(ilocal)) {
467 int iglobal = getGlobalParNum(ilocal);
468 assert(iglobal >= 0 && iglobal < idim);
469 int ioffs = idim * iglobal;
470 for (
int jlocal = 0; jlocal < getNPar(); ++jlocal) {
471 if (!isParamFixed(jlocal) && isParamMeasured(jlocal)) {
472 int jglobal = getGlobalParNum(jlocal);
473 assert(jglobal >= 0 && jglobal < idim);
474 M[ioffs + jglobal] += getD2Chi2DParam2(ilocal, jlocal);
482 int BaseFitObject::addToGlobalChi2DerVector(
double* y,
int idim)
const
485 assert(getNPar() <= BaseDefs::MAXPAR);
486 if (not covinvvalid and not calculateCovInv())
return 0;
487 for (
int ilocal = 0; ilocal < getNPar(); ++ilocal) {
488 if (!isParamFixed(ilocal) && isParamMeasured(ilocal)) {
489 int iglobal = getGlobalParNum(ilocal);
490 assert(iglobal >= 0 && iglobal < idim);
491 y[iglobal] += getDChi2DParam(ilocal);
498 void BaseFitObject::addToGlobalChi2DerVector(
double* y,
int idim,
499 double lambda,
double der[],
int metaSet)
const
502 if (!cachevalid) updateCache();
503 for (
int ilocal = 0; ilocal < getNPar(); ilocal++) {
504 int iglobal = globalParNum[ilocal];
506 assert(iglobal < idim);
507 for (
int j = 0; j < BaseDefs::nMetaVars[metaSet]; j++) {
508 y[iglobal] += lambda * der[j] * getFirstDerivative_Meta_Local(j , ilocal , metaSet);
515 void BaseFitObject::addTo1stDerivatives(
double M[],
int idim,
516 double der[],
int kglobal,
int metaSet)
const
518 if (!cachevalid) updateCache();
519 for (
int ilocal = 0; ilocal < getNPar(); ilocal++) {
520 int iglobal = globalParNum[ilocal];
522 for (
int j = 0; j < BaseDefs::nMetaVars[metaSet]; j++) {
523 double x = der[j] * getFirstDerivative_Meta_Local(j, ilocal , metaSet);
524 M[idim * kglobal + iglobal] += x;
525 M[idim * iglobal + kglobal] += x;
534 void BaseFitObject::addTo2ndDerivatives(
double der2[],
int idim,
535 double factor[],
int metaSet
540 if (!cachevalid) updateCache();
541 for (
int ilocal = 0; ilocal < getNPar(); ilocal++) {
542 int iglobal = getGlobalParNum(ilocal);
543 if (iglobal < 0)
continue;
544 for (
int jlocal = ilocal; jlocal < getNPar(); jlocal++) {
545 int jglobal = getGlobalParNum(jlocal);
546 if (jglobal < 0)
continue;
548 for (
int imeta = 0; imeta < BaseDefs::nMetaVars[metaSet]; imeta++) {
549 sum += factor[imeta] * getSecondDerivative_Meta_Local(imeta, ilocal , jlocal , metaSet);
551 der2[idim * iglobal + jglobal] += sum;
552 if (iglobal != jglobal) der2[idim * jglobal + iglobal] += sum;
559 void BaseFitObject::addTo2ndDerivatives(
double M[],
int idim,
double lambda,
double der[],
int metaSet)
const
561 double factor[BaseDefs::MAXINTERVARS];
562 for (
int i = 0; i < BaseDefs::nMetaVars[metaSet]; i++) factor[i] = lambda * der[i];
563 addTo2ndDerivatives(M, idim, factor, metaSet);
587 void BaseFitObject::initCov()
589 for (
int i = 0; i < getNPar(); ++i) {
590 for (
int j = 0; j < getNPar(); ++j) {
591 cov[i][j] =
static_cast<double>(i == j);
597 double BaseFitObject::getError2(
double der[],
int metaSet)
const
599 if (!cachevalid) updateCache();
601 for (
int i = 0; i < BaseDefs::nMetaVars[metaSet]; i++) {
602 for (
int j = 0; j < BaseDefs::nMetaVars[metaSet]; j++) {
604 for (
int k = 0; k < getNPar(); k++) {
605 for (
int l = 0; l < getNPar(); l++) {
606 cov_i_j += getFirstDerivative_Meta_Local(i , k , metaSet) * cov[k][l] * getFirstDerivative_Meta_Local(j , l , metaSet);
609 totError += der[i] * der[j] * cov_i_j;