Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-05 07:45:05

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/Direction.hpp"
0012 #include "Acts/Definitions/Units.hpp"
0013 #include "Acts/Geometry/Layer.hpp"
0014 #include "Acts/Geometry/TrackingGeometry.hpp"
0015 #include "Acts/Geometry/TrackingVolume.hpp"
0016 #include "Acts/Propagator/NavigationTarget.hpp"
0017 #include "Acts/Propagator/NavigatorOptions.hpp"
0018 #include "Acts/Propagator/NavigatorStatistics.hpp"
0019 #include "Acts/Surfaces/BoundaryTolerance.hpp"
0020 #include "Acts/Surfaces/Surface.hpp"
0021 #include "Acts/Utilities/Enumerate.hpp"
0022 #include "Acts/Utilities/Intersection.hpp"
0023 #include "Acts/Utilities/Logger.hpp"
0024 #include "Acts/Utilities/Result.hpp"
0025 
0026 #include <limits>
0027 #include <memory>
0028 
0029 namespace Acts {
0030 
0031 /// @brief A fully guided navigator
0032 ///
0033 /// This is a fully guided navigator that progresses through a provided sequence
0034 /// of surfaces.
0035 ///
0036 /// This can either be used as a validation tool, for truth tracking, or track
0037 /// refitting.
0038 ///
0039 class DirectNavigator {
0040  public:
0041   /// @brief The nested configuration struct
0042   struct Config {};
0043 
0044   /// @brief The nested options struct
0045   struct Options : public NavigatorPlainOptions {
0046     /// Constructor from geometry context
0047     /// @param gctx The geometry context
0048     explicit Options(const GeometryContext& gctx)
0049         : NavigatorPlainOptions(gctx) {}
0050 
0051     /// The surface tolerance
0052     double surfaceTolerance = s_onSurfaceTolerance;
0053 
0054     // TODO https://github.com/acts-project/acts/issues/2738
0055     /// Distance limit to discard intersections "behind us"
0056     /// @note this is only necessary because some surfaces have more than one
0057     ///       intersection
0058     double nearLimit = -100 * UnitConstants::um;
0059 
0060     /// The far limit to resolve surfaces
0061     double farLimit = std::numeric_limits<double>::max();
0062 
0063     /// Set the plain navigator options
0064     /// @param options The plain navigator options to copy
0065     void setPlainOptions(const NavigatorPlainOptions& options) {
0066       static_cast<NavigatorPlainOptions&>(*this) = options;
0067     }
0068   };
0069 
0070   /// @brief Nested State struct
0071   ///
0072   /// It acts as an internal state which is created for every
0073   /// propagation/extrapolation step and keep thread-local navigation
0074   /// information
0075   struct State {
0076     /// Constructor from options
0077     /// @param options_ The navigator options
0078     explicit State(const Options& options_) : options(options_) {}
0079 
0080     /// Configuration options for the direct navigator
0081     Options options;
0082 
0083     /// Propagation direction (forward or backward)
0084     Direction direction = Direction::Forward();
0085 
0086     /// Index of the next surface to try
0087     /// @note -1 means before the first surface in the sequence and size()
0088     ///       means after the last surface in the sequence
0089     std::int32_t surfaceIndex = -1;
0090 
0091     /// Navigation state - external interface: the current surface
0092     const Surface* currentSurface = nullptr;
0093 
0094     /// Navigation state - external interface: a break has been detected
0095     bool navigationBreak = false;
0096 
0097     /// Navigation statistics
0098     NavigatorStatistics statistics;
0099 
0100     /// Get the current navigation surface
0101     /// @return Reference to the surface at the current surface index
0102     const Surface& navSurface() const {
0103       return *options.externalSurfaces.at(surfaceIndex);
0104     }
0105 
0106     /// Move to the next surface in the sequence
0107     /// Increments or decrements surface index based on propagation direction
0108     void nextSurface() {
0109       if (direction == Direction::Forward()) {
0110         ++surfaceIndex;
0111       } else {
0112         --surfaceIndex;
0113       }
0114     }
0115 
0116     /// Check if we have reached the end of the surface sequence
0117     /// @return True if no more surfaces remain in the propagation direction
0118     bool endOfSurfaces() const {
0119       if (direction == Direction::Forward()) {
0120         return surfaceIndex >=
0121                static_cast<int>(options.externalSurfaces.size());
0122       }
0123       return surfaceIndex < 0;
0124     }
0125 
0126     /// Get the number of surfaces remaining in the sequence
0127     /// @return Number of surfaces left to process in the propagation direction
0128     int remainingSurfaces() const {
0129       if (direction == Direction::Forward()) {
0130         return options.externalSurfaces.size() - surfaceIndex;
0131       }
0132       return surfaceIndex + 1;
0133     }
0134 
0135     /// Reset the surface index to the initial position
0136     /// Sets index to before first surface (forward) or after last surface
0137     /// (backward)
0138     void resetSurfaceIndex() {
0139       surfaceIndex = direction == Direction::Forward()
0140                          ? -1
0141                          : static_cast<int>(options.externalSurfaces.size());
0142     }
0143   };
0144 
0145   /// Constructor with optional logger
0146   /// @param _logger Logger instance for navigation messages
0147   explicit DirectNavigator(std::unique_ptr<const Logger> _logger =
0148                                getDefaultLogger("DirectNavigator",
0149                                                 Logging::INFO))
0150       : m_logger{std::move(_logger)} {}
0151 
0152   /// Create a new navigation state from options
0153   /// @param options The navigator options
0154   /// @return New state initialized with the provided options
0155   State makeState(const Options& options) const {
0156     State state(options);
0157     return state;
0158   }
0159 
0160   /// Get the current surface from the navigation state
0161   /// @param state The navigation state
0162   /// @return Pointer to current surface, nullptr if none
0163   const Surface* currentSurface(const State& state) const {
0164     return state.currentSurface;
0165   }
0166 
0167   /// Get the current tracking volume (not used by DirectNavigator)
0168   /// @param state The navigation state (unused)
0169   /// @return Always returns nullptr as DirectNavigator doesn't use volumes
0170   const TrackingVolume* currentVolume(const State& state) const {
0171     static_cast<void>(state);
0172     return nullptr;
0173   }
0174 
0175   /// Get the current volume material (not used by DirectNavigator)
0176   /// @param state The navigation state (unused)
0177   /// @return Always returns nullptr as DirectNavigator doesn't use volume material
0178   const IVolumeMaterial* currentVolumeMaterial(const State& state) const {
0179     static_cast<void>(state);
0180     return nullptr;
0181   }
0182 
0183   /// Get the start surface from the navigation state
0184   /// @param state The navigation state
0185   /// @return Pointer to start surface, nullptr if none
0186   const Surface* startSurface(const State& state) const {
0187     return state.options.startSurface;
0188   }
0189 
0190   /// Get the target surface from the navigation state
0191   /// @param state The navigation state
0192   /// @return Pointer to target surface, nullptr if none
0193   const Surface* targetSurface(const State& state) const {
0194     return state.options.targetSurface;
0195   }
0196 
0197   /// Check if the end of world has been reached (not applicable for
0198   /// DirectNavigator)
0199   /// @param state The navigation state (unused)
0200   /// @return Always returns false as DirectNavigator operates on a surface sequence
0201   bool endOfWorldReached(State& state) const {
0202     static_cast<void>(state);
0203     return false;
0204   }
0205 
0206   /// Check if navigation should break/stop
0207   /// @param state The navigation state
0208   /// @return True if navigation should break, false otherwise
0209   bool navigationBreak(const State& state) const {
0210     return state.navigationBreak;
0211   }
0212 
0213   /// @brief Initialize the navigator
0214   ///
0215   /// This function initializes the navigator for a new propagation.
0216   ///
0217   /// @param state The navigation state
0218   /// @param position The start position
0219   /// @param direction The start direction
0220   /// @param propagationDirection The propagation direction
0221   /// @return Always returns success result as DirectNavigator initialization cannot fail
0222   [[nodiscard]] Result<void> initialize(State& state, const Vector3& position,
0223                                         const Vector3& direction,
0224                                         Direction propagationDirection) const {
0225     static_cast<void>(position);
0226     static_cast<void>(direction);
0227 
0228     ACTS_VERBOSE("Initialize. Surface sequence for navigation:");
0229     for (const Surface* surface : state.options.externalSurfaces) {
0230       ACTS_VERBOSE(surface->geometryId()
0231                    << " - "
0232                    << surface->center(state.options.geoContext).transpose());
0233     }
0234 
0235     state.direction = propagationDirection;
0236     ACTS_VERBOSE("Navigation direction is " << propagationDirection);
0237 
0238     // We set the current surface to the start surface
0239     state.currentSurface = state.options.startSurface;
0240     if (state.currentSurface != nullptr) {
0241       ACTS_VERBOSE("Current surface set to start surface "
0242                    << state.currentSurface->geometryId());
0243     } else {
0244       ACTS_VERBOSE("Current surface set to nullptr");
0245     }
0246 
0247     // Find initial index.
0248     auto found = std::ranges::find(state.options.externalSurfaces,
0249                                    state.options.startSurface);
0250 
0251     if (found != state.options.externalSurfaces.end()) {
0252       // The index should be the index before the start surface, depending on
0253       // the direction
0254       state.surfaceIndex =
0255           std::distance(state.options.externalSurfaces.begin(), found);
0256       state.surfaceIndex += state.direction == Direction::Backward() ? 1 : -1;
0257     } else {
0258       ACTS_DEBUG(
0259           "Did not find the start surface in the sequence. Assuming it is not "
0260           "part of the sequence. Trusting the correctness of the input "
0261           "sequence. Resetting the surface index.");
0262       state.resetSurfaceIndex();
0263     }
0264 
0265     state.navigationBreak = false;
0266 
0267     return Result<void>::success();
0268   }
0269 
0270   /// @brief Get the next target surface
0271   ///
0272   /// This function gets the next target surface for the propagation. For
0273   /// the direct navigator this is always the next surface in the sequence.
0274   ///
0275   /// @param state The navigation state
0276   /// @param position The current position
0277   /// @param direction The current direction
0278   ///
0279   /// @return The next target surface
0280   NavigationTarget nextTarget(State& state, const Vector3& position,
0281                               const Vector3& direction) const {
0282     // Navigator target always resets the current surface
0283     state.currentSurface = nullptr;
0284 
0285     if (state.navigationBreak) {
0286       return NavigationTarget::None();
0287     }
0288 
0289     ACTS_VERBOSE("DirectNavigator::nextTarget");
0290 
0291     // Move the sequence to the next surface
0292     state.nextSurface();
0293 
0294     while (!state.endOfSurfaces()) {
0295       ACTS_VERBOSE("Next surface candidate is "
0296                    << state.navSurface().geometryId() << ". "
0297                    << state.remainingSurfaces() << " out of "
0298                    << state.options.externalSurfaces.size()
0299                    << " surfaces remain to try.");
0300 
0301       // Establish & update the surface status
0302       // TODO we do not know the intersection index - passing the closer one
0303       const Surface& surface = state.navSurface();
0304       const double farLimit = std::numeric_limits<double>::max();
0305       const NavigationTarget target = chooseIntersection(
0306           state.options.geoContext, surface, position, direction,
0307           BoundaryTolerance::Infinite(), state.options.nearLimit, farLimit,
0308           state.options.surfaceTolerance);
0309       if (target.isValid()) {
0310         return target;
0311       }
0312 
0313       ACTS_VERBOSE("No valid intersection found with surface "
0314                    << surface.geometryId() << ", trying next surface.");
0315       state.nextSurface();
0316     }
0317 
0318     ACTS_VERBOSE("End of surfaces reached, navigation break.");
0319     state.navigationBreak = true;
0320     return NavigationTarget::None();
0321   }
0322 
0323   /// @brief Check if the current target is still valid
0324   ///
0325   /// This function checks if the target is valid. For the direct navigator this
0326   /// is always true.
0327   ///
0328   /// @param state The navigation state
0329   /// @param position The current position
0330   /// @param direction The current direction
0331   ///
0332   /// @return True if the target is valid
0333   bool checkTargetValid(const State& state, const Vector3& position,
0334                         const Vector3& direction) const {
0335     static_cast<void>(state);
0336     static_cast<void>(position);
0337     static_cast<void>(direction);
0338 
0339     return true;
0340   }
0341 
0342   /// @brief Handle the surface reached
0343   ///
0344   /// This function handles the surface reached. For the direct navigator this
0345   /// effectively sets the current surface to the reached surface.
0346   ///
0347   /// @param state The navigation state
0348   /// @param position The current position
0349   /// @param direction The current direction
0350   /// @param surface The surface reached
0351   void handleSurfaceReached(State& state, const Vector3& position,
0352                             const Vector3& direction,
0353                             const Surface& surface) const {
0354     static_cast<void>(position);
0355     static_cast<void>(direction);
0356     static_cast<void>(surface);
0357 
0358     if (state.navigationBreak) {
0359       return;
0360     }
0361 
0362     ACTS_VERBOSE("DirectNavigator::handleSurfaceReached");
0363 
0364     // Set the current surface
0365     state.currentSurface = &state.navSurface();
0366     ACTS_VERBOSE("Current surface set to "
0367                  << state.currentSurface->geometryId());
0368   }
0369 
0370  private:
0371   NavigationTarget chooseIntersection(
0372       const GeometryContext& gctx, const Surface& surface,
0373       const Vector3& position, const Vector3& direction,
0374       const BoundaryTolerance& boundaryTolerance, double nearLimit,
0375       double farLimit, double tolerance) const {
0376     auto intersections = surface.intersect(gctx, position, direction,
0377                                            boundaryTolerance, tolerance);
0378 
0379     for (auto [intersectionIndex, intersection] :
0380          Acts::enumerate(intersections)) {
0381       if (intersection.isValid() &&
0382           detail::checkPathLength(intersection.pathLength(), nearLimit,
0383                                   farLimit, logger())) {
0384         return NavigationTarget(intersection, intersectionIndex, surface,
0385                                 boundaryTolerance);
0386       }
0387     }
0388 
0389     return NavigationTarget::None();
0390   }
0391 
0392   const Logger& logger() const { return *m_logger; }
0393 
0394   std::unique_ptr<const Logger> m_logger;
0395 };
0396 
0397 }  // namespace Acts