Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-08 08:27:22

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
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   // Pre-Propagation: call to the actor list, abort condition check
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         // This indicates a geometry overlap which is not handled by the
0063         // navigator, so we skip this target.
0064         // This can also happen in a well-behaved geometry with external
0065         // surfaces.
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   // priming error condition
0082   bool terminatedNormally = false;
0083 
0084   // Pre-Stepping: target setting
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   // Stepping loop
0099   for (; state.steps < state.options.maxSteps; ++state.steps) {
0100     // Perform a step
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     // Accumulate the path length
0110     state.pathLength += *res;
0111     // Update the position and direction
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     // release actor and aborter constrains after step was performed
0122     m_stepper.releaseStepSize(state.stepping, ConstrainedStep::Type::Navigator);
0123     m_stepper.releaseStepSize(state.stepping, ConstrainedStep::Type::Actor);
0124 
0125     // Post-stepping: check target status, call actors, check abort conditions
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     // Update the position and direction because actors might have changed it
0158     state.position = m_stepper.position(state.stepping);
0159     state.direction =
0160         state.options.direction * m_stepper.direction(state.stepping);
0161 
0162     // Pre-Stepping: target setting
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       // navigator step constraint is not valid anymore
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   }  // end of stepping loop
0187 
0188   // check if we didn't terminate normally via aborters
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   // Post-stepping call to the actor list
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   // Perform the actual propagation
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   // Perform the actual propagation
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   // Expand the actor list with a path aborter, and with a target aborter
0267   // unless the propagation has no target surface
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   // Create the extended options and declare their type
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   // Hand the target surface to the aborter that stops the propagation there
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   // Navigator initialize state call
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   // Apply the loop protection - it resets the internal path limit
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& /*options*/,
0334                                   bool createFinalParameters,
0335                                   const Surface* target) const
0336     -> Result<ResultType<propagator_options_t>> {
0337   // Type of the full propagation result, including output from actors
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       // We are at a surface, so we need to compute the bound state
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   // dummy initialization
0413   Result<DerivedResult> res =
0414       Result<DerivedResult>::failure(PropagatorError::Failure);
0415 
0416   // Due to the geometry of the perigee and point surfaces (their intersection
0417   // is a point of closest approach, which can sit behind the current step) the
0418   // overstepping tolerance is sometimes not met.
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   // Without errors we can expect a valid endParameters when propagating to a
0437   // target surface
0438   assert((*res).endParameters);
0439   return std::move((*res).endParameters.value());
0440 }
0441 
0442 }  // namespace Acts