Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-11-03 08:57:40

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