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