Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-01 09:08:30

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       // TODO https://github.com/acts-project/acts/issues/2738
0052       // The direct navigator uses a relaxed near limit to discard
0053       // intersections "behind us". This is only necessary because some
0054       // surfaces have more than one intersection.
0055       nearLimit = -100 * UnitConstants::um;
0056     }
0057 
0058     /// The ordered sequence of surfaces to walk through
0059     std::vector<const Surface*> surfaceSequence;
0060 
0061     /// Set the plain navigator options
0062     /// @param options The plain navigator options to copy
0063     void setPlainOptions(const NavigatorPlainOptions& options) {
0064       // Preserve the direct-navigator-specific near limit, which differs from
0065       // the plain default.
0066       const double keepNearLimit = nearLimit;
0067       static_cast<NavigatorPlainOptions&>(*this) = options;
0068       nearLimit = keepNearLimit;
0069     }
0070   };
0071 
0072   /// @brief Nested State struct
0073   ///
0074   /// It acts as an internal state which is created for every
0075   /// propagation/extrapolation step and keep thread-local navigation
0076   /// information
0077   struct State {
0078     /// Constructor from options
0079     /// @param options_ The navigator options
0080     explicit State(const Options& options_) : options(options_) {}
0081 
0082     /// Configuration options for the direct navigator
0083     Options options;
0084 
0085     /// Propagation direction (forward or backward)
0086     Direction direction = Direction::Forward();
0087 
0088     /// Surface where the navigation started
0089     const Surface* startSurface = nullptr;
0090 
0091     /// Surface that is the target of the navigation
0092     const Surface* targetSurface = nullptr;
0093 
0094     /// Index of the next surface to try
0095     /// @note -1 means before the first surface in the sequence and size()
0096     ///       means after the last surface in the sequence
0097     std::int32_t surfaceIndex = -1;
0098 
0099     /// Navigation state - external interface: the current surface
0100     const Surface* currentSurface = nullptr;
0101 
0102     /// Navigation state - external interface: a break has been detected
0103     bool navigationBreak = false;
0104 
0105     /// Navigation statistics
0106     NavigatorStatistics statistics;
0107 
0108     /// Get the current navigation surface
0109     /// @return Reference to the surface at the current surface index
0110     const Surface& navSurface() const {
0111       return *options.surfaceSequence.at(surfaceIndex);
0112     }
0113 
0114     /// Move to the next surface in the sequence
0115     /// Increments or decrements surface index based on propagation direction
0116     void nextSurface() {
0117       if (direction == Direction::Forward()) {
0118         ++surfaceIndex;
0119       } else {
0120         --surfaceIndex;
0121       }
0122     }
0123 
0124     /// Check if we have reached the end of the surface sequence
0125     /// @return True if no more surfaces remain in the propagation direction
0126     bool endOfSurfaces() const {
0127       if (direction == Direction::Forward()) {
0128         return surfaceIndex >= static_cast<int>(options.surfaceSequence.size());
0129       }
0130       return surfaceIndex < 0;
0131     }
0132 
0133     /// Get the number of surfaces remaining in the sequence
0134     /// @return Number of surfaces left to process in the propagation direction
0135     int remainingSurfaces() const {
0136       if (direction == Direction::Forward()) {
0137         return static_cast<int>(options.surfaceSequence.size()) - surfaceIndex;
0138       }
0139       return surfaceIndex + 1;
0140     }
0141 
0142     /// Reset the surface index to the initial position
0143     /// Sets index to before first surface (forward) or after last surface
0144     /// (backward)
0145     void resetSurfaceIndex() {
0146       surfaceIndex = direction == Direction::Forward()
0147                          ? -1
0148                          : static_cast<int>(options.surfaceSequence.size());
0149     }
0150   };
0151 
0152   /// Constructor with optional logger
0153   /// @param _logger Logger instance for navigation messages
0154   explicit DirectNavigator(std::unique_ptr<const Logger> _logger =
0155                                getDefaultLogger("DirectNavigator",
0156                                                 Logging::INFO))
0157       : m_logger{std::move(_logger)} {}
0158 
0159   /// Create a new navigation state from options
0160   /// @param options The navigator options
0161   /// @return New state initialized with the provided options
0162   State makeState(const Options& options) const {
0163     State state(options);
0164     return state;
0165   }
0166 
0167   /// Get the current surface from the navigation state
0168   /// @param state The navigation state
0169   /// @return Pointer to current surface, nullptr if none
0170   const Surface* currentSurface(const State& state) const {
0171     return state.currentSurface;
0172   }
0173 
0174   /// Get the current tracking volume (not used by DirectNavigator)
0175   /// @param state The navigation state (unused)
0176   /// @return Always returns nullptr as DirectNavigator doesn't use volumes
0177   const TrackingVolume* currentVolume(const State& state) const {
0178     static_cast<void>(state);
0179     return nullptr;
0180   }
0181 
0182   /// Get the current volume material (not used by DirectNavigator)
0183   /// @param state The navigation state (unused)
0184   /// @return Always returns nullptr as DirectNavigator doesn't use volume material
0185   const IVolumeMaterial* currentVolumeMaterial(const State& state) const {
0186     static_cast<void>(state);
0187     return nullptr;
0188   }
0189 
0190   /// Get the start surface from the navigation state
0191   /// @param state The navigation state
0192   /// @return Pointer to start surface, nullptr if none
0193   const Surface* startSurface(const State& state) const {
0194     return state.startSurface;
0195   }
0196 
0197   /// Get the target surface from the navigation state
0198   /// @param state The navigation state
0199   /// @return Pointer to target surface, nullptr if none
0200   const Surface* targetSurface(const State& state) const {
0201     return state.targetSurface;
0202   }
0203 
0204   /// Check if the end of world has been reached (not applicable for
0205   /// DirectNavigator)
0206   /// @param state The navigation state (unused)
0207   /// @return Always returns false as DirectNavigator operates on a surface sequence
0208   bool endOfWorldReached(State& state) const {
0209     static_cast<void>(state);
0210     return false;
0211   }
0212 
0213   /// Check if navigation should break/stop
0214   /// @param state The navigation state
0215   /// @return True if navigation should break, false otherwise
0216   bool navigationBreak(const State& state) const {
0217     return state.navigationBreak;
0218   }
0219 
0220   /// @brief Initialize the navigator
0221   ///
0222   /// This function initializes the navigator for a new propagation.
0223   ///
0224   /// @param state The navigation state
0225   /// @param args The initialization arguments of this navigation run
0226   /// @return Always returns success result as DirectNavigator initialization cannot fail
0227   [[nodiscard]] Result<void> initialize(
0228       State& state, const NavigatorInitializeArguments& args) const {
0229     ACTS_VERBOSE("Initialize. Surface sequence for navigation:");
0230     for (const Surface* surface : state.options.surfaceSequence) {
0231       ACTS_VERBOSE(surface->geometryId()
0232                    << " - "
0233                    << surface->center(state.options.geoContext).transpose());
0234     }
0235 
0236     state.direction = args.propagationDirection;
0237     ACTS_VERBOSE("Navigation direction is " << args.propagationDirection);
0238 
0239     state.startSurface = args.startSurface;
0240     state.targetSurface = args.targetSurface;
0241 
0242     // We set the current surface to the start surface
0243     state.currentSurface = state.startSurface;
0244     if (state.currentSurface != nullptr) {
0245       ACTS_VERBOSE("Current surface set to start surface "
0246                    << state.currentSurface->geometryId());
0247     } else {
0248       ACTS_VERBOSE("Current surface set to nullptr");
0249     }
0250 
0251     // Find initial index.
0252     auto found =
0253         std::ranges::find(state.options.surfaceSequence, state.startSurface);
0254 
0255     if (found != state.options.surfaceSequence.end()) {
0256       // The index should be the index before the start surface, depending on
0257       // the direction
0258       state.surfaceIndex =
0259           std::distance(state.options.surfaceSequence.begin(), found);
0260       state.surfaceIndex += state.direction == Direction::Backward() ? 1 : -1;
0261     } else {
0262       ACTS_DEBUG(
0263           "Did not find the start surface in the sequence. Assuming it is not "
0264           "part of the sequence. Trusting the correctness of the input "
0265           "sequence. Resetting the surface index.");
0266       state.resetSurfaceIndex();
0267     }
0268 
0269     state.navigationBreak = false;
0270 
0271     return Result<void>::success();
0272   }
0273 
0274   /// @brief Get the next target surface
0275   ///
0276   /// This function gets the next target surface for the propagation. For
0277   /// the direct navigator this is always the next surface in the sequence.
0278   ///
0279   /// @param state The navigation state
0280   /// @param position The current position
0281   /// @param direction The current direction
0282   /// @param curvature Current global geometric curvature (inverse length)
0283   ///
0284   /// @return The next target surface
0285   NavigationTarget nextTarget(
0286       State& state, const Vector3& position, const Vector3& direction,
0287       [[maybe_unused]] const Vector3& curvature = Vector3::Zero()) 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   /// @param curvature Current global geometric curvature (inverse length)
0338   ///
0339   /// @return True if the target is valid
0340   bool checkTargetValid(
0341       const State& state, const Vector3& position, const Vector3& direction,
0342       [[maybe_unused]] const Vector3& curvature = Vector3::Zero()) const {
0343     static_cast<void>(state);
0344     static_cast<void>(position);
0345     static_cast<void>(direction);
0346 
0347     return true;
0348   }
0349 
0350   /// @brief Handle the surface reached
0351   ///
0352   /// This function handles the surface reached. For the direct navigator this
0353   /// effectively sets the current surface to the reached surface.
0354   ///
0355   /// @param state The navigation state
0356   /// @param position The current position
0357   /// @param direction The current direction
0358   /// @param curvature Current global geometric curvature (inverse length)
0359   /// @param surface The surface reached
0360   void handleSurfaceReached(
0361       State& state, const Vector3& position, const Vector3& direction,
0362       const Surface& surface,
0363       [[maybe_unused]] const Vector3& curvature = Vector3::Zero()) const {
0364     static_cast<void>(position);
0365     static_cast<void>(direction);
0366     static_cast<void>(surface);
0367 
0368     if (state.navigationBreak) {
0369       return;
0370     }
0371 
0372     ACTS_VERBOSE("DirectNavigator::handleSurfaceReached");
0373 
0374     // Set the current surface
0375     state.currentSurface = &state.navSurface();
0376     ACTS_VERBOSE("Current surface set to "
0377                  << state.currentSurface->geometryId());
0378   }
0379 
0380  private:
0381   NavigationTarget chooseIntersection(
0382       const GeometryContext& gctx, const Surface& surface,
0383       const Vector3& position, const Vector3& direction,
0384       const BoundaryTolerance& boundaryTolerance, double nearLimit,
0385       double farLimit, double tolerance) const {
0386     auto intersections = surface.intersect(gctx, position, direction,
0387                                            boundaryTolerance, tolerance);
0388 
0389     for (auto [intersectionIndex, intersection] :
0390          Acts::enumerate(intersections)) {
0391       if (intersection.isValid() &&
0392           detail::checkPathLength(intersection.pathLength(), nearLimit,
0393                                   farLimit, logger())) {
0394         return NavigationTarget(intersection, intersectionIndex, surface,
0395                                 boundaryTolerance);
0396       }
0397     }
0398 
0399     return NavigationTarget::None();
0400   }
0401 
0402   const Logger& logger() const { return *m_logger; }
0403 
0404   std::unique_ptr<const Logger> m_logger;
0405 };
0406 
0407 }  // namespace Acts