File indexing completed on 2025-01-18 09:11:28
0001
0002
0003
0004
0005
0006
0007
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
0039 if (par.covariance()) {
0040
0041 const auto& surface = par.referenceSurface();
0042
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
0062 state.pars = freeParams;
0063 state.cov = cov;
0064 state.stepSize = ConstrainedStep(stepSize);
0065 state.pathAccumulated = 0.;
0066
0067
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& ,
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
0146 constexpr double lower = 0.25;
0147 constexpr double upper = 4.0;
0148
0149 constexpr double exponent = 0.25;
0150
0151 double x = stepTolerance / errorEstimate_;
0152
0153 if constexpr (exponent == 0.25) {
0154
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
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
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
0196
0197 if (std::abs(h) < std::abs(stepSizeCutOff)) {
0198
0199 return EigenStepperError::StepSizeStalled;
0200 }
0201
0202
0203
0204 if (nStepTrials > maxRungeKuttaStepTrials) {
0205
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 }