Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-11-04 09:21:39

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