diff --git a/Core/include/Acts/Propagator/PropagatorOptions.hpp b/Core/include/Acts/Propagator/PropagatorOptions.hpp index 039aed013a5..78e7edab2fe 100644 --- a/Core/include/Acts/Propagator/PropagatorOptions.hpp +++ b/Core/include/Acts/Propagator/PropagatorOptions.hpp @@ -33,13 +33,22 @@ struct PurePropagatorPlainOptions { /// Absolute maximum path length double pathLimit = std::numeric_limits::max(); - /// Required tolerance to reach surface - double surfaceTolerance = s_onSurfaceTolerance; - /// Loop protection step, it adapts the pathLimit bool loopProtection = true; /// Allowed loop fraction, 1 is a full loop double loopFraction = 0.5; + + /// Required tolerance to reach surface + double surfaceTolerance = s_onSurfaceTolerance; + + /// Constrain the propagation to selected volumes + /// @note ignored if empty + /// @note requires `VolumeConstraintAborter` aborter + std::vector constrainToVolumeIds; + /// Additional volumes to be considered as end of world + /// @note ignored if empty + /// @note requires `VolumeConstraintAborter` aborter + std::vector endOfWorldVolumeIds; }; } // namespace detail diff --git a/Core/include/Acts/Propagator/StandardAborters.hpp b/Core/include/Acts/Propagator/StandardAborters.hpp index ce460a945d7..706b0ce0697 100644 --- a/Core/include/Acts/Propagator/StandardAborters.hpp +++ b/Core/include/Acts/Propagator/StandardAborters.hpp @@ -161,7 +161,7 @@ struct ForcedSurfaceReached : SurfaceReached { : SurfaceReached(std::numeric_limits::lowest()) {} }; -/// This is the condition that the end of World has been reached +/// This is the condition that the end of world has been reached /// it then triggers an propagation abort struct EndOfWorldReached { /// boolean operator for abort condition without using the result @@ -181,6 +181,60 @@ struct EndOfWorldReached { } }; +/// This is the condition that the end of world has been reached +/// it then triggers a propagation abort +struct VolumeConstraintAborter { + /// boolean operator for abort condition without using the result + /// + /// @tparam propagator_state_t Type of the propagator state + /// @tparam navigator_t Type of the navigator + /// + /// @param [in,out] state The propagation state object + /// @param [in] navigator The navigator object + /// @param logger a logger instance + template + bool checkAbort(propagator_state_t& state, const stepper_t& /*stepper*/, + const navigator_t& navigator, const Logger& logger) const { + const auto& constrainToVolumeIds = state.options.constrainToVolumeIds; + const auto& endOfWorldVolumeIds = state.options.endOfWorldVolumeIds; + + if (constrainToVolumeIds.empty() && endOfWorldVolumeIds.empty()) { + return false; + } + const auto* currentVolume = navigator.currentVolume(state.navigation); + + // We need a volume to check its ID + if (currentVolume == nullptr) { + return false; + } + + const auto currentVolumeId = + static_cast(currentVolume->geometryId().volume()); + + if (!constrainToVolumeIds.empty() && + std::find(constrainToVolumeIds.begin(), constrainToVolumeIds.end(), + currentVolumeId) == constrainToVolumeIds.end()) { + ACTS_VERBOSE( + "VolumeConstraintAborter aborter | Abort with volume constrain " + << currentVolumeId); + return true; + } + + if (!endOfWorldVolumeIds.empty() && + std::find(endOfWorldVolumeIds.begin(), endOfWorldVolumeIds.end(), + currentVolumeId) != endOfWorldVolumeIds.end()) { + ACTS_VERBOSE( + "VolumeConstraintAborter aborter | Abort with additional end of " + "world volume " + << currentVolumeId); + return true; + } + + return false; + } +}; + /// Aborter that checks if the propagation has reached any surface struct AnySurfaceReached { template pixelVolumes; - std::set stripVolumes; + std::vector pixelVolumeIds; + std::vector stripVolumeIds; - /// additional track selector settings + // additional track selector settings std::size_t maxPixelHoles = std::numeric_limits::max(); std::size_t maxStripHoles = std::numeric_limits::max(); + + /// The volume ids to constrain the track finding to + std::vector constrainToVolumeIds; + /// The volume ids to stop the track finding at + std::vector endOfWorldVolumeIds; }; /// Constructor of the track finding algorithm diff --git a/Examples/Algorithms/TrackFinding/src/TrackFindingAlgorithm.cpp b/Examples/Algorithms/TrackFinding/src/TrackFindingAlgorithm.cpp index 0a5ae601d20..a6d5efc69e6 100644 --- a/Examples/Algorithms/TrackFinding/src/TrackFindingAlgorithm.cpp +++ b/Examples/Algorithms/TrackFinding/src/TrackFindingAlgorithm.cpp @@ -217,16 +217,18 @@ class BranchStopper { } bool tooManyHolesPS = false; - if (!(m_cfg.pixelVolumes.empty() && m_cfg.stripVolumes.empty())) { + if (!(m_cfg.pixelVolumeIds.empty() && m_cfg.stripVolumeIds.empty())) { auto& branchState = branchStateAccessor(track); // count both holes and outliers as holes for pixel/strip counts if (trackState.typeFlags().test(Acts::TrackStateFlag::HoleFlag) || trackState.typeFlags().test(Acts::TrackStateFlag::OutlierFlag)) { - if (m_cfg.pixelVolumes.contains( - trackState.referenceSurface().geometryId().volume())) { + auto volumeId = trackState.referenceSurface().geometryId().volume(); + if (std::find(m_cfg.pixelVolumeIds.begin(), m_cfg.pixelVolumeIds.end(), + volumeId) != m_cfg.pixelVolumeIds.end()) { ++branchState.nPixelHoles; - } else if (m_cfg.stripVolumes.contains( - trackState.referenceSurface().geometryId().volume())) { + } else if (std::find(m_cfg.stripVolumeIds.begin(), + m_cfg.stripVolumeIds.end(), + volumeId) != m_cfg.stripVolumeIds.end()) { ++branchState.nStripHoles; } } @@ -350,11 +352,15 @@ ProcessCode TrackFindingAlgorithm::execute(const AlgorithmContext& ctx) const { firstPropOptions.maxSteps = m_cfg.maxSteps; firstPropOptions.direction = m_cfg.reverseSearch ? Acts::Direction::Backward : Acts::Direction::Forward; + firstPropOptions.constrainToVolumeIds = m_cfg.constrainToVolumeIds; + firstPropOptions.endOfWorldVolumeIds = m_cfg.endOfWorldVolumeIds; Acts::PropagatorPlainOptions secondPropOptions(ctx.geoContext, ctx.magFieldContext); secondPropOptions.maxSteps = m_cfg.maxSteps; secondPropOptions.direction = firstPropOptions.direction.invert(); + secondPropOptions.constrainToVolumeIds = m_cfg.constrainToVolumeIds; + secondPropOptions.endOfWorldVolumeIds = m_cfg.endOfWorldVolumeIds; // Set the CombinatorialKalmanFilter options TrackFinderOptions firstOptions(ctx.geoContext, ctx.magFieldContext, @@ -379,6 +385,8 @@ ProcessCode TrackFindingAlgorithm::execute(const AlgorithmContext& ctx) const { logger().cloneWithSuffix("Propagator")); ExtrapolatorOptions extrapolationOptions(ctx.geoContext, ctx.magFieldContext); + extrapolationOptions.constrainToVolumeIds = m_cfg.constrainToVolumeIds; + extrapolationOptions.endOfWorldVolumeIds = m_cfg.endOfWorldVolumeIds; // Perform the track finding for all initial parameters ACTS_DEBUG("Invoke track finding with " << initialParameters.size() diff --git a/Examples/Python/python/acts/examples/reconstruction.py b/Examples/Python/python/acts/examples/reconstruction.py index e47b435e72b..ab12005af86 100644 --- a/Examples/Python/python/acts/examples/reconstruction.py +++ b/Examples/Python/python/acts/examples/reconstruction.py @@ -147,8 +147,24 @@ "maxPixelHoles", "maxStripHoles", "trimTracks", + "constrainToVolumes", + "endOfWorldVolumes", + ], + defaults=[ + 15.0, + 25.0, + 10, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, ], - defaults=[15.0, 25.0, 10, None, None, None, None, None, None, None, None], ) AmbiguityResolutionConfig = namedtuple( @@ -1531,11 +1547,13 @@ def addCKFTracks( reverseSearch=reverseSearch, seedDeduplication=ckfConfig.seedDeduplication, stayOnSeed=ckfConfig.stayOnSeed, - pixelVolumes=ckfConfig.pixelVolumes, - stripVolumes=ckfConfig.stripVolumes, + pixelVolumeIds=ckfConfig.pixelVolumes, + stripVolumeIds=ckfConfig.stripVolumes, maxPixelHoles=ckfConfig.maxPixelHoles, maxStripHoles=ckfConfig.maxStripHoles, trimTracks=ckfConfig.trimTracks, + constrainToVolumeIds=ckfConfig.constrainToVolumes, + endOfWorldVolumeIds=ckfConfig.endOfWorldVolumes, ), ) s.addAlgorithm(trackFinder) diff --git a/Examples/Python/src/TrackFinding.cpp b/Examples/Python/src/TrackFinding.cpp index 05ebcb3c7a7..4179d58d94a 100644 --- a/Examples/Python/src/TrackFinding.cpp +++ b/Examples/Python/src/TrackFinding.cpp @@ -337,11 +337,13 @@ void addTrackFinding(Context& ctx) { ACTS_PYTHON_MEMBER(reverseSearch); ACTS_PYTHON_MEMBER(seedDeduplication); ACTS_PYTHON_MEMBER(stayOnSeed); - ACTS_PYTHON_MEMBER(pixelVolumes); - ACTS_PYTHON_MEMBER(stripVolumes); + ACTS_PYTHON_MEMBER(pixelVolumeIds); + ACTS_PYTHON_MEMBER(stripVolumeIds); ACTS_PYTHON_MEMBER(maxPixelHoles); ACTS_PYTHON_MEMBER(maxStripHoles); ACTS_PYTHON_MEMBER(trimTracks); + ACTS_PYTHON_MEMBER(constrainToVolumeIds); + ACTS_PYTHON_MEMBER(endOfWorldVolumeIds); ACTS_PYTHON_STRUCT_END(); } diff --git a/Examples/Scripts/Python/full_chain_itk.py b/Examples/Scripts/Python/full_chain_itk.py index 6231127096c..5e268f87fcb 100755 --- a/Examples/Scripts/Python/full_chain_itk.py +++ b/Examples/Scripts/Python/full_chain_itk.py @@ -126,8 +126,8 @@ seedDeduplication=True, stayOnSeed=True, # ITk volumes from Noemi's plot - pixelVolumes={8, 9, 10, 13, 14, 15, 16, 18, 19, 20}, - stripVolumes={22, 23, 24}, + pixelVolumes=[8, 9, 10, 13, 14, 15, 16, 18, 19, 20], + stripVolumes=[22, 23, 24], maxPixelHoles=1, maxStripHoles=2, ), diff --git a/Examples/Scripts/Python/full_chain_odd.py b/Examples/Scripts/Python/full_chain_odd.py index e76111da7ac..e6da5eee4dd 100755 --- a/Examples/Scripts/Python/full_chain_odd.py +++ b/Examples/Scripts/Python/full_chain_odd.py @@ -363,10 +363,27 @@ numMeasurementsCutOff=10, seedDeduplication=True, stayOnSeed=True, - pixelVolumes={16, 17, 18}, - stripVolumes={23, 24, 25}, + pixelVolumes=[16, 17, 18], + stripVolumes=[23, 24, 25], maxPixelHoles=1, maxStripHoles=2, + constrainToVolumes=[ + 2, # beam pipe + 32, + 4, # beam pip gap + 16, + 17, + 18, # pixel + 20, # PST + 23, + 24, + 25, # short strip + 26, + 8, # long strip gap + 28, + 29, + 30, # long strip + ], ), outputDirRoot=outputDir if args.output_root else None, outputDirCsv=outputDir if args.output_csv else None, diff --git a/Tests/UnitTests/Fatras/Kernel/SimulationActorTests.cpp b/Tests/UnitTests/Fatras/Kernel/SimulationActorTests.cpp index de87bf883c1..e52d586c30b 100644 --- a/Tests/UnitTests/Fatras/Kernel/SimulationActorTests.cpp +++ b/Tests/UnitTests/Fatras/Kernel/SimulationActorTests.cpp @@ -12,6 +12,7 @@ #include "Acts/Definitions/PdgParticle.hpp" #include "Acts/Definitions/Units.hpp" #include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/TrackingVolume.hpp" #include "Acts/Material/HomogeneousSurfaceMaterial.hpp" #include "Acts/Material/MaterialSlab.hpp" #include "Acts/Propagator/ConstrainedStep.hpp" @@ -148,6 +149,11 @@ struct MockNavigator { return state.currentSurface; } + const Acts::TrackingVolume *currentVolume( + const MockNavigatorState & /*state*/) const { + return nullptr; + } + bool endOfWorldReached(const MockNavigatorState & /*state*/) const { return false; } @@ -158,6 +164,10 @@ struct MockPropagatorState { MockStepperState stepping; Acts::GeometryContext geoContext; Acts::PropagatorStage stage = Acts::PropagatorStage::invalid; + + struct { + std::vector constrainToVolumeIds; + } options; }; template