Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-02 07:50:48

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/Intersection.hpp"
0022 #include "Acts/Utilities/Logger.hpp"
0023 #include "Acts/Utilities/Result.hpp"
0024 
0025 #include <limits>
0026 #include <memory>
0027 #include <vector>
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   /// The sequentially crossed surfaces
0042   using SurfaceSequence = std::vector<const Surface*>;
0043 
0044   /// @brief The nested configuration struct
0045   struct Config {};
0046 
0047   /// @brief The nested options struct
0048   struct Options : public NavigatorPlainOptions {
0049     explicit Options(const GeometryContext& gctx)
0050         : NavigatorPlainOptions(gctx) {}
0051 
0052     /// The Surface sequence
0053     SurfaceSequence surfaces;
0054 
0055     /// The surface tolerance
0056     double surfaceTolerance = s_onSurfaceTolerance;
0057 
0058     // TODO https://github.com/acts-project/acts/issues/2738
0059     /// Distance limit to discard intersections "behind us"
0060     /// @note this is only necessary because some surfaces have more than one
0061     ///       intersection
0062     double nearLimit = -100 * UnitConstants::um;
0063 
0064     /// The far limit to resolve surfaces
0065     double farLimit = std::numeric_limits<double>::max();
0066 
0067     void setPlainOptions(const NavigatorPlainOptions& options) {
0068       static_cast<NavigatorPlainOptions&>(*this) = options;
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     explicit State(const Options& options_) : options(options_) {}
0079 
0080     Options options;
0081 
0082     Direction direction = Direction::Forward();
0083 
0084     /// Index of the next surface to try
0085     /// @note -1 means before the first surface in the sequence and size()
0086     ///       means after the last surface in the sequence
0087     int surfaceIndex = -1;
0088 
0089     /// Navigation state - external interface: the current surface
0090     const Surface* currentSurface = nullptr;
0091 
0092     /// Navigation state - external interface: a break has been detected
0093     bool navigationBreak = false;
0094 
0095     /// Navigation statistics
0096     NavigatorStatistics statistics;
0097 
0098     const Surface& navSurface() const {
0099       return *options.surfaces.at(surfaceIndex);
0100     }
0101 
0102     void nextSurface() {
0103       if (direction == Direction::Forward()) {
0104         ++surfaceIndex;
0105       } else {
0106         --surfaceIndex;
0107       }
0108     }
0109 
0110     bool endOfSurfaces() const {
0111       if (direction == Direction::Forward()) {
0112         return surfaceIndex >= static_cast<int>(options.surfaces.size());
0113       }
0114       return surfaceIndex < 0;
0115     }
0116 
0117     int remainingSurfaces() const {
0118       if (direction == Direction::Forward()) {
0119         return options.surfaces.size() - surfaceIndex;
0120       }
0121       return surfaceIndex + 1;
0122     }
0123 
0124     void resetSurfaceIndex() {
0125       surfaceIndex = direction == Direction::Forward()
0126                          ? -1
0127                          : static_cast<int>(options.surfaces.size());
0128     }
0129   };
0130 
0131   explicit DirectNavigator(std::unique_ptr<const Logger> _logger =
0132                                getDefaultLogger("DirectNavigator",
0133                                                 Logging::INFO))
0134       : m_logger{std::move(_logger)} {}
0135 
0136   State makeState(const Options& options) const {
0137     State state(options);
0138     return state;
0139   }
0140 
0141   const Surface* currentSurface(const State& state) const {
0142     return state.currentSurface;
0143   }
0144 
0145   const TrackingVolume* currentVolume(const State& /*state*/) const {
0146     return nullptr;
0147   }
0148 
0149   const IVolumeMaterial* currentVolumeMaterial(const State& /*state*/) const {
0150     return nullptr;
0151   }
0152 
0153   const Surface* startSurface(const State& state) const {
0154     return state.options.startSurface;
0155   }
0156 
0157   const Surface* targetSurface(const State& state) const {
0158     return state.options.targetSurface;
0159   }
0160 
0161   bool endOfWorldReached(State& /*state*/) const { return false; }
0162 
0163   bool navigationBreak(const State& state) const {
0164     return state.navigationBreak;
0165   }
0166 
0167   /// @brief Initialize the navigator
0168   ///
0169   /// This function initializes the navigator for a new propagation.
0170   ///
0171   /// @param state The navigation state
0172   /// @param position The start position
0173   /// @param direction The start direction
0174   /// @param propagationDirection The propagation direction
0175   [[nodiscard]] Result<void> initialize(State& state, const Vector3& position,
0176                                         const Vector3& direction,
0177                                         Direction propagationDirection) const {
0178     (void)position;
0179     (void)direction;
0180 
0181     ACTS_VERBOSE("Initialize. Surface sequence for navigation:");
0182     for (const Surface* surface : state.options.surfaces) {
0183       ACTS_VERBOSE(surface->geometryId()
0184                    << " - "
0185                    << surface->center(state.options.geoContext).transpose());
0186     }
0187 
0188     state.direction = propagationDirection;
0189     ACTS_VERBOSE("Navigation direction is " << propagationDirection);
0190 
0191     // We set the current surface to the start surface
0192     state.currentSurface = state.options.startSurface;
0193     if (state.currentSurface != nullptr) {
0194       ACTS_VERBOSE("Current surface set to start surface "
0195                    << state.currentSurface->geometryId());
0196     } else {
0197       ACTS_VERBOSE("Current surface set to nullptr");
0198     }
0199 
0200     // Find initial index.
0201     auto found =
0202         std::ranges::find(state.options.surfaces, state.options.startSurface);
0203 
0204     if (found != state.options.surfaces.end()) {
0205       // The index should be the index before the start surface, depending on
0206       // the direction
0207       state.surfaceIndex = std::distance(state.options.surfaces.begin(), found);
0208       state.surfaceIndex += state.direction == Direction::Backward() ? 1 : -1;
0209     } else {
0210       ACTS_DEBUG(
0211           "Did not find the start surface in the sequence. Assuming it is not "
0212           "part of the sequence. Trusting the correctness of the input "
0213           "sequence. Resetting the surface index.");
0214       state.resetSurfaceIndex();
0215     }
0216 
0217     state.navigationBreak = false;
0218 
0219     return Result<void>::success();
0220   }
0221 
0222   /// @brief Get the next target surface
0223   ///
0224   /// This function gets the next target surface for the propagation. For
0225   /// the direct navigator this is always the next surface in the sequence.
0226   ///
0227   /// @param state The navigation state
0228   /// @param position The current position
0229   /// @param direction The current direction
0230   ///
0231   /// @return The next target surface
0232   NavigationTarget nextTarget(State& state, const Vector3& position,
0233                               const Vector3& direction) const {
0234     // Navigator target always resets the current surface
0235     state.currentSurface = nullptr;
0236 
0237     if (state.navigationBreak) {
0238       return NavigationTarget::None();
0239     }
0240 
0241     ACTS_VERBOSE("DirectNavigator::nextTarget");
0242 
0243     // Move the sequence to the next surface
0244     state.nextSurface();
0245 
0246     if (!state.endOfSurfaces()) {
0247       ACTS_VERBOSE("Next surface candidate is  "
0248                    << state.navSurface().geometryId() << ". "
0249                    << state.remainingSurfaces() << " out of "
0250                    << state.options.surfaces.size()
0251                    << " surfaces remain to try.");
0252     } else {
0253       ACTS_VERBOSE("End of surfaces reached, navigation break.");
0254       state.navigationBreak = true;
0255       return NavigationTarget::None();
0256     }
0257 
0258     // Establish & update the surface status
0259     // TODO we do not know the intersection index - passing the closer one
0260     const Surface& surface = state.navSurface();
0261     const double farLimit = std::numeric_limits<double>::max();
0262     const auto intersection = chooseIntersection(
0263         state.options.geoContext, surface, position, direction,
0264         BoundaryTolerance::Infinite(), state.options.nearLimit, farLimit,
0265         state.options.surfaceTolerance);
0266     return NavigationTarget(surface, intersection.index(),
0267                             BoundaryTolerance::Infinite());
0268   }
0269 
0270   /// @brief Check if the current target is still valid
0271   ///
0272   /// This function checks if the target is valid. For the direct navigator this
0273   /// is always true.
0274   ///
0275   /// @param state The navigation state
0276   /// @param position The current position
0277   /// @param direction The current direction
0278   ///
0279   /// @return True if the target is valid
0280   bool checkTargetValid(const State& state, const Vector3& position,
0281                         const Vector3& direction) const {
0282     (void)state;
0283     (void)position;
0284     (void)direction;
0285 
0286     return true;
0287   }
0288 
0289   /// @brief Handle the surface reached
0290   ///
0291   /// This function handles the surface reached. For the direct navigator this
0292   /// effectively sets the current surface to the reached surface.
0293   ///
0294   /// @param state The navigation state
0295   /// @param position The current position
0296   /// @param direction The current direction
0297   /// @param surface The surface reached
0298   void handleSurfaceReached(State& state, const Vector3& position,
0299                             const Vector3& direction,
0300                             const Surface& surface) const {
0301     (void)position;
0302     (void)direction;
0303     (void)surface;
0304 
0305     if (state.navigationBreak) {
0306       return;
0307     }
0308 
0309     ACTS_VERBOSE("DirectNavigator::handleSurfaceReached");
0310 
0311     // Set the current surface
0312     state.currentSurface = &state.navSurface();
0313     ACTS_VERBOSE("Current surface set to  "
0314                  << state.currentSurface->geometryId());
0315   }
0316 
0317  private:
0318   ObjectIntersection<Surface> chooseIntersection(
0319       const GeometryContext& gctx, const Surface& surface,
0320       const Vector3& position, const Vector3& direction,
0321       const BoundaryTolerance& boundaryTolerance, double nearLimit,
0322       double farLimit, double tolerance) const {
0323     auto intersections = surface.intersect(gctx, position, direction,
0324                                            boundaryTolerance, tolerance);
0325 
0326     for (auto& intersection : intersections.split()) {
0327       if (detail::checkPathLength(intersection.pathLength(), nearLimit,
0328                                   farLimit, logger())) {
0329         return intersection;
0330       }
0331     }
0332 
0333     return ObjectIntersection<Surface>::invalid();
0334   }
0335 
0336   const Logger& logger() const { return *m_logger; }
0337 
0338   std::unique_ptr<const Logger> m_logger;
0339 };
0340 
0341 }  // namespace Acts