File indexing completed on 2025-08-05 08:09:18
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/EventData/TransformationHelpers.hpp"
0010 #include "Acts/Propagator/ConstrainedStep.hpp"
0011 #include "Acts/Propagator/detail/CovarianceEngine.hpp"
0012
0013 template <typename E, typename A>
0014 Acts::EigenStepper<E, A>::EigenStepper(
0015 std::shared_ptr<const MagneticFieldProvider> bField, double overstepLimit)
0016 : m_bField(std::move(bField)), m_overstepLimit(overstepLimit) {}
0017
0018 template <typename E, typename A>
0019 auto Acts::EigenStepper<E, A>::makeState(
0020 std::reference_wrapper<const GeometryContext> gctx,
0021 std::reference_wrapper<const MagneticFieldContext> mctx,
0022 const BoundTrackParameters& par, double ssize) const -> State {
0023 return State{gctx, m_bField->makeCache(mctx), par, ssize};
0024 }
0025
0026 template <typename E, typename A>
0027 void Acts::EigenStepper<E, A>::resetState(State& state,
0028 const BoundVector& boundParams,
0029 const BoundSquareMatrix& cov,
0030 const Surface& surface,
0031 const double stepSize) const {
0032 FreeVector freeParams =
0033 transformBoundToFreeParameters(surface, state.geoContext, boundParams);
0034
0035
0036 state.pars = freeParams;
0037 state.cov = cov;
0038 state.stepSize = ConstrainedStep(stepSize);
0039 state.pathAccumulated = 0.;
0040
0041
0042 state.jacToGlobal = surface.boundToFreeJacobian(
0043 state.geoContext, freeParams.template segment<3>(eFreePos0),
0044 freeParams.template segment<3>(eFreeDir0));
0045 state.jacobian = BoundMatrix::Identity();
0046 state.jacTransport = FreeMatrix::Identity();
0047 state.derivative = FreeVector::Zero();
0048 }
0049
0050 template <typename E, typename A>
0051 auto Acts::EigenStepper<E, A>::boundState(
0052 State& state, const Surface& surface, bool transportCov,
0053 const FreeToBoundCorrection& freeToBoundCorrection) const
0054 -> Result<BoundState> {
0055 return detail::boundState(
0056 state.geoContext, surface, state.cov, state.jacobian, state.jacTransport,
0057 state.derivative, state.jacToGlobal, state.pars, state.particleHypothesis,
0058 state.covTransport && transportCov, state.pathAccumulated,
0059 freeToBoundCorrection);
0060 }
0061
0062 template <typename E, typename A>
0063 template <typename propagator_state_t, typename navigator_t>
0064 bool Acts::EigenStepper<E, A>::prepareCurvilinearState(
0065 propagator_state_t& prop_state, const navigator_t& navigator) const {
0066
0067 if (prop_state.stepping.pathAccumulated == 0.) {
0068
0069
0070
0071 if (prop_state.stepping.extension.validExtensionForStep(prop_state, *this,
0072 navigator)) {
0073
0074 auto& sd = prop_state.stepping.stepData;
0075 auto pos = position(prop_state.stepping);
0076 auto fieldRes = getField(prop_state.stepping, pos);
0077 if (fieldRes.ok()) {
0078 sd.B_first = *fieldRes;
0079 if (prop_state.stepping.extension.k1(prop_state, *this, navigator,
0080 sd.k1, sd.B_first, sd.kQoP)) {
0081
0082 prop_state.stepping.derivative.template head<3>() =
0083 prop_state.stepping.pars.template segment<3>(eFreeDir0);
0084
0085 prop_state.stepping.derivative.template segment<3>(4) = sd.k1;
0086
0087 prop_state.stepping.extension.finalize(
0088 prop_state, *this, navigator,
0089 prop_state.stepping.pathAccumulated);
0090 return true;
0091 }
0092 }
0093 }
0094 return false;
0095 }
0096 return true;
0097 }
0098
0099 template <typename E, typename A>
0100 auto Acts::EigenStepper<E, A>::curvilinearState(State& state,
0101 bool transportCov) const
0102 -> CurvilinearState {
0103 return detail::curvilinearState(
0104 state.cov, state.jacobian, state.jacTransport, state.derivative,
0105 state.jacToGlobal, state.pars, state.particleHypothesis,
0106 state.covTransport && transportCov, state.pathAccumulated);
0107 }
0108
0109 template <typename E, typename A>
0110 void Acts::EigenStepper<E, A>::update(State& state,
0111 const FreeVector& freeParams,
0112 const BoundVector& ,
0113 const Covariance& covariance,
0114 const Surface& surface) const {
0115 state.pars = freeParams;
0116 state.cov = covariance;
0117 state.jacToGlobal = surface.boundToFreeJacobian(
0118 state.geoContext, freeParams.template segment<3>(eFreePos0),
0119 freeParams.template segment<3>(eFreeDir0));
0120 }
0121
0122 template <typename E, typename A>
0123 void Acts::EigenStepper<E, A>::update(State& state, const Vector3& uposition,
0124 const Vector3& udirection, double qOverP,
0125 double time) const {
0126 state.pars.template segment<3>(eFreePos0) = uposition;
0127 state.pars.template segment<3>(eFreeDir0) = udirection;
0128 state.pars[eFreeTime] = time;
0129 state.pars[eFreeQOverP] = qOverP;
0130 }
0131
0132 template <typename E, typename A>
0133 void Acts::EigenStepper<E, A>::transportCovarianceToCurvilinear(
0134 State& state) const {
0135 detail::transportCovarianceToCurvilinear(state.cov, state.jacobian,
0136 state.jacTransport, state.derivative,
0137 state.jacToGlobal, direction(state));
0138 }
0139
0140 template <typename E, typename A>
0141 void Acts::EigenStepper<E, A>::transportCovarianceToBound(
0142 State& state, const Surface& surface,
0143 const FreeToBoundCorrection& freeToBoundCorrection) const {
0144 detail::transportCovarianceToBound(state.geoContext.get(), surface, state.cov,
0145 state.jacobian, state.jacTransport,
0146 state.derivative, state.jacToGlobal,
0147 state.pars, freeToBoundCorrection);
0148 }
0149
0150 template <typename E, typename A>
0151 template <typename propagator_state_t, typename navigator_t>
0152 Acts::Result<double> Acts::EigenStepper<E, A>::step(
0153 propagator_state_t& state, const navigator_t& navigator) const {
0154
0155 auto& sd = state.stepping.stepData;
0156 double error_estimate = 0.;
0157 double h2 = 0, half_h = 0;
0158
0159 auto pos = position(state.stepping);
0160 auto dir = direction(state.stepping);
0161
0162
0163 auto fieldRes = getField(state.stepping, pos);
0164 if (!fieldRes.ok()) {
0165 return fieldRes.error();
0166 }
0167 sd.B_first = *fieldRes;
0168 if (!state.stepping.extension.validExtensionForStep(state, *this,
0169 navigator) ||
0170 !state.stepping.extension.k1(state, *this, navigator, sd.k1, sd.B_first,
0171 sd.kQoP)) {
0172 return 0.;
0173 }
0174
0175
0176
0177
0178
0179 const auto tryRungeKuttaStep = [&](const double h) -> Result<bool> {
0180
0181 constexpr auto success = &Result<bool>::success;
0182 constexpr auto failure = &Result<bool>::failure;
0183
0184
0185 h2 = h * h;
0186 half_h = h * 0.5;
0187
0188
0189 const Vector3 pos1 = pos + half_h * dir + h2 * 0.125 * sd.k1;
0190 auto field = getField(state.stepping, pos1);
0191 if (!field.ok()) {
0192 return failure(field.error());
0193 }
0194 sd.B_middle = *field;
0195
0196 if (!state.stepping.extension.k2(state, *this, navigator, sd.k2,
0197 sd.B_middle, sd.kQoP, half_h, sd.k1)) {
0198 return success(false);
0199 }
0200
0201
0202 if (!state.stepping.extension.k3(state, *this, navigator, sd.k3,
0203 sd.B_middle, sd.kQoP, half_h, sd.k2)) {
0204 return success(false);
0205 }
0206
0207
0208 const Vector3 pos2 = pos + h * dir + h2 * 0.5 * sd.k3;
0209 field = getField(state.stepping, pos2);
0210 if (!field.ok()) {
0211 return failure(field.error());
0212 }
0213 sd.B_last = *field;
0214 if (!state.stepping.extension.k4(state, *this, navigator, sd.k4, sd.B_last,
0215 sd.kQoP, h, sd.k3)) {
0216 return success(false);
0217 }
0218
0219
0220 error_estimate =
0221 h2 * ((sd.k1 - sd.k2 - sd.k3 + sd.k4).template lpNorm<1>() +
0222 std::abs(sd.kQoP[0] - sd.kQoP[1] - sd.kQoP[2] + sd.kQoP[3]));
0223 error_estimate = std::max(error_estimate, 1e-20);
0224
0225 return success(error_estimate <= state.options.stepTolerance);
0226 };
0227
0228 const double initialH =
0229 state.stepping.stepSize.value() * state.options.direction;
0230 double h = initialH;
0231 std::size_t nStepTrials = 0;
0232
0233
0234 while (true) {
0235 auto res = tryRungeKuttaStep(h);
0236 if (!res.ok()) {
0237 return res.error();
0238 }
0239 if (!!res.value()) {
0240 break;
0241 }
0242
0243
0244 const double stepSizeScaling =
0245 std::clamp(std::sqrt(std::sqrt(state.options.stepTolerance /
0246 std::abs(2. * error_estimate))),
0247 0.25, 4.0);
0248 h *= stepSizeScaling;
0249
0250
0251
0252 if (std::abs(h) < std::abs(state.options.stepSizeCutOff)) {
0253
0254 return EigenStepperError::StepSizeStalled;
0255 }
0256
0257
0258
0259 if (nStepTrials > state.options.maxRungeKuttaStepTrials) {
0260
0261 return EigenStepperError::StepSizeAdjustmentFailed;
0262 }
0263 nStepTrials++;
0264 }
0265
0266
0267 if (state.stepping.covTransport) {
0268
0269 FreeMatrix D;
0270 if (!state.stepping.extension.finalize(state, *this, navigator, h, D)) {
0271 return EigenStepperError::StepInvalid;
0272 }
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291 assert((D.topLeftCorner<4, 4>().isIdentity()));
0292 assert((D.bottomLeftCorner<4, 4>().isZero()));
0293 assert((state.stepping.jacTransport.template topLeftCorner<4, 4>()
0294 .isIdentity()));
0295 assert((state.stepping.jacTransport.template bottomLeftCorner<4, 4>()
0296 .isZero()));
0297
0298 state.stepping.jacTransport.template topRightCorner<4, 4>() +=
0299 D.topRightCorner<4, 4>() *
0300 state.stepping.jacTransport.template bottomRightCorner<4, 4>();
0301 state.stepping.jacTransport.template bottomRightCorner<4, 4>() =
0302 (D.bottomRightCorner<4, 4>() *
0303 state.stepping.jacTransport.template bottomRightCorner<4, 4>())
0304 .eval();
0305 } else {
0306 if (!state.stepping.extension.finalize(state, *this, navigator, h)) {
0307 return EigenStepperError::StepInvalid;
0308 }
0309 }
0310
0311
0312 state.stepping.pars.template segment<3>(eFreePos0) +=
0313 h * dir + h2 / 6. * (sd.k1 + sd.k2 + sd.k3);
0314 state.stepping.pars.template segment<3>(eFreeDir0) +=
0315 h / 6. * (sd.k1 + 2. * (sd.k2 + sd.k3) + sd.k4);
0316 (state.stepping.pars.template segment<3>(eFreeDir0)).normalize();
0317
0318 if (state.stepping.covTransport) {
0319 state.stepping.derivative.template head<3>() =
0320 state.stepping.pars.template segment<3>(eFreeDir0);
0321 state.stepping.derivative.template segment<3>(4) = sd.k4;
0322 }
0323 state.stepping.pathAccumulated += h;
0324
0325 const double stepSizeScaling =
0326 std::clamp(std::sqrt(std::sqrt(state.options.stepTolerance /
0327 std::abs(error_estimate))),
0328 0.25, 4.0);
0329 const double nextAccuracy = std::abs(h * stepSizeScaling);
0330 const double previousAccuracy = std::abs(state.stepping.stepSize.accuracy());
0331 const double initialStepLength = std::abs(initialH);
0332 if (nextAccuracy < initialStepLength || nextAccuracy > previousAccuracy) {
0333 state.stepping.stepSize.setAccuracy(nextAccuracy);
0334 }
0335 state.stepping.stepSize.nStepTrials = nStepTrials;
0336
0337 return h;
0338 }
0339
0340 template <typename E, typename A>
0341 void Acts::EigenStepper<E, A>::setIdentityJacobian(State& state) const {
0342 state.jacobian = BoundMatrix::Identity();
0343 }