Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:10:06

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2019-2023 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 http://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 #include "Acts/Geometry/BoundarySurfaceT.hpp"
0012 #include "Acts/Geometry/Layer.hpp"
0013 #include "Acts/Geometry/TrackingGeometry.hpp"
0014 #include "Acts/Geometry/TrackingVolume.hpp"
0015 #include "Acts/Propagator/Propagator.hpp"
0016 #include "Acts/Surfaces/Surface.hpp"
0017 #include "Acts/Utilities/Intersection.hpp"
0018 
0019 #include <algorithm>
0020 #include <iterator>
0021 #include <limits>
0022 #include <memory>
0023 #include <vector>
0024 
0025 namespace Acts {
0026 
0027 /// This is a fully guided navigator that progresses through a pre-given
0028 /// sequence of surfaces.
0029 ///
0030 /// This can either be used as a validation tool, for truth tracking, or track
0031 /// refitting.
0032 class DirectNavigator {
0033  public:
0034   /// The sequentially crossed surfaces
0035   using SurfaceSequence = std::vector<const Surface*>;
0036   using SurfaceIter = std::vector<const Surface*>::iterator;
0037 
0038   DirectNavigator(std::unique_ptr<const Logger> _logger =
0039                       getDefaultLogger("DirectNavigator", Logging::INFO))
0040       : m_logger{std::move(_logger)} {}
0041 
0042   /// @brief Nested Actor struct, called Initializer
0043   ///
0044   /// This is needed for the initialization of the surface sequence.
0045   struct Initializer {
0046     /// The Surface sequence
0047     SurfaceSequence navSurfaces = {};
0048 
0049     /// Actor result / state
0050     struct this_result {
0051       bool initialized = false;
0052     };
0053 
0054     using result_type = this_result;
0055 
0056     /// Defaulting the constructor
0057     Initializer() = default;
0058 
0059     /// Actor operator call
0060     /// @tparam statet Type of the full propagator state
0061     /// @tparam stepper_t Type of the stepper
0062     /// @tparam navigator_t Type of the navigator
0063     ///
0064     /// @param state the entire propagator state
0065     /// @param r the result of this Actor
0066     template <typename propagator_state_t, typename stepper_t,
0067               typename navigator_t>
0068     void operator()(propagator_state_t& state, const stepper_t& /*stepper*/,
0069                     const navigator_t& /*navigator*/, result_type& r,
0070                     const Logger& /*logger*/) const {
0071       // Only act once
0072       if (!r.initialized) {
0073         // Initialize the surface sequence
0074         state.navigation.navSurfaces = navSurfaces;
0075         state.navigation.navSurfaceIter = state.navigation.navSurfaces.begin();
0076 
0077         // In case the start surface is in the list of nav surfaces
0078         // we need to correct the iterator to point to the next surface
0079         // in the vector
0080         if (state.navigation.startSurface) {
0081           auto surfaceIter = std::find(state.navigation.navSurfaces.begin(),
0082                                        state.navigation.navSurfaces.end(),
0083                                        state.navigation.startSurface);
0084           // if current surface in the list, point to the next surface
0085           if (surfaceIter != state.navigation.navSurfaces.end()) {
0086             state.navigation.navSurfaceIter = ++surfaceIter;
0087           }
0088         }
0089 
0090         r.initialized = true;
0091       }
0092     }
0093   };
0094 
0095   /// @brief Nested State struct
0096   ///
0097   /// It acts as an internal state which is created for every
0098   /// propagation/extrapolation step and keep thread-local navigation
0099   /// information
0100   struct State {
0101     /// Externally provided surfaces - expected to be ordered along the path
0102     SurfaceSequence navSurfaces = {};
0103 
0104     /// Iterator the next surface
0105     SurfaceIter navSurfaceIter = navSurfaces.begin();
0106 
0107     /// Navigation state - external interface: the start surface
0108     const Surface* startSurface = nullptr;
0109     /// Navigation state - external interface: the current surface
0110     const Surface* currentSurface = nullptr;
0111     /// Navigation state - external interface: the target surface
0112     const Surface* targetSurface = nullptr;
0113     /// Navigation state - starting layer
0114     const Layer* startLayer = nullptr;
0115     /// Navigation state - target layer
0116     const Layer* targetLayer = nullptr;
0117     /// Navigation state: the start volume
0118     const TrackingVolume* startVolume = nullptr;
0119     /// Navigation state: the current volume
0120     const TrackingVolume* currentVolume = nullptr;
0121     /// Navigation state: the target volume
0122     const TrackingVolume* targetVolume = nullptr;
0123 
0124     /// Navigation state - external interface: target is reached
0125     bool targetReached = false;
0126     /// Navigation state - external interface: a break has been detected
0127     bool navigationBreak = false;
0128   };
0129 
0130   State makeState(const Surface* startSurface,
0131                   const Surface* targetSurface) const {
0132     State result;
0133     result.startSurface = startSurface;
0134     result.targetSurface = targetSurface;
0135     return result;
0136   }
0137 
0138   const Surface* currentSurface(const State& state) const {
0139     return state.currentSurface;
0140   }
0141 
0142   const TrackingVolume* currentVolume(const State& state) const {
0143     return state.currentVolume;
0144   }
0145 
0146   const IVolumeMaterial* currentVolumeMaterial(const State& state) const {
0147     if (state.currentVolume == nullptr) {
0148       return nullptr;
0149     }
0150     return state.currentVolume->volumeMaterial();
0151   }
0152 
0153   const Surface* startSurface(const State& state) const {
0154     return state.startSurface;
0155   }
0156 
0157   const Surface* targetSurface(const State& state) const {
0158     return state.targetSurface;
0159   }
0160 
0161   bool targetReached(const State& state) const { return state.targetReached; }
0162 
0163   bool endOfWorldReached(State& state) const {
0164     return state.currentVolume == nullptr;
0165   }
0166 
0167   bool navigationBreak(const State& state) const {
0168     return state.navigationBreak;
0169   }
0170 
0171   void currentSurface(State& state, const Surface* surface) const {
0172     state.currentSurface = surface;
0173   }
0174 
0175   void targetReached(State& state, bool targetReached) const {
0176     state.targetReached = targetReached;
0177   }
0178 
0179   void navigationBreak(State& state, bool navigationBreak) const {
0180     state.navigationBreak = navigationBreak;
0181   }
0182 
0183   /// @brief Initialize call - start of propagation
0184   ///
0185   /// @tparam propagator_state_t The state type of the propagator
0186   /// @tparam stepper_t The type of stepper used for the propagation
0187   ///
0188   /// @param [in,out] state is the propagation state object
0189   template <typename propagator_state_t, typename stepper_t>
0190   void initialize(propagator_state_t& state,
0191                   const stepper_t& /*stepper*/) const {
0192     ACTS_VERBOSE(volInfo(state) << "initialize");
0193 
0194     // We set the current surface to the start surface
0195     state.navigation.currentSurface = state.navigation.startSurface;
0196     if (state.navigation.currentSurface) {
0197       ACTS_VERBOSE(volInfo(state)
0198                    << "Current surface set to start surface "
0199                    << state.navigation.currentSurface->geometryId());
0200     }
0201   }
0202 
0203   /// @brief Navigator pre step call
0204   ///
0205   /// @tparam propagator_state_t is the type of Propagatgor state
0206   /// @tparam stepper_t is the used type of the Stepper by the Propagator
0207   ///
0208   /// @param [in,out] state is the mutable propagator state object
0209   /// @param [in] stepper Stepper in use
0210   template <typename propagator_state_t, typename stepper_t>
0211   void preStep(propagator_state_t& state, const stepper_t& stepper) const {
0212     ACTS_VERBOSE(volInfo(state) << "pre step");
0213 
0214     // Navigator target always resets the current surface
0215     state.navigation.currentSurface = nullptr;
0216     // Output the position in the sequence
0217     ACTS_VERBOSE(std::distance(state.navigation.navSurfaceIter,
0218                                state.navigation.navSurfaces.end())
0219                  << " out of " << state.navigation.navSurfaces.size()
0220                  << " surfaces remain to try.");
0221 
0222     if (state.navigation.navSurfaceIter != state.navigation.navSurfaces.end()) {
0223       // Establish & update the surface status
0224       // TODO we do not know the intersection index - passing the closer one
0225       const auto& surface = **state.navigation.navSurfaceIter;
0226       const double farLimit = std::numeric_limits<double>::max();
0227       const auto index =
0228           chooseIntersection(
0229               state.geoContext, surface, stepper.position(state.stepping),
0230               state.options.direction * stepper.direction(state.stepping),
0231               BoundaryCheck(false), m_nearLimit, farLimit,
0232               state.options.surfaceTolerance)
0233               .index();
0234       auto surfaceStatus = stepper.updateSurfaceStatus(
0235           state.stepping, surface, index, state.options.direction,
0236           BoundaryCheck(false), state.options.surfaceTolerance, *m_logger);
0237       if (surfaceStatus == Intersection3D::Status::unreachable) {
0238         ACTS_VERBOSE(
0239             "Surface not reachable anymore, switching to next one in "
0240             "sequence");
0241         // Move the sequence to the next surface
0242         ++state.navigation.navSurfaceIter;
0243       } else {
0244         ACTS_VERBOSE("Navigation stepSize set to "
0245                      << stepper.outputStepSize(state.stepping));
0246       }
0247     } else {
0248       // Set the navigation break
0249       state.navigation.navigationBreak = true;
0250       // If no externally provided target is given, the target is reached
0251       if (state.navigation.targetSurface == nullptr) {
0252         state.navigation.targetReached = true;
0253         // Announce it then
0254         ACTS_VERBOSE("No target Surface, job done.");
0255       }
0256     }
0257   }
0258 
0259   /// @brief Navigator post step call
0260   ///
0261   /// @tparam propagator_state_t is the type of Propagatgor state
0262   /// @tparam stepper_t is the used type of the Stepper by the Propagator
0263   ///
0264   /// @param [in,out] state is the mutable propagator state object
0265   /// @param [in] stepper Stepper in use
0266   template <typename propagator_state_t, typename stepper_t>
0267   void postStep(propagator_state_t& state, const stepper_t& stepper) const {
0268     ACTS_VERBOSE(volInfo(state) << "post step");
0269 
0270     // Navigator post step always resets the current surface
0271     state.navigation.currentSurface = nullptr;
0272     // Output the position in the sequence
0273     ACTS_VERBOSE(std::distance(state.navigation.navSurfaceIter,
0274                                state.navigation.navSurfaces.end())
0275                  << " out of " << state.navigation.navSurfaces.size()
0276                  << " surfaces remain to try.");
0277 
0278     // Check if we are on surface
0279     if (state.navigation.navSurfaceIter != state.navigation.navSurfaces.end()) {
0280       // Establish the surface status
0281       // TODO we do not know the intersection index - passing the closer one
0282       const auto& surface = **state.navigation.navSurfaceIter;
0283       const double farLimit = std::numeric_limits<double>::max();
0284       const auto index =
0285           chooseIntersection(
0286               state.geoContext, surface, stepper.position(state.stepping),
0287               state.options.direction * stepper.direction(state.stepping),
0288               BoundaryCheck(false), m_nearLimit, farLimit,
0289               state.options.surfaceTolerance)
0290               .index();
0291       auto surfaceStatus = stepper.updateSurfaceStatus(
0292           state.stepping, surface, index, state.options.direction,
0293           BoundaryCheck(false), state.options.surfaceTolerance, *m_logger);
0294       if (surfaceStatus == Intersection3D::Status::onSurface) {
0295         // Set the current surface
0296         state.navigation.currentSurface = *state.navigation.navSurfaceIter;
0297         ACTS_VERBOSE("Current surface set to  "
0298                      << state.navigation.currentSurface->geometryId())
0299         // Move the sequence to the next surface
0300         ++state.navigation.navSurfaceIter;
0301         if (state.navigation.navSurfaceIter !=
0302             state.navigation.navSurfaces.end()) {
0303           ACTS_VERBOSE("Next surface candidate is  "
0304                        << (*state.navigation.navSurfaceIter)->geometryId());
0305         }
0306       } else if (surfaceStatus == Intersection3D::Status::reachable) {
0307         ACTS_VERBOSE("Next surface reachable at distance  "
0308                      << stepper.outputStepSize(state.stepping));
0309       }
0310     }
0311   }
0312 
0313  private:
0314   template <typename propagator_state_t>
0315   std::string volInfo(const propagator_state_t& state) const {
0316     return (state.navigation.currentVolume != nullptr
0317                 ? state.navigation.currentVolume->volumeName()
0318                 : "No Volume") +
0319            " | ";
0320   }
0321 
0322   ObjectIntersection<Surface> chooseIntersection(
0323       const GeometryContext& gctx, const Surface& surface,
0324       const Vector3& position, const Vector3& direction,
0325       const BoundaryCheck& bcheck, double nearLimit, double farLimit,
0326       double tolerance) const {
0327     auto intersections =
0328         surface.intersect(gctx, position, direction, bcheck, tolerance);
0329 
0330     for (auto& intersection : intersections.split()) {
0331       if (detail::checkIntersection(intersection, nearLimit, farLimit,
0332                                     logger())) {
0333         return intersection;
0334       }
0335     }
0336 
0337     return ObjectIntersection<Surface>::invalid();
0338   }
0339 
0340   const Logger& logger() const { return *m_logger; }
0341 
0342   std::unique_ptr<const Logger> m_logger;
0343 
0344   // TODO https://github.com/acts-project/acts/issues/2738
0345   /// Distance limit to discard intersections "behind us"
0346   /// @note this is only necessary because some surfaces have more than one
0347   ///       intersection
0348   double m_nearLimit = -100 * UnitConstants::um;
0349 };
0350 
0351 }  // namespace Acts