File indexing completed on 2025-01-18 09:10:59
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Geometry/Layer.hpp"
0013 #include "Acts/Geometry/TrackingGeometry.hpp"
0014 #include "Acts/Geometry/TrackingVolume.hpp"
0015 #include "Acts/Propagator/NavigationTarget.hpp"
0016 #include "Acts/Propagator/NavigatorOptions.hpp"
0017 #include "Acts/Propagator/NavigatorStatistics.hpp"
0018 #include "Acts/Propagator/detail/NavigationHelpers.hpp"
0019 #include "Acts/Surfaces/BoundaryTolerance.hpp"
0020 #include "Acts/Surfaces/Surface.hpp"
0021 #include "Acts/Utilities/Intersection.hpp"
0022 #include "Acts/Utilities/Logger.hpp"
0023 #include "Acts/Utilities/StringHelpers.hpp"
0024
0025 #include <algorithm>
0026 #include <cstdint>
0027 #include <limits>
0028 #include <memory>
0029 #include <vector>
0030
0031 namespace Acts {
0032
0033
0034
0035
0036
0037
0038 class TryAllNavigatorBase {
0039 public:
0040
0041 struct Config {
0042
0043 std::shared_ptr<const TrackingGeometry> trackingGeometry;
0044
0045
0046 bool resolveSensitive = true;
0047
0048 bool resolveMaterial = true;
0049
0050 bool resolvePassive = false;
0051
0052
0053 BoundaryTolerance boundaryToleranceSurfaceApproach =
0054 BoundaryTolerance::None();
0055 };
0056
0057
0058 struct Options : public NavigatorPlainOptions {
0059 explicit Options(const GeometryContext& gctx)
0060 : NavigatorPlainOptions(gctx) {}
0061
0062
0063 double surfaceTolerance = s_onSurfaceTolerance;
0064
0065
0066 double nearLimit = s_onSurfaceTolerance;
0067
0068
0069 double farLimit = std::numeric_limits<double>::max();
0070
0071 void setPlainOptions(const NavigatorPlainOptions& options) {
0072 static_cast<NavigatorPlainOptions&>(*this) = options;
0073 }
0074 };
0075
0076
0077
0078
0079
0080 struct State {
0081 explicit State(const Options& options_) : options(options_) {}
0082
0083 Options options;
0084
0085
0086
0087
0088 const Surface* startSurface = nullptr;
0089
0090
0091
0092
0093 const Surface* targetSurface = nullptr;
0094
0095
0096
0097 const Surface* currentSurface = nullptr;
0098 const TrackingVolume* currentVolume = nullptr;
0099
0100
0101 std::vector<detail::NavigationObjectCandidate> navigationCandidates;
0102
0103
0104 bool navigationBreak = false;
0105
0106
0107 NavigatorStatistics statistics;
0108 };
0109
0110
0111
0112
0113
0114 TryAllNavigatorBase(Config cfg, std::unique_ptr<const Logger> logger)
0115 : m_cfg(std::move(cfg)), m_logger{std::move(logger)} {}
0116
0117 const Surface* currentSurface(const State& state) const {
0118 return state.currentSurface;
0119 }
0120
0121 const TrackingVolume* currentVolume(const State& state) const {
0122 return state.currentVolume;
0123 }
0124
0125 const IVolumeMaterial* currentVolumeMaterial(const State& state) const {
0126 if (state.currentVolume == nullptr) {
0127 return nullptr;
0128 }
0129 return state.currentVolume->volumeMaterial();
0130 }
0131
0132 const Surface* startSurface(const State& state) const {
0133 return state.startSurface;
0134 }
0135
0136 const Surface* targetSurface(const State& state) const {
0137 return state.targetSurface;
0138 }
0139
0140 bool endOfWorldReached(State& state) const {
0141 return state.currentVolume == nullptr;
0142 }
0143
0144 bool navigationBreak(const State& state) const {
0145 return state.navigationBreak;
0146 }
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157 void initialize(State& state, const Vector3& position,
0158 const Vector3& direction,
0159 Direction propagationDirection) const {
0160 (void)propagationDirection;
0161
0162 ACTS_VERBOSE("initialize");
0163
0164 const TrackingVolume* startVolume = nullptr;
0165
0166 if (state.startSurface != nullptr &&
0167 state.startSurface->associatedLayer() != nullptr) {
0168 ACTS_VERBOSE(
0169 "Fast start initialization through association from Surface.");
0170 const auto* startLayer = state.startSurface->associatedLayer();
0171 startVolume = startLayer->trackingVolume();
0172 } else {
0173 ACTS_VERBOSE("Slow start initialization through search.");
0174 ACTS_VERBOSE("Starting from position " << toString(position)
0175 << " and direction "
0176 << toString(direction));
0177 startVolume = m_cfg.trackingGeometry->lowestTrackingVolume(
0178 state.options.geoContext, position);
0179 }
0180
0181
0182 {
0183 state.currentVolume = startVolume;
0184 if (state.currentVolume != nullptr) {
0185 ACTS_VERBOSE(volInfo(state) << "Start volume resolved.");
0186 } else {
0187 ACTS_ERROR("Start volume not resolved.");
0188 }
0189
0190 state.currentSurface = state.startSurface;
0191 if (state.currentSurface != nullptr) {
0192 ACTS_VERBOSE(volInfo(state) << "Current surface set to start surface "
0193 << state.currentSurface->geometryId());
0194 } else {
0195 ACTS_VERBOSE(volInfo(state) << "No start surface set.");
0196 }
0197 }
0198 }
0199
0200 protected:
0201
0202 void initializeVolumeCandidates(State& state) const {
0203 const TrackingVolume* volume = state.currentVolume;
0204 ACTS_VERBOSE(volInfo(state) << "Initialize volume");
0205
0206 if (volume == nullptr) {
0207 state.navigationBreak = true;
0208 ACTS_VERBOSE(volInfo(state) << "No volume set. Good luck.");
0209 return;
0210 }
0211
0212 emplaceAllVolumeCandidates(
0213 state.navigationCandidates, *volume, m_cfg.resolveSensitive,
0214 m_cfg.resolveMaterial, m_cfg.resolvePassive,
0215 m_cfg.boundaryToleranceSurfaceApproach, logger());
0216 }
0217
0218 std::string volInfo(const State& state) const {
0219 return (state.currentVolume != nullptr ? state.currentVolume->volumeName()
0220 : "No Volume") +
0221 " | ";
0222 }
0223
0224 const Logger& logger() const { return *m_logger; }
0225
0226 Config m_cfg;
0227
0228 std::unique_ptr<const Logger> m_logger;
0229 };
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240 class TryAllNavigator : public TryAllNavigatorBase {
0241 public:
0242 using Config = TryAllNavigatorBase::Config;
0243 using Options = TryAllNavigatorBase::Options;
0244
0245
0246 struct State : public TryAllNavigatorBase::State {
0247 explicit State(const Options& options_)
0248 : TryAllNavigatorBase::State(options_) {}
0249
0250 std::vector<detail::IntersectedNavigationObject> currentCandidates;
0251 };
0252
0253
0254
0255
0256
0257 TryAllNavigator(Config cfg,
0258 std::unique_ptr<const Logger> logger =
0259 getDefaultLogger("TryAllNavigator", Logging::INFO))
0260 : TryAllNavigatorBase(std::move(cfg), std::move(logger)) {}
0261
0262 State makeState(const Options& options) const {
0263 State state(options);
0264 state.startSurface = options.startSurface;
0265 state.targetSurface = options.targetSurface;
0266
0267 return state;
0268 }
0269
0270 using TryAllNavigatorBase::currentSurface;
0271 using TryAllNavigatorBase::currentVolume;
0272 using TryAllNavigatorBase::currentVolumeMaterial;
0273 using TryAllNavigatorBase::endOfWorldReached;
0274 using TryAllNavigatorBase::navigationBreak;
0275 using TryAllNavigatorBase::startSurface;
0276 using TryAllNavigatorBase::targetSurface;
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287 void initialize(State& state, const Vector3& position,
0288 const Vector3& direction,
0289 Direction propagationDirection) const {
0290 TryAllNavigatorBase::initialize(state, position, direction,
0291 propagationDirection);
0292
0293
0294 reinitializeCandidates(state);
0295 }
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308 NavigationTarget nextTarget(State& state, const Vector3& position,
0309 const Vector3& direction) const {
0310
0311 if (state.navigationBreak) {
0312 return NavigationTarget::None();
0313 }
0314
0315 ACTS_VERBOSE(volInfo(state) << "nextTarget");
0316
0317
0318 state.currentSurface = nullptr;
0319
0320 double nearLimit = state.options.nearLimit;
0321 double farLimit = state.options.farLimit;
0322
0323
0324 if (!state.currentCandidates.empty()) {
0325 const detail::IntersectedNavigationObject& previousCandidate =
0326 state.currentCandidates.front();
0327
0328 const Surface& surface = *previousCandidate.intersection.object();
0329 std::uint8_t index = previousCandidate.intersection.index();
0330 BoundaryTolerance boundaryTolerance = previousCandidate.boundaryTolerance;
0331
0332 auto intersection = surface.intersect(
0333 state.options.geoContext, position, direction, boundaryTolerance,
0334 state.options.surfaceTolerance)[index];
0335
0336 if (intersection.pathLength() < 0) {
0337 nearLimit = std::min(nearLimit, intersection.pathLength() -
0338 state.options.surfaceTolerance);
0339 farLimit = -state.options.surfaceTolerance;
0340
0341 ACTS_VERBOSE(volInfo(state)
0342 << "handle overstepping with nearLimit " << nearLimit
0343 << " and farLimit " << farLimit);
0344 }
0345 }
0346
0347 std::vector<detail::IntersectedNavigationObject> intersectionCandidates;
0348
0349
0350 for (const auto& candidate : state.navigationCandidates) {
0351 auto intersections =
0352 candidate.intersect(state.options.geoContext, position, direction,
0353 state.options.surfaceTolerance);
0354 for (const auto& intersection : intersections.first.split()) {
0355
0356 if (!intersection.isValid() ||
0357 !detail::checkPathLength(intersection.pathLength(), nearLimit,
0358 farLimit)) {
0359 continue;
0360 }
0361
0362 intersectionCandidates.emplace_back(intersection, intersections.second,
0363 candidate.boundaryTolerance);
0364 }
0365 }
0366
0367 std::ranges::sort(intersectionCandidates,
0368 detail::IntersectedNavigationObject::forwardOrder);
0369
0370 ACTS_VERBOSE(volInfo(state) << "found " << intersectionCandidates.size()
0371 << " intersections");
0372
0373 NavigationTarget nextTarget = NavigationTarget::None();
0374 state.currentCandidates.clear();
0375
0376 for (const auto& candidate : intersectionCandidates) {
0377 const auto& intersection = candidate.intersection;
0378 const Surface& surface = *intersection.object();
0379 BoundaryTolerance boundaryTolerance = candidate.boundaryTolerance;
0380
0381 if (intersection.status() == IntersectionStatus::onSurface) {
0382 ACTS_ERROR(volInfo(state)
0383 << "We are on surface " << surface.geometryId()
0384 << " before trying to reach it. This should not happen. "
0385 "Good luck.");
0386 continue;
0387 }
0388
0389 if (intersection.status() == IntersectionStatus::reachable) {
0390 nextTarget =
0391 NavigationTarget(surface, intersection.index(), boundaryTolerance);
0392 break;
0393 }
0394 }
0395
0396 state.currentCandidates = std::move(intersectionCandidates);
0397
0398 if (nextTarget.isNone()) {
0399 ACTS_VERBOSE(volInfo(state) << "no target found");
0400 } else {
0401 ACTS_VERBOSE(volInfo(state)
0402 << "next target is " << nextTarget.surface->geometryId());
0403 }
0404
0405 return nextTarget;
0406 }
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421 bool checkTargetValid(const State& state, const Vector3& position,
0422 const Vector3& direction) const {
0423 (void)state;
0424 (void)position;
0425 (void)direction;
0426
0427 return false;
0428 }
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438 void handleSurfaceReached(State& state, const Vector3& position,
0439 const Vector3& direction,
0440 const Surface& ) const {
0441
0442 if (state.navigationBreak) {
0443 return;
0444 }
0445
0446 ACTS_VERBOSE(volInfo(state) << "handleSurfaceReached");
0447
0448 if (state.currentCandidates.empty()) {
0449 ACTS_VERBOSE(volInfo(state) << "No current candidate set.");
0450 return;
0451 }
0452
0453 assert(state.currentSurface == nullptr && "Current surface must be reset.");
0454
0455
0456
0457 std::vector<detail::IntersectedNavigationObject> hitCandidates;
0458
0459 for (const auto& candidate : state.currentCandidates) {
0460 const Surface& surface = *candidate.intersection.object();
0461 std::uint8_t index = candidate.intersection.index();
0462 BoundaryTolerance boundaryTolerance = BoundaryTolerance::None();
0463
0464 auto intersection = surface.intersect(
0465 state.options.geoContext, position, direction, boundaryTolerance,
0466 state.options.surfaceTolerance)[index];
0467
0468 if (intersection.status() == IntersectionStatus::onSurface) {
0469 hitCandidates.emplace_back(candidate);
0470 }
0471 }
0472
0473 state.currentCandidates.clear();
0474
0475 ACTS_VERBOSE(volInfo(state)
0476 << "Found " << hitCandidates.size()
0477 << " intersections on surface with bounds check.");
0478
0479 if (hitCandidates.empty()) {
0480 ACTS_VERBOSE(volInfo(state) << "No hit candidates found.");
0481 return;
0482 }
0483
0484 if (hitCandidates.size() > 1) {
0485 ACTS_VERBOSE(volInfo(state)
0486 << "Only using first intersection within bounds.");
0487 }
0488
0489
0490 const auto candidate = hitCandidates.front();
0491 const auto& intersection = candidate.intersection;
0492 const Surface& surface = *intersection.object();
0493
0494 ACTS_VERBOSE(volInfo(state) << "Surface " << surface.geometryId()
0495 << " successfully hit, storing it.");
0496 state.currentSurface = &surface;
0497
0498 if (candidate.template checkType<Surface>()) {
0499 ACTS_VERBOSE(volInfo(state) << "This is a surface");
0500 } else if (candidate.template checkType<Layer>()) {
0501 ACTS_VERBOSE(volInfo(state) << "This is a layer");
0502 } else if (candidate.template checkType<BoundarySurface>()) {
0503 ACTS_VERBOSE(volInfo(state)
0504 << "This is a boundary. Reinitialize navigation");
0505
0506 const auto& boundary = *candidate.template object<BoundarySurface>();
0507
0508 state.currentVolume = boundary.attachedVolume(state.options.geoContext,
0509 position, direction);
0510
0511 ACTS_VERBOSE(volInfo(state) << "Switched volume");
0512
0513 reinitializeCandidates(state);
0514 } else {
0515 ACTS_ERROR(volInfo(state) << "Unknown intersection type");
0516 }
0517 }
0518
0519 private:
0520
0521 void reinitializeCandidates(State& state) const {
0522 state.navigationCandidates.clear();
0523 state.currentCandidates.clear();
0524
0525 initializeVolumeCandidates(state);
0526 }
0527 };
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543 class TryAllOverstepNavigator : public TryAllNavigatorBase {
0544 public:
0545 using Config = TryAllNavigatorBase::Config;
0546
0547 using Options = TryAllNavigatorBase::Options;
0548
0549
0550
0551
0552
0553 struct State : public TryAllNavigatorBase::State {
0554 explicit State(const Options& options_)
0555 : TryAllNavigatorBase::State(options_) {}
0556
0557
0558 std::vector<detail::IntersectedNavigationObject> activeCandidates;
0559
0560 int activeCandidateIndex = -1;
0561
0562
0563 std::optional<Vector3> lastPosition;
0564
0565
0566 const detail::IntersectedNavigationObject& activeCandidate() const {
0567 return activeCandidates.at(activeCandidateIndex);
0568 }
0569
0570 bool endOfCandidates() const {
0571 return activeCandidateIndex >= static_cast<int>(activeCandidates.size());
0572 }
0573 };
0574
0575
0576
0577
0578
0579 TryAllOverstepNavigator(Config cfg,
0580 std::unique_ptr<const Logger> logger =
0581 getDefaultLogger("TryAllOverstepNavigator",
0582 Logging::INFO))
0583 : TryAllNavigatorBase(std::move(cfg), std::move(logger)) {}
0584
0585 State makeState(const Options& options) const {
0586 State state(options);
0587 state.startSurface = options.startSurface;
0588 state.targetSurface = options.targetSurface;
0589
0590 return state;
0591 }
0592
0593 using TryAllNavigatorBase::currentSurface;
0594 using TryAllNavigatorBase::currentVolume;
0595 using TryAllNavigatorBase::currentVolumeMaterial;
0596 using TryAllNavigatorBase::endOfWorldReached;
0597 using TryAllNavigatorBase::navigationBreak;
0598 using TryAllNavigatorBase::startSurface;
0599 using TryAllNavigatorBase::targetSurface;
0600
0601
0602
0603
0604
0605
0606
0607
0608
0609
0610 void initialize(State& state, const Vector3& position,
0611 const Vector3& direction,
0612 Direction propagationDirection) const {
0613 TryAllNavigatorBase::initialize(state, position, direction,
0614 propagationDirection);
0615
0616
0617 reinitializeCandidates(state);
0618
0619 state.lastPosition.reset();
0620 }
0621
0622
0623
0624
0625
0626
0627
0628
0629
0630
0631
0632
0633 NavigationTarget nextTarget(State& state, const Vector3& position,
0634 const Vector3& direction) const {
0635 (void)direction;
0636
0637 if (state.navigationBreak) {
0638 return NavigationTarget::None();
0639 }
0640
0641 ACTS_VERBOSE(volInfo(state) << "nextTarget");
0642
0643 state.currentSurface = nullptr;
0644
0645
0646 if (!state.lastPosition.has_value() && state.endOfCandidates()) {
0647 ACTS_VERBOSE(
0648 volInfo(state)
0649 << "Initial position, nothing to do, blindly stepping forward.");
0650 state.lastPosition = position;
0651 return NavigationTarget::None();
0652 }
0653
0654 if (state.endOfCandidates()) {
0655 ACTS_VERBOSE(volInfo(state) << "evaluate blind step");
0656
0657 Vector3 stepStart = state.lastPosition.value();
0658 Vector3 stepEnd = position;
0659 Vector3 step = stepEnd - stepStart;
0660 double stepDistance = step.norm();
0661 if (stepDistance < std::numeric_limits<double>::epsilon()) {
0662 ACTS_ERROR(volInfo(state) << "Step distance is zero. " << stepDistance);
0663 }
0664 Vector3 stepDirection = step.normalized();
0665
0666 double nearLimit = -stepDistance + state.options.surfaceTolerance;
0667 double farLimit = 0;
0668
0669 state.lastPosition.reset();
0670 state.activeCandidates.clear();
0671 state.activeCandidateIndex = -1;
0672
0673
0674 for (const auto& candidate : state.navigationCandidates) {
0675 auto intersections =
0676 candidate.intersect(state.options.geoContext, stepEnd,
0677 stepDirection, state.options.surfaceTolerance);
0678 for (const auto& intersection : intersections.first.split()) {
0679
0680 if (!intersection.isValid() ||
0681 !detail::checkPathLength(intersection.pathLength(), nearLimit,
0682 farLimit)) {
0683 continue;
0684 }
0685
0686 state.activeCandidates.emplace_back(
0687 intersection, intersections.second, candidate.boundaryTolerance);
0688 }
0689 }
0690
0691 std::ranges::sort(state.activeCandidates,
0692 detail::IntersectedNavigationObject::forwardOrder);
0693
0694 ACTS_VERBOSE(volInfo(state) << "Found " << state.activeCandidates.size()
0695 << " intersections");
0696
0697 for (const auto& candidate : state.activeCandidates) {
0698 ACTS_VERBOSE("found candidate "
0699 << candidate.intersection.object()->geometryId());
0700 }
0701 }
0702
0703 ++state.activeCandidateIndex;
0704
0705 if (state.endOfCandidates()) {
0706 ACTS_VERBOSE(volInfo(state)
0707 << "No target found, blindly stepping forward.");
0708 state.lastPosition = position;
0709 return NavigationTarget::None();
0710 }
0711
0712 ACTS_VERBOSE(volInfo(state) << "handle active candidates");
0713
0714 ACTS_VERBOSE(volInfo(state)
0715 << (state.activeCandidates.size() - state.activeCandidateIndex)
0716 << " out of " << state.activeCandidates.size()
0717 << " surfaces remain to try.");
0718
0719 const auto& candidate = state.activeCandidate();
0720 const auto& intersection = candidate.intersection;
0721 const Surface& surface = *intersection.object();
0722 BoundaryTolerance boundaryTolerance = candidate.boundaryTolerance;
0723
0724 ACTS_VERBOSE(volInfo(state)
0725 << "Next surface candidate will be " << surface.geometryId());
0726
0727 return NavigationTarget(surface, intersection.index(), boundaryTolerance);
0728 }
0729
0730
0731
0732
0733
0734
0735
0736
0737
0738
0739
0740 bool checkTargetValid(const State& state, const Vector3& position,
0741 const Vector3& direction) const {
0742 (void)state;
0743 (void)position;
0744 (void)direction;
0745
0746 return true;
0747 }
0748
0749
0750
0751
0752
0753
0754
0755
0756
0757 void handleSurfaceReached(State& state, const Vector3& position,
0758 const Vector3& direction,
0759 const Surface& ) const {
0760 if (state.navigationBreak) {
0761 return;
0762 }
0763
0764 ACTS_VERBOSE(volInfo(state) << "handleSurfaceReached");
0765
0766 assert(state.currentSurface == nullptr && "Current surface must be reset.");
0767
0768 if (state.endOfCandidates()) {
0769 ACTS_VERBOSE(volInfo(state) << "No active candidate set.");
0770 return;
0771 }
0772
0773 std::vector<detail::IntersectedNavigationObject> hitCandidates;
0774
0775 while (!state.endOfCandidates()) {
0776 const auto& candidate = state.activeCandidate();
0777 const auto& intersection = candidate.intersection;
0778 const Surface& surface = *intersection.object();
0779 BoundaryTolerance boundaryTolerance = candidate.boundaryTolerance;
0780
0781
0782 IntersectionStatus surfaceStatus =
0783 surface
0784 .intersect(state.options.geoContext, position, direction,
0785 boundaryTolerance,
0786 state.options.surfaceTolerance)[intersection.index()]
0787 .status();
0788
0789 if (surfaceStatus != IntersectionStatus::onSurface) {
0790 break;
0791 }
0792
0793
0794 boundaryTolerance = BoundaryTolerance::None();
0795 surfaceStatus =
0796 surface
0797 .intersect(state.options.geoContext, position, direction,
0798 boundaryTolerance,
0799 state.options.surfaceTolerance)[intersection.index()]
0800 .status();
0801
0802 if (surfaceStatus == IntersectionStatus::onSurface) {
0803 hitCandidates.emplace_back(candidate);
0804 }
0805
0806 ++state.activeCandidateIndex;
0807 ACTS_VERBOSE("skip candidate " << surface.geometryId());
0808 }
0809
0810
0811 --state.activeCandidateIndex;
0812
0813 ACTS_VERBOSE(volInfo(state)
0814 << "Found " << hitCandidates.size()
0815 << " intersections on surface with bounds check.");
0816
0817 if (hitCandidates.empty()) {
0818 ACTS_VERBOSE(volInfo(state)
0819 << "Surface successfully hit, but outside bounds.");
0820 return;
0821 }
0822
0823 if (hitCandidates.size() > 1) {
0824 ACTS_VERBOSE(volInfo(state)
0825 << "Only using first intersection within bounds.");
0826 }
0827
0828
0829 const auto& candidate = hitCandidates.front();
0830 const auto& intersection = candidate.intersection;
0831 const Surface& surface = *intersection.object();
0832
0833 ACTS_VERBOSE(volInfo(state) << "Surface successfully hit, storing it.");
0834 state.currentSurface = &surface;
0835
0836 if (state.currentSurface != nullptr) {
0837 ACTS_VERBOSE(volInfo(state) << "Current surface set to surface "
0838 << surface.geometryId());
0839 }
0840
0841 if (candidate.template checkType<Surface>()) {
0842 ACTS_VERBOSE(volInfo(state) << "This is a surface");
0843 } else if (candidate.template checkType<Layer>()) {
0844 ACTS_VERBOSE(volInfo(state) << "This is a layer");
0845 } else if (candidate.template checkType<BoundarySurface>()) {
0846 ACTS_VERBOSE(volInfo(state)
0847 << "This is a boundary. Reinitialize navigation");
0848
0849 const auto& boundary = *candidate.template object<BoundarySurface>();
0850
0851 state.currentVolume = boundary.attachedVolume(state.options.geoContext,
0852 position, direction);
0853
0854 ACTS_VERBOSE(volInfo(state) << "Switched volume");
0855
0856 reinitializeCandidates(state);
0857 } else {
0858 ACTS_ERROR(volInfo(state) << "Unknown intersection type");
0859 }
0860 }
0861
0862 private:
0863
0864 void reinitializeCandidates(State& state) const {
0865 state.navigationCandidates.clear();
0866 state.activeCandidates.clear();
0867 state.activeCandidateIndex = -1;
0868
0869 initializeVolumeCandidates(state);
0870 }
0871 };
0872
0873 }