Belle II Software  release-06-01-15
HelixUtils.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * External Contributor: Wouter Hulsbergen *
5  * *
6  * See git log for contributors and copyright holders. *
7  * This file is licensed under LGPL-3.0, see LICENSE.md. *
8  **************************************************************************/
9 
10 #include <TMath.h>
11 
12 #include <framework/gearbox/Const.h>
13 #include <framework/logging/Logger.h>
14 
15 #include <TVector3.h>
16 #include <analysis/VertexFitting/TreeFitter/HelixUtils.h>
17 
18 namespace TreeFitter {
19 
21  double L, double Bz,
22  TVector3& position,
23  TVector3& momentum, int& charge)
24  {
25  position = helix.getPositionAtArcLength2D(L);
26  momentum = helix.getMomentumAtArcLength2D(L, Bz);
27  charge = helix.getChargeSign();
28  }
29 
30  void HelixUtils::helixFromVertex(const Eigen::Matrix<double, 1, 6>& positionAndMomentum,
31  int charge, double Bz,
32  Belle2::Helix& helix,
33  double& L,
34  Eigen::Matrix<double, 5, 6>& jacobian)
35  {
36 
37 
38  TVector3 position(positionAndMomentum(0),
39  positionAndMomentum(1),
40  positionAndMomentum(2));
41  TVector3 momentum(positionAndMomentum(3),
42  positionAndMomentum(4),
43  positionAndMomentum(5));
44 
45  helix = Belle2::Helix(position, momentum, charge, Bz);
46  L = helix.getArcLength2DAtXY(positionAndMomentum(0),
47  positionAndMomentum(1));
48 
49  const double alpha = helix.getAlpha(Bz);
50 
51  //Copied from Belle2::UncertainHelix
52  // COMPLETELY WRONG SINCE IT ASSUMES IT'S IN THE.operator() PERIGEE,
53  // ONLY A PLACEHOLDER FOR NOW
54  // 1. Rotate to a system where phi0 = 0
55  Eigen::Matrix<double, 6, 6> jacobianRot = Eigen::Matrix<double, 6, 6>::Zero(6, 6);
56 
57  const double px = positionAndMomentum(3);
58  const double py = positionAndMomentum(4);
59  const double pt = hypot(px, py);
60  const double cosPhi0 = px / pt;
61  const double sinPhi0 = py / pt;
62 
63  // Passive rotation matrix by phi0:
64  jacobianRot(iX, iX) = cosPhi0;
65  jacobianRot(iX, iY) = sinPhi0;
66  jacobianRot(iY, iX) = -sinPhi0;
67  jacobianRot(iY, iY) = cosPhi0;
68  jacobianRot(iZ, iZ) = 1.0;
69 
70  jacobianRot(iPx, iPx) = cosPhi0;
71  jacobianRot(iPx, iPy) = sinPhi0;
72  jacobianRot(iPy, iPx) = -sinPhi0;
73  jacobianRot(iPy, iPy) = cosPhi0;
74  jacobianRot(iPz, iPz) = 1.0;
75 
76  // 2. Translate to perigee parameters on the position
77  const double pz = positionAndMomentum(5);
78  const double invPt = 1 / pt;
79  const double invPtSquared = invPt * invPt;
80  Eigen::Matrix<double, 5, 6> jacobianToHelixParameters = Eigen::Matrix<double, 5, 6>::Zero(5, 6);
81  jacobianToHelixParameters(iD0, iY) = -1;
82  jacobianToHelixParameters(iPhi0, iX) = charge * invPt / alpha;
83  jacobianToHelixParameters(iPhi0, iPy) = invPt;
84  jacobianToHelixParameters(iOmega, iPx) = -charge * invPtSquared / alpha;
85  jacobianToHelixParameters(iTanLambda, iPx) = - pz * invPtSquared;
86  jacobianToHelixParameters(iTanLambda, iPz) = invPt;
87  jacobianToHelixParameters(iZ0, iX) = - pz * invPt;
88  jacobianToHelixParameters(iZ0, iZ) = 1;
89  //
90  jacobian = jacobianToHelixParameters * jacobianRot;
91 
92  }
93 
94  std::string HelixUtils::helixParName(int i)
95  {
96  std::string rc ;
97  switch (i) {
98  case 1 : rc = "d0 : " ; break ;
99  case 2 : rc = "phi0 : " ; break ;
100  case 3 : rc = "omega : " ; break ;
101  case 4 : rc = "z0 : " ; break ;
102  case 5 : rc = "tandip: " ; break ;
103  case 6 : rc = "L : " ; break ;
104  }
105  return rc ;
106  }
107 
108  std::string HelixUtils::vertexParName(int i)
109  {
110  std::string rc ;
111  switch (i) {
112  case 1 : rc = "x : " ; break ;
113  case 2 : rc = "y : " ; break ;
114  case 3 : rc = "z : " ; break ;
115  case 4 : rc = "px : " ; break ;
116  case 5 : rc = "py : " ; break ;
117  case 6 : rc = "pz : " ; break ;
118  }
119  return rc ;
120  }
121 
122  void HelixUtils::printVertexPar(const TVector3& position, const TVector3& momentum, int charge)
123  {
124  for (int i = 0; i < 3; ++i)
125  B2INFO(vertexParName(i + 1).c_str() << position[i]);
126  for (int i = 0; i < 3; ++i)
127  B2INFO(vertexParName(i + 4).c_str() << momentum[i]);
128  B2INFO("charge: " << charge);
129 
130  }
131 
132  void HelixUtils::getHelixAndJacobianFromVertexNumerical(const Eigen::Matrix<double, 1, 6>& positionAndMom,
133  int charge, double Bz,
134  Belle2::Helix& helix,
135  // cppcheck-suppress constParameter ; jacobian is updated below
136  Eigen::Matrix<double, 5, 6>& jacobian)
137  {
138 
139  TVector3 position(positionAndMom(0),
140  positionAndMom(1),
141  positionAndMom(2));
142 
143  TVector3 momentum(positionAndMom(3),
144  positionAndMom(4),
145  positionAndMom(5));
146 
147  helix = Belle2::Helix(position, momentum, charge, Bz);
148 
149  // numeric calculation of the jacobian
150  Belle2::Helix helixPlusDelta;
151 
152  double delta = 1e-5;// this is arbitrary, only needs to be small
153 
154  TVector3 postmp;
155  TVector3 momtmp;
156 
157  for (int jin = 0; jin < 6; ++jin) {
158  for (int i = 0; i < 3; ++i) {
159  postmp[i] = positionAndMom(i);
160  momtmp[i] = positionAndMom(i + 3);
161  }
162  if (jin < 3) {
163  postmp[jin] += delta;
164  } else {
165  momtmp[jin - 3] += delta;
166  }
167 
168  helixPlusDelta = Belle2::Helix(postmp, momtmp, charge, Bz);
169  jacobian(iD0, jin) = (helixPlusDelta.getD0() - helix.getD0()) / delta ;
170  jacobian(iPhi0, jin) = (helixPlusDelta.getPhi0() - helix.getPhi0()) / delta ;
171  jacobian(iOmega, jin) = (helixPlusDelta.getOmega() - helix.getOmega()) / delta ;
172  jacobian(iZ0, jin) = (helixPlusDelta.getZ0() - helix.getZ0()) / delta ;
173  jacobian(iTanLambda, jin) = (helixPlusDelta.getTanLambda() - helix.getTanLambda()) / delta ;
174 
175  // jacobian[iArcLength2D][jin] = (LPlusDelta - L) / delta ;
176  }
177  }
178 
180  const Eigen::Matrix<double, 1, 6>& positionAndMom,
181  int charge, double Bz,
182  const Belle2::Helix& helix,
183  // cppcheck-suppress constParameter ; jacobian is assigned new matrix elements below
184  Eigen::Matrix<double, 5, 6>& jacobian,
185  double delta
186  )
187  {
188  // numeric calculation of the jacobian
189  Belle2::Helix helixPlusDelta;
190 
191  TVector3 postmp;
192  TVector3 momtmp;
193 
194  for (int jin = 0; jin < 6; ++jin) {
195  for (int i = 0; i < 3; ++i) {
196  postmp[i] = positionAndMom(i);
197  momtmp[i] = positionAndMom(i + 3);
198  }
199 
200  if (jin < 3) {
201  postmp[jin] += delta;
202  } else {
203  momtmp[jin - 3] += delta;
204  }
205 
206  helixPlusDelta = Belle2::Helix(postmp, momtmp, charge, Bz);
207  jacobian(iD0, jin) = (helixPlusDelta.getD0() - helix.getD0()) / delta ;
208  jacobian(iPhi0, jin) = (helixPlusDelta.getPhi0() - helix.getPhi0()) / delta ;
209  jacobian(iOmega, jin) = (helixPlusDelta.getOmega() - helix.getOmega()) / delta ;
210  jacobian(iZ0, jin) = (helixPlusDelta.getZ0() - helix.getZ0()) / delta ;
211  jacobian(iTanLambda, jin) = (helixPlusDelta.getTanLambda() - helix.getTanLambda()) / delta ;
212  }
213 
214  }
215 
216  inline double sqr(double x) { return x * x ; }
217 
218  double HelixUtils::phidomain(const double phi)
219  {
220  double rc = phi ;
221  if (phi < -TMath::Pi()) rc += TMath::TwoPi();
222  else if (phi > TMath::Pi()) rc -= TMath::TwoPi();
223  return rc ;
224  }
225 
226  //POCA between two tracks
227  double HelixUtils::helixPoca(const Belle2::Helix& helix1,
228  const Belle2::Helix& helix2,
229  double& flt1, double& flt2,
230  TVector3& vertex, bool parallel)
231  {
232 
233  double d0_1 = helix1.getD0();
234  double phi0_1 = helix1.getPhi0();
235  double omega_1 = helix1.getOmega();
236  double z0_1 = helix1.getZ0();
237  double tandip_1 = helix1.getTanLambda();
238  double cosdip_1 = cos(atan(tandip_1)) ; // can do that faster
239 
240  double d0_2 = helix2.getD0();
241  double phi0_2 = helix2.getPhi0();
242  double omega_2 = helix2.getOmega();
243  double z0_2 = helix2.getZ0();
244  double tandip_2 = helix2.getTanLambda();
245  double cosdip_2 = cos(atan(tandip_2)) ; // can do that faster
246 
247  double r_1 = 1 / omega_1 ;
248  double r_2 = 1 / omega_2 ;
249 
250  double x0_1 = - (r_1 + d0_1) * sin(phi0_1) ;
251  double y0_1 = (r_1 + d0_1) * cos(phi0_1) ;
252 
253  double x0_2 = - (r_2 + d0_2) * sin(phi0_2) ;
254  double y0_2 = (r_2 + d0_2) * cos(phi0_2) ;
255 
256  double deltax = x0_2 - x0_1 ;
257  double deltay = y0_2 - y0_1 ;
258 
259  double phi1[2] ;
260  double phi2[2] ;
261  int nsolutions = 1;
262 
263  // the phi of the 'intersection'.
264  const double pi = TMath::Pi();
265  double phi = - atan2(deltax, deltay) ;
266  double phinot = phi > 0 ? phi - pi : phi + pi ;
267  phi1[0] = r_1 < 0 ? phi : phinot ;
268  phi2[0] = r_2 > 0 ? phi : phinot ;
269 
270  double R1 = fabs(r_1) ;
271  double R2 = fabs(r_2) ;
272  double Rmin = R1 < R2 ? R1 : R2 ;
273  double Rmax = R1 > R2 ? R1 : R2 ;
274  double dX = sqrt(deltax * deltax + deltay * deltay) ;
275 
276  if (!parallel && dX + Rmin > Rmax && dX < R1 + R2) {
277  // there are two solutions
278  nsolutions = 2 ;
279  double ddphi1 = acos((dX * dX - R2 * R2 + R1 * R1) / (2.*dX * R1)) ;
280  phi1[1] = phidomain(phi1[0] + ddphi1) ;
281  phi1[0] = phidomain(phi1[0] - ddphi1) ;
282 
283  double ddphi2 = acos((dX * dX - R1 * R1 + R2 * R2) / (2.*dX * R2)) ;
284  phi2[1] = phidomain(phi2[0] - ddphi2) ;
285  phi2[0] = phidomain(phi2[0] + ddphi2) ;
286 
287  } else if (dX < Rmax) {
288  if (R1 > R2) phi2[0] = r_2 < 0 ? phi : phinot ;
289  else phi1[0] = r_1 < 0 ? phi : phinot ;
290  }
291 
292  // find the best solution for z by running multiples of 2_pi
293  double z1(0), z2(0) ;
294  bool first(true) ;
295  int ibest = 0;
296  const int ncirc(2) ;
297  for (int i = 0; i < nsolutions; ++i) {
298  double dphi1 = phidomain(phi1[i] - phi0_1) ;
299  double dphi2 = phidomain(phi2[i] - phi0_2) ;
300  for (int n1 = 1 - ncirc; n1 <= 1 + ncirc ; ++n1) {
301  double l1 = (dphi1 + n1 * TMath::TwoPi()) / omega_1 ;
302  double tmpz1 = (z0_1 + l1 * tandip_1) ;
303  if (n1 == 0 || fabs(tmpz1) < 100) {
304  for (int n2 = 1 - ncirc ; n2 <= 1 + ncirc; ++n2) {
305  double l2 = (dphi2 + n2 * TMath::TwoPi()) / omega_2 ;
306  double tmpz2 = (z0_2 + l2 * tandip_2) ;
307  if (n2 == 0 || fabs(tmpz2) < 100) {
308  if (first || fabs(tmpz1 - tmpz2) < fabs(z1 - z2)) {
309  ibest = i ;
310  first = false ;
311  z1 = tmpz1 ;
312  z2 = tmpz2 ;
313  flt1 = l1 / cosdip_1 ;
314  flt2 = l2 / cosdip_2 ;
315  }
316  }
317  }
318  }
319  }
320  }
321 
322  double x1 = r_1 * sin(phi1[ibest]) + x0_1 ;
323  double y1 = -r_1 * cos(phi1[ibest]) + y0_1 ;
324 
325  double x2 = r_2 * sin(phi2[ibest]) + x0_2 ;
326  double y2 = -r_2 * cos(phi2[ibest]) + y0_2 ;
327 
328  vertex.SetX(0.5 * (x1 + x2));
329  vertex.SetY(0.5 * (y1 + y2));
330  vertex.SetZ(0.5 * (z1 + z2));
331 
332  return sqrt(sqr(x2 - x1) + sqr(y2 - y1) + sqr(z2 - z1)) ;
333  }
334 
335  //POCA between a track and a point
337  const TVector3& point,
338  double& flt)
339  {
340  double d0 = helix.getD0();
341  double phi0 = helix.getPhi0();
342  double omega = helix.getOmega();
343  double z0 = helix.getZ0();
344  double tandip = helix.getTanLambda();
345  double cosdip = cos(atan(tandip)) ; // can do that faster
346 
347  double r = 1 / omega ;
348 
349  double x0 = - (r + d0) * sin(phi0) ;
350  double y0 = (r + d0) * cos(phi0) ;
351 
352  double deltax = x0 - point.X() ;
353  double deltay = y0 - point.Y() ;
354 
355  const double pi = TMath::Pi();
356  double phi = - atan2(deltax, deltay) ;
357  if (r < 0) phi = phi > 0 ? phi - pi : phi + pi ;
358 
359  // find the best solution for z by running multiples of 2_pi
360  double x = r * sin(phi) + x0 ;
361  double y = -r * cos(phi) + y0 ;
362  double z(0) ;
363  bool first(true) ;
364  const int ncirc(2) ;
365  double dphi = phidomain(phi - phi0) ;
366  for (int n = 1 - ncirc; n <= 1 + ncirc ; ++n) {
367  double l = (dphi + n * TMath::TwoPi()) / omega ;
368  double tmpz = (z0 + l * tandip) ;
369  if (first || fabs(tmpz - point.z()) < fabs(z - point.z())) {
370  first = false ;
371  z = tmpz ;
372  flt = l / cosdip ;
373  }
374  }
375  return sqrt(sqr(x - point.x()) + sqr(y - point.y()) + sqr(z - point.z())) ;
376  }
377 
378  // cppcheck-suppress constParameter ; jacobian is clearly updated in the function
379  void HelixUtils::getJacobianToCartesianFrameworkHelix(Eigen::Matrix<double, 5, 6>& jacobian,
380  const double x,
381  const double y,
382  const double z __attribute__((unused)),
383  const double px,
384  const double py,
385  const double pz,
386  const double bfield,
387  const double charge
388  )
389 
390  {
391  const double alpha = 1.0 / (bfield * Belle2::Const::speedOfLight) * 1E4;
392  const double aq = charge / alpha;
393 
394  const double pt = std::hypot(px, py);
395  const double pt2 = pt * pt;
396  const double pt3 = pt2 * pt;
397  const double aq2 = aq * aq;
398 
399  const double x2 = x * x;
400  const double y2 = y * y;
401  const double r = x2 + y2;
402 
403  const double px2 = px * px;
404  const double py2 = py * py;
405 
406  const double px0 = px - aq * y;
407  const double py0 = py + aq * x;
408 
409  const double pt02 = px0 * px0 + py0 * py0;
410  const double pt0 = std::sqrt(pt02);
411  double sqrt13 = pt0 / pt;
412 
413  // D d0 / Dx_i
414  jacobian(0, 0) = py0 / pt0;
415  jacobian(0, 1) = -px0 / pt0;
416  jacobian(0, 2) = 0;
417  jacobian(0, 3) = (-(y * (aq2 * r + 2 * aq * py * x + 2 * py2 * (1 + sqrt13))) - px * (2 * py * x * (1 + sqrt13) + aq * (y2 *
418  (-1 + sqrt13) + x2 * (1 + sqrt13)))) /
419  (pt2 * pt0 * (1 + sqrt13) * (1 + sqrt13));
420 
421  jacobian(0, 4) = (2 * px2 * x * (1 + sqrt13) + 2 * px * y * (py - aq * x + py * sqrt13) + aq * (aq * r * x - py * (x2 *
422  (-1 + sqrt13) + y2 * (1 + sqrt13)))) /
423  (pt2 * pt0 * (1 + sqrt13) * (1 + sqrt13));
424  jacobian(0, 5) = 0;
425 
426  // D phi0 / Dx_i0;
427  jacobian(1, 0) = aq * px0 / pt02;
428  jacobian(1, 1) = aq * py0 / pt02;
429  jacobian(1, 2) = 0;
430  jacobian(1, 3) = -py0 / pt02;
431  jacobian(1, 4) = px0 / pt02;
432  jacobian(1, 5) = 0;
433 
434  // D omega / Dx_i
435  jacobian(2, 0) = 0;
436  jacobian(2, 1) = 0;
437  jacobian(2, 2) = 0;
438  jacobian(2, 3) = - aq * px / pt3;
439  jacobian(2, 4) = - aq * py / pt3;
440  jacobian(2, 5) = 0;
441 
442  // D z0 / Dx_i
443  jacobian(3, 0) = -pz * px0 / pt02;
444  jacobian(3, 1) = -pz * py0 / pt02;
445  jacobian(3, 2) = 1;
446  jacobian(3, 3) = (pz * (px2 * x - py * (aq * r + py * x) + 2 * px * py * y)) / (pt2 * pt02);
447  jacobian(3, 4) = (pz * (px * (aq * r + 2 * py * x) - px2 * y + py2 * y)) / (pt2 * pt02);
448  jacobian(3, 5) = std::atan2(-(aq * (px * x + py * y)), (px2 + py * py0 - aq * px * y)) / aq; //pt on num. and denom cancels.
449 
450  // D tan lambda / Dx_i
451  jacobian(4, 0) = 0;
452  jacobian(4, 1) = 0;
453  jacobian(4, 2) = 0;
454  jacobian(4, 3) = -pz * px / pt3;
455  jacobian(4, 4) = -pz * py / pt3;
456  jacobian(4, 5) = 1. / pt;
457  }
458 
459 }
Helix parameter class.
Definition: Helix.h:48
static const double speedOfLight
[cm/ns]
Definition: Const.h:575
static std::string vertexParName(int i)
map of the vertex parameters by list index
Definition: HelixUtils.cc:108
static void helixFromVertex(const Eigen::Matrix< double, 1, 6 > &positionAndMomentum, int charge, double Bz, Belle2::Helix &helix, double &L, Eigen::Matrix< double, 5, 6 > &jacobian)
vertex --> helix
Definition: HelixUtils.cc:30
static void getHelixAndJacobianFromVertexNumerical(const Eigen::Matrix< double, 1, 6 > &positionAndMom, int charge, double Bz, Belle2::Helix &helix, Eigen::Matrix< double, 5, 6 > &jacobian)
get helix and jacobian from a vertex
Definition: HelixUtils.cc:132
static void vertexFromHelix(const Belle2::Helix &helix, double L, double Bz, TVector3 &position, TVector3 &momentum, int &charge)
helix --> vertex
Definition: HelixUtils.cc:20
static void getJacobianFromVertexNumerical(const Eigen::Matrix< double, 1, 6 > &positionAndMom, int charge, double Bz, const Belle2::Helix &helix, Eigen::Matrix< double, 5, 6 > &jacobian, double delta=1e-5)
get jacobian from a vertex
Definition: HelixUtils.cc:179
static std::string helixParName(int i)
map of the helix parameters by list index
Definition: HelixUtils.cc:94
static void printVertexPar(const TVector3 &position, const TVector3 &momentum, int charge)
Print the vertex parameters.
Definition: HelixUtils.cc:122
static double phidomain(const double phi)
the domain of phi
Definition: HelixUtils.cc:218
static double helixPoca(const Belle2::Helix &helix1, const Belle2::Helix &helix2, double &flt1, double &flt2, TVector3 &vertex, bool parallel=false)
POCA between two tracks.
Definition: HelixUtils.cc:227
static void getJacobianToCartesianFrameworkHelix(Eigen::Matrix< double, 5, 6 > &jacobian, const double x, const double y, const double z, const double px, const double py, const double pz, const double bfield, const double charge)
get the jacobian dh={helix pars}/dx={x,y,z,px,py,pz} for the implementation of the framework helix.
Definition: HelixUtils.cc:379