Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:09:18

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