Back to home page

EIC code displayed by LXR

 
 

    


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

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/Definitions/Direction.hpp"
0016 #include "Acts/Definitions/TrackParametrization.hpp"
0017 #include "Acts/EventData/TrackParameters.hpp"
0018 #include "Acts/EventData/detail/CorrectedTransformationFreeToBound.hpp"
0019 #include "Acts/MagneticField/NullBField.hpp"
0020 #include "Acts/Propagator/ConstrainedStep.hpp"
0021 #include "Acts/Propagator/PropagatorTraits.hpp"
0022 #include "Acts/Propagator/StepperOptions.hpp"
0023 #include "Acts/Propagator/StepperStatistics.hpp"
0024 #include "Acts/Propagator/detail/SteppingHelper.hpp"
0025 #include "Acts/Surfaces/BoundaryTolerance.hpp"
0026 #include "Acts/Surfaces/Surface.hpp"
0027 #include "Acts/Utilities/Intersection.hpp"
0028 #include "Acts/Utilities/Logger.hpp"
0029 #include "Acts/Utilities/MathHelpers.hpp"
0030 #include "Acts/Utilities/Result.hpp"
0031 
0032 #include <cmath>
0033 #include <limits>
0034 #include <string>
0035 #include <tuple>
0036 
0037 namespace Acts {
0038 
0039 /// @brief straight line stepper based on Surface intersection
0040 ///
0041 /// The straight line stepper is a simple navigation stepper
0042 /// to be used to navigate through the tracking geometry. It can be
0043 /// used for simple material mapping, navigation validation
0044 class StraightLineStepper {
0045  public:
0046   using Jacobian = BoundMatrix;
0047   using Covariance = BoundSquareMatrix;
0048   using BoundState = std::tuple<BoundTrackParameters, Jacobian, double>;
0049   using CurvilinearState =
0050       std::tuple<CurvilinearTrackParameters, Jacobian, double>;
0051   using BField = NullBField;
0052 
0053   struct Config {};
0054 
0055   struct Options : public StepperPlainOptions {
0056     Options(const GeometryContext& gctx, const MagneticFieldContext& mctx)
0057         : StepperPlainOptions(gctx, mctx) {}
0058 
0059     void setPlainOptions(const StepperPlainOptions& options) {
0060       static_cast<StepperPlainOptions&>(*this) = options;
0061     }
0062   };
0063 
0064   /// State for track parameter propagation
0065   ///
0066   struct State {
0067     /// Constructor from the initial bound track parameters
0068     ///
0069     /// @param [in] optionsIn The options for the stepper
0070     ///
0071     /// @note the covariance matrix is copied when needed
0072     explicit State(const Options& optionsIn) : options(optionsIn) {}
0073 
0074     Options options;
0075 
0076     /// Jacobian from local to the global frame
0077     BoundToFreeMatrix jacToGlobal = BoundToFreeMatrix::Zero();
0078 
0079     /// Pure transport jacobian part from runge kutta integration
0080     FreeMatrix jacTransport = FreeMatrix::Identity();
0081 
0082     /// The full jacobian of the transport entire transport
0083     Jacobian jacobian = Jacobian::Identity();
0084 
0085     /// The propagation derivative
0086     FreeVector derivative = FreeVector::Zero();
0087 
0088     /// Internal free vector parameters
0089     FreeVector pars = FreeVector::Zero();
0090 
0091     /// Particle hypothesis
0092     ParticleHypothesis particleHypothesis = ParticleHypothesis::pion();
0093 
0094     /// Boolean to indicate if you need covariance transport
0095     bool covTransport = false;
0096     Covariance cov = Covariance::Zero();
0097 
0098     /// accummulated path length state
0099     double pathAccumulated = 0.;
0100 
0101     /// Total number of performed steps
0102     std::size_t nSteps = 0;
0103 
0104     /// Totoal number of attempted steps
0105     std::size_t nStepTrials = 0;
0106 
0107     /// adaptive step size of the runge-kutta integration
0108     ConstrainedStep stepSize;
0109 
0110     // Previous step size for overstep estimation (ignored for SL stepper)
0111     double previousStepSize = 0.;
0112 
0113     /// Statistics of the stepper
0114     StepperStatistics statistics;
0115   };
0116 
0117   StraightLineStepper() = default;
0118 
0119   State makeState(const Options& options,
0120                   const BoundTrackParameters& par) const {
0121     State state{options};
0122 
0123     state.particleHypothesis = par.particleHypothesis();
0124 
0125     Vector3 position = par.position(options.geoContext);
0126     Vector3 direction = par.direction();
0127     state.pars.template segment<3>(eFreePos0) = position;
0128     state.pars.template segment<3>(eFreeDir0) = direction;
0129     state.pars[eFreeTime] = par.time();
0130     state.pars[eFreeQOverP] = par.parameters()[eBoundQOverP];
0131 
0132     // Init the jacobian matrix if needed
0133     if (par.covariance()) {
0134       // Get the reference surface for navigation
0135       const auto& surface = par.referenceSurface();
0136       // set the covariance transport flag to true and copy
0137       state.covTransport = true;
0138       state.cov = BoundSquareMatrix(*par.covariance());
0139       state.jacToGlobal =
0140           surface.boundToFreeJacobian(options.geoContext, position, direction);
0141     }
0142 
0143     state.stepSize = ConstrainedStep(options.maxStepSize);
0144 
0145     return state;
0146   }
0147 
0148   /// @brief Resets the state
0149   ///
0150   /// @param [in, out] state State of the stepper
0151   /// @param [in] boundParams Parameters in bound parametrisation
0152   /// @param [in] cov Covariance matrix
0153   /// @param [in] surface The reset @c State will be on this surface
0154   /// @param [in] stepSize Step size
0155   void resetState(
0156       State& state, const BoundVector& boundParams,
0157       const BoundSquareMatrix& cov, const Surface& surface,
0158       const double stepSize = std::numeric_limits<double>::max()) const;
0159 
0160   /// Get the field for the stepping, this gives back a zero field
0161   Result<Vector3> getField(State& /*state*/, const Vector3& /*pos*/) const {
0162     // get the field from the cell
0163     return Result<Vector3>::success({0., 0., 0.});
0164   }
0165 
0166   /// Global particle position accessor
0167   ///
0168   /// @param state [in] The stepping state (thread-local cache)
0169   Vector3 position(const State& state) const {
0170     return state.pars.template segment<3>(eFreePos0);
0171   }
0172 
0173   /// Momentum direction accessor
0174   ///
0175   /// @param state [in] The stepping state (thread-local cache)
0176   Vector3 direction(const State& state) const {
0177     return state.pars.template segment<3>(eFreeDir0);
0178   }
0179 
0180   /// QoP direction accessor
0181   ///
0182   /// @param state [in] The stepping state (thread-local cache)
0183   double qOverP(const State& state) const { return state.pars[eFreeQOverP]; }
0184 
0185   /// Absolute momentum accessor
0186   ///
0187   /// @param state [in] The stepping state (thread-local cache)
0188   double absoluteMomentum(const State& state) const {
0189     return particleHypothesis(state).extractMomentum(qOverP(state));
0190   }
0191 
0192   /// Momentum accessor
0193   ///
0194   /// @param state [in] The stepping state (thread-local cache)
0195   Vector3 momentum(const State& state) const {
0196     return absoluteMomentum(state) * direction(state);
0197   }
0198 
0199   /// Charge access
0200   ///
0201   /// @param state [in] The stepping state (thread-local cache)
0202   double charge(const State& state) const {
0203     return particleHypothesis(state).extractCharge(qOverP(state));
0204   }
0205 
0206   /// Particle hypothesis
0207   ///
0208   /// @param state [in] The stepping state (thread-local cache)
0209   const ParticleHypothesis& particleHypothesis(const State& state) const {
0210     return state.particleHypothesis;
0211   }
0212 
0213   /// Time access
0214   ///
0215   /// @param state [in] The stepping state (thread-local cache)
0216   double time(const State& state) const { return state.pars[eFreeTime]; }
0217 
0218   /// Update surface status
0219   ///
0220   /// This method intersects the provided surface and update the navigation
0221   /// step estimation accordingly (hence it changes the state). It also
0222   /// returns the status of the intersection to trigger onSurface in case
0223   /// the surface is reached.
0224   ///
0225   /// @param [in,out] state The stepping state (thread-local cache)
0226   /// @param [in] surface The surface provided
0227   /// @param [in] index The surface intersection index
0228   /// @param [in] navDir The navigation direction
0229   /// @param [in] boundaryTolerance The boundary check for this status update
0230   /// @param [in] surfaceTolerance Surface tolerance used for intersection
0231   /// @param [in] stype The step size type to be set
0232   /// @param [in] logger A logger instance
0233   IntersectionStatus updateSurfaceStatus(
0234       State& state, const Surface& surface, std::uint8_t index,
0235       Direction navDir, const BoundaryTolerance& boundaryTolerance,
0236       double surfaceTolerance, ConstrainedStep::Type stype,
0237       const Logger& logger = getDummyLogger()) const {
0238     return detail::updateSingleSurfaceStatus<StraightLineStepper>(
0239         *this, state, surface, index, navDir, boundaryTolerance,
0240         surfaceTolerance, stype, logger);
0241   }
0242 
0243   /// Update step size
0244   ///
0245   /// It checks the status to the reference surface & updates
0246   /// the step size accordingly
0247   ///
0248   /// @param state [in,out] The stepping state (thread-local cache)
0249   /// @param oIntersection [in] The ObjectIntersection to layer, boundary, etc
0250   /// @param direction [in] The propagation direction
0251   /// @param stype [in] The step size type to be set
0252   template <typename object_intersection_t>
0253   void updateStepSize(State& state, const object_intersection_t& oIntersection,
0254                       Direction direction, ConstrainedStep::Type stype) const {
0255     (void)direction;
0256     double stepSize = oIntersection.pathLength();
0257     updateStepSize(state, stepSize, stype);
0258   }
0259 
0260   /// Update step size - explicitly with a double
0261   ///
0262   /// @param state [in,out] The stepping state (thread-local cache)
0263   /// @param stepSize [in] The step size value
0264   /// @param stype [in] The step size type to be set
0265   void updateStepSize(State& state, double stepSize,
0266                       ConstrainedStep::Type stype) const {
0267     state.previousStepSize = state.stepSize.value();
0268     state.stepSize.update(stepSize, stype);
0269   }
0270 
0271   /// Get the step size
0272   ///
0273   /// @param state [in] The stepping state (thread-local cache)
0274   /// @param stype [in] The step size type to be returned
0275   double getStepSize(const State& state, ConstrainedStep::Type stype) const {
0276     return state.stepSize.value(stype);
0277   }
0278 
0279   /// Release the Step size
0280   ///
0281   /// @param [in,out] state The stepping state (thread-local cache)
0282   /// @param [in] stype The step size type to be released
0283   void releaseStepSize(State& state, ConstrainedStep::Type stype) const {
0284     state.stepSize.release(stype);
0285   }
0286 
0287   /// Output the Step Size - single component
0288   ///
0289   /// @param state [in,out] The stepping state (thread-local cache)
0290   std::string outputStepSize(const State& state) const {
0291     return state.stepSize.toString();
0292   }
0293 
0294   /// Create and return the bound state at the current position
0295   ///
0296   /// @brief It does not check if the transported state is at the surface, this
0297   /// needs to be guaranteed by the propagator
0298   ///
0299   /// @param [in] state State that will be presented as @c BoundState
0300   /// @param [in] surface The surface to which we bind the state
0301   /// @param [in] transportCov Flag steering covariance transport
0302   /// @param [in] freeToBoundCorrection Correction for non-linearity effect during transform from free to bound
0303   ///
0304   /// @return A bound state:
0305   ///   - the parameters at the surface
0306   ///   - the stepwise jacobian towards it (from last bound)
0307   ///   - and the path length (from start - for ordering)
0308   Result<BoundState> boundState(
0309       State& state, const Surface& surface, bool transportCov = true,
0310       const FreeToBoundCorrection& freeToBoundCorrection =
0311           FreeToBoundCorrection(false)) const;
0312 
0313   /// @brief If necessary fill additional members needed for curvilinearState
0314   ///
0315   /// Compute path length derivatives in case they have not been computed
0316   /// yet, which is the case if no step has been executed yet.
0317   ///
0318   /// @param [in, out] prop_state State that will be presented as @c BoundState
0319   /// @param [in] navigator the navigator of the propagation
0320   /// @return true if nothing is missing after this call, false otherwise.
0321   template <typename propagator_state_t, typename navigator_t>
0322   bool prepareCurvilinearState(
0323       [[maybe_unused]] propagator_state_t& prop_state,
0324       [[maybe_unused]] const navigator_t& navigator) const {
0325     // test whether the accumulated path has still its initial value.
0326     if (prop_state.stepping.pathAccumulated == 0.) {
0327       // dr/ds :
0328       prop_state.stepping.derivative.template head<3>() =
0329           direction(prop_state.stepping);
0330       // dt / ds
0331       prop_state.stepping.derivative(eFreeTime) =
0332           fastHypot(1., prop_state.stepping.particleHypothesis.mass() /
0333                             absoluteMomentum(prop_state.stepping));
0334       // d (dr/ds) / ds : == 0
0335       prop_state.stepping.derivative.template segment<3>(4) =
0336           Acts::Vector3::Zero().transpose();
0337       // d qop / ds  == 0
0338       prop_state.stepping.derivative(eFreeQOverP) = 0.;
0339     }
0340     return true;
0341   }
0342 
0343   /// Create and return a curvilinear state at the current position
0344   ///
0345   /// @brief This creates a curvilinear state.
0346   ///
0347   /// @param [in] state State that will be presented as @c CurvilinearState
0348   /// @param [in] transportCov Flag steering covariance transport
0349   ///
0350   /// @return A curvilinear state:
0351   ///   - the curvilinear parameters at given position
0352   ///   - the stepweise jacobian towards it (from last bound)
0353   ///   - and the path length (from start - for ordering)
0354   CurvilinearState curvilinearState(State& state,
0355                                     bool transportCov = true) const;
0356 
0357   /// Method to update a stepper state to the some parameters
0358   ///
0359   /// @param [in,out] state State object that will be updated
0360   /// @param [in] freeParams Free parameters that will be written into @p state
0361   /// @param [in] boundParams Corresponding bound parameters used to update jacToGlobal in @p state
0362   /// @param [in] covariance Covariance that will be written into @p state
0363   /// @param [in] surface The surface used to update the jacToGlobal
0364   void update(State& state, const FreeVector& freeParams,
0365               const BoundVector& boundParams, const Covariance& covariance,
0366               const Surface& surface) const;
0367 
0368   /// Method to update the stepper state
0369   ///
0370   /// @param [in,out] state State object that will be updated
0371   /// @param [in] uposition the updated position
0372   /// @param [in] udirection the updated direction
0373   /// @param [in] qop the updated qop value
0374   /// @param [in] time the updated time value
0375   void update(State& state, const Vector3& uposition, const Vector3& udirection,
0376               double qop, double time) const;
0377 
0378   /// Method for on-demand transport of the covariance
0379   /// to a new curvilinear frame at current  position,
0380   /// or direction of the state - for the moment a dummy method
0381   ///
0382   /// @param [in,out] state State of the stepper
0383   void transportCovarianceToCurvilinear(State& state) const;
0384 
0385   /// Method for on-demand transport of the covariance
0386   /// to a new curvilinear frame at current  position,
0387   /// or direction of the state - for the moment a dummy method
0388   ///
0389   /// @tparam surface_t the surface type - ignored here
0390   ///
0391   /// @param [in,out] state The stepper state
0392   /// @param [in] surface is the surface to which the covariance is
0393   ///        forwarded to
0394   /// @note no check is done if the position is actually on the surface
0395   /// @param [in] freeToBoundCorrection Correction for non-linearity effect during transform from free to bound
0396   ///
0397   void transportCovarianceToBound(
0398       State& state, const Surface& surface,
0399       const FreeToBoundCorrection& freeToBoundCorrection =
0400           FreeToBoundCorrection(false)) const;
0401 
0402   /// Perform a straight line propagation step
0403   ///
0404   /// @param [in,out] state is the propagation state associated with the track
0405   /// parameters that are being propagated.
0406   ///                The state contains the desired step size,
0407   ///                it can be negative during backwards track propagation,
0408   ///                and since we're using an adaptive algorithm, it can
0409   ///                be modified by the stepper class during propagation.
0410   ///
0411   /// @return the step size taken
0412   template <typename propagator_state_t, typename navigator_t>
0413   Result<double> step(propagator_state_t& state,
0414                       const navigator_t& /*navigator*/) const {
0415     // use the adjusted step size
0416     const auto h = state.stepping.stepSize.value() * state.options.direction;
0417     const auto m = state.stepping.particleHypothesis.mass();
0418     const auto p = absoluteMomentum(state.stepping);
0419     // time propagates along distance as 1/b = sqrt(1 + m²/p²)
0420     const auto dtds = fastHypot(1., m / p);
0421     // Update the track parameters according to the equations of motion
0422     Vector3 dir = direction(state.stepping);
0423     state.stepping.pars.template segment<3>(eFreePos0) += h * dir;
0424     state.stepping.pars[eFreeTime] += h * dtds;
0425 
0426     // Propagate the jacobian
0427     if (state.stepping.covTransport) {
0428       // The step transport matrix in global coordinates
0429       FreeMatrix D = FreeMatrix::Identity();
0430       D.block<3, 3>(0, 4) = ActsSquareMatrix<3>::Identity() * h;
0431       // Extend the calculation by the time propagation
0432       // Evaluate dt/dlambda
0433       D(3, 7) = h * m * m * state.stepping.pars[eFreeQOverP] / dtds;
0434       // Set the derivative factor the time
0435       state.stepping.derivative(3) = dtds;
0436       // Update jacobian and derivative
0437       state.stepping.jacTransport = D * state.stepping.jacTransport;
0438       state.stepping.derivative.template head<3>() = dir;
0439     }
0440 
0441     // state the path length
0442     state.stepping.pathAccumulated += h;
0443     ++state.stepping.nSteps;
0444     ++state.stepping.nStepTrials;
0445 
0446     ++state.stepping.statistics.nAttemptedSteps;
0447     ++state.stepping.statistics.nSuccessfulSteps;
0448     if (state.options.direction != Direction::fromScalarZeroAsPositive(h)) {
0449       ++state.stepping.statistics.nReverseSteps;
0450     }
0451     state.stepping.statistics.pathLength += h;
0452     state.stepping.statistics.absolutePathLength += std::abs(h);
0453 
0454     return h;
0455   }
0456 };
0457 
0458 template <typename navigator_t>
0459 struct SupportsBoundParameters<StraightLineStepper, navigator_t>
0460     : public std::true_type {};
0461 
0462 }  // namespace Acts