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