File indexing completed on 2025-01-18 09:10:55
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/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
0037 const Detector* detector = nullptr;
0038
0039
0040
0041 bool resolveSensitive = true;
0042
0043 bool resolveMaterial = true;
0044
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
0058
0059
0060
0061
0062 struct State : public NavigationState {
0063 explicit State(const Options& options_) : options(options_) {}
0064
0065 Options options;
0066
0067
0068 const Surface* currentSurface = nullptr;
0069
0070 bool navigationBreak = false;
0071
0072
0073 NavigatorStatistics statistics;
0074 };
0075
0076
0077
0078
0079
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
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
0176 const auto& candidate = state.surfaceCandidate();
0177 const auto& surface = (candidate.surface != nullptr)
0178 ? (*candidate.surface)
0179 : (candidate.portal->surface());
0180
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
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
0268
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
0279
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& , 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
0309
0310
0311
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
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337 void updateCandidateSurfaces(State& state, const Vector3& position) const {
0338 ACTS_VERBOSE(volInfo(state)
0339 << posInfo(state, position) << "initialize target");
0340
0341
0342 state.currentVolume->updateNavigationState(state.options.geoContext, state);
0343
0344
0345 auto& nCandidates = state.surfaceCandidates;
0346 std::ranges::sort(nCandidates, {}, [](const auto& c) {
0347 return c.objectIntersection.pathLength();
0348 });
0349
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 }