File indexing completed on 2025-11-27 09:19:19
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Propagator/Propagator.hpp"
0012
0013 #include "Acts/EventData/TrackParametersConcept.hpp"
0014 #include "Acts/Propagator/ActorList.hpp"
0015 #include "Acts/Propagator/ConstrainedStep.hpp"
0016 #include "Acts/Propagator/NavigationTarget.hpp"
0017 #include "Acts/Propagator/PropagatorError.hpp"
0018 #include "Acts/Propagator/StandardAborters.hpp"
0019 #include "Acts/Propagator/detail/LoopProtection.hpp"
0020 #include "Acts/Utilities/Intersection.hpp"
0021
0022 #include <concepts>
0023
0024 template <typename S, typename N>
0025 template <typename propagator_state_t>
0026 Acts::Result<void> Acts::Propagator<S, N>::propagate(
0027 propagator_state_t& state) const {
0028 ACTS_VERBOSE("Entering propagation.");
0029
0030 state.stage = PropagatorStage::prePropagation;
0031
0032
0033 state.options.actorList.act(state, m_stepper, m_navigator, logger());
0034
0035 if (state.options.actorList.checkAbort(state, m_stepper, m_navigator,
0036 logger())) {
0037 ACTS_VERBOSE("Propagation terminated without going into stepping loop.");
0038
0039 state.stage = PropagatorStage::postPropagation;
0040
0041 state.options.actorList.act(state, m_stepper, m_navigator, logger());
0042
0043 return Result<void>::success();
0044 }
0045
0046 auto getNextTarget = [&]() -> Result<NavigationTarget> {
0047 for (unsigned int i = 0; i < state.options.maxTargetSkipping; ++i) {
0048 NavigationTarget nextTarget = m_navigator.nextTarget(
0049 state.navigation, state.position, state.direction);
0050 if (nextTarget.isNone()) {
0051 return NavigationTarget::None();
0052 }
0053 IntersectionStatus preStepSurfaceStatus = m_stepper.updateSurfaceStatus(
0054 state.stepping, nextTarget.surface(), nextTarget.intersectionIndex(),
0055 state.options.direction, nextTarget.boundaryTolerance(),
0056 state.options.surfaceTolerance, ConstrainedStep::Type::Navigator,
0057 logger());
0058 if (preStepSurfaceStatus == IntersectionStatus::onSurface) {
0059
0060
0061
0062
0063 ACTS_VERBOSE("Pre-step surface status is onSurface, skipping target "
0064 << nextTarget.surface().geometryId());
0065 continue;
0066 }
0067 if (preStepSurfaceStatus == IntersectionStatus::reachable) {
0068 return nextTarget;
0069 }
0070 }
0071
0072 ACTS_ERROR("getNextTarget failed to find a valid target surface after "
0073 << state.options.maxTargetSkipping << " attempts.");
0074 return Result<NavigationTarget>::failure(
0075 PropagatorError::NextTargetLimitReached);
0076 };
0077
0078
0079 bool terminatedNormally = false;
0080
0081
0082 state.stage = PropagatorStage::preStep;
0083
0084 Result<NavigationTarget> nextTargetResult = getNextTarget();
0085 if (!nextTargetResult.ok()) {
0086 return nextTargetResult.error();
0087 }
0088 NavigationTarget nextTarget = *nextTargetResult;
0089
0090 ACTS_VERBOSE("Starting stepping loop.");
0091
0092
0093 for (; state.steps < state.options.maxSteps; ++state.steps) {
0094
0095 Result<double> res =
0096 m_stepper.step(state.stepping, state.options.direction,
0097 m_navigator.currentVolumeMaterial(state.navigation));
0098 if (!res.ok()) {
0099 ACTS_ERROR("Step failed with " << res.error() << ": "
0100 << res.error().message());
0101
0102 return res.error();
0103 }
0104
0105 state.pathLength += *res;
0106
0107 state.position = m_stepper.position(state.stepping);
0108 state.direction =
0109 state.options.direction * m_stepper.direction(state.stepping);
0110
0111 ACTS_VERBOSE("Step with size " << *res << " performed. We are now at "
0112 << state.position.transpose()
0113 << " with direction "
0114 << state.direction.transpose());
0115
0116
0117 m_stepper.releaseStepSize(state.stepping, ConstrainedStep::Type::Navigator);
0118 m_stepper.releaseStepSize(state.stepping, ConstrainedStep::Type::Actor);
0119
0120
0121 state.stage = PropagatorStage::postStep;
0122
0123 if (!nextTarget.isNone()) {
0124 IntersectionStatus postStepSurfaceStatus = m_stepper.updateSurfaceStatus(
0125 state.stepping, nextTarget.surface(), nextTarget.intersectionIndex(),
0126 state.options.direction, nextTarget.boundaryTolerance(),
0127 state.options.surfaceTolerance, ConstrainedStep::Type::Navigator,
0128 logger());
0129 if (postStepSurfaceStatus == IntersectionStatus::onSurface) {
0130 m_navigator.handleSurfaceReached(state.navigation, state.position,
0131 state.direction, nextTarget.surface());
0132 }
0133 if (postStepSurfaceStatus != IntersectionStatus::reachable) {
0134 nextTarget = NavigationTarget::None();
0135 }
0136 }
0137
0138 state.options.actorList.act(state, m_stepper, m_navigator, logger());
0139
0140 if (state.options.actorList.checkAbort(state, m_stepper, m_navigator,
0141 logger())) {
0142 terminatedNormally = true;
0143 break;
0144 }
0145
0146
0147 state.position = m_stepper.position(state.stepping);
0148 state.direction =
0149 state.options.direction * m_stepper.direction(state.stepping);
0150
0151
0152 state.stage = PropagatorStage::preStep;
0153
0154 if (!nextTarget.isNone() &&
0155 !m_navigator.checkTargetValid(state.navigation, state.position,
0156 state.direction)) {
0157 ACTS_VERBOSE("Target is not valid anymore.");
0158 nextTarget = NavigationTarget::None();
0159 }
0160
0161 if (nextTarget.isNone()) {
0162
0163 m_stepper.releaseStepSize(state.stepping,
0164 ConstrainedStep::Type::Navigator);
0165
0166 nextTargetResult = getNextTarget();
0167 if (!nextTargetResult.ok()) {
0168 return nextTargetResult.error();
0169 }
0170 nextTarget = *nextTargetResult;
0171 }
0172 }
0173
0174
0175 if (!terminatedNormally) {
0176 ACTS_ERROR("Propagation reached the step count limit of "
0177 << state.options.maxSteps << " (did " << state.steps
0178 << " steps)");
0179 return PropagatorError::StepCountLimitReached;
0180 }
0181
0182 ACTS_VERBOSE("Stepping loop done.");
0183
0184 state.stage = PropagatorStage::postPropagation;
0185
0186
0187 state.options.actorList.act(state, m_stepper, m_navigator, logger());
0188
0189 return Result<void>::success();
0190 }
0191
0192 template <typename S, typename N>
0193 template <typename parameters_t, typename propagator_options_t,
0194 typename path_aborter_t>
0195 auto Acts::Propagator<S, N>::propagate(const parameters_t& start,
0196 const propagator_options_t& options,
0197 bool createFinalParameters) const
0198 -> Result<
0199 actor_list_t_result_t<StepperBoundTrackParameters,
0200 typename propagator_options_t::actor_list_type>> {
0201 static_assert(std::copy_constructible<StepperBoundTrackParameters>,
0202 "return track parameter type must be copy-constructible");
0203
0204 auto state = makeState<propagator_options_t, path_aborter_t>(options);
0205
0206 auto initRes =
0207 initialize<decltype(state), parameters_t, path_aborter_t>(state, start);
0208 if (!initRes.ok()) {
0209 return initRes.error();
0210 }
0211
0212
0213 auto propagationResult = propagate(state);
0214
0215 return makeResult(std::move(state), propagationResult, options,
0216 createFinalParameters);
0217 }
0218
0219 template <typename S, typename N>
0220 template <typename parameters_t, typename propagator_options_t,
0221 typename target_aborter_t, typename path_aborter_t>
0222 auto Acts::Propagator<S, N>::propagate(
0223 const parameters_t& start, const Surface& target,
0224 const propagator_options_t& options) const
0225 -> Result<
0226 actor_list_t_result_t<StepperBoundTrackParameters,
0227 typename propagator_options_t::actor_list_type>> {
0228 static_assert(BoundTrackParametersConcept<parameters_t>,
0229 "Parameters do not fulfill bound parameters concept.");
0230
0231 auto state =
0232 makeState<propagator_options_t, target_aborter_t, path_aborter_t>(
0233 target, options);
0234
0235 auto initRes =
0236 initialize<decltype(state), parameters_t, path_aborter_t>(state, start);
0237 if (!initRes.ok()) {
0238 return initRes.error();
0239 }
0240
0241
0242 auto propagationResult = propagate(state);
0243
0244 return makeResult(std::move(state), propagationResult, target, options);
0245 }
0246
0247 template <typename S, typename N>
0248 template <typename propagator_options_t, typename path_aborter_t>
0249 auto Acts::Propagator<S, N>::makeState(
0250 const propagator_options_t& options) const {
0251
0252 using ReturnParameterType = StepperBoundTrackParameters;
0253
0254 static_assert(std::copy_constructible<ReturnParameterType>,
0255 "return track parameter type must be copy-constructible");
0256
0257
0258 path_aborter_t pathAborter;
0259 pathAborter.internalLimit = options.pathLimit;
0260
0261 auto actorList = options.actorList.append(pathAborter);
0262
0263
0264 auto eOptions = options.extend(actorList);
0265
0266 using OptionsType = decltype(eOptions);
0267 using StateType =
0268 actor_list_t_state_t<OptionsType,
0269 typename propagator_options_t::actor_list_type>;
0270
0271 StateType state{eOptions, m_stepper.makeState(eOptions.stepping),
0272 m_navigator.makeState(eOptions.navigation)};
0273
0274 return state;
0275 }
0276
0277 template <typename S, typename N>
0278 template <typename propagator_options_t, typename target_aborter_t,
0279 typename path_aborter_t>
0280 auto Acts::Propagator<S, N>::makeState(
0281 const Surface& target, const propagator_options_t& options) const {
0282
0283 target_aborter_t targetAborter;
0284 targetAborter.surface = ⌖
0285 path_aborter_t pathAborter;
0286 pathAborter.internalLimit = options.pathLimit;
0287
0288 auto actorList = options.actorList.append(targetAborter, pathAborter);
0289
0290
0291 auto eOptions = options.extend(actorList);
0292 eOptions.navigation.targetSurface = ⌖
0293
0294 using OptionsType = decltype(eOptions);
0295 using StateType =
0296 actor_list_t_state_t<OptionsType,
0297 typename propagator_options_t::actor_list_type>;
0298
0299 StateType state{eOptions, m_stepper.makeState(eOptions.stepping),
0300 m_navigator.makeState(eOptions.navigation)};
0301
0302 return state;
0303 }
0304
0305 template <typename S, typename N>
0306 template <typename propagator_state_t, typename parameters_t,
0307 typename path_aborter_t>
0308 Acts::Result<void> Acts::Propagator<S, N>::initialize(
0309 propagator_state_t& state, const parameters_t& start) const {
0310 static_assert(BoundTrackParametersConcept<parameters_t>,
0311 "Parameters do not fulfill bound parameters concept.");
0312
0313 m_stepper.initialize(state.stepping, start.toBound());
0314
0315 state.position = m_stepper.position(state.stepping);
0316 state.direction =
0317 state.options.direction * m_stepper.direction(state.stepping);
0318
0319 state.navigation.options.startSurface = &start.referenceSurface();
0320
0321
0322 auto navInitRes =
0323 m_navigator.initialize(state.navigation, state.position, state.direction,
0324 state.options.direction);
0325 if (!navInitRes.ok()) {
0326 return navInitRes.error();
0327 }
0328
0329
0330 detail::setupLoopProtection(
0331 state, m_stepper, state.options.actorList.template get<path_aborter_t>(),
0332 false, logger());
0333
0334 return Result<void>::success();
0335 }
0336
0337 template <typename S, typename N>
0338 template <typename propagator_state_t, typename propagator_options_t>
0339 auto Acts::Propagator<S, N>::makeResult(propagator_state_t state,
0340 Result<void> propagationResult,
0341 const propagator_options_t& ,
0342 bool createFinalParameters) const
0343 -> Result<
0344 actor_list_t_result_t<StepperBoundTrackParameters,
0345 typename propagator_options_t::actor_list_type>> {
0346
0347 using ReturnParameterType = StepperBoundTrackParameters;
0348
0349 static_assert(std::copy_constructible<ReturnParameterType>,
0350 "return track parameter type must be copy-constructible");
0351
0352
0353 using ResultType =
0354 actor_list_t_result_t<ReturnParameterType,
0355 typename propagator_options_t::actor_list_type>;
0356
0357 if (!propagationResult.ok()) {
0358 return propagationResult.error();
0359 }
0360
0361 ResultType result{};
0362 moveStateToResult(state, result);
0363
0364 const Surface* currentSurface = m_navigator.currentSurface(state.navigation);
0365 if (createFinalParameters && currentSurface == nullptr) {
0366 if (!m_stepper.prepareCurvilinearState(state.stepping)) {
0367
0368 return propagationResult.error();
0369 }
0370
0371 auto curvState = m_stepper.curvilinearState(state.stepping);
0372
0373 result.endParameters = std::get<StepperBoundTrackParameters>(curvState);
0374
0375 if (state.stepping.covTransport) {
0376 result.transportJacobian = std::get<Jacobian>(curvState);
0377 }
0378 } else if (createFinalParameters && currentSurface != nullptr) {
0379
0380 auto boundState =
0381 m_stepper.boundState(state.stepping, *currentSurface).value();
0382
0383 result.endParameters = std::get<StepperBoundTrackParameters>(boundState);
0384
0385 if (state.stepping.covTransport) {
0386 result.transportJacobian = std::get<Jacobian>(boundState);
0387 }
0388 }
0389
0390 return Result<ResultType>::success(std::move(result));
0391 }
0392
0393 template <typename S, typename N>
0394 template <typename propagator_state_t, typename propagator_options_t>
0395 auto Acts::Propagator<S, N>::makeResult(
0396 propagator_state_t state, Result<void> propagationResult,
0397 const Surface& target, const propagator_options_t& ) const
0398 -> Result<
0399 actor_list_t_result_t<StepperBoundTrackParameters,
0400 typename propagator_options_t::actor_list_type>> {
0401
0402 using ReturnParameterType = StepperBoundTrackParameters;
0403
0404 static_assert(std::copy_constructible<ReturnParameterType>,
0405 "return track parameter type must be copy-constructible");
0406
0407
0408 using ResultType =
0409 actor_list_t_result_t<ReturnParameterType,
0410 typename propagator_options_t::actor_list_type>;
0411
0412 if (!propagationResult.ok()) {
0413 return propagationResult.error();
0414 }
0415
0416 ResultType result{};
0417 moveStateToResult(state, result);
0418
0419
0420 auto bsRes = m_stepper.boundState(state.stepping, target);
0421 if (!bsRes.ok()) {
0422 return bsRes.error();
0423 }
0424 const auto& bs = *bsRes;
0425
0426
0427 result.endParameters = std::get<StepperBoundTrackParameters>(bs);
0428
0429 if (state.stepping.covTransport) {
0430 result.transportJacobian = std::get<Jacobian>(bs);
0431 }
0432 return Result<ResultType>::success(std::move(result));
0433 }
0434
0435 template <typename S, typename N>
0436 template <typename propagator_state_t, typename result_t>
0437 void Acts::Propagator<S, N>::moveStateToResult(propagator_state_t& state,
0438 result_t& result) const {
0439 result.tuple() = std::move(state.tuple());
0440
0441 result.steps = state.steps;
0442 result.pathLength = state.pathLength;
0443
0444 result.statistics.stepping = state.stepping.statistics;
0445 result.statistics.navigation = state.navigation.statistics;
0446 }
0447
0448 template <typename derived_t>
0449 Acts::Result<Acts::BoundTrackParameters>
0450 Acts::detail::BasePropagatorHelper<derived_t>::propagateToSurface(
0451 const BoundTrackParameters& start, const Surface& target,
0452 const Options& options) const {
0453 using ResultType = Result<typename derived_t::template actor_list_t_result_t<
0454 BoundTrackParameters, ActorList<>>>;
0455 using DerivedOptions = typename derived_t::template Options<>;
0456
0457 DerivedOptions derivedOptions(options);
0458
0459
0460 ResultType res = ResultType::failure(PropagatorError::Failure);
0461
0462
0463
0464 if (target.type() == Surface::SurfaceType::Perigee) {
0465 res = static_cast<const derived_t*>(this)
0466 ->template propagate<BoundTrackParameters, DerivedOptions,
0467 ForcedSurfaceReached, PathLimitReached>(
0468 start, target, derivedOptions);
0469 } else {
0470 res = static_cast<const derived_t*>(this)
0471 ->template propagate<BoundTrackParameters, DerivedOptions,
0472 SurfaceReached, PathLimitReached>(
0473 start, target, derivedOptions);
0474 }
0475
0476 if (!res.ok()) {
0477 return res.error();
0478 }
0479
0480
0481
0482 assert((*res).endParameters);
0483 return std::move((*res).endParameters.value());
0484 }