Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HelicalTrackLinearizer.ipp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file HelicalTrackLinearizer.ipp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019-2023 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
11 
12 template <typename propagator_t, typename propagator_options_t>
15  const BoundTrackParameters& params, double linPointTime,
16  const Surface& perigeeSurface, const Acts::GeometryContext& gctx,
17  const Acts::MagneticFieldContext& mctx, State& state) const {
18  // Create propagator options
19  propagator_options_t pOptions(gctx, mctx);
20 
21  // Length scale at which we consider to be sufficiently close to the Perigee
22  // surface to skip the propagation.
23  pOptions.targetTolerance = m_cfg.targetTolerance;
24 
25  // Get intersection of the track with the Perigee if the particle would
26  // move on a straight line.
27  // This allows us to determine whether we need to propagate the track
28  // forward or backward to arrive at the PCA.
29  auto intersection =
30  perigeeSurface
31  .intersect(gctx, params.position(gctx), params.direction(), false)
32  .closest();
33 
34  // Setting the propagation direction using the intersection length from
35  // above
36  // We handle zero path length as forward propagation, but we could actually
37  // skip the whole propagation in this case
38  pOptions.direction =
39  Direction::fromScalarZeroAsPositive(intersection.pathLength());
40 
41  // Propagate to the PCA of the reference point
42  auto result = m_cfg.propagator->propagate(params, perigeeSurface, pOptions);
43  if (not result.ok()) {
44  return result.error();
45  }
46 
47  // Extracting the track parameters at said PCA - this corresponds to the
48  // Perigee representation of the track wrt the reference point
49  const auto& endParams = *result->endParameters;
50  BoundVector paramsAtPCA = endParams.parameters();
51 
52  // Extracting the 4D position of the PCA in global coordinates
53  Vector4 pca = Vector4::Zero();
54  {
55  auto pos = endParams.position(gctx);
56  pca[ePos0] = pos[ePos0];
57  pca[ePos1] = pos[ePos1];
58  pca[ePos2] = pos[ePos2];
59  pca[eTime] = endParams.time();
60  }
61  BoundSquareMatrix parCovarianceAtPCA = endParams.covariance().value();
62 
63  // Extracting Perigee parameters and compute functions of them for later
64  // usage
65  ActsScalar d0 = paramsAtPCA(BoundIndices::eBoundLoc0);
66 
67  ActsScalar phi = paramsAtPCA(BoundIndices::eBoundPhi);
68  ActsScalar sinPhi = std::sin(phi);
69  ActsScalar cosPhi = std::cos(phi);
70 
72  ActsScalar sinTheta = std::sin(theta);
73  ActsScalar tanTheta = std::tan(theta);
74 
75  // q over p
76  ActsScalar qOvP = paramsAtPCA(BoundIndices::eBoundQOverP);
77  // Rest mass
78  ActsScalar m0 = params.particleHypothesis().mass();
79  // Momentum
80  ActsScalar p = params.particleHypothesis().extractMomentum(qOvP);
81 
82  // Speed in units of c
83  ActsScalar beta = p / std::hypot(p, m0);
84  // Transverse speed (i.e., speed in the x-y plane)
85  ActsScalar betaT = beta * sinTheta;
86 
87  // Momentum direction at the PCA
88  Vector3 momentumAtPCA(phi, theta, qOvP);
89 
90  // Particle charge
91  ActsScalar absoluteCharge = params.particleHypothesis().absoluteCharge();
92 
93  // get the z-component of the B-field at the PCA
94  auto field =
95  m_cfg.bField->getField(VectorHelpers::position(pca), state.fieldCache);
96  if (!field.ok()) {
97  return field.error();
98  }
99  ActsScalar Bz = (*field)[eZ];
100 
101  // Complete Jacobian (consists of positionJacobian and momentumJacobian)
102  ActsMatrix<eBoundSize, eLinSize> completeJacobian =
103  ActsMatrix<eBoundSize, eLinSize>::Zero(eBoundSize, eLinSize);
104 
105  // The particle moves on a straight trajectory if its charge is 0 or if there
106  // is no B field. Conversely, if it has a charge and the B field is constant,
107  // it moves on a helical trajectory.
108  if (absoluteCharge == 0. or Bz == 0.) {
109  // Derivatives can be found in Eqs. 5.39 and 5.40 of Ref. (1).
110  // Since we propagated to the PCA (point P in Ref. (1)), we evaluate the
111  // Jacobians there. One can show that, in this case, RTilde = 0 and QTilde =
112  // -d0.
113 
114  // Derivatives of d0
115  completeJacobian(eBoundLoc0, eLinPos0) = -sinPhi;
116  completeJacobian(eBoundLoc0, eLinPos1) = cosPhi;
117 
118  // Derivatives of z0
119  completeJacobian(eBoundLoc1, eLinPos0) = -cosPhi / tanTheta;
120  completeJacobian(eBoundLoc1, eLinPos1) = -sinPhi / tanTheta;
121  completeJacobian(eBoundLoc1, eLinPos2) = 1.;
122  completeJacobian(eBoundLoc1, eLinPhi) = -d0 / tanTheta;
123 
124  // Derivatives of phi
125  completeJacobian(eBoundPhi, eLinPhi) = 1.;
126 
127  // Derivatives of theta
128  completeJacobian(eBoundTheta, eLinTheta) = 1.;
129 
130  // Derivatives of q/p
131  completeJacobian(eBoundQOverP, eLinQOverP) = 1.;
132 
133  // Derivatives of time
134  completeJacobian(eBoundTime, eLinPos0) = -cosPhi / betaT;
135  completeJacobian(eBoundTime, eLinPos1) = -sinPhi / betaT;
136  completeJacobian(eBoundTime, eLinTime) = 1.;
137  completeJacobian(eBoundTime, eLinPhi) = -d0 / betaT;
138  } else {
139  // Helix radius
140  ActsScalar rho = sinTheta * (1. / qOvP) / Bz;
141  // Sign of helix radius
142  ActsScalar h = (rho < 0.) ? -1 : 1;
143 
144  // Quantities from Eq. 5.34 in Ref. (1) (see .hpp)
145  ActsScalar X = pca(0) - perigeeSurface.center(gctx).x() + rho * sinPhi;
146  ActsScalar Y = pca(1) - perigeeSurface.center(gctx).y() - rho * cosPhi;
147  ActsScalar S2 = (X * X + Y * Y);
148  // S is the 2D distance from the helix center to the reference point
149  // in the x-y plane
150  ActsScalar S = std::sqrt(S2);
151 
152  ActsScalar XoverS2 = X / S2;
153  ActsScalar YoverS2 = Y / S2;
154  ActsScalar rhoCotTheta = rho / tanTheta;
155  ActsScalar rhoOverBetaT = rho / betaT;
156  // Absolute value of rho over S
157  ActsScalar absRhoOverS = h * rho / S;
158 
159  // Derivatives can be found in Eq. 5.36 in Ref. (1)
160  // Since we propagated to the PCA (point P in Ref. (1)), the points
161  // P and V coincide, and thus deltaPhi = 0.
162  // One can show that if deltaPhi = 0 --> R = 0 and Q = h * S.
163  // As a consequence, many terms of the B matrix vanish.
164 
165  // Derivatives of d0
166  completeJacobian(eBoundLoc0, eLinPos0) = -h * X / S;
167  completeJacobian(eBoundLoc0, eLinPos1) = -h * Y / S;
168 
169  // Derivatives of z0
170  completeJacobian(eBoundLoc1, eLinPos0) = rhoCotTheta * YoverS2;
171  completeJacobian(eBoundLoc1, eLinPos1) = -rhoCotTheta * XoverS2;
172  completeJacobian(eBoundLoc1, eLinPos2) = 1.;
173  completeJacobian(eBoundLoc1, eLinPhi) = rhoCotTheta * (1. - absRhoOverS);
174 
175  // Derivatives of phi
176  completeJacobian(eBoundPhi, eLinPos0) = -YoverS2;
177  completeJacobian(eBoundPhi, eLinPos1) = XoverS2;
178  completeJacobian(eBoundPhi, eLinPhi) = absRhoOverS;
179 
180  // Derivatives of theta
181  completeJacobian(eBoundTheta, eLinTheta) = 1.;
182 
183  // Derivatives of q/p
184  completeJacobian(eBoundQOverP, eLinQOverP) = 1.;
185 
186  // Derivatives of time
187  completeJacobian(eBoundTime, eLinPos0) = rhoOverBetaT * YoverS2;
188  completeJacobian(eBoundTime, eLinPos1) = -rhoOverBetaT * XoverS2;
189  completeJacobian(eBoundTime, eLinTime) = 1.;
190  completeJacobian(eBoundTime, eLinPhi) = rhoOverBetaT * (1. - absRhoOverS);
191  }
192 
193  // Extracting positionJacobian and momentumJacobian from the complete Jacobian
194  ActsMatrix<eBoundSize, eLinPosSize> positionJacobian =
195  completeJacobian.block<eBoundSize, eLinPosSize>(0, 0);
196  ActsMatrix<eBoundSize, eLinMomSize> momentumJacobian =
197  completeJacobian.block<eBoundSize, eLinMomSize>(0, eLinPosSize);
198 
199  // const term in Taylor expansion from Eq. 5.38 in Ref. (1)
200  BoundVector constTerm =
201  paramsAtPCA - positionJacobian * pca - momentumJacobian * momentumAtPCA;
202 
203  // The parameter weight
204  BoundSquareMatrix weightAtPCA = parCovarianceAtPCA.inverse();
205 
206  Vector4 linPoint;
207  linPoint.head<3>() = perigeeSurface.center(gctx);
208  linPoint[3] = linPointTime;
209 
210  return LinearizedTrack(paramsAtPCA, parCovarianceAtPCA, weightAtPCA, linPoint,
211  positionJacobian, momentumJacobian, pca, momentumAtPCA,
212  constTerm);
213 }