Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:11:32

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include "Acts/Vertexing/HelicalTrackLinearizer.hpp"
0010 
0011 #include "Acts/Propagator/PropagatorOptions.hpp"
0012 #include "Acts/Utilities/MathHelpers.hpp"
0013 #include "Acts/Vertexing/LinearizerTrackParameters.hpp"
0014 
0015 Acts::Result<Acts::LinearizedTrack>
0016 Acts::HelicalTrackLinearizer::linearizeTrack(
0017     const BoundTrackParameters& params, double linPointTime,
0018     const Surface& perigeeSurface, const Acts::GeometryContext& gctx,
0019     const Acts::MagneticFieldContext& mctx,
0020     MagneticFieldProvider::Cache& fieldCache) const {
0021   // Create propagator options
0022   PropagatorPlainOptions pOptions(gctx, mctx);
0023 
0024   // Length scale at which we consider to be sufficiently close to the Perigee
0025   // surface to skip the propagation.
0026   pOptions.surfaceTolerance = m_cfg.targetTolerance;
0027 
0028   // Get intersection of the track with the Perigee if the particle would
0029   // move on a straight line.
0030   // This allows us to determine whether we need to propagate the track
0031   // forward or backward to arrive at the PCA.
0032   auto intersection =
0033       perigeeSurface
0034           .intersect(gctx, params.position(gctx), params.direction(),
0035                      BoundaryTolerance::Infinite())
0036           .closest();
0037 
0038   // Setting the propagation direction using the intersection length from
0039   // above
0040   // We handle zero path length as forward propagation, but we could actually
0041   // skip the whole propagation in this case
0042   pOptions.direction =
0043       Direction::fromScalarZeroAsPositive(intersection.pathLength());
0044 
0045   // Propagate to the PCA of the reference point
0046   const auto res =
0047       m_cfg.propagator->propagateToSurface(params, perigeeSurface, pOptions);
0048   if (!res.ok()) {
0049     return res.error();
0050   }
0051   const auto& endParams = *res;
0052 
0053   // Extracting the track parameters at said PCA - this corresponds to the
0054   // Perigee representation of the track wrt the reference point
0055   BoundVector paramsAtPCA = endParams.parameters();
0056 
0057   // Extracting the 4D position of the PCA in global coordinates
0058   Vector4 pca = Vector4::Zero();
0059   {
0060     auto pos = endParams.position(gctx);
0061     pca[ePos0] = pos[ePos0];
0062     pca[ePos1] = pos[ePos1];
0063     pca[ePos2] = pos[ePos2];
0064     pca[eTime] = endParams.time();
0065   }
0066   BoundSquareMatrix parCovarianceAtPCA = endParams.covariance().value();
0067 
0068   // Extracting Perigee parameters and compute functions of them for later
0069   // usage
0070   double d0 = paramsAtPCA(BoundIndices::eBoundLoc0);
0071 
0072   double phi = paramsAtPCA(BoundIndices::eBoundPhi);
0073   double sinPhi = std::sin(phi);
0074   double cosPhi = std::cos(phi);
0075 
0076   double theta = paramsAtPCA(BoundIndices::eBoundTheta);
0077   double sinTheta = std::sin(theta);
0078   double tanTheta = std::tan(theta);
0079 
0080   // q over p
0081   double qOvP = paramsAtPCA(BoundIndices::eBoundQOverP);
0082   // Rest mass
0083   double m0 = params.particleHypothesis().mass();
0084   // Momentum
0085   double p = params.particleHypothesis().extractMomentum(qOvP);
0086 
0087   // Speed in units of c
0088   double beta = p / fastHypot(p, m0);
0089   // Transverse speed (i.e., speed in the x-y plane)
0090   double betaT = beta * sinTheta;
0091 
0092   // Momentum direction at the PCA
0093   Vector3 momentumAtPCA(phi, theta, qOvP);
0094 
0095   // Particle charge
0096   double absoluteCharge = params.particleHypothesis().absoluteCharge();
0097 
0098   // get the z-component of the B-field at the PCA
0099   auto field = m_cfg.bField->getField(VectorHelpers::position(pca), fieldCache);
0100   if (!field.ok()) {
0101     return field.error();
0102   }
0103   double Bz = (*field)[eZ];
0104 
0105   // Complete Jacobian (consists of positionJacobian and momentumJacobian)
0106   ActsMatrix<eBoundSize, eLinSize> completeJacobian =
0107       ActsMatrix<eBoundSize, eLinSize>::Zero(eBoundSize, eLinSize);
0108 
0109   // The particle moves on a straight trajectory if its charge is 0 or if there
0110   // is no B field. Conversely, if it has a charge and the B field is constant,
0111   // it moves on a helical trajectory.
0112   if (absoluteCharge == 0. || Bz == 0.) {
0113     // Derivatives can be found in Eqs. 5.39 and 5.40 of Ref. (1).
0114     // Since we propagated to the PCA (point P in Ref. (1)), we evaluate the
0115     // Jacobians there. One can show that, in this case, RTilde = 0 and QTilde =
0116     // -d0.
0117 
0118     // Derivatives of d0
0119     completeJacobian(eBoundLoc0, eLinPos0) = -sinPhi;
0120     completeJacobian(eBoundLoc0, eLinPos1) = cosPhi;
0121 
0122     // Derivatives of z0
0123     completeJacobian(eBoundLoc1, eLinPos0) = -cosPhi / tanTheta;
0124     completeJacobian(eBoundLoc1, eLinPos1) = -sinPhi / tanTheta;
0125     completeJacobian(eBoundLoc1, eLinPos2) = 1.;
0126     completeJacobian(eBoundLoc1, eLinPhi) = -d0 / tanTheta;
0127 
0128     // Derivatives of phi
0129     completeJacobian(eBoundPhi, eLinPhi) = 1.;
0130 
0131     // Derivatives of theta
0132     completeJacobian(eBoundTheta, eLinTheta) = 1.;
0133 
0134     // Derivatives of q/p
0135     completeJacobian(eBoundQOverP, eLinQOverP) = 1.;
0136 
0137     // Derivatives of time
0138     completeJacobian(eBoundTime, eLinPos0) = -cosPhi / betaT;
0139     completeJacobian(eBoundTime, eLinPos1) = -sinPhi / betaT;
0140     completeJacobian(eBoundTime, eLinTime) = 1.;
0141     completeJacobian(eBoundTime, eLinPhi) = -d0 / betaT;
0142   } else {
0143     // Helix radius
0144     double rho = sinTheta * (1. / qOvP) / Bz;
0145     // Sign of helix radius
0146     double h = (rho < 0.) ? -1 : 1;
0147 
0148     // Quantities from Eq. 5.34 in Ref. (1) (see .hpp)
0149     double X = pca(0) - perigeeSurface.center(gctx).x() + rho * sinPhi;
0150     double Y = pca(1) - perigeeSurface.center(gctx).y() - rho * cosPhi;
0151     double S2 = (X * X + Y * Y);
0152     // S is the 2D distance from the helix center to the reference point
0153     // in the x-y plane
0154     double S = std::sqrt(S2);
0155 
0156     double XoverS2 = X / S2;
0157     double YoverS2 = Y / S2;
0158     double rhoCotTheta = rho / tanTheta;
0159     double rhoOverBetaT = rho / betaT;
0160     // Absolute value of rho over S
0161     double absRhoOverS = h * rho / S;
0162 
0163     // Derivatives can be found in Eq. 5.36 in Ref. (1)
0164     // Since we propagated to the PCA (point P in Ref. (1)), the points
0165     // P and V coincide, and thus deltaPhi = 0.
0166     // One can show that if deltaPhi = 0 --> R = 0 and Q = h * S.
0167     // As a consequence, many terms of the B matrix vanish.
0168 
0169     // Derivatives of d0
0170     completeJacobian(eBoundLoc0, eLinPos0) = -h * X / S;
0171     completeJacobian(eBoundLoc0, eLinPos1) = -h * Y / S;
0172 
0173     // Derivatives of z0
0174     completeJacobian(eBoundLoc1, eLinPos0) = rhoCotTheta * YoverS2;
0175     completeJacobian(eBoundLoc1, eLinPos1) = -rhoCotTheta * XoverS2;
0176     completeJacobian(eBoundLoc1, eLinPos2) = 1.;
0177     completeJacobian(eBoundLoc1, eLinPhi) = rhoCotTheta * (1. - absRhoOverS);
0178 
0179     // Derivatives of phi
0180     completeJacobian(eBoundPhi, eLinPos0) = -YoverS2;
0181     completeJacobian(eBoundPhi, eLinPos1) = XoverS2;
0182     completeJacobian(eBoundPhi, eLinPhi) = absRhoOverS;
0183 
0184     // Derivatives of theta
0185     completeJacobian(eBoundTheta, eLinTheta) = 1.;
0186 
0187     // Derivatives of q/p
0188     completeJacobian(eBoundQOverP, eLinQOverP) = 1.;
0189 
0190     // Derivatives of time
0191     completeJacobian(eBoundTime, eLinPos0) = rhoOverBetaT * YoverS2;
0192     completeJacobian(eBoundTime, eLinPos1) = -rhoOverBetaT * XoverS2;
0193     completeJacobian(eBoundTime, eLinTime) = 1.;
0194     completeJacobian(eBoundTime, eLinPhi) = rhoOverBetaT * (1. - absRhoOverS);
0195   }
0196 
0197   // Extracting positionJacobian and momentumJacobian from the complete Jacobian
0198   ActsMatrix<eBoundSize, eLinPosSize> positionJacobian =
0199       completeJacobian.block<eBoundSize, eLinPosSize>(0, 0);
0200   ActsMatrix<eBoundSize, eLinMomSize> momentumJacobian =
0201       completeJacobian.block<eBoundSize, eLinMomSize>(0, eLinPosSize);
0202 
0203   // const term in Taylor expansion from Eq. 5.38 in Ref. (1)
0204   BoundVector constTerm =
0205       paramsAtPCA - positionJacobian * pca - momentumJacobian * momentumAtPCA;
0206 
0207   // The parameter weight
0208   BoundSquareMatrix weightAtPCA = parCovarianceAtPCA.inverse();
0209 
0210   Vector4 linPoint;
0211   linPoint.head<3>() = perigeeSurface.center(gctx);
0212   linPoint[3] = linPointTime;
0213 
0214   return LinearizedTrack(paramsAtPCA, parCovarianceAtPCA, weightAtPCA, linPoint,
0215                          positionJacobian, momentumJacobian, pca, momentumAtPCA,
0216                          constTerm);
0217 }