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