Belle II Software  release-08-01-10
ParticleFitObject.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/ParticleFitObject.h"
18 #include <framework/logging/Logger.h>
19 
20 #include <iostream>
21 #undef NDEBUG
22 #include <cassert>
23 #include <cmath>
24 using std::isfinite;
25 using std::endl;
26 
27 // #include <TMatrixDSym.h>
28 #include <gsl/gsl_matrix.h>
29 #include <gsl/gsl_linalg.h>
30 
31 
32 namespace Belle2 {
37  namespace OrcaKinFit {
38 
40  : mass(0), fourMomentum(FourVector(0, 0, 0, 0)), paramCycl{}
41  {
42  for (double& i : paramCycl)
43  i = -1;
44  }
45 
47 
49  : BaseFitObject(rhs), mass(0), fourMomentum(FourVector(0, 0, 0, 0)), paramCycl{}
50  {
51  //B2INFO( "copying ParticleFitObject with name" << rhs.name );
53  }
54 
56  {
57  if (this != &rhs) {
58  assign(rhs); // calls virtual function assign of derived class
59  }
60  return *this;
61  }
62 
63  bool ParticleFitObject::setMass(double mass_)
64  {
65  if (!isfinite(mass_)) return false;
66  if (mass == mass_) return true;
68  mass = std::abs(mass_);
69  return true;
70  }
71 
72 
74  {
75  if (const auto* psource = dynamic_cast<const ParticleFitObject*>(&source)) {
76  if (psource != this) {
77  BaseFitObject::assign(source);
78  mass = psource->mass;
79  for (int i = 0; i < BaseDefs::MAXPAR; ++i)
80  paramCycl[i] = psource->paramCycl[i];
81  }
82  } else {
83  assert(0);
84  }
85  return *this;
86  }
87 
88 
90  {
91  return mass;
92  }
93 
94  std::ostream& ParticleFitObject::print4Vector(std::ostream& os) const
95  {
96  os << "[" << getE() << ", " << getPx() << ", "
97  << getPy() << ", " << getPz() << "]";
98  return os;
99  }
100 
101  FourVector ParticleFitObject::getFourMomentum() const
102  {
103  if (!cachevalid) updateCache();
104  return fourMomentum;
105  }
106  double ParticleFitObject::getE() const
107  {
108  return getFourMomentum().getE();
109  }
111  {
112  return getFourMomentum().getPx();
113  }
115  {
116  return getFourMomentum().getPy();
117  }
119  {
120  return getFourMomentum().getPz();
121  }
122  double ParticleFitObject::getP() const
123  {
124  return getFourMomentum().getP();
125  }
127  {
128  return getFourMomentum().getP2();
129  }
131  {
132  return getFourMomentum().getPt();
133  }
135  {
136  return getFourMomentum().getPt2();
137  }
138 
139 
140  std::ostream& ParticleFitObject::print(std::ostream& os) const
141  {
142 
143  if (!cachevalid) updateCache();
144 
145  printParams(os);
146  os << " => ";
147  print4Vector(os);
148  os << std::endl;
149  return os;
150  }
151 
152  void ParticleFitObject::addToGlobalChi2DerVectorNum(double* y, int idim, double eps)
153  {
154  for (int ilocal = 0; ilocal < getNPar(); ++ilocal) {
155  int iglobal = getGlobalParNum(ilocal);
156  assert(iglobal >= 0 && iglobal < idim);
157  y[iglobal] += num1stDerivative(ilocal, eps);
158  }
159  }
160 
161 
162  void ParticleFitObject::addToGlobalChi2DerMatrixNum(double* M, int idim, double eps)
163  {
164  for (int ilocal1 = 0; ilocal1 < getNPar(); ++ilocal1) {
165  int iglobal1 = getGlobalParNum(ilocal1);
166  for (int ilocal2 = ilocal1; ilocal2 < getNPar(); ++ilocal2) {
167  int iglobal2 = getGlobalParNum(ilocal2);
168  M[idim * iglobal1 + iglobal2] += num2ndDerivative(ilocal1, eps, ilocal2, eps);
169  }
170  }
171  }
172 
173  void ParticleFitObject::getDerivatives(double der[], int idim) const
174  {
175  for (int ilocal = 0; ilocal < getNPar(); ++ilocal) {
176  assert(ilocal < idim);
177  der [4 * ilocal] = getDE(ilocal);
178  der [4 * ilocal + 1] = getDPx(ilocal);
179  der [4 * ilocal + 2] = getDPy(ilocal);
180  der [4 * ilocal + 3] = getDPz(ilocal);
181  }
182  }
183 
184  void ParticleFitObject::test1stDerivatives()
185  {
186  B2INFO("ParticleFitObject::test1stDerivatives, object " << getName() << "\n");
187  double ycalc[100], ynum[100];
188  for (int i = 0; i < 100; ++i) ycalc[i] = ynum[i] = 0;
189  addToGlobalChi2DerVector(ycalc, 100);
190  double eps = 0.00001;
191  addToGlobalChi2DerVectorNum(ynum, 100, eps);
192  for (int ilocal = 0; ilocal < getNPar(); ++ilocal) {
193  int iglobal = getGlobalParNum(ilocal);
194  double calc = ycalc[iglobal];
195  double num = ynum[iglobal];
196  B2INFO("fo: " << getName() << " par " << ilocal << "/"
197  << iglobal << " (" << getParamName(ilocal)
198  << ") calc: " << calc << " - num: " << num << " = " << calc - num);
199  }
200  }
201 
202  void ParticleFitObject::test2ndDerivatives()
203  {
204  B2INFO("ParticleFitObject::test2ndDerivatives, object " << getName() << "\n");
205  const int idim = 100;
206  auto* Mnum = new double[idim * idim];
207  auto* Mcalc = new double[idim * idim];
208  for (int i = 0; i < idim * idim; ++i) Mnum[i] = Mcalc[i] = 0;
209  addToGlobalChi2DerMatrix(Mcalc, idim);
210  double eps = 0.0001;
211  B2INFO("eps=" << eps);
212  addToGlobalChi2DerMatrixNum(Mnum, idim, eps);
213  for (int ilocal1 = 0; ilocal1 < getNPar(); ++ilocal1) {
214  int iglobal1 = getGlobalParNum(ilocal1);
215  for (int ilocal2 = ilocal1; ilocal2 < getNPar(); ++ilocal2) {
216  int iglobal2 = getGlobalParNum(ilocal2);
217  double calc = Mcalc[idim * iglobal1 + iglobal2];
218  double num = Mnum[idim * iglobal1 + iglobal2];
219  B2INFO("fo: " << getName() << " par " << ilocal1 << "/"
220  << iglobal1 << " (" << getParamName(ilocal1)
221  << "), par " << ilocal2 << "/"
222  << iglobal2 << " (" << getParamName(ilocal2)
223  << ") calc: " << calc << " - num: " << num << " = " << calc - num);
224  }
225  }
226  delete[] Mnum;
227  delete[] Mcalc;
228  }
229 
230  double ParticleFitObject::num1stDerivative(int ilocal, double eps)
231  {
232  double save = getParam(ilocal);
233  setParam(ilocal, save + eps);
234  double v1 = getChi2();
235  setParam(ilocal, save - eps);
236  double v2 = getChi2();
237  double result = (v1 - v2) / (2 * eps);
238  setParam(ilocal, save);
239  return result;
240  }
241 
242  double ParticleFitObject::num2ndDerivative(int ilocal1, double eeps1,
243  int ilocal2, double eeps2)
244  {
245  double result;
246 
247  if (ilocal1 == ilocal2) {
248  double save = getParam(ilocal1);
249  double v0 = getChi2();
250  setParam(ilocal1, save + eeps1);
251  double v1 = getChi2();
252  setParam(ilocal1, save - eeps1);
253  double v2 = getChi2();
254  result = (v1 + v2 - 2 * v0) / (eeps1 * eeps1);
255  setParam(ilocal1, save);
256  } else {
257  double save1 = getParam(ilocal1);
258  double save2 = getParam(ilocal2);
259  setParam(ilocal1, save1 + eeps1);
260  setParam(ilocal2, save2 + eeps2);
261  double v11 = getChi2();
262  setParam(ilocal2, save2 - eeps2);
263  double v12 = getChi2();
264  setParam(ilocal1, save1 - eeps1);
265  double v22 = getChi2();
266  setParam(ilocal2, save2 + eeps2);
267  double v21 = getChi2();
268  result = (v11 + v22 - v12 - v21) / (4 * eeps1 * eeps2);
269  setParam(ilocal1, save1);
270  setParam(ilocal2, save2);
271  }
272  return result;
273  }
274 
275 
277  {
278  // reimplemented here to take account of cyclical variables e.g azimuthal angle phi - DJeans
279 
280  if (not covinvvalid and not calculateCovInv()) return 0;
281 
282  double resid[BaseDefs::MAXPAR] = {0};
283  for (int i = 0; i < getNPar(); i++) {
284  if (isParamMeasured(i) && !isParamFixed(i)) {
285  resid[i] = par[i] - mpar[i];
286  if (paramCycl[i] > 0) {
287  resid[i] = fmod(resid[i], paramCycl[i]);
288  if (resid[i] > paramCycl[i] / 2) resid[i] -= paramCycl[i];
289  if (resid[i] < -paramCycl[i] / 2) resid[i] += paramCycl[i];
290  }
291  }
292  }
293 
294 
295  double chi2 = 0;
296  for (int i = 0; i < getNPar(); i++) {
297  if (isParamMeasured(i) && !isParamFixed(i)) {
298  for (int j = 0; j < getNPar(); j++) {
299  if (isParamMeasured(j) && !isParamFixed(j)) {
300  chi2 += resid[i] * covinv[i][j] * resid[j];
301  // B2INFO( getName () << " === " << i << " " << j << " : " <<
302  // resid[i] << "*" << covinv[i][j] << "*" << resid[j] << " = " << resid[i]*covinv[i][j]*resid[j] << " , sum " << chi2);
303  }
304  }
305  }
306  }
307 
308  // B2INFO("ParticleFitObject::getChi2 () chi2 = " << chi2 );
309  return chi2;
310  }
311 
312  }// end OrcaKinFit namespace
314 } // end Belle2 namespace
bool covinvvalid
flag for valid inverse covariance matrix
virtual int getNPar() const =0
Get total number of parameters of this FitObject.
virtual void addToGlobalChi2DerMatrix(double *M, int idim) const
Add 2nd derivatives of chi squared to global derivative matrix.
virtual const char * getParamName(int ilocal) const =0
Get name of parameter ilocal.
virtual BaseFitObject & assign(const BaseFitObject &source)
Assign from anther object, if of same type.
virtual bool setParam(int ilocal, double par_, bool measured_, bool fixed_=false)
Set value and measured flag of parameter i; return: significant change.
double covinv[BaseDefs::MAXPAR][BaseDefs::MAXPAR]
inverse pf local covariance matrix
bool cachevalid
flag for valid cache
virtual int getGlobalParNum(int ilocal) const
Get global parameter number of parameter ilocal.
virtual const char * getName() const
Get object's name.
virtual bool isParamFixed(int ilocal) const
Returns whether parameter is fixed.
double par[BaseDefs::MAXPAR]
fit parameters
void invalidateCache() const
invalidate any cached quantities
double mpar[BaseDefs::MAXPAR]
measured parameters
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 std::ostream & printParams(std::ostream &os) const
print the parameters and errors
virtual bool calculateCovInv() const
Calculate the inverse of the covariance matrix.
virtual bool isParamMeasured(int ilocal) const
Get measured flag for parameter ilocal.
Yet another four vector class, with metric +—.
Definition: FourVector.h:43
double getPx() const
Returns the x momentum / 1 component.
Definition: FourVector.h:128
double getPz() const
Returns the z momentum / 3 component.
Definition: FourVector.h:130
double getPt2() const
Returns the transverse momentum squared / magnitude of the 1 and 2 component vector squared.
Definition: FourVector.h:132
double getPy() const
Returns the y momentum / 2 component.
Definition: FourVector.h:129
double getP2() const
Returns the momentum squared / magnitude of the three vector squared.
Definition: FourVector.h:135
double getPt() const
Returns the transverse momentum / magnitude of the 1 and 2 component vector.
Definition: FourVector.h:133
double getP() const
Returns the momentum / magnitude of the three vector.
Definition: FourVector.h:136
double getE() const
Returns the energy / 0 component.
Definition: FourVector.h:127
virtual double getPx() const
Return px.
virtual ~ParticleFitObject()
Virtual destructor.
virtual void addToGlobalChi2DerMatrixNum(double *M, int idim, double eps)
Add numerically determined derivatives of chi squared to global covariance matrix.
ParticleFitObject & operator=(const ParticleFitObject &rhs)
Assignment.
virtual double getPz() const
Return pz.
virtual bool setMass(double mass_)
Set mass of particle; return=success.
double num2ndDerivative(int ilocal1, double eps1, int ilocal2, double eps2)
Evaluates numerically the 2nd derivative of chi2 w.r.t. 2 parameters.
virtual void addToGlobalChi2DerVectorNum(double *y, int idim, double eps)
Add numerically determined derivatives of chi squared to global derivative vector.
virtual std::ostream & print(std::ostream &os) const override
print object to ostream
virtual double getPt2() const
Return pt (transverse momentum) squared.
virtual double getDE(int ilocal) const =0
Return d E / d par_ilocal (derivative of E w.r.t. local parameter ilocal)
virtual double getPy() const
Return py.
virtual double getDPx(int ilocal) const =0
Return d p_x / d par_ilocal (derivative of px w.r.t. local parameter ilocal)
virtual double getDPz(int ilocal) const =0
Return d p_z / d par_ilocal (derivative of pz w.r.t. local parameter ilocal)
virtual double getP2() const
Return p (momentum) squared.
virtual double getPt() const
Return pt (transverse momentum)
virtual double getP() const
Return p (momentum)
virtual ParticleFitObject & assign(const BaseFitObject &source) override
Assign from anther object, if of same type.
virtual double getE() const
Return E.
double num1stDerivative(int ilocal, double eps)
Evaluates numerically the 1st derivative of chi2 w.r.t. a parameter.
virtual double getChi2() const override
Get chi squared from measured and fitted parameters.
virtual double getDPy(int ilocal) const =0
Return d p_y / d par_ilocal (derivative of py w.r.t. local parameter ilocal)
virtual double getMass() const
Get mass of particle.
virtual std::ostream & print4Vector(std::ostream &os) const
print the four-momentum (E, px, py, pz)
Abstract base class for different kinds of events.