diff --git a/Core/include/Acts/Propagator/Navigator.hpp b/Core/include/Acts/Propagator/Navigator.hpp index 221963d0020..fc20ef34608 100644 --- a/Core/include/Acts/Propagator/Navigator.hpp +++ b/Core/include/Acts/Propagator/Navigator.hpp @@ -604,7 +604,32 @@ class Navigator { // Request the compatible surfaces state.navSurfaces = currentLayer->compatibleSurfaces( state.options.geoContext, position, direction, navOpts); - std::ranges::sort(state.navSurfaces, SurfaceIntersection::pathLengthOrder); + // Sort the surfaces by path length. + // Special care is taken for the external surfaces which should always come + // first, so they are preferred to be targeted and hit first. + std::ranges::sort( + state.navSurfaces, [&state, &navOpts](const SurfaceIntersection& a, + const SurfaceIntersection& b) { + // Prefer to sort by path length. We assume surfaces are at the same + // distance if the difference is smaller than the tolerance. + if (std::abs(a.pathLength() - b.pathLength()) > + state.options.surfaceTolerance) { + return SurfaceIntersection::pathLengthOrder(a, b); + } + // If the path length is practically the same, sort by geometry. First + // we check if one of the surfaces is external. + bool aIsExternal = rangeContainsValue(navOpts.externalSurfaces, + a.object()->geometryId()); + bool bIsExternal = rangeContainsValue(navOpts.externalSurfaces, + b.object()->geometryId()); + if (aIsExternal == bIsExternal) { + // If both are external or both are not external, sort by geometry + // identifier + return a.object()->geometryId() < b.object()->geometryId(); + } + // If only one is external, it should come first + return aIsExternal; + }); // Print surface information if (logger().doPrint(Logging::VERBOSE)) {