Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-02 08:04:18

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