Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /acts/Core/include/Acts/Propagator/GenericRungeKuttaStepper.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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/Definitions/Direction.hpp"
0013 #include "Acts/Definitions/Units.hpp"
0014 #include "Acts/EventData/BoundTrackParameters.hpp"
0015 #include "Acts/EventData/detail/CorrectedTransformationFreeToBound.hpp"
0016 #include "Acts/MagneticField/MagneticFieldProvider.hpp"
0017 #include "Acts/Propagator/ButcherTableau.hpp"
0018 #include "Acts/Propagator/ConstrainedStep.hpp"
0019 #include "Acts/Propagator/NavigationTarget.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 
0025 #include <optional>
0026 #include <stdexcept>
0027 #include <string>
0028 
0029 namespace Acts {
0030 
0031 class IVolumeMaterial;
0032 
0033 /// @brief Reference stepper with a configurable Runge-Kutta tableau
0034 ///
0035 /// The stepper integrates the equation of motion in vacuum for the free
0036 /// parameters y = (r, t, T, q/p),
0037 ///
0038 ///   dy/ds = f(y) = (T, 1/beta, (q/p) T x B(r), 0),
0039 ///
0040 /// with any explicit @ref ButcherTableau. It is not optimised. It is meant as a
0041 /// reference to compare other steppers against.
0042 ///
0043 /// The transport jacobian is the exact derivative of the discrete step. The
0044 /// stepper differentiates each stage with the chain rule,
0045 ///
0046 ///   dY_i = I + h sum_j a_ij dK_j,  dK_i = J_f(Y_i) dY_i,
0047 ///   D = I + h sum_i b_i dK_i,
0048 ///
0049 /// so it works for every tableau. Here dY_i, dK_i and D are the derivatives
0050 /// of the stage, of the stage slope and of the step by the free parameters at
0051 /// the start of the step. J_f = df/dy has the non-zero blocks
0052 ///
0053 ///   d(r)/dT = I,  d(t)/d(q/p) = d(1/beta)/d(q/p),
0054 ///   d(T)/dr = (q/p) [T x] dB/dr,  d(T)/dT = -(q/p) [B x],
0055 ///   d(T)/d(q/p) = T x B.
0056 ///
0057 /// The stepper takes dB/dr from the field provider. If the provider does not
0058 /// implement the gradient, the stepper computes it with central finite
0059 /// differences of the field, so the jacobian is exact up to the O(epsilon^2)
0060 /// error of the gradient, see @ref Options::fieldGradientEpsilon. Without the
0061 /// gradient term (@ref Options::includeFieldGradient) the jacobian is not
0062 /// exact.
0063 ///
0064 /// After the step, the stepper normalises the direction to unit length. This
0065 /// is part of the discrete step, so the stepper also applies its derivative
0066 /// (I - T T^T / |T|^2) / |T| to the direction rows of D.
0067 ///
0068 /// The stepper adapts the step size to @ref StepperPlainOptions::stepTolerance
0069 /// with one of two error estimates, see @ref ErrorEstimation. The error
0070 /// estimate is the maximum norm of the position (mm), the time (mm) and the
0071 /// dimensionless direction components, with the same absolute tolerance. In
0072 /// vacuum q/p does not change, so it does not contribute. The step size
0073 /// control follows Hairer, Nørsett, Wanner, Solving Ordinary Differential
0074 /// Equations I, 2nd ed., Section II.4.
0075 ///
0076 /// As for @ref HelixStepper, a step to the straight-line distance of a surface
0077 /// can pass it, and the next step goes back. A target aborter must accept an
0078 /// intersection that far behind the track.
0079 ///
0080 /// @note The order of a tableau only holds in a smooth field. An interpolated
0081 ///       field map is continuous but not differentiable at the cell faces.
0082 ///       A step that crosses a face has a local error of order h^2 for every
0083 ///       tableau. The number of crossings does not decrease with h, so in a
0084 ///       field map every tableau is only accurate to about second order.
0085 /// @note The stepper propagates in vacuum only. It ignores volume material.
0086 class GenericRungeKuttaStepper final {
0087  public:
0088   /// Type alias for bound track parameters
0089   using BoundParameters = BoundTrackParameters;
0090   /// Type alias for jacobian matrix
0091   using Jacobian = BoundMatrix;
0092   /// Type alias for covariance matrix
0093   using Covariance = BoundMatrix;
0094 
0095   /// Type alias for the magnetic field and its gradient
0096   using FieldAndGradient = MagneticFieldProvider::FieldAndGradient;
0097 
0098   /// Error estimate for the adaptive step size
0099   ///
0100   /// Both use the same tolerance. The embedded estimate is for the lower-order
0101   /// solution, so the propagated solution is usually 100 to 1000 times more
0102   /// accurate than the tolerance. Step doubling estimates the propagated
0103   /// solution itself, so its local error is about the tolerance.
0104   enum class ErrorEstimation {
0105     /// Fixed step size
0106     None,
0107     /// Solution minus embedded solution. Needs embedded weights.
0108     Embedded,
0109     /// One step of h against two steps of h/2, which are propagated. Works
0110     /// for every tableau, at about three times the cost.
0111     StepDoubling,
0112   };
0113 
0114   /// Configuration for the Runge-Kutta stepper.
0115   struct Config {
0116     /// Magnetic field provider
0117     std::shared_ptr<const MagneticFieldProvider> bField;
0118 
0119     /// Runge-Kutta tableau. It is shared, so that all steppers can use the
0120     /// static built-in tableaus without a copy.
0121     std::shared_ptr<const ButcherTableau> tableau =
0122         ButcherTableau::dormandPrince54();
0123   };
0124 
0125   /// Runtime options for Runge-Kutta propagation.
0126   struct Options : public StepperPlainOptions {
0127     /// Constructor
0128     /// @param gctx Geometry context
0129     /// @param mctx Magnetic field context
0130     Options(const GeometryContext& gctx, const MagneticFieldContext& mctx)
0131         : StepperPlainOptions(gctx, mctx) {}
0132 
0133     /// Error estimate for the adaptive step size
0134     ErrorEstimation errorEstimation = ErrorEstimation::Embedded;
0135 
0136     /// Include the field gradient in the transport jacobian
0137     bool includeFieldGradient = true;
0138 
0139     /// Distance of the field lookups for the finite-difference gradient, if
0140     /// the field provider does not implement the gradient.
0141     ///
0142     /// The truncation error of the central difference is of order epsilon^2.
0143     /// The round-off error is of order eps_machine |B| / epsilon, which is
0144     /// about 1e-14 |B| per mm for 10 um. This is far below the gradient of a
0145     /// real field. 10 um is also small compared with a field-map cell, so the
0146     /// lookups usually stay in one cell.
0147     double fieldGradientEpsilon = 10 * UnitConstants::um;
0148 
0149     /// Include the jacobian in the error estimate. Its entries have mixed
0150     /// units, and the stepper uses the same tolerance for all of them.
0151     bool jacobianInErrorEstimate = false;
0152 
0153     /// Set plain stepper options
0154     /// @param options Plain stepper options
0155     void setPlainOptions(const StepperPlainOptions& options) {
0156       static_cast<StepperPlainOptions&>(*this) = options;
0157     }
0158   };
0159 
0160   /// @brief State for track parameter propagation
0161   ///
0162   /// It contains the stepping information and is provided thread local
0163   /// by the propagator
0164   struct State {
0165     /// Constructor from the options and the field cache
0166     ///
0167     /// @param [in] optionsIn is the configuration of the stepper
0168     /// @param [in] fieldCacheIn is the cache object for the magnetic field
0169     State(const Options& optionsIn, MagneticFieldProvider::Cache fieldCacheIn)
0170         : options(optionsIn), fieldCache(std::move(fieldCacheIn)) {}
0171 
0172     /// Configuration options for the stepper
0173     Options options;
0174 
0175     /// Internal free vector parameters
0176     FreeVector pars = FreeVector::Zero();
0177 
0178     /// The propagation derivative
0179     FreeVector derivative = FreeVector::Zero();
0180 
0181     /// Jacobian from local to the global frame
0182     BoundToFreeMatrix jacToGlobal = BoundToFreeMatrix::Zero();
0183 
0184     /// Pure transport jacobian part from the Runge-Kutta steps
0185     FreeMatrix jacTransport = FreeMatrix::Identity();
0186 
0187     /// Covariance matrix for track parameter uncertainties, set if the
0188     /// covariance is transported
0189     std::optional<Covariance> cov;
0190 
0191     /// Particle hypothesis
0192     ParticleHypothesis particleHypothesis = ParticleHypothesis::pion();
0193 
0194     /// Adaptive step size of the Runge-Kutta steps
0195     ConstrainedStep stepSize;
0196 
0197     /// Last performed step (for overstep limit calculation)
0198     double previousStepSize = 0.;
0199 
0200     /// Magnetic field at the current position, reused as the first stage of
0201     /// the next step. Reset whenever the position is set from outside.
0202     std::optional<FieldAndGradient> field;
0203 
0204     /// Whether @ref field contains the gradient
0205     bool fieldHasGradient = false;
0206 
0207     /// Accumulated path length state
0208     double pathAccumulated = 0.;
0209 
0210     /// Total number of performed steps
0211     std::size_t nSteps = 0;
0212 
0213     /// Statistics of the stepper
0214     StepperStatistics statistics;
0215 
0216     /// This caches the current magnetic field cell and stays
0217     /// (and interpolates) within it as long as this is valid.
0218     MagneticFieldProvider::Cache fieldCache;
0219   };
0220 
0221   /// Constructor requires knowledge of the detector's magnetic field
0222   /// @param bField The magnetic field provider
0223   explicit GenericRungeKuttaStepper(
0224       std::shared_ptr<const MagneticFieldProvider> bField);
0225 
0226   /// @brief Constructor with configuration
0227   /// @param config The configuration of the stepper
0228   explicit GenericRungeKuttaStepper(const Config& config);
0229 
0230   /// Create a state object
0231   /// @param options Stepper options
0232   /// @return State object
0233   /// @throws std::invalid_argument for an embedded error estimate without
0234   ///         embedded weights
0235   State makeState(const Options& options) const;
0236 
0237   /// Initialize the state from bound track parameters
0238   /// @param state The state to initialize
0239   /// @param par The bound track parameters
0240   void initialize(State& state, const BoundParameters& par) const;
0241 
0242   /// Initialize the state from bound parameters
0243   /// @param state The state to initialize
0244   /// @param boundParams Bound track parameters vector
0245   /// @param cov Covariance matrix
0246   /// @param particleHypothesis Particle hypothesis
0247   /// @param surface Reference surface
0248   void initialize(State& state, const BoundVector& boundParams,
0249                   const std::optional<BoundMatrix>& cov,
0250                   ParticleHypothesis particleHypothesis,
0251                   const Surface& surface) const;
0252 
0253   /// Get the field for the stepping, it checks first if the access is still
0254   /// within the Cell, and updates the cell if necessary.
0255   ///
0256   /// @param [in,out] state is the propagation state associated with the track
0257   ///                 the magnetic field cell is used (and potentially updated)
0258   /// @param [in] pos is the field position
0259   /// @return Magnetic field vector
0260   Result<Vector3> getField(State& state, const Vector3& pos) const {
0261     return m_bField->getField(pos, state.fieldCache);
0262   }
0263 
0264   /// Current global geometric curvature d(direction)/ds in inverse length.
0265   /// Unchanged under propagation reversal; reflects current momentum and field.
0266   /// @param state Stepping state; the field cache may be updated
0267   /// @return Curvature vector, or a field lookup error
0268   Result<Vector3> curvature(State& state) const {
0269     return detail::magneticCurvature(*this, state);
0270   }
0271 
0272   /// Global particle position accessor
0273   ///
0274   /// @param state [in] The stepping state (thread-local cache)
0275   /// @return Position vector
0276   Vector3 position(const State& state) const {
0277     return state.pars.template segment<3>(eFreePos0);
0278   }
0279 
0280   /// Momentum direction accessor
0281   ///
0282   /// @param state [in] The stepping state (thread-local cache)
0283   /// @return Direction vector
0284   Vector3 direction(const State& state) const {
0285     return state.pars.template segment<3>(eFreeDir0);
0286   }
0287 
0288   /// QoP direction accessor
0289   ///
0290   /// @param state [in] The stepping state (thread-local cache)
0291   /// @return Charge over momentum
0292   double qOverP(const State& state) const { return state.pars[eFreeQOverP]; }
0293 
0294   /// Absolute momentum accessor
0295   ///
0296   /// @param state [in] The stepping state (thread-local cache)
0297   /// @return Absolute momentum
0298   double absoluteMomentum(const State& state) const {
0299     return particleHypothesis(state).extractMomentum(qOverP(state));
0300   }
0301 
0302   /// Momentum accessor
0303   ///
0304   /// @param state [in] The stepping state (thread-local cache)
0305   /// @return Momentum vector
0306   Vector3 momentum(const State& state) const {
0307     return absoluteMomentum(state) * direction(state);
0308   }
0309 
0310   /// Charge access
0311   ///
0312   /// @param state [in] The stepping state (thread-local cache)
0313   /// @return Particle charge
0314   double charge(const State& state) const {
0315     return particleHypothesis(state).extractCharge(qOverP(state));
0316   }
0317 
0318   /// Particle hypothesis
0319   ///
0320   /// @param state [in] The stepping state (thread-local cache)
0321   /// @return Particle hypothesis
0322   const ParticleHypothesis& particleHypothesis(const State& state) const {
0323     return state.particleHypothesis;
0324   }
0325 
0326   /// Time access
0327   ///
0328   /// @param state [in] The stepping state (thread-local cache)
0329   /// @return Time
0330   double time(const State& state) const { return state.pars[eFreeTime]; }
0331 
0332   /// Update surface status
0333   ///
0334   /// It checks the status to the reference surface & updates
0335   /// the step size accordingly
0336   ///
0337   /// @param [in,out] state The stepping state (thread-local cache)
0338   /// @param [in] surface The surface provided
0339   /// @param [in] index The surface intersection index
0340   /// @param [in] navDir The navigation direction
0341   /// @param [in] boundaryTolerance The boundary check for this status update
0342   /// @param [in] surfaceTolerance Surface tolerance used for intersection
0343   /// @param [in] stype The step size type to be set
0344   /// @param [in] logger A @c Logger instance
0345   /// @param curvature Global geometric curvature for the crossing estimate
0346   /// @return Intersection status
0347   IntersectionStatus updateSurfaceStatus(
0348       State& state, const Surface& surface, std::uint8_t index,
0349       Direction navDir, const BoundaryTolerance& boundaryTolerance,
0350       double surfaceTolerance, ConstrainedStep::Type stype,
0351       const Logger& logger = getDummyLogger(),
0352       const Vector3& curvature = Vector3::Zero()) const {
0353     return detail::updateSingleSurfaceStatus<GenericRungeKuttaStepper>(
0354         *this, state, surface, index, navDir, boundaryTolerance,
0355         surfaceTolerance, stype, logger, curvature);
0356   }
0357 
0358   /// Update step size
0359   ///
0360   /// This method intersects the provided surface and update the navigation
0361   /// step estimation accordingly (hence it changes the state). It also
0362   /// returns the status of the intersection to trigger onSurface in case
0363   /// the surface is reached.
0364   ///
0365   /// @param state [in,out] The stepping state (thread-local cache)
0366   /// @param target [in] The NavigationTarget
0367   /// @param direction [in] The propagation direction
0368   /// @param stype [in] The step size type to be set
0369   void updateStepSize(State& state, const NavigationTarget& target,
0370                       Direction direction, ConstrainedStep::Type stype) const {
0371     static_cast<void>(direction);
0372     double stepSize = target.pathLength();
0373     updateStepSize(state, stepSize, stype);
0374   }
0375 
0376   /// Update step size - explicitly with a double
0377   ///
0378   /// @param state [in,out] The stepping state (thread-local cache)
0379   /// @param stepSize [in] The step size value
0380   /// @param stype [in] The step size type to be set
0381   void updateStepSize(State& state, double stepSize,
0382                       ConstrainedStep::Type stype) const {
0383     state.previousStepSize = state.stepSize.value();
0384     state.stepSize.update(stepSize, stype);
0385   }
0386 
0387   /// Get the step size
0388   ///
0389   /// @param state [in] The stepping state (thread-local cache)
0390   /// @param stype [in] The step size type to be returned
0391   /// @return Step size
0392   double getStepSize(const State& state, ConstrainedStep::Type stype) const {
0393     return state.stepSize.value(stype);
0394   }
0395 
0396   /// Release the Step size
0397   ///
0398   /// @param state [in,out] The stepping state (thread-local cache)
0399   /// @param [in] stype The step size type to be released
0400   void releaseStepSize(State& state, ConstrainedStep::Type stype) const {
0401     state.stepSize.release(stype);
0402   }
0403 
0404   /// Output the Step Size - single component
0405   ///
0406   /// @param state [in,out] The stepping state (thread-local cache)
0407   /// @return String representation of step size
0408   std::string outputStepSize(const State& state) const {
0409     return state.stepSize.toString();
0410   }
0411 
0412   /// Get the step size constraints
0413   ///
0414   /// @param state [in] The stepping state (thread-local cache)
0415   /// @return The step size constraints
0416   const ConstrainedStep& stepSize(const State& state) const {
0417     return state.stepSize;
0418   }
0419 
0420   /// Get the stepper statistics
0421   ///
0422   /// @param state [in] The stepping state (thread-local cache)
0423   /// @return The statistics since the last initialization
0424   const StepperStatistics& statistics(const State& state) const {
0425     return state.statistics;
0426   }
0427 
0428   /// Get the path length
0429   ///
0430   /// @param state [in] The stepping state (thread-local cache)
0431   /// @return The path length since the last initialization
0432   double pathLength(const State& state) const { return state.pathAccumulated; }
0433 
0434   /// Check if the state carries a covariance
0435   ///
0436   /// @param state [in] The stepping state (thread-local cache)
0437   /// @return True if the covariance is transported
0438   bool hasCovariance(const State& state) const { return state.cov.has_value(); }
0439 
0440   /// Get the covariance at the anchor
0441   ///
0442   /// The anchor is the frame of the last initialization, transport or update.
0443   ///
0444   /// @param state [in] The stepping state (thread-local cache)
0445   /// @return The covariance at the anchor, or no value if the state does not
0446   ///         carry a covariance
0447   const std::optional<Covariance>& covariance(const State& state) const {
0448     return state.cov;
0449   }
0450 
0451   /// Set the covariance at the anchor
0452   ///
0453   /// The state must already carry a covariance, because the stepper only
0454   /// transports the Jacobian while it has one.
0455   ///
0456   /// @param [in,out] state The stepping state (thread-local cache)
0457   /// @param [in] covariance The new covariance at the anchor
0458   /// @throws std::logic_error if the state does not carry a covariance
0459   void setCovariance(State& state, const Covariance& covariance) const {
0460     if (!state.cov.has_value()) {
0461       throw std::logic_error(
0462           "Cannot set the covariance of a state without a covariance");
0463     }
0464     state.cov = covariance;
0465   }
0466 
0467   /// Get the bound parameters at the current position
0468   ///
0469   /// The parameters carry the covariance at the anchor if the state has one.
0470   ///
0471   /// @note It does not check if the state is on @p surface or anchored on it
0472   ///
0473   /// @param [in] state The stepping state (thread-local cache)
0474   /// @param [in] surface The surface of the parameters
0475   /// @return The bound parameters, or a failure if the position cannot be
0476   ///         expressed on @p surface
0477   Result<BoundParameters> boundParameters(const State& state,
0478                                           const Surface& surface) const;
0479 
0480   /// @brief If necessary fill additional members needed for
0481   /// transportToCurvilinear
0482   ///
0483   /// Compute path length derivatives in case they have not been computed
0484   /// yet, which is the case if no step has been executed yet.
0485   ///
0486   /// @param [in, out] state State of the stepper
0487   /// @return true if nothing is missing after this call, false otherwise.
0488   bool prepareCurvilinearState(State& state) const;
0489 
0490   /// Get the curvilinear parameters at the current position
0491   ///
0492   /// The parameters carry the covariance at the anchor if the state has one.
0493   ///
0494   /// @param [in] state The stepping state (thread-local cache)
0495   /// @return The curvilinear parameters
0496   BoundParameters curvilinearParameters(const State& state) const;
0497 
0498   /// Method to update a stepper state to the some parameters
0499   ///
0500   /// This anchors the state on @p surface.
0501   ///
0502   /// @param [in,out] state State object that will be updated
0503   /// @param [in] freeParams Free parameters that will be written into @p state
0504   /// @param [in] boundParams Corresponding bound parameters used to update jacToGlobal in @p state
0505   /// @param [in] covariance The covariance that will be written into @p state
0506   ///                        if the state carries a covariance
0507   /// @param [in] surface The surface used to update the jacToGlobal
0508   void update(State& state, const FreeVector& freeParams,
0509               const BoundVector& boundParams, const Covariance& covariance,
0510               const Surface& surface) const;
0511 
0512   /// Method to update the stepper state
0513   ///
0514   /// @param [in,out] state State object that will be updated
0515   /// @param [in] uposition the updated position
0516   /// @param [in] udirection the updated direction
0517   /// @param [in] qop the updated qop value
0518   /// @param [in] time the updated time value
0519   void update(State& state, const Vector3& uposition, const Vector3& udirection,
0520               double qop, double time) const;
0521 
0522   /// Transport the covariance to the curvilinear frame at the current position
0523   ///
0524   /// This anchors the state on the curvilinear frame. Without a covariance
0525   /// the state does not change.
0526   ///
0527   /// @param [in,out] state State of the stepper
0528   /// @return The jacobian from the previous anchor to the curvilinear frame
0529   Jacobian transportToCurvilinear(State& state) const;
0530 
0531   /// Transport the covariance to a surface at the current position
0532   ///
0533   /// This anchors the state on @p surface. Without a covariance the state
0534   /// does not change. The state must be on @p surface, and it stays unchanged
0535   /// if it is not.
0536   ///
0537   /// @param [in,out] state State of the stepper
0538   /// @param [in] surface The surface to transport the covariance to
0539   /// @param [in] freeToBoundCorrection Correction for non-linearity effect during transform from free to bound
0540   /// @return The jacobian from the previous anchor to @p surface, or a failure
0541   ///         if the state is not on @p surface
0542   Result<Jacobian> transportToBound(
0543       State& state, const Surface& surface,
0544       const FreeToBoundCorrection& freeToBoundCorrection =
0545           FreeToBoundCorrection(false)) const;
0546 
0547   /// Perform a Runge-Kutta track parameter propagation step
0548   ///
0549   /// @param [in,out] state State of the stepper
0550   /// @param propDir is the direction of propagation
0551   /// @param material is ignored, the stepper propagates in vacuum only
0552   /// @return the result of the step
0553   /// @throws std::invalid_argument for an embedded error estimate without
0554   ///         embedded weights
0555   ///
0556   /// @note The state contains the desired step size. It can be negative during
0557   ///       backwards track propagation, and since the step size is adaptive,
0558   ///       it can be modified by the stepper class during propagation.
0559   Result<double> step(State& state, Direction propDir,
0560                       const IVolumeMaterial* material) const;
0561 
0562   /// Get the field and optionally its gradient at a position.
0563   ///
0564   /// @param [in,out] state The stepper state with the field cache
0565   /// @param [in] pos The position of the lookup
0566   /// @param [in] withGradient Whether the gradient is needed
0567   /// @return The field and the gradient, which is zero without @p withGradient
0568   Result<FieldAndGradient> getFieldAndGradient(State& state, const Vector3& pos,
0569                                                bool withGradient) const;
0570 
0571  private:
0572   /// @param options Stepper options
0573   /// @throws std::invalid_argument for an embedded error estimate without
0574   ///         embedded weights
0575   void checkErrorEstimation(const Options& options) const;
0576 
0577   /// Magnetic field inside of the detector
0578   std::shared_ptr<const MagneticFieldProvider> m_bField;
0579 
0580   /// Runge-Kutta tableau
0581   std::shared_ptr<const ButcherTableau> m_tableau;
0582 };
0583 
0584 template <>
0585 struct SupportsBoundParameters<GenericRungeKuttaStepper>
0586     : public std::true_type {};
0587 
0588 }  // namespace Acts