File indexing completed on 2026-04-05 07:45:05
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Direction.hpp"
0012 #include "Acts/Definitions/Units.hpp"
0013 #include "Acts/Geometry/Layer.hpp"
0014 #include "Acts/Geometry/TrackingGeometry.hpp"
0015 #include "Acts/Geometry/TrackingVolume.hpp"
0016 #include "Acts/Propagator/NavigationTarget.hpp"
0017 #include "Acts/Propagator/NavigatorOptions.hpp"
0018 #include "Acts/Propagator/NavigatorStatistics.hpp"
0019 #include "Acts/Surfaces/BoundaryTolerance.hpp"
0020 #include "Acts/Surfaces/Surface.hpp"
0021 #include "Acts/Utilities/Enumerate.hpp"
0022 #include "Acts/Utilities/Intersection.hpp"
0023 #include "Acts/Utilities/Logger.hpp"
0024 #include "Acts/Utilities/Result.hpp"
0025
0026 #include <limits>
0027 #include <memory>
0028
0029 namespace Acts {
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039 class DirectNavigator {
0040 public:
0041
0042 struct Config {};
0043
0044
0045 struct Options : public NavigatorPlainOptions {
0046
0047
0048 explicit Options(const GeometryContext& gctx)
0049 : NavigatorPlainOptions(gctx) {}
0050
0051
0052 double surfaceTolerance = s_onSurfaceTolerance;
0053
0054
0055
0056
0057
0058 double nearLimit = -100 * UnitConstants::um;
0059
0060
0061 double farLimit = std::numeric_limits<double>::max();
0062
0063
0064
0065 void setPlainOptions(const NavigatorPlainOptions& options) {
0066 static_cast<NavigatorPlainOptions&>(*this) = options;
0067 }
0068 };
0069
0070
0071
0072
0073
0074
0075 struct State {
0076
0077
0078 explicit State(const Options& options_) : options(options_) {}
0079
0080
0081 Options options;
0082
0083
0084 Direction direction = Direction::Forward();
0085
0086
0087
0088
0089 std::int32_t surfaceIndex = -1;
0090
0091
0092 const Surface* currentSurface = nullptr;
0093
0094
0095 bool navigationBreak = false;
0096
0097
0098 NavigatorStatistics statistics;
0099
0100
0101
0102 const Surface& navSurface() const {
0103 return *options.externalSurfaces.at(surfaceIndex);
0104 }
0105
0106
0107
0108 void nextSurface() {
0109 if (direction == Direction::Forward()) {
0110 ++surfaceIndex;
0111 } else {
0112 --surfaceIndex;
0113 }
0114 }
0115
0116
0117
0118 bool endOfSurfaces() const {
0119 if (direction == Direction::Forward()) {
0120 return surfaceIndex >=
0121 static_cast<int>(options.externalSurfaces.size());
0122 }
0123 return surfaceIndex < 0;
0124 }
0125
0126
0127
0128 int remainingSurfaces() const {
0129 if (direction == Direction::Forward()) {
0130 return options.externalSurfaces.size() - surfaceIndex;
0131 }
0132 return surfaceIndex + 1;
0133 }
0134
0135
0136
0137
0138 void resetSurfaceIndex() {
0139 surfaceIndex = direction == Direction::Forward()
0140 ? -1
0141 : static_cast<int>(options.externalSurfaces.size());
0142 }
0143 };
0144
0145
0146
0147 explicit DirectNavigator(std::unique_ptr<const Logger> _logger =
0148 getDefaultLogger("DirectNavigator",
0149 Logging::INFO))
0150 : m_logger{std::move(_logger)} {}
0151
0152
0153
0154
0155 State makeState(const Options& options) const {
0156 State state(options);
0157 return state;
0158 }
0159
0160
0161
0162
0163 const Surface* currentSurface(const State& state) const {
0164 return state.currentSurface;
0165 }
0166
0167
0168
0169
0170 const TrackingVolume* currentVolume(const State& state) const {
0171 static_cast<void>(state);
0172 return nullptr;
0173 }
0174
0175
0176
0177
0178 const IVolumeMaterial* currentVolumeMaterial(const State& state) const {
0179 static_cast<void>(state);
0180 return nullptr;
0181 }
0182
0183
0184
0185
0186 const Surface* startSurface(const State& state) const {
0187 return state.options.startSurface;
0188 }
0189
0190
0191
0192
0193 const Surface* targetSurface(const State& state) const {
0194 return state.options.targetSurface;
0195 }
0196
0197
0198
0199
0200
0201 bool endOfWorldReached(State& state) const {
0202 static_cast<void>(state);
0203 return false;
0204 }
0205
0206
0207
0208
0209 bool navigationBreak(const State& state) const {
0210 return state.navigationBreak;
0211 }
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222 [[nodiscard]] Result<void> initialize(State& state, const Vector3& position,
0223 const Vector3& direction,
0224 Direction propagationDirection) const {
0225 static_cast<void>(position);
0226 static_cast<void>(direction);
0227
0228 ACTS_VERBOSE("Initialize. Surface sequence for navigation:");
0229 for (const Surface* surface : state.options.externalSurfaces) {
0230 ACTS_VERBOSE(surface->geometryId()
0231 << " - "
0232 << surface->center(state.options.geoContext).transpose());
0233 }
0234
0235 state.direction = propagationDirection;
0236 ACTS_VERBOSE("Navigation direction is " << propagationDirection);
0237
0238
0239 state.currentSurface = state.options.startSurface;
0240 if (state.currentSurface != nullptr) {
0241 ACTS_VERBOSE("Current surface set to start surface "
0242 << state.currentSurface->geometryId());
0243 } else {
0244 ACTS_VERBOSE("Current surface set to nullptr");
0245 }
0246
0247
0248 auto found = std::ranges::find(state.options.externalSurfaces,
0249 state.options.startSurface);
0250
0251 if (found != state.options.externalSurfaces.end()) {
0252
0253
0254 state.surfaceIndex =
0255 std::distance(state.options.externalSurfaces.begin(), found);
0256 state.surfaceIndex += state.direction == Direction::Backward() ? 1 : -1;
0257 } else {
0258 ACTS_DEBUG(
0259 "Did not find the start surface in the sequence. Assuming it is not "
0260 "part of the sequence. Trusting the correctness of the input "
0261 "sequence. Resetting the surface index.");
0262 state.resetSurfaceIndex();
0263 }
0264
0265 state.navigationBreak = false;
0266
0267 return Result<void>::success();
0268 }
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280 NavigationTarget nextTarget(State& state, const Vector3& position,
0281 const Vector3& direction) const {
0282
0283 state.currentSurface = nullptr;
0284
0285 if (state.navigationBreak) {
0286 return NavigationTarget::None();
0287 }
0288
0289 ACTS_VERBOSE("DirectNavigator::nextTarget");
0290
0291
0292 state.nextSurface();
0293
0294 while (!state.endOfSurfaces()) {
0295 ACTS_VERBOSE("Next surface candidate is "
0296 << state.navSurface().geometryId() << ". "
0297 << state.remainingSurfaces() << " out of "
0298 << state.options.externalSurfaces.size()
0299 << " surfaces remain to try.");
0300
0301
0302
0303 const Surface& surface = state.navSurface();
0304 const double farLimit = std::numeric_limits<double>::max();
0305 const NavigationTarget target = chooseIntersection(
0306 state.options.geoContext, surface, position, direction,
0307 BoundaryTolerance::Infinite(), state.options.nearLimit, farLimit,
0308 state.options.surfaceTolerance);
0309 if (target.isValid()) {
0310 return target;
0311 }
0312
0313 ACTS_VERBOSE("No valid intersection found with surface "
0314 << surface.geometryId() << ", trying next surface.");
0315 state.nextSurface();
0316 }
0317
0318 ACTS_VERBOSE("End of surfaces reached, navigation break.");
0319 state.navigationBreak = true;
0320 return NavigationTarget::None();
0321 }
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333 bool checkTargetValid(const State& state, const Vector3& position,
0334 const Vector3& direction) const {
0335 static_cast<void>(state);
0336 static_cast<void>(position);
0337 static_cast<void>(direction);
0338
0339 return true;
0340 }
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351 void handleSurfaceReached(State& state, const Vector3& position,
0352 const Vector3& direction,
0353 const Surface& surface) const {
0354 static_cast<void>(position);
0355 static_cast<void>(direction);
0356 static_cast<void>(surface);
0357
0358 if (state.navigationBreak) {
0359 return;
0360 }
0361
0362 ACTS_VERBOSE("DirectNavigator::handleSurfaceReached");
0363
0364
0365 state.currentSurface = &state.navSurface();
0366 ACTS_VERBOSE("Current surface set to "
0367 << state.currentSurface->geometryId());
0368 }
0369
0370 private:
0371 NavigationTarget chooseIntersection(
0372 const GeometryContext& gctx, const Surface& surface,
0373 const Vector3& position, const Vector3& direction,
0374 const BoundaryTolerance& boundaryTolerance, double nearLimit,
0375 double farLimit, double tolerance) const {
0376 auto intersections = surface.intersect(gctx, position, direction,
0377 boundaryTolerance, tolerance);
0378
0379 for (auto [intersectionIndex, intersection] :
0380 Acts::enumerate(intersections)) {
0381 if (intersection.isValid() &&
0382 detail::checkPathLength(intersection.pathLength(), nearLimit,
0383 farLimit, logger())) {
0384 return NavigationTarget(intersection, intersectionIndex, surface,
0385 boundaryTolerance);
0386 }
0387 }
0388
0389 return NavigationTarget::None();
0390 }
0391
0392 const Logger& logger() const { return *m_logger; }
0393
0394 std::unique_ptr<const Logger> m_logger;
0395 };
0396
0397 }