Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/Acts/Propagator/DenseEnvironmentExtension.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) 2018-2024 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/PdgParticle.hpp"
0016 #include "Acts/Definitions/TrackParametrization.hpp"
0017 #include "Acts/Material/Interactions.hpp"
0018 #include "Acts/Propagator/AbortList.hpp"
0019 #include "Acts/Propagator/ActionList.hpp"
0020 #include "Acts/Propagator/Propagator.hpp"
0021 #include "Acts/Utilities/VectorHelpers.hpp"
0022 
0023 #include <array>
0024 #include <cmath>
0025 
0026 namespace Acts {
0027 
0028 /// @brief Evaluater of the k_i's and elements of the transport matrix
0029 /// D of the RKN4 stepping. This implementation involves energy loss due to
0030 /// ioninisation, bremsstrahlung, pair production and photonuclear interaction
0031 /// in the propagation and the jacobian. These effects will only occur if the
0032 /// propagation is in a TrackingVolume with attached material.
0033 struct DenseEnvironmentExtension {
0034   using Scalar = ActsScalar;
0035   /// @brief Vector3 replacement for the custom scalar type
0036   using ThisVector3 = Eigen::Matrix<Scalar, 3, 1>;
0037 
0038   /// Momentum at a certain point
0039   Scalar currentMomentum = 0.;
0040   /// Particles momentum at k1
0041   Scalar initialMomentum = 0.;
0042   /// Material that will be passed
0043   /// TODO : Might not be needed anymore
0044   Material material;
0045   /// Derivatives dLambda''dlambda at each sub-step point
0046   std::array<Scalar, 4> dLdl{};
0047   /// q/p at each sub-step
0048   std::array<Scalar, 4> qop{};
0049   /// Derivatives dPds at each sub-step
0050   std::array<Scalar, 4> dPds{};
0051   /// Derivative d(dEds)d(q/p) evaluated at the initial point
0052   Scalar dgdqopValue = 0.;
0053   /// Derivative dEds at the initial point
0054   Scalar g = 0.;
0055   /// k_i equivalent for the time propagation
0056   std::array<Scalar, 4> tKi{};
0057   /// Lambda''_i
0058   std::array<Scalar, 4> Lambdappi{};
0059   /// Energy at each sub-step
0060   std::array<Scalar, 4> energy{};
0061 
0062   /// @brief Control function if the step evaluation would be valid
0063   ///
0064   /// @tparam propagator_state_t Type of the state of the propagator
0065   /// @tparam stepper_t Type of the stepper
0066   /// @tparam navigator_t Type of the navigator
0067   ///
0068   /// @param [in] state State of the propagator
0069   /// @param [in] stepper Stepper of the propagator
0070   /// @param [in] navigator Navigator of the propagator
0071   ///
0072   /// @return Boolean flag if the step would be valid
0073   template <typename propagator_state_t, typename stepper_t,
0074             typename navigator_t>
0075   int bid(const propagator_state_t& state, const stepper_t& stepper,
0076           const navigator_t& navigator) const {
0077     const auto& particleHypothesis = stepper.particleHypothesis(state.stepping);
0078     float absQ = particleHypothesis.absoluteCharge();
0079     float mass = particleHypothesis.mass();
0080 
0081     // Check for valid particle properties
0082     if (absQ == 0. || mass == 0. ||
0083         stepper.absoluteMomentum(state.stepping) <
0084             state.options.momentumCutOff) {
0085       return 0;
0086     }
0087 
0088     // Check existence of a volume with material
0089     if (!navigator.currentVolumeMaterial(state.navigation)) {
0090       return 0;
0091     }
0092 
0093     return 2;
0094   }
0095 
0096   /// @brief Evaluater of the k_i's of the RKN4. For the case of i = 0 this
0097   /// step sets up member parameters, too.
0098   ///
0099   /// @tparam stepper_state_t Type of the state of the propagator
0100   /// @tparam stepper_t Type of the stepper
0101   /// @tparam navigator_t Type of the navigator
0102   ///
0103   /// @param [in] state State of the propagator
0104   /// @param [in] stepper Stepper of the propagator
0105   /// @param [in] navigator Navigator of the propagator
0106   /// @param [out] knew Next k_i that is evaluated
0107   /// @param [out] kQoP k_i elements of the momenta
0108   /// @param [in] bField B-Field at the evaluation position
0109   /// @param [in] i Index of the k_i, i = [0, 3]
0110   /// @param [in] h Step size (= 0. ^ 0.5 * StepSize ^ StepSize)
0111   /// @param [in] kprev Evaluated k_{i - 1}
0112   ///
0113   /// @return Boolean flag if the calculation is valid
0114   template <typename propagator_state_t, typename stepper_t,
0115             typename navigator_t>
0116   bool k(const propagator_state_t& state, const stepper_t& stepper,
0117          const navigator_t& navigator, ThisVector3& knew, const Vector3& bField,
0118          std::array<Scalar, 4>& kQoP, const int i = 0, const double h = 0.,
0119          const ThisVector3& kprev = ThisVector3::Zero()) {
0120     double q = stepper.charge(state.stepping);
0121     const auto& particleHypothesis = stepper.particleHypothesis(state.stepping);
0122     float mass = particleHypothesis.mass();
0123 
0124     // i = 0 is used for setup and evaluation of k
0125     if (i == 0) {
0126       // Set up container for energy loss
0127       auto volumeMaterial = navigator.currentVolumeMaterial(state.navigation);
0128       ThisVector3 position = stepper.position(state.stepping);
0129       material = volumeMaterial->material(position.template cast<double>());
0130       initialMomentum = stepper.absoluteMomentum(state.stepping);
0131       currentMomentum = initialMomentum;
0132       qop[0] = stepper.qOverP(state.stepping);
0133       initializeEnergyLoss(state, stepper);
0134       // Evaluate k
0135       knew = qop[0] * stepper.direction(state.stepping).cross(bField);
0136       // Evaluate k for the time propagation
0137       Lambdappi[0] = -qop[0] * qop[0] * qop[0] * g * energy[0] / (q * q);
0138       //~ tKi[0] = std::hypot(1, mass / initialMomentum);
0139       tKi[0] = std::hypot(1, mass * qop[0]);
0140       kQoP[0] = Lambdappi[0];
0141     } else {
0142       // Update parameters and check for momentum condition
0143       updateEnergyLoss(mass, h, state, stepper, i);
0144       if (currentMomentum < state.options.momentumCutOff) {
0145         return false;
0146       }
0147       // Evaluate k
0148       knew = qop[i] *
0149              (stepper.direction(state.stepping) + h * kprev).cross(bField);
0150       // Evaluate k_i for the time propagation
0151       auto qopNew = qop[0] + h * Lambdappi[i - 1];
0152       Lambdappi[i] = -qopNew * qopNew * qopNew * g * energy[i] / (q * q);
0153       tKi[i] = std::hypot(1, mass * qopNew);
0154       kQoP[i] = Lambdappi[i];
0155     }
0156     return true;
0157   }
0158 
0159   /// @brief After a RKN4 step was accepted by the stepper this method has an
0160   /// additional veto on the quality of the step. The veto lies in evaluation
0161   /// of the energy loss and the therewith constrained to keep the momentum
0162   /// after the step in reasonable values.
0163   ///
0164   /// @tparam propagator_state_t Type of the state of the propagator
0165   /// @tparam stepper_t Type of the stepper
0166   /// @tparam navigator_t Type of the navigator
0167   ///
0168   /// @param [in] state State of the propagator
0169   /// @param [in] stepper Stepper of the propagator
0170   /// @param [in] h Step size
0171   ///
0172   /// @return Boolean flag if the calculation is valid
0173   template <typename propagator_state_t, typename stepper_t,
0174             typename navigator_t>
0175   bool finalize(propagator_state_t& state, const stepper_t& stepper,
0176                 const navigator_t& /*navigator*/, const double h) const {
0177     const auto& particleHypothesis = stepper.particleHypothesis(state.stepping);
0178     float mass = particleHypothesis.mass();
0179 
0180     // Evaluate the new momentum
0181     auto newMomentum =
0182         stepper.absoluteMomentum(state.stepping) +
0183         (h / 6.) * (dPds[0] + 2. * (dPds[1] + dPds[2]) + dPds[3]);
0184 
0185     // Break propagation if momentum becomes below cut-off
0186     if (newMomentum < state.options.momentumCutOff) {
0187       return false;
0188     }
0189 
0190     // Add derivative dlambda/ds = Lambda''
0191     state.stepping.derivative(7) = -std::hypot(mass, newMomentum) * g /
0192                                    (newMomentum * newMomentum * newMomentum);
0193 
0194     // Update momentum
0195     state.stepping.pars[eFreeQOverP] =
0196         stepper.charge(state.stepping) / newMomentum;
0197     // Add derivative dt/ds = 1/(beta * c) = sqrt(m^2 * p^{-2} + c^{-2})
0198     state.stepping.derivative(3) = std::hypot(1, mass / newMomentum);
0199     // Update time
0200     state.stepping.pars[eFreeTime] +=
0201         (h / 6.) * (tKi[0] + 2. * (tKi[1] + tKi[2]) + tKi[3]);
0202 
0203     return true;
0204   }
0205 
0206   /// @brief After a RKN4 step was accepted by the stepper this method has an
0207   /// additional veto on the quality of the step. The veto lies in the
0208   /// evaluation
0209   /// of the energy loss, the therewith constrained to keep the momentum
0210   /// after the step in reasonable values and the evaluation of the transport
0211   /// matrix.
0212   ///
0213   /// @tparam propagator_state_t Type of the state of the propagator
0214   /// @tparam stepper_t Type of the stepper
0215   /// @tparam navigator_t Type of the navigator
0216   ///
0217   /// @param [in] state State of the propagator
0218   /// @param [in] stepper Stepper of the propagator
0219   /// @param [in] navigator Navigator of the propagator
0220   /// @param [in] h Step size
0221   /// @param [out] D Transport matrix
0222   ///
0223   /// @return Boolean flag if the calculation is valid
0224   template <typename propagator_state_t, typename stepper_t,
0225             typename navigator_t>
0226   bool finalize(propagator_state_t& state, const stepper_t& stepper,
0227                 const navigator_t& navigator, const double h,
0228                 FreeMatrix& D) const {
0229     return finalize(state, stepper, navigator, h) &&
0230            transportMatrix(state, stepper, h, D);
0231   }
0232 
0233  private:
0234   /// @brief Evaluates the transport matrix D for the jacobian
0235   ///
0236   /// @tparam propagator_state_t Type of the state of the propagator
0237   /// @tparam stepper_t Type of the stepper
0238   ///
0239   /// @param [in] state State of the propagator
0240   /// @param [in] stepper Stepper of the propagator
0241   /// @param [in] h Step size
0242   /// @param [out] D Transport matrix
0243   ///
0244   /// @return Boolean flag if evaluation is valid
0245   template <typename propagator_state_t, typename stepper_t>
0246   bool transportMatrix(propagator_state_t& state, const stepper_t& stepper,
0247                        const double h, FreeMatrix& D) const {
0248     /// The calculations are based on ATL-SOFT-PUB-2009-002. The update of the
0249     /// Jacobian matrix is requires only the calculation of eq. 17 and 18.
0250     /// Since the terms of eq. 18 are currently 0, this matrix is not needed
0251     /// in the calculation. The matrix A from eq. 17 consists out of 3
0252     /// different parts. The first one is given by the upper left 3x3 matrix
0253     /// that are calculated by dFdT and dGdT. The second is given by the top 3
0254     /// lines of the rightmost column. This is calculated by dFdL and dGdL.
0255     /// The remaining non-zero term is calculated directly. The naming of the
0256     /// variables is explained in eq. 11 and are directly related to the
0257     /// initial problem in eq. 7.
0258     /// The evaluation is based on propagating the parameters T and lambda
0259     /// (including g(lambda) and E(lambda)) as given in eq. 16 and evaluating
0260     /// the derivations for matrix A.
0261     /// @note The translation for u_{n+1} in eq. 7 is in this case a
0262     /// 3-dimensional vector without a dependency of Lambda or lambda neither in
0263     /// u_n nor in u_n'. The second and fourth eq. in eq. 14 have the constant
0264     /// offset matrices h * Id and Id respectively. This involves that the
0265     /// constant offset does not exist for rectangular matrix dFdu' (due to the
0266     /// missing Lambda part) and only exists for dGdu' in dlambda/dlambda.
0267 
0268     auto& sd = state.stepping.stepData;
0269     auto dir = stepper.direction(state.stepping);
0270     const auto& particleHypothesis = stepper.particleHypothesis(state.stepping);
0271     float mass = particleHypothesis.mass();
0272 
0273     D = FreeMatrix::Identity();
0274     const double half_h = h * 0.5;
0275 
0276     // This sets the reference to the sub matrices
0277     // dFdx is already initialised as (3x3) zero
0278     auto dFdT = D.block<3, 3>(0, 4);
0279     auto dFdL = D.block<3, 1>(0, 7);
0280     // dGdx is already initialised as (3x3) identity
0281     auto dGdT = D.block<3, 3>(4, 4);
0282     auto dGdL = D.block<3, 1>(4, 7);
0283 
0284     ActsMatrix<3, 3> dk1dT = ActsMatrix<3, 3>::Zero();
0285     ActsMatrix<3, 3> dk2dT = ActsMatrix<3, 3>::Identity();
0286     ActsMatrix<3, 3> dk3dT = ActsMatrix<3, 3>::Identity();
0287     ActsMatrix<3, 3> dk4dT = ActsMatrix<3, 3>::Identity();
0288 
0289     Vector3 dk1dL = Vector3::Zero();
0290     Vector3 dk2dL = Vector3::Zero();
0291     Vector3 dk3dL = Vector3::Zero();
0292     Vector3 dk4dL = Vector3::Zero();
0293 
0294     /// Propagation of derivatives of dLambda''dlambda at each sub-step
0295     std::array<double, 4> jdL{};
0296 
0297     // Evaluation of the rightmost column without the last term.
0298     jdL[0] = dLdl[0];
0299     dk1dL = dir.cross(sd.B_first);
0300 
0301     jdL[1] = dLdl[1] * (1. + half_h * jdL[0]);
0302     dk2dL = (1. + half_h * jdL[0]) * (dir + half_h * sd.k1).cross(sd.B_middle) +
0303             qop[1] * half_h * dk1dL.cross(sd.B_middle);
0304 
0305     jdL[2] = dLdl[2] * (1. + half_h * jdL[1]);
0306     dk3dL = (1. + half_h * jdL[1]) * (dir + half_h * sd.k2).cross(sd.B_middle) +
0307             qop[2] * half_h * dk2dL.cross(sd.B_middle);
0308 
0309     jdL[3] = dLdl[3] * (1. + h * jdL[2]);
0310     dk4dL = (1. + h * jdL[2]) * (dir + h * sd.k3).cross(sd.B_last) +
0311             qop[3] * h * dk3dL.cross(sd.B_last);
0312 
0313     dk1dT(0, 1) = sd.B_first.z();
0314     dk1dT(0, 2) = -sd.B_first.y();
0315     dk1dT(1, 0) = -sd.B_first.z();
0316     dk1dT(1, 2) = sd.B_first.x();
0317     dk1dT(2, 0) = sd.B_first.y();
0318     dk1dT(2, 1) = -sd.B_first.x();
0319     dk1dT *= qop[0];
0320 
0321     dk2dT += half_h * dk1dT;
0322     dk2dT = qop[1] * VectorHelpers::cross(dk2dT, sd.B_middle);
0323 
0324     dk3dT += half_h * dk2dT;
0325     dk3dT = qop[2] * VectorHelpers::cross(dk3dT, sd.B_middle);
0326 
0327     dk4dT += h * dk3dT;
0328     dk4dT = qop[3] * VectorHelpers::cross(dk4dT, sd.B_last);
0329 
0330     dFdT.setIdentity();
0331     dFdT += h / 6. * (dk1dT + dk2dT + dk3dT);
0332     dFdT *= h;
0333 
0334     dFdL = h * h / 6. * (dk1dL + dk2dL + dk3dL);
0335 
0336     dGdT += h / 6. * (dk1dT + 2. * (dk2dT + dk3dT) + dk4dT);
0337 
0338     dGdL = h / 6. * (dk1dL + 2. * (dk2dL + dk3dL) + dk4dL);
0339 
0340     // Evaluation of the dLambda''/dlambda term
0341     D(7, 7) += (h / 6.) * (jdL[0] + 2. * (jdL[1] + jdL[2]) + jdL[3]);
0342 
0343     // The following comment lines refer to the application of the time being
0344     // treated as a position. Since t and qop are treated independently for now,
0345     // this just serves as entry point for building their relation
0346     //~ double dtpp1dl = -mass * mass * qop[0] * qop[0] *
0347     //~ (3. * g + qop[0] * dgdqop(energy[0], .mass,
0348     //~ absPdg, meanEnergyLoss));
0349 
0350     double dtp1dl = qop[0] * mass * mass / std::hypot(1, qop[0] * mass);
0351     double qopNew = qop[0] + half_h * Lambdappi[0];
0352 
0353     //~ double dtpp2dl = -mass * mass * qopNew *
0354     //~ qopNew *
0355     //~ (3. * g * (1. + half_h * jdL[0]) +
0356     //~ qopNew * dgdqop(energy[1], mass, absPdgCode, meanEnergyLoss));
0357 
0358     double dtp2dl = qopNew * mass * mass / std::hypot(1, qopNew * mass);
0359     qopNew = qop[0] + half_h * Lambdappi[1];
0360 
0361     //~ double dtpp3dl = -mass * mass * qopNew *
0362     //~ qopNew *
0363     //~ (3. * g * (1. + half_h * jdL[1]) +
0364     //~ qopNew * dgdqop(energy[2], mass, absPdg, meanEnergyLoss));
0365 
0366     double dtp3dl = qopNew * mass * mass / std::hypot(1, qopNew * mass);
0367     qopNew = qop[0] + half_h * Lambdappi[2];
0368     double dtp4dl = qopNew * mass * mass / std::hypot(1, qopNew * mass);
0369 
0370     //~ D(3, 7) = h * mass * mass * qop[0] /
0371     //~ std::hypot(1., mass * qop[0])
0372     //~ + h * h / 6. * (dtpp1dl + dtpp2dl + dtpp3dl);
0373 
0374     D(3, 7) = (h / 6.) * (dtp1dl + 2. * (dtp2dl + dtp3dl) + dtp4dl);
0375     return true;
0376   }
0377 
0378   /// @brief Initializer of all parameters related to a RKN4 step with energy
0379   /// loss of a particle in material
0380   ///
0381   /// @tparam propagator_state_t Type of the state of the propagator
0382   /// @tparam stepper_t Type of the stepper
0383   ///
0384   /// @param [in] state Deliverer of configurations
0385   /// @param [in] stepper Stepper of the propagator
0386   template <typename propagator_state_t, typename stepper_t>
0387   void initializeEnergyLoss(const propagator_state_t& state,
0388                             const stepper_t& stepper) {
0389     const auto& particleHypothesis = stepper.particleHypothesis(state.stepping);
0390     float mass = particleHypothesis.mass();
0391     PdgParticle absPdg = particleHypothesis.absolutePdg();
0392     float absQ = particleHypothesis.absoluteCharge();
0393 
0394     energy[0] = std::hypot(initialMomentum, mass);
0395     // use unit length as thickness to compute the energy loss per unit length
0396     Acts::MaterialSlab slab(material, 1);
0397     // Use the same energy loss throughout the step.
0398     if (state.options.meanEnergyLoss) {
0399       g = -computeEnergyLossMean(slab, absPdg, mass, static_cast<float>(qop[0]),
0400                                  absQ);
0401     } else {
0402       // TODO using the unit path length is not quite right since the most
0403       //      probably energy loss is not independent from the path length.
0404       g = -computeEnergyLossMode(slab, absPdg, mass, static_cast<float>(qop[0]),
0405                                  absQ);
0406     }
0407     // Change of the momentum per path length
0408     // dPds = dPdE * dEds
0409     dPds[0] = g * energy[0] / initialMomentum;
0410     if (state.stepping.covTransport) {
0411       // Calculate the change of the energy loss per path length and
0412       // inverse momentum
0413       if (state.options.includeGradient) {
0414         if (state.options.meanEnergyLoss) {
0415           dgdqopValue = deriveEnergyLossMeanQOverP(
0416               slab, absPdg, mass, static_cast<float>(qop[0]), absQ);
0417         } else {
0418           // TODO path length dependence; see above
0419           dgdqopValue = deriveEnergyLossModeQOverP(
0420               slab, absPdg, mass, static_cast<float>(qop[0]), absQ);
0421         }
0422       }
0423       // Calculate term for later error propagation
0424       dLdl[0] = (-qop[0] * qop[0] * g * energy[0] *
0425                      (3. - (initialMomentum * initialMomentum) /
0426                                (energy[0] * energy[0])) -
0427                  qop[0] * qop[0] * qop[0] * energy[0] * dgdqopValue);
0428     }
0429   }
0430 
0431   /// @brief Update of the kinematic parameters of the RKN4 sub-steps after
0432   /// initialization with energy loss of a particle in material
0433   ///
0434   /// @tparam propagator_state_t Type of the state of the propagator
0435   /// @tparam stepper_t Type of the stepper
0436   ///
0437   /// @param [in] h Stepped distance of the sub-step (1-3)
0438   /// @param [in] mass Mass of the particle
0439   /// @param [in] state State of the stepper
0440   /// @param [in] stepper Stepper of the propagator
0441   /// @param [in] i Index of the sub-step (1-3)
0442   template <typename propagator_state_t, typename stepper_t>
0443   void updateEnergyLoss(const double mass, const double h,
0444                         const propagator_state_t& state,
0445                         const stepper_t& stepper, const int i) {
0446     // Update parameters related to a changed momentum
0447     currentMomentum = initialMomentum + h * dPds[i - 1];
0448     energy[i] = std::hypot(currentMomentum, mass);
0449     dPds[i] = g * energy[i] / currentMomentum;
0450     qop[i] = stepper.charge(state.stepping) / currentMomentum;
0451     // Calculate term for later error propagation
0452     if (state.stepping.covTransport) {
0453       dLdl[i] = (-qop[i] * qop[i] * g * energy[i] *
0454                      (3. - (currentMomentum * currentMomentum) /
0455                                (energy[i] * energy[i])) -
0456                  qop[i] * qop[i] * qop[i] * energy[i] * dgdqopValue);
0457     }
0458   }
0459 };
0460 
0461 template <typename action_list_t = ActionList<>,
0462           typename aborter_list_t = AbortList<>>
0463 struct DenseStepperPropagatorOptions
0464     : public PropagatorOptions<action_list_t, aborter_list_t> {
0465   /// Copy Constructor
0466   DenseStepperPropagatorOptions(
0467       const DenseStepperPropagatorOptions<action_list_t, aborter_list_t>&
0468           dspo) = default;
0469 
0470   /// Constructor with GeometryContext
0471   ///
0472   /// @param gctx The current geometry context object, e.g. alignment
0473   /// @param mctx The current magnetic fielc context object
0474   DenseStepperPropagatorOptions(const GeometryContext& gctx,
0475                                 const MagneticFieldContext& mctx)
0476       : PropagatorOptions<action_list_t, aborter_list_t>(gctx, mctx) {}
0477 
0478   /// Toggle between mean and mode evaluation of energy loss
0479   bool meanEnergyLoss = true;
0480 
0481   /// Boolean flag for inclusion of d(dEds)d(q/p) into energy loss
0482   bool includeGradient = true;
0483 
0484   /// Cut-off value for the momentum in SI units
0485   double momentumCutOff = 0.;
0486 
0487   /// @brief Expand the Options with extended aborters
0488   ///
0489   /// @tparam extended_aborter_list_t Type of the new aborter list
0490   ///
0491   /// @param aborters The new aborter list to be used (internally)
0492   template <typename extended_aborter_list_t>
0493   DenseStepperPropagatorOptions<action_list_t, extended_aborter_list_t> extend(
0494       extended_aborter_list_t aborters) const {
0495     DenseStepperPropagatorOptions<action_list_t, extended_aborter_list_t>
0496         eoptions(this->geoContext, this->magFieldContext);
0497 
0498     // Copy the options over
0499     eoptions.setPlainOptions(*this);
0500 
0501     // Action / abort list
0502     eoptions.actionList = std::move(this->actionList);
0503     eoptions.abortList = std::move(aborters);
0504 
0505     // Copy dense environment specific parameters
0506     eoptions.meanEnergyLoss = meanEnergyLoss;
0507     eoptions.includeGradient = includeGradient;
0508     eoptions.momentumCutOff = momentumCutOff;
0509 
0510     // And return the options
0511     return eoptions;
0512   }
0513 };
0514 
0515 }  // namespace Acts