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