11 #include <boost/algorithm/string.hpp>
27 using namespace Acts::UnitLiterals;
34 template <
typename object_t>
44 bool resolveSensitive =
true;
46 bool resolveMaterial =
true;
48 bool resolvePassive =
false;
51 const object_t* startObject =
nullptr;
53 const object_t* endObject =
nullptr;
64 double overstepLimit = -1
_um;
74 bool resolves =
true,
bool resolvem =
true,
75 bool resolvep =
false,
const object_t* sobject =
nullptr,
76 const object_t* eobject =
nullptr)
79 resolveSensitive(resolves),
80 resolveMaterial(resolvem),
81 resolvePassive(resolvep),
84 pathLimit(ndir * std::numeric_limits<double>::
max()),
85 overstepLimit(-1
_um) {}
149 bool resolveSensitive =
true;
151 bool resolveMaterial =
true;
153 bool resolvePassive =
false;
203 bool startLayerResolved =
false;
205 bool targetReached =
false;
207 bool navigationBreak =
false;
231 template <
typename propagator_state_t,
typename stepper_t>
242 debugLog(state, [&] {
return std::string(
"Entering navigator::status."); });
245 if (not state.navigation.startVolume) {
252 state.navigation.currentSurface =
nullptr;
256 if (status(state, stepper, state.navigation.navSurfaces,
257 state.navigation.navSurfaceIter)) {
259 [&] {
return std::string(
"Status: in surface handling."); });
260 if (state.navigation.currentSurface) {
261 debugLog(state, [&] {
262 return std::string(
"On surface: switch forward or release.");
264 if (++state.navigation.navSurfaceIter ==
265 state.navigation.navSurfaces.end()) {
267 if (!state.navigation.navLayers.empty()) {
268 ++state.navigation.navLayerIter;
271 state.navigation.navigationStage = Stage::boundaryTarget;
277 state.navigation.navigationStage = Stage::surfaceTarget;
279 [&] {
return std::string(
"Staying focussed on surface."); });
281 }
else if (status(state, stepper, state.navigation.navLayers,
282 state.navigation.navLayerIter)) {
284 [&] {
return std::string(
"Status: in layer handling."); });
285 if (state.navigation.currentSurface !=
nullptr) {
286 debugLog(state, [&] {
287 return std::string(
"On layer: update layer information.");
289 if (resolveSurfaces(state, stepper)) {
291 state.navigation.navigationStage = Stage::surfaceTarget;
296 state.navigation.navigationStage = Stage::layerTarget;
298 [&] {
return std::string(
"Staying focussed on layer."); });
301 }
else if (status(state, stepper, state.navigation.navBoundaries,
302 state.navigation.navBoundaryIter)) {
304 [&] {
return std::string(
"Status: in boundary handling."); });
307 if (state.navigation.currentSurface !=
nullptr) {
309 debugLog(state, [&] {
310 return std::string(
"On boundary: update volume information.");
313 state.navigation.navSurfaces.clear();
314 state.navigation.navSurfaceIter = state.navigation.navSurfaces.end();
315 state.navigation.navLayers.clear();
316 state.navigation.navLayerIter = state.navigation.navLayers.end();
319 auto boundary = state.navigation.navBoundaryIter->object;
320 state.navigation.currentVolume = boundary->attachedVolume(
321 state.geoContext, stepper.position(state.stepping),
322 stepper.direction(state.stepping), state.stepping.navDir);
324 if (!state.navigation.currentVolume) {
325 debugLog(state, [&] {
327 "No more volume to progress to, stopping navigation.");
330 state.navigation.navigationBreak =
true;
331 stepper.releaseStepSize(state.stepping);
334 debugLog(state, [&] {
return std::string(
"Volume updated."); });
336 state.navigation.navBoundaries.clear();
337 state.navigation.navBoundaryIter =
338 state.navigation.navBoundaries.end();
342 state.navigation.navigationStage = Stage::boundaryTarget;
344 [&] {
return std::string(
"Staying focussed on boundary."); });
346 }
else if (state.navigation.currentVolume ==
347 state.navigation.targetVolume) {
348 debugLog(state, [&] {
349 return std::string(
"No further navigation action, proceed to target.");
352 state.navigation.navigationBreak =
true;
353 stepper.releaseStepSize(state.stepping);
355 debugLog(state, [&] {
356 return std::string(
"Status could not be determined - good luck.");
374 template <
typename propagator_state_t,
typename stepper_t>
382 debugLog(state, [&] {
return std::string(
"Entering navigator::target."); });
385 if (state.navigation.targetSurface and not state.navigation.targetVolume) {
387 initializeTarget(state, stepper);
391 if (state.navigation.navigationStage <= Stage::surfaceTarget and
392 targetSurfaces(state, stepper)) {
394 [&] {
return std::string(
"Target set to next surface."); });
395 }
else if (state.navigation.navigationStage <= Stage::layerTarget and
396 targetLayers(state, stepper)) {
397 debugLog(state, [&] {
return std::string(
"Target set to next layer."); });
398 }
else if (targetBoundaries(state, stepper)) {
400 [&] {
return std::string(
"Target set to next boundary."); });
402 debugLog(state, [&] {
403 return std::string(
"No further navigation action, proceed to target.");
406 state.navigation.navigationBreak =
true;
407 stepper.releaseStepSize(state.stepping);
411 state.navigation.currentSurface =
nullptr;
428 template <
typename propagator_state_t,
typename stepper_t>
431 debugLog(state, [&] {
return std::string(
"Initialization."); });
434 if (not state.navigation.worldVolume) {
442 state.navigation.currentSurface = state.navigation.startSurface;
443 if (state.navigation.currentSurface) {
444 debugLog(state, [&] {
445 std::stringstream dstream;
446 dstream <<
"Current surface set to start surface ";
447 dstream << state.navigation.currentSurface->geoID();
448 return dstream.str();
454 if (state.navigation.startSurface &&
455 state.navigation.startSurface->associatedLayer()) {
456 debugLog(state, [&] {
457 return std::string(
"Fast start initialization through association.");
460 state.navigation.startLayer =
461 state.navigation.startSurface->associatedLayer();
462 state.navigation.startVolume =
463 state.navigation.startLayer->trackingVolume();
465 state.navigation.currentVolume = state.navigation.startVolume;
467 debugLog(state, [&] {
468 return std::string(
"Slow start initialization through search.");
471 debugLog(state, [&] {
472 std::stringstream dstream;
473 dstream <<
"Starting from position "
474 <<
toString(stepper.position(state.stepping));
475 dstream <<
" and direction "
476 <<
toString(stepper.direction(state.stepping));
477 return dstream.str();
480 state.geoContext, stepper.position(state.stepping));
481 state.navigation.startLayer =
482 state.navigation.startVolume
483 ? state.navigation.startVolume->associatedLayer(
484 state.geoContext, stepper.position(state.stepping))
487 state.navigation.currentVolume = state.navigation.startVolume;
488 if (state.navigation.startVolume) {
489 debugLog(state, [&] {
return std::string(
"Start volume resolved."); });
512 template <
typename propagator_state_t,
typename stepper_t,
513 typename navigation_surfaces_t,
typename navigation_iter_t>
514 bool status(propagator_state_t& state,
const stepper_t&
stepper,
515 navigation_surfaces_t& navSurfaces,
516 const navigation_iter_t& navIter)
const {
518 if (navSurfaces.empty() or navIter == navSurfaces.end()) {
522 auto surface = navIter->representation;
527 stepper.updateSurfaceStatus(state.stepping, *
surface,
true);
528 if (surfaceStatus == Intersection::Status::onSurface) {
529 debugLog(state, [&] {
530 return std::string(
"Status Surface successfully hit, storing it.");
533 state.navigation.currentSurface =
surface;
534 if (state.navigation.currentSurface) {
535 debugLog(state, [&] {
536 std::stringstream dstream;
537 dstream <<
"Current surface set to surface ";
538 dstream << state.navigation.currentSurface->geoID();
539 return dstream.str();
559 template <
typename propagator_state_t,
typename stepper_t>
560 bool targetSurfaces(propagator_state_t& state,
561 const stepper_t&
stepper)
const {
562 if (state.navigation.navigationBreak) {
567 if (state.navigation.startLayer and
568 not state.navigation.startLayerResolved) {
570 [&] {
return std::string(
"Start layer to be resolved."); });
572 state.navigation.startLayerResolved =
true;
574 resolveSurfaces(state, stepper, state.navigation.startLayer);
575 if (not startResolved and
576 state.navigation.startLayer == state.navigation.targetLayer) {
577 debugLog(state, [&] {
578 return std::string(
"Start is target layer, nothing left to do.");
581 state.navigation.navigationBreak =
true;
582 stepper.releaseStepSize(state.stepping);
584 return startResolved;
589 if (state.navigation.navSurfaces.empty() or
590 state.navigation.navSurfaceIter == state.navigation.navSurfaces.end()) {
591 debugLog(state, [&] {
592 return std::string(
"No surfaces present, target at layer first.");
597 while (state.navigation.navSurfaceIter !=
598 state.navigation.navSurfaces.end()) {
600 debugLog(state, [&] {
601 std::stringstream dstream;
602 dstream << std::distance(state.navigation.navSurfaceIter,
603 state.navigation.navSurfaces.end());
604 dstream <<
" out of " << state.navigation.navSurfaces.size();
605 dstream <<
" surfaces remain to try.";
606 return dstream.str();
609 auto surface = state.navigation.navSurfaceIter->object;
611 debugLog(state, [&] {
612 std::stringstream dstream;
613 dstream <<
"Next surface candidate will be ";
614 dstream << surface->geoID();
615 return dstream.str();
619 stepper.updateSurfaceStatus(state.stepping, *surface,
true);
620 if (surfaceStatus == Intersection::Status::reachable) {
621 debugLog(state, [&] {
622 std::stringstream dstream;
623 dstream <<
"Surface reachable, step size updated to ";
624 dstream << stepper.outputStepSize(state.stepping);
625 return dstream.str();
629 ++state.navigation.navSurfaceIter;
634 if (state.navigation.navSurfaceIter == state.navigation.navSurfaces.end()) {
635 debugLog(state, [&] {
636 return std::string(
"Last surface on layer reached, switching layer.");
639 state.navigation.navSurfaces.clear();
640 state.navigation.navSurfaceIter = state.navigation.navSurfaces.end();
642 ++state.navigation.navLayerIter;
666 template <
typename propagator_state_t,
typename stepper_t>
668 if (state.navigation.navigationBreak) {
673 if (state.navigation.navLayers.empty()) {
674 debugLog(state, [&] {
675 return std::string(
"No layers present, resolve volume first.");
679 if (state.navigation.currentVolume->hasBoundingVolumeHierarchy()) {
682 state.stepping.navDir,
true, resolveSensitive, resolveMaterial,
683 resolvePassive,
nullptr, state.navigation.targetSurface);
684 navOpts.
overstepLimit = stepper.overstepLimit(state.stepping);
685 double opening_angle = 0;
721 auto protoNavSurfaces =
722 state.navigation.currentVolume->compatibleSurfacesFromHierarchy(
723 state.geoContext, stepper.position(state.stepping),
724 stepper.direction(state.stepping), opening_angle, navOpts);
725 if (!protoNavSurfaces.empty()) {
729 if (state.navigation.currentSurface ==
nullptr ||
730 state.navigation.currentSurface !=
731 protoNavSurfaces.front().object) {
733 state.navigation.navSurfaces = std::move(protoNavSurfaces);
735 state.navigation.navSurfaceIter =
736 state.navigation.navSurfaces.begin();
737 state.navigation.navLayers = {};
738 state.navigation.navLayerIter = state.navigation.navLayers.end();
740 stepper.updateStepSize(state.stepping,
741 *state.navigation.navSurfaceIter,
true);
742 debugLog(state, [&] {
743 std::stringstream dstream;
744 dstream <<
"Navigation stepSize updated to ";
745 dstream << stepper.outputStepSize(state.stepping);
746 return dstream.str();
753 if (resolveLayers(state, stepper)) {
759 while (state.navigation.navLayerIter != state.navigation.navLayers.end()) {
761 auto layerSurface = state.navigation.navLayerIter->representation;
763 if (state.navigation.currentSurface == layerSurface) {
764 debugLog(state, [&] {
765 return std::string(
"We are on a layer, resolve Surfaces.");
768 if (resolveSurfaces(state, stepper)) {
772 ++state.navigation.navLayerIter;
778 stepper.updateSurfaceStatus(state.stepping, *layerSurface,
true);
779 if (layerStatus == Intersection::Status::reachable) {
780 debugLog(state, [&] {
781 std::stringstream dstream;
782 dstream <<
"Layer reachable, step size updated to ";
783 dstream << stepper.outputStepSize(state.stepping);
784 return dstream.str();
788 debugLog(state, [&] {
789 return std::string(
"Layer intersection not valid, skipping it.");
791 ++state.navigation.navLayerIter;
796 if (state.navigation.currentVolume == state.navigation.targetVolume) {
797 initializeTarget(state, stepper);
800 debugLog(state, [&] {
801 std::stringstream dstream;
802 dstream <<
"Last layer";
803 if (state.navigation.currentVolume == state.navigation.targetVolume) {
804 dstream <<
" (final volume) done, proceed to target.";
806 dstream <<
" done, target volume boundary.";
808 return dstream.str();
811 state.navigation.navigationBreak =
812 (state.navigation.currentVolume == state.navigation.targetVolume);
842 template <
typename propagator_state_t,
typename stepper_t>
843 bool targetBoundaries(propagator_state_t& state,
844 const stepper_t&
stepper)
const {
845 if (state.navigation.navigationBreak) {
849 if (!state.navigation.currentVolume) {
850 debugLog(state, [&] {
852 "No sufficient information to resolve boundary, "
853 "stopping navigation.");
855 stepper.releaseStepSize(state.stepping);
857 }
else if (state.navigation.currentVolume ==
858 state.navigation.targetVolume) {
859 debugLog(state, [&] {
861 "In target volume: no need to resolve boundary, "
862 "stopping navigation.");
863 state.navigation.navigationBreak =
true;
864 stepper.releaseStepSize(state.stepping);
870 initializeTarget(state, stepper);
873 auto findBoundaries = [&]() ->
bool {
878 navOpts.
overstepLimit = stepper.overstepLimit(state.stepping);
881 navOpts.
startObject = state.navigation.currentSurface;
882 debugLog(state, [&] {
883 std::stringstream ss;
884 ss <<
"Try to find boundaries, we are at: "
885 << stepper.position(state.stepping).transpose()
886 <<
", dir: " << stepper.direction(state.stepping).transpose();
890 state.navigation.navBoundaries =
891 state.navigation.currentVolume->compatibleBoundaries(
892 state.geoContext, stepper.position(state.stepping),
893 stepper.direction(state.stepping), navOpts);
895 debugLog(state, [&] {
896 std::stringstream dstream;
897 dstream << state.navigation.navBoundaries.size();
898 dstream <<
" boundary candidates found at path(s): ";
899 for (
auto& bc : state.navigation.navBoundaries) {
900 dstream << bc.intersection.pathLength <<
" ";
902 return dstream.str();
905 state.navigation.navBoundaryIter = state.navigation.navBoundaries.begin();
906 if (not state.navigation.navBoundaries.empty()) {
908 stepper.updateStepSize(state.stepping,
909 *state.navigation.navBoundaryIter,
true);
910 debugLog(state, [&] {
911 std::stringstream dstream;
912 dstream <<
"Navigation stepSize updated to ";
913 dstream << stepper.outputStepSize(state.stepping);
914 return dstream.str();
922 if (state.navigation.navBoundaries.empty() and findBoundaries()) {
927 while (state.navigation.navBoundaryIter !=
928 state.navigation.navBoundaries.end()) {
930 auto boundarySurface = state.navigation.navBoundaryIter->representation;
932 auto boundaryStatus =
933 stepper.updateSurfaceStatus(state.stepping, *boundarySurface,
true);
934 if (boundaryStatus == Intersection::Status::reachable) {
935 debugLog(state, [&] {
936 std::stringstream dstream;
937 dstream <<
"Boundary reachable, step size updated to ";
938 dstream << stepper.outputStepSize(state.stepping);
939 return dstream.str();
943 debugLog(state, [&] {
944 std::stringstream dstream;
945 dstream <<
"Boundary ";
946 dstream << std::distance(state.navigation.navBoundaryIter,
947 state.navigation.navBoundaries.end());
948 dstream <<
" out of " << state.navigation.navBoundaries.size();
949 dstream <<
" not reachable anymore, switching to next.";
950 return dstream.str();
954 ++state.navigation.navBoundaryIter;
957 state.navigation.navBoundaries.clear();
958 debugLog(state, [&] {
959 return std::string(
"Boundary navigation lost, re-targetting.");
961 if (findBoundaries()) {
989 template <
typename propagator_state_t,
typename stepper_t>
990 void initializeTarget(propagator_state_t& state,
991 const stepper_t&
stepper)
const {
992 if (state.navigation.targetVolume and
993 state.stepping.pathAccumulated == 0.) {
994 debugLog(state, [&] {
995 return std::string(
"Re-initialzing cancelled as it is the first step.");
1000 if (state.navigation.targetSurface &&
1001 state.navigation.targetSurface->associatedLayer() &&
1002 !state.navigation.targetVolume) {
1003 debugLog(state, [&] {
1004 return std::string(
"Fast target initialization through association.");
1006 debugLog(state, [&] {
1007 std::stringstream dstream;
1008 dstream <<
"Target surface set to ";
1009 dstream << state.navigation.targetSurface->geoID();
1010 return dstream.str();
1013 state.navigation.targetLayer =
1014 state.navigation.targetSurface->associatedLayer();
1015 state.navigation.targetVolume =
1016 state.navigation.targetLayer->trackingVolume();
1017 }
else if (state.navigation.targetSurface) {
1019 if (state.navigation.targetVolume) {
1020 debugLog(state, [&] {
1021 return std::string(
"Re-initialization of target volume triggered.");
1026 auto targetIntersection = state.navigation.targetSurface->intersect(
1027 state.geoContext, stepper.position(state.stepping),
1028 state.stepping.navDir * stepper.direction(state.stepping),
false);
1029 if (targetIntersection) {
1030 debugLog(state, [&] {
1031 std::stringstream dstream;
1032 dstream <<
"Target estimate position (";
1033 dstream << targetIntersection.intersection.position.x() <<
", ";
1034 dstream << targetIntersection.intersection.position.y() <<
", ";
1035 dstream << targetIntersection.intersection.position.z() <<
")";
1036 return dstream.str();
1039 auto tPosition = targetIntersection.intersection.position;
1040 state.navigation.targetVolume =
1042 state.navigation.targetLayer =
1043 state.navigation.targetVolume
1044 ? state.navigation.targetVolume->associatedLayer(
1045 state.geoContext, tPosition)
1047 if (state.navigation.targetVolume) {
1048 debugLog(state, [&] {
1049 std::stringstream dstream;
1050 dstream <<
"Target volume estimated : ";
1051 dstream << state.navigation.targetVolume->volumeName();
1052 return dstream.str();
1069 template <
typename propagator_state_t,
typename stepper_t>
1070 bool resolveSurfaces(propagator_state_t& state,
const stepper_t&
stepper,
1071 const Layer* cLayer =
nullptr)
const {
1073 auto layerSurface = cLayer ? state.navigation.startSurface
1074 : state.navigation.navLayerIter->representation;
1075 auto navLayer = cLayer ? cLayer : state.navigation.navLayerIter->object;
1077 bool onStart = (navLayer == state.navigation.startLayer);
1078 auto startSurface = onStart ? state.navigation.startSurface : layerSurface;
1081 state.stepping.navDir,
true, resolveSensitive, resolveMaterial,
1082 resolvePassive, startSurface, state.navigation.targetSurface);
1088 : stepper.overstepLimit(state.stepping);
1091 state.navigation.navSurfaces = navLayer->compatibleSurfaces(
1092 state.geoContext, stepper.position(state.stepping),
1093 stepper.direction(state.stepping), navOpts);
1095 if (!state.navigation.navSurfaces.empty()) {
1096 debugLog(state, [&] {
1097 std::stringstream dstream;
1098 dstream << state.navigation.navSurfaces.size();
1099 dstream <<
" surface candidates found at path(s): ";
1100 for (
auto& sfc : state.navigation.navSurfaces) {
1101 dstream << sfc.intersection.pathLength <<
" ";
1103 return dstream.str();
1106 state.navigation.navSurfaceIter = state.navigation.navSurfaces.begin();
1108 stepper.updateStepSize(state.stepping, *state.navigation.navSurfaceIter,
1110 debugLog(state, [&] {
1111 std::stringstream dstream;
1112 dstream <<
"Navigation stepSize updated to ";
1113 dstream << stepper.outputStepSize(state.stepping);
1114 return dstream.str();
1118 state.navigation.navSurfaceIter = state.navigation.navSurfaces.end();
1120 [&] {
return std::string(
"No surface candidates found."); });
1139 template <
typename propagator_state_t,
typename stepper_t>
1140 bool resolveLayers(propagator_state_t& state,
1141 const stepper_t&
stepper)
const {
1143 [&] {
return std::string(
"Searching for compatible layers."); });
1147 (state.navigation.currentVolume == state.navigation.startVolume)
1148 ? state.navigation.startLayer
1153 resolveSensitive, resolveMaterial,
1154 resolvePassive, startLayer,
nullptr);
1158 navOpts.overstepLimit = stepper.overstepLimit(state.stepping);
1160 state.navigation.navLayers =
1161 state.navigation.currentVolume->compatibleLayers(
1162 state.geoContext, stepper.position(state.stepping),
1163 stepper.direction(state.stepping), navOpts);
1166 if (!state.navigation.navLayers.empty()) {
1168 debugLog(state, [&] {
1169 std::stringstream dstream;
1170 dstream << state.navigation.navLayers.size();
1171 dstream <<
" layer candidates found at path(s): ";
1172 for (
auto&
lc : state.navigation.navLayers) {
1173 dstream <<
lc.intersection.pathLength <<
" ";
1175 return dstream.str();
1178 state.navigation.navLayerIter = state.navigation.navLayers.begin();
1180 if (state.navigation.startLayer &&
1181 state.navigation.navLayerIter->object !=
1182 state.navigation.startLayer) {
1183 debugLog(state, [&] {
return std::string(
"Target at layer."); });
1185 stepper.updateStepSize(state.stepping, *state.navigation.navLayerIter,
1187 debugLog(state, [&] {
1188 std::stringstream dstream;
1189 dstream <<
"Navigation stepSize updated to ";
1190 dstream << stepper.outputStepSize(state.stepping);
1191 return dstream.str();
1198 state.navigation.navLayerIter = state.navigation.navLayers.end();
1201 debugLog(state, [&] {
1202 return std::string(
"No compatible layer candidates found.");
1205 stepper.releaseStepSize(state.stepping);
1222 template <
typename propagator_state_t,
typename stepper_t>
1229 if (!resolveSensitive && !resolveMaterial && !resolvePassive) {
1239 if (state.navigation.navigationBreak) {
1241 if (state.navigation.targetReached || !state.navigation.targetSurface) {
1244 auto targetStatus = stepper.updateSurfaceStatus(
1245 state.stepping, *state.navigation.targetSurface,
true);
1247 if (targetStatus == Intersection::Status::onSurface) {
1249 state.navigation.currentSurface = state.navigation.targetSurface;
1250 debugLog(state, [&] {
1251 std::stringstream dstream;
1252 dstream <<
"Current surface set to target surface ";
1253 dstream << state.navigation.currentSurface->geoID();
1254 return dstream.str();
1274 template <
typename propagator_state_t>
1275 void debugLog(propagator_state_t& state,
1277 if (state.options.debug) {
1278 std::string vName =
"No Volume";
1279 if (state.navigation.currentVolume) {
1280 vName = state.navigation.currentVolume->volumeName();
1282 std::vector<std::string> lines;
1283 std::string input = logAction();
1285 for (
const auto& line : lines) {
1286 std::stringstream dstream;
1287 dstream <<
">>>" << std::setw(state.options.debugPfxWidth) << vName
1289 dstream << std::setw(state.options.debugMsgWidth) << line <<
'\n';
1290 state.options.debugString += dstream.str();