File indexing completed on 2025-12-15 09:42:11
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 }