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