Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-20 07:58:16

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/EventData/TrackParameters.hpp"
0013 #include "Acts/EventData/detail/CorrectedTransformationFreeToBound.hpp"
0014 #include "Acts/MagneticField/MagneticFieldProvider.hpp"
0015 #include "Acts/Propagator/ConstrainedStep.hpp"
0016 #include "Acts/Propagator/EigenStepperDefaultExtension.hpp"
0017 #include "Acts/Propagator/NavigationTarget.hpp"
0018 #include "Acts/Propagator/PropagatorTraits.hpp"
0019 #include "Acts/Propagator/StepperOptions.hpp"
0020 #include "Acts/Propagator/StepperStatistics.hpp"
0021 #include "Acts/Propagator/detail/SteppingHelper.hpp"
0022 #include "Acts/Surfaces/Surface.hpp"
0023 #include "Acts/Utilities/Intersection.hpp"
0024 #include "Acts/Utilities/Result.hpp"
0025 
0026 #include <type_traits>
0027 
0028 namespace Acts {
0029 
0030 class IVolumeMaterial;
0031 
0032 /// @brief Runge-Kutta-Nystroem stepper based on Eigen implementation
0033 /// for the following ODE:
0034 ///
0035 /// r = (x,y,z)    ... global position
0036 /// T = (Ax,Ay,Az) ... momentum direction (normalized)
0037 ///
0038 /// dr/ds = T
0039 /// dT/ds = q/p * (T x B)
0040 ///
0041 /// with s being the arc length of the track, q the charge of the particle,
0042 /// p the momentum magnitude and B the magnetic field
0043 ///
0044 template <typename extension_t = EigenStepperDefaultExtension>
0045 class EigenStepper {
0046  public:
0047   /// Jacobian, Covariance and State definitions
0048   using Jacobian = BoundMatrix;
0049   /// Type alias for covariance matrix (bound square matrix)
0050   using Covariance = BoundSquareMatrix;
0051   /// Type alias for bound state tuple containing parameters, jacobian, and path
0052   /// length
0053   using BoundState = std::tuple<BoundTrackParameters, Jacobian, double>;
0054 
0055   struct Config {
0056     std::shared_ptr<const MagneticFieldProvider> bField;
0057   };
0058 
0059   struct Options : public StepperPlainOptions {
0060     Options(const GeometryContext& gctx, const MagneticFieldContext& mctx)
0061         : StepperPlainOptions(gctx, mctx) {}
0062 
0063     void setPlainOptions(const StepperPlainOptions& options) {
0064       static_cast<StepperPlainOptions&>(*this) = options;
0065     }
0066   };
0067 
0068   /// @brief State for track parameter propagation
0069   ///
0070   /// It contains the stepping information and is provided thread local
0071   /// by the propagator
0072   struct State {
0073     /// Constructor from the initial bound track parameters
0074     ///
0075     /// @param [in] optionsIn is the options object for the stepper
0076     /// @param [in] fieldCacheIn is the cache object for the magnetic field
0077     ///
0078     /// @note the covariance matrix is copied when needed
0079     State(const Options& optionsIn, MagneticFieldProvider::Cache fieldCacheIn)
0080         : options(optionsIn), fieldCache(std::move(fieldCacheIn)) {}
0081 
0082     /// Configuration options for the Eigen stepper
0083     Options options;
0084 
0085     /// Internal free vector parameters
0086     FreeVector pars = FreeVector::Zero();
0087 
0088     /// Particle hypothesis
0089     ParticleHypothesis particleHypothesis = ParticleHypothesis::pion();
0090 
0091     /// Covariance matrix (and indicator)
0092     /// associated with the initial error on track parameters
0093     bool covTransport = false;
0094     /// Covariance matrix for track parameter uncertainties
0095     Covariance cov = Covariance::Zero();
0096 
0097     /// The full jacobian of the transport entire transport
0098     Jacobian jacobian = Jacobian::Identity();
0099 
0100     /// Jacobian from local to the global frame
0101     BoundToFreeMatrix jacToGlobal = BoundToFreeMatrix::Zero();
0102 
0103     /// Pure transport jacobian part from runge kutta integration
0104     FreeMatrix jacTransport = FreeMatrix::Identity();
0105 
0106     /// The propagation derivative
0107     FreeVector derivative = FreeVector::Zero();
0108 
0109     /// Accummulated path length state
0110     double pathAccumulated = 0.;
0111 
0112     /// Total number of performed steps
0113     std::size_t nSteps = 0;
0114 
0115     /// Totoal number of attempted steps
0116     std::size_t nStepTrials = 0;
0117 
0118     /// Adaptive step size of the runge-kutta integration
0119     ConstrainedStep stepSize;
0120 
0121     /// Last performed step (for overstep limit calculation)
0122     double previousStepSize = 0.;
0123 
0124     /// This caches the current magnetic field cell and stays
0125     /// (and interpolates) within it as long as this is valid.
0126     /// See step() code for details.
0127     MagneticFieldProvider::Cache fieldCache;
0128 
0129     /// Algorithmic extension
0130     extension_t extension;
0131 
0132     /// @brief Storage of magnetic field and the sub steps during a RKN4 step
0133     struct {
0134       /// Magnetic field evaulations
0135       Vector3 B_first, B_middle, B_last;
0136       /// k_i of the RKN4 algorithm
0137       Vector3 k1, k2, k3, k4;
0138       /// k_i elements of the momenta
0139       std::array<double, 4> kQoP{};
0140     } stepData;
0141 
0142     /// Statistics of the stepper
0143     StepperStatistics statistics;
0144   };
0145 
0146   /// Constructor requires knowledge of the detector's magnetic field
0147   /// @param bField The magnetic field provider
0148   explicit EigenStepper(std::shared_ptr<const MagneticFieldProvider> bField);
0149 
0150   /// @brief Constructor with configuration
0151   ///
0152   /// @param [in] config The configuration of the stepper
0153   explicit EigenStepper(const Config& config) : m_bField(config.bField) {}
0154 
0155   /// Create a stepper state from given options
0156   /// @param options Configuration options for the stepper state
0157   /// @return Initialized stepper state object
0158   State makeState(const Options& options) const;
0159 
0160   /// Initialize the stepper state from bound track parameters
0161   /// @param state Stepper state to initialize
0162   /// @param par Bound track parameters to initialize from
0163   void initialize(State& state, const BoundTrackParameters& par) const;
0164 
0165   /// Initialize the stepper state from bound parameters and surface
0166   /// @param state Stepper state to initialize
0167   /// @param boundParams Vector of bound track parameters
0168   /// @param cov Optional covariance matrix
0169   /// @param particleHypothesis Particle hypothesis for the track
0170   /// @param surface Surface associated with the parameters
0171   void initialize(State& state, const BoundVector& boundParams,
0172                   const std::optional<BoundMatrix>& cov,
0173                   ParticleHypothesis particleHypothesis,
0174                   const Surface& surface) const;
0175 
0176   /// Get the field for the stepping, it checks first if the access is still
0177   /// within the Cell, and updates the cell if necessary.
0178   ///
0179   /// @param [in,out] state is the propagation state associated with the track
0180   ///                 the magnetic field cell is used (and potentially updated)
0181   /// @param [in] pos is the field position
0182   /// @return Magnetic field vector at the given position or error
0183   Result<Vector3> getField(State& state, const Vector3& pos) const {
0184     // get the field from the cell
0185     return m_bField->getField(pos, state.fieldCache);
0186   }
0187 
0188   /// Global particle position accessor
0189   ///
0190   /// @param state [in] The stepping state (thread-local cache)
0191   /// @return Current global position vector
0192   Vector3 position(const State& state) const {
0193     return state.pars.template segment<3>(eFreePos0);
0194   }
0195 
0196   /// Momentum direction accessor
0197   ///
0198   /// @param state [in] The stepping state (thread-local cache)
0199   /// @return Current normalized direction vector
0200   Vector3 direction(const State& state) const {
0201     return state.pars.template segment<3>(eFreeDir0);
0202   }
0203 
0204   /// QoP direction accessor
0205   ///
0206   /// @param state [in] The stepping state (thread-local cache)
0207   /// @return Charge over momentum (q/p) value
0208   double qOverP(const State& state) const { return state.pars[eFreeQOverP]; }
0209 
0210   /// Absolute momentum accessor
0211   ///
0212   /// @param state [in] The stepping state (thread-local cache)
0213   /// @return Absolute momentum magnitude
0214   double absoluteMomentum(const State& state) const {
0215     return particleHypothesis(state).extractMomentum(qOverP(state));
0216   }
0217 
0218   /// Momentum accessor
0219   ///
0220   /// @param state [in] The stepping state (thread-local cache)
0221   /// @return Current momentum vector
0222   Vector3 momentum(const State& state) const {
0223     return absoluteMomentum(state) * direction(state);
0224   }
0225 
0226   /// Charge access
0227   ///
0228   /// @param state [in] The stepping state (thread-local cache)
0229   /// @return Electric charge of the particle
0230   double charge(const State& state) const {
0231     return particleHypothesis(state).extractCharge(qOverP(state));
0232   }
0233 
0234   /// Particle hypothesis
0235   ///
0236   /// @param state [in] The stepping state (thread-local cache)
0237   /// @return Reference to the particle hypothesis used
0238   const ParticleHypothesis& particleHypothesis(const State& state) const {
0239     return state.particleHypothesis;
0240   }
0241 
0242   /// Time access
0243   ///
0244   /// @param state [in] The stepping state (thread-local cache)
0245   /// @return The time coordinate from the free parameters vector
0246   double time(const State& state) const { return state.pars[eFreeTime]; }
0247 
0248   /// Update surface status
0249   ///
0250   /// It checks the status to the reference surface & updates
0251   /// the step size accordingly
0252   ///
0253   /// @param [in,out] state The stepping state (thread-local cache)
0254   /// @param [in] surface The surface provided
0255   /// @param [in] index The surface intersection index
0256   /// @param [in] propDir The propagation direction
0257   /// @param [in] boundaryTolerance The boundary check for this status update
0258   /// @param [in] surfaceTolerance Surface tolerance used for intersection
0259   /// @param [in] stype The step size type to be set
0260   /// @param [in] logger A @c Logger instance
0261   /// @return Status of the intersection indicating whether surface was reached
0262   IntersectionStatus updateSurfaceStatus(
0263       State& state, const Surface& surface, std::uint8_t index,
0264       Direction propDir, const BoundaryTolerance& boundaryTolerance,
0265       double surfaceTolerance, ConstrainedStep::Type stype,
0266       const Logger& logger = getDummyLogger()) const {
0267     return detail::updateSingleSurfaceStatus<EigenStepper>(
0268         *this, state, surface, index, propDir, boundaryTolerance,
0269         surfaceTolerance, stype, logger);
0270   }
0271 
0272   /// Update step size
0273   ///
0274   /// This method intersects the provided surface and update the navigation
0275   /// step estimation accordingly (hence it changes the state). It also
0276   /// returns the status of the intersection to trigger onSurface in case
0277   /// the surface is reached.
0278   ///
0279   /// @param state [in,out] The stepping state (thread-local cache)
0280   /// @param target [in] The NavigationTarget
0281   /// @param direction [in] The propagation direction
0282   /// @param stype [in] The step size type to be set
0283   void updateStepSize(State& state, const NavigationTarget& target,
0284                       Direction direction, ConstrainedStep::Type stype) const {
0285     (void)direction;
0286     double stepSize = target.pathLength();
0287     updateStepSize(state, stepSize, stype);
0288   }
0289 
0290   /// Update step size - explicitly with a double
0291   ///
0292   /// @param state [in,out] The stepping state (thread-local cache)
0293   /// @param stepSize [in] The step size value
0294   /// @param stype [in] The step size type to be set
0295   void updateStepSize(State& state, double stepSize,
0296                       ConstrainedStep::Type stype) const {
0297     state.previousStepSize = state.stepSize.value();
0298     state.stepSize.update(stepSize, stype);
0299   }
0300 
0301   /// Get the step size
0302   ///
0303   /// @param state [in] The stepping state (thread-local cache)
0304   /// @param stype [in] The step size type to be returned
0305   /// @return Current step size for the specified constraint type
0306   double getStepSize(const State& state, ConstrainedStep::Type stype) const {
0307     return state.stepSize.value(stype);
0308   }
0309 
0310   /// Release the Step size
0311   ///
0312   /// @param state [in,out] The stepping state (thread-local cache)
0313   /// @param [in] stype The step size type to be released
0314   void releaseStepSize(State& state, ConstrainedStep::Type stype) const {
0315     state.stepSize.release(stype);
0316   }
0317 
0318   /// Output the Step Size - single component
0319   ///
0320   /// @param state [in,out] The stepping state (thread-local cache)
0321   /// @return String representation of the current step size
0322   std::string outputStepSize(const State& state) const {
0323     return state.stepSize.toString();
0324   }
0325 
0326   /// Create and return the bound state at the current position
0327   ///
0328   /// @brief This transports (if necessary) the covariance
0329   /// to the surface and creates a bound state. It does not check
0330   /// if the transported state is at the surface, this needs to
0331   /// be guaranteed by the propagator
0332   ///
0333   /// @param [in] state State that will be presented as @c BoundState
0334   /// @param [in] surface The surface to which we bind the state
0335   /// @param [in] transportCov Flag steering covariance transport
0336   /// @param [in] freeToBoundCorrection Correction for non-linearity effect during transform from free to bound
0337   ///
0338   /// @return A bound state:
0339   ///   - the parameters at the surface
0340   ///   - the stepwise jacobian towards it (from last bound)
0341   ///   - and the path length (from start - for ordering)
0342   Result<BoundState> boundState(
0343       State& state, const Surface& surface, bool transportCov = true,
0344       const FreeToBoundCorrection& freeToBoundCorrection =
0345           FreeToBoundCorrection(false)) const;
0346 
0347   /// @brief If necessary fill additional members needed for curvilinearState
0348   ///
0349   /// Compute path length derivatives in case they have not been computed
0350   /// yet, which is the case if no step has been executed yet.
0351   ///
0352   /// @param [in, out] state The state of the stepper
0353   /// @return true if nothing is missing after this call, false otherwise.
0354   bool prepareCurvilinearState(State& state) const;
0355 
0356   /// Create and return a curvilinear state at the current position
0357   ///
0358   /// @brief This transports (if necessary) the covariance
0359   /// to the current position and creates a curvilinear state.
0360   ///
0361   /// @param [in] state State that will be presented as @c CurvilinearState
0362   /// @param [in] transportCov Flag steering covariance transport
0363   ///
0364   /// @return A curvilinear state:
0365   ///   - the curvilinear parameters at given position
0366   ///   - the stepweise jacobian towards it (from last bound)
0367   ///   - and the path length (from start - for ordering)
0368   BoundState curvilinearState(State& state, bool transportCov = true) const;
0369 
0370   /// Method to update a stepper state to the some parameters
0371   ///
0372   /// @param [in,out] state State object that will be updated
0373   /// @param [in] freeParams Free parameters that will be written into @p state
0374   /// @param [in] boundParams Corresponding bound parameters used to update jacToGlobal in @p state
0375   /// @param [in] covariance The covariance that will be written into @p state
0376   /// @param [in] surface The surface used to update the jacToGlobal
0377   void update(State& state, const FreeVector& freeParams,
0378               const BoundVector& boundParams, const Covariance& covariance,
0379               const Surface& surface) const;
0380 
0381   /// Method to update the stepper state
0382   ///
0383   /// @param [in,out] state State object that will be updated
0384   /// @param [in] uposition the updated position
0385   /// @param [in] udirection the updated direction
0386   /// @param [in] qOverP the updated qOverP value
0387   /// @param [in] time the updated time value
0388   void update(State& state, const Vector3& uposition, const Vector3& udirection,
0389               double qOverP, double time) const;
0390 
0391   /// Method for on-demand transport of the covariance
0392   /// to a new curvilinear frame at current  position,
0393   /// or direction of the state
0394   ///
0395   /// @param [in,out] state State of the stepper
0396   void transportCovarianceToCurvilinear(State& state) const;
0397 
0398   /// Method for on-demand transport of the covariance
0399   /// to a new curvilinear frame at current position,
0400   /// or direction of the state
0401   ///
0402   /// @tparam surface_t the Surface type
0403   ///
0404   /// @param [in,out] state State of the stepper
0405   /// @param [in] surface is the surface to which the covariance is forwarded to
0406   /// @param [in] freeToBoundCorrection Correction for non-linearity effect during transform from free to bound
0407   /// @note no check is done if the position is actually on the surface
0408   void transportCovarianceToBound(
0409       State& state, const Surface& surface,
0410       const FreeToBoundCorrection& freeToBoundCorrection =
0411           FreeToBoundCorrection(false)) const;
0412 
0413   /// Perform a Runge-Kutta track parameter propagation step
0414   ///
0415   /// @param [in,out] state State of the stepper
0416   /// @param propDir is the direction of propagation
0417   /// @param material is the optional volume material we are stepping through.
0418   //         This is simply ignored if `nullptr`.
0419   /// @return the result of the step
0420   ///
0421   /// @note The state contains the desired step size. It can be negative during
0422   ///       backwards track propagation, and since we're using an adaptive
0423   ///       algorithm, it can be modified by the stepper class during
0424   ///       propagation.
0425   Result<double> step(State& state, Direction propDir,
0426                       const IVolumeMaterial* material) const;
0427 
0428   /// Method that reset the Jacobian to the Identity for when no bound state are
0429   /// available
0430   ///
0431   /// @param [in,out] state State of the stepper
0432   void setIdentityJacobian(State& state) const;
0433 
0434  protected:
0435   /// Magnetic field inside of the detector
0436   std::shared_ptr<const MagneticFieldProvider> m_bField;
0437 };
0438 
0439 template <>
0440 struct SupportsBoundParameters<EigenStepper<>> : public std::true_type {};
0441 
0442 }  // namespace Acts
0443 
0444 #include "Acts/Propagator/EigenStepper.ipp"