Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:10:55

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/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/BoundaryTolerance.hpp"
0021 #include "Acts/Surfaces/Surface.hpp"
0022 #include "Acts/Utilities/Logger.hpp"
0023 
0024 #include <algorithm>
0025 #include <sstream>
0026 #include <string>
0027 
0028 #include <boost/algorithm/string.hpp>
0029 #include <boost/container/small_vector.hpp>
0030 
0031 namespace Acts::Experimental {
0032 
0033 class DetectorNavigator {
0034  public:
0035   struct Config {
0036     /// Detector for this Navigation
0037     const Detector* detector = nullptr;
0038 
0039     /// Configuration for this Navigator
0040     /// stop at every sensitive surface (whether it has material or not)
0041     bool resolveSensitive = true;
0042     /// stop at every material surface (whether it is passive or not)
0043     bool resolveMaterial = true;
0044     /// stop at every surface regardless what it is
0045     bool resolvePassive = false;
0046   };
0047 
0048   struct Options : public NavigatorPlainOptions {
0049     explicit Options(const GeometryContext& gctx)
0050         : NavigatorPlainOptions(gctx) {}
0051 
0052     void setPlainOptions(const NavigatorPlainOptions& options) {
0053       static_cast<NavigatorPlainOptions&>(*this) = options;
0054     }
0055   };
0056 
0057   /// Nested State struct
0058   ///
0059   /// It acts as an internal state which is
0060   /// created for every propagation/extrapolation step
0061   /// and keep thread-local navigation information
0062   struct State : public NavigationState {
0063     explicit State(const Options& options_) : options(options_) {}
0064 
0065     Options options;
0066 
0067     /// Navigation state - external state: the current surface
0068     const Surface* currentSurface = nullptr;
0069     /// Navigation state : a break has been detected
0070     bool navigationBreak = false;
0071 
0072     /// Navigation statistics
0073     NavigatorStatistics statistics;
0074   };
0075 
0076   /// Constructor with configuration object
0077   ///
0078   /// @param cfg The navigator configuration
0079   /// @param _logger a logger instance
0080   explicit DetectorNavigator(Config cfg,
0081                              std::shared_ptr<const Logger> _logger =
0082                                  getDefaultLogger("DetectorNavigator",
0083                                                   Logging::Level::INFO))
0084       : m_cfg{cfg}, m_logger{std::move(_logger)} {}
0085 
0086   State makeState(const Options& options) const {
0087     State state(options);
0088     return state;
0089   }
0090 
0091   const Surface* currentSurface(const State& state) const {
0092     return state.currentSurface;
0093   }
0094 
0095   const DetectorVolume* currentVolume(const State& state) const {
0096     return state.currentVolume;
0097   }
0098 
0099   const IVolumeMaterial* currentVolumeMaterial(const State& state) const {
0100     return state.currentVolume->volumeMaterial();
0101   }
0102 
0103   const Surface* startSurface(const State& state) const {
0104     return state.options.startSurface;
0105   }
0106 
0107   const Surface* targetSurface(const State& state) const {
0108     return state.options.targetSurface;
0109   }
0110 
0111   bool endOfWorldReached(State& state) const {
0112     return state.currentVolume == nullptr;
0113   }
0114 
0115   bool navigationBreak(const State& state) const {
0116     return state.navigationBreak;
0117   }
0118 
0119   void initialize(State& state, const Vector3& position,
0120                   const Vector3& direction,
0121                   Direction propagationDirection) const {
0122     (void)propagationDirection;
0123 
0124     ACTS_VERBOSE(volInfo(state) << posInfo(state, position) << "initialize");
0125 
0126     if (state.currentDetector == nullptr) {
0127       ACTS_VERBOSE("Assigning detector from the config.");
0128       state.currentDetector = m_cfg.detector;
0129     }
0130     if (state.currentDetector == nullptr) {
0131       throw std::invalid_argument("DetectorNavigator: no detector assigned");
0132     }
0133 
0134     fillNavigationState(position, direction, state);
0135     if (state.currentVolume == nullptr) {
0136       state.currentVolume = state.currentDetector->findDetectorVolume(
0137           state.options.geoContext, state.position);
0138     }
0139     if (state.currentVolume == nullptr) {
0140       throw std::invalid_argument("DetectorNavigator: no current volume found");
0141     }
0142     updateCandidateSurfaces(state, position);
0143   }
0144 
0145   NavigationTarget nextTarget(State& state, const Vector3& position,
0146                               const Vector3& direction) const {
0147     ACTS_VERBOSE(volInfo(state)
0148                  << posInfo(state, position) << "Entering navigator::preStep.");
0149 
0150     if (inactive()) {
0151       ACTS_VERBOSE(volInfo(state)
0152                    << posInfo(state, position) << "navigator inactive");
0153       return NavigationTarget::None();
0154     }
0155 
0156     fillNavigationState(position, direction, state);
0157 
0158     if (state.currentSurface != nullptr) {
0159       ACTS_VERBOSE(volInfo(state)
0160                    << posInfo(state, position) << "stepping through surface");
0161     }
0162 
0163     if (state.surfaceCandidateIndex == state.surfaceCandidates.size()) {
0164       ACTS_VERBOSE(volInfo(state)
0165                    << posInfo(state, position) << "no surface candidates");
0166       return NavigationTarget::None();
0167     }
0168 
0169     // Screen output how much is left to try
0170     ACTS_VERBOSE(volInfo(state) << posInfo(state, position)
0171                                 << (state.surfaceCandidates.size() -
0172                                     state.surfaceCandidateIndex)
0173                                 << " out of " << state.surfaceCandidates.size()
0174                                 << " surfaces remain to try.");
0175     // Take the surface
0176     const auto& candidate = state.surfaceCandidate();
0177     const auto& surface = (candidate.surface != nullptr)
0178                               ? (*candidate.surface)
0179                               : (candidate.portal->surface());
0180     // Screen output which surface you are on
0181     ACTS_VERBOSE(volInfo(state)
0182                  << posInfo(state, position)
0183                  << "next surface candidate will be " << surface.geometryId()
0184                  << " (" << surface.center(state.options.geoContext).transpose()
0185                  << ")");
0186 
0187     state.currentSurface = nullptr;
0188     state.currentPortal = nullptr;
0189 
0190     return NavigationTarget(surface, candidate.objectIntersection.index(),
0191                             candidate.boundaryTolerance);
0192   }
0193 
0194   bool checkTargetValid(const State& state, const Vector3& position,
0195                         const Vector3& direction) const {
0196     (void)state;
0197     (void)position;
0198     (void)direction;
0199 
0200     return true;
0201   }
0202 
0203   void handleSurfaceReached(State& state, const Vector3& position,
0204                             const Vector3& direction,
0205                             const Surface& surface) const {
0206     (void)surface;
0207 
0208     ACTS_VERBOSE(volInfo(state) << posInfo(state, position)
0209                                 << "Entering navigator::handleSurfaceReached.");
0210 
0211     fillNavigationState(position, direction, state);
0212 
0213     if (inactive()) {
0214       ACTS_VERBOSE(volInfo(state)
0215                    << posInfo(state, position) << "navigator inactive");
0216       return;
0217     }
0218 
0219     if (state.surfaceCandidateIndex == state.surfaceCandidates.size()) {
0220       ACTS_VERBOSE(volInfo(state)
0221                    << posInfo(state, position)
0222                    << "no surface candidates - waiting for target call");
0223       return;
0224     }
0225 
0226     const Portal* nextPortal = nullptr;
0227     const Surface* nextSurface = nullptr;
0228     bool isPortal = false;
0229 
0230     if (state.surfaceCandidate().surface != nullptr) {
0231       nextSurface = state.surfaceCandidate().surface;
0232     } else if (state.surfaceCandidate().portal != nullptr) {
0233       nextPortal = state.surfaceCandidate().portal;
0234       nextSurface = &nextPortal->surface();
0235       isPortal = true;
0236     } else {
0237       std::string msg = "DetectorNavigator: " + volInfo(state) +
0238                         posInfo(state, position) +
0239                         "panic: not a surface not a portal - what is it?";
0240       throw std::runtime_error(msg);
0241     }
0242 
0243     ACTS_VERBOSE(volInfo(state)
0244                  << posInfo(state, position) << "landed on surface");
0245 
0246     if (isPortal) {
0247       ACTS_VERBOSE(volInfo(state)
0248                    << posInfo(state, position)
0249                    << "this is a portal, updating to new volume.");
0250       state.currentPortal = nextPortal;
0251       state.currentSurface = &nextPortal->surface();
0252       state.surfaceCandidates.clear();
0253       state.surfaceCandidateIndex = 0;
0254 
0255       state.currentPortal->updateDetectorVolume(state.options.geoContext,
0256                                                 state);
0257 
0258       // If no Volume is found, we are at the end of the world
0259       if (state.currentVolume == nullptr) {
0260         ACTS_VERBOSE(volInfo(state)
0261                      << posInfo(state, position)
0262                      << "no volume after Portal update, end of world.");
0263         state.navigationBreak = true;
0264         return;
0265       }
0266 
0267       // Switched to a new volume
0268       // Update candidate surfaces
0269       updateCandidateSurfaces(state, position);
0270 
0271       ACTS_VERBOSE(volInfo(state)
0272                    << posInfo(state, position) << "current portal set to "
0273                    << state.currentPortal->surface().geometryId());
0274     } else {
0275       ACTS_VERBOSE(volInfo(state) << posInfo(state, position)
0276                                   << "this is a surface, storing it.");
0277 
0278       // If we are on the surface pointed at by the iterator, we can make
0279       // it the current one to pass it to the other actors
0280       state.currentSurface = nextSurface;
0281       ACTS_VERBOSE(volInfo(state)
0282                    << posInfo(state, position) << "current surface set to "
0283                    << state.currentSurface->geometryId());
0284       ++state.surfaceCandidateIndex;
0285     }
0286   }
0287 
0288  private:
0289   Config m_cfg;
0290 
0291   std::shared_ptr<const Logger> m_logger;
0292 
0293   std::string volInfo(const State& state) const {
0294     return (state.currentVolume != nullptr ? state.currentVolume->name()
0295                                            : "No Volume") +
0296            " | ";
0297   }
0298 
0299   std::string posInfo(const State& /*state*/, const Vector3& position) const {
0300     std::stringstream ss;
0301     ss << position.transpose();
0302     ss << " | ";
0303     return ss.str();
0304   }
0305 
0306   const Logger& logger() const { return *m_logger; }
0307 
0308   /// This checks if a navigation break had been triggered or navigator
0309   /// is misconfigured
0310   ///
0311   /// @return true if the navigator is inactive
0312   bool inactive() const {
0313     if (m_cfg.detector == nullptr) {
0314       return true;
0315     }
0316 
0317     if (!m_cfg.resolveSensitive && !m_cfg.resolveMaterial &&
0318         !m_cfg.resolvePassive) {
0319       return true;
0320     }
0321 
0322     return false;
0323   }
0324 
0325   /// @brief Navigation (re-)initialisation for the target
0326   ///
0327   /// @note This is only called a few times every propagation/extrapolation
0328   ///
0329   /// As a straight line estimate can lead you to the wrong destination
0330   /// Volume, this will be called at:
0331   /// - initialization
0332   /// - attempted volume switch
0333   /// Target finding by association will not be done again
0334   ///
0335   /// @param [in,out] state is the propagation state object
0336   /// @param [in] position is the current position
0337   void updateCandidateSurfaces(State& state, const Vector3& position) const {
0338     ACTS_VERBOSE(volInfo(state)
0339                  << posInfo(state, position) << "initialize target");
0340 
0341     // Here we get the candidate surfaces
0342     state.currentVolume->updateNavigationState(state.options.geoContext, state);
0343 
0344     // Sort properly the surface candidates
0345     auto& nCandidates = state.surfaceCandidates;
0346     std::ranges::sort(nCandidates, {}, [](const auto& c) {
0347       return c.objectIntersection.pathLength();
0348     });
0349     // Set the surface candidate
0350     state.surfaceCandidateIndex = 0;
0351   }
0352 
0353   void fillNavigationState(const Vector3& position, const Vector3& direction,
0354                            State& state) const {
0355     state.position = position;
0356     state.direction = direction;
0357   }
0358 };
0359 
0360 }  // namespace Acts::Experimental