26 #include <boost/algorithm/string.hpp>
30 using namespace Acts::UnitLiterals;
37 template <
typename object_t>
47 bool resolveSensitive =
true;
49 bool resolveMaterial =
true;
51 bool resolvePassive =
false;
54 const object_t* startObject =
nullptr;
56 const object_t* endObject =
nullptr;
67 double overstepLimit = -1_um;
77 bool resolves =
true,
bool resolvem =
true,
78 bool resolvep =
false,
const object_t* sobject =
nullptr,
79 const object_t* eobject =
nullptr)
82 resolveSensitive(resolves),
83 resolveMaterial(resolvem),
84 resolvePassive(resolvep),
87 pathLimit(ndir * std::numeric_limits<double>::
max()),
88 overstepLimit(-1_um) {}
152 bool resolveSensitive =
true;
154 bool resolveMaterial =
true;
156 bool resolvePassive =
false;
206 bool startLayerResolved =
false;
208 bool targetReached =
false;
210 bool navigationBreak =
false;
234 template <
typename propagator_state_t,
typename stepper_t>
236 const auto& logger = state.options.logger;
239 if (inactive(state, stepper)) {
247 ACTS_VERBOSE(volInfo(state) <<
"Entering navigator::status.");
250 if (not state.navigation.startVolume or not state.navigation.startSurface) {
252 initialize(state, stepper);
257 state.navigation.currentSurface =
nullptr;
261 if (status(state, stepper, state.navigation.navSurfaces,
262 state.navigation.navSurfaceIter)) {
263 ACTS_VERBOSE(volInfo(state) <<
"Status: in surface handling.");
264 if (state.navigation.currentSurface) {
266 <<
"On surface: switch forward or release.");
267 if (++state.navigation.navSurfaceIter ==
268 state.navigation.navSurfaces.end()) {
270 if (!state.navigation.navLayers.empty()) {
271 ++state.navigation.navLayerIter;
274 state.navigation.navigationStage = Stage::boundaryTarget;
280 state.navigation.navigationStage = Stage::surfaceTarget;
281 ACTS_VERBOSE(volInfo(state) <<
"Staying focussed on surface.");
283 }
else if (status(state, stepper, state.navigation.navLayers,
284 state.navigation.navLayerIter)) {
285 ACTS_VERBOSE(volInfo(state) <<
"Status: in layer handling.");
286 if (state.navigation.currentSurface !=
nullptr) {
287 ACTS_VERBOSE(volInfo(state) <<
"On layer: update layer information.");
288 if (resolveSurfaces(state, stepper)) {
290 state.navigation.navigationStage = Stage::surfaceTarget;
295 state.navigation.navigationStage = Stage::layerTarget;
296 ACTS_VERBOSE(volInfo(state) <<
"Staying focussed on layer.");
299 }
else if (status(state, stepper, state.navigation.navBoundaries,
300 state.navigation.navBoundaryIter)) {
301 ACTS_VERBOSE(volInfo(state) <<
"Status: in boundary handling.");
304 if (state.navigation.currentSurface !=
nullptr) {
307 <<
"On boundary: update volume information.");
309 state.navigation.navSurfaces.clear();
310 state.navigation.navSurfaceIter = state.navigation.navSurfaces.end();
311 state.navigation.navLayers.clear();
312 state.navigation.navLayerIter = state.navigation.navLayers.end();
315 auto boundary = state.navigation.navBoundaryIter->object;
316 state.navigation.currentVolume = boundary->attachedVolume(
317 state.geoContext, stepper.position(state.stepping),
318 stepper.direction(state.stepping), state.stepping.navDir);
320 if (!state.navigation.currentVolume) {
323 <<
"No more volume to progress to, stopping navigation.");
325 state.navigation.navigationBreak =
true;
326 stepper.releaseStepSize(state.stepping);
331 state.navigation.navBoundaries.clear();
332 state.navigation.navBoundaryIter =
333 state.navigation.navBoundaries.end();
337 state.navigation.navigationStage = Stage::boundaryTarget;
338 ACTS_VERBOSE(volInfo(state) <<
"Staying focussed on boundary.");
340 }
else if (state.navigation.currentVolume ==
341 state.navigation.targetVolume) {
343 <<
"No further navigation action, proceed to target.");
345 state.navigation.navigationBreak =
true;
346 stepper.releaseStepSize(state.stepping);
349 <<
"Status could not be determined - good luck.");
366 template <
typename propagator_state_t,
typename stepper_t>
368 const auto& logger = state.options.logger;
370 if (inactive(state, stepper)) {
375 ACTS_VERBOSE(volInfo(state) <<
"Entering navigator::target.");
378 if (state.navigation.targetSurface and not state.navigation.targetVolume) {
380 initializeTarget(state, stepper);
384 if (state.navigation.navigationStage <= Stage::surfaceTarget and
385 targetSurfaces(state, stepper)) {
386 ACTS_VERBOSE(volInfo(state) <<
"Target set to next surface.");
387 }
else if (state.navigation.navigationStage <= Stage::layerTarget and
388 targetLayers(state, stepper)) {
389 ACTS_VERBOSE(volInfo(state) <<
"Target set to next layer.");
390 }
else if (targetBoundaries(state, stepper)) {
391 ACTS_VERBOSE(volInfo(state) <<
"Target set to next boundary.");
394 <<
"No further navigation action, proceed to target.");
396 state.navigation.navigationBreak =
true;
397 stepper.releaseStepSize(state.stepping);
401 state.navigation.currentSurface =
nullptr;
418 template <
typename propagator_state_t,
typename stepper_t>
420 const auto& logger = state.options.logger;
426 if (not state.navigation.worldVolume) {
434 state.navigation.currentSurface = state.navigation.startSurface;
435 if (state.navigation.currentSurface) {
437 <<
"Current surface set to start surface "
438 << state.navigation.currentSurface->geometryId());
443 if (state.navigation.startSurface &&
444 state.navigation.startSurface->associatedLayer()) {
447 <<
"Fast start initialization through association from Surface.");
449 state.navigation.startLayer =
450 state.navigation.startSurface->associatedLayer();
451 state.navigation.startVolume =
452 state.navigation.startLayer->trackingVolume();
454 state.navigation.currentVolume = state.navigation.startVolume;
456 if (state.navigation.startVolume) {
459 <<
"Fast start initialization through association from Volume.");
460 state.navigation.startLayer =
461 state.navigation.startVolume->associatedLayer(
462 state.geoContext, stepper.position(state.stepping));
464 state.navigation.currentVolume = state.navigation.startVolume;
467 <<
"Slow start initialization through search.");
470 <<
"Starting from position "
471 <<
toString(stepper.position(state.stepping))
473 <<
toString(stepper.direction(state.stepping)));
475 state.geoContext, stepper.position(state.stepping));
476 state.navigation.startLayer =
477 state.navigation.startVolume
478 ? state.navigation.startVolume->associatedLayer(
479 state.geoContext, stepper.position(state.stepping))
482 state.navigation.currentVolume = state.navigation.startVolume;
483 if (state.navigation.startVolume) {
484 ACTS_VERBOSE(volInfo(state) <<
"Start volume resolved.");
508 template <
typename propagator_state_t,
typename stepper_t,
509 typename navigation_surfaces_t,
typename navigation_iter_t>
510 bool status(propagator_state_t& state,
const stepper_t&
stepper,
511 navigation_surfaces_t& navSurfaces,
512 const navigation_iter_t& navIter)
const {
513 const auto& logger = state.options.logger;
516 if (navSurfaces.empty() or navIter == navSurfaces.end()) {
520 auto surface = navIter->representation;
525 stepper.updateSurfaceStatus(state.stepping, *
surface,
true);
526 if (surfaceStatus == Intersection3D::Status::onSurface) {
528 <<
"Status Surface successfully hit, storing it.");
530 state.navigation.currentSurface =
surface;
531 if (state.navigation.currentSurface) {
533 <<
"Current surface set to surface "
534 << state.navigation.currentSurface->geometryId());
553 template <
typename propagator_state_t,
typename stepper_t>
554 bool targetSurfaces(propagator_state_t& state,
555 const stepper_t&
stepper)
const {
556 const auto& logger = state.options.logger;
558 if (state.navigation.navigationBreak) {
563 if (state.navigation.startLayer and
564 not state.navigation.startLayerResolved) {
565 ACTS_VERBOSE(volInfo(state) <<
"Start layer to be resolved.");
567 state.navigation.startLayerResolved =
true;
569 resolveSurfaces(state, stepper, state.navigation.startLayer);
570 if (not startResolved and
571 state.navigation.startLayer == state.navigation.targetLayer) {
573 <<
"Start is target layer, nothing left to do.");
575 state.navigation.navigationBreak =
true;
576 stepper.releaseStepSize(state.stepping);
578 return startResolved;
583 if (state.navigation.navSurfaces.empty() or
584 state.navigation.navSurfaceIter == state.navigation.navSurfaces.end()) {
586 <<
"No surfaces present, target at layer first.");
590 while (state.navigation.navSurfaceIter !=
591 state.navigation.navSurfaces.end()) {
594 << std::distance(state.navigation.navSurfaceIter,
595 state.navigation.navSurfaces.end())
596 <<
" out of " << state.navigation.navSurfaces.size()
597 <<
" surfaces remain to try.");
599 auto surface = state.navigation.navSurfaceIter->object;
601 ACTS_VERBOSE(volInfo(state) <<
"Next surface candidate will be "
602 << surface->geometryId());
605 stepper.updateSurfaceStatus(state.stepping, *surface,
true);
606 if (surfaceStatus == Intersection3D::Status::reachable) {
608 <<
"Surface reachable, step size updated to "
609 << stepper.outputStepSize(state.stepping));
612 ++state.navigation.navSurfaceIter;
617 if (state.navigation.navSurfaceIter == state.navigation.navSurfaces.end()) {
619 <<
"Last surface on layer reached, switching layer.");
621 state.navigation.navSurfaces.clear();
622 state.navigation.navSurfaceIter = state.navigation.navSurfaces.end();
624 ++state.navigation.navLayerIter;
648 template <
typename propagator_state_t,
typename stepper_t>
650 const auto& logger = state.options.logger;
652 if (state.navigation.navigationBreak) {
657 if (state.navigation.navLayers.empty()) {
659 <<
"No layers present, resolve volume first.");
662 if (state.navigation.currentVolume->hasBoundingVolumeHierarchy()) {
665 state.stepping.navDir,
true, resolveSensitive, resolveMaterial,
666 resolvePassive,
nullptr, state.navigation.targetSurface);
667 navOpts.
overstepLimit = stepper.overstepLimit(state.stepping);
668 double opening_angle = 0;
700 auto protoNavSurfaces =
701 state.navigation.currentVolume->compatibleSurfacesFromHierarchy(
702 state.geoContext, stepper.position(state.stepping),
703 stepper.direction(state.stepping), opening_angle, navOpts);
704 if (!protoNavSurfaces.empty()) {
708 if (state.navigation.currentSurface ==
nullptr ||
709 protoNavSurfaces.front().intersection.pathLength > 1_um) {
711 state.navigation.navSurfaces = std::move(protoNavSurfaces);
713 state.navigation.navSurfaceIter =
714 state.navigation.navSurfaces.begin();
715 state.navigation.navLayers = {};
716 state.navigation.navLayerIter = state.navigation.navLayers.end();
718 stepper.updateStepSize(state.stepping,
719 *state.navigation.navSurfaceIter,
true);
721 <<
"Navigation stepSize updated to "
722 << stepper.outputStepSize(state.stepping));
728 if (resolveLayers(state, stepper)) {
734 while (state.navigation.navLayerIter != state.navigation.navLayers.end()) {
736 auto layerSurface = state.navigation.navLayerIter->representation;
738 if (state.navigation.currentSurface == layerSurface) {
739 ACTS_VERBOSE(volInfo(state) <<
"We are on a layer, resolve Surfaces.");
741 if (resolveSurfaces(state, stepper)) {
745 ++state.navigation.navLayerIter;
751 stepper.updateSurfaceStatus(state.stepping, *layerSurface,
true);
752 if (layerStatus == Intersection3D::Status::reachable) {
753 ACTS_VERBOSE(volInfo(state) <<
"Layer reachable, step size updated to "
754 << stepper.outputStepSize(state.stepping));
758 <<
"Layer intersection not valid, skipping it.");
759 ++state.navigation.navLayerIter;
764 if (state.navigation.currentVolume == state.navigation.targetVolume) {
765 initializeTarget(state, stepper);
769 dstream <<
"Last layer";
770 if (state.navigation.currentVolume == state.navigation.targetVolume) {
771 dstream <<
" (final volume) done, proceed to target.";
773 dstream <<
" done, target volume boundary.";
777 state.navigation.navigationBreak =
778 (state.navigation.currentVolume == state.navigation.targetVolume);
808 template <
typename propagator_state_t,
typename stepper_t>
809 bool targetBoundaries(propagator_state_t& state,
810 const stepper_t&
stepper)
const {
811 const auto& logger = state.options.logger;
813 if (state.navigation.navigationBreak) {
817 if (!state.navigation.currentVolume) {
819 <<
"No sufficient information to resolve boundary, "
820 "stopping navigation.");
821 stepper.releaseStepSize(state.stepping);
823 }
else if (state.navigation.currentVolume ==
824 state.navigation.targetVolume) {
826 <<
"In target volume: no need to resolve boundary, "
827 "stopping navigation.");
828 state.navigation.navigationBreak =
true;
829 stepper.releaseStepSize(state.stepping);
834 initializeTarget(state, stepper);
837 auto findBoundaries = [&]() ->
bool {
842 navOpts.
overstepLimit = stepper.overstepLimit(state.stepping);
845 navOpts.
startObject = state.navigation.currentSurface;
847 <<
"Try to find boundaries, we are at: "
848 << stepper.position(state.stepping).transpose() <<
", dir: "
849 << stepper.direction(state.stepping).transpose());
852 state.navigation.navBoundaries =
853 state.navigation.currentVolume->compatibleBoundaries(
854 state.geoContext, stepper.position(state.stepping),
855 stepper.direction(state.stepping), navOpts,
860 dstream << state.navigation.navBoundaries.size();
861 dstream <<
" boundary candidates found at path(s): ";
862 for (
auto& bc : state.navigation.navBoundaries) {
863 dstream << bc.intersection.pathLength <<
" ";
867 state.navigation.navBoundaryIter = state.navigation.navBoundaries.begin();
868 if (not state.navigation.navBoundaries.empty()) {
870 stepper.updateStepSize(state.stepping,
871 *state.navigation.navBoundaryIter,
true);
872 ACTS_VERBOSE(volInfo(state) <<
"Navigation stepSize updated to "
873 << stepper.outputStepSize(state.stepping));
880 if (state.navigation.navBoundaries.empty() and findBoundaries()) {
885 while (state.navigation.navBoundaryIter !=
886 state.navigation.navBoundaries.end()) {
888 auto boundarySurface = state.navigation.navBoundaryIter->representation;
890 auto boundaryStatus =
891 stepper.updateSurfaceStatus(state.stepping, *boundarySurface,
true);
892 if (boundaryStatus == Intersection3D::Status::reachable) {
894 <<
"Boundary reachable, step size updated to "
895 << stepper.outputStepSize(state.stepping));
900 dstream <<
"Boundary ";
901 dstream << std::distance(state.navigation.navBoundaryIter,
902 state.navigation.navBoundaries.end());
903 dstream <<
" out of " << state.navigation.navBoundaries.size();
904 dstream <<
" not reachable anymore, switching to next.";
908 ++state.navigation.navBoundaryIter;
911 state.navigation.navBoundaries.clear();
912 ACTS_VERBOSE(volInfo(state) <<
"Boundary navigation lost, re-targetting.");
913 if (findBoundaries()) {
941 template <
typename propagator_state_t,
typename stepper_t>
942 void initializeTarget(propagator_state_t& state,
943 const stepper_t&
stepper)
const {
944 const auto& logger = state.options.logger;
946 if (state.navigation.targetVolume and
947 state.stepping.pathAccumulated == 0.) {
949 <<
"Re-initialzing cancelled as it is the first step.");
953 if (state.navigation.targetSurface &&
954 state.navigation.targetSurface->associatedLayer() &&
955 !state.navigation.targetVolume) {
957 <<
"Fast target initialization through association.");
959 <<
"Target surface set to "
960 << state.navigation.targetSurface->geometryId());
961 state.navigation.targetLayer =
962 state.navigation.targetSurface->associatedLayer();
963 state.navigation.targetVolume =
964 state.navigation.targetLayer->trackingVolume();
965 }
else if (state.navigation.targetSurface) {
967 if (state.navigation.targetVolume) {
969 <<
"Re-initialization of target volume triggered.");
973 auto targetIntersection = state.navigation.targetSurface->intersect(
974 state.geoContext, stepper.position(state.stepping),
975 state.stepping.navDir * stepper.direction(state.stepping),
false);
976 if (targetIntersection) {
978 <<
"Target estimate position ("
979 << targetIntersection.intersection.position.x() <<
", "
980 << targetIntersection.intersection.position.y() <<
", "
981 << targetIntersection.intersection.position.z() <<
")");
983 auto tPosition = targetIntersection.intersection.position;
984 state.navigation.targetVolume =
986 state.navigation.targetLayer =
987 state.navigation.targetVolume
988 ? state.navigation.targetVolume->associatedLayer(
989 state.geoContext, tPosition)
991 if (state.navigation.targetVolume) {
993 <<
"Target volume estimated : "
994 << state.navigation.targetVolume->volumeName());
1010 template <
typename propagator_state_t,
typename stepper_t>
1011 bool resolveSurfaces(propagator_state_t& state,
const stepper_t&
stepper,
1012 const Layer* cLayer =
nullptr)
const {
1013 const auto& logger = state.options.logger;
1015 auto layerSurface = cLayer ? state.navigation.startSurface
1016 : state.navigation.navLayerIter->representation;
1017 auto navLayer = cLayer ? cLayer : state.navigation.navLayerIter->object;
1019 bool onStart = (navLayer == state.navigation.startLayer);
1020 auto startSurface = onStart ? state.navigation.startSurface : layerSurface;
1023 state.stepping.navDir,
true, resolveSensitive, resolveMaterial,
1024 resolvePassive, startSurface, state.navigation.targetSurface);
1030 : stepper.overstepLimit(state.stepping);
1033 state.navigation.navSurfaces = navLayer->compatibleSurfaces(
1034 state.geoContext, stepper.position(state.stepping),
1035 stepper.direction(state.stepping), navOpts);
1037 if (!state.navigation.navSurfaces.empty()) {
1039 dstream << state.navigation.navSurfaces.size();
1040 dstream <<
" surface candidates found at path(s): ";
1041 for (
auto& sfc : state.navigation.navSurfaces) {
1042 dstream << sfc.intersection.pathLength <<
" ";
1047 state.navigation.navSurfaceIter = state.navigation.navSurfaces.begin();
1049 stepper.updateStepSize(state.stepping, *state.navigation.navSurfaceIter,
1051 ACTS_VERBOSE(volInfo(state) <<
"Navigation stepSize updated to "
1052 << stepper.outputStepSize(state.stepping));
1055 state.navigation.navSurfaceIter = state.navigation.navSurfaces.end();
1056 ACTS_VERBOSE(volInfo(state) <<
"No surface candidates found.");
1075 template <
typename propagator_state_t,
typename stepper_t>
1076 bool resolveLayers(propagator_state_t& state,
1077 const stepper_t&
stepper)
const {
1078 const auto& logger = state.options.logger;
1079 ACTS_VERBOSE(volInfo(state) <<
"Searching for compatible layers.");
1083 (state.navigation.currentVolume == state.navigation.startVolume)
1084 ? state.navigation.startLayer
1089 resolveSensitive, resolveMaterial,
1090 resolvePassive, startLayer,
nullptr);
1094 navOpts.overstepLimit = stepper.overstepLimit(state.stepping);
1096 state.navigation.navLayers =
1097 state.navigation.currentVolume->compatibleLayers(
1098 state.geoContext, stepper.position(state.stepping),
1099 stepper.direction(state.stepping), navOpts);
1102 if (!state.navigation.navLayers.empty()) {
1105 dstream << state.navigation.navLayers.size();
1106 dstream <<
" layer candidates found at path(s): ";
1107 for (
auto& lc : state.navigation.navLayers) {
1108 dstream << lc.intersection.pathLength <<
" ";
1112 state.navigation.navLayerIter = state.navigation.navLayers.begin();
1114 if (state.navigation.startLayer &&
1115 state.navigation.navLayerIter->object !=
1116 state.navigation.startLayer) {
1119 stepper.updateStepSize(state.stepping, *state.navigation.navLayerIter,
1121 ACTS_VERBOSE(volInfo(state) <<
"Navigation stepSize updated to "
1122 << stepper.outputStepSize(state.stepping));
1128 state.navigation.navLayerIter = state.navigation.navLayers.end();
1131 ACTS_VERBOSE(volInfo(state) <<
"No compatible layer candidates found.");
1133 stepper.releaseStepSize(state.stepping);
1150 template <
typename propagator_state_t,
typename stepper_t>
1152 const auto& logger = state.options.logger;
1159 if (!resolveSensitive && !resolveMaterial && !resolvePassive) {
1169 if (state.navigation.navigationBreak) {
1171 if (state.navigation.targetReached || !state.navigation.targetSurface) {
1174 auto targetStatus = stepper.updateSurfaceStatus(
1175 state.stepping, *state.navigation.targetSurface,
true);
1177 if (targetStatus == Intersection3D::Status::onSurface) {
1179 state.navigation.currentSurface = state.navigation.targetSurface;
1182 <<
"Current surface set to target surface "
1183 << state.navigation.currentSurface->geometryId());
1191 template <
typename propagator_state_t>
1192 std::string
volInfo(
const propagator_state_t& state)
const {
1193 return (state.navigation.currentVolume
1194 ? state.navigation.currentVolume->volumeName()