Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:11:28

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 #include "Acts/Propagator/SympyStepper.hpp"
0010 
0011 #include "Acts/Propagator/detail/SympyCovarianceEngine.hpp"
0012 #include "Acts/Propagator/detail/SympyJacobianEngine.hpp"
0013 
0014 #include <cmath>
0015 
0016 #include "codegen/sympy_stepper_math.hpp"
0017 
0018 namespace Acts {
0019 
0020 SympyStepper::SympyStepper(std::shared_ptr<const MagneticFieldProvider> bField)
0021     : m_bField(std::move(bField)) {}
0022 
0023 SympyStepper::SympyStepper(const Config& config) : m_bField(config.bField) {}
0024 
0025 SympyStepper::State SympyStepper::makeState(
0026     const Options& options, const BoundTrackParameters& par) const {
0027   State state{options, m_bField->makeCache(options.magFieldContext)};
0028 
0029   state.particleHypothesis = par.particleHypothesis();
0030 
0031   Vector3 position = par.position(options.geoContext);
0032   Vector3 direction = par.direction();
0033   state.pars.template segment<3>(eFreePos0) = position;
0034   state.pars.template segment<3>(eFreeDir0) = direction;
0035   state.pars[eFreeTime] = par.time();
0036   state.pars[eFreeQOverP] = par.parameters()[eBoundQOverP];
0037 
0038   // Init the jacobian matrix if needed
0039   if (par.covariance()) {
0040     // Get the reference surface for navigation
0041     const auto& surface = par.referenceSurface();
0042     // set the covariance transport flag to true and copy
0043     state.covTransport = true;
0044     state.cov = BoundSquareMatrix(*par.covariance());
0045     state.jacToGlobal =
0046         surface.boundToFreeJacobian(options.geoContext, position, direction);
0047   }
0048 
0049   state.stepSize = ConstrainedStep(options.maxStepSize);
0050 
0051   return state;
0052 }
0053 
0054 void SympyStepper::resetState(State& state, const BoundVector& boundParams,
0055                               const BoundSquareMatrix& cov,
0056                               const Surface& surface,
0057                               const double stepSize) const {
0058   FreeVector freeParams = transformBoundToFreeParameters(
0059       surface, state.options.geoContext, boundParams);
0060 
0061   // Update the stepping state
0062   state.pars = freeParams;
0063   state.cov = cov;
0064   state.stepSize = ConstrainedStep(stepSize);
0065   state.pathAccumulated = 0.;
0066 
0067   // Reinitialize the stepping jacobian
0068   state.jacToGlobal = surface.boundToFreeJacobian(
0069       state.options.geoContext, freeParams.template segment<3>(eFreePos0),
0070       freeParams.template segment<3>(eFreeDir0));
0071   state.jacobian = BoundMatrix::Identity();
0072   state.jacTransport = FreeMatrix::Identity();
0073   state.derivative = FreeVector::Zero();
0074 }
0075 
0076 Result<std::tuple<BoundTrackParameters, BoundMatrix, double>>
0077 SympyStepper::boundState(
0078     State& state, const Surface& surface, bool transportCov,
0079     const FreeToBoundCorrection& freeToBoundCorrection) const {
0080   return detail::sympy::boundState(
0081       state.options.geoContext, surface, state.cov, state.jacobian,
0082       state.jacTransport, state.derivative, state.jacToGlobal, state.pars,
0083       state.particleHypothesis, state.covTransport && transportCov,
0084       state.pathAccumulated, freeToBoundCorrection);
0085 }
0086 
0087 std::tuple<CurvilinearTrackParameters, BoundMatrix, double>
0088 SympyStepper::curvilinearState(State& state, bool transportCov) const {
0089   return detail::sympy::curvilinearState(
0090       state.cov, state.jacobian, state.jacTransport, state.derivative,
0091       state.jacToGlobal, state.pars, state.particleHypothesis,
0092       state.covTransport && transportCov, state.pathAccumulated);
0093 }
0094 
0095 void SympyStepper::update(State& state, const FreeVector& freeParams,
0096                           const BoundVector& /*boundParams*/,
0097                           const Covariance& covariance,
0098                           const Surface& surface) const {
0099   state.pars = freeParams;
0100   state.cov = covariance;
0101   state.jacToGlobal = surface.boundToFreeJacobian(
0102       state.options.geoContext, freeParams.template segment<3>(eFreePos0),
0103       freeParams.template segment<3>(eFreeDir0));
0104 }
0105 
0106 void SympyStepper::update(State& state, const Vector3& uposition,
0107                           const Vector3& udirection, double qOverP,
0108                           double time) const {
0109   state.pars.template segment<3>(eFreePos0) = uposition;
0110   state.pars.template segment<3>(eFreeDir0) = udirection;
0111   state.pars[eFreeTime] = time;
0112   state.pars[eFreeQOverP] = qOverP;
0113 }
0114 
0115 void SympyStepper::transportCovarianceToCurvilinear(State& state) const {
0116   detail::sympy::transportCovarianceToCurvilinear(
0117       state.cov, state.jacobian, state.jacTransport, state.derivative,
0118       state.jacToGlobal, state.pars.template segment<3>(eFreeDir0));
0119 }
0120 
0121 void SympyStepper::transportCovarianceToBound(
0122     State& state, const Surface& surface,
0123     const FreeToBoundCorrection& freeToBoundCorrection) const {
0124   detail::sympy::transportCovarianceToBound(
0125       state.options.geoContext, surface, state.cov, state.jacobian,
0126       state.jacTransport, state.derivative, state.jacToGlobal, state.pars,
0127       freeToBoundCorrection);
0128 }
0129 
0130 Result<double> SympyStepper::stepImpl(
0131     State& state, Direction stepDirection, double stepTolerance,
0132     double stepSizeCutOff, std::size_t maxRungeKuttaStepTrials) const {
0133   auto pos = position(state);
0134   auto dir = direction(state);
0135   double t = time(state);
0136   double qop = qOverP(state);
0137   double m = particleHypothesis(state).mass();
0138   double p_abs = absoluteMomentum(state);
0139 
0140   auto getB = [&](const double* p) -> Result<Vector3> {
0141     return getField(state, {p[0], p[1], p[2]});
0142   };
0143 
0144   const auto calcStepSizeScaling = [&](const double errorEstimate_) -> double {
0145     // For details about these values see ATL-SOFT-PUB-2009-001
0146     constexpr double lower = 0.25;
0147     constexpr double upper = 4.0;
0148     // This is given by the order of the Runge-Kutta method
0149     constexpr double exponent = 0.25;
0150 
0151     double x = stepTolerance / errorEstimate_;
0152 
0153     if constexpr (exponent == 0.25) {
0154       // This is 3x faster than std::pow
0155       x = std::sqrt(std::sqrt(x));
0156     } else {
0157       x = std::pow(x, exponent);
0158     }
0159 
0160     return std::clamp(x, lower, upper);
0161   };
0162 
0163   double h = state.stepSize.value() * stepDirection;
0164   double initialH = h;
0165   std::size_t nStepTrials = 0;
0166   double errorEstimate = 0.;
0167 
0168   while (true) {
0169     ++nStepTrials;
0170     ++state.statistics.nAttemptedSteps;
0171 
0172     // For details about the factor 4 see ATL-SOFT-PUB-2009-001
0173     Result<bool> res =
0174         rk4(pos.data(), dir.data(), t, h, qop, m, p_abs, getB, &errorEstimate,
0175             4 * stepTolerance, state.pars.template segment<3>(eFreePos0).data(),
0176             state.pars.template segment<3>(eFreeDir0).data(),
0177             state.pars.template segment<1>(eFreeTime).data(),
0178             state.derivative.data(),
0179             state.covTransport ? state.jacTransport.data() : nullptr);
0180     if (!res.ok()) {
0181       return res.error();
0182     }
0183     // Protect against division by zero
0184     errorEstimate = std::max(1e-20, errorEstimate);
0185 
0186     if (*res) {
0187       break;
0188     }
0189 
0190     ++state.statistics.nRejectedSteps;
0191 
0192     const double stepSizeScaling = calcStepSizeScaling(errorEstimate);
0193     h *= stepSizeScaling;
0194 
0195     // If step size becomes too small the particle remains at the initial
0196     // place
0197     if (std::abs(h) < std::abs(stepSizeCutOff)) {
0198       // Not moving due to too low momentum needs an aborter
0199       return EigenStepperError::StepSizeStalled;
0200     }
0201 
0202     // If the parameter is off track too much or given stepSize is not
0203     // appropriate
0204     if (nStepTrials > maxRungeKuttaStepTrials) {
0205       // Too many trials, have to abort
0206       return EigenStepperError::StepSizeAdjustmentFailed;
0207     }
0208   }
0209 
0210   state.pathAccumulated += h;
0211   ++state.nSteps;
0212   state.nStepTrials += nStepTrials;
0213 
0214   ++state.statistics.nSuccessfulSteps;
0215   if (stepDirection != Direction::fromScalarZeroAsPositive(initialH)) {
0216     ++state.statistics.nReverseSteps;
0217   }
0218   state.statistics.pathLength += h;
0219   state.statistics.absolutePathLength += std::abs(h);
0220 
0221   const double stepSizeScaling = calcStepSizeScaling(errorEstimate);
0222   const double nextAccuracy = std::abs(h * stepSizeScaling);
0223   const double previousAccuracy = std::abs(state.stepSize.accuracy());
0224   const double initialStepLength = std::abs(initialH);
0225   if (nextAccuracy < initialStepLength || nextAccuracy > previousAccuracy) {
0226     state.stepSize.setAccuracy(nextAccuracy);
0227   }
0228 
0229   return h;
0230 }
0231 
0232 void SympyStepper::setIdentityJacobian(State& state) const {
0233   state.jacobian = BoundMatrix::Identity();
0234 }
0235 
0236 }  // namespace Acts