File indexing completed on 2025-08-05 08:09:19
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Units.hpp"
0012 #include "Acts/Geometry/BoundarySurfaceT.hpp"
0013 #include "Acts/Geometry/GeometryIdentifier.hpp"
0014 #include "Acts/Geometry/Layer.hpp"
0015 #include "Acts/Geometry/TrackingGeometry.hpp"
0016 #include "Acts/Geometry/TrackingVolume.hpp"
0017 #include "Acts/Propagator/ConstrainedStep.hpp"
0018 #include "Acts/Surfaces/Surface.hpp"
0019 #include "Acts/Utilities/Logger.hpp"
0020 #include "Acts/Utilities/StringHelpers.hpp"
0021
0022 #include <iomanip>
0023 #include <iterator>
0024 #include <sstream>
0025 #include <string>
0026
0027 #include <boost/container/small_vector.hpp>
0028
0029 namespace Acts {
0030
0031
0032
0033
0034
0035
0036 template <typename object_t>
0037 struct NavigationOptions {
0038
0039 BoundaryCheck boundaryCheck = BoundaryCheck(true);
0040
0041
0042
0043 bool resolveSensitive = true;
0044
0045 bool resolveMaterial = true;
0046
0047 bool resolvePassive = false;
0048
0049
0050 const object_t* startObject = nullptr;
0051
0052 const object_t* endObject = nullptr;
0053
0054
0055 std::vector<GeometryIdentifier> externalSurfaces = {};
0056
0057
0058 double nearLimit = 0;
0059
0060 double farLimit = std::numeric_limits<double>::max();
0061
0062
0063 bool forceIntersectBoundaries = false;
0064 };
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083 class Navigator {
0084 public:
0085 using Surfaces = std::vector<const Surface*>;
0086
0087 using NavigationSurfaces =
0088 boost::container::small_vector<SurfaceIntersection, 10>;
0089
0090 using NavigationLayers =
0091 boost::container::small_vector<LayerIntersection, 10>;
0092
0093 using NavigationBoundaries =
0094 boost::container::small_vector<BoundaryIntersection, 4>;
0095
0096 using ExternalSurfaces = std::multimap<uint64_t, GeometryIdentifier>;
0097
0098
0099 enum struct Stage : int {
0100 undefined = 0,
0101 surfaceTarget = 1,
0102 layerTarget = 2,
0103 boundaryTarget = 3
0104 };
0105
0106 struct Config {
0107
0108 std::shared_ptr<const TrackingGeometry> trackingGeometry{nullptr};
0109
0110
0111 bool resolveSensitive = true;
0112
0113 bool resolveMaterial = true;
0114
0115 bool resolvePassive = false;
0116 };
0117
0118
0119
0120
0121
0122 struct State {
0123
0124
0125 NavigationSurfaces navSurfaces = {};
0126
0127 std::size_t navSurfaceIndex = navSurfaces.size();
0128
0129
0130
0131 NavigationLayers navLayers = {};
0132
0133 std::size_t navLayerIndex = navLayers.size();
0134
0135
0136
0137 NavigationBoundaries navBoundaries = {};
0138
0139 std::size_t navBoundaryIndex = navBoundaries.size();
0140
0141 auto navSurface() const { return navSurfaces.at(navSurfaceIndex); }
0142 auto navLayer() const { return navLayers.at(navLayerIndex); }
0143 auto navBoundary() const { return navBoundaries.at(navBoundaryIndex); }
0144
0145
0146 ExternalSurfaces externalSurfaces = {};
0147
0148
0149 const TrackingVolume* worldVolume = nullptr;
0150
0151
0152 const TrackingVolume* startVolume = nullptr;
0153
0154 const Layer* startLayer = nullptr;
0155
0156 const Surface* startSurface = nullptr;
0157
0158 const Surface* currentSurface = nullptr;
0159
0160 const TrackingVolume* currentVolume = nullptr;
0161
0162 const TrackingVolume* targetVolume = nullptr;
0163
0164 const Layer* targetLayer = nullptr;
0165
0166 const Surface* targetSurface = nullptr;
0167
0168
0169 bool startLayerResolved = false;
0170
0171 bool targetReached = false;
0172
0173
0174 bool lastHierarchySurfaceReached = false;
0175
0176 bool navigationBreak = false;
0177
0178 Stage navigationStage = Stage::undefined;
0179
0180 bool forceIntersectBoundaries = false;
0181 };
0182
0183
0184
0185
0186
0187 explicit Navigator(Config cfg,
0188 std::shared_ptr<const Logger> _logger =
0189 getDefaultLogger("Navigator", Logging::Level::INFO))
0190 : m_cfg{std::move(cfg)}, m_logger{std::move(_logger)} {}
0191
0192 State makeState(const Surface* startSurface,
0193 const Surface* targetSurface) const {
0194 State result;
0195 result.startSurface = startSurface;
0196 result.targetSurface = targetSurface;
0197 return result;
0198 }
0199
0200 const Surface* currentSurface(const State& state) const {
0201 return state.currentSurface;
0202 }
0203
0204 const TrackingVolume* currentVolume(const State& state) const {
0205 return state.currentVolume;
0206 }
0207
0208 const IVolumeMaterial* currentVolumeMaterial(const State& state) const {
0209 if (state.currentVolume == nullptr) {
0210 return nullptr;
0211 }
0212 return state.currentVolume->volumeMaterial();
0213 }
0214
0215 const Surface* startSurface(const State& state) const {
0216 return state.startSurface;
0217 }
0218
0219 const Surface* targetSurface(const State& state) const {
0220 return state.targetSurface;
0221 }
0222
0223 bool targetReached(const State& state) const { return state.targetReached; }
0224
0225 bool endOfWorldReached(const State& state) const {
0226 return state.currentVolume == nullptr;
0227 }
0228
0229 bool navigationBreak(const State& state) const {
0230 return state.navigationBreak;
0231 }
0232
0233 void currentSurface(State& state, const Surface* surface) const {
0234 state.currentSurface = surface;
0235 }
0236
0237 void targetReached(State& state, bool targetReached) const {
0238 state.targetReached = targetReached;
0239 }
0240
0241 void navigationBreak(State& state, bool navigationBreak) const {
0242 state.navigationBreak = navigationBreak;
0243 }
0244
0245 void insertExternalSurface(State& state, GeometryIdentifier geoid) const {
0246 state.externalSurfaces.insert(
0247 std::pair<uint64_t, GeometryIdentifier>(geoid.layer(), geoid));
0248 }
0249
0250
0251
0252
0253
0254
0255
0256
0257 template <typename propagator_state_t, typename stepper_t>
0258 void initialize(propagator_state_t& state, const stepper_t& stepper) const {
0259
0260 ACTS_VERBOSE(volInfo(state) << "Initialization.");
0261
0262
0263 if (!state.navigation.worldVolume) {
0264 state.navigation.worldVolume =
0265 m_cfg.trackingGeometry->highestTrackingVolume();
0266 }
0267
0268
0269
0270
0271
0272 state.navigation.currentSurface = state.navigation.startSurface;
0273 if (state.navigation.currentSurface) {
0274 ACTS_VERBOSE(volInfo(state)
0275 << "Current surface set to start surface "
0276 << state.navigation.currentSurface->geometryId());
0277 }
0278
0279
0280
0281
0282 if (state.navigation.startSurface &&
0283 state.navigation.startSurface->associatedLayer()) {
0284 ACTS_VERBOSE(
0285 volInfo(state)
0286 << "Fast start initialization through association from Surface.");
0287
0288 state.navigation.startLayer =
0289 state.navigation.startSurface->associatedLayer();
0290 state.navigation.startVolume =
0291 state.navigation.startLayer->trackingVolume();
0292
0293 state.navigation.currentVolume = state.navigation.startVolume;
0294 } else if (state.navigation.startVolume) {
0295 ACTS_VERBOSE(
0296 volInfo(state)
0297 << "Fast start initialization through association from Volume.");
0298 state.navigation.startLayer =
0299 state.navigation.startVolume->associatedLayer(
0300 state.geoContext, stepper.position(state.stepping));
0301
0302 state.navigation.currentVolume = state.navigation.startVolume;
0303 } else {
0304 ACTS_VERBOSE(volInfo(state)
0305 << "Slow start initialization through search.");
0306
0307 ACTS_VERBOSE(volInfo(state)
0308 << "Starting from position "
0309 << toString(stepper.position(state.stepping))
0310 << " and direction "
0311 << toString(stepper.direction(state.stepping)));
0312 state.navigation.startVolume =
0313 m_cfg.trackingGeometry->lowestTrackingVolume(
0314 state.geoContext, stepper.position(state.stepping));
0315 state.navigation.startLayer =
0316 state.navigation.startVolume
0317 ? state.navigation.startVolume->associatedLayer(
0318 state.geoContext, stepper.position(state.stepping))
0319 : nullptr;
0320
0321 state.navigation.currentVolume = state.navigation.startVolume;
0322 if (state.navigation.startVolume) {
0323 ACTS_VERBOSE(volInfo(state) << "Start volume resolved.");
0324 }
0325 }
0326 }
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340 template <typename propagator_state_t, typename stepper_t>
0341 void preStep(propagator_state_t& state, const stepper_t& stepper) const {
0342
0343 if (inactive(state, stepper)) {
0344 return;
0345 }
0346
0347
0348 ACTS_VERBOSE(volInfo(state) << "Entering navigator::preStep.");
0349
0350
0351 if (state.navigation.targetSurface && !state.navigation.targetVolume) {
0352
0353 initializeTarget(state, stepper);
0354 }
0355
0356 if (state.navigation.navigationStage <= Stage::surfaceTarget &&
0357 targetSurfaces(state, stepper)) {
0358 ACTS_VERBOSE(volInfo(state) << "Target set to next surface.");
0359 } else if (state.navigation.navigationStage <= Stage::layerTarget &&
0360 targetLayers(state, stepper)) {
0361 ACTS_VERBOSE(volInfo(state) << "Target set to next layer.");
0362 } else if (targetBoundaries(state, stepper)) {
0363 ACTS_VERBOSE(volInfo(state) << "Target set to next boundary.");
0364 } else {
0365 ACTS_VERBOSE(volInfo(state)
0366 << "No further navigation action, proceed to target.");
0367
0368 state.navigation.navigationBreak = true;
0369 stepper.releaseStepSize(state.stepping, ConstrainedStep::actor);
0370 }
0371
0372
0373 state.navigation.currentSurface = nullptr;
0374 }
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395 template <typename propagator_state_t, typename stepper_t>
0396 void postStep(propagator_state_t& state, const stepper_t& stepper) const {
0397
0398 if (inactive(state, stepper)) {
0399 return;
0400 }
0401
0402
0403 state.navigation.navigationStage = Stage::undefined;
0404
0405
0406 ACTS_VERBOSE(volInfo(state) << "Entering navigator::postStep.");
0407
0408
0409 state.navigation.currentSurface = nullptr;
0410
0411
0412
0413 if (surfaceStatus(state, stepper, state.navigation.navSurfaces,
0414 state.navigation.navSurfaceIndex)) {
0415 ACTS_VERBOSE(volInfo(state) << "Post step: in surface handling.");
0416 if (state.navigation.currentSurface) {
0417 ACTS_VERBOSE(volInfo(state)
0418 << "On surface: switch forward or release.");
0419 if (++state.navigation.navSurfaceIndex ==
0420 state.navigation.navSurfaces.size()) {
0421
0422 if (!state.navigation.navLayers.empty()) {
0423 ++state.navigation.navLayerIndex;
0424 } else if (state.navigation.startLayer != nullptr &&
0425 state.navigation.currentSurface->associatedLayer() ==
0426 state.navigation.startLayer) {
0427
0428 state.navigation.navigationStage = Stage::layerTarget;
0429 return;
0430 } else {
0431
0432 state.navigation.navigationStage = Stage::boundaryTarget;
0433 return;
0434 }
0435 }
0436 }
0437
0438 state.navigation.navigationStage = Stage::surfaceTarget;
0439 ACTS_VERBOSE(volInfo(state) << "Staying focussed on surface.");
0440
0441 } else if (surfaceStatus(state, stepper, state.navigation.navLayers,
0442 state.navigation.navLayerIndex)) {
0443 ACTS_VERBOSE(volInfo(state) << "Post step: in layer handling.");
0444 if (state.navigation.currentSurface != nullptr) {
0445 ACTS_VERBOSE(volInfo(state) << "On layer: update layer information.");
0446 if (resolveSurfaces(state, stepper)) {
0447
0448 state.navigation.navigationStage = Stage::surfaceTarget;
0449 return;
0450 }
0451 } else {
0452
0453 state.navigation.navigationStage = Stage::layerTarget;
0454 ACTS_VERBOSE(volInfo(state) << "Staying focussed on layer.");
0455 }
0456
0457 } else if (surfaceStatus(state, stepper, state.navigation.navBoundaries,
0458 state.navigation.navBoundaryIndex)) {
0459 ACTS_VERBOSE(volInfo(state) << "Post step: in boundary handling.");
0460
0461
0462 if (state.navigation.currentSurface != nullptr) {
0463
0464 ACTS_VERBOSE(volInfo(state)
0465 << "On boundary: update volume information.");
0466
0467 state.navigation.navSurfaces.clear();
0468 state.navigation.navSurfaceIndex = state.navigation.navSurfaces.size();
0469 state.navigation.navLayers.clear();
0470 state.navigation.navLayerIndex = state.navigation.navLayers.size();
0471 state.navigation.lastHierarchySurfaceReached = false;
0472
0473
0474 auto boundary = state.navigation.navBoundary().second;
0475 state.navigation.currentVolume = boundary->attachedVolume(
0476 state.geoContext, stepper.position(state.stepping),
0477 state.options.direction * stepper.direction(state.stepping));
0478
0479 if (!state.navigation.currentVolume) {
0480 ACTS_VERBOSE(
0481 volInfo(state)
0482 << "No more volume to progress to, stopping navigation.");
0483
0484 state.navigation.navigationBreak = true;
0485 return;
0486 } else {
0487 ACTS_VERBOSE(volInfo(state) << "Volume updated.");
0488
0489 state.navigation.navBoundaries.clear();
0490 state.navigation.navBoundaryIndex =
0491 state.navigation.navBoundaries.size();
0492 }
0493 } else {
0494
0495 state.navigation.navigationStage = Stage::boundaryTarget;
0496 ACTS_VERBOSE(volInfo(state) << "Staying focussed on boundary.");
0497 }
0498 } else if (state.navigation.currentVolume ==
0499 state.navigation.targetVolume) {
0500 if (state.navigation.targetSurface == nullptr) {
0501 ACTS_WARNING(volInfo(state)
0502 << "No further navigation action, proceed to "
0503 "target. This is very likely an error");
0504 } else {
0505 ACTS_VERBOSE(volInfo(state)
0506 << "No further navigation action, proceed to target.");
0507 }
0508
0509 state.navigation.navigationBreak = true;
0510 } else {
0511 ACTS_VERBOSE(volInfo(state)
0512 << "Status could not be determined - good luck.");
0513 }
0514 }
0515
0516 private:
0517 const SurfaceIntersection& candidateIntersection(
0518 const NavigationSurfaces& surfaces, std::size_t index) const {
0519 return surfaces.at(index);
0520 }
0521 const SurfaceIntersection& candidateIntersection(
0522 const NavigationLayers& surfaces, std::size_t index) const {
0523 return surfaces.at(index).first;
0524 }
0525 const SurfaceIntersection& candidateIntersection(
0526 const NavigationBoundaries& surfaces, std::size_t index) const {
0527 return surfaces.at(index).first;
0528 }
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545 template <typename propagator_state_t, typename stepper_t,
0546 typename navigation_surfaces_t>
0547 bool surfaceStatus(propagator_state_t& state, const stepper_t& stepper,
0548 const navigation_surfaces_t& navSurfaces,
0549 std::size_t navIndex) const {
0550
0551 if (navSurfaces.empty() || navIndex == navSurfaces.size()) {
0552 return false;
0553 }
0554 const auto& intersection = candidateIntersection(navSurfaces, navIndex);
0555
0556 const auto* surface = intersection.object();
0557
0558
0559
0560 auto surfaceStatus = stepper.updateSurfaceStatus(
0561 state.stepping, *surface, intersection.index(), state.options.direction,
0562 BoundaryCheck(true), state.options.surfaceTolerance, logger());
0563 if (surfaceStatus == Intersection3D::Status::onSurface) {
0564 ACTS_VERBOSE(volInfo(state)
0565 << "Status Surface successfully hit, storing it.");
0566
0567 state.navigation.currentSurface = surface;
0568 if (state.navigation.currentSurface) {
0569 ACTS_VERBOSE(volInfo(state)
0570 << "Current surface set to surface "
0571 << state.navigation.currentSurface->geometryId());
0572 }
0573 }
0574
0575 return true;
0576 }
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590 template <typename propagator_state_t, typename stepper_t>
0591 bool targetSurfaces(propagator_state_t& state,
0592 const stepper_t& stepper) const {
0593 if (state.navigation.navigationBreak) {
0594 return false;
0595 }
0596
0597 if (state.navigation.startLayer && !state.navigation.startLayerResolved) {
0598 ACTS_VERBOSE(volInfo(state) << "Start layer to be resolved.");
0599
0600 state.navigation.startLayerResolved = true;
0601 bool startResolved =
0602 resolveSurfaces(state, stepper, state.navigation.startLayer);
0603 if (!startResolved &&
0604 state.navigation.startLayer == state.navigation.targetLayer) {
0605 ACTS_VERBOSE(volInfo(state)
0606 << "Start is target layer, nothing left to do.");
0607
0608 state.navigation.navigationBreak = true;
0609 stepper.releaseStepSize(state.stepping, ConstrainedStep::actor);
0610 }
0611 return startResolved;
0612 }
0613
0614
0615
0616 if (state.navigation.navSurfaces.empty() ||
0617 state.navigation.navSurfaceIndex ==
0618 state.navigation.navSurfaces.size()) {
0619 ACTS_VERBOSE(volInfo(state)
0620 << "No surfaces present, target at layer first.");
0621 return false;
0622 }
0623 auto layerID = state.navigation.navSurface().object()->geometryId().layer();
0624 std::pair<ExternalSurfaces::iterator, ExternalSurfaces::iterator>
0625 externalSurfaceRange =
0626 state.navigation.externalSurfaces.equal_range(layerID);
0627
0628 while (state.navigation.navSurfaceIndex !=
0629 state.navigation.navSurfaces.size()) {
0630
0631 ACTS_VERBOSE(volInfo(state)
0632 << (state.navigation.navSurfaces.size() -
0633 state.navigation.navSurfaceIndex)
0634 << " out of " << state.navigation.navSurfaces.size()
0635 << " surfaces remain to try.");
0636 const auto& intersection = state.navigation.navSurface();
0637
0638 const auto* surface = intersection.object();
0639
0640 ACTS_VERBOSE(volInfo(state) << "Next surface candidate will be "
0641 << surface->geometryId());
0642
0643 bool boundaryCheck = true;
0644 for (auto it = externalSurfaceRange.first;
0645 it != externalSurfaceRange.second; it++) {
0646 if (surface->geometryId() == it->second) {
0647 boundaryCheck = false;
0648 break;
0649 }
0650 }
0651 auto surfaceStatus = stepper.updateSurfaceStatus(
0652 state.stepping, *surface, intersection.index(),
0653 state.options.direction, BoundaryCheck(boundaryCheck),
0654 state.options.surfaceTolerance, logger());
0655 if (surfaceStatus == Intersection3D::Status::reachable) {
0656 ACTS_VERBOSE(volInfo(state)
0657 << "Surface reachable, step size updated to "
0658 << stepper.outputStepSize(state.stepping));
0659 return true;
0660 }
0661 ++state.navigation.navSurfaceIndex;
0662 continue;
0663 }
0664
0665
0666 if (state.navigation.navSurfaceIndex ==
0667 state.navigation.navSurfaces.size()) {
0668
0669 state.navigation.navSurfaces.clear();
0670 state.navigation.navSurfaceIndex = state.navigation.navSurfaces.size();
0671
0672 if (state.navigation.navLayerIndex != state.navigation.navLayers.size()) {
0673 ACTS_VERBOSE(volInfo(state)
0674 << "Last surface on layer reached, switching layer.");
0675
0676 ++state.navigation.navLayerIndex;
0677 } else {
0678 ACTS_VERBOSE(volInfo(state)
0679 << "Last surface on layer reached, and no layer.");
0680
0681 state.navigation.lastHierarchySurfaceReached = true;
0682 state.navigation.navigationBreak =
0683 (state.navigation.currentVolume == state.navigation.targetVolume);
0684 }
0685 }
0686
0687 return false;
0688 }
0689
0690
0691
0692
0693
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708 template <typename propagator_state_t, typename stepper_t>
0709 bool targetLayers(propagator_state_t& state, const stepper_t& stepper) const {
0710 using namespace UnitLiterals;
0711
0712 if (state.navigation.navigationBreak ||
0713 state.navigation.lastHierarchySurfaceReached) {
0714 return false;
0715 }
0716
0717
0718 if (state.navigation.navLayers.empty()) {
0719 ACTS_VERBOSE(volInfo(state)
0720 << "No layers present, resolve volume first.");
0721
0722 if (resolveLayers(state, stepper)) {
0723
0724 return true;
0725 }
0726 }
0727
0728 while (state.navigation.navLayerIndex !=
0729 state.navigation.navLayers.size()) {
0730 const auto& intersection = state.navigation.navLayer().first;
0731
0732 const auto* layerSurface = intersection.object();
0733
0734 if (state.navigation.currentSurface == layerSurface) {
0735 ACTS_VERBOSE(volInfo(state) << "We are on a layer, resolve Surfaces.");
0736
0737 if (resolveSurfaces(state, stepper)) {
0738 return true;
0739 } else {
0740
0741 ++state.navigation.navLayerIndex;
0742 continue;
0743 }
0744 }
0745
0746 auto layerStatus = stepper.updateSurfaceStatus(
0747 state.stepping, *layerSurface, intersection.index(),
0748 state.options.direction, BoundaryCheck(true),
0749 state.options.surfaceTolerance, logger());
0750 if (layerStatus == Intersection3D::Status::reachable) {
0751 ACTS_VERBOSE(volInfo(state) << "Layer reachable, step size updated to "
0752 << stepper.outputStepSize(state.stepping));
0753 return true;
0754 }
0755 ACTS_VERBOSE(volInfo(state)
0756 << "Layer intersection not valid, skipping it.");
0757 ++state.navigation.navLayerIndex;
0758 }
0759
0760
0761
0762 if (state.navigation.currentVolume == state.navigation.targetVolume) {
0763 initializeTarget(state, stepper);
0764 }
0765
0766 if (logger().doPrint(Logging::VERBOSE)) {
0767 std::ostringstream os;
0768 os << "Last layer";
0769 if (state.navigation.currentVolume == state.navigation.targetVolume) {
0770 os << " (final volume) done, proceed to target.";
0771 } else {
0772 os << " done, target volume boundary.";
0773 }
0774 logger().log(Logging::VERBOSE, os.str());
0775 }
0776
0777 state.navigation.navigationBreak =
0778 (state.navigation.currentVolume == state.navigation.targetVolume);
0779 return false;
0780 }
0781
0782
0783
0784
0785
0786
0787
0788
0789
0790
0791
0792
0793
0794
0795
0796
0797
0798
0799
0800
0801
0802
0803
0804
0805
0806
0807 template <typename propagator_state_t, typename stepper_t>
0808 bool targetBoundaries(propagator_state_t& state,
0809 const stepper_t& stepper) const {
0810 if (state.navigation.navigationBreak) {
0811 return false;
0812 }
0813
0814 if (!state.navigation.currentVolume) {
0815 ACTS_VERBOSE(volInfo(state)
0816 << "No sufficient information to resolve boundary, "
0817 "stopping navigation.");
0818 stepper.releaseStepSize(state.stepping, ConstrainedStep::actor);
0819 return false;
0820 } else if (state.navigation.currentVolume ==
0821 state.navigation.targetVolume) {
0822 ACTS_VERBOSE(volInfo(state)
0823 << "In target volume: no need to resolve boundary, "
0824 "stopping navigation.");
0825 state.navigation.navigationBreak = true;
0826 stepper.releaseStepSize(state.stepping, ConstrainedStep::actor);
0827 return true;
0828 }
0829
0830
0831 initializeTarget(state, stepper);
0832
0833
0834 auto findBoundaries = [&]() -> bool {
0835
0836 NavigationOptions<Surface> navOpts;
0837
0838 navOpts.startObject = state.navigation.currentSurface;
0839 navOpts.nearLimit = stepper.overstepLimit(state.stepping);
0840 navOpts.farLimit =
0841 stepper.getStepSize(state.stepping, ConstrainedStep::aborter);
0842 navOpts.forceIntersectBoundaries =
0843 state.navigation.forceIntersectBoundaries;
0844
0845 ACTS_VERBOSE(volInfo(state)
0846 << "Try to find boundaries, we are at: "
0847 << stepper.position(state.stepping).transpose() << ", dir: "
0848 << stepper.direction(state.stepping).transpose());
0849
0850
0851 state.navigation.navBoundaries =
0852 state.navigation.currentVolume->compatibleBoundaries(
0853 state.geoContext, stepper.position(state.stepping),
0854 state.options.direction * stepper.direction(state.stepping),
0855 navOpts, logger());
0856
0857 if (logger().doPrint(Logging::VERBOSE)) {
0858 std::ostringstream os;
0859 os << state.navigation.navBoundaries.size();
0860 os << " boundary candidates found at path(s): ";
0861 for (auto& bc : state.navigation.navBoundaries) {
0862 os << bc.first.pathLength() << " ";
0863 }
0864 logger().log(Logging::VERBOSE, os.str());
0865 }
0866
0867 state.navigation.navBoundaryIndex = 0;
0868 if (!state.navigation.navBoundaries.empty()) {
0869
0870 stepper.updateStepSize(state.stepping,
0871 state.navigation.navBoundary().first,
0872 state.options.direction, true);
0873 ACTS_VERBOSE(volInfo(state) << "Navigation stepSize updated to "
0874 << stepper.outputStepSize(state.stepping));
0875 return true;
0876 }
0877 return false;
0878 };
0879
0880
0881 if (state.navigation.navBoundaries.empty() && findBoundaries()) {
0882 return true;
0883 }
0884
0885
0886 while (state.navigation.navBoundaryIndex !=
0887 state.navigation.navBoundaries.size()) {
0888 const auto& intersection = state.navigation.navBoundary().first;
0889
0890 const auto* boundarySurface = intersection.object();
0891
0892 auto boundaryStatus = stepper.updateSurfaceStatus(
0893 state.stepping, *boundarySurface, intersection.index(),
0894 state.options.direction, BoundaryCheck(true),
0895 state.options.surfaceTolerance, logger());
0896 if (boundaryStatus == Intersection3D::Status::reachable) {
0897 ACTS_VERBOSE(volInfo(state)
0898 << "Boundary reachable, step size updated to "
0899 << stepper.outputStepSize(state.stepping));
0900 return true;
0901 } else {
0902 ACTS_VERBOSE("Boundary "
0903 << (state.navigation.navBoundaries.size() -
0904 state.navigation.navBoundaryIndex)
0905 << " out of " << state.navigation.navBoundaries.size()
0906 << " not reachable anymore, switching to next.");
0907 ACTS_VERBOSE("Targeted boundary surface was: \n"
0908 << std::tie(*boundarySurface, state.geoContext));
0909 }
0910
0911 ++state.navigation.navBoundaryIndex;
0912 }
0913
0914 state.navigation.navBoundaries.clear();
0915 ACTS_VERBOSE(volInfo(state) << "Boundary navigation lost, re-targetting.");
0916 state.navigation.forceIntersectBoundaries = true;
0917 if (findBoundaries()) {
0918
0919 state.navigation.forceIntersectBoundaries = false;
0920 return true;
0921 }
0922
0923
0924 return false;
0925 }
0926
0927
0928
0929
0930
0931
0932
0933
0934
0935
0936
0937
0938
0939
0940
0941
0942
0943
0944 template <typename propagator_state_t, typename stepper_t>
0945 void initializeTarget(propagator_state_t& state,
0946 const stepper_t& stepper) const {
0947 if (state.navigation.targetVolume && state.stepping.pathAccumulated == 0.) {
0948 ACTS_VERBOSE(volInfo(state)
0949 << "Re-initialzing cancelled as it is the first step.");
0950 return;
0951 }
0952
0953 if (state.navigation.targetSurface &&
0954 state.navigation.targetSurface->associatedLayer() &&
0955 !state.navigation.targetVolume) {
0956 ACTS_VERBOSE(volInfo(state)
0957 << "Fast target initialization through association.");
0958 ACTS_VERBOSE(volInfo(state)
0959 << "Target surface set to "
0960 << state.navigation.targetSurface->geometryId());
0961 state.navigation.targetLayer =
0962 state.navigation.targetSurface->associatedLayer();
0963 state.navigation.targetVolume =
0964 state.navigation.targetLayer->trackingVolume();
0965 } else if (state.navigation.targetSurface) {
0966
0967 if (state.navigation.targetVolume) {
0968 ACTS_VERBOSE(volInfo(state)
0969 << "Re-initialization of target volume triggered.");
0970 }
0971
0972
0973 auto targetIntersection =
0974 state.navigation.targetSurface
0975 ->intersect(
0976 state.geoContext, stepper.position(state.stepping),
0977 state.options.direction * stepper.direction(state.stepping),
0978 BoundaryCheck(false), state.options.surfaceTolerance)
0979 .closest();
0980 if (targetIntersection) {
0981 ACTS_VERBOSE(volInfo(state)
0982 << "Target estimate position ("
0983 << targetIntersection.position().x() << ", "
0984 << targetIntersection.position().y() << ", "
0985 << targetIntersection.position().z() << ")");
0986
0987 auto tPosition = targetIntersection.position();
0988 state.navigation.targetVolume =
0989 m_cfg.trackingGeometry->lowestTrackingVolume(state.geoContext,
0990 tPosition);
0991 state.navigation.targetLayer =
0992 state.navigation.targetVolume
0993 ? state.navigation.targetVolume->associatedLayer(
0994 state.geoContext, tPosition)
0995 : nullptr;
0996 if (state.navigation.targetVolume) {
0997 ACTS_VERBOSE(volInfo(state)
0998 << "Target volume estimated : "
0999 << state.navigation.targetVolume->volumeName());
1000 }
1001 }
1002 }
1003 }
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015 template <typename propagator_state_t, typename stepper_t>
1016 bool resolveSurfaces(propagator_state_t& state, const stepper_t& stepper,
1017 const Layer* cLayer = nullptr) const {
1018
1019 auto layerSurface = cLayer ? state.navigation.startSurface
1020 : state.navigation.navLayer().first.object();
1021 auto navLayer = cLayer ? cLayer : state.navigation.navLayer().second;
1022
1023 bool onStart = (navLayer == state.navigation.startLayer);
1024 auto startSurface = onStart ? state.navigation.startSurface : layerSurface;
1025
1026 NavigationOptions<Surface> navOpts;
1027 navOpts.resolveSensitive = m_cfg.resolveSensitive;
1028 navOpts.resolveMaterial = m_cfg.resolveMaterial;
1029 navOpts.resolvePassive = m_cfg.resolvePassive;
1030 navOpts.startObject = startSurface;
1031 navOpts.endObject = state.navigation.targetSurface;
1032
1033 std::vector<GeometryIdentifier> externalSurfaces;
1034 if (!state.navigation.externalSurfaces.empty()) {
1035 auto layerID = layerSurface->geometryId().layer();
1036 auto externalSurfaceRange =
1037 state.navigation.externalSurfaces.equal_range(layerID);
1038 navOpts.externalSurfaces.reserve(
1039 state.navigation.externalSurfaces.count(layerID));
1040 for (auto itSurface = externalSurfaceRange.first;
1041 itSurface != externalSurfaceRange.second; itSurface++) {
1042 navOpts.externalSurfaces.push_back(itSurface->second);
1043 }
1044 }
1045
1046 navOpts.nearLimit = (cLayer != nullptr)
1047 ? state.options.surfaceTolerance
1048 : stepper.overstepLimit(state.stepping);
1049
1050 navOpts.farLimit =
1051 stepper.getStepSize(state.stepping, ConstrainedStep::aborter);
1052
1053
1054 state.navigation.navSurfaces = navLayer->compatibleSurfaces(
1055 state.geoContext, stepper.position(state.stepping),
1056 state.options.direction * stepper.direction(state.stepping), navOpts);
1057
1058 if (!state.navigation.navSurfaces.empty()) {
1059 if (logger().doPrint(Logging::VERBOSE)) {
1060 std::ostringstream os;
1061 os << state.navigation.navSurfaces.size();
1062 os << " surface candidates found at path(s): ";
1063 for (auto& sfc : state.navigation.navSurfaces) {
1064 os << sfc.pathLength() << " ";
1065 }
1066 logger().log(Logging::VERBOSE, os.str());
1067 }
1068
1069
1070 state.navigation.navSurfaceIndex = 0;
1071
1072 stepper.updateStepSize(state.stepping, state.navigation.navSurface(),
1073 state.options.direction, true);
1074 ACTS_VERBOSE(volInfo(state) << "Navigation stepSize updated to "
1075 << stepper.outputStepSize(state.stepping));
1076 return true;
1077 }
1078 state.navigation.navSurfaceIndex = state.navigation.navSurfaces.size();
1079 ACTS_VERBOSE(volInfo(state) << "No surface candidates found.");
1080 return false;
1081 }
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097 template <typename propagator_state_t, typename stepper_t>
1098 bool resolveLayers(propagator_state_t& state,
1099 const stepper_t& stepper) const {
1100 ACTS_VERBOSE(volInfo(state) << "Searching for compatible layers.");
1101
1102
1103 auto startLayer =
1104 (state.navigation.currentVolume == state.navigation.startVolume)
1105 ? state.navigation.startLayer
1106 : nullptr;
1107
1108
1109 NavigationOptions<Layer> navOpts;
1110 navOpts.resolveSensitive = m_cfg.resolveSensitive;
1111 navOpts.resolveMaterial = m_cfg.resolveMaterial;
1112 navOpts.resolvePassive = m_cfg.resolvePassive;
1113 navOpts.startObject = startLayer;
1114 navOpts.nearLimit = stepper.overstepLimit(state.stepping);
1115 navOpts.farLimit =
1116 stepper.getStepSize(state.stepping, ConstrainedStep::aborter);
1117
1118 state.navigation.navLayers =
1119 state.navigation.currentVolume->compatibleLayers(
1120 state.geoContext, stepper.position(state.stepping),
1121 state.options.direction * stepper.direction(state.stepping),
1122 navOpts);
1123
1124
1125 if (!state.navigation.navLayers.empty()) {
1126
1127 if (logger().doPrint(Logging::VERBOSE)) {
1128 std::ostringstream os;
1129 os << state.navigation.navLayers.size();
1130 os << " layer candidates found at path(s): ";
1131 for (auto& lc : state.navigation.navLayers) {
1132 os << lc.first.pathLength() << " ";
1133 }
1134 logger().log(Logging::VERBOSE, os.str());
1135 }
1136
1137 state.navigation.navLayerIndex = 0;
1138
1139 if (state.navigation.startLayer &&
1140 state.navigation.navLayer().second != state.navigation.startLayer) {
1141 ACTS_VERBOSE(volInfo(state) << "Target at layer.");
1142
1143 stepper.updateStepSize(state.stepping,
1144 state.navigation.navLayer().first,
1145 state.options.direction, true);
1146 ACTS_VERBOSE(volInfo(state) << "Navigation stepSize updated to "
1147 << stepper.outputStepSize(state.stepping));
1148 return true;
1149 }
1150 }
1151
1152
1153 state.navigation.navLayerIndex = state.navigation.navLayers.size();
1154
1155
1156 ACTS_VERBOSE(volInfo(state) << "No compatible layer candidates found.");
1157
1158 stepper.releaseStepSize(state.stepping, ConstrainedStep::actor);
1159 return false;
1160 }
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174 template <typename propagator_state_t, typename stepper_t>
1175 bool inactive(propagator_state_t& state, const stepper_t& stepper) const {
1176
1177 if (!m_cfg.trackingGeometry) {
1178 return true;
1179 }
1180
1181 if (!m_cfg.resolveSensitive && !m_cfg.resolveMaterial &&
1182 !m_cfg.resolvePassive) {
1183 return true;
1184 }
1185
1186
1187
1188
1189
1190
1191 if (state.navigation.navigationBreak) {
1192
1193 if (state.navigation.targetReached || !state.navigation.targetSurface) {
1194 return true;
1195 }
1196
1197 auto targetStatus = stepper.updateSurfaceStatus(
1198 state.stepping, *state.navigation.targetSurface, 0,
1199 state.options.direction, BoundaryCheck(true),
1200 state.options.surfaceTolerance, logger());
1201
1202 if (targetStatus == Intersection3D::Status::onSurface) {
1203
1204 state.navigation.currentSurface = state.navigation.targetSurface;
1205 ACTS_VERBOSE(volInfo(state)
1206 << volInfo(state)
1207 << "Current surface set to target surface "
1208 << state.navigation.currentSurface->geometryId());
1209 return true;
1210 }
1211 }
1212 return false;
1213 }
1214
1215 private:
1216 template <typename propagator_state_t>
1217 std::string volInfo(const propagator_state_t& state) const {
1218 return (state.navigation.currentVolume
1219 ? state.navigation.currentVolume->volumeName()
1220 : "No Volume") +
1221 " | ";
1222 }
1223
1224 const Logger& logger() const { return *m_logger; }
1225
1226 Config m_cfg;
1227
1228 std::shared_ptr<const Logger> m_logger;
1229 };
1230
1231 }