From e006ab69d7b49bc510d4858c44df00891080aafe Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Wed, 4 Dec 2024 17:00:52 +0100 Subject: [PATCH 1/3] fix: Distinguish between hits and measurements in `ParticleSelector` in Examples --- .../TruthTracking/ParticleSelector.cpp | 43 +++++++++++++++---- .../TruthTracking/ParticleSelector.hpp | 11 ++++- .../Python/python/acts/examples/simulation.py | 3 ++ Examples/Python/src/TruthTracking.cpp | 2 + 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.cpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.cpp index b4ef0928da0..ac52c55d495 100644 --- a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.cpp +++ b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.cpp @@ -8,8 +8,8 @@ #include "ActsExamples/TruthTracking/ParticleSelector.hpp" -#include "Acts/Definitions/Common.hpp" #include "Acts/Utilities/VectorHelpers.hpp" +#include "ActsExamples/EventData/Index.hpp" #include "ActsExamples/EventData/SimParticle.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" @@ -17,8 +17,10 @@ #include #include -ActsExamples::ParticleSelector::ParticleSelector(const Config& config, - Acts::Logging::Level level) +namespace ActsExamples { + +ParticleSelector::ParticleSelector(const Config& config, + Acts::Logging::Level level) : IAlgorithm("ParticleSelector", level), m_cfg(config) { if (m_cfg.inputParticles.empty()) { throw std::invalid_argument("Missing input particles collection"); @@ -28,8 +30,17 @@ ActsExamples::ParticleSelector::ParticleSelector(const Config& config, } m_inputParticles.initialize(m_cfg.inputParticles); + m_inputParticleMeasurementsMap.maybeInitialize( + m_cfg.inputParticleMeasurementsMap); m_outputParticles.initialize(m_cfg.outputParticles); + if (m_inputParticleMeasurementsMap.isInitialized() && + (m_cfg.measurementsMin > 0 || + m_cfg.measurementsMax < std::numeric_limits::max())) { + throw std::invalid_argument( + "Measurement-based cuts require the inputMeasurementParticlesMap"); + } + ACTS_DEBUG("selection particle rho [" << m_cfg.rhoMin << "," << m_cfg.rhoMax << ")"); ACTS_DEBUG("selection particle |z| [" << m_cfg.absZMin << "," << m_cfg.absZMax @@ -46,6 +57,8 @@ ActsExamples::ParticleSelector::ParticleSelector(const Config& config, << ")"); ACTS_DEBUG("selection particle m [" << m_cfg.mMin << "," << m_cfg.mMax << ")"); + ACTS_DEBUG("selection particle hits [" << m_cfg.hitsMin << "," + << m_cfg.hitsMax << ")"); ACTS_DEBUG("selection particle measurements [" << m_cfg.measurementsMin << "," << m_cfg.measurementsMax << ")"); ACTS_DEBUG("remove charged particles " << m_cfg.removeCharged); @@ -59,12 +72,18 @@ ActsExamples::ParticleSelector::ParticleSelector(const Config& config, << m_cfg.maxPrimaryVertexId << ")"); } -ActsExamples::ProcessCode ActsExamples::ParticleSelector::execute( - const AlgorithmContext& ctx) const { +ProcessCode ParticleSelector::execute(const AlgorithmContext& ctx) const { // prepare input/ output types const SimParticleContainer& inputParticles = m_inputParticles(ctx); + const static InverseMultimap emptyMeasurementParticlesMap; + const InverseMultimap& inputMeasurementParticlesMap = + m_inputParticleMeasurementsMap.isInitialized() + ? m_inputParticleMeasurementsMap(ctx) + : emptyMeasurementParticlesMap; + std::size_t nInvalidCharge = 0; + std::size_t nInvalidHitCount = 0; std::size_t nInvalidMeasurementCount = 0; // helper functions to select tracks @@ -87,9 +106,14 @@ ActsExamples::ProcessCode ActsExamples::ParticleSelector::execute( nInvalidCharge += static_cast(!validCharge); - bool validMeasurementCount = - within(p.numberOfHits(), m_cfg.measurementsMin, m_cfg.measurementsMax); + const bool validHitCount = + within(p.numberOfHits(), m_cfg.hitsMin, m_cfg.hitsMax); + nInvalidHitCount += static_cast(!validHitCount); + const std::size_t measurementCount = + inputMeasurementParticlesMap.count(p.particleId()); + const bool validMeasurementCount = + within(measurementCount, m_cfg.measurementsMin, m_cfg.measurementsMax); nInvalidMeasurementCount += static_cast(!validMeasurementCount); @@ -103,7 +127,7 @@ ActsExamples::ProcessCode ActsExamples::ParticleSelector::execute( } return validPdg && validCharge && validSecondary && validPrimaryVertexId && - validMeasurementCount && + validHitCount && validMeasurementCount && within(p.transverseMomentum(), m_cfg.ptMin, m_cfg.ptMax) && within(std::abs(eta), m_cfg.absEtaMin, m_cfg.absEtaMax) && within(eta, m_cfg.etaMin, m_cfg.etaMax) && @@ -132,6 +156,7 @@ ActsExamples::ProcessCode ActsExamples::ParticleSelector::execute( << outputParticles.size() << " from " << inputParticles.size() << " particles"); ACTS_DEBUG("filtered out because of charge: " << nInvalidCharge); + ACTS_DEBUG("filtered out because of hit count: " << nInvalidHitCount); ACTS_DEBUG("filtered out because of measurement count: " << nInvalidMeasurementCount); @@ -139,3 +164,5 @@ ActsExamples::ProcessCode ActsExamples::ParticleSelector::execute( return ProcessCode::SUCCESS; } + +} // namespace ActsExamples diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.hpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.hpp index 4bd465d1b4d..4c57c5cbeef 100644 --- a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.hpp +++ b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.hpp @@ -9,6 +9,7 @@ #pragma once #include "Acts/Utilities/Logger.hpp" +#include "ActsExamples/EventData/Index.hpp" #include "ActsExamples/EventData/SimParticle.hpp" #include "ActsExamples/Framework/DataHandle.hpp" #include "ActsExamples/Framework/IAlgorithm.hpp" @@ -26,6 +27,9 @@ class ParticleSelector final : public IAlgorithm { struct Config { /// The input particles collection. std::string inputParticles; + /// (Optionally) The input particle measurements map. Only required for + /// measurement-based cuts. + std::string inputParticleMeasurementsMap; /// The output particles collection. std::string outputParticles; @@ -51,7 +55,10 @@ class ParticleSelector final : public IAlgorithm { // Rest mass cuts double mMin = 0; double mMax = std::numeric_limits::infinity(); - /// Measurement number cuts + // Hit count cuts + std::size_t hitsMin = 0; + std::size_t hitsMax = std::numeric_limits::max(); + // Measurement number cuts std::size_t measurementsMin = 0; std::size_t measurementsMax = std::numeric_limits::max(); /// Remove charged particles. @@ -81,6 +88,8 @@ class ParticleSelector final : public IAlgorithm { Config m_cfg; ReadDataHandle m_inputParticles{this, "InputParticles"}; + ReadDataHandle> m_inputParticleMeasurementsMap{ + this, "InputParticleMeasurementsMap"}; WriteDataHandle m_outputParticles{this, "OutputParticles"}; diff --git a/Examples/Python/python/acts/examples/simulation.py b/Examples/Python/python/acts/examples/simulation.py index 411f4410361..7e1f9cb009f 100644 --- a/Examples/Python/python/acts/examples/simulation.py +++ b/Examples/Python/python/acts/examples/simulation.py @@ -41,6 +41,7 @@ "absEta", # (min,max) "pt", # (min,max) "m", # (min,max) + "hits", # (min,max) "measurements", # (min,max) "removeCharged", # bool "removeNeutral", # bool @@ -393,6 +394,8 @@ def addParticleSelection( ptMax=config.pt[1], mMin=config.m[0], mMax=config.m[1], + hitsMin=config.hits[0], + hitsMax=config.hits[1], measurementsMin=config.measurements[0], measurementsMax=config.measurements[1], removeCharged=config.removeCharged, diff --git a/Examples/Python/src/TruthTracking.cpp b/Examples/Python/src/TruthTracking.cpp index 4799d93dbdb..4d3569f4656 100644 --- a/Examples/Python/src/TruthTracking.cpp +++ b/Examples/Python/src/TruthTracking.cpp @@ -84,6 +84,8 @@ void addTruthTracking(Context& ctx) { ACTS_PYTHON_MEMBER(mMax); ACTS_PYTHON_MEMBER(ptMin); ACTS_PYTHON_MEMBER(ptMax); + ACTS_PYTHON_MEMBER(hitsMin); + ACTS_PYTHON_MEMBER(hitsMax); ACTS_PYTHON_MEMBER(measurementsMin); ACTS_PYTHON_MEMBER(measurementsMax); ACTS_PYTHON_MEMBER(removeCharged); From df40a9d69a917e370516db2429f42f0d1db9b144 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Fri, 6 Dec 2024 09:26:06 +0100 Subject: [PATCH 2/3] fix default; replace measurement cuts with hit cuts --- CI/physmon/workflows/physmon_trackfinding_1muon.py | 2 +- CI/physmon/workflows/physmon_trackfinding_4muon_50vertices.py | 2 +- CI/physmon/workflows/physmon_trackfinding_ttbar_pu200.py | 2 +- Examples/Python/python/acts/examples/simulation.py | 2 +- Examples/Python/tests/test_examples.py | 2 +- Examples/Scripts/Optimization/ckf.py | 2 +- Examples/Scripts/Python/ckf_tracks.py | 2 +- Examples/Scripts/Python/full_chain_itk.py | 2 +- Examples/Scripts/Python/full_chain_itk_Gbts.py | 2 +- Examples/Scripts/Python/full_chain_odd.py | 4 ++-- Examples/Scripts/Python/full_chain_odd_LRT.py | 4 ++-- Examples/Scripts/Python/full_chain_test.py | 2 +- Examples/Scripts/Python/hashing_seeding.py | 2 +- Examples/Scripts/Python/seeding.py | 2 +- Examples/Scripts/Python/truth_tracking_gsf.py | 2 +- Examples/Scripts/Python/truth_tracking_gx2f.py | 2 +- Examples/Scripts/Python/truth_tracking_kalman.py | 2 +- 17 files changed, 19 insertions(+), 19 deletions(-) diff --git a/CI/physmon/workflows/physmon_trackfinding_1muon.py b/CI/physmon/workflows/physmon_trackfinding_1muon.py index 90305112099..028b30ce5e5 100755 --- a/CI/physmon/workflows/physmon_trackfinding_1muon.py +++ b/CI/physmon/workflows/physmon_trackfinding_1muon.py @@ -74,7 +74,7 @@ def run_ckf_tracking(label, seeding): rnd=rnd, postSelectParticles=ParticleSelectorConfig( pt=(0.9 * u.GeV, None), - measurements=(9, None), + hits=(9, None), removeNeutral=True, ), ) diff --git a/CI/physmon/workflows/physmon_trackfinding_4muon_50vertices.py b/CI/physmon/workflows/physmon_trackfinding_4muon_50vertices.py index 1a119c8ed6c..85debced2b4 100755 --- a/CI/physmon/workflows/physmon_trackfinding_4muon_50vertices.py +++ b/CI/physmon/workflows/physmon_trackfinding_4muon_50vertices.py @@ -71,7 +71,7 @@ rnd=rnd, postSelectParticles=ParticleSelectorConfig( pt=(0.9 * u.GeV, None), - measurements=(9, None), + hits=(9, None), removeNeutral=True, ), ) diff --git a/CI/physmon/workflows/physmon_trackfinding_ttbar_pu200.py b/CI/physmon/workflows/physmon_trackfinding_ttbar_pu200.py index 4b4c75e1f36..de4021a5055 100755 --- a/CI/physmon/workflows/physmon_trackfinding_ttbar_pu200.py +++ b/CI/physmon/workflows/physmon_trackfinding_ttbar_pu200.py @@ -71,7 +71,7 @@ ), postSelectParticles=ParticleSelectorConfig( pt=(0.5 * u.GeV, None), - measurements=(9, None), + hits=(9, None), removeNeutral=True, ), ) diff --git a/Examples/Python/python/acts/examples/simulation.py b/Examples/Python/python/acts/examples/simulation.py index 7e1f9cb009f..ff690e2a777 100644 --- a/Examples/Python/python/acts/examples/simulation.py +++ b/Examples/Python/python/acts/examples/simulation.py @@ -47,7 +47,7 @@ "removeNeutral", # bool "removeSecondaries", # bool ], - defaults=[(None, None)] * 9 + [None] * 3, + defaults=[(None, None)] * 10 + [None] * 3, ) diff --git a/Examples/Python/tests/test_examples.py b/Examples/Python/tests/test_examples.py index 2261e58cea4..8441514c26b 100644 --- a/Examples/Python/tests/test_examples.py +++ b/Examples/Python/tests/test_examples.py @@ -427,7 +427,7 @@ def test_itk_seeding(tmp_path, trk_geo, field, assert_root_hash): postSelectParticles=ParticleSelectorConfig( pt=(0.9 * u.GeV, None), eta=(-4, 4), - measurements=(9, None), + hits=(9, None), removeNeutral=True, ), ) diff --git a/Examples/Scripts/Optimization/ckf.py b/Examples/Scripts/Optimization/ckf.py index e0cd5fd9870..0077f35317b 100755 --- a/Examples/Scripts/Optimization/ckf.py +++ b/Examples/Scripts/Optimization/ckf.py @@ -171,7 +171,7 @@ def runCKFTracks( rnd=rnd, postSelectParticles=ParticleSelectorConfig( pt=(0.5 * u.GeV, None), - measurements=(9, None), + hits=(9, None), removeNeutral=True, ), ) diff --git a/Examples/Scripts/Python/ckf_tracks.py b/Examples/Scripts/Python/ckf_tracks.py index 75ec8a7c316..15a50466799 100755 --- a/Examples/Scripts/Python/ckf_tracks.py +++ b/Examples/Scripts/Python/ckf_tracks.py @@ -82,7 +82,7 @@ def runCKFTracks( rnd=rnd, postSelectParticles=ParticleSelectorConfig( pt=(0.5 * u.GeV, None), - measurements=(9, None), + hits=(9, None), removeNeutral=True, ), ) diff --git a/Examples/Scripts/Python/full_chain_itk.py b/Examples/Scripts/Python/full_chain_itk.py index b5c17278a1e..afb1df6a12b 100755 --- a/Examples/Scripts/Python/full_chain_itk.py +++ b/Examples/Scripts/Python/full_chain_itk.py @@ -74,7 +74,7 @@ postSelectParticles=ParticleSelectorConfig( pt=(1.0 * u.GeV, None), eta=(-4.0, 4.0), - measurements=(9, None), + hits=(9, None), removeNeutral=True, ), outputDirRoot=outputDir, diff --git a/Examples/Scripts/Python/full_chain_itk_Gbts.py b/Examples/Scripts/Python/full_chain_itk_Gbts.py index ac9cc8ae8fc..a939bd7e930 100755 --- a/Examples/Scripts/Python/full_chain_itk_Gbts.py +++ b/Examples/Scripts/Python/full_chain_itk_Gbts.py @@ -69,7 +69,7 @@ postSelectParticles=ParticleSelectorConfig( pt=(1.0 * u.GeV, None), eta=(-4.0, 4.0), - measurements=(9, None), + hits=(9, None), removeNeutral=True, ), outputDirRoot=outputDir, diff --git a/Examples/Scripts/Python/full_chain_odd.py b/Examples/Scripts/Python/full_chain_odd.py index 7ddaa02054f..50a13219afa 100755 --- a/Examples/Scripts/Python/full_chain_odd.py +++ b/Examples/Scripts/Python/full_chain_odd.py @@ -278,7 +278,7 @@ postSelectParticles=ParticleSelectorConfig( pt=(1.0 * u.GeV, None), eta=(-3.0, 3.0), - measurements=(9, None), + hits=(9, None), removeNeutral=True, ), outputDirRoot=outputDir if args.output_root else None, @@ -306,7 +306,7 @@ postSelectParticles=ParticleSelectorConfig( pt=(1.0 * u.GeV, None), eta=(-3.0, 3.0), - measurements=(9, None), + hits=(9, None), removeNeutral=True, ), enableInteractions=True, diff --git a/Examples/Scripts/Python/full_chain_odd_LRT.py b/Examples/Scripts/Python/full_chain_odd_LRT.py index cfa03b5336c..57f7ce85876 100644 --- a/Examples/Scripts/Python/full_chain_odd_LRT.py +++ b/Examples/Scripts/Python/full_chain_odd_LRT.py @@ -273,7 +273,7 @@ postSelectParticles=ParticleSelectorConfig( pt=(1.0 * u.GeV, None), eta=(-3.0, 3.0), - measurements=(9, None), + hits=(9, None), removeNeutral=True, ), outputDirRoot=outputDir if args.output_root else None, @@ -300,7 +300,7 @@ postSelectParticles=ParticleSelectorConfig( pt=(1.0 * u.GeV, None), eta=(-3.0, 3.0), - measurements=(9, None), + hits=(9, None), removeNeutral=True, ), enableInteractions=True, diff --git a/Examples/Scripts/Python/full_chain_test.py b/Examples/Scripts/Python/full_chain_test.py index 595dbd43a4e..49d7dacfeed 100755 --- a/Examples/Scripts/Python/full_chain_test.py +++ b/Examples/Scripts/Python/full_chain_test.py @@ -370,7 +370,7 @@ def full_chain(args): postSelectParticles = ParticleSelectorConfig( pt=(ptMin, None), eta=etaRange if not args.generic_detector else (None, None), - measurements=(9, None), + hits=(9, None), removeNeutral=True, ) diff --git a/Examples/Scripts/Python/hashing_seeding.py b/Examples/Scripts/Python/hashing_seeding.py index 770c34e5185..10f68b5cea9 100755 --- a/Examples/Scripts/Python/hashing_seeding.py +++ b/Examples/Scripts/Python/hashing_seeding.py @@ -215,7 +215,7 @@ def runHashingSeeding( postSelectParticles=ParticleSelectorConfig( pt=(1.0 * u.GeV, None), eta=(-eta, eta), - measurements=(9, None), + hits=(9, None), removeNeutral=True, ), enableInteractions=True, diff --git a/Examples/Scripts/Python/seeding.py b/Examples/Scripts/Python/seeding.py index 3beb6071aae..1e5b9e50d6b 100755 --- a/Examples/Scripts/Python/seeding.py +++ b/Examples/Scripts/Python/seeding.py @@ -90,7 +90,7 @@ def runSeeding( postSelectParticles=ParticleSelectorConfig( pt=(1.0 * u.GeV, None), eta=(-2.5, 2.5), - measurements=(9, None), + hits=(9, None), removeNeutral=True, ), ) diff --git a/Examples/Scripts/Python/truth_tracking_gsf.py b/Examples/Scripts/Python/truth_tracking_gsf.py index ae8aca06d6c..4f194a65662 100755 --- a/Examples/Scripts/Python/truth_tracking_gsf.py +++ b/Examples/Scripts/Python/truth_tracking_gsf.py @@ -79,7 +79,7 @@ def runTruthTrackingGsf( enableInteractions=True, postSelectParticles=ParticleSelectorConfig( pt=(0.9 * u.GeV, None), - measurements=(7, None), + hits=(7, None), removeNeutral=True, removeSecondaries=True, ), diff --git a/Examples/Scripts/Python/truth_tracking_gx2f.py b/Examples/Scripts/Python/truth_tracking_gx2f.py index 8503dc982f4..31ebb447d42 100644 --- a/Examples/Scripts/Python/truth_tracking_gx2f.py +++ b/Examples/Scripts/Python/truth_tracking_gx2f.py @@ -76,7 +76,7 @@ def runTruthTrackingGx2f( enableInteractions=True, postSelectParticles=ParticleSelectorConfig( pt=(0.9 * u.GeV, None), - measurements=(7, None), + hits=(7, None), removeNeutral=True, removeSecondaries=True, ), diff --git a/Examples/Scripts/Python/truth_tracking_kalman.py b/Examples/Scripts/Python/truth_tracking_kalman.py index 91c18f1dd28..971f0c4bab4 100755 --- a/Examples/Scripts/Python/truth_tracking_kalman.py +++ b/Examples/Scripts/Python/truth_tracking_kalman.py @@ -84,7 +84,7 @@ def runTruthTrackingKalman( enableInteractions=True, postSelectParticles=ParticleSelectorConfig( pt=(0.9 * u.GeV, None), - measurements=(7, None), + hits=(7, None), removeNeutral=True, removeSecondaries=True, ), From 1dcdc906d789080001d1c5a5d5912463301b48b8 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Fri, 6 Dec 2024 09:45:45 +0100 Subject: [PATCH 3/3] Apply suggestions from code review --- .../ActsExamples/TruthTracking/ParticleSelector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.cpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.cpp index ac52c55d495..6896763f32c 100644 --- a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.cpp +++ b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.cpp @@ -34,7 +34,7 @@ ParticleSelector::ParticleSelector(const Config& config, m_cfg.inputParticleMeasurementsMap); m_outputParticles.initialize(m_cfg.outputParticles); - if (m_inputParticleMeasurementsMap.isInitialized() && + if (!m_inputParticleMeasurementsMap.isInitialized() && (m_cfg.measurementsMin > 0 || m_cfg.measurementsMax < std::numeric_limits::max())) { throw std::invalid_argument(