File indexing completed on 2025-11-03 08:57:03
0001 
0002 
0003 
0004 
0005 
0006 
0007 
0008 
0009 #pragma once
0010 
0011 #include "Acts/Detector/Detector.hpp"
0012 #include "Acts/Detector/DetectorVolume.hpp"
0013 #include "Acts/Detector/Portal.hpp"
0014 #include "Acts/Geometry/GeometryIdentifier.hpp"
0015 #include "Acts/Geometry/Layer.hpp"
0016 #include "Acts/Navigation/NavigationState.hpp"
0017 #include "Acts/Propagator/NavigationTarget.hpp"
0018 #include "Acts/Propagator/NavigatorOptions.hpp"
0019 #include "Acts/Propagator/NavigatorStatistics.hpp"
0020 #include "Acts/Surfaces/Surface.hpp"
0021 #include "Acts/Utilities/Logger.hpp"
0022 
0023 #include <algorithm>
0024 #include <sstream>
0025 #include <string>
0026 
0027 #include <boost/algorithm/string.hpp>
0028 #include <boost/container/small_vector.hpp>
0029 
0030 namespace Acts::Experimental {
0031 
0032 class DetectorNavigator {
0033  public:
0034   struct Config {
0035     
0036     const Detector* detector = nullptr;
0037 
0038     
0039     
0040     bool resolveSensitive = true;
0041     
0042     bool resolveMaterial = true;
0043     
0044     bool resolvePassive = false;
0045   };
0046 
0047   struct Options : public NavigatorPlainOptions {
0048     explicit Options(const GeometryContext& gctx)
0049         : NavigatorPlainOptions(gctx) {}
0050 
0051     void setPlainOptions(const NavigatorPlainOptions& options) {
0052       static_cast<NavigatorPlainOptions&>(*this) = options;
0053     }
0054   };
0055 
0056   
0057   
0058   
0059   
0060   
0061   struct State : public NavigationState {
0062     
0063     
0064     explicit State(const Options& options_) : options(options_) {}
0065 
0066     
0067     Options options;
0068 
0069     
0070     const Surface* currentSurface = nullptr;
0071     
0072     bool navigationBreak = false;
0073 
0074     
0075     NavigatorStatistics statistics;
0076   };
0077 
0078   
0079   
0080   
0081   
0082   explicit DetectorNavigator(Config cfg,
0083                              std::shared_ptr<const Logger> _logger =
0084                                  getDefaultLogger("DetectorNavigator",
0085                                                   Logging::Level::INFO))
0086       : m_cfg{cfg}, m_logger{std::move(_logger)} {}
0087 
0088   State makeState(const Options& options) const {
0089     State state(options);
0090     return state;
0091   }
0092 
0093   const Surface* currentSurface(const State& state) const {
0094     return state.currentSurface;
0095   }
0096 
0097   const DetectorVolume* currentVolume(const State& state) const {
0098     return state.currentVolume;
0099   }
0100 
0101   const IVolumeMaterial* currentVolumeMaterial(const State& state) const {
0102     return state.currentVolume->volumeMaterial();
0103   }
0104 
0105   const Surface* startSurface(const State& state) const {
0106     return state.options.startSurface;
0107   }
0108 
0109   const Surface* targetSurface(const State& state) const {
0110     return state.options.targetSurface;
0111   }
0112 
0113   bool endOfWorldReached(State& state) const {
0114     return state.currentVolume == nullptr;
0115   }
0116 
0117   bool navigationBreak(const State& state) const {
0118     return state.navigationBreak;
0119   }
0120 
0121   [[nodiscard]] Result<void> initialize(State& state, const Vector3& position,
0122                                         const Vector3& direction,
0123                                         Direction propagationDirection) const {
0124     (void)propagationDirection;
0125 
0126     ACTS_VERBOSE(volInfo(state) << posInfo(state, position) << "initialize");
0127 
0128     if (state.currentDetector == nullptr) {
0129       ACTS_VERBOSE("Assigning detector from the config.");
0130       state.currentDetector = m_cfg.detector;
0131     }
0132     if (state.currentDetector == nullptr) {
0133       throw std::invalid_argument("DetectorNavigator: no detector assigned");
0134     }
0135 
0136     fillNavigationState(position, direction, state);
0137     if (state.currentVolume == nullptr) {
0138       state.currentVolume = state.currentDetector->findDetectorVolume(
0139           state.options.geoContext, state.position);
0140     }
0141     if (state.currentVolume == nullptr) {
0142       throw std::invalid_argument("DetectorNavigator: no current volume found");
0143     }
0144     updateCandidateSurfaces(state, position);
0145 
0146     return Result<void>::success();
0147   }
0148 
0149   NavigationTarget nextTarget(State& state, const Vector3& position,
0150                               const Vector3& direction) const {
0151     ACTS_VERBOSE(volInfo(state)
0152                  << posInfo(state, position) << "Entering navigator::preStep.");
0153 
0154     if (inactive()) {
0155       ACTS_VERBOSE(volInfo(state)
0156                    << posInfo(state, position) << "navigator inactive");
0157       return NavigationTarget::None();
0158     }
0159 
0160     fillNavigationState(position, direction, state);
0161 
0162     if (state.currentSurface != nullptr) {
0163       ACTS_VERBOSE(volInfo(state)
0164                    << posInfo(state, position) << "stepping through surface");
0165     }
0166     ++state.surfaceCandidateIndex;
0167 
0168     if (state.surfaceCandidateIndex ==
0169         static_cast<int>(state.surfaceCandidates.size())) {
0170       ACTS_VERBOSE(volInfo(state)
0171                    << posInfo(state, position) << "no surface candidates");
0172       
0173       
0174       if (state.currentPortal == nullptr) {
0175         updateCandidateSurfaces(state, position);
0176         state.surfaceCandidateIndex = 0;
0177       } else {
0178         return NavigationTarget::None();
0179       }
0180     }
0181 
0182     
0183     ACTS_VERBOSE(volInfo(state) << posInfo(state, position)
0184                                 << (state.surfaceCandidates.size() -
0185                                     state.surfaceCandidateIndex)
0186                                 << " out of " << state.surfaceCandidates.size()
0187                                 << " surfaces remain to try.");
0188 
0189     
0190     const auto& candidate = state.surfaceCandidate();
0191     const auto& surface = candidate.surface();
0192     
0193     ACTS_VERBOSE(volInfo(state)
0194                  << posInfo(state, position)
0195                  << "next surface candidate will be " << surface.geometryId()
0196                  << " (" << surface.center(state.options.geoContext).transpose()
0197                  << ")");
0198 
0199     state.currentSurface = nullptr;
0200     state.currentPortal = nullptr;
0201     return candidate;
0202   }
0203 
0204   bool checkTargetValid(const State& state, const Vector3& position,
0205                         const Vector3& direction) const {
0206     (void)state;
0207     (void)position;
0208     (void)direction;
0209 
0210     return true;
0211   }
0212 
0213   void handleSurfaceReached(State& state, const Vector3& position,
0214                             const Vector3& direction,
0215                             const Surface& surface) const {
0216     (void)surface;
0217 
0218     ACTS_VERBOSE(volInfo(state) << posInfo(state, position)
0219                                 << "Entering navigator::handleSurfaceReached.");
0220 
0221     fillNavigationState(position, direction, state);
0222 
0223     if (inactive()) {
0224       ACTS_VERBOSE(volInfo(state)
0225                    << posInfo(state, position) << "navigator inactive");
0226       return;
0227     }
0228 
0229     if (state.surfaceCandidateIndex ==
0230         static_cast<int>(state.surfaceCandidates.size())) {
0231       ACTS_VERBOSE(volInfo(state)
0232                    << posInfo(state, position)
0233                    << "no surface candidates - waiting for target call");
0234       return;
0235     }
0236 
0237     const Portal* nextPortal = nullptr;
0238     const Surface* nextSurface = nullptr;
0239     bool isPortal = false;
0240 
0241     nextSurface = &state.surfaceCandidate().surface();
0242     if (state.surfaceCandidate().isPortalTarget()) {
0243       nextPortal = &state.surfaceCandidate().gen2Portal();
0244       nextSurface = &nextPortal->surface();
0245       isPortal = true;
0246     }
0247 
0248     ACTS_VERBOSE(volInfo(state)
0249                  << posInfo(state, position) << "landed on surface");
0250 
0251     if (isPortal) {
0252       ACTS_VERBOSE(volInfo(state)
0253                    << posInfo(state, position)
0254                    << "this is a portal, updating to new volume.");
0255       state.currentPortal = nextPortal;
0256       state.currentSurface = &nextPortal->surface();
0257       state.surfaceCandidates.clear();
0258       state.surfaceCandidateIndex = -1;
0259 
0260       state.currentPortal->updateDetectorVolume(state.options.geoContext,
0261                                                 state);
0262 
0263       
0264       if (state.currentVolume == nullptr) {
0265         ACTS_VERBOSE(volInfo(state)
0266                      << posInfo(state, position)
0267                      << "no volume after Portal update, end of world.");
0268         state.navigationBreak = true;
0269         return;
0270       }
0271 
0272       
0273       
0274       updateCandidateSurfaces(state, position);
0275 
0276       ACTS_VERBOSE(volInfo(state)
0277                    << posInfo(state, position) << "current portal set to "
0278                    << state.currentPortal->surface().geometryId());
0279     } else {
0280       ACTS_VERBOSE(volInfo(state) << posInfo(state, position)
0281                                   << "this is a surface, storing it.");
0282 
0283       
0284       
0285       state.currentSurface = nextSurface;
0286       ACTS_VERBOSE(volInfo(state)
0287                    << posInfo(state, position) << "current surface set to "
0288                    << state.currentSurface->geometryId());
0289     }
0290   }
0291 
0292  private:
0293   Config m_cfg;
0294 
0295   std::shared_ptr<const Logger> m_logger;
0296 
0297   std::string volInfo(const State& state) const {
0298     return (state.currentVolume != nullptr ? state.currentVolume->name()
0299                                            : "No Volume") +
0300            " | ";
0301   }
0302 
0303   std::string posInfo(const State& , const Vector3& position) const {
0304     std::stringstream ss;
0305     ss << position.transpose();
0306     ss << " | ";
0307     return ss.str();
0308   }
0309 
0310   const Logger& logger() const { return *m_logger; }
0311 
0312   
0313   
0314   
0315   
0316   bool inactive() const {
0317     if (m_cfg.detector == nullptr) {
0318       return true;
0319     }
0320 
0321     if (!m_cfg.resolveSensitive && !m_cfg.resolveMaterial &&
0322         !m_cfg.resolvePassive) {
0323       return true;
0324     }
0325 
0326     return false;
0327   }
0328 
0329   
0330   
0331   
0332   
0333   
0334   
0335   
0336   
0337   
0338   
0339   
0340   
0341   void updateCandidateSurfaces(State& state, const Vector3& position) const {
0342     ACTS_VERBOSE(volInfo(state)
0343                  << posInfo(state, position) << "initialize target");
0344 
0345     
0346     state.currentVolume->updateNavigationState(state.options.geoContext, state);
0347 
0348     
0349     auto& nCandidates = state.surfaceCandidates;
0350     std::ranges::sort(nCandidates, NavigationTarget::pathLengthOrder);
0351     state.surfaceCandidateIndex = -1;
0352   }
0353 
0354   void fillNavigationState(const Vector3& position, const Vector3& direction,
0355                            State& state) const {
0356     state.position = position;
0357     state.direction = direction;
0358   }
0359 };
0360 
0361 }