Belle II Software  release-08-01-10
BaseHardConstraint.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * Forked from https://github.com/iLCSoft/MarlinKinfit *
6  * *
7  * Further information about the fit engine and the user interface *
8  * provided in MarlinKinfit can be found at *
9  * https://www.desy.de/~blist/kinfit/doc/html/ *
10  * and in the LCNotes LC-TOOL-2009-001 and LC-TOOL-2009-004 available *
11  * from http://www-flc.desy.de/lcnotes/ *
12  * *
13  * See git log for contributors and copyright holders. *
14  * This file is licensed under LGPL-3.0, see LICENSE.md. *
15  **************************************************************************/
16 
17 #include "analysis/OrcaKinFit/BaseHardConstraint.h"
18 #include <framework/logging/Logger.h>
19 
20 #undef NDEBUG
21 #include <cassert>
22 
23 #include <cstring>
24 #include <iostream>
25 #include <cmath>
26 
27 namespace Belle2 {
32  namespace OrcaKinFit {
33 
35 
36 
37  void BaseHardConstraint::add1stDerivativesToMatrix(double* M, int idim) const
38  {
39  double dgdpi[BaseDefs::MAXINTERVARS];
40  for (unsigned int i = 0; i < fitobjects.size(); ++i) {
41  const BaseFitObject* foi = fitobjects[i];
42  assert(foi);
43  if (firstDerivatives(i, dgdpi)) {
44  foi->addTo1stDerivatives(M, idim, dgdpi, getGlobalNum(), getVarBasis());
45  }
46  }
47  }
48 
49 
75  void BaseHardConstraint::add2ndDerivativesToMatrix(double* M, int idim, double lambda) const
76  {
77 
84  // Derivatives $\frac{\partial ^2 g}{\partial P_i \partial P_j}$ at fixed i, j
85  // d2GdPidPj[4*ii+jj] is derivative w.r.t. P_i,ii and P_j,jj, where ii=0,1,2,3 for E,px,py,pz
86  double d2GdPidPj[BaseDefs::MAXINTERVARS * BaseDefs::MAXINTERVARS];
87 
88  // Derivatives $\frac {\partial P_i}{\partial a_k}$ for all i;
89  // k is local parameter number
90  // dPidAk[KMAX*4*i + 4*k + ii] is $\frac {\partial P_{i,ii}}{\partial a_k}$,
91  // with ii=0, 1, 2, 3 for E, px, py, pz
92  const int n = fitobjects.size();
93  auto* dPidAk = new double[n * BaseDefs::MAXPAR * BaseDefs::MAXINTERVARS];
94  bool* dPidAkval = new bool[n];
95 
96  for (int i = 0; i < n; ++i) dPidAkval[i] = false;
97 
98  // Derivatives $\frac{\partial ^2 g}{\partial P_i \partial a_l}$ at fixed i
99  // d2GdPdAl[4*l + ii] is $\frac{\partial ^2 g}{\partial P_{i,ii} \partial a_l}$
100  double d2GdPdAl[static_cast<int>(BaseDefs::MAXINTERVARS) * BaseDefs::MAXPAR];
101  // Derivatives $\frac{\partial ^2 g}{\partial a_k \partial a_l}$
102  double d2GdAkdAl[BaseDefs::MAXPAR * BaseDefs::MAXPAR] = {0};
103 
104  // Global parameter numbers: parglobal[BaseDefs::MAXPAR*i+klocal]
105  // is global parameter number of local parameter klocal of i-th Fit object
106  int* parglobal = new int[BaseDefs::MAXPAR * n];
107 
108  for (int i = 0; i < n; ++i) {
109  const BaseFitObject* foi = fitobjects[i];
110  assert(foi);
111  for (int klocal = 0; klocal < foi->getNPar(); ++klocal) {
112  parglobal [BaseDefs::MAXPAR * i + klocal] = foi->getGlobalParNum(klocal);
113  }
114  }
115 
116 
117  for (int i = 0; i < n; ++i) {
118  const BaseFitObject* foi = fitobjects[i];
119  assert(foi);
120  for (int j = 0; j < n; ++j) {
121  const BaseFitObject* foj = fitobjects[j];
122  assert(foj);
123  if (secondDerivatives(i, j, d2GdPidPj)) {
124  if (!dPidAkval[i]) {
125  foi->getDerivatives(dPidAk + i * (static_cast<int>(BaseDefs::MAXPAR) * BaseDefs::MAXINTERVARS),
126  static_cast<int>(BaseDefs::MAXPAR) * BaseDefs::MAXINTERVARS);
127  dPidAkval[i] = true;
128  }
129  if (!dPidAkval[j]) {
130  foj->getDerivatives(dPidAk + j * (static_cast<int>(BaseDefs::MAXPAR) * BaseDefs::MAXINTERVARS),
131  static_cast<int>(BaseDefs::MAXPAR) * BaseDefs::MAXINTERVARS);
132  dPidAkval[j] = true;
133  }
134  // Now sum over E/px/Py/Pz for object j:
135  // $$\frac{\partial ^2 g}{\partial P_{i,ii} \partial a_l}
136  // = (sum_{j}) sum_{jj} frac{\partial ^2 g}{\partial P_{i,ii} \partial P_{j,jj}}
137  // \cdot \frac{\partial P_{j,jj}}{\partial a_l}
138  // We're summing over jj here
139  for (int llocal = 0; llocal < foj->getNPar(); ++llocal) {
140  for (int ii = 0; ii < BaseDefs::MAXINTERVARS; ++ii) {
141  int ind1 = BaseDefs::MAXINTERVARS * ii;
142  int ind2 = (static_cast<int>(BaseDefs::MAXPAR) * BaseDefs::MAXINTERVARS) * j + BaseDefs::MAXINTERVARS * llocal;
143  double& r = d2GdPdAl[BaseDefs::MAXINTERVARS * llocal + ii];
144  r = d2GdPidPj[ ind1] * dPidAk[ ind2]; // E
145  r += d2GdPidPj[++ind1] * dPidAk[++ind2]; // px
146  r += d2GdPidPj[++ind1] * dPidAk[++ind2]; // py
147  r += d2GdPidPj[++ind1] * dPidAk[++ind2]; // pz
148  }
149  }
150  // Now sum over E/px/Py/Pz for object i, i.e. sum over ii:
151  // $$
152  // \frac{\partial ^2 g}{\partial a_k \partial a_l}
153  // = \sum_{ii} \frac{\partial ^2 g}{\partial P_{i,ii} \partial a_l} \cdot
154  // \frac{\partial P_{i,ii}}{\partial a_k}
155  // $$
156  for (int klocal = 0; klocal < foi->getNPar(); ++klocal) {
157  for (int llocal = 0; llocal < foj->getNPar(); ++llocal) {
158  int ind1 = BaseDefs::MAXINTERVARS * llocal;
159  int ind2 = (static_cast<int>(BaseDefs::MAXPAR) * BaseDefs::MAXINTERVARS) * i + BaseDefs::MAXINTERVARS * klocal;
160  double& r = d2GdAkdAl[BaseDefs::MAXPAR * klocal + llocal];
161  r = d2GdPdAl[ ind1] * dPidAk[ ind2]; //E
162  r += d2GdPdAl[++ind1] * dPidAk[++ind2]; // px
163  r += d2GdPdAl[++ind1] * dPidAk[++ind2]; // py
164  r += d2GdPdAl[++ind1] * dPidAk[++ind2]; // pz
165  }
166  }
167  // Now expand the local parameter numbers to global ones
168  for (int klocal = 0; klocal < foi->getNPar(); ++klocal) {
169  int kglobal = parglobal [BaseDefs::MAXPAR * i + klocal];
170  for (int llocal = 0; llocal < foj->getNPar(); ++llocal) {
171  int lglobal = parglobal [BaseDefs::MAXPAR * j + llocal];
172  M [idim * kglobal + lglobal] += lambda * d2GdAkdAl[BaseDefs::MAXPAR * klocal + llocal];
173  }
174  }
175  }
176  }
177  }
187  double dgdpi[BaseDefs::MAXINTERVARS];
188  for (int i = 0; i < n; ++i) {
189  const BaseFitObject* foi = fitobjects[i];
190  assert(foi);
191  if (firstDerivatives(i, dgdpi)) {
192  foi->addTo2ndDerivatives(M, idim, lambda, dgdpi, getVarBasis());
193  }
194  }
195 
196  delete[] dPidAk;
197  delete[] dPidAkval;
198  delete[] parglobal;
199  }
200 
201  void BaseHardConstraint::addToGlobalChi2DerVector(double* y, int idim, double lambda) const
202  {
203  double dgdpi[BaseDefs::MAXINTERVARS];
204  for (unsigned int i = 0; i < fitobjects.size(); ++i) {
205  const BaseFitObject* foi = fitobjects[i];
206  assert(foi);
207  if (firstDerivatives(i, dgdpi)) {
208  foi->addToGlobalChi2DerVector(y, idim, lambda, dgdpi, getVarBasis());
209  }
210  }
211  }
212 
213 
215  {
216  double dgdpi[BaseDefs::MAXINTERVARS];
217  double error2 = 0;
218  for (unsigned int i = 0; i < fitobjects.size(); ++i) {
219  const BaseFitObject* foi = fitobjects[i];
220  assert(foi);
221  if (firstDerivatives(i, dgdpi)) {
222  error2 += foi->getError2(dgdpi, getVarBasis());
223  }
224  }
225  return std::sqrt(std::abs(error2));
226  }
227 
228 
229  double BaseHardConstraint::dirDer(double* p, double* w, int idim, double mu)
230  {
231  double* pw, *pp;
232  for (pw = w; pw < w + idim; * (pw++) = 0);
233  addToGlobalChi2DerVector(w, idim, mu);
234  double result = 0;
235  for (pw = w, pp = p; pw < w + idim; result += *(pp++) * *(pw++));
236  return mu * result;
237  }
238 
239  double BaseHardConstraint::dirDerAbs(double* p, double* w, int idim, double mu)
240  {
241  double val = getValue();
242  if (val == 0) return mu * std::fabs(dirDer(p, w, idim, 1));
243  else if (val > 0) return mu * dirDer(p, w, idim, 1);
244  else return -mu * dirDer(p, w, idim, 1);
245  }
246 
247 
248  void BaseHardConstraint::test1stDerivatives()
249  {
250  B2INFO("BaseConstraint::test1stDerivatives for " << getName());
251  double y[100];
252  for (double& i : y) i = 0;
253  addToGlobalChi2DerVector(y, 100, 1);
254  double eps = 0.00001;
255  for (unsigned int ifo = 0; ifo < fitobjects.size(); ++ifo) {
256  BaseFitObject* fo = fitobjects[ifo];
257  assert(fo);
258  for (int ilocal = 0; ilocal < fo->getNPar(); ++ilocal) {
259  int iglobal = fo->getGlobalParNum(ilocal);
260  double calc = y[iglobal];
261  double num = num1stDerivative(ifo, ilocal, eps);
262  B2INFO("fo: " << fo->getName() << " par " << ilocal << "/"
263  << iglobal << " (" << fo->getParamName(ilocal)
264  << ") calc: " << calc << " - num: " << num << " = " << calc - num);
265  }
266  }
267  }
268 
269  void BaseHardConstraint::test2ndDerivatives()
270  {
271  B2INFO("BaseConstraint::test2ndDerivatives for " << getName());
272  const int idim = 100;
273  auto* M = new double[idim * idim];
274  for (int i = 0; i < idim * idim; ++i) M[i] = 0;
275  add2ndDerivativesToMatrix(M, idim, 1);
276  double eps = 0.0001;
277  B2INFO("eps=" << eps);
278 
279  for (unsigned int ifo1 = 0; ifo1 < fitobjects.size(); ++ifo1) {
280  BaseFitObject* fo1 = fitobjects[ifo1];
281  assert(fo1);
282  for (unsigned int ifo2 = ifo1; ifo2 < fitobjects.size(); ++ifo2) {
283  BaseFitObject* fo2 = fitobjects[ifo2];
284  assert(fo2);
285  for (int ilocal1 = 0; ilocal1 < fo1->getNPar(); ++ilocal1) {
286  int iglobal1 = fo1->getGlobalParNum(ilocal1);
287  for (int ilocal2 = (ifo1 == ifo2 ? ilocal1 : 0); ilocal2 < fo2->getNPar(); ++ilocal2) {
288  int iglobal2 = fo2->getGlobalParNum(ilocal2);
289  double calc = M[idim * iglobal1 + iglobal2];
290  double num = num2ndDerivative(ifo1, ilocal1, eps, ifo2, ilocal2, eps);
291  B2INFO("fo1: " << fo1->getName() << " par " << ilocal1 << "/"
292  << iglobal1 << " (" << fo1->getParamName(ilocal1)
293  << "), fo2: " << fo2->getName() << " par " << ilocal2 << "/"
294  << iglobal2 << " (" << fo2->getParamName(ilocal2)
295  << ") calc: " << calc << " - num: " << num << " = " << calc - num);
296  }
297  }
298  }
299  }
300  delete[] M;
301  }
302 
303 
304  double BaseHardConstraint::num1stDerivative(int ifo, int ilocal, double eps)
305  {
306  BaseFitObject* fo = fitobjects[ifo];
307  assert(fo);
308  double save = fo->getParam(ilocal);
309  fo->setParam(ilocal, save + eps);
310  double v1 = getValue();
311  fo->setParam(ilocal, save - eps);
312  double v2 = getValue();
313  double result = (v1 - v2) / (2 * eps);
314  fo->setParam(ilocal, save);
315  return result;
316  }
317 
318  double BaseHardConstraint::num2ndDerivative(int ifo1, int ilocal1, double eps1,
319  int ifo2, int ilocal2, double eps2)
320  {
321  double result;
322 
323  if (ifo1 == ifo2 && ilocal1 == ilocal2) {
324  BaseFitObject* fo = fitobjects[ifo1];
325  assert(fo);
326  double save = fo->getParam(ilocal1);
327  double v0 = getValue();
328  fo->setParam(ilocal1, save + eps1);
329  double v1 = getValue();
330  fo->setParam(ilocal1, save - eps1);
331  double v2 = getValue();
332  result = (v1 + v2 - 2 * v0) / (eps1 * eps1);
333  fo->setParam(ilocal1, save);
334  } else {
335  BaseFitObject* fo1 = fitobjects[ifo1];
336  assert(fo1);
337  BaseFitObject* fo2 = fitobjects[ifo2];
338  assert(fo2);
339  double save1 = fo1->getParam(ilocal1);
340  double save2 = fo2->getParam(ilocal2);
341  fo1->setParam(ilocal1, save1 + eps1);
342  fo2->setParam(ilocal2, save2 + eps2);
343  double v11 = getValue();
344  fo2->setParam(ilocal2, save2 - eps2);
345  double v12 = getValue();
346  fo1->setParam(ilocal1, save1 - eps1);
347  double v22 = getValue();
348  fo2->setParam(ilocal2, save2 + eps2);
349  double v21 = getValue();
350  result = (v11 + v22 - v12 - v21) / (4 * eps1 * eps2);
351  fo1->setParam(ilocal1, save1);
352  fo2->setParam(ilocal2, save2);
353  }
354  return result;
355  }
356 
357  void BaseHardConstraint::printFirstDerivatives() const
358  {
359 
360  B2INFO("BaseHardConstraint::printFirstDerivatives " << fitobjects.size());
361 
362  double dgdpi[BaseDefs::MAXINTERVARS];
363  for (unsigned int i = 0; i < fitobjects.size(); ++i) {
364  const BaseFitObject* foi = fitobjects[i];
365  assert(foi);
366  if (firstDerivatives(i, dgdpi)) {
367  B2INFO("first derivs for obj " << i << " : ");
368  for (double j : dgdpi)
369  B2INFO(j << " ");
370  }
371  }
372 
373  return;
374  }
375 
376  void BaseHardConstraint::printSecondDerivatives() const
377  {
378 
379  double d2GdPidPj[BaseDefs::MAXINTERVARS * BaseDefs::MAXINTERVARS];
380 
381  int n = fitobjects.size();
382 
383  for (int i = 0; i < n; ++i) {
384  const BaseFitObject* foi = fitobjects[i];
385  assert(foi);
386  for (int j = 0; j < n; ++j) {
387  const BaseFitObject* foj = fitobjects[j];
388  assert(foj);
389  if (secondDerivatives(i, j, d2GdPidPj)) {
390 
391  B2INFO("second derivs for objs " << i << " " << j);
392 
393  int k(0);
394  for (int k1 = 0; k1 < BaseDefs::MAXINTERVARS; k1++) {
395  for (int k2 = 0; k2 < BaseDefs::MAXINTERVARS; k2++) {
396  B2INFO(d2GdPidPj[k++] << " ");
397  }
398  }
399  }
400  }
401  }
402 
403  return;
404  }
405 
406  }// end OrcaKinFit namespace
408 } // end Belle2 namespace
virtual const char * getName() const
Returns the name of the constraint.
virtual int getNPar() const =0
Get total number of parameters of this FitObject.
virtual const char * getParamName(int ilocal) const =0
Get name of parameter ilocal.
virtual bool setParam(int ilocal, double par_, bool measured_, bool fixed_=false)
Set value and measured flag of parameter i; return: significant change.
virtual int getGlobalParNum(int ilocal) const
Get global parameter number of parameter ilocal.
virtual const char * getName() const
Get object's name.
virtual double getParam(int ilocal) const
Get current value of parameter ilocal.
virtual int addToGlobalChi2DerVector(double *y, int idim) const
Add derivatives of chi squared to global derivative vector.
virtual ~BaseHardConstraint()
Virtual destructor.
virtual int getGlobalNum() const
Accesses position of constraint in global constraint list.
virtual double getValue() const override=0
Returns the value of the constraint.
FitObjectContainer fitobjects
The FitObjectContainer.
virtual void add1stDerivativesToMatrix(double *M, int idim) const
Adds first order derivatives to global covariance matrix M.
virtual double getError() const override
Returns the error on the value of the constraint.
virtual void addToGlobalChi2DerVector(double *y, int idim, double lambda) const
Add lambda times derivatives of chi squared to global derivative vector.
virtual double dirDerAbs(double *p, double *w, int idim, double mu=1)
Calculate directional derivative for abs(c)
virtual double dirDer(double *p, double *w, int idim, double mu=1)
Calculate directional derivative.
virtual bool secondDerivatives(int i, int j, double *derivatives) const =0
Second derivatives with respect to the meta-variables of Fit objects i and j; result false if all der...
virtual bool firstDerivatives(int i, double *derivatives) const =0
First derivatives with respect to the meta-variables of Fit objects i; result false if all derivative...
virtual void add2ndDerivativesToMatrix(double *M, int idim, double lambda) const
Adds second order derivatives to global covariance matrix M.
virtual double num2ndDerivative(int ifo1, int ilocal1, double eps1, int ifo2, int ilocal2, double eps2)
Evaluates numerically the 2nd derivative w.r.t. 2 parameters.
virtual double num1stDerivative(int ifo, int ilocal, double eps)
Evaluates numerically the 1st derivative w.r.t. a parameter.
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Abstract base class for different kinds of events.