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