Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:10:57

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 #pragma once
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/TrackParametrization.hpp"
0013 #include "Acts/Utilities/VectorHelpers.hpp"
0014 
0015 #include <array>
0016 
0017 namespace Acts {
0018 
0019 /// @brief Default evaluator of the k_i's and elements of the transport matrix
0020 /// D of the RKN4 stepping. This is a pure implementation by textbook.
0021 struct EigenStepperDefaultExtension {
0022   /// @brief Evaluator of the k_i's of the RKN4. For the case of i = 0 this
0023   /// step sets up qop, too.
0024   ///
0025   /// @tparam i Index of the k_i, i = [0, 3]
0026   /// @tparam propagator_state_t Type of the state of the propagator
0027   /// @tparam stepper_t Type of the stepper
0028   /// @tparam navigator_t Type of the navigator
0029   ///
0030   /// @param [in] state State of the propagator
0031   /// @param [in] stepper Stepper of the propagation
0032   /// @param [out] knew Next k_i that is evaluated
0033   /// @param [in] bField B-Field at the evaluation position
0034   /// @param [out] kQoP k_i elements of the momenta
0035   /// @param [in] h Step size (= 0. ^ 0.5 * StepSize ^ StepSize)
0036   /// @param [in] kprev Evaluated k_{i - 1}
0037   ///
0038   /// @return Boolean flag if the calculation is valid
0039   template <int i, typename propagator_state_t, typename stepper_t,
0040             typename navigator_t>
0041   bool k(const propagator_state_t& state, const stepper_t& stepper,
0042          const navigator_t& /*navigator*/, Vector3& knew, const Vector3& bField,
0043          std::array<double, 4>& kQoP, const double h = 0.,
0044          const Vector3& kprev = Vector3::Zero())
0045     requires(i >= 0 && i <= 3)
0046   {
0047     auto qop = stepper.qOverP(state.stepping);
0048     // First step does not rely on previous data
0049     if constexpr (i == 0) {
0050       knew = qop * stepper.direction(state.stepping).cross(bField);
0051       kQoP = {0., 0., 0., 0.};
0052     } else {
0053       knew =
0054           qop * (stepper.direction(state.stepping) + h * kprev).cross(bField);
0055     }
0056     return true;
0057   }
0058 
0059   /// @brief Veto function after a RKN4 step was accepted by judging on the
0060   /// error of the step. Since the textbook does not deliver further vetos,
0061   /// this is a dummy function.
0062   ///
0063   /// @tparam propagator_state_t Type of the state of the propagator
0064   /// @tparam stepper_t Type of the stepper
0065   /// @tparam navigator_t Type of the navigator
0066   ///
0067   /// @param [in] state State of the propagator
0068   /// @param [in] stepper Stepper of the propagation
0069   /// @param [in] h Step size
0070   ///
0071   /// @return Boolean flag if the calculation is valid
0072   template <typename propagator_state_t, typename stepper_t,
0073             typename navigator_t>
0074   bool finalize(propagator_state_t& state, const stepper_t& stepper,
0075                 const navigator_t& /*navigator*/, const double h) const {
0076     propagateTime(state, stepper, h);
0077     return true;
0078   }
0079 
0080   /// @brief Veto function after a RKN4 step was accepted by judging on the
0081   /// error of the step. Since the textbook does not deliver further vetos,
0082   /// this is just for the evaluation of the transport matrix.
0083   ///
0084   /// @tparam propagator_state_t Type of the state of the propagator
0085   /// @tparam stepper_t Type of the stepper
0086   /// @tparam navigator_t Type of the navigator
0087   ///
0088   /// @param [in] state State of the propagator
0089   /// @param [in] stepper Stepper of the propagation
0090   /// @param [in] h Step size
0091   /// @param [out] D Transport matrix
0092   ///
0093   /// @return Boolean flag if the calculation is valid
0094   template <typename propagator_state_t, typename stepper_t,
0095             typename navigator_t>
0096   bool finalize(propagator_state_t& state, const stepper_t& stepper,
0097                 const navigator_t& /*navigator*/, const double h,
0098                 FreeMatrix& D) const {
0099     propagateTime(state, stepper, h);
0100     return transportMatrix(state, stepper, h, D);
0101   }
0102 
0103  private:
0104   /// @brief Propagation function for the time coordinate
0105   ///
0106   /// @tparam propagator_state_t Type of the state of the propagator
0107   /// @tparam stepper_t Type of the stepper
0108   ///
0109   /// @param [in, out] state State of the propagator
0110   /// @param [in] stepper Stepper of the propagation
0111   /// @param [in] h Step size
0112   template <typename propagator_state_t, typename stepper_t>
0113   void propagateTime(propagator_state_t& state, const stepper_t& stepper,
0114                      const double h) const {
0115     /// This evaluation is based on dt/ds = 1/v = 1/(beta * c) with the velocity
0116     /// v, the speed of light c and beta = v/c. This can be re-written as dt/ds
0117     /// = sqrt(m^2/p^2 + c^{-2}) with the mass m and the momentum p.
0118     auto m = stepper.particleHypothesis(state.stepping).mass();
0119     auto p = stepper.absoluteMomentum(state.stepping);
0120     auto dtds = std::sqrt(1 + m * m / (p * p));
0121     state.stepping.pars[eFreeTime] += h * dtds;
0122     if (state.stepping.covTransport) {
0123       state.stepping.derivative(3) = dtds;
0124     }
0125   }
0126 
0127   /// @brief Calculates the transport matrix D for the jacobian
0128   ///
0129   /// @tparam propagator_state_t Type of the state of the propagator
0130   /// @tparam stepper_t Type of the stepper
0131   ///
0132   /// @param [in] state State of the propagator
0133   /// @param [in] stepper Stepper of the propagation
0134   /// @param [in] h Step size
0135   /// @param [out] D Transport matrix
0136   ///
0137   /// @return Boolean flag if evaluation is valid
0138   template <typename propagator_state_t, typename stepper_t>
0139   bool transportMatrix(propagator_state_t& state, const stepper_t& stepper,
0140                        const double h, FreeMatrix& D) const {
0141     /// The calculations are based on ATL-SOFT-PUB-2009-002. The update of the
0142     /// Jacobian matrix is requires only the calculation of eq. 17 and 18.
0143     /// Since the terms of eq. 18 are currently 0, this matrix is not needed
0144     /// in the calculation. The matrix A from eq. 17 consists out of 3
0145     /// different parts. The first one is given by the upper left 3x3 matrix
0146     /// that are calculated by the derivatives dF/dT (called dFdT) and dG/dT
0147     /// (calls dGdT). The second is given by the top 3 lines of the rightmost
0148     /// column. This is calculated by dFdL and dGdL. The remaining non-zero term
0149     /// is calculated directly. The naming of the variables is explained in eq.
0150     /// 11 and are directly related to the initial problem in eq. 7.
0151     /// The evaluation is based by propagating the parameters T and lambda as
0152     /// given in eq. 16 and evaluating the derivations for matrix A.
0153     /// @note The translation for u_{n+1} in eq. 7 is in this case a
0154     /// 3-dimensional vector without a dependency of Lambda or lambda neither in
0155     /// u_n nor in u_n'. The second and fourth eq. in eq. 14 have the constant
0156     /// offset matrices h * Id and Id respectively. This involves that the
0157     /// constant offset does not exist for rectangular matrix dGdu' (due to the
0158     /// missing Lambda part) and only exists for dFdu' in dlambda/dlambda.
0159 
0160     auto m = state.stepping.particleHypothesis.mass();
0161     auto& sd = state.stepping.stepData;
0162     auto dir = stepper.direction(state.stepping);
0163     auto qop = stepper.qOverP(state.stepping);
0164     auto p = stepper.absoluteMomentum(state.stepping);
0165     auto dtds = std::sqrt(1 + m * m / (p * p));
0166 
0167     D = FreeMatrix::Identity();
0168 
0169     double half_h = h * 0.5;
0170     // This sets the reference to the sub matrices
0171     // dFdx is already initialised as (3x3) idendity
0172     auto dFdT = D.block<3, 3>(0, 4);
0173     auto dFdL = D.block<3, 1>(0, 7);
0174     // dGdx is already initialised as (3x3) zero
0175     auto dGdT = D.block<3, 3>(4, 4);
0176     auto dGdL = D.block<3, 1>(4, 7);
0177 
0178     SquareMatrix3 dk1dT = SquareMatrix3::Zero();
0179     SquareMatrix3 dk2dT = SquareMatrix3::Identity();
0180     SquareMatrix3 dk3dT = SquareMatrix3::Identity();
0181     SquareMatrix3 dk4dT = SquareMatrix3::Identity();
0182 
0183     Vector3 dk1dL = Vector3::Zero();
0184     Vector3 dk2dL = Vector3::Zero();
0185     Vector3 dk3dL = Vector3::Zero();
0186     Vector3 dk4dL = Vector3::Zero();
0187 
0188     // For the case without energy loss
0189     dk1dL = dir.cross(sd.B_first);
0190     dk2dL = (dir + half_h * sd.k1).cross(sd.B_middle) +
0191             qop * half_h * dk1dL.cross(sd.B_middle);
0192     dk3dL = (dir + half_h * sd.k2).cross(sd.B_middle) +
0193             qop * half_h * dk2dL.cross(sd.B_middle);
0194     dk4dL =
0195         (dir + h * sd.k3).cross(sd.B_last) + qop * h * dk3dL.cross(sd.B_last);
0196 
0197     dk1dT(0, 1) = sd.B_first.z();
0198     dk1dT(0, 2) = -sd.B_first.y();
0199     dk1dT(1, 0) = -sd.B_first.z();
0200     dk1dT(1, 2) = sd.B_first.x();
0201     dk1dT(2, 0) = sd.B_first.y();
0202     dk1dT(2, 1) = -sd.B_first.x();
0203     dk1dT *= qop;
0204 
0205     dk2dT += half_h * dk1dT;
0206     dk2dT = qop * VectorHelpers::cross(dk2dT, sd.B_middle);
0207 
0208     dk3dT += half_h * dk2dT;
0209     dk3dT = qop * VectorHelpers::cross(dk3dT, sd.B_middle);
0210 
0211     dk4dT += h * dk3dT;
0212     dk4dT = qop * VectorHelpers::cross(dk4dT, sd.B_last);
0213 
0214     dFdT.setIdentity();
0215     dFdT += h / 6. * (dk1dT + dk2dT + dk3dT);
0216     dFdT *= h;
0217 
0218     dFdL = (h * h) / 6. * (dk1dL + dk2dL + dk3dL);
0219 
0220     dGdT += h / 6. * (dk1dT + 2. * (dk2dT + dk3dT) + dk4dT);
0221 
0222     dGdL = h / 6. * (dk1dL + 2. * (dk2dL + dk3dL) + dk4dL);
0223 
0224     D(3, 7) = h * m * m * qop / dtds;
0225     return true;
0226   }
0227 };
0228 
0229 }  // namespace Acts