Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-28 08:21:10

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/Definitions/Units.hpp"
0012 #include "Acts/Propagator/ConstrainedStep.hpp"
0013 #include "Acts/Surfaces/BoundaryTolerance.hpp"
0014 #include "Acts/Surfaces/Surface.hpp"
0015 #include "Acts/Utilities/Enumerate.hpp"
0016 #include "Acts/Utilities/Intersection.hpp"
0017 #include "Acts/Utilities/Logger.hpp"
0018 
0019 #include <limits>
0020 
0021 namespace Acts {
0022 
0023 /// This is the condition that the pathLimit has been reached
0024 struct PathLimitReached {
0025   /// Internal path limit for loop protection
0026   double internalLimit = std::numeric_limits<double>::max();
0027 
0028   /// boolean operator for abort condition without using the result
0029   ///
0030   /// @tparam propagator_state_t Type of the propagator state
0031   /// @tparam stepper_t Type of the stepper
0032   /// @tparam navigator_t Type of the navigator
0033   ///
0034   /// @param [in,out] state The propagation state object
0035   /// @param [in] stepper Stepper used for propagation
0036   /// @param [in] navigator Navigator used for propagation
0037   /// @param logger a logger instance
0038   /// @return True if path limit exceeded and propagation should abort
0039   template <typename propagator_state_t, typename stepper_t,
0040             typename navigator_t>
0041   bool checkAbort(propagator_state_t& state, const stepper_t& stepper,
0042                   const navigator_t& navigator, const Logger& logger) const {
0043     static_cast<void>(navigator);
0044 
0045     // Check if the maximum allowed step size has to be updated
0046     double distance =
0047         std::abs(internalLimit) - std::abs(state.stepping.pathAccumulated);
0048     double tolerance = state.options.surfaceTolerance;
0049     bool limitReached = (std::abs(distance) < std::abs(tolerance));
0050     if (limitReached) {
0051       ACTS_VERBOSE("PathLimit aborter | " << "Path limit reached at distance "
0052                                           << distance);
0053       return true;
0054     }
0055     stepper.updateStepSize(state.stepping, distance,
0056                            ConstrainedStep::Type::Actor);
0057     ACTS_VERBOSE("PathLimit aborter | "
0058                  << "Target stepSize (path limit) updated to "
0059                  << stepper.outputStepSize(state.stepping));
0060     return false;
0061   }
0062 };
0063 
0064 /// Tag used in place of a target aborter type to build a propagator state for
0065 /// a propagation without a target surface
0066 struct NoTargetAborter {};
0067 
0068 /// This is the condition that the Surface has been reached it then triggers a
0069 /// propagation abort
0070 struct SurfaceReached {
0071   /// Target surface to reach for propagation termination
0072   const Surface* surface = nullptr;
0073   /// Boundary tolerance for surface intersection checks
0074   BoundaryTolerance boundaryTolerance = BoundaryTolerance::None();
0075 
0076   // TODO https://github.com/acts-project/acts/issues/2738
0077   /// Distance limit to discard intersections "behind us"
0078   /// @note this is only necessary because some surfaces have more than one
0079   ///       intersection
0080   double nearLimit = -100 * UnitConstants::um;
0081 
0082   SurfaceReached() = default;
0083   /// Constructor with custom near limit
0084   /// @param nLimit Distance limit to discard intersections "behind us"
0085   explicit SurfaceReached(double nLimit) : nearLimit(nLimit) {}
0086 
0087   /// boolean operator for abort condition without using the result
0088   ///
0089   /// @tparam propagator_state_t Type of the propagator state
0090   /// @tparam stepper_t Type of the stepper
0091   /// @tparam navigator_t Type of the navigator
0092   ///
0093   /// @param [in,out] state The propagation state object
0094   /// @param [in] stepper Stepper used for propagation
0095   /// @param [in] navigator Navigator used for propagation
0096   /// @param logger a logger instance
0097   /// @return true if abort condition is met (surface reached)
0098   template <typename propagator_state_t, typename stepper_t,
0099             typename navigator_t>
0100   bool checkAbort(propagator_state_t& state, const stepper_t& stepper,
0101                   const navigator_t& navigator, const Logger& logger) const {
0102     if (surface == nullptr) {
0103       ACTS_VERBOSE("SurfaceReached aborter | Target surface not set.");
0104       return false;
0105     }
0106 
0107     if (navigator.currentSurface(state.navigation) == surface) {
0108       ACTS_VERBOSE("SurfaceReached aborter | Target surface reached.");
0109       return true;
0110     }
0111 
0112     // not using the stepper overstep limit here because it does not always work
0113     // for perigee surfaces
0114     // note: the near limit is necessary for surfaces with more than one
0115     // intersection in order to discard the ones which are behind us
0116     const double farLimit = std::numeric_limits<double>::max();
0117     const double tolerance = state.options.surfaceTolerance;
0118 
0119     const MultiIntersection3D multiIntersection = surface->intersect(
0120         state.geoContext, stepper.position(state.stepping),
0121         state.options.direction * stepper.direction(state.stepping),
0122         boundaryTolerance, tolerance);
0123     const Intersection3D closestIntersection = multiIntersection.closest();
0124 
0125     bool reached = false;
0126 
0127     if (closestIntersection.status() == IntersectionStatus::onSurface) {
0128       const double distance = closestIntersection.pathLength();
0129       ACTS_VERBOSE(
0130           "SurfaceReached aborter | "
0131           "Target surface reached at distance (tolerance) "
0132           << distance << " (" << tolerance << ")");
0133       reached = true;
0134     }
0135 
0136     if (const auto intersectionIt = std::ranges::find_if(
0137             multiIntersection,
0138             [&](const auto& intersection) {
0139               return intersection.isValid() &&
0140                      detail::checkPathLength(intersection.pathLength(),
0141                                              nearLimit, farLimit, logger);
0142             });
0143         intersectionIt != multiIntersection.end()) {
0144       stepper.updateSurfaceStatus(
0145           state.stepping, *surface, intersectionIt - multiIntersection.begin(),
0146           state.options.direction, boundaryTolerance,
0147           state.options.surfaceTolerance, ConstrainedStep::Type::Actor, logger);
0148       ACTS_VERBOSE(
0149           "SurfaceReached aborter | "
0150           "Target stepSize (surface) updated to "
0151           << stepper.outputStepSize(state.stepping));
0152     } else {
0153       ACTS_VERBOSE(
0154           "SurfaceReached aborter | "
0155           "Target intersection not found. Maybe next time?");
0156     }
0157 
0158     return reached;
0159   }
0160 };
0161 
0162 /// Similar to SurfaceReached, but with an infinite overstep limit.
0163 ///
0164 /// This can be used to force the propagation to the target surface.
0165 struct ForcedSurfaceReached : SurfaceReached {
0166   ForcedSurfaceReached()
0167       : SurfaceReached(std::numeric_limits<double>::lowest()) {}
0168 };
0169 
0170 /// This is the condition that the end of world has been reached
0171 /// it then triggers an propagation abort
0172 struct EndOfWorldReached {
0173   /// boolean operator for abort condition without using the result
0174   ///
0175   /// @tparam propagator_state_t Type of the propagator state
0176   /// @tparam navigator_t Type of the navigator
0177   ///
0178   /// @param [in,out] state The propagation state object
0179   /// @param [in] navigator The navigator object
0180   /// @return True if end of world reached and propagation should abort
0181   template <typename propagator_state_t, typename stepper_t,
0182             typename navigator_t>
0183   bool checkAbort(propagator_state_t& state, const stepper_t& /*stepper*/,
0184                   const navigator_t& navigator,
0185                   const Logger& /*logger*/) const {
0186     bool endOfWorld = navigator.endOfWorldReached(state.navigation);
0187     return endOfWorld;
0188   }
0189 };
0190 
0191 /// This is the condition that the end of world has been reached
0192 /// it then triggers a propagation abort
0193 struct VolumeConstraintAborter {
0194   /// boolean operator for abort condition without using the result
0195   ///
0196   /// @tparam propagator_state_t Type of the propagator state
0197   /// @tparam navigator_t Type of the navigator
0198   ///
0199   /// @param [in,out] state The propagation state object
0200   /// @param [in] navigator The navigator object
0201   /// @param logger a logger instance
0202   /// @return True if volume constraints violated and propagation should abort
0203   template <typename propagator_state_t, typename stepper_t,
0204             typename navigator_t>
0205   bool checkAbort(propagator_state_t& state, const stepper_t& /*stepper*/,
0206                   const navigator_t& navigator, const Logger& logger) const {
0207     const auto& constrainToVolumeIds = state.options.constrainToVolumeIds;
0208     const auto& endOfWorldVolumeIds = state.options.endOfWorldVolumeIds;
0209 
0210     if (constrainToVolumeIds.empty() && endOfWorldVolumeIds.empty()) {
0211       return false;
0212     }
0213     const auto* currentVolume = navigator.currentVolume(state.navigation);
0214 
0215     // We need a volume to check its ID
0216     if (currentVolume == nullptr) {
0217       return false;
0218     }
0219 
0220     const auto currentVolumeId =
0221         static_cast<std::uint32_t>(currentVolume->geometryId().volume());
0222 
0223     if (!constrainToVolumeIds.empty() &&
0224         !rangeContainsValue(constrainToVolumeIds, currentVolumeId)) {
0225       ACTS_VERBOSE(
0226           "VolumeConstraintAborter aborter | Abort with volume constrain "
0227           << currentVolumeId);
0228       return true;
0229     }
0230 
0231     if (!endOfWorldVolumeIds.empty() &&
0232         rangeContainsValue(endOfWorldVolumeIds, currentVolumeId)) {
0233       ACTS_VERBOSE(
0234           "VolumeConstraintAborter aborter | Abort with additional end of "
0235           "world volume "
0236           << currentVolumeId);
0237       return true;
0238     }
0239 
0240     return false;
0241   }
0242 };
0243 
0244 /// Aborter that checks if the propagation has reached any surface
0245 struct AnySurfaceReached {
0246   /// Check if any surface has been reached during propagation
0247   /// @tparam propagator_state_t Type of the propagator state
0248   /// @tparam stepper_t Type of the stepper
0249   /// @tparam navigator_t Type of the navigator
0250   /// @param state The propagation state object
0251   /// @param stepper Stepper used for propagation (unused)
0252   /// @param navigator Navigator used for propagation
0253   /// @param logger Logger instance (unused)
0254   /// @return true if any surface has been reached, false otherwise
0255   template <typename propagator_state_t, typename stepper_t,
0256             typename navigator_t>
0257   bool checkAbort(propagator_state_t& state, const stepper_t& stepper,
0258                   const navigator_t& navigator, const Logger& logger) const {
0259     static_cast<void>(stepper);
0260     static_cast<void>(logger);
0261 
0262     const Surface* startSurface = navigator.startSurface(state.navigation);
0263     const Surface* targetSurface = navigator.targetSurface(state.navigation);
0264     const Surface* currentSurface = navigator.currentSurface(state.navigation);
0265 
0266     // `startSurface` is excluded because we want to reach a new surface
0267     // `targetSurface` is excluded because another aborter should handle it
0268     if (currentSurface != nullptr && currentSurface != startSurface &&
0269         currentSurface != targetSurface) {
0270       return true;
0271     }
0272 
0273     return false;
0274   }
0275 };
0276 
0277 }  // namespace Acts