Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-25 07:55:49

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/NumericalTrackLinearizer.hpp"
0010 
0011 #include "Acts/EventData/TrackParameters.hpp"
0012 #include "Acts/Propagator/PropagatorOptions.hpp"
0013 #include "Acts/Utilities/Intersection.hpp"
0014 #include "Acts/Utilities/UnitVectors.hpp"
0015 #include "Acts/Vertexing/LinearizerTrackParameters.hpp"
0016 
0017 #include <numbers>
0018 
0019 Acts::Result<Acts::LinearizedTrack>
0020 Acts::NumericalTrackLinearizer::linearizeTrack(
0021     const BoundTrackParameters& params, double linPointTime,
0022     const Surface& perigeeSurface, const Acts::GeometryContext& gctx,
0023     const Acts::MagneticFieldContext& mctx,
0024     MagneticFieldProvider::Cache& /*fieldCache*/) const {
0025   // Create propagator options
0026   PropagatorPlainOptions pOptions(gctx, mctx);
0027 
0028   // Length scale at which we consider to be sufficiently close to the Perigee
0029   // surface to skip the propagation.
0030   pOptions.surfaceTolerance = m_cfg.targetTolerance;
0031 
0032   // Get intersection of the track with the Perigee if the particle would
0033   // move on a straight line.
0034   // This allows us to determine whether we need to propagate the track
0035   // forward or backward to arrive at the PCA.
0036   Intersection3D intersection =
0037       perigeeSurface
0038           .intersect(gctx, params.position(gctx), params.direction(),
0039                      BoundaryTolerance::Infinite())
0040           .closest();
0041 
0042   // Setting the propagation direction using the intersection length from
0043   // above.
0044   // We handle zero path length as forward propagation, but we could actually
0045   // skip the whole propagation in this case.
0046   pOptions.direction =
0047       Direction::fromScalarZeroAsPositive(intersection.pathLength());
0048 
0049   // Propagate to the PCA of the reference point
0050   auto result =
0051       m_cfg.propagator->propagateToSurface(params, perigeeSurface, pOptions);
0052   if (!result.ok()) {
0053     return result.error();
0054   }
0055 
0056   // Extracting the Perigee representation of the track wrt the reference point
0057   auto endParams = *result;
0058   BoundVector perigeeParams = endParams.parameters();
0059 
0060   // Covariance and weight matrix at the PCA to the reference point
0061   BoundSquareMatrix parCovarianceAtPCA = endParams.covariance().value();
0062   BoundSquareMatrix weightAtPCA = parCovarianceAtPCA.inverse();
0063 
0064   // Vector containing the track parameters at the PCA
0065   // Note that we parametrize the track using the following parameters:
0066   // (x, y, z, t, phi, theta, q/p),
0067   // where
0068   // -) (x, y, z, t) is the global 4D position of the PCA
0069   // -) phi and theta are the global angles of the momentum at the PCA
0070   // -) q/p is the charge divided by the total momentum at the PCA
0071   Acts::ActsVector<eLinSize> paramVec;
0072 
0073   // 4D PCA and the momentum of the track at the PCA
0074   // These quantities will be used in the computation of the constant term in
0075   // the Taylor expansion
0076   Vector4 pca;
0077   Vector3 momentumAtPCA;
0078 
0079   // Fill "paramVec", "pca", and "momentumAtPCA"
0080   {
0081     Vector3 globalCoords = endParams.position(gctx);
0082     double globalTime = endParams.time();
0083     double phi = perigeeParams(BoundIndices::eBoundPhi);
0084     double theta = perigeeParams(BoundIndices::eBoundTheta);
0085     double qOvP = perigeeParams(BoundIndices::eBoundQOverP);
0086 
0087     paramVec << globalCoords, globalTime, phi, theta, qOvP;
0088     pca << globalCoords, globalTime;
0089     momentumAtPCA << phi, theta, qOvP;
0090   }
0091 
0092   // Complete Jacobian (consists of positionJacobian and momentumJacobian)
0093   ActsMatrix<eBoundSize, eLinSize> completeJacobian =
0094       ActsMatrix<eBoundSize, eLinSize>::Zero(eBoundSize, eLinSize);
0095 
0096   // Perigee parameters wrt the reference point after wiggling
0097   BoundVector newPerigeeParams;
0098 
0099   // Check if wiggled angle theta are within definition range [0, pi]
0100   if (paramVec(eLinTheta) + m_cfg.delta > std::numbers::pi) {
0101     ACTS_ERROR(
0102         "Wiggled theta outside range, choose a smaller wiggle (i.e., delta)! "
0103         "You might need to decrease targetTolerance as well.");
0104   }
0105 
0106   // Wiggling each of the parameters at the PCA and computing the Perigee
0107   // parametrization of the resulting new track. This allows us to approximate
0108   // the numerical derivatives.
0109   for (unsigned int i = 0; i < eLinSize; i++) {
0110     Acts::ActsVector<eLinSize> paramVecCopy = paramVec;
0111     // Wiggle
0112     paramVecCopy(i) += m_cfg.delta;
0113 
0114     // Create curvilinear track object from our parameters. This is needed for
0115     // the propagation. Note that we work without covariance since we don't need
0116     // it to compute the derivative.
0117     Vector3 wiggledDir = makeDirectionFromPhiTheta(paramVecCopy(eLinPhi),
0118                                                    paramVecCopy(eLinTheta));
0119     // Since we work in 4D we have eLinPosSize = 4
0120     BoundTrackParameters wiggledCurvilinearParams =
0121         BoundTrackParameters::createCurvilinear(
0122             paramVecCopy.template head<eLinPosSize>(), wiggledDir,
0123             paramVecCopy(eLinQOverP), std::nullopt, ParticleHypothesis::pion());
0124 
0125     // Obtain propagation direction
0126     intersection = perigeeSurface
0127                        .intersect(gctx, paramVecCopy.template head<3>(),
0128                                   wiggledDir, BoundaryTolerance::Infinite())
0129                        .closest();
0130     pOptions.direction =
0131         Direction::fromScalarZeroAsPositive(intersection.pathLength());
0132 
0133     // Propagate to the new PCA and extract Perigee parameters
0134     auto newResult = m_cfg.propagator->propagateToSurface(
0135         wiggledCurvilinearParams, perigeeSurface, pOptions);
0136     if (!newResult.ok()) {
0137       return newResult.error();
0138     }
0139     newPerigeeParams = newResult->parameters();
0140 
0141     // Computing the numerical derivatives and filling the Jacobian
0142     completeJacobian.array().col(i) =
0143         (newPerigeeParams - perigeeParams) / m_cfg.delta;
0144     // We need to account for the periodicity of phi. We overwrite the
0145     // previously computed value for better readability.
0146     completeJacobian(eLinPhi, i) =
0147         Acts::detail::difference_periodic(newPerigeeParams(eLinPhi),
0148                                           perigeeParams(eLinPhi),
0149                                           2 * std::numbers::pi) /
0150         m_cfg.delta;
0151   }
0152 
0153   // Extracting positionJacobian and momentumJacobian from the complete Jacobian
0154   ActsMatrix<eBoundSize, eLinPosSize> positionJacobian =
0155       completeJacobian.block<eBoundSize, eLinPosSize>(0, 0);
0156   ActsMatrix<eBoundSize, eLinMomSize> momentumJacobian =
0157       completeJacobian.block<eBoundSize, eLinMomSize>(0, eLinPosSize);
0158 
0159   // Constant term of Taylor expansion (Eq. 5.38 in Ref. (1))
0160   BoundVector constTerm =
0161       perigeeParams - positionJacobian * pca - momentumJacobian * momentumAtPCA;
0162 
0163   Vector4 linPoint;
0164   linPoint.head<3>() = perigeeSurface.center(gctx);
0165   linPoint[3] = linPointTime;
0166 
0167   return LinearizedTrack(perigeeParams, parCovarianceAtPCA, weightAtPCA,
0168                          linPoint, positionJacobian, momentumJacobian, pca,
0169                          momentumAtPCA, constTerm);
0170 }