Belle II Software  release-08-01-10
SoftGaussParticleConstraint.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/SoftGaussParticleConstraint.h"
18 #include "analysis/OrcaKinFit/ParticleFitObject.h"
19 #include <framework/logging/Logger.h>
20 #include <iostream>
21 #include <cmath>
22 using namespace std;
23 
24 namespace Belle2 {
29  namespace OrcaKinFit {
30 
31  SoftGaussParticleConstraint::SoftGaussParticleConstraint(double sigma_)
32  : sigma(sigma_)
33  {
35  }
36 
38  {
39  return sigma;
40  }
41 
43  {
44  if (sigma_ != 0) sigma = std::abs(sigma_);
45  return sigma;
46  }
47 
49  {
50  double r = getValue() / getSigma();
51  return r * r;
52  }
53 
55  {
56  double dgdpi[4];
57  double error2 = 0;
58  for (unsigned int i = 0; i < fitobjects.size(); ++i) {
59  const ParticleFitObject* foi = fitobjects[i];
60  assert(foi);
61  if (firstDerivatives(i, dgdpi)) {
62  error2 += foi->getError2(dgdpi, getVarBasis());
63  }
64  }
65  return std::sqrt(std::abs(error2));
66  }
67 
92  {
93 
100  double s = getSigma();
101  double fact = 2 * getValue() / (s * s);
102 
103  // Derivatives $\frac{\partial ^2 g}{\partial P_i \partial P_j}$ at fixed i, j
104  // 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
105  double d2GdPidPj[16];
106  // Derivatives $\frac {\partial P_i}{\partial a_k}$ for all i;
107  // k is local parameter number
108  // dPidAk[KMAX*4*i + 4*k + ii] is $\frac {\partial P_{i,ii}}{\partial a_k}$,
109  // with ii=0, 1, 2, 3 for E, px, py, pz
110  const int KMAX = 4;
111  const int n = fitobjects.size();
112  auto* dPidAk = new double[n * KMAX * 4];
113  bool* dPidAkval = new bool[n];
114 
115  for (int i = 0; i < n; ++i) dPidAkval[i] = false;
116 
117  // Derivatives $\frac{\partial ^2 g}{\partial P_i \partial a_l}$ at fixed i
118  // d2GdPdAl[4*l + ii] is $\frac{\partial ^2 g}{\partial P_{i,ii} \partial a_l}$
119  double d2GdPdAl[4 * KMAX];
120  // Derivatives $\frac{\partial ^2 g}{\partial a_k \partial a_l}$
121  double d2GdAkdAl[KMAX * KMAX] = {0};
122 
123  // Global parameter numbers: parglobal[KMAX*i+klocal]
124  // is global parameter number of local parameter klocal of i-th Fit object
125  int* parglobal = new int[KMAX * n];
126 
127  for (int i = 0; i < n; ++i) {
128  const ParticleFitObject* foi = fitobjects[i];
129  assert(foi);
130  for (int klocal = 0; klocal < foi->getNPar(); ++klocal) {
131  parglobal [KMAX * i + klocal] = foi->getGlobalParNum(klocal);
132  }
133  }
134 
135 
136  for (int i = 0; i < n; ++i) {
137  const ParticleFitObject* foi = fitobjects[i];
138  assert(foi);
139  for (int j = 0; j < n; ++j) {
140  const ParticleFitObject* foj = fitobjects[j];
141  assert(foj);
142  if (secondDerivatives(i, j, d2GdPidPj)) {
143  if (!dPidAkval[i]) {
144  foi->getDerivatives(dPidAk + i * (KMAX * 4), KMAX * 4);
145  dPidAkval[i] = true;
146  }
147  if (!dPidAkval[j]) {
148  foj->getDerivatives(dPidAk + j * (KMAX * 4), KMAX * 4);
149  dPidAkval[j] = true;
150  }
151  // Now sum over E/px/Py/Pz for object j:
152  // $$\frac{\partial ^2 g}{\partial P_{i,ii} \partial a_l}
153  // = (sum_{j}) sum_{jj} frac{\partial ^2 g}{\partial P_{i,ii} \partial P_{j,jj}}
154  // \cdot \frac{\partial P_{j,jj}}{\partial a_l}
155  // We're summing over jj here
156  for (int llocal = 0; llocal < foj->getNPar(); ++llocal) {
157  for (int ii = 0; ii < 4; ++ii) {
158  int ind1 = 4 * ii;
159  int ind2 = (KMAX * 4) * j + 4 * llocal;
160  double& r = d2GdPdAl[4 * llocal + ii];
161  r = d2GdPidPj[ ind1] * dPidAk[ ind2]; // E
162  r += d2GdPidPj[++ind1] * dPidAk[++ind2]; // px
163  r += d2GdPidPj[++ind1] * dPidAk[++ind2]; // py
164  r += d2GdPidPj[++ind1] * dPidAk[++ind2]; // pz
165  }
166  }
167  // Now sum over E/px/Py/Pz for object i, i.e. sum over ii:
168  // $$
169  // \frac{\partial ^2 g}{\partial a_k \partial a_l}
170  // = \sum_{ii} \frac{\partial ^2 g}{\partial P_{i,ii} \partial a_l} \cdot
171  // \frac{\partial P_{i,ii}}{\partial a_k}
172  // $$
173  for (int klocal = 0; klocal < foi->getNPar(); ++klocal) {
174  for (int llocal = 0; llocal < foj->getNPar(); ++llocal) {
175  int ind1 = 4 * llocal;
176  int ind2 = (KMAX * 4) * i + 4 * klocal;
177  double& r = d2GdAkdAl[KMAX * klocal + llocal];
178  r = d2GdPdAl[ ind1] * dPidAk[ ind2]; //E
179  r += d2GdPdAl[++ind1] * dPidAk[++ind2]; // px
180  r += d2GdPdAl[++ind1] * dPidAk[++ind2]; // py
181  r += d2GdPdAl[++ind1] * dPidAk[++ind2]; // pz
182  }
183  }
184  // Now expand the local parameter numbers to global ones
185  for (int klocal = 0; klocal < foi->getNPar(); ++klocal) {
186  int kglobal = parglobal [KMAX * i + klocal];
187  for (int llocal = 0; llocal < foj->getNPar(); ++llocal) {
188  int lglobal = parglobal [KMAX * j + llocal];
189  M [idim * kglobal + lglobal] += fact * d2GdAkdAl[KMAX * klocal + llocal];
190  }
191  }
192  }
193  }
194  }
213  auto* v = new double[idim];
214  for (int i = 0; i < idim; ++i) v[i] = 0;
215  double sqrtfact2 = sqrt(2.0) / s;
216 
217  double dgdpi[4];
218  for (int i = 0; i < n; ++i) {
219  const ParticleFitObject* foi = fitobjects[i];
220  assert(foi);
221  if (firstDerivatives(i, dgdpi)) {
222  foi->addTo2ndDerivatives(M, idim, fact, dgdpi, getVarBasis());
223  foi->addToGlobalChi2DerVector(v, idim, sqrtfact2, dgdpi, getVarBasis());
224  }
225  }
226 
227  for (int i = 0; i < idim; ++i) {
228  if (double vi = v[i]) {
229  int ioffs = i * idim;
230  for (double* pvj = v; pvj < v + idim; ++pvj) {
231  M[ioffs++] += vi * (*pvj);
232  }
233  }
234  }
235 
236 
237  delete[] dPidAk;
238  delete[] dPidAkval;
239  delete[] parglobal;
240  delete[] v;
241  }
242 
244  {
245  double dgdpi[4];
246  double s = getSigma();
247  double r = 2 * getValue() / (s * s);
248  for (unsigned int i = 0; i < fitobjects.size(); ++i) {
249  const ParticleFitObject* foi = fitobjects[i];
250  assert(foi);
251  if (firstDerivatives(i, dgdpi)) {
252  foi->addToGlobalChi2DerVector(y, idim, r, dgdpi, getVarBasis());
253  }
254  }
255  }
256 
257  void SoftGaussParticleConstraint::test1stDerivatives()
258  {
259  B2INFO("SoftGaussParticleConstraint::test1stDerivatives for " << getName());
260  double y[100];
261  for (double& i : y) i = 0;
262  addToGlobalChi2DerVector(y, 100);
263  double eps = 0.00001;
264  for (unsigned int ifo = 0; ifo < fitobjects.size(); ++ifo) {
265  ParticleFitObject* fo = fitobjects[ifo];
266  assert(fo);
267  for (int ilocal = 0; ilocal < fo->getNPar(); ++ilocal) {
268  int iglobal = fo->getGlobalParNum(ilocal);
269  double calc = y[iglobal];
270  double num = num1stDerivative(ifo, ilocal, eps);
271  B2INFO("fo: " << fo->getName() << " par " << ilocal << "/"
272  << iglobal << " (" << fo->getParamName(ilocal)
273  << ") calc: " << calc << " - num: " << num << " = " << calc - num);
274  }
275  }
276  }
277  void SoftGaussParticleConstraint::test2ndDerivatives()
278  {
279  B2INFO("SoftGaussParticleConstraint::test2ndDerivatives for " << getName());
280  const int idim = 100;
281  auto* M = new double[idim * idim];
282  for (int i = 0; i < idim * idim; ++i) M[i] = 0;
283  add2ndDerivativesToMatrix(M, idim);
284  double eps = 0.0001;
285  B2INFO("eps=" << eps);
286 
287  for (unsigned int ifo1 = 0; ifo1 < fitobjects.size(); ++ifo1) {
288  ParticleFitObject* fo1 = fitobjects[ifo1];
289  assert(fo1);
290  for (unsigned int ifo2 = ifo1; ifo2 < fitobjects.size(); ++ifo2) {
291  ParticleFitObject* fo2 = fitobjects[ifo2];
292  assert(fo2);
293  for (int ilocal1 = 0; ilocal1 < fo1->getNPar(); ++ilocal1) {
294  int iglobal1 = fo1->getGlobalParNum(ilocal1);
295  for (int ilocal2 = (ifo1 == ifo2 ? ilocal1 : 0); ilocal2 < fo2->getNPar(); ++ilocal2) {
296  int iglobal2 = fo2->getGlobalParNum(ilocal2);
297  double calc = M[idim * iglobal1 + iglobal2];
298  double num = num2ndDerivative(ifo1, ilocal1, eps, ifo2, ilocal2, eps);
299  B2INFO("fo1: " << fo1->getName() << " par " << ilocal1 << "/"
300  << iglobal1 << " (" << fo1->getParamName(ilocal1)
301  << "), fo2: " << fo2->getName() << " par " << ilocal2 << "/"
302  << iglobal2 << " (" << fo2->getParamName(ilocal2)
303  << ") calc: " << calc << " - num: " << num << " = " << calc - num);
304  }
305  }
306  }
307  }
308  delete[] M;
309  }
310 
311 
312  double SoftGaussParticleConstraint::num1stDerivative(int ifo, int ilocal, double eps)
313  {
314  ParticleFitObject* fo = fitobjects[ifo];
315  assert(fo);
316  double save = fo->getParam(ilocal);
317  fo->setParam(ilocal, save + eps);
318  double v1 = getChi2();
319  fo->setParam(ilocal, save - eps);
320  double v2 = getChi2();
321  double result = (v1 - v2) / (2 * eps);
322  fo->setParam(ilocal, save);
323  return result;
324  }
325 
326  double SoftGaussParticleConstraint::num2ndDerivative(int ifo1, int ilocal1, double eps1,
327  int ifo2, int ilocal2, double eps2)
328  {
329  double result;
330 
331  if (ifo1 == ifo2 && ilocal1 == ilocal2) {
332  ParticleFitObject* fo = fitobjects[ifo1];
333  assert(fo);
334  double save = fo->getParam(ilocal1);
335  double v0 = getChi2();
336  fo->setParam(ilocal1, save + eps1);
337  double v1 = getChi2();
338  fo->setParam(ilocal1, save - eps1);
339  double v2 = getChi2();
340  result = (v1 + v2 - 2 * v0) / (eps1 * eps1);
341  fo->setParam(ilocal1, save);
342  } else {
343  ParticleFitObject* fo1 = fitobjects[ifo1];
344  assert(fo1);
345  ParticleFitObject* fo2 = fitobjects[ifo2];
346  assert(fo2);
347  double save1 = fo1->getParam(ilocal1);
348  double save2 = fo2->getParam(ilocal2);
349  fo1->setParam(ilocal1, save1 + eps1);
350  fo2->setParam(ilocal2, save2 + eps2);
351  double v11 = getChi2();
352  fo2->setParam(ilocal2, save2 - eps2);
353  double v12 = getChi2();
354  fo1->setParam(ilocal1, save1 - eps1);
355  double v22 = getChi2();
356  fo2->setParam(ilocal2, save2 + eps2);
357  double v21 = getChi2();
358  result = (v11 + v22 - v12 - v21) / (4 * eps1 * eps2);
359  fo1->setParam(ilocal1, save1);
360  fo2->setParam(ilocal2, save2);
361  }
362  return result;
363  }
364 
365  int SoftGaussParticleConstraint::getVarBasis() const
366  {
367  return VAR_BASIS;
368  }
369  }// end OrcaKinFit namespace
371 } // end Belle2 namespace
372 
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 double getValue() const override=0
Returns the value of the constraint function.
FitObjectContainer fitobjects
The FitObjectContainer.
virtual void add2ndDerivativesToMatrix(double *M, int idim) const override
Adds second 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) const override
Add derivatives of chi squared to global derivative matrix.
virtual bool secondDerivatives(int i, int j, double *derivatives) const =0
Second derivatives with respect to the 4-vectors of Fit objects i and j; result false if all derivati...
virtual bool firstDerivatives(int i, double *derivatives) const =0
First derivatives with respect to the 4-vector of Fit objects i; result false if all derivatives are ...
void invalidateCache() const
Invalidates any cached values for the next event.
virtual double setSigma(double sigma_)
Sets the sigma.
virtual double getSigma() const
Returns the sigma.
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 getChi2() const override
Returns the chi2.
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.