From 1701308e2f852e48fd379d7c887c2efec8fc36df Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Wed, 27 Nov 2024 13:13:35 +0100 Subject: [PATCH 01/12] refactor: Reworked `HitSelector` in Examples (#3836) The motivations is that one can select hits to constrain the reconstruction to a subset of them. This can be especially useful for studies which look at different pile-up. Pile-up vertices have consecutive primary vertex IDs so one can simulate for example pile-up 200 and then reconstruct only a subset of them. Bocked by - https://github.com/acts-project/acts/pull/3837 ## Summary by CodeRabbit - **New Features** - Introduced the `HitSelector` class for enhanced hit selection based on various criteria such as position, time, energy loss, and primary vertex ID. - Added new parameters to the `HitSelector` algorithm, allowing for more comprehensive filtering of hits. - **Bug Fixes** - Improved validation logic in the `ParticleSelector` class to include primary vertex ID checks. - **Documentation** - Updated header files to reflect the new structure and functionality of the `HitSelector`. - **Chores** - Removed outdated `HitSelector` files from the utilities library to streamline the codebase. --- .../TruthTracking/HitSelector.cpp | 97 +++++++++++++++++++ .../TruthTracking/HitSelector.hpp | 86 ++++++++++++++++ .../TruthTracking/ParticleSelector.cpp | 14 ++- .../TruthTracking/ParticleSelector.hpp | 6 ++ .../Algorithms/TruthTracking/CMakeLists.txt | 1 + Examples/Algorithms/Utilities/CMakeLists.txt | 1 - .../ActsExamples/Utilities/HitSelector.hpp | 50 ---------- .../Algorithms/Utilities/src/HitSelector.cpp | 33 ------- Examples/Python/src/TruthTracking.cpp | 11 ++- 9 files changed, 212 insertions(+), 87 deletions(-) create mode 100644 Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/HitSelector.cpp create mode 100644 Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/HitSelector.hpp delete mode 100644 Examples/Algorithms/Utilities/include/ActsExamples/Utilities/HitSelector.hpp delete mode 100644 Examples/Algorithms/Utilities/src/HitSelector.cpp diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/HitSelector.cpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/HitSelector.cpp new file mode 100644 index 00000000000..a494957a589 --- /dev/null +++ b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/HitSelector.cpp @@ -0,0 +1,97 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "ActsExamples/TruthTracking/HitSelector.hpp" + +#include "Acts/Utilities/MathHelpers.hpp" +#include "ActsExamples/EventData/SimHit.hpp" +#include "ActsExamples/EventData/SimParticle.hpp" + +namespace ActsExamples { + +HitSelector::HitSelector(const Config& config, Acts::Logging::Level level) + : IAlgorithm("HitSelector", level), m_cfg(config) { + if (m_cfg.minX >= m_cfg.maxX || m_cfg.minY >= m_cfg.maxY || + m_cfg.minZ >= m_cfg.maxZ || m_cfg.minR >= m_cfg.maxR || + m_cfg.minTime >= m_cfg.maxTime || + m_cfg.minEnergyLoss >= m_cfg.maxEnergyLoss || + m_cfg.minPrimaryVertexId >= m_cfg.maxPrimaryVertexId) { + throw std::invalid_argument( + "Invalid bounds configuration: min values must be less than max " + "values"); + } + m_inputHits.initialize(m_cfg.inputHits); + m_inputParticlesSelected.maybeInitialize(m_cfg.inputParticlesSelected); + m_outputHits.initialize(m_cfg.outputHits); + + ACTS_DEBUG("selection particles " << m_cfg.inputParticlesSelected); + ACTS_DEBUG("selection hit x [" << m_cfg.minX << "," << m_cfg.maxX << ")"); + ACTS_DEBUG("selection hit y [" << m_cfg.minY << "," << m_cfg.maxY << ")"); + ACTS_DEBUG("selection hit z [" << m_cfg.minZ << "," << m_cfg.maxZ << ")"); + ACTS_DEBUG("selection hit r [" << m_cfg.minR << "," << m_cfg.maxR << ")"); + ACTS_DEBUG("selection hit time [" << m_cfg.minTime << "," << m_cfg.maxTime + << ")"); + ACTS_DEBUG("selection hit energy loss [" << m_cfg.minEnergyLoss << "," + << m_cfg.maxEnergyLoss << ")"); + ACTS_DEBUG("selection primary vertex ID [" << m_cfg.minPrimaryVertexId << "," + << m_cfg.maxPrimaryVertexId + << ")"); +} + +ProcessCode HitSelector::execute(const AlgorithmContext& ctx) const { + const SimHitContainer& hits = m_inputHits(ctx); + const SimParticleContainer* particlesSelected = + m_inputParticlesSelected.isInitialized() ? &m_inputParticlesSelected(ctx) + : nullptr; + + std::vector unorderedHits; + unorderedHits.reserve(hits.size()); + + for (const auto& hit : hits) { + const double r = Acts::fastHypot(hit.position().x(), hit.position().y()); + const std::uint64_t primaryVertexId = hit.particleId().vertexPrimary(); + + const bool validParticle = (particlesSelected == nullptr) || + particlesSelected->contains(hit.particleId()); + const bool validX = + (m_cfg.minX <= hit.position().x()) && (hit.position().x() < m_cfg.maxX); + const bool validY = + (m_cfg.minY <= hit.position().y()) && (hit.position().y() < m_cfg.maxY); + const bool validZ = + (m_cfg.minZ <= hit.position().z()) && (hit.position().z() < m_cfg.maxZ); + const bool validR = (m_cfg.minR <= r) && (r < m_cfg.maxR); + const bool validTime = + (m_cfg.minTime <= hit.time()) && (hit.time() < m_cfg.maxTime); + const bool validEnergyLoss = + (m_cfg.minEnergyLoss <= hit.depositedEnergy()) && + (hit.depositedEnergy() < m_cfg.maxEnergyLoss); + const bool validPrimaryVertexId = + (m_cfg.minPrimaryVertexId <= primaryVertexId) && + (primaryVertexId < m_cfg.maxPrimaryVertexId); + + const bool validHit = validParticle && validX && validY && validZ && + validR && validTime && validEnergyLoss && + validPrimaryVertexId; + if (validHit) { + unorderedHits.push_back(hit); + } + } + + // hits are still sorted after filtering + SimHitContainer selectedHits(boost::container::ordered_range_t{}, + unorderedHits.begin(), unorderedHits.end()); + + ACTS_DEBUG("selected " << selectedHits.size() << " from " << hits.size() + << " hits"); + + m_outputHits(ctx, std::move(selectedHits)); + + return ProcessCode::SUCCESS; +} + +} // namespace ActsExamples diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/HitSelector.hpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/HitSelector.hpp new file mode 100644 index 00000000000..37a4e8131ec --- /dev/null +++ b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/HitSelector.hpp @@ -0,0 +1,86 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/Utilities/Logger.hpp" +#include "ActsExamples/EventData/SimHit.hpp" +#include "ActsExamples/EventData/SimParticle.hpp" +#include "ActsExamples/Framework/DataHandle.hpp" +#include "ActsExamples/Framework/IAlgorithm.hpp" + +#include +#include + +namespace ActsExamples { + +/// Select hits by applying some selection cuts. +class HitSelector final : public IAlgorithm { + public: + struct Config { + /// Input hit collection. + std::string inputHits; + /// Optional input particle collection. + std::string inputParticlesSelected; + /// Output hit collection + std::string outputHits; + + /// Min x cut + double minX = -std::numeric_limits::max(); + /// Max x cut + double maxX = std::numeric_limits::max(); + + /// Min y cut + double minY = -std::numeric_limits::max(); + /// Max y cut + double maxY = std::numeric_limits::max(); + + /// Min z cut + double minZ = -std::numeric_limits::max(); + /// Max z cut + double maxZ = std::numeric_limits::max(); + + /// Min r cut + double minR = 0.0; + /// Max r cut + double maxR = std::numeric_limits::max(); + + /// Min time cut + double minTime = -std::numeric_limits::max(); + /// Max time cut + double maxTime = std::numeric_limits::max(); + + /// Min energy loss cut + double minEnergyLoss = 0; + /// Max energy loss cut + double maxEnergyLoss = std::numeric_limits::max(); + + /// Min primary vertex ID cut + std::uint64_t minPrimaryVertexId = 0; + /// Max primary vertex ID cut + std::uint64_t maxPrimaryVertexId = + std::numeric_limits::max(); + }; + + HitSelector(const Config& config, Acts::Logging::Level level); + + ProcessCode execute(const AlgorithmContext& ctx) const final; + + /// Get readonly access to the config parameters + const Config& config() const { return m_cfg; } + + private: + Config m_cfg; + + ReadDataHandle m_inputHits{this, "InputHits"}; + ReadDataHandle m_inputParticlesSelected{ + this, "InputParticlesSelected"}; + WriteDataHandle m_outputHits{this, "OutputHits"}; +}; + +} // namespace ActsExamples diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.cpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.cpp index 738399a1e42..b4ef0928da0 100644 --- a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.cpp +++ b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.cpp @@ -46,9 +46,17 @@ ActsExamples::ParticleSelector::ParticleSelector(const Config& config, << ")"); ACTS_DEBUG("selection particle m [" << m_cfg.mMin << "," << m_cfg.mMax << ")"); + ACTS_DEBUG("selection particle measurements [" + << m_cfg.measurementsMin << "," << m_cfg.measurementsMax << ")"); ACTS_DEBUG("remove charged particles " << m_cfg.removeCharged); ACTS_DEBUG("remove neutral particles " << m_cfg.removeNeutral); ACTS_DEBUG("remove secondary particles " << m_cfg.removeSecondaries); + ACTS_DEBUG("exclude pdgs: "); + for (auto pdg : m_cfg.excludeAbsPdgs) { + ACTS_DEBUG(" " << pdg); + } + ACTS_DEBUG("primary vertex ID [" << m_cfg.minPrimaryVertexId << "," + << m_cfg.maxPrimaryVertexId << ")"); } ActsExamples::ProcessCode ActsExamples::ParticleSelector::execute( @@ -73,6 +81,9 @@ ActsExamples::ProcessCode ActsExamples::ParticleSelector::execute( const bool validCharged = (p.charge() != 0) && !m_cfg.removeCharged; const bool validCharge = validNeutral || validCharged; const bool validSecondary = !m_cfg.removeSecondaries || !p.isSecondary(); + const bool validPrimaryVertexId = + within(p.particleId().vertexPrimary(), m_cfg.minPrimaryVertexId, + m_cfg.maxPrimaryVertexId); nInvalidCharge += static_cast(!validCharge); @@ -91,7 +102,8 @@ ActsExamples::ProcessCode ActsExamples::ParticleSelector::execute( } } - return validPdg && validCharge && validSecondary && validMeasurementCount && + return validPdg && validCharge && validSecondary && validPrimaryVertexId && + 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) && diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.hpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.hpp index 78326844f19..4bd465d1b4d 100644 --- a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.hpp +++ b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.hpp @@ -62,6 +62,12 @@ class ParticleSelector final : public IAlgorithm { bool removeSecondaries = false; /// Exclude particles depending on absolute pdg value std::vector excludeAbsPdgs; + + /// Min primary vertex ID cut + std::uint64_t minPrimaryVertexId = 0; + /// Max primary vertex ID cut + std::uint64_t maxPrimaryVertexId = + std::numeric_limits::max(); }; ParticleSelector(const Config& config, Acts::Logging::Level level); diff --git a/Examples/Algorithms/TruthTracking/CMakeLists.txt b/Examples/Algorithms/TruthTracking/CMakeLists.txt index 4594cdb7480..280e1104ce2 100644 --- a/Examples/Algorithms/TruthTracking/CMakeLists.txt +++ b/Examples/Algorithms/TruthTracking/CMakeLists.txt @@ -9,6 +9,7 @@ add_library( ActsExamples/TruthTracking/TruthTrackFinder.cpp ActsExamples/TruthTracking/TruthVertexFinder.cpp ActsExamples/TruthTracking/TruthSeedingAlgorithm.cpp + ActsExamples/TruthTracking/HitSelector.cpp ) target_include_directories( ActsExamplesTruthTracking diff --git a/Examples/Algorithms/Utilities/CMakeLists.txt b/Examples/Algorithms/Utilities/CMakeLists.txt index ba9419c1914..309ff662bc6 100644 --- a/Examples/Algorithms/Utilities/CMakeLists.txt +++ b/Examples/Algorithms/Utilities/CMakeLists.txt @@ -7,7 +7,6 @@ add_library( src/TrackSelectorAlgorithm.cpp src/TracksToTrajectories.cpp src/PrototracksToTracks.cpp - src/HitSelector.cpp src/TracksToParameters.cpp ) target_include_directories( diff --git a/Examples/Algorithms/Utilities/include/ActsExamples/Utilities/HitSelector.hpp b/Examples/Algorithms/Utilities/include/ActsExamples/Utilities/HitSelector.hpp deleted file mode 100644 index bb1f7ba24e8..00000000000 --- a/Examples/Algorithms/Utilities/include/ActsExamples/Utilities/HitSelector.hpp +++ /dev/null @@ -1,50 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -#pragma once - -#include "Acts/TrackFinding/TrackSelector.hpp" -#include "Acts/Utilities/Logger.hpp" -#include "ActsExamples/EventData/SimHit.hpp" -#include "ActsExamples/Framework/DataHandle.hpp" -#include "ActsExamples/Framework/IAlgorithm.hpp" - -#include -#include -#include - -namespace ActsExamples { - -/// Select tracks by applying some selection cuts. -class HitSelector final : public IAlgorithm { - public: - struct Config { - /// Input track collection. - std::string inputHits; - /// Output track collection - std::string outputHits; - - /// Time cut - double maxTime = std::numeric_limits::max(); - }; - - HitSelector(const Config& config, Acts::Logging::Level level); - - ProcessCode execute(const AlgorithmContext& ctx) const final; - - /// Get readonly access to the config parameters - const Config& config() const { return m_cfg; } - - private: - Config m_cfg; - - ReadDataHandle m_inputHits{this, "InputHits"}; - WriteDataHandle m_outputHits{this, "OutputHits"}; -}; - -} // namespace ActsExamples diff --git a/Examples/Algorithms/Utilities/src/HitSelector.cpp b/Examples/Algorithms/Utilities/src/HitSelector.cpp deleted file mode 100644 index c9a33b5f65a..00000000000 --- a/Examples/Algorithms/Utilities/src/HitSelector.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -#include "ActsExamples/Utilities/HitSelector.hpp" - -ActsExamples::HitSelector::HitSelector(const Config& config, - Acts::Logging::Level level) - : IAlgorithm("HitSelector", level), m_cfg(config) { - m_inputHits.initialize(m_cfg.inputHits); - m_outputHits.initialize(m_cfg.outputHits); -} - -ActsExamples::ProcessCode ActsExamples::HitSelector::execute( - const ActsExamples::AlgorithmContext& ctx) const { - const auto& hits = m_inputHits(ctx); - SimHitContainer selectedHits; - - std::copy_if(hits.begin(), hits.end(), - std::inserter(selectedHits, selectedHits.begin()), - [&](const auto& hit) { return hit.time() < m_cfg.maxTime; }); - - ACTS_DEBUG("selected " << selectedHits.size() << " from " << hits.size() - << " hits"); - - m_outputHits(ctx, std::move(selectedHits)); - - return {}; -} diff --git a/Examples/Python/src/TruthTracking.cpp b/Examples/Python/src/TruthTracking.cpp index 3f0d8a0915a..1502ce23d40 100644 --- a/Examples/Python/src/TruthTracking.cpp +++ b/Examples/Python/src/TruthTracking.cpp @@ -8,6 +8,7 @@ #include "Acts/Plugins/Python/Utilities.hpp" #include "Acts/Utilities/Logger.hpp" +#include "ActsExamples/TruthTracking/HitSelector.hpp" #include "ActsExamples/TruthTracking/ParticleSelector.hpp" #include "ActsExamples/TruthTracking/ParticleSmearing.hpp" #include "ActsExamples/TruthTracking/TrackModifier.hpp" @@ -16,7 +17,6 @@ #include "ActsExamples/TruthTracking/TruthSeedingAlgorithm.hpp" #include "ActsExamples/TruthTracking/TruthTrackFinder.hpp" #include "ActsExamples/TruthTracking/TruthVertexFinder.hpp" -#include "ActsExamples/Utilities/HitSelector.hpp" #include @@ -85,6 +85,8 @@ void addTruthTracking(Context& ctx) { ACTS_PYTHON_MEMBER(removeNeutral); ACTS_PYTHON_MEMBER(removeSecondaries); ACTS_PYTHON_MEMBER(excludeAbsPdgs); + ACTS_PYTHON_MEMBER(minPrimaryVertexId); + ACTS_PYTHON_MEMBER(maxPrimaryVertexId); ACTS_PYTHON_STRUCT_END(); pythonRangeProperty(c, "rho", &Config::rhoMin, &Config::rhoMax); @@ -97,6 +99,8 @@ void addTruthTracking(Context& ctx) { pythonRangeProperty(c, "pt", &Config::ptMin, &Config::ptMax); pythonRangeProperty(c, "measurements", &Config::measurementsMin, &Config::measurementsMax); + pythonRangeProperty(c, "primaryVertexId", &Config::minPrimaryVertexId, + &Config::maxPrimaryVertexId); } { @@ -154,7 +158,10 @@ void addTruthTracking(Context& ctx) { outputParticles, outputSeeds, outputProtoTracks, deltaRMin, deltaRMax); ACTS_PYTHON_DECLARE_ALGORITHM(ActsExamples::HitSelector, mex, "HitSelector", - inputHits, outputHits, maxTime); + inputHits, inputParticlesSelected, outputHits, + minX, maxX, minY, maxY, minZ, maxZ, minR, maxR, + minTime, maxTime, minEnergyLoss, maxEnergyLoss, + minPrimaryVertexId, maxPrimaryVertexId); ACTS_PYTHON_DECLARE_ALGORITHM( ActsExamples::TrackTruthMatcher, mex, "TrackTruthMatcher", inputTracks, From 2e74ffa18582100f63d17a884deab288dcd6a996 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Wed, 27 Nov 2024 14:41:40 +0100 Subject: [PATCH 02/12] feat: Allow copy of measurements in Examples (#3911) Adds new capabilities to the Examples' measurement container: copy measurements from one container to the other. pulled out of https://github.com/acts-project/acts/pull/3836 ## Summary by CodeRabbit - **New Features** - Introduced new template methods in the `MeasurementContainer` class for copying measurements, enhancing usability for measurement duplication. - **Bug Fixes** - Removed unnecessary include directives to simplify dependencies. - **Documentation** - Updated concept checks in `MeasurementConcept` to ensure compliance with new measurement requirements. --- .../ActsExamples/EventData/Measurement.hpp | 30 +++++++++++++------ .../EventData/MeasurementConcept.hpp | 2 +- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Examples/Framework/include/ActsExamples/EventData/Measurement.hpp b/Examples/Framework/include/ActsExamples/EventData/Measurement.hpp index ab232628341..174dc05ef40 100644 --- a/Examples/Framework/include/ActsExamples/EventData/Measurement.hpp +++ b/Examples/Framework/include/ActsExamples/EventData/Measurement.hpp @@ -10,25 +10,16 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/EventData/MeasurementHelpers.hpp" #include "Acts/EventData/SubspaceHelpers.hpp" #include "Acts/EventData/Types.hpp" -#include "Acts/EventData/detail/ParameterTraits.hpp" -#include "Acts/EventData/detail/PrintParameters.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" #include "Acts/Utilities/Iterator.hpp" #include "ActsExamples/EventData/GeometryContainers.hpp" #include "ActsExamples/EventData/IndexSourceLink.hpp" #include "ActsExamples/EventData/MeasurementConcept.hpp" -#include -#include -#include #include -#include -#include #include -#include #include #include @@ -138,6 +129,11 @@ class MeasurementContainer { return getMeasurement(addMeasurement(Size, geometryId)); } + template + VariableProxy copyMeasurement(const OtherDerived& other); + template + FixedProxy copyMeasurement(const OtherDerived& other); + template VariableProxy emplaceMeasurement(std::uint8_t size, Acts::GeometryIdentifier geometryId, @@ -494,6 +490,22 @@ class VariableMeasurementProxy } }; +template +MeasurementContainer::VariableProxy MeasurementContainer::copyMeasurement( + const OtherDerived& other) { + VariableProxy meas = makeMeasurement(other.size(), other.geometryId()); + meas.copyFrom(other); + return meas; +} + +template +MeasurementContainer::FixedProxy MeasurementContainer::copyMeasurement( + const OtherDerived& other) { + FixedProxy meas = makeMeasurement(other.geometryId()); + meas.copyFrom(other); + return meas; +} + template MeasurementContainer::VariableProxy MeasurementContainer::emplaceMeasurement( std::uint8_t size, Acts::GeometryIdentifier geometryId, Args&&... args) { diff --git a/Examples/Framework/include/ActsExamples/EventData/MeasurementConcept.hpp b/Examples/Framework/include/ActsExamples/EventData/MeasurementConcept.hpp index 14627a78c53..9394b1bf992 100644 --- a/Examples/Framework/include/ActsExamples/EventData/MeasurementConcept.hpp +++ b/Examples/Framework/include/ActsExamples/EventData/MeasurementConcept.hpp @@ -8,7 +8,6 @@ #pragma once -#include "Acts/EventData/SourceLink.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" #include @@ -23,4 +22,5 @@ concept MeasurementConcept = requires(const T& m) { { m.parameters() }; { m.covariance() }; }; + } // namespace ActsExamples From 98acf9004a4ed50d0b77ce1da415514d289e12d8 Mon Sep 17 00:00:00 2001 From: "Alexander J. Pfleger" <70842573+AJPfleger@users.noreply.github.com> Date: Wed, 27 Nov 2024 17:07:15 +0100 Subject: [PATCH 03/12] chore: replace some couts with logger (#3912) ## Summary by CodeRabbit - **Bug Fixes** - Improved logging consistency by replacing standard output with structured logging mechanisms across multiple classes. - Corrected minor typographical errors in comments for clarity. - **Documentation** - Enhanced comment clarity and formatting for better readability in the codebase. --- .../TrackFinding/src/MuonHoughSeeder.cpp | 18 ++++++++---------- Examples/Io/EDM4hep/src/EDM4hepReader.cpp | 4 ++-- .../Io/Root/src/RootMaterialTrackReader.cpp | 3 --- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/Examples/Algorithms/TrackFinding/src/MuonHoughSeeder.cpp b/Examples/Algorithms/TrackFinding/src/MuonHoughSeeder.cpp index b074d14ab91..dda3349d254 100644 --- a/Examples/Algorithms/TrackFinding/src/MuonHoughSeeder.cpp +++ b/Examples/Algorithms/TrackFinding/src/MuonHoughSeeder.cpp @@ -88,10 +88,9 @@ ActsExamples::ProcessCode ActsExamples::MuonHoughSeeder::execute( // create the function parametrising the drift radius uncertainty auto houghWidth_fromDC = [](double, const DriftCircle& DC) { - return std::min(DC.rDriftError() * 3., - 1.0); // scale reported errors up to at least 1mm or 3 - // times the reported error as drift circle calib not - // fully reliable at this stage + // scale reported errors up to at least 1mm or 3 times the reported error as + // drift circle calib not fully reliable at this stage + return std::min(DC.rDriftError() * 3., 1.0); }; // store the true parameters @@ -100,12 +99,12 @@ ActsExamples::ProcessCode ActsExamples::MuonHoughSeeder::execute( // instantiate the hough plane Acts::HoughTransformUtils::HoughPlane houghPlane(planeCfg); - // also insantiate the peak finder + // also instantiate the peak finder Acts::HoughTransformUtils::PeakFinders::IslandsAroundMax< Acts::GeometryIdentifier::Value> peakFinder(peakFinderCfg); - // loop pver true hirs + // loop over true hits for (auto& SH : gotSH) { // read the identifier MuonMdtIdentifierFields detailedInfo = @@ -113,10 +112,9 @@ ActsExamples::ProcessCode ActsExamples::MuonHoughSeeder::execute( // store the true parameters truePatterns.emplace_back(SH.direction().y() / SH.direction().z(), SH.fourPosition().y()); - // std::cout<<"station name=" << - // static_cast(SH.stationName)<first << " has " - << hitsByParticle.count(it->first) << " hits" << std::endl; + ACTS_DEBUG("Particle " << it->first << " has " + << hitsByParticle.count(it->first) << " hits"); std::vector hitIndices; hitIndices.reserve(hitsByParticle.count(it->first)); diff --git a/Examples/Io/Root/src/RootMaterialTrackReader.cpp b/Examples/Io/Root/src/RootMaterialTrackReader.cpp index b7e5e0ef4f2..dc8a48e137e 100644 --- a/Examples/Io/Root/src/RootMaterialTrackReader.cpp +++ b/Examples/Io/Root/src/RootMaterialTrackReader.cpp @@ -83,9 +83,6 @@ RootMaterialTrackReader::RootMaterialTrackReader(const Config& config, ACTS_DEBUG("The full chain has " << nentries << " entries for " << m_events << " events this corresponds to a batch size of: " << m_batchSize); - std::cout << "The full chain has " << nentries << " entries for " << m_events - << " events this corresponds to a batch size of: " << m_batchSize - << std::endl; // Sort the entry numbers of the events { From 0c5aacc5f040992d6ef08e4eb3fdb416d45669c6 Mon Sep 17 00:00:00 2001 From: Benjamin Huth <37871400+benjaminhuth@users.noreply.github.com> Date: Wed, 27 Nov 2024 18:52:07 +0100 Subject: [PATCH 04/12] feat: Add JSON detector element (#3851) Add a json detector element, which is explicitly constructed from a `nlohmann::json` object in order to ensure consistency. Move json surface reading utilities from examples to Plugins. --- Examples/Io/Json/CMakeLists.txt | 1 - Examples/Python/src/Detector.cpp | 6 ++ Examples/Python/src/Json.cpp | 28 ++++-- Plugins/Json/CMakeLists.txt | 2 + .../Acts/Plugins/Json/JsonDetectorElement.hpp | 38 +++++++ .../Acts/Plugins}/Json/JsonSurfacesReader.hpp | 22 ++++- Plugins/Json/src/JsonDetectorElement.cpp | 41 ++++++++ .../Json/src/JsonSurfacesReader.cpp | 29 +++++- Tests/UnitTests/Plugins/Json/CMakeLists.txt | 1 + .../Plugins/Json/JsonSurfacesReaderTests.cpp | 98 +++++++++++++++++++ docs/_extensions/lazy_autodoc.py | 1 + 11 files changed, 250 insertions(+), 17 deletions(-) create mode 100644 Plugins/Json/include/Acts/Plugins/Json/JsonDetectorElement.hpp rename {Examples/Io/Json/include/ActsExamples/Io => Plugins/Json/include/Acts/Plugins}/Json/JsonSurfacesReader.hpp (58%) create mode 100644 Plugins/Json/src/JsonDetectorElement.cpp rename {Examples/Io => Plugins}/Json/src/JsonSurfacesReader.cpp (75%) create mode 100644 Tests/UnitTests/Plugins/Json/JsonSurfacesReaderTests.cpp diff --git a/Examples/Io/Json/CMakeLists.txt b/Examples/Io/Json/CMakeLists.txt index 255d862881f..5461f5dd98d 100644 --- a/Examples/Io/Json/CMakeLists.txt +++ b/Examples/Io/Json/CMakeLists.txt @@ -4,7 +4,6 @@ add_library( src/JsonGeometryList.cpp src/JsonMaterialWriter.cpp src/JsonSurfacesWriter.cpp - src/JsonSurfacesReader.cpp src/JsonDigitizationConfig.cpp ) target_include_directories( diff --git a/Examples/Python/src/Detector.cpp b/Examples/Python/src/Detector.cpp index 833364301a7..94770ce7283 100644 --- a/Examples/Python/src/Detector.cpp +++ b/Examples/Python/src/Detector.cpp @@ -221,6 +221,12 @@ void addDetector(Context& ctx) { patchKwargsConstructor(c); } + + { + py::class_>( + mex, "DetectorElementBase"); + } } } // namespace Acts::Python diff --git a/Examples/Python/src/Json.cpp b/Examples/Python/src/Json.cpp index cbf9bfb6581..1eb1d83bfc0 100644 --- a/Examples/Python/src/Json.cpp +++ b/Examples/Python/src/Json.cpp @@ -11,13 +11,13 @@ #include "Acts/Detector/ProtoDetector.hpp" #include "Acts/Plugins/Json/DetectorJsonConverter.hpp" #include "Acts/Plugins/Json/JsonMaterialDecorator.hpp" +#include "Acts/Plugins/Json/JsonSurfacesReader.hpp" #include "Acts/Plugins/Json/MaterialMapJsonConverter.hpp" #include "Acts/Plugins/Json/ProtoDetectorJsonConverter.hpp" #include "Acts/Plugins/Python/Utilities.hpp" #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/Framework/ProcessCode.hpp" #include "ActsExamples/Io/Json/JsonMaterialWriter.hpp" -#include "ActsExamples/Io/Json/JsonSurfacesReader.hpp" #include "ActsExamples/Io/Json/JsonSurfacesWriter.hpp" #include "ActsExamples/Io/Json/JsonTrackParamsLookupReader.hpp" #include "ActsExamples/Io/Json/JsonTrackParamsLookupWriter.hpp" @@ -204,21 +204,29 @@ void addJson(Context& ctx) { } { - auto sjOptions = py::class_( - mex, "SurfaceJsonOptions") - .def(py::init<>()); + auto sjOptions = + py::class_(m, "SurfaceJsonOptions") + .def(py::init<>()); - ACTS_PYTHON_STRUCT_BEGIN(sjOptions, - ActsExamples::JsonSurfacesReader::Options); + ACTS_PYTHON_STRUCT_BEGIN(sjOptions, Acts::JsonSurfacesReader::Options); ACTS_PYTHON_MEMBER(inputFile); ACTS_PYTHON_MEMBER(jsonEntryPath); ACTS_PYTHON_STRUCT_END(); - mex.def("readSurfaceHierarchyMapFromJson", - ActsExamples::JsonSurfacesReader::readHierarchyMap); + m.def("readSurfaceHierarchyMapFromJson", + Acts::JsonSurfacesReader::readHierarchyMap); - mex.def("readSurfaceVectorFromJson", - ActsExamples::JsonSurfacesReader::readVector); + m.def("readSurfaceVectorFromJson", Acts::JsonSurfacesReader::readVector); + + py::class_>( + m, "JsonDetectorElement") + .def("surface", [](Acts::JsonDetectorElement& self) { + return self.surface().getSharedPtr(); + }); + + m.def("readDetectorElementsFromJson", + Acts::JsonSurfacesReader::readDetectorElements); } { diff --git a/Plugins/Json/CMakeLists.txt b/Plugins/Json/CMakeLists.txt index 0d3ff9875ee..20634d2bfe5 100644 --- a/Plugins/Json/CMakeLists.txt +++ b/Plugins/Json/CMakeLists.txt @@ -22,6 +22,8 @@ add_library( src/VolumeJsonConverter.cpp src/AmbiguityConfigJsonConverter.cpp src/DetrayJsonHelper.cpp + src/JsonDetectorElement.cpp + src/JsonSurfacesReader.cpp ) target_include_directories( ActsPluginJson diff --git a/Plugins/Json/include/Acts/Plugins/Json/JsonDetectorElement.hpp b/Plugins/Json/include/Acts/Plugins/Json/JsonDetectorElement.hpp new file mode 100644 index 00000000000..34c5a5b173a --- /dev/null +++ b/Plugins/Json/include/Acts/Plugins/Json/JsonDetectorElement.hpp @@ -0,0 +1,38 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. +#pragma once + +#include "Acts/Geometry/DetectorElementBase.hpp" + +#include + +namespace Acts { + +/// A implementation of a detector element, that is constructed from a +/// JSON description of a surface. The idea behind this is that it helps +/// importing whole tracking geometries from JSON files. In some parts of +/// the codebase, the existence of a detector element associated to a surface +/// has a specific meaning (e.g., flags surfaces as sensitive). +class JsonDetectorElement : public DetectorElementBase { + public: + JsonDetectorElement(const nlohmann::json &jSurface, double thickness); + + Surface &surface() override; + const Surface &surface() const override; + + double thickness() const override; + + const Transform3 &transform(const GeometryContext &gctx) const override; + + private: + std::shared_ptr m_surface; + Transform3 m_transform{}; + double m_thickness{}; +}; + +} // namespace Acts diff --git a/Examples/Io/Json/include/ActsExamples/Io/Json/JsonSurfacesReader.hpp b/Plugins/Json/include/Acts/Plugins/Json/JsonSurfacesReader.hpp similarity index 58% rename from Examples/Io/Json/include/ActsExamples/Io/Json/JsonSurfacesReader.hpp rename to Plugins/Json/include/Acts/Plugins/Json/JsonSurfacesReader.hpp index 50bbf15d35f..17822c24401 100644 --- a/Examples/Io/Json/include/ActsExamples/Io/Json/JsonSurfacesReader.hpp +++ b/Plugins/Json/include/Acts/Plugins/Json/JsonSurfacesReader.hpp @@ -9,6 +9,7 @@ #pragma once #include "Acts/Geometry/GeometryHierarchyMap.hpp" +#include "Acts/Plugins/Json/JsonDetectorElement.hpp" #include #include @@ -18,9 +19,11 @@ namespace Acts { class Surface; } -namespace ActsExamples::JsonSurfacesReader { +namespace Acts::JsonSurfacesReader { /// @brief Options specification for surface reading +/// The file should contain an array of json surfaces +/// as produced by the SurfaceJsonConverter tools struct Options { /// @brief Which input file to read from std::string inputFile = ""; @@ -29,6 +32,7 @@ struct Options { }; /// @brief Read the surfaces from the input file +/// For details on the file format see the options struct /// /// @param options specifies which file and what to read /// @@ -37,10 +41,22 @@ Acts::GeometryHierarchyMap> readHierarchyMap( const Options& options); /// @brief Read the flat surfaces from the input file +/// For details on the file format see the options struct /// -/// @param inputFile is the input file to read from +/// @param options options for surface reading /// /// @return a vector of surfaces std::vector> readVector(const Options& options); -} // namespace ActsExamples::JsonSurfacesReader +/// @brief Read the surfaces from the input file and create +/// detector elements +/// For details on the file format see the options struct +/// +/// @param options options for surface reading +/// @param thickness the thickness used to construct the detector element +/// +/// @return a vector of surfaces +std::vector> readDetectorElements( + const Options& options, double thickness); + +} // namespace Acts::JsonSurfacesReader diff --git a/Plugins/Json/src/JsonDetectorElement.cpp b/Plugins/Json/src/JsonDetectorElement.cpp new file mode 100644 index 00000000000..5c1b4568ca5 --- /dev/null +++ b/Plugins/Json/src/JsonDetectorElement.cpp @@ -0,0 +1,41 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "Acts/Plugins/Json/JsonDetectorElement.hpp" + +#include "Acts/Plugins/Json/AlgebraJsonConverter.hpp" +#include "Acts/Plugins/Json/SurfaceJsonConverter.hpp" + +namespace Acts { + +JsonDetectorElement::JsonDetectorElement(const nlohmann::json &jSurface, + double thickness) + : m_thickness(thickness) { + m_surface = Acts::SurfaceJsonConverter::fromJson(jSurface); + m_transform = Transform3JsonConverter::fromJson(jSurface["transform"]); + m_surface->assignDetectorElement(*this); +} + +const Surface &JsonDetectorElement::surface() const { + return *m_surface; +} + +Surface &JsonDetectorElement::surface() { + return *m_surface; +} + +const Transform3 &JsonDetectorElement::transform( + const GeometryContext & /*gctx*/) const { + return m_transform; +} + +double JsonDetectorElement::thickness() const { + return m_thickness; +} + +} // namespace Acts diff --git a/Examples/Io/Json/src/JsonSurfacesReader.cpp b/Plugins/Json/src/JsonSurfacesReader.cpp similarity index 75% rename from Examples/Io/Json/src/JsonSurfacesReader.cpp rename to Plugins/Json/src/JsonSurfacesReader.cpp index 469c9828d46..fcee0ee7b86 100644 --- a/Examples/Io/Json/src/JsonSurfacesReader.cpp +++ b/Plugins/Json/src/JsonSurfacesReader.cpp @@ -6,7 +6,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -#include "ActsExamples/Io/Json/JsonSurfacesReader.hpp" +#include "Acts/Plugins/Json/JsonSurfacesReader.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" #include "Acts/Plugins/Json/ActsJson.hpp" @@ -17,7 +17,7 @@ #include #include -namespace ActsExamples { +namespace Acts { Acts::GeometryHierarchyMap> JsonSurfacesReader::readHierarchyMap( @@ -73,4 +73,27 @@ std::vector> JsonSurfacesReader::readVector( return surfaces; } -} // namespace ActsExamples +std::vector> +JsonSurfacesReader::readDetectorElements(const Options& options, + double thickness = 0.0) { + nlohmann::json j; + { + std::ifstream in(options.inputFile); + in >> j; + } + + // Walk down the path to the surface entries + nlohmann::json jSurfaces = j; + for (const auto& jep : options.jsonEntryPath) { + jSurfaces = jSurfaces[jep]; + } + + std::vector> elements; + for (const auto& jSurface : jSurfaces) { + elements.emplace_back( + std::make_shared(jSurface, thickness)); + } + return elements; +} + +} // namespace Acts diff --git a/Tests/UnitTests/Plugins/Json/CMakeLists.txt b/Tests/UnitTests/Plugins/Json/CMakeLists.txt index 141f86fb3fe..82ad95611ed 100644 --- a/Tests/UnitTests/Plugins/Json/CMakeLists.txt +++ b/Tests/UnitTests/Plugins/Json/CMakeLists.txt @@ -16,3 +16,4 @@ add_unittest(SurfaceBoundsJsonConverter SurfaceBoundsJsonConverterTests.cpp) add_unittest(SurfaceJsonConverter SurfaceJsonConverterTests.cpp) add_unittest(VolumeBoundsJsonConverter VolumeBoundsJsonConverterTests.cpp) add_unittest(TrackParametersJsonConverter TrackParametersJsonConverterTests.cpp) +add_unittest(JsonSurfacesReader JsonSurfacesReaderTests.cpp) diff --git a/Tests/UnitTests/Plugins/Json/JsonSurfacesReaderTests.cpp b/Tests/UnitTests/Plugins/Json/JsonSurfacesReaderTests.cpp new file mode 100644 index 00000000000..e70bad6c7bf --- /dev/null +++ b/Tests/UnitTests/Plugins/Json/JsonSurfacesReaderTests.cpp @@ -0,0 +1,98 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include +#include + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Plugins/Json/JsonSurfacesReader.hpp" +#include "Acts/Plugins/Json/SurfaceJsonConverter.hpp" +#include "Acts/Surfaces/PlaneSurface.hpp" +#include "Acts/Surfaces/RectangleBounds.hpp" +#include "Acts/Utilities/Zip.hpp" + +#include +#include +#include + +#include +#include + +const std::vector> surfaces = []() { + std::vector> v; + + for (int i = 0; i < 3; ++i) { + auto bounds = std::make_shared(1.0, 1.0); + Acts::Transform3 transform = Acts::Transform3::Identity(); + transform.translate(Acts::Vector3::Random()); + Acts::Vector3 randomAngles = Acts::Vector3::Random(); + Acts::SquareMatrix3 rotMatrix; + rotMatrix = Eigen::AngleAxis(randomAngles[0], Acts::Vector3::UnitX()) * + Eigen::AngleAxis(randomAngles[1], Acts::Vector3::UnitY()) * + Eigen::AngleAxis(randomAngles[2], Acts::Vector3::UnitZ()); + transform.rotate(rotMatrix); + v.push_back( + Acts::Surface::makeShared(transform, bounds)); + } + + return v; +}(); + +const std::string filename = "json_surfaces_reader_tests.json"; + +struct FileFixture { + FileFixture() { + nlohmann::json js = nlohmann::json::array(); + + for (const auto &s : surfaces) { + js.push_back(Acts::SurfaceJsonConverter::toJson({}, *s)); + } + + nlohmann::json j; + j["foo"] = js; + + std::ofstream f(filename); + f << j.dump(2); + } + + ~FileFixture() { std::filesystem::remove(filename); } +}; + +FileFixture fileFixture; + +BOOST_AUTO_TEST_CASE(surface_reading_test) { + auto readBackSurfaces = + Acts::JsonSurfacesReader::readVector({filename, {"foo"}}); + + BOOST_REQUIRE_EQUAL(surfaces.size(), readBackSurfaces.size()); + for (auto [refSurface, surface] : Acts::zip(surfaces, readBackSurfaces)) { + BOOST_CHECK( + refSurface->transform({}).isApprox(surface->transform({}), 1.e-4)); + BOOST_CHECK(refSurface->center({}).isApprox(surface->center({}), 1.e-4)); + BOOST_CHECK_EQUAL(refSurface->type(), surface->type()); + BOOST_CHECK_EQUAL(refSurface->bounds().type(), surface->bounds().type()); + } +} + +BOOST_AUTO_TEST_CASE(json_detelement_reading_test) { + auto readBackDetElements = + Acts::JsonSurfacesReader::readDetectorElements({filename, {"foo"}}, 1.0); + + BOOST_REQUIRE_EQUAL(surfaces.size(), readBackDetElements.size()); + for (auto [refSurface, detElement] : + Acts::zip(surfaces, readBackDetElements)) { + auto surface = &detElement->surface(); + BOOST_CHECK( + refSurface->transform({}).isApprox(surface->transform({}), 1.e-4)); + BOOST_CHECK(refSurface->center({}).isApprox(surface->center({}), 1.e-4)); + BOOST_CHECK_EQUAL(refSurface->type(), surface->type()); + BOOST_CHECK_EQUAL(refSurface->bounds().type(), surface->bounds().type()); + } +} diff --git a/docs/_extensions/lazy_autodoc.py b/docs/_extensions/lazy_autodoc.py index 6034fa7d0df..3c9513c4268 100644 --- a/docs/_extensions/lazy_autodoc.py +++ b/docs/_extensions/lazy_autodoc.py @@ -117,6 +117,7 @@ def run() -> None: "Acts::Logging::DefaultFilterPolicy", "Acts::Logging::DefaultPrintPolicy", "Acts::SourceLink", + "Acts::JsonDetectorElement", } role_instances["func"] = { From 9173bb4b2c99ea806eb5ad342af9d64d3ee32e1f Mon Sep 17 00:00:00 2001 From: Benjamin Huth <37871400+benjaminhuth@users.noreply.github.com> Date: Wed, 27 Nov 2024 20:24:43 +0100 Subject: [PATCH 05/12] refactor: Allow track selection without reference surface (#3791) Adds a flag to allow track selection without reference surface, which is off by default. Also refactors the track selector config handling in python to avoid that different uses get out of sync. ## Summary by CodeRabbit - **New Features** - Introduced a new configuration option, `requireReferenceSurface`, for track validation, enhancing track selection flexibility. - Added a function, `trackSelectorDefaultKWArgs`, to streamline track selection parameter configuration. - **Improvements** - Refactored track validation logic for improved clarity and separation of concerns. - Enhanced configurability of track selection and seeding algorithms, allowing for more adaptable configurations. - Updated default values in the `TrackSelectorConfig` to accommodate the new field. --- .../Acts/TrackFinding/TrackSelector.hpp | 47 +++++++---- .../python/acts/examples/reconstruction.py | 80 +++++++++---------- Examples/Python/src/ExampleAlgorithms.cpp | 1 + 3 files changed, 69 insertions(+), 59 deletions(-) diff --git a/Core/include/Acts/TrackFinding/TrackSelector.hpp b/Core/include/Acts/TrackFinding/TrackSelector.hpp index 5a2cf53df27..fe4287a38b0 100644 --- a/Core/include/Acts/TrackFinding/TrackSelector.hpp +++ b/Core/include/Acts/TrackFinding/TrackSelector.hpp @@ -80,6 +80,10 @@ class TrackSelector { std::size_t maxSharedHits = std::numeric_limits::max(); double maxChi2 = inf; + /// Whether a reference surface is required for the track + /// If false, the parameter cuts are not evaluated + bool requireReferenceSurface = true; + // Defaults to: no cut MeasurementCounter measurementCounter; @@ -447,22 +451,33 @@ bool TrackSelector::isValidTrack(const track_proxy_t& track) const { const Config& cuts = *cutsPtr; - return track.hasReferenceSurface() && - within(track.transverseMomentum(), cuts.ptMin, cuts.ptMax) && - (!m_isUnbinned || (within(absEta(), cuts.absEtaMin, cuts.absEtaMax) && - within(_eta, cuts.etaMin, cuts.etaMax))) && - within(track.phi(), cuts.phiMin, cuts.phiMax) && - within(track.loc0(), cuts.loc0Min, cuts.loc0Max) && - within(track.loc1(), cuts.loc1Min, cuts.loc1Max) && - within(track.time(), cuts.timeMin, cuts.timeMax) && - checkMin(track.nMeasurements(), cuts.minMeasurements) && - checkMax(track.nHoles(), cuts.maxHoles) && - checkMax(track.nOutliers(), cuts.maxOutliers) && - checkMax(track.nHoles() + track.nOutliers(), - cuts.maxHolesAndOutliers) && - checkMax(track.nSharedHits(), cuts.maxSharedHits) && - checkMax(track.chi2(), cuts.maxChi2) && - cuts.measurementCounter.isValidTrack(track); + auto parameterCuts = [&]() { + return within(track.transverseMomentum(), cuts.ptMin, cuts.ptMax) && + (!m_isUnbinned || + (within(absEta(), cuts.absEtaMin, cuts.absEtaMax) && + within(_eta, cuts.etaMin, cuts.etaMax))) && + within(track.phi(), cuts.phiMin, cuts.phiMax) && + within(track.loc0(), cuts.loc0Min, cuts.loc0Max) && + within(track.loc1(), cuts.loc1Min, cuts.loc1Max) && + within(track.time(), cuts.timeMin, cuts.timeMax); + }; + + auto trackCuts = [&]() { + return checkMin(track.nMeasurements(), cuts.minMeasurements) && + checkMax(track.nHoles(), cuts.maxHoles) && + checkMax(track.nOutliers(), cuts.maxOutliers) && + checkMax(track.nHoles() + track.nOutliers(), + cuts.maxHolesAndOutliers) && + checkMax(track.nSharedHits(), cuts.maxSharedHits) && + checkMax(track.chi2(), cuts.maxChi2) && + cuts.measurementCounter.isValidTrack(track); + }; + + if (cuts.requireReferenceSurface) { + return track.hasReferenceSurface() && parameterCuts() && trackCuts(); + } else { + return trackCuts(); + } } inline TrackSelector::TrackSelector( diff --git a/Examples/Python/python/acts/examples/reconstruction.py b/Examples/Python/python/acts/examples/reconstruction.py index bc1b1d4df9d..0d1131d45cf 100644 --- a/Examples/Python/python/acts/examples/reconstruction.py +++ b/Examples/Python/python/acts/examples/reconstruction.py @@ -123,10 +123,42 @@ "maxSharedHits", "maxChi2", "nMeasurementsGroupMin", + "requireReferenceSurface", ], - defaults=[(None, None)] * 7 + [None] * 7, + defaults=[(None, None)] * 7 + [None] * 8, ) + +def trackSelectorDefaultKWArgs(c): + """ + Encapsulate this boilerplate code into a function so different uses do not get out of sync + """ + return acts.examples.defaultKWArgs( + loc0Min=c.loc0[0], + loc0Max=c.loc0[1], + loc1Min=c.loc1[0], + loc1Max=c.loc1[1], + timeMin=c.time[0], + timeMax=c.time[1], + phiMin=c.phi[0], + phiMax=c.phi[1], + etaMin=c.eta[0], + etaMax=c.eta[1], + absEtaMin=c.absEta[0], + absEtaMax=c.absEta[1], + ptMin=c.pt[0], + ptMax=c.pt[1], + minMeasurements=c.nMeasurementsMin, + maxHoles=c.maxHoles, + maxOutliers=c.maxOutliers, + maxHolesAndOutliers=c.maxHolesAndOutliers, + maxSharedHits=c.maxSharedHits, + maxChi2=c.maxChi2, + measurementCounter=c.nMeasurementsGroupMin, + requireReferenceSurface=c.requireReferenceSurface, + ) + + CkfConfig = namedtuple( "CkfConfig", [ @@ -1424,32 +1456,10 @@ def addCKFTracks( else trackSelectorConfig ) ) + + overwriteArgs = dict() if len(tslist) == 1 else dict(absEtaMax=None) cutSets = [ - acts.TrackSelector.Config( - **acts.examples.defaultKWArgs( - loc0Min=c.loc0[0], - loc0Max=c.loc0[1], - loc1Min=c.loc1[0], - loc1Max=c.loc1[1], - timeMin=c.time[0], - timeMax=c.time[1], - phiMin=c.phi[0], - phiMax=c.phi[1], - etaMin=c.eta[0], - etaMax=c.eta[1], - absEtaMin=c.absEta[0], - absEtaMax=c.absEta[1] if len(tslist) == 1 else None, - ptMin=c.pt[0], - ptMax=c.pt[1], - minMeasurements=c.nMeasurementsMin, - maxHoles=c.maxHoles, - maxOutliers=c.maxOutliers, - maxHolesAndOutliers=c.maxHolesAndOutliers, - maxSharedHits=c.maxSharedHits, - maxChi2=c.maxChi2, - measurementCounter=c.nMeasurementsGroupMin, - ) - ) + acts.TrackSelector.Config(**(trackSelectorDefaultKWArgs(c) | overwriteArgs)) for c in tslist ] if len(tslist) == 0: @@ -1702,23 +1712,7 @@ def addTrackSelection( # single cut config for implicit single bin eta configuration selectorConfig = acts.TrackSelector.Config( - **acts.examples.defaultKWArgs( - loc0Min=trackSelectorConfig.loc0[0], - loc0Max=trackSelectorConfig.loc0[1], - loc1Min=trackSelectorConfig.loc1[0], - loc1Max=trackSelectorConfig.loc1[1], - timeMin=trackSelectorConfig.time[0], - timeMax=trackSelectorConfig.time[1], - phiMin=trackSelectorConfig.phi[0], - phiMax=trackSelectorConfig.phi[1], - etaMin=trackSelectorConfig.eta[0], - etaMax=trackSelectorConfig.eta[1], - absEtaMin=trackSelectorConfig.absEta[0], - absEtaMax=trackSelectorConfig.absEta[1], - ptMin=trackSelectorConfig.pt[0], - ptMax=trackSelectorConfig.pt[1], - minMeasurements=trackSelectorConfig.nMeasurementsMin, - ) + **trackSelectorDefaultKWArgs(trackSelectorConfig) ) trackSelector = acts.examples.TrackSelectorAlgorithm( diff --git a/Examples/Python/src/ExampleAlgorithms.cpp b/Examples/Python/src/ExampleAlgorithms.cpp index 7d9007183e8..411973d147e 100644 --- a/Examples/Python/src/ExampleAlgorithms.cpp +++ b/Examples/Python/src/ExampleAlgorithms.cpp @@ -109,6 +109,7 @@ void addExampleAlgorithms(Context& ctx) { ACTS_PYTHON_MEMBER(maxSharedHits); ACTS_PYTHON_MEMBER(maxChi2); ACTS_PYTHON_MEMBER(measurementCounter); + ACTS_PYTHON_MEMBER(requireReferenceSurface); ACTS_PYTHON_STRUCT_END(); pythonRangeProperty(c, "loc0", &Config::loc0Min, &Config::loc0Max); From 217ad15211d0b2efbc943acc17d450462fd921ab Mon Sep 17 00:00:00 2001 From: Paul Gessinger Date: Wed, 27 Nov 2024 21:44:43 +0100 Subject: [PATCH 06/12] fix: Change MTJ test dynamic column names (#3914) The names need to work with xAOD, and xAOD does not allow :: in the column name. --- .../Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp b/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp index 422dc58e053..368138fe38d 100644 --- a/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp +++ b/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp @@ -1166,10 +1166,10 @@ class MultiTrajectoryTestsCommon { BOOST_CHECK_EQUAL(ts1.template component(col), value); }; - test("std::uint32_t", std::uint32_t{1}); - test("std::uint64_t", std::uint64_t{2}); - test("std::int32_t", std::int32_t{-3}); - test("std::int64_t", std::int64_t{-4}); + test("std_uint32_t", std::uint32_t{1}); + test("std_uint64_t", std::uint64_t{2}); + test("std_int32_t", std::int32_t{-3}); + test("std_int64_t", std::int64_t{-4}); test("float", float{8.9}); test("double", double{656.2}); From e10cd5455e3d8f2b4a7a09a1375b9644a537fdca Mon Sep 17 00:00:00 2001 From: "Alexander J. Pfleger" <70842573+AJPfleger@users.noreply.github.com> Date: Thu, 28 Nov 2024 10:14:40 +0100 Subject: [PATCH 07/12] chore(physmon): make configuration of all the fitters the same (#3916) Popped up in a discussion in https://github.com/acts-project/acts/pull/3889 that the configurations should be the same for all fitters. ## Summary by CodeRabbit - **Chores** - Updated parameter naming in function calls for improved clarity and readability. --- CI/physmon/workflows/physmon_trackfitting_gsf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CI/physmon/workflows/physmon_trackfitting_gsf.py b/CI/physmon/workflows/physmon_trackfitting_gsf.py index 694623e2926..4738bc4d397 100755 --- a/CI/physmon/workflows/physmon_trackfitting_gsf.py +++ b/CI/physmon/workflows/physmon_trackfitting_gsf.py @@ -20,9 +20,9 @@ tp = Path(temp) runTruthTrackingGsf( - setup.trackingGeometry, - setup.field, - setup.digiConfig, + trackingGeometry=setup.trackingGeometry, + field=setup.field, + digiConfigFile=setup.digiConfig, outputDir=tp, s=s, ) From 2eee79491fcb9e48ab0ca90731f421b664c6e0a6 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Fri, 29 Nov 2024 09:52:57 +0100 Subject: [PATCH 08/12] refactor!: Clean track EDM projector (#3605) Clean deprecated projector functions from `TrackStateProxy` and rename the new methods to something recognizable. Also deals with the ACTS internal downstream changes. ## Summary by CodeRabbit - **New Features** - Enhanced handling of projector subspace indices across various components for improved accuracy in alignment and calibration processes. - **Bug Fixes** - Updated method calls to ensure consistent use of `setProjectorSubspaceIndices`, enhancing the clarity and functionality of the track state management. - **Documentation** - Minor adjustments to comments for better clarity on the changes related to projector handling. - **Tests** - Updated test cases to reflect changes in method names and ensure proper validation of projector subspace indices. --- .../Kernel/detail/AlignmentEngine.hpp | 4 +- .../Acts/EventData/SubspaceHelpers.hpp | 30 +-- .../Acts/EventData/TrackStateProxy.hpp | 171 ++++-------------- .../Acts/EventData/TrackStateProxy.ipp | 5 - .../Acts/EventData/TrackStateProxyConcept.hpp | 6 - .../detail/MultiTrajectoryTestsCommon.hpp | 31 +--- .../Acts/EventData/detail/TestSourceLink.hpp | 22 +-- .../Acts/TrackFinding/MeasurementSelector.ipp | 2 +- .../Acts/TrackFitting/GainMatrixSmoother.hpp | 1 - .../Acts/TrackFitting/GainMatrixUpdater.hpp | 2 +- .../TrackFitting/GlobalChiSquareFitter.hpp | 2 +- .../include/Acts/TrackFitting/MbfSmoother.hpp | 7 +- .../detail/GainMatrixUpdaterImpl.hpp | 2 +- .../Acts/TrackFitting/detail/GsfUtils.hpp | 8 +- Core/include/Acts/Utilities/TrackHelpers.hpp | 7 +- Core/src/TrackFinding/MeasurementSelector.cpp | 5 +- Core/src/TrackFitting/GsfUtils.cpp | 13 +- Core/src/TrackFitting/MbfSmoother.cpp | 16 +- .../TrackFitting/src/RefittingCalibrator.cpp | 2 +- .../Framework/ML/src/NeuralCalibrator.cpp | 2 +- .../src/EventData/MeasurementCalibration.cpp | 2 +- .../src/EventData/ScalingCalibrator.cpp | 2 +- .../Io/Root/src/RootTrackStatesWriter.cpp | 8 +- Tests/Benchmarks/TrackEdmBenchmark.cpp | 2 +- .../Core/EventData/TrackTestsExtra.cpp | 2 +- .../Core/TrackFitting/FitterTestsCommon.hpp | 11 +- .../Core/TrackFitting/MbfSmootherTests.cpp | 9 +- 27 files changed, 127 insertions(+), 247 deletions(-) diff --git a/Alignment/include/ActsAlignment/Kernel/detail/AlignmentEngine.hpp b/Alignment/include/ActsAlignment/Kernel/detail/AlignmentEngine.hpp index 1bb21fdc8bd..b26175abcdd 100644 --- a/Alignment/include/ActsAlignment/Kernel/detail/AlignmentEngine.hpp +++ b/Alignment/include/ActsAlignment/Kernel/detail/AlignmentEngine.hpp @@ -208,7 +208,9 @@ TrackAlignmentState trackAlignmentState( measdim) = measCovariance; // (b) Get and fill the bound parameters to measurement projection matrix - const ActsDynamicMatrix H = state.effectiveProjector(); + const ActsDynamicMatrix H = + state.projectorSubspaceHelper().fullProjector().topLeftCorner( + measdim, eBoundSize); alignState.projectionMatrix.block(iMeasurement, iParams, measdim, eBoundSize) = H; // (c) Get and fill the residual diff --git a/Core/include/Acts/EventData/SubspaceHelpers.hpp b/Core/include/Acts/EventData/SubspaceHelpers.hpp index 029dbf372b3..f48690cf036 100644 --- a/Core/include/Acts/EventData/SubspaceHelpers.hpp +++ b/Core/include/Acts/EventData/SubspaceHelpers.hpp @@ -14,8 +14,7 @@ #include "Acts/Utilities/AlgebraHelpers.hpp" #include "Acts/Utilities/Enumerate.hpp" -#include -#include +#include #include @@ -25,30 +24,30 @@ namespace Acts { /// /// Indices must be unique and within the full size of the subspace /// -/// @tparam Container type of the container +/// @tparam index_range_t the type of the container of indices /// -/// @param container the container of indices +/// @param indexRange the range of indices /// @param fullSize the full size of the subspace /// @param subspaceSize the size of the subspace /// /// @return true if the indices are consistent -template -inline static bool checkSubspaceIndices(const Container& container, +template +inline static bool checkSubspaceIndices(const index_range_t& indexRange, std::size_t fullSize, std::size_t subspaceSize) { if (subspaceSize > fullSize) { return false; } - if (static_cast(container.size()) != subspaceSize) { + if (static_cast(indexRange.size()) != subspaceSize) { return false; } - for (auto it = container.begin(); it != container.end();) { + for (auto it = indexRange.begin(); it != indexRange.end();) { auto index = *it; if (index >= fullSize) { return false; } ++it; - if (std::find(it, container.end(), index) != container.end()) { + if (std::find(it, indexRange.end(), index) != indexRange.end()) { return false; } } @@ -69,7 +68,8 @@ inline static SerializedSubspaceIndices serializeSubspaceIndices( { SerializedSubspaceIndices result = 0; for (std::size_t i = 0; i < FullSize; ++i) { - result |= static_cast(indices[i]) << (i * 8); + result |= static_cast(indices[i] & 0xFF) + << (i * 8); } return result; } @@ -88,7 +88,7 @@ inline static SubspaceIndices deserializeSubspaceIndices( { SubspaceIndices result; for (std::size_t i = 0; i < FullSize; ++i) { - result[i] = static_cast(serialized >> (i * 8)); + result[i] = static_cast((serialized >> (i * 8)) & 0xFF); } return result; } @@ -187,8 +187,8 @@ class VariableSubspaceHelper using IndexType = index_t; using Container = boost::container::static_vector; - template - explicit VariableSubspaceHelper(const OtherContainer& indices) { + template + explicit VariableSubspaceHelper(const other_index_range_t& indices) { assert(checkSubspaceIndices(indices, kFullSize, indices.size()) && "Invalid indices"); m_indices.resize(indices.size()); @@ -236,8 +236,8 @@ class FixedSubspaceHelper using IndexType = index_t; using Container = std::array; - template - explicit FixedSubspaceHelper(const OtherContainer& indices) { + template + explicit FixedSubspaceHelper(const other_index_range_t& indices) { assert(checkSubspaceIndices(indices, kFullSize, kSubspaceSize) && "Invalid indices"); std::transform(indices.begin(), indices.end(), m_indices.begin(), diff --git a/Core/include/Acts/EventData/TrackStateProxy.hpp b/Core/include/Acts/EventData/TrackStateProxy.hpp index 3f7ddf1a028..4338c434f77 100644 --- a/Core/include/Acts/EventData/TrackStateProxy.hpp +++ b/Core/include/Acts/EventData/TrackStateProxy.hpp @@ -8,7 +8,6 @@ #pragma once -#include "Acts/Definitions/Algebra.hpp" #include "Acts/Definitions/TrackParametrization.hpp" #include "Acts/EventData/SourceLink.hpp" #include "Acts/EventData/SubspaceHelpers.hpp" @@ -17,11 +16,11 @@ #include "Acts/EventData/TrackStateType.hpp" #include "Acts/EventData/Types.hpp" #include "Acts/Surfaces/Surface.hpp" -#include "Acts/Utilities/AlgebraHelpers.hpp" #include "Acts/Utilities/HashedString.hpp" #include "Acts/Utilities/Helpers.hpp" #include +#include #include #include @@ -127,11 +126,6 @@ struct TrackStateTraits { typename detail_lt::DynamicSizeTypes::CoefficientsMap; using EffectiveCalibratedCovariance = typename detail_lt::DynamicSizeTypes::CovarianceMap; - - constexpr static auto ProjectorFlags = Eigen::RowMajor | Eigen::AutoAlign; - using Projector = Eigen::Matrix; - using EffectiveProjector = Eigen::Matrix; }; /// Proxy object to access a single point on the trajectory. @@ -207,17 +201,6 @@ class TrackStateProxy { /// Sentinel value that indicates an invalid index static constexpr IndexType kInvalid = kTrackIndexInvalid; - /// Matrix representing the projector (measurement mapping function) for a - /// measurement. This is not a map type, but an actual matrix. This matrix - /// is always \f$M \times M\f$, even if the local measurement dimension is lower. - /// The actual \f$N\times M\f$ projector is given by the top \f$N\f$ rows. - using Projector = typename TrackStateTraits::Projector; - - /// Dynamic variant of the projector matrix - /// @warning Using this type is discouraged, as it has a runtime overhead - using EffectiveProjector = - typename TrackStateTraits::EffectiveProjector; - /// The track state container backend given as a template parameter using Trajectory = trajectory_t; @@ -615,145 +598,61 @@ class TrackStateProxy { /// /// @{ - /// Returns the projector (measurement mapping function) for this track - /// state. It is derived from the uncalibrated measurement - /// @note This function returns the overallocated projector. This means it - /// is of dimension MxM, where M is the maximum number of measurement - /// dimensions. The NxM submatrix, where N is the actual dimension of the - /// measurement, is located in the top left corner, everything else is zero. - /// @return The overallocated projector - Projector projector() const; - - /// Returns whether a projector is set - /// @return Whether it is set - bool hasProjector() const { return has(); } - - /// Returns the projector (measurement mapping function) for this track - /// state. It is derived from the uncalibrated measurement - /// @warning This function returns the effective projector. This means it - /// is of dimension \f$N\times M\f$, where \f$N\f$ is the actual dimension of the - /// measurement. - /// @return The effective projector - EffectiveProjector effectiveProjector() const { - return projector().topLeftCorner(calibratedSize(), M); - } - - /// Set the projector on this track state - /// This will convert the projector to a more compact bitset representation - /// and store it. - /// @param projector The projector in the form of a dense matrix - /// @note @p projector is assumed to only have 0s or 1s as components. - template - [[deprecated("use setProjector(span) instead")]] void setProjector( - const Eigen::MatrixBase& projector) - requires(!ReadOnly) + /// Set the projector subspace indices + /// @param subspaceIndices The projector subspace indices to set + template + void setProjectorSubspaceIndices(const index_range_t& subspaceIndices) + requires(!ReadOnly && + std::convertible_to, + std::uint8_t>) { - constexpr int rows = Eigen::MatrixBase::RowsAtCompileTime; - constexpr int cols = Eigen::MatrixBase::ColsAtCompileTime; - - static_assert(rows != -1 && cols != -1, - "Assignment of dynamic matrices is currently not supported."); - assert(has()); - - static_assert(rows <= M, "Given projector has too many rows"); - static_assert(cols <= eBoundSize, "Given projector has too many columns"); - - // set up full size projector with only zeros - typename TrackStateProxy::Projector fullProjector = - decltype(fullProjector)::Zero(); - - // assign (potentially) smaller actual projector to matrix, preserving - // zeroes outside of smaller matrix block. - fullProjector.template topLeftCorner() = projector; - - // convert to bitset before storing - ProjectorBitset projectorBitset = matrixToBitset(fullProjector).to_ulong(); - setProjectorBitset(projectorBitset); - } - - /// Directly get the projector bitset, a compressed form of a projection - /// matrix - /// @note This is mainly to copy explicitly a projector from one state - /// to another. Use the `projector` or `effectiveProjector` method if - /// you want to access the matrix. - /// @return The projector bitset - [[deprecated("use projector() instead")]] ProjectorBitset projectorBitset() - const { - return variableBoundSubspaceHelper().projectorBitset(); + assert(subspaceIndices.size() <= eBoundSize); + BoundSubspaceIndices boundSubspace{}; + std::transform(subspaceIndices.begin(), subspaceIndices.end(), + boundSubspace.begin(), + [](auto i) { return static_cast(i); }); + component() = + serializeSubspaceIndices(boundSubspace); } - /// Set the projector bitset, a compressed form of a projection matrix - /// @param proj The projector bitset - /// - /// @note This is mainly to copy explicitly a projector from one state - /// to another. If you have a projection matrix, set it with - /// `setProjector`. - [[deprecated("use setProjector(span) instead")]] void setProjectorBitset( - ProjectorBitset proj) - requires(!ReadOnly) - { - BoundMatrix projMatrix = bitsetToMatrix(proj); - BoundSubspaceIndices boundSubspace = - projectorToSubspaceIndices(projMatrix); - setBoundSubspaceIndices(boundSubspace); - } + /// Returns whether a projector is set + /// @return Whether it is set + bool hasProjector() const { return has(); } - BoundSubspaceIndices boundSubspaceIndices() const { + /// Returns the projector subspace indices + /// @return The projector subspace indices + BoundSubspaceIndices projectorSubspaceIndices() const { assert(has()); return deserializeSubspaceIndices( component()); } + /// Returns the projector subspace indices + /// @return The projector subspace indices template - SubspaceIndices subspaceIndices() const { - BoundSubspaceIndices boundSubspace = BoundSubspaceIndices(); + SubspaceIndices projectorSubspaceIndices() const { + BoundSubspaceIndices boundSubspace = projectorSubspaceIndices(); SubspaceIndices subspace; std::copy(boundSubspace.begin(), boundSubspace.begin() + measdim, subspace.begin()); return subspace; } - void setBoundSubspaceIndices(BoundSubspaceIndices boundSubspace) - requires(!ReadOnly) - { - assert(has()); - component() = - serializeSubspaceIndices(boundSubspace); - } - - template - void setSubspaceIndices(SubspaceIndices subspace) - requires(!ReadOnly && measdim <= eBoundSize) - { - assert(has()); - BoundSubspaceIndices boundSubspace{}; - std::copy(subspace.begin(), subspace.end(), boundSubspace.begin()); - setBoundSubspaceIndices(boundSubspace); - } - - template - void setSubspaceIndices(std::array subspaceIndices) - requires(!ReadOnly && measdim <= eBoundSize) - { - assert(has()); - BoundSubspaceIndices boundSubspace{}; - std::transform(subspaceIndices.begin(), subspaceIndices.end(), - boundSubspace.begin(), - [](index_t i) { return static_cast(i); }); - setBoundSubspaceIndices(boundSubspace); - } - - VariableBoundSubspaceHelper variableBoundSubspaceHelper() const { - BoundSubspaceIndices boundSubspace = boundSubspaceIndices(); + /// Creates a variable size subspace helper + /// @return The subspace helper + VariableBoundSubspaceHelper projectorSubspaceHelper() const { + BoundSubspaceIndices boundSubspace = projectorSubspaceIndices(); std::span validSubspaceIndices( boundSubspace.begin(), boundSubspace.begin() + calibratedSize()); return VariableBoundSubspaceHelper(validSubspaceIndices); } + /// Creates a fixed size subspace helper + /// @return The subspace helper template - FixedBoundSubspaceHelper fixedBoundSubspaceHelper() const { - SubspaceIndices subspace = subspaceIndices(); + FixedBoundSubspaceHelper projectorSubspaceHelper() const { + SubspaceIndices subspace = projectorSubspaceIndices(); return FixedBoundSubspaceHelper(subspace); } @@ -1028,7 +927,7 @@ class TrackStateProxy { other.template calibratedCovariance().eval()); }); - setBoundSubspaceIndices(other.boundSubspaceIndices()); + setProjectorSubspaceIndices(other.projectorSubspaceIndices()); } } else { if (ACTS_CHECK_BIT(mask, PM::Predicted) && @@ -1073,7 +972,7 @@ class TrackStateProxy { other.template calibratedCovariance().eval()); }); - setBoundSubspaceIndices(other.boundSubspaceIndices()); + setProjectorSubspaceIndices(other.projectorSubspaceIndices()); } } diff --git a/Core/include/Acts/EventData/TrackStateProxy.ipp b/Core/include/Acts/EventData/TrackStateProxy.ipp index e36be5f3c25..16abe8fb3aa 100644 --- a/Core/include/Acts/EventData/TrackStateProxy.ipp +++ b/Core/include/Acts/EventData/TrackStateProxy.ipp @@ -61,11 +61,6 @@ inline auto TrackStateProxy::covariance() const } } -template -inline auto TrackStateProxy::projector() const -> Projector { - return variableBoundSubspaceHelper().fullProjector(); -} - template inline auto TrackStateProxy::getUncalibratedSourceLink() const -> SourceLink { diff --git a/Core/include/Acts/EventData/TrackStateProxyConcept.hpp b/Core/include/Acts/EventData/TrackStateProxyConcept.hpp index 61e98adbc48..4b8a713f864 100644 --- a/Core/include/Acts/EventData/TrackStateProxyConcept.hpp +++ b/Core/include/Acts/EventData/TrackStateProxyConcept.hpp @@ -111,12 +111,6 @@ concept TrackStateProxyConcept = { cv.hasProjector() } -> std::same_as; { v.hasProjector() } -> std::same_as; - { cv.effectiveProjector() } -> std::same_as; - { v.effectiveProjector() } -> std::same_as; - - { cv.projectorBitset() } -> std::same_as; - { v.projectorBitset() } -> std::same_as; - { cv.getUncalibratedSourceLink() } -> std::same_as; { v.getUncalibratedSourceLink() } -> std::same_as; diff --git a/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp b/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp index 368138fe38d..7926ca3ba77 100644 --- a/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp +++ b/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp @@ -471,8 +471,8 @@ class MultiTrajectoryTestsCommon { pc.sourceLink.sourceId); // Explicitly unset to avoid error below ts.unset(TrackStatePropMask::Calibrated); - testSourceLinkCalibratorReturn( - gctx, cctx, SourceLink{ttsb.sourceLink}, ts); + testSourceLinkCalibrator(gctx, cctx, + SourceLink{ttsb.sourceLink}, ts); BOOST_CHECK_EQUAL( ts.getUncalibratedSourceLink().template get().sourceId, ttsb.sourceLink.sourceId); @@ -549,21 +549,6 @@ class MultiTrajectoryTestsCommon { BOOST_CHECK_EQUAL(ts.template calibratedCovariance(), expCov); }); } - - BOOST_CHECK(ts.hasProjector()); - ActsMatrix fullProj; - fullProj.setZero(); - { - Acts::GeometryContext gctx; - Acts::CalibrationContext cctx; - // create a temporary measurement to extract the projector matrix - testSourceLinkCalibratorReturn( - gctx, cctx, SourceLink{pc.sourceLink}, ts); - fullProj = ts.projector(); - } - BOOST_CHECK_EQUAL(ts.effectiveProjector(), - fullProj.topLeftCorner(nMeasurements, eBoundSize)); - BOOST_CHECK_EQUAL(ts.projector(), fullProj); } void testTrackStateProxyAllocations(std::default_random_engine& rng) { @@ -782,7 +767,8 @@ class MultiTrajectoryTestsCommon { }); BOOST_CHECK_NE(ts1.calibratedSize(), ts2.calibratedSize()); - BOOST_CHECK_NE(ts1.projector(), ts2.projector()); + BOOST_CHECK(ts1.projectorSubspaceIndices() != + ts2.projectorSubspaceIndices()); BOOST_CHECK_NE(ts1.jacobian(), ts2.jacobian()); BOOST_CHECK_NE(ts1.chi2(), ts2.chi2()); @@ -813,7 +799,8 @@ class MultiTrajectoryTestsCommon { }); BOOST_CHECK_EQUAL(ts1.calibratedSize(), ts2.calibratedSize()); - BOOST_CHECK_EQUAL(ts1.projector(), ts2.projector()); + BOOST_CHECK(ts1.projectorSubspaceIndices() == + ts2.projectorSubspaceIndices()); BOOST_CHECK_EQUAL(ts1.jacobian(), ts2.jacobian()); BOOST_CHECK_EQUAL(ts1.chi2(), ts2.chi2()); @@ -840,7 +827,8 @@ class MultiTrajectoryTestsCommon { }); BOOST_CHECK_NE(ts1.calibratedSize(), ts2.calibratedSize()); - BOOST_CHECK_NE(ts1.projector(), ts2.projector()); + BOOST_CHECK(ts1.projectorSubspaceIndices() != + ts2.projectorSubspaceIndices()); BOOST_CHECK_NE(ts1.jacobian(), ts2.jacobian()); BOOST_CHECK_NE(ts1.chi2(), ts2.chi2()); @@ -864,7 +852,8 @@ class MultiTrajectoryTestsCommon { }); BOOST_CHECK_EQUAL(ts1.calibratedSize(), ts2.calibratedSize()); - BOOST_CHECK_EQUAL(ts1.projector(), ts2.projector()); + BOOST_CHECK(ts1.projectorSubspaceIndices() == + ts2.projectorSubspaceIndices()); BOOST_CHECK_EQUAL(ts1.jacobian(), ts2.jacobian()); BOOST_CHECK_EQUAL(ts1.chi2(), ts2.chi2()); // always copied diff --git a/Core/include/Acts/EventData/detail/TestSourceLink.hpp b/Core/include/Acts/EventData/detail/TestSourceLink.hpp index 4a98b1a28a9..9a6350e7df4 100644 --- a/Core/include/Acts/EventData/detail/TestSourceLink.hpp +++ b/Core/include/Acts/EventData/detail/TestSourceLink.hpp @@ -18,9 +18,7 @@ #include "Acts/Geometry/TrackingGeometry.hpp" #include "Acts/Utilities/CalibrationContext.hpp" -#include #include -#include #include #include #include @@ -126,7 +124,7 @@ inline std::ostream& operator<<(std::ostream& os, /// @param gctx Unused /// @param trackState TrackState to calibrated template -void testSourceLinkCalibratorReturn( +void testSourceLinkCalibrator( const GeometryContext& /*gctx*/, const CalibrationContext& /*cctx*/, const SourceLink& sourceLink, typename trajectory_t::TrackStateProxy trackState) { @@ -139,30 +137,18 @@ void testSourceLinkCalibratorReturn( trackState.allocateCalibrated(2); trackState.template calibrated<2>() = sl.parameters; trackState.template calibratedCovariance<2>() = sl.covariance; - trackState.setSubspaceIndices(std::array{sl.indices[0], sl.indices[1]}); + trackState.setProjectorSubspaceIndices( + std::array{sl.indices[0], sl.indices[1]}); } else if (sl.indices[0] != Acts::eBoundSize) { trackState.allocateCalibrated(1); trackState.template calibrated<1>() = sl.parameters.head<1>(); trackState.template calibratedCovariance<1>() = sl.covariance.topLeftCorner<1, 1>(); - trackState.setSubspaceIndices(std::array{sl.indices[0]}); + trackState.setProjectorSubspaceIndices(std::array{sl.indices[0]}); } else { throw std::runtime_error( "Tried to extract measurement from invalid TestSourceLink"); } } -/// Extract the measurement from a TestSourceLink. -/// -/// @param gctx Unused -/// @param trackState TrackState to calibrated -template -void testSourceLinkCalibrator( - const GeometryContext& gctx, const CalibrationContext& cctx, - const SourceLink& sourceLink, - typename trajectory_t::TrackStateProxy trackState) { - testSourceLinkCalibratorReturn(gctx, cctx, sourceLink, - trackState); -} - } // namespace Acts::detail::Test diff --git a/Core/include/Acts/TrackFinding/MeasurementSelector.ipp b/Core/include/Acts/TrackFinding/MeasurementSelector.ipp index 30d09c002be..5e13ffd904a 100644 --- a/Core/include/Acts/TrackFinding/MeasurementSelector.ipp +++ b/Core/include/Acts/TrackFinding/MeasurementSelector.ipp @@ -63,7 +63,7 @@ MeasurementSelector::select( trackState.effectiveCalibrated().data(), trackState.effectiveCalibratedCovariance().data(), trackState.predicted(), trackState.predictedCovariance(), - trackState.boundSubspaceIndices(), trackState.calibratedSize()); + trackState.projectorSubspaceIndices(), trackState.calibratedSize()); trackState.chi2() = chi2; if (chi2 < minChi2) { diff --git a/Core/include/Acts/TrackFitting/GainMatrixSmoother.hpp b/Core/include/Acts/TrackFitting/GainMatrixSmoother.hpp index cf5b372f487..5adc8340cfe 100644 --- a/Core/include/Acts/TrackFitting/GainMatrixSmoother.hpp +++ b/Core/include/Acts/TrackFitting/GainMatrixSmoother.hpp @@ -10,7 +10,6 @@ #include "Acts/EventData/MultiTrajectory.hpp" #include "Acts/Geometry/GeometryContext.hpp" -#include "Acts/TrackFitting/KalmanFitterError.hpp" #include "Acts/Utilities/Delegate.hpp" #include "Acts/Utilities/Logger.hpp" #include "Acts/Utilities/Result.hpp" diff --git a/Core/include/Acts/TrackFitting/GainMatrixUpdater.hpp b/Core/include/Acts/TrackFitting/GainMatrixUpdater.hpp index 0ac45a79b1d..9d8ae5a0d03 100644 --- a/Core/include/Acts/TrackFitting/GainMatrixUpdater.hpp +++ b/Core/include/Acts/TrackFitting/GainMatrixUpdater.hpp @@ -80,7 +80,7 @@ class GainMatrixUpdater { // shape later trackState.effectiveCalibrated().data(), trackState.effectiveCalibratedCovariance().data(), - trackState.boundSubspaceIndices(), + trackState.projectorSubspaceIndices(), trackState.predicted(), trackState.predictedCovariance(), trackState.filtered(), diff --git a/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp b/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp index eaa9020053d..dc0bc221e9a 100644 --- a/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp +++ b/Core/include/Acts/TrackFitting/GlobalChiSquareFitter.hpp @@ -423,7 +423,7 @@ void addMeasurementToGx2fSums(Gx2fSystem& extendedSystem, trackState.template calibrated(); const ActsMatrix projector = - trackState.projector().template topLeftCorner(); + trackState.template projectorSubspaceHelper().projector(); const Eigen::MatrixXd projJacobian = projector * extendedJacobian; diff --git a/Core/include/Acts/TrackFitting/MbfSmoother.hpp b/Core/include/Acts/TrackFitting/MbfSmoother.hpp index 02066a642e7..be7a8c12311 100644 --- a/Core/include/Acts/TrackFitting/MbfSmoother.hpp +++ b/Core/include/Acts/TrackFitting/MbfSmoother.hpp @@ -87,9 +87,6 @@ class MbfSmoother { /// Internal track state representation for the smoother. /// @note This allows us to move parts of the implementation into the .cpp struct InternalTrackState final { - using Projector = - typename TrackStateTraits::Projector; using Jacobian = typename TrackStateTraits::Covariance; @@ -105,14 +102,14 @@ class MbfSmoother { // This is used to build a covariance matrix view in the .cpp file const double* calibrated{nullptr}; const double* calibratedCovariance{nullptr}; - Projector projector; + BoundSubspaceIndices projector; template explicit Measurement(TrackStateProxy ts) : calibratedSize(ts.calibratedSize()), calibrated(ts.effectiveCalibrated().data()), calibratedCovariance(ts.effectiveCalibratedCovariance().data()), - projector(ts.projector()) {} + projector(ts.projectorSubspaceIndices()) {} }; Jacobian jacobian; diff --git a/Core/include/Acts/TrackFitting/detail/GainMatrixUpdaterImpl.hpp b/Core/include/Acts/TrackFitting/detail/GainMatrixUpdaterImpl.hpp index 0dce3c2ba21..0437ca551a3 100644 --- a/Core/include/Acts/TrackFitting/detail/GainMatrixUpdaterImpl.hpp +++ b/Core/include/Acts/TrackFitting/detail/GainMatrixUpdaterImpl.hpp @@ -35,7 +35,7 @@ std::tuple GainMatrixUpdater::visitMeasurementImpl( ACTS_VERBOSE("Calibrated measurement: " << calibrated.transpose()); ACTS_VERBOSE("Calibrated measurement covariance:\n" << calibratedCovariance); - std::span validSubspaceIndices( + std::span validSubspaceIndices( trackState.projector.begin(), trackState.projector.begin() + kMeasurementSize); FixedBoundSubspaceHelper subspaceHelper( diff --git a/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp b/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp index 98605052bf6..574a69e8f71 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp @@ -13,6 +13,7 @@ #include "Acts/EventData/MultiComponentTrackParameters.hpp" #include "Acts/EventData/MultiTrajectory.hpp" #include "Acts/EventData/TrackParameters.hpp" +#include "Acts/EventData/Types.hpp" #include "Acts/Utilities/Logger.hpp" #include @@ -154,9 +155,7 @@ double calculateDeterminant( const double *fullCalibratedCovariance, TrackStateTraits::Covariance predictedCovariance, - TrackStateTraits::Projector - projector, - unsigned int calibratedSize); + BoundSubspaceIndices projector, unsigned int calibratedSize); /// Reweight the components according to `R. Frühwirth, "Track fitting /// with non-Gaussian noise"`. See also the implementation in Athena at @@ -190,7 +189,8 @@ void computePosteriorWeights( .template calibratedCovariance< MultiTrajectoryTraits::MeasurementSizeMax>() .data(), - state.predictedCovariance(), state.projector(), state.calibratedSize()); + state.predictedCovariance(), state.projectorSubspaceIndices(), + state.calibratedSize()); const auto factor = std::sqrt(1. / detR) * safeExp(-0.5 * chi2); diff --git a/Core/include/Acts/Utilities/TrackHelpers.hpp b/Core/include/Acts/Utilities/TrackHelpers.hpp index 2e86a62910d..2e40c6b4988 100644 --- a/Core/include/Acts/Utilities/TrackHelpers.hpp +++ b/Core/include/Acts/Utilities/TrackHelpers.hpp @@ -693,8 +693,11 @@ std::pair calculateUnbiasedParametersCovariance( return visit_measurement( trackState.calibratedSize(), [&](std::integral_constant) { - auto H = trackState.projector() - .template topLeftCorner(); + FixedBoundSubspaceHelper subspaceHelper = + trackState.template projectorSubspaceHelper(); + + // TODO use subspace helper for projection instead + auto H = subspaceHelper.projector(); auto s = trackState.smoothed(); auto C = trackState.smoothedCovariance(); auto m = trackState.template calibrated(); diff --git a/Core/src/TrackFinding/MeasurementSelector.cpp b/Core/src/TrackFinding/MeasurementSelector.cpp index 2a3c0e2d390..676cf8074ff 100644 --- a/Core/src/TrackFinding/MeasurementSelector.cpp +++ b/Core/src/TrackFinding/MeasurementSelector.cpp @@ -9,7 +9,6 @@ #include "Acts/TrackFinding/MeasurementSelector.hpp" #include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" #include "Acts/EventData/MeasurementHelpers.hpp" #include "Acts/EventData/SubspaceHelpers.hpp" #include "Acts/EventData/Types.hpp" @@ -19,6 +18,8 @@ #include #include #include +#include +#include namespace Acts { @@ -99,7 +100,7 @@ double MeasurementSelector::calculateChi2( using ParametersVector = ActsVector; - std::span validSubspaceIndices( + std::span validSubspaceIndices( projector.begin(), projector.begin() + kMeasurementSize); FixedBoundSubspaceHelper subspaceHelper( validSubspaceIndices); diff --git a/Core/src/TrackFitting/GsfUtils.cpp b/Core/src/TrackFitting/GsfUtils.cpp index b70544e47c6..8ff52f2c1b6 100644 --- a/Core/src/TrackFitting/GsfUtils.cpp +++ b/Core/src/TrackFitting/GsfUtils.cpp @@ -9,8 +9,12 @@ #include "Acts/TrackFitting/detail/GsfUtils.hpp" #include "Acts/EventData/MeasurementHelpers.hpp" +#include "Acts/EventData/SubspaceHelpers.hpp" +#include "Acts/EventData/Types.hpp" #include +#include +#include namespace Acts::detail { @@ -19,17 +23,20 @@ using TrackStateTraits = double calculateDeterminant(const double* fullCalibratedCovariance, TrackStateTraits::Covariance predictedCovariance, - TrackStateTraits::Projector projector, + BoundSubspaceIndices projector, unsigned int calibratedSize) { return visit_measurement(calibratedSize, [&](auto N) { constexpr std::size_t kMeasurementSize = decltype(N)::value; + std::span validSubspaceIndices( + projector.begin(), projector.begin() + kMeasurementSize); + FixedBoundSubspaceHelper subspaceHelper( + validSubspaceIndices); typename Acts::TrackStateTraits< kMeasurementSize, true>::CalibratedCovariance calibratedCovariance{ fullCalibratedCovariance}; - const auto H = - projector.template topLeftCorner().eval(); + const auto H = subspaceHelper.projector(); return (H * predictedCovariance * H.transpose() + calibratedCovariance) .determinant(); diff --git a/Core/src/TrackFitting/MbfSmoother.cpp b/Core/src/TrackFitting/MbfSmoother.cpp index e260a578e38..9b300989e90 100644 --- a/Core/src/TrackFitting/MbfSmoother.cpp +++ b/Core/src/TrackFitting/MbfSmoother.cpp @@ -10,6 +10,8 @@ #include "Acts/EventData/TrackParameterHelpers.hpp" +#include + namespace Acts { void MbfSmoother::calculateSmoothed(InternalTrackState& ts, @@ -42,9 +44,13 @@ void MbfSmoother::visitMeasurement(const InternalTrackState& ts, visit_measurement(measurement.calibratedSize, [&](auto N) -> void { constexpr std::size_t kMeasurementSize = decltype(N)::value; + std::span validSubspaceIndices( + measurement.projector.begin(), + measurement.projector.begin() + kMeasurementSize); + FixedBoundSubspaceHelper subspaceHelper( + validSubspaceIndices); - using MeasurementMatrix = - Eigen::Matrix; + using ProjectorMatrix = Eigen::Matrix; using CovarianceMatrix = Eigen::Matrix; using KalmanGainMatrix = @@ -55,10 +61,8 @@ void MbfSmoother::visitMeasurement(const InternalTrackState& ts, typename TrackStateTraits::CalibratedCovariance calibratedCovariance{measurement.calibratedCovariance}; - // Measurement matrix - const MeasurementMatrix H = - measurement.projector - .template topLeftCorner(); + // Projector matrix + const ProjectorMatrix H = subspaceHelper.projector(); // Residual covariance const CovarianceMatrix S = diff --git a/Examples/Algorithms/TrackFitting/src/RefittingCalibrator.cpp b/Examples/Algorithms/TrackFitting/src/RefittingCalibrator.cpp index eaf2f74bffa..154dc5d7285 100644 --- a/Examples/Algorithms/TrackFitting/src/RefittingCalibrator.cpp +++ b/Examples/Algorithms/TrackFitting/src/RefittingCalibrator.cpp @@ -35,7 +35,7 @@ void RefittingCalibrator::calibrate(const Acts::GeometryContext& /*gctx*/, sl.state.template calibratedCovariance().eval()); }); - trackState.setBoundSubspaceIndices(sl.state.boundSubspaceIndices()); + trackState.setProjectorSubspaceIndices(sl.state.projectorSubspaceIndices()); } } // namespace ActsExamples diff --git a/Examples/Framework/ML/src/NeuralCalibrator.cpp b/Examples/Framework/ML/src/NeuralCalibrator.cpp index 83e4d11354e..83c7a2bc09a 100644 --- a/Examples/Framework/ML/src/NeuralCalibrator.cpp +++ b/Examples/Framework/ML/src/NeuralCalibrator.cpp @@ -190,6 +190,6 @@ void ActsExamples::NeuralCalibrator::calibrate( calibratedCovariance(boundLoc1, boundLoc1) = output[iVar0 + 1]; trackState.allocateCalibrated(calibratedParameters, calibratedCovariance); - trackState.setSubspaceIndices(fixedMeasurement.subspaceIndices()); + trackState.setProjectorSubspaceIndices(fixedMeasurement.subspaceIndices()); }); } diff --git a/Examples/Framework/src/EventData/MeasurementCalibration.cpp b/Examples/Framework/src/EventData/MeasurementCalibration.cpp index 190d37153bb..d7b8c96da70 100644 --- a/Examples/Framework/src/EventData/MeasurementCalibration.cpp +++ b/Examples/Framework/src/EventData/MeasurementCalibration.cpp @@ -43,7 +43,7 @@ void ActsExamples::PassThroughCalibrator::calibrate( trackState.allocateCalibrated(fixedMeasurement.parameters().eval(), fixedMeasurement.covariance().eval()); - trackState.setSubspaceIndices(fixedMeasurement.subspaceIndices()); + trackState.setProjectorSubspaceIndices(fixedMeasurement.subspaceIndices()); }); } diff --git a/Examples/Framework/src/EventData/ScalingCalibrator.cpp b/Examples/Framework/src/EventData/ScalingCalibrator.cpp index 2a956902513..50e693e8b15 100644 --- a/Examples/Framework/src/EventData/ScalingCalibrator.cpp +++ b/Examples/Framework/src/EventData/ScalingCalibrator.cpp @@ -179,6 +179,6 @@ void ActsExamples::ScalingCalibrator::calibrate( calibratedCovariance(boundLoc1, boundLoc1) *= ct.y_scale; trackState.allocateCalibrated(calibratedParameters, calibratedCovariance); - trackState.setSubspaceIndices(fixedMeasurement.subspaceIndices()); + trackState.setProjectorSubspaceIndices(fixedMeasurement.subspaceIndices()); }); } diff --git a/Examples/Io/Root/src/RootTrackStatesWriter.cpp b/Examples/Io/Root/src/RootTrackStatesWriter.cpp index f90fa96ab0e..37d7cdf2fc9 100644 --- a/Examples/Io/Root/src/RootTrackStatesWriter.cpp +++ b/Examples/Io/Root/src/RootTrackStatesWriter.cpp @@ -452,8 +452,8 @@ ProcessCode RootTrackStatesWriter::writeT(const AlgorithmContext& ctx, m_t_eT.push_back(static_cast(truthParams[Acts::eBoundTime])); // expand the local measurements into the full bound space - Acts::BoundVector meas = state.effectiveProjector().transpose() * - state.effectiveCalibrated(); + Acts::BoundVector meas = state.projectorSubspaceHelper().expandVector( + state.effectiveCalibrated()); // extract local and global position Acts::Vector2 local(meas[Acts::eBoundLoc0], meas[Acts::eBoundLoc1]); Acts::Vector3 global = @@ -633,7 +633,9 @@ ProcessCode RootTrackStatesWriter::writeT(const AlgorithmContext& ctx, if (ipar == ePredicted) { // local hit residual info - auto H = state.effectiveProjector(); + auto H = + state.projectorSubspaceHelper().fullProjector().topLeftCorner( + state.calibratedSize(), Acts::eBoundSize); auto V = state.effectiveCalibratedCovariance(); auto resCov = V + H * covariance * H.transpose(); Acts::ActsDynamicVector res = diff --git a/Tests/Benchmarks/TrackEdmBenchmark.cpp b/Tests/Benchmarks/TrackEdmBenchmark.cpp index a85b0482be2..ce14eef8e8a 100644 --- a/Tests/Benchmarks/TrackEdmBenchmark.cpp +++ b/Tests/Benchmarks/TrackEdmBenchmark.cpp @@ -149,7 +149,7 @@ int main(int /*argc*/, char** /*argv[]*/) { std::array indices{0}; std::iota(indices.begin(), indices.end(), 0); - trackState.setBoundSubspaceIndices(indices); + trackState.setProjectorSubspaceIndices(indices); }); trackState.typeFlags().set(TrackStateFlag::MeasurementFlag); diff --git a/Tests/UnitTests/Core/EventData/TrackTestsExtra.cpp b/Tests/UnitTests/Core/EventData/TrackTestsExtra.cpp index f2f27ed8522..ecf49d7cd5b 100644 --- a/Tests/UnitTests/Core/EventData/TrackTestsExtra.cpp +++ b/Tests/UnitTests/Core/EventData/TrackTestsExtra.cpp @@ -457,7 +457,7 @@ BOOST_AUTO_TEST_CASE(CopyTrackProxyCalibrated) { auto track1 = tc.makeTrack(); auto ts = track1.appendTrackState(TrackStatePropMask::Calibrated); ts.allocateCalibrated(kMeasurementSize); - ts.setSubspaceIndices(BoundSubspaceIndices{}); + ts.setProjectorSubspaceIndices(BoundSubspaceIndices{}); auto tsCopy = track1.appendTrackState(TrackStatePropMask::Calibrated); tsCopy.copyFrom(ts, TrackStatePropMask::Calibrated, false); diff --git a/Tests/UnitTests/Core/TrackFitting/FitterTestsCommon.hpp b/Tests/UnitTests/Core/TrackFitting/FitterTestsCommon.hpp index 269370d4fc4..dca8ac045ca 100644 --- a/Tests/UnitTests/Core/TrackFitting/FitterTestsCommon.hpp +++ b/Tests/UnitTests/Core/TrackFitting/FitterTestsCommon.hpp @@ -10,6 +10,7 @@ #include +#include "Acts/Definitions/TrackParametrization.hpp" #include "Acts/Definitions/Units.hpp" #include "Acts/EventData/MultiTrajectory.hpp" #include "Acts/EventData/ProxyAccessor.hpp" @@ -56,9 +57,13 @@ struct TestOutlierFinder { if (!state.hasCalibrated() || !state.hasPredicted()) { return false; } - auto residuals = (state.effectiveCalibrated() - - state.effectiveProjector() * state.predicted()) - .eval(); + auto subspaceHelper = state.projectorSubspaceHelper(); + auto projector = + subspaceHelper.fullProjector() + .topLeftCorner(state.calibratedSize(), Acts::eBoundSize) + .eval(); + auto residuals = + (state.effectiveCalibrated() - projector * state.predicted()).eval(); auto distance = residuals.norm(); return (distanceMax <= distance); } diff --git a/Tests/UnitTests/Core/TrackFitting/MbfSmootherTests.cpp b/Tests/UnitTests/Core/TrackFitting/MbfSmootherTests.cpp index 21d0a347e56..e87d386b5b5 100644 --- a/Tests/UnitTests/Core/TrackFitting/MbfSmootherTests.cpp +++ b/Tests/UnitTests/Core/TrackFitting/MbfSmootherTests.cpp @@ -8,9 +8,7 @@ #include -#include "Acts/Definitions/Algebra.hpp" #include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/EventData/MultiTrajectory.hpp" #include "Acts/EventData/TrackStatePropMask.hpp" #include "Acts/EventData/TrackStateType.hpp" #include "Acts/EventData/VectorMultiTrajectory.hpp" @@ -19,7 +17,6 @@ #include "Acts/TrackFitting/MbfSmoother.hpp" #include "Acts/Utilities/Result.hpp" -#include #include #include @@ -59,7 +56,7 @@ BOOST_AUTO_TEST_CASE(Smooth) { ts.allocateCalibrated(2); ts.calibrated<2>() << 0.351, 0.473; ts.calibratedCovariance<2>() << 1e+8, 0., 0., 1e+8; - ts.setSubspaceIndices<2>(projector); + ts.setProjectorSubspaceIndices(projector); ts.filtered() << 0.301, 0.503, std::numbers::pi / 2., 0., 1 / 100., 0.; ts.filteredCovariance() = covTrk; @@ -76,7 +73,7 @@ BOOST_AUTO_TEST_CASE(Smooth) { ts.allocateCalibrated(2); ts.calibrated<2>() << 0.351, 0.473; ts.calibratedCovariance<2>() << 1e+8, 0., 0., 1e+8; - ts.setSubspaceIndices<2>(projector); + ts.setProjectorSubspaceIndices(projector); ts.filtered() << 0.27, 0.53, std::numbers::pi / 2., 0., 1 / 100., 0.; ts.filteredCovariance() = covTrk; @@ -93,7 +90,7 @@ BOOST_AUTO_TEST_CASE(Smooth) { ts.allocateCalibrated(2); ts.calibrated<2>() << 0.351, 0.473; ts.calibratedCovariance<2>() << 1e+8, 0., 0., 1e+8; - ts.setSubspaceIndices<2>(projector); + ts.setProjectorSubspaceIndices(projector); ts.filtered() << 0.33, 0.43, std::numbers::pi / 2., 0., 1 / 100., 0.; ts.filteredCovariance() = covTrk; From 9c9444e35b0fd71374ce0fa4c9ff3c55854dc976 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Fri, 29 Nov 2024 11:17:57 +0100 Subject: [PATCH 09/12] refactor: Replace `ParticleSmearing` with `TrackParameterSmearing` in Examples (#3784) - extract track parameters from particles - replace `ParticleSmearing` with `TrackParameterSmearing` ## Summary by CodeRabbit - **New Features** - Introduced `TrackParameterSmearing` and `ParticleTrackParamExtractor` classes for enhanced track parameter processing. - Updated smearing configurations and parameters to improve clarity and usability. - Enhanced Python bindings for various generator classes, allowing for customizable event generation. - **Bug Fixes** - Adjusted logging levels for new algorithms to ensure appropriate verbosity. - **Documentation** - Updated comments and documentation to reflect changes in parameter names and functionalities. - **Chores** - Removed deprecated `ParticleSmearing` algorithm and associated files from the project. --- .../workflows/physmon_trackfinding_1muon.py | 18 +- .../Generators/EventGenerator.cpp | 21 ++- .../Generators/EventGenerator.hpp | 4 +- .../TruthTracking/ParticleSmearing.cpp | 158 ---------------- .../ParticleTrackParamExtractor.cpp | 72 +++++++ .../ParticleTrackParamExtractor.hpp | 48 +++++ .../TruthTracking/TrackParameterSmearing.cpp | 175 ++++++++++++++++++ ...mearing.hpp => TrackParameterSmearing.hpp} | 49 ++--- .../Algorithms/TruthTracking/CMakeLists.txt | 3 +- .../python/acts/examples/reconstruction.py | 67 ++++--- Examples/Python/src/Generators.cpp | 2 - Examples/Python/src/TruthTracking.cpp | 17 +- Examples/Python/tests/conftest.py | 19 +- Examples/Python/tests/root_file_hashes.txt | 12 +- Examples/Python/tests/test_algorithms.py | 4 +- Examples/Python/tests/test_propagation.py | 25 +-- Examples/Scripts/Optimization/ckf.py | 18 +- Examples/Scripts/Python/ckf_tracks.py | 18 +- Examples/Scripts/Python/full_chain_test.py | 4 +- .../Scripts/Python/material_validation.py | 16 +- .../Scripts/Python/material_validation_itk.py | 22 +-- Examples/Scripts/Python/propagation.py | 17 +- Examples/Scripts/Python/vertex_fitting.py | 13 +- 23 files changed, 471 insertions(+), 331 deletions(-) delete mode 100644 Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp create mode 100644 Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleTrackParamExtractor.cpp create mode 100644 Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleTrackParamExtractor.hpp create mode 100644 Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TrackParameterSmearing.cpp rename Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/{ParticleSmearing.hpp => TrackParameterSmearing.hpp} (61%) diff --git a/CI/physmon/workflows/physmon_trackfinding_1muon.py b/CI/physmon/workflows/physmon_trackfinding_1muon.py index aaa4bc9f71d..90305112099 100755 --- a/CI/physmon/workflows/physmon_trackfinding_1muon.py +++ b/CI/physmon/workflows/physmon_trackfinding_1muon.py @@ -18,7 +18,7 @@ from acts.examples.reconstruction import ( addSeeding, - ParticleSmearingSigmas, + TrackSmearingSigmas, SeedFinderConfigArg, SeedFinderOptionsArg, SeedingAlgorithm, @@ -91,15 +91,15 @@ def run_ckf_tracking(label, seeding): s, setup.trackingGeometry, setup.field, - ParticleSmearingSigmas( # only used by SeedingAlgorithm.TruthSmeared + TrackSmearingSigmas( # only used by SeedingAlgorithm.TruthSmeared # zero eveything so the CKF has a chance to find the measurements - d0=0, - d0PtA=0, - d0PtB=0, - z0=0, - z0PtA=0, - z0PtB=0, - t0=0, + loc0=0, + loc0PtA=0, + loc0PtB=0, + loc1=0, + loc1PtA=0, + loc1PtB=0, + time=0, phi=0, theta=0, ptRel=0, diff --git a/Examples/Algorithms/Generators/ActsExamples/Generators/EventGenerator.cpp b/Examples/Algorithms/Generators/ActsExamples/Generators/EventGenerator.cpp index a11d62c928f..9d5c1b873d3 100644 --- a/Examples/Algorithms/Generators/ActsExamples/Generators/EventGenerator.cpp +++ b/Examples/Algorithms/Generators/ActsExamples/Generators/EventGenerator.cpp @@ -8,17 +8,23 @@ #include "ActsExamples/Generators/EventGenerator.hpp" +#include "Acts/Surfaces/PerigeeSurface.hpp" #include "ActsExamples/EventData/SimVertex.hpp" +#include "ActsExamples/EventData/Track.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" #include "ActsFatras/EventData/Barcode.hpp" #include "ActsFatras/EventData/Particle.hpp" #include +#include +#include #include #include +#include -ActsExamples::EventGenerator::EventGenerator(const Config& cfg, - Acts::Logging::Level lvl) +namespace ActsExamples { + +EventGenerator::EventGenerator(const Config& cfg, Acts::Logging::Level lvl) : m_cfg(cfg), m_logger(Acts::getDefaultLogger("EventGenerator", lvl)) { if (m_cfg.outputParticles.empty()) { throw std::invalid_argument("Missing output particles collection"); @@ -37,17 +43,15 @@ ActsExamples::EventGenerator::EventGenerator(const Config& cfg, m_outputVertices.initialize(m_cfg.outputVertices); } -std::string ActsExamples::EventGenerator::name() const { +std::string EventGenerator::name() const { return "EventGenerator"; } -std::pair -ActsExamples::EventGenerator::availableEvents() const { +std::pair EventGenerator::availableEvents() const { return {0u, std::numeric_limits::max()}; } -ActsExamples::ProcessCode ActsExamples::EventGenerator::read( - const AlgorithmContext& ctx) { +ProcessCode EventGenerator::read(const AlgorithmContext& ctx) { SimParticleContainer particles; SimVertexContainer vertices; @@ -120,5 +124,8 @@ ActsExamples::ProcessCode ActsExamples::EventGenerator::read( // move generated event to the store m_outputParticles(ctx, std::move(particles)); m_outputVertices(ctx, std::move(vertices)); + return ProcessCode::SUCCESS; } + +} // namespace ActsExamples diff --git a/Examples/Algorithms/Generators/ActsExamples/Generators/EventGenerator.hpp b/Examples/Algorithms/Generators/ActsExamples/Generators/EventGenerator.hpp index 46720b9fff1..7a76ac03d71 100644 --- a/Examples/Algorithms/Generators/ActsExamples/Generators/EventGenerator.hpp +++ b/Examples/Algorithms/Generators/ActsExamples/Generators/EventGenerator.hpp @@ -18,7 +18,6 @@ #include "ActsExamples/Framework/RandomNumbers.hpp" #include -#include #include #include #include @@ -93,8 +92,9 @@ class EventGenerator final : public ActsExamples::IReader { struct Config { /// Name of the output particles collection. std::string outputParticles; - /// Name of the vertex collection. + /// Name of the output vertex collection. std::string outputVertices; + /// List of generators that should be used to generate the event. std::vector generators; /// The random number service. diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp deleted file mode 100644 index 4c09134ef20..00000000000 --- a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.cpp +++ /dev/null @@ -1,158 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -#include "ActsExamples/TruthTracking/ParticleSmearing.hpp" - -#include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/Seeding/EstimateTrackParamsFromSeed.hpp" -#include "Acts/Surfaces/PerigeeSurface.hpp" -#include "Acts/Surfaces/Surface.hpp" -#include "Acts/Utilities/detail/periodic.hpp" -#include "ActsExamples/EventData/SimParticle.hpp" -#include "ActsExamples/EventData/Track.hpp" -#include "ActsExamples/Framework/AlgorithmContext.hpp" -#include "ActsExamples/Framework/RandomNumbers.hpp" - -#include -#include -#include -#include -#include - -ActsExamples::ParticleSmearing::ParticleSmearing(const Config& config, - Acts::Logging::Level level) - : IAlgorithm("ParticleSmearing", level), m_cfg(config) { - if (m_cfg.inputParticles.empty()) { - throw std::invalid_argument("Missing input truth particles collection"); - } - if (m_cfg.outputTrackParameters.empty()) { - throw std::invalid_argument("Missing output tracks parameters collection"); - } - if (m_cfg.randomNumbers == nullptr) { - throw std::invalid_argument("Missing random numbers tool"); - } - - if (m_cfg.particleHypothesis) { - ACTS_INFO("Override truth particle hypothesis with " - << *m_cfg.particleHypothesis); - } - - m_inputParticles.initialize(m_cfg.inputParticles); - m_outputTrackParameters.initialize(m_cfg.outputTrackParameters); -} - -ActsExamples::ProcessCode ActsExamples::ParticleSmearing::execute( - const AlgorithmContext& ctx) const { - // setup input and output containers - const auto& particles = m_inputParticles(ctx); - TrackParametersContainer parameters; - parameters.reserve(particles.size()); - - // setup random number generator and standard gaussian - auto rng = m_cfg.randomNumbers->spawnGenerator(ctx); - std::normal_distribution stdNormal(0.0, 1.0); - - for (auto&& [vtxId, vtxParticles] : groupBySecondaryVertex(particles)) { - // a group contains at least one particle by construction. assume that all - // particles within the group originate from the same position and use it to - // as the reference position for the perigee frame. - auto perigee = Acts::Surface::makeShared( - vtxParticles.begin()->position()); - - for (const auto& particle : vtxParticles) { - const auto time = particle.time(); - const auto phi = Acts::VectorHelpers::phi(particle.direction()); - const auto theta = Acts::VectorHelpers::theta(particle.direction()); - const auto pt = particle.transverseMomentum(); - const auto p = particle.absoluteMomentum(); - const auto qOverP = particle.qOverP(); - const auto particleHypothesis = - m_cfg.particleHypothesis.value_or(particle.hypothesis()); - - // compute momentum-dependent resolutions - const double sigmaD0 = - m_cfg.sigmaD0 + - m_cfg.sigmaD0PtA * std::exp(-1.0 * std::abs(m_cfg.sigmaD0PtB) * pt); - const double sigmaZ0 = - m_cfg.sigmaZ0 + - m_cfg.sigmaZ0PtA * std::exp(-1.0 * std::abs(m_cfg.sigmaZ0PtB) * pt); - // shortcuts for other resolutions - const double sigmaT0 = m_cfg.sigmaT0; - const double sigmaPhi = m_cfg.sigmaPhi; - const double sigmaTheta = m_cfg.sigmaTheta; - const double sigmaQOverP = - std::sqrt(std::pow(m_cfg.sigmaPtRel * qOverP, 2) + - std::pow(sigmaTheta * (qOverP * std::tan(theta)), 2)); - - Acts::BoundVector params = Acts::BoundVector::Zero(); - // smear the position/time - // note that we smear d0 and z0 in the perigee frame - params[Acts::eBoundLoc0] = sigmaD0 * stdNormal(rng); - params[Acts::eBoundLoc1] = sigmaZ0 * stdNormal(rng); - params[Acts::eBoundTime] = time + sigmaT0 * stdNormal(rng); - // smear direction angles phi,theta ensuring correct bounds - const auto [newPhi, newTheta] = Acts::detail::normalizePhiTheta( - phi + sigmaPhi * stdNormal(rng), theta + sigmaTheta * stdNormal(rng)); - params[Acts::eBoundPhi] = newPhi; - params[Acts::eBoundTheta] = newTheta; - // compute smeared q/p - params[Acts::eBoundQOverP] = qOverP + sigmaQOverP * stdNormal(rng); - - ACTS_VERBOSE("Smearing particle (pos, time, phi, theta, q/p):"); - ACTS_VERBOSE(" from: " << particle.position().transpose() << ", " << time - << ", " << phi << ", " << theta << ", " << qOverP); - ACTS_VERBOSE(" to: " << perigee - ->localToGlobal( - ctx.geoContext, - Acts::Vector2{params[Acts::eBoundLoc0], - params[Acts::eBoundLoc1]}, - particle.direction() * p) - .transpose() - << ", " << params[Acts::eBoundTime] << ", " - << params[Acts::eBoundPhi] << ", " - << params[Acts::eBoundTheta] << ", " - << params[Acts::eBoundQOverP]); - - // build the track covariance matrix using the smearing sigmas - Acts::BoundSquareMatrix cov = Acts::BoundSquareMatrix::Zero(); - if (m_cfg.initialSigmas) { - // use the initial sigmas if set - - Acts::EstimateTrackParamCovarianceConfig config{ - .initialSigmas = - Eigen::Map{ - m_cfg.initialSigmas->data()}, - .initialSigmaPtRel = m_cfg.initialSigmaPtRel, - .initialVarInflation = Eigen::Map{ - m_cfg.initialVarInflation.data()}}; - - cov = Acts::estimateTrackParamCovariance(config, params, false); - } else { - // otherwise use the smearing sigmas - - Acts::BoundVector sigmas = Acts::BoundVector( - {sigmaD0, sigmaZ0, sigmaPhi, sigmaTheta, sigmaQOverP, sigmaT0}); - - for (std::size_t i = Acts::eBoundLoc0; i < Acts::eBoundSize; ++i) { - double sigma = sigmas[i]; - double variance = sigma * sigma; - - // Inflate the initial covariance - variance *= m_cfg.initialVarInflation[i]; - - cov(i, i) = variance; - } - } - parameters.emplace_back(perigee, params, cov, particleHypothesis); - } - } - - m_outputTrackParameters(ctx, std::move(parameters)); - return ProcessCode::SUCCESS; -} diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleTrackParamExtractor.cpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleTrackParamExtractor.cpp new file mode 100644 index 00000000000..d480ca8f88f --- /dev/null +++ b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleTrackParamExtractor.cpp @@ -0,0 +1,72 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "ActsExamples/TruthTracking/ParticleTrackParamExtractor.hpp" + +#include "Acts/Surfaces/PerigeeSurface.hpp" +#include "ActsExamples/EventData/SimParticle.hpp" +#include "ActsExamples/Framework/AlgorithmContext.hpp" + +#include +#include + +namespace ActsExamples { + +ParticleTrackParamExtractor::ParticleTrackParamExtractor( + const Config& config, Acts::Logging::Level level) + : IAlgorithm("ParticleTrackParamExtractor", level), m_cfg(config) { + if (m_cfg.inputParticles.empty()) { + throw std::invalid_argument("Missing input particles collection"); + } + if (m_cfg.outputTrackParameters.empty()) { + throw std::invalid_argument("Missing output track parameters collection"); + } + + m_inputParticles.initialize(m_cfg.inputParticles); + m_outputTrackParameters.initialize(m_cfg.outputTrackParameters); +} + +ActsExamples::ProcessCode ParticleTrackParamExtractor::execute( + const AlgorithmContext& ctx) const { + const SimParticleContainer& particles = m_inputParticles(ctx); + + std::unordered_map> + perigeeSurfaces; + + for (auto&& [vtxId, vtxParticles] : groupBySecondaryVertex(particles)) { + // a group contains at least one particle by construction. assume that all + // particles within the group originate from the same position and use it + // to as the reference position for the perigee frame. + auto perigee = Acts::Surface::makeShared( + vtxParticles.begin()->position()); + perigeeSurfaces[vtxId] = perigee; + } + + // create track parameters from the particles + TrackParametersContainer trackParameters; + + for (const auto& particle : particles) { + const auto vtxId = particle.particleId().vertexId(); + const auto particleHypothesis = particle.hypothesis(); + const auto phi = Acts::VectorHelpers::phi(particle.direction()); + const auto theta = Acts::VectorHelpers::theta(particle.direction()); + const auto qOverP = particle.qOverP(); + const auto time = particle.time(); + + trackParameters.emplace_back( + perigeeSurfaces.at(vtxId), + Acts::BoundVector{0, 0, phi, theta, qOverP, time}, std::nullopt, + particleHypothesis); + } + + m_outputTrackParameters(ctx, std::move(trackParameters)); + + return ProcessCode::SUCCESS; +} + +} // namespace ActsExamples diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleTrackParamExtractor.hpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleTrackParamExtractor.hpp new file mode 100644 index 00000000000..60882fa9ace --- /dev/null +++ b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleTrackParamExtractor.hpp @@ -0,0 +1,48 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/Utilities/Logger.hpp" +#include "ActsExamples/EventData/SimParticle.hpp" +#include "ActsExamples/EventData/Track.hpp" +#include "ActsExamples/Framework/DataHandle.hpp" +#include "ActsExamples/Framework/IAlgorithm.hpp" +#include "ActsExamples/Framework/ProcessCode.hpp" + +#include + +namespace ActsExamples { +struct AlgorithmContext; + +/// Extract track parameters from particles. +class ParticleTrackParamExtractor final : public IAlgorithm { + public: + struct Config { + /// The input particles collection. + std::string inputParticles; + /// The output track parameters collection. + std::string outputTrackParameters; + }; + + ParticleTrackParamExtractor(const Config& config, Acts::Logging::Level level); + + ProcessCode execute(const AlgorithmContext& ctx) const final; + + /// Get readonly access to the config parameters + const Config& config() const { return m_cfg; } + + private: + Config m_cfg; + + ReadDataHandle m_inputParticles{this, "InputParticles"}; + WriteDataHandle m_outputTrackParameters{ + this, "OutputTrackParameters"}; +}; + +} // namespace ActsExamples diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TrackParameterSmearing.cpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TrackParameterSmearing.cpp new file mode 100644 index 00000000000..f1789749f77 --- /dev/null +++ b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TrackParameterSmearing.cpp @@ -0,0 +1,175 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "ActsExamples/TruthTracking/TrackParameterSmearing.hpp" + +#include "Acts/Seeding/EstimateTrackParamsFromSeed.hpp" +#include "ActsExamples/EventData/Track.hpp" +#include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Framework/RandomNumbers.hpp" + +#include +#include +#include + +namespace ActsExamples { + +TrackParameterSmearing::TrackParameterSmearing(const Config& config, + Acts::Logging::Level level) + : IAlgorithm("TrackParameterSmearing", level), m_cfg(config) { + if (m_cfg.inputTrackParameters.empty()) { + throw std::invalid_argument("Missing input track parameters collection"); + } + if (m_cfg.outputTrackParameters.empty()) { + throw std::invalid_argument("Missing output track parameters collection"); + } + if (m_cfg.randomNumbers == nullptr) { + throw std::invalid_argument("Missing random numbers tool"); + } + + if (m_cfg.particleHypothesis) { + ACTS_INFO("Override truth particle hypothesis with " + << *m_cfg.particleHypothesis); + } + + m_inputTrackParameters.initialize(m_cfg.inputTrackParameters); + m_outputTrackParameters.initialize(m_cfg.outputTrackParameters); + + ACTS_DEBUG("smearing track param loc0 " << m_cfg.sigmaLoc0 << " A " + << m_cfg.sigmaLoc0PtA << " B " + << m_cfg.sigmaLoc0PtB); + ACTS_DEBUG("smearing track param loc1 " << m_cfg.sigmaLoc1 << " A " + << m_cfg.sigmaLoc1PtA << " B " + << m_cfg.sigmaLoc1PtB); + ACTS_DEBUG("smearing track param time " << m_cfg.sigmaTime); + ACTS_DEBUG("smearing track param phi " << m_cfg.sigmaPhi); + ACTS_DEBUG("smearing track param theta " << m_cfg.sigmaTheta); + ACTS_DEBUG("smearing track param q/p " << m_cfg.sigmaPtRel); + ACTS_DEBUG( + "initial sigmas " + << Acts::BoundVector( + m_cfg.initialSigmas.value_or(std::array()).data()) + .transpose()); + ACTS_DEBUG("initial sigma pt rel " << m_cfg.initialSigmaPtRel); + ACTS_DEBUG( + "initial var inflation " + << Acts::BoundVector(m_cfg.initialVarInflation.data()).transpose()); + if (m_cfg.particleHypothesis) { + ACTS_DEBUG("particle hypothesis " << *m_cfg.particleHypothesis); + } else { + ACTS_DEBUG("particle hypothesis truth"); + } +} + +ProcessCode TrackParameterSmearing::execute(const AlgorithmContext& ctx) const { + // setup input and output containers + const auto& inputTrackParametersContainer = m_inputTrackParameters(ctx); + + ACTS_VERBOSE("Smearing " << inputTrackParametersContainer.size() + << " track parameters"); + + TrackParametersContainer outputTrackParametersContainer; + outputTrackParametersContainer.reserve(inputTrackParametersContainer.size()); + + // setup random number generator and standard gaussian + auto rng = m_cfg.randomNumbers->spawnGenerator(ctx); + std::normal_distribution stdNormal(0.0, 1.0); + + for (const auto& inputTrackParameters : inputTrackParametersContainer) { + const auto position = inputTrackParameters.localPosition(); + const auto time = inputTrackParameters.time(); + const auto phi = inputTrackParameters.phi(); + const auto theta = inputTrackParameters.theta(); + const auto pt = inputTrackParameters.transverseMomentum(); + const auto qOverP = inputTrackParameters.qOverP(); + const auto particleHypothesis = m_cfg.particleHypothesis.value_or( + inputTrackParameters.particleHypothesis()); + + // compute momentum-dependent resolutions + const double sigmaLoc0 = + m_cfg.sigmaLoc0 + + m_cfg.sigmaLoc0PtA * std::exp(-1.0 * std::abs(m_cfg.sigmaLoc0PtB) * pt); + const double sigmaLoc1 = + m_cfg.sigmaLoc1 + + m_cfg.sigmaLoc1PtA * std::exp(-1.0 * std::abs(m_cfg.sigmaLoc1PtB) * pt); + // shortcuts for other resolutions + const double sigmaTime = m_cfg.sigmaTime; + const double sigmaPhi = m_cfg.sigmaPhi; + const double sigmaTheta = m_cfg.sigmaTheta; + const double sigmaQOverP = + std::sqrt(std::pow(m_cfg.sigmaPtRel * qOverP, 2) + + std::pow(sigmaTheta * (qOverP * std::tan(theta)), 2)); + + Acts::BoundVector params = Acts::BoundVector::Zero(); + // smear the position/time + // note that we smear d0 and z0 in the perigee frame + params[Acts::eBoundLoc0] = position[0] + sigmaLoc0 * stdNormal(rng); + params[Acts::eBoundLoc1] = position[1] + sigmaLoc1 * stdNormal(rng); + params[Acts::eBoundTime] = time + sigmaTime * stdNormal(rng); + // smear direction angles phi,theta ensuring correct bounds + const auto [newPhi, newTheta] = Acts::detail::normalizePhiTheta( + phi + sigmaPhi * stdNormal(rng), theta + sigmaTheta * stdNormal(rng)); + params[Acts::eBoundPhi] = newPhi; + params[Acts::eBoundTheta] = newTheta; + // compute smeared q/p + params[Acts::eBoundQOverP] = qOverP + sigmaQOverP * stdNormal(rng); + + // build the track covariance matrix using the smearing sigmas + Acts::BoundSquareMatrix cov = Acts::BoundSquareMatrix::Zero(); + if (m_cfg.initialSigmas) { + // use the initial sigmas if set + + Acts::EstimateTrackParamCovarianceConfig config{ + .initialSigmas = + Eigen::Map{m_cfg.initialSigmas->data()}, + .initialSigmaPtRel = m_cfg.initialSigmaPtRel, + .initialVarInflation = Eigen::Map{ + m_cfg.initialVarInflation.data()}}; + + cov = Acts::estimateTrackParamCovariance(config, params, false); + } else { + // otherwise use the smearing sigmas + + Acts::BoundVector sigmas = Acts::BoundVector( + {sigmaLoc0, sigmaLoc1, sigmaPhi, sigmaTheta, sigmaQOverP, sigmaTime}); + + for (std::size_t i = Acts::eBoundLoc0; i < Acts::eBoundSize; ++i) { + double sigma = sigmas[i]; + double variance = sigma * sigma; + + // Inflate the initial covariance + variance *= m_cfg.initialVarInflation[i]; + + cov(i, i) = variance; + } + } + + const auto& outputTrackParameters = + outputTrackParametersContainer.emplace_back( + inputTrackParameters.referenceSurface().shared_from_this(), params, + cov, particleHypothesis); + + ACTS_VERBOSE("Smearing particle (pos, time, phi, theta, q/p):"); + ACTS_VERBOSE( + " from: " << inputTrackParameters.position(ctx.geoContext).transpose() + << ", " << time << ", " << phi << ", " << theta << ", " + << qOverP); + ACTS_VERBOSE( + " to: " << outputTrackParameters.position(ctx.geoContext).transpose() + << ", " << params[Acts::eBoundTime] << ", " + << params[Acts::eBoundPhi] << ", " + << params[Acts::eBoundTheta] << ", " + << params[Acts::eBoundQOverP]); + } + + m_outputTrackParameters(ctx, std::move(outputTrackParametersContainer)); + + return ProcessCode::SUCCESS; +} + +} // namespace ActsExamples diff --git a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.hpp b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TrackParameterSmearing.hpp similarity index 61% rename from Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.hpp rename to Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TrackParameterSmearing.hpp index 3b60f12b099..53bab3b62e5 100644 --- a/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.hpp +++ b/Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TrackParameterSmearing.hpp @@ -11,7 +11,6 @@ #include "Acts/Definitions/Units.hpp" #include "Acts/EventData/ParticleHypothesis.hpp" #include "Acts/Utilities/Logger.hpp" -#include "ActsExamples/EventData/SimParticle.hpp" #include "ActsExamples/EventData/Track.hpp" #include "ActsExamples/Framework/DataHandle.hpp" #include "ActsExamples/Framework/IAlgorithm.hpp" @@ -19,7 +18,6 @@ #include "ActsExamples/Framework/RandomNumbers.hpp" #include -#include #include #include #include @@ -28,36 +26,38 @@ namespace ActsExamples { class RandomNumbers; struct AlgorithmContext; -/// Create track states by smearing truth particle information. +/// @brief Smear track parameters. /// -/// Particles are smeared in the perigee frame anchored at their true vertex -/// position. The `d0` and `z0` parameters are always defined within that -/// perigee frame and not globally. The generated bound parameters are stored in -/// the same order as the input particles. -class ParticleSmearing final : public IAlgorithm { +/// Track parameters are smeared in the local frame. The `loc0` and `loc1` +/// parameters are always defined within that local frame and not globally. The +/// generated bound parameters are stored in the same order as the input +/// parameters. +class TrackParameterSmearing final : public IAlgorithm { public: struct Config { - /// Input truth particles collection. - std::string inputParticles; - /// Output smeared tracks parameters collection. + /// Input track parameters collection. + std::string inputTrackParameters; + /// Output smeared track parameters collection. std::string outputTrackParameters; /// Random numbers service. std::shared_ptr randomNumbers = nullptr; // Smearing parameters - /// Constant term of the d0 resolution. - double sigmaD0 = 20 * Acts::UnitConstants::um; - /// Pt-dependent d0 resolution of the form sigma_d0 = A*exp(-1.*abs(B)*pt). - double sigmaD0PtA = 30 * Acts::UnitConstants::um; - double sigmaD0PtB = 0.3 / Acts::UnitConstants::GeV; - /// Constant term of the z0 resolution. - double sigmaZ0 = 20 * Acts::UnitConstants::um; - /// Pt-dependent z0 resolution of the form sigma_z0 = A*exp(-1.*abs(B)*pt). - double sigmaZ0PtA = 30 * Acts::UnitConstants::um; - double sigmaZ0PtB = 0.3 / Acts::UnitConstants::GeV; + /// Constant term of the loc0 resolution. + double sigmaLoc0 = 20 * Acts::UnitConstants::um; + /// Pt-dependent loc0 resolution of the form sigma_loc0 = + /// A*exp(-1.*abs(B)*pt). + double sigmaLoc0PtA = 30 * Acts::UnitConstants::um; + double sigmaLoc0PtB = 0.3 / Acts::UnitConstants::GeV; + /// Constant term of the loc1 resolution. + double sigmaLoc1 = 20 * Acts::UnitConstants::um; + /// Pt-dependent loc1 resolution of the form sigma_loc1 = + /// A*exp(-1.*abs(B)*pt). + double sigmaLoc1PtA = 30 * Acts::UnitConstants::um; + double sigmaLoc1PtB = 0.3 / Acts::UnitConstants::GeV; /// Time resolution. - double sigmaT0 = 1 * Acts::UnitConstants::ns; + double sigmaTime = 1 * Acts::UnitConstants::ns; /// Phi angular resolution. double sigmaPhi = 1 * Acts::UnitConstants::degree; /// Theta angular resolution. @@ -77,7 +77,7 @@ class ParticleSmearing final : public IAlgorithm { std::optional particleHypothesis = std::nullopt; }; - ParticleSmearing(const Config& config, Acts::Logging::Level level); + TrackParameterSmearing(const Config& config, Acts::Logging::Level level); ProcessCode execute(const AlgorithmContext& ctx) const override; @@ -87,7 +87,8 @@ class ParticleSmearing final : public IAlgorithm { private: Config m_cfg; - ReadDataHandle m_inputParticles{this, "InputParticles"}; + ReadDataHandle m_inputTrackParameters{ + this, "InputTrackParameters"}; WriteDataHandle m_outputTrackParameters{ this, "OutputTrackParameters"}; diff --git a/Examples/Algorithms/TruthTracking/CMakeLists.txt b/Examples/Algorithms/TruthTracking/CMakeLists.txt index 280e1104ce2..9f576efa1b4 100644 --- a/Examples/Algorithms/TruthTracking/CMakeLists.txt +++ b/Examples/Algorithms/TruthTracking/CMakeLists.txt @@ -2,7 +2,8 @@ add_library( ActsExamplesTruthTracking SHARED ActsExamples/TruthTracking/ParticleSelector.cpp - ActsExamples/TruthTracking/ParticleSmearing.cpp + ActsExamples/TruthTracking/ParticleTrackParamExtractor.cpp + ActsExamples/TruthTracking/TrackParameterSmearing.cpp ActsExamples/TruthTracking/TrackParameterSelector.cpp ActsExamples/TruthTracking/TrackModifier.cpp ActsExamples/TruthTracking/TrackTruthMatcher.cpp diff --git a/Examples/Python/python/acts/examples/reconstruction.py b/Examples/Python/python/acts/examples/reconstruction.py index 0d1131d45cf..a365572cabc 100644 --- a/Examples/Python/python/acts/examples/reconstruction.py +++ b/Examples/Python/python/acts/examples/reconstruction.py @@ -13,9 +13,20 @@ "Default TruthSmeared TruthEstimated Orthogonal HoughTransform Gbts Hashing", ) -ParticleSmearingSigmas = namedtuple( - "ParticleSmearingSigmas", - ["d0", "d0PtA", "d0PtB", "z0", "z0PtA", "z0PtB", "t0", "phi", "theta", "ptRel"], +TrackSmearingSigmas = namedtuple( + "TrackSmearingSigmas", + [ + "loc0", + "loc0PtA", + "loc0PtB", + "loc1", + "loc1PtA", + "loc1PtB", + "time", + "phi", + "theta", + "ptRel", + ], defaults=[None] * 10, ) @@ -256,7 +267,7 @@ class VertexFinder(Enum): @acts.examples.NamedTypeArgs( seedingAlgorithm=SeedingAlgorithm, - particleSmearingSigmas=ParticleSmearingSigmas, + trackSmearingSigmas=TrackSmearingSigmas, seedFinderConfigArg=SeedFinderConfigArg, seedFinderOptionsArg=SeedFinderOptionsArg, seedFilterConfigArg=SeedFilterConfigArg, @@ -275,7 +286,7 @@ def addSeeding( layerMappingConfigFile: Optional[Union[Path, str]] = None, connector_inputConfigFile: Optional[Union[Path, str]] = None, seedingAlgorithm: SeedingAlgorithm = SeedingAlgorithm.Default, - particleSmearingSigmas: ParticleSmearingSigmas = ParticleSmearingSigmas(), + trackSmearingSigmas: TrackSmearingSigmas = TrackSmearingSigmas(), initialSigmas: Optional[list] = None, initialSigmaPtRel: Optional[float] = None, initialVarInflation: Optional[list] = None, @@ -313,15 +324,15 @@ def addSeeding( Json file for space point geometry selection. Not required for SeedingAlgorithm.TruthSmeared. seedingAlgorithm : SeedingAlgorithm, Default seeding algorithm to use: one of Default (no truth information used), TruthSmeared, TruthEstimated - particleSmearingSigmas : ParticleSmearingSigmas(d0, d0PtA, d0PtB, z0, z0PtA, z0PtB, t0, phi, theta, ptRel) - ParticleSmearing configuration. - Defaults specified in Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.hpp + trackSmearingSigmas : TrackSmearingSigmas(loc0, loc0PtA, loc0PtB, loc1, loc1PtA, loc1PtB, time, phi, theta, ptRel) + TrackSmearing configuration. + Defaults specified in Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TrackParameterSmearing.hpp initialSigmas : list Sets the initial covariance matrix diagonal. This is ignored in case of TruthSmearing. Defaults specified in Examples/Algorithms/TrackFinding/include/ActsExamples/TrackFinding/TrackParamsEstimationAlgorithm.hpp initialVarInflation : list List of 6 scale factors to inflate the initial covariance matrix - Defaults (all 1) specified in Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSmearing.hpp + Defaults (all 1) specified in Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/TrackParameterSmearing.hpp seedFinderConfigArg : SeedFinderConfigArg(maxSeedsPerSpM, cotThetaMax, sigmaScattering, radLengthPerSeed, minPt, impactMax, deltaPhiMax, interactionPointCut, deltaZMax, maxPtScattering, zBinEdges, zBinsCustomLooping, rRangeMiddleSP, useVariableMiddleSPRange, binSizeR, seedConfirmation, centralSeedConfirmationRange, forwardSeedConfirmationRange, deltaR, deltaRBottomSP, deltaRTopSP, deltaRMiddleSPRange, collisionRegion, r, z) SeedFinderConfig settings. deltaR, deltaRBottomSP, deltaRTopSP, deltaRMiddleSPRange, collisionRegion, r, z. Defaults specified in Core/include/Acts/Seeding/SeedFinderConfig.hpp @@ -366,7 +377,7 @@ def addSeeding( s=s, rnd=rnd, selectedParticles=selectedParticles, - particleSmearingSigmas=particleSmearingSigmas, + trackSmearingSigmas=trackSmearingSigmas, initialSigmas=initialSigmas, initialSigmaPtRel=initialSigmaPtRel, initialVarInflation=initialVarInflation, @@ -520,7 +531,7 @@ def addTruthSmearedSeeding( s: acts.examples.Sequencer, rnd: Optional[acts.examples.RandomNumbers], selectedParticles: str, - particleSmearingSigmas: ParticleSmearingSigmas, + trackSmearingSigmas: TrackSmearingSigmas, initialSigmas: Optional[List[float]], initialSigmaPtRel: Optional[float], initialVarInflation: Optional[List[float]], @@ -532,31 +543,39 @@ def addTruthSmearedSeeding( """ rnd = rnd or acts.examples.RandomNumbers(seed=42) - # Run particle smearing - ptclSmear = acts.examples.ParticleSmearing( + + trkParamExtractor = acts.examples.ParticleTrackParamExtractor( level=logLevel, inputParticles=selectedParticles, + outputTrackParameters="trueparameters", + ) + s.addAlgorithm(trkParamExtractor) + + # Smearing track parameters + trkSmear = acts.examples.TrackParameterSmearing( + level=logLevel, + inputTrackParameters=trkParamExtractor.config.outputTrackParameters, outputTrackParameters="estimatedparameters", randomNumbers=rnd, # gaussian sigmas to smear particle parameters **acts.examples.defaultKWArgs( - sigmaD0=particleSmearingSigmas.d0, - sigmaD0PtA=particleSmearingSigmas.d0PtA, - sigmaD0PtB=particleSmearingSigmas.d0PtB, - sigmaZ0=particleSmearingSigmas.z0, - sigmaZ0PtA=particleSmearingSigmas.z0PtA, - sigmaZ0PtB=particleSmearingSigmas.z0PtB, - sigmaT0=particleSmearingSigmas.t0, - sigmaPhi=particleSmearingSigmas.phi, - sigmaTheta=particleSmearingSigmas.theta, - sigmaPtRel=particleSmearingSigmas.ptRel, + sigmaLoc0=trackSmearingSigmas.loc0, + sigmaLoc0PtA=trackSmearingSigmas.loc0PtA, + sigmaLoc0PtB=trackSmearingSigmas.loc0PtB, + sigmaLoc1=trackSmearingSigmas.loc1, + sigmaLoc1PtA=trackSmearingSigmas.loc1PtA, + sigmaLoc1PtB=trackSmearingSigmas.loc1PtB, + sigmaTime=trackSmearingSigmas.time, + sigmaPhi=trackSmearingSigmas.phi, + sigmaTheta=trackSmearingSigmas.theta, + sigmaPtRel=trackSmearingSigmas.ptRel, initialSigmas=initialSigmas, initialSigmaPtRel=initialSigmaPtRel, initialVarInflation=initialVarInflation, particleHypothesis=particleHypothesis, ), ) - s.addAlgorithm(ptclSmear) + s.addAlgorithm(trkSmear) truthTrkFndAlg = acts.examples.TruthTrackFinder( level=logLevel, diff --git a/Examples/Python/src/Generators.cpp b/Examples/Python/src/Generators.cpp index 454227ddbf6..bc24b8e43f7 100644 --- a/Examples/Python/src/Generators.cpp +++ b/Examples/Python/src/Generators.cpp @@ -16,8 +16,6 @@ #include "ActsExamples/Generators/ParametricParticleGenerator.hpp" #include "ActsExamples/Generators/VertexGenerators.hpp" -#include -#include #include #include #include diff --git a/Examples/Python/src/TruthTracking.cpp b/Examples/Python/src/TruthTracking.cpp index 1502ce23d40..319ee24e2ee 100644 --- a/Examples/Python/src/TruthTracking.cpp +++ b/Examples/Python/src/TruthTracking.cpp @@ -10,9 +10,10 @@ #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/TruthTracking/HitSelector.hpp" #include "ActsExamples/TruthTracking/ParticleSelector.hpp" -#include "ActsExamples/TruthTracking/ParticleSmearing.hpp" +#include "ActsExamples/TruthTracking/ParticleTrackParamExtractor.hpp" #include "ActsExamples/TruthTracking/TrackModifier.hpp" #include "ActsExamples/TruthTracking/TrackParameterSelector.hpp" +#include "ActsExamples/TruthTracking/TrackParameterSmearing.hpp" #include "ActsExamples/TruthTracking/TrackTruthMatcher.hpp" #include "ActsExamples/TruthTracking/TruthSeedingAlgorithm.hpp" #include "ActsExamples/TruthTracking/TruthTrackFinder.hpp" @@ -41,12 +42,16 @@ void addTruthTracking(Context& ctx) { ActsExamples::TruthTrackFinder, mex, "TruthTrackFinder", inputParticles, inputMeasurementParticlesMap, outputProtoTracks); + ACTS_PYTHON_DECLARE_ALGORITHM(ActsExamples::ParticleTrackParamExtractor, mex, + "ParticleTrackParamExtractor", inputParticles, + outputTrackParameters); + ACTS_PYTHON_DECLARE_ALGORITHM( - ActsExamples::ParticleSmearing, mex, "ParticleSmearing", inputParticles, - outputTrackParameters, sigmaD0, sigmaD0PtA, sigmaD0PtB, sigmaZ0, - sigmaZ0PtA, sigmaZ0PtB, sigmaT0, sigmaPhi, sigmaTheta, sigmaPtRel, - initialSigmas, initialSigmaPtRel, initialVarInflation, particleHypothesis, - randomNumbers); + ActsExamples::TrackParameterSmearing, mex, "TrackParameterSmearing", + inputTrackParameters, outputTrackParameters, sigmaLoc0, sigmaLoc0PtA, + sigmaLoc0PtB, sigmaLoc1, sigmaLoc1PtA, sigmaLoc1PtB, sigmaTime, sigmaPhi, + sigmaTheta, sigmaPtRel, initialSigmas, initialSigmaPtRel, + initialVarInflation, particleHypothesis, randomNumbers); { using Alg = ActsExamples::ParticleSelector; diff --git a/Examples/Python/tests/conftest.py b/Examples/Python/tests/conftest.py index 71c0899fe3f..4bd8a430730 100644 --- a/Examples/Python/tests/conftest.py +++ b/Examples/Python/tests/conftest.py @@ -209,19 +209,12 @@ def _basic_prop_seq_factory(geo, s=None): rnd=rng, ) - # Run particle smearing - trackParametersGenerator = acts.examples.ParticleSmearing( - level=acts.logging.INFO, + trkParamExtractor = acts.examples.ParticleTrackParamExtractor( + level=acts.logging.WARNING, inputParticles="particles_input", - outputTrackParameters="start_parameters", - randomNumbers=rng, - sigmaD0=0.0, - sigmaZ0=0.0, - sigmaPhi=0.0, - sigmaTheta=0.0, - sigmaPtRel=0.0, + outputTrackParameters="params_particles_input", ) - s.addAlgorithm(trackParametersGenerator) + s.addAlgorithm(trkParamExtractor) nav = acts.Navigator(trackingGeometry=geo) stepper = acts.StraightLineStepper() @@ -232,11 +225,11 @@ def _basic_prop_seq_factory(geo, s=None): level=acts.logging.WARNING, propagatorImpl=prop, sterileLogger=False, - inputTrackParameters="start_parameters", + inputTrackParameters="params_particles_input", outputSummaryCollection="propagation_summary", ) - s.addAlgorithm(alg) + return s, alg return _basic_prop_seq_factory diff --git a/Examples/Python/tests/root_file_hashes.txt b/Examples/Python/tests/root_file_hashes.txt index ab5e04706bb..6eeaaebff44 100644 --- a/Examples/Python/tests/root_file_hashes.txt +++ b/Examples/Python/tests/root_file_hashes.txt @@ -16,7 +16,7 @@ test_itk_seeding__estimatedparams.root: fc042037f12a434f2236df7d225b8ca24209b691 test_itk_seeding__performance_seeding.root: 78ebda54cd0f026ba4b7f316724ffd946de56a932735914baf1b7bba9505c29d test_itk_seeding__particles.root: 907ff693262c0db14b12c74b16586cb20d79caf5f03f93b178943e41ed35a1b6 test_itk_seeding__particles_simulation.root: ef0246069aa697019f28a8b270a68de95312cae5f2f2c74848566c3ce4f70363 -test_propagation__propagation_summary.root: 400043dfeed9eda16512ec5fd4a1389f94b98565083f06f439c7b7b59e46c544 +test_propagation__propagation_summary.root: de0c105ab0de0096241855fe3db46d7c5d054d897625ede4df276472a7e43c57 test_material_recording__geant4_material_tracks.root: c022b9362249b29f57a07926b20644e3ab4ab8ebcf03f773fbf46c446fc1a0a1 test_truth_tracking_gsf[generic]__trackstates_gsf.root: 4df2c69d5dd7d5446a547651e4e962daf17924f5c8617165a93a3223c8ba18fd test_truth_tracking_gsf[generic]__tracksummary_gsf.root: 8c01d139cb865afa1959c62dbca76f3a1fb8b684c57ea4c2968baa6ffedadb6f @@ -24,9 +24,9 @@ test_truth_tracking_gsf[odd]__trackstates_gsf.root: c7397e53ea093f2432943ae263fc test_truth_tracking_gsf[odd]__tracksummary_gsf.root: 4562341f12a61ea0d5e25872b6bf466b79a73781dc95fc18ef9c6515f0a47916 test_particle_gun__particles.root: 669d0304eb8bcf244aa627809a117944e5e3b994fdfcfb8710f2b9a8f9a62d3b test_material_mapping__material-map_tracks.root: 938b1a855369e9304401cb10d2751df3fd7acf32a2573f2057eb1691cd94edf3 -test_material_mapping__propagation-material.root: 5eacd0cb804d381171c8fb65d7b2d36e1d57db9f4cb2b58c0f24703479218cbf +test_material_mapping__propagation-material.root: e2b4eade0d8124c03c89e01bf6ff5029dd12e3c9efc0a19c22a12c5cd2800e77 test_volume_material_mapping__material-map-volume_tracks.root: 98e212d32ca054fa3d01af4167c1f49755a139d43b82c57908197f5985e0a4ff -test_volume_material_mapping__propagation-volume-material.root: 3e9d38cc541a1956b2f33be320d457559bb230311130a8531bf09371c272f913 +test_volume_material_mapping__propagation-volume-material.root: 42bb2fd9c50d44210c914e487903bbdef65a0491f0a85a7159c0e078ac983a80 test_digitization_example[smeared]__measurements.root: 2b583b886b76f94786c6c2832aa84d176059cbbc35882fb34b4fd1f22dd4c006 test_digitization_example[geometric]__measurements.root: 85efa861d14207fd7d1798dab093edcd0a2685bc189b4fc9a96b07d1001013a0 test_digitization_example_input[smeared]__particles.root: 669d0304eb8bcf244aa627809a117944e5e3b994fdfcfb8710f2b9a8f9a62d3b @@ -56,9 +56,9 @@ test_vertex_fitting_reading[AMVF-False-100]__performance_vertexing.root: 009e4b1 test_vertex_fitting_reading[AMVF-True-100]__performance_vertexing.root: 2d0dc1e02bfd1f7eaae26ef8ac657ce0291f70c7e4efddd35d171d31988a631e test_bfield_writing__solenoid.root: 7be51f0ed9cb99f59ae0271ba79cdb84635e6ee3d2109ea8a4b521875029c21d test_bfield_writing__solenoid2.root: 2db149336c9cd749dc50025076b49f9bc0586d53792b87a0fdd7f21a649a01a5 -test_root_prop_step_writer[configPosConstructor]__prop_steps.root: a783d525eebb4737e6e6bcf20d63d6f35520f4bcf23301ae8c4657309cbccdda -test_root_prop_step_writer[configKwConstructor]__prop_steps.root: a783d525eebb4737e6e6bcf20d63d6f35520f4bcf23301ae8c4657309cbccdda -test_root_prop_step_writer[kwargsConstructor]__prop_steps.root: a783d525eebb4737e6e6bcf20d63d6f35520f4bcf23301ae8c4657309cbccdda +test_root_prop_step_writer[configPosConstructor]__prop_steps.root: 200ece7cde60eb0dd8835cf4830835e9058d897ba5759099d96914b06a1df092 +test_root_prop_step_writer[configKwConstructor]__prop_steps.root: 200ece7cde60eb0dd8835cf4830835e9058d897ba5759099d96914b06a1df092 +test_root_prop_step_writer[kwargsConstructor]__prop_steps.root: 200ece7cde60eb0dd8835cf4830835e9058d897ba5759099d96914b06a1df092 test_root_particle_writer[configPosConstructor]__particles.root: e5d723e138b4e121c6e74a6dba072072f622995e117a40b8e63755ac784baad6 test_root_particle_writer[configKwConstructor]__particles.root: e5d723e138b4e121c6e74a6dba072072f622995e117a40b8e63755ac784baad6 test_root_particle_writer[kwargsConstructor]__particles.root: e5d723e138b4e121c6e74a6dba072072f622995e117a40b8e63755ac784baad6 diff --git a/Examples/Python/tests/test_algorithms.py b/Examples/Python/tests/test_algorithms.py index 4cca7199291..6311dc6460a 100644 --- a/Examples/Python/tests/test_algorithms.py +++ b/Examples/Python/tests/test_algorithms.py @@ -14,7 +14,7 @@ TruthTrackFinder, ParticleSelector, TruthVertexFinder, - ParticleSmearing, + TrackParameterSmearing, TrackSelectorAlgorithm, TrackFittingAlgorithm, SurfaceSortingAlgorithm, @@ -44,7 +44,7 @@ TruthTrackFinder, ParticleSelector, TruthVertexFinder, - ParticleSmearing, + TrackParameterSmearing, TrackSelectorAlgorithm, TrackFittingAlgorithm, SurfaceSortingAlgorithm, diff --git a/Examples/Python/tests/test_propagation.py b/Examples/Python/tests/test_propagation.py index 6583098f427..adfc55ba8c2 100644 --- a/Examples/Python/tests/test_propagation.py +++ b/Examples/Python/tests/test_propagation.py @@ -56,34 +56,27 @@ def test_steppers(conf_const, trk_geo): rnd=rnd, ) - # Run particle smearing - trackParametersGenerator = acts.examples.ParticleSmearing( - level=acts.logging.INFO, - inputParticles="particles_input", - outputTrackParameters="start_parameters", - randomNumbers=rnd, - sigmaD0=0.0, - sigmaZ0=0.0, - sigmaPhi=0.0, - sigmaTheta=0.0, - sigmaPtRel=0.0, - ) - seq.addAlgorithm(trackParametersGenerator) - prop = acts.examples.ConcretePropagator( acts.Propagator(stepper=s, navigator=nav) ) + trkParamExtractor = acts.examples.ParticleTrackParamExtractor( + level=acts.logging.WARNING, + inputParticles="particles_input", + outputTrackParameters="params_particles_input", + ) + seq.addAlgorithm(trkParamExtractor) + alg = conf_const( acts.examples.PropagationAlgorithm, level=acts.logging.WARNING, propagatorImpl=prop, - inputTrackParameters="start_parameters", + inputTrackParameters="params_particles_input", outputSummaryCollection="propagation_summary", sterileLogger=False, ) - seq.addAlgorithm(alg) + chkAlg = AssertCollectionExistsAlg( "propagation_summary", "chk_alg", level=acts.logging.WARNING ) diff --git a/Examples/Scripts/Optimization/ckf.py b/Examples/Scripts/Optimization/ckf.py index ba18291735c..e0cd5fd9870 100755 --- a/Examples/Scripts/Optimization/ckf.py +++ b/Examples/Scripts/Optimization/ckf.py @@ -123,7 +123,7 @@ def runCKFTracks( from acts.examples.reconstruction import ( addSeeding, - ParticleSmearingSigmas, + TrackSmearingSigmas, SeedFinderConfigArg, SeedFinderOptionsArg, SeedingAlgorithm, @@ -188,15 +188,15 @@ def runCKFTracks( s, trackingGeometry, field, - ParticleSmearingSigmas( # only used by SeedingAlgorithm.TruthSmeared + TrackSmearingSigmas( # only used by SeedingAlgorithm.TruthSmeared # zero eveything so the CKF has a chance to find the measurements - d0=0, - d0PtA=0, - d0PtB=0, - z0=0, - z0PtA=0, - z0PtB=0, - t0=0, + loc0=0, + loc0PtA=0, + loc0PtB=0, + loc1=0, + loc1PtA=0, + loc1PtB=0, + time=0, phi=0, theta=0, ptRel=0, diff --git a/Examples/Scripts/Python/ckf_tracks.py b/Examples/Scripts/Python/ckf_tracks.py index 97f56d17ff0..75ec8a7c316 100755 --- a/Examples/Scripts/Python/ckf_tracks.py +++ b/Examples/Scripts/Python/ckf_tracks.py @@ -34,7 +34,7 @@ def runCKFTracks( from acts.examples.reconstruction import ( addSeeding, - ParticleSmearingSigmas, + TrackSmearingSigmas, SeedFinderConfigArg, SeedFinderOptionsArg, SeedingAlgorithm, @@ -99,15 +99,15 @@ def runCKFTracks( s, trackingGeometry, field, - ParticleSmearingSigmas( # only used by SeedingAlgorithm.TruthSmeared + TrackSmearingSigmas( # only used by SeedingAlgorithm.TruthSmeared # zero eveything so the CKF has a chance to find the measurements - d0=0, - d0PtA=0, - d0PtB=0, - z0=0, - z0PtA=0, - z0PtB=0, - t0=0, + loc0=0, + loc0PtA=0, + loc0PtB=0, + loc1=0, + loc1PtA=0, + loc1PtB=0, + time=0, phi=0, theta=0, ptRel=0, diff --git a/Examples/Scripts/Python/full_chain_test.py b/Examples/Scripts/Python/full_chain_test.py index f0010bd498e..595dbd43a4e 100755 --- a/Examples/Scripts/Python/full_chain_test.py +++ b/Examples/Scripts/Python/full_chain_test.py @@ -521,7 +521,7 @@ def full_chain(args): from acts.examples.reconstruction import ( addSeeding, - ParticleSmearingSigmas, + TrackSmearingSigmas, addCKFTracks, CkfConfig, SeedingAlgorithm, @@ -547,7 +547,7 @@ def full_chain(args): seedingAlgorithm=args.seeding_algorithm, **( dict( - particleSmearingSigmas=ParticleSmearingSigmas(ptRel=0.01), + trackSmearingSigmas=TrackSmearingSigmas(ptRel=0.01), rnd=rnd, ) if args.seeding_algorithm == SeedingAlgorithm.TruthSmeared diff --git a/Examples/Scripts/Python/material_validation.py b/Examples/Scripts/Python/material_validation.py index ebc26041cd2..94c0f21b94a 100755 --- a/Examples/Scripts/Python/material_validation.py +++ b/Examples/Scripts/Python/material_validation.py @@ -40,30 +40,22 @@ def runMaterialValidation( rnd=rnd, ) - # Run particle smearing - trackParametersGenerator = acts.examples.ParticleSmearing( + trkParamExtractor = acts.examples.ParticleTrackParamExtractor( level=acts.logging.INFO, inputParticles="particles_input", - outputTrackParameters="start_parameters", - randomNumbers=rnd, - sigmaD0=0.0, - sigmaZ0=0.0, - sigmaPhi=0.0, - sigmaTheta=0.0, - sigmaPtRel=0.0, + outputTrackParameters="params_particles_input", ) - s.addAlgorithm(trackParametersGenerator) + s.addAlgorithm(trkParamExtractor) alg = acts.examples.PropagationAlgorithm( propagatorImpl=prop, level=acts.logging.INFO, sterileLogger=True, recordMaterialInteractions=True, - inputTrackParameters="start_parameters", + inputTrackParameters="params_particles_input", outputSummaryCollection="propagation_summary", outputMaterialCollection="material_tracks", ) - s.addAlgorithm(alg) s.addWriter( diff --git a/Examples/Scripts/Python/material_validation_itk.py b/Examples/Scripts/Python/material_validation_itk.py index 759f75a5ea2..4d5f095ef10 100755 --- a/Examples/Scripts/Python/material_validation_itk.py +++ b/Examples/Scripts/Python/material_validation_itk.py @@ -10,6 +10,8 @@ def runMaterialValidation( + nevents, + ntracks, trackingGeometry, decorators, field, @@ -18,7 +20,8 @@ def runMaterialValidation( dumpPropagationSteps=False, s=None, ): - s = s or Sequencer(events=1000, numThreads=-1) + # Create a sequencer + s = s or Sequencer(events=nevents, numThreads=-1) rnd = acts.examples.RandomNumbers(seed=42) @@ -44,31 +47,22 @@ def runMaterialValidation( rnd=rnd, ) - # Run particle smearing - trackParametersGenerator = acts.examples.ParticleSmearing( + trkParamExtractor = acts.examples.ParticleTrackParamExtractor( level=acts.logging.INFO, inputParticles="particles_input", - outputTrackParameters="start_parameters", - randomNumbers=rnd, - sigmaD0=0.0, - sigmaZ0=0.0, - sigmaPhi=0.0, - sigmaTheta=0.0, - sigmaPRel=0.0, - addCovariances=False, + outputTrackParameters="params_particles_input", ) - s.addAlgorithm(trackParametersGenerator) + s.addAlgorithm(trkParamExtractor) alg = acts.examples.PropagationAlgorithm( propagatorImpl=prop, level=acts.logging.INFO, sterileLogger=False, recordMaterialInteractions=True, - inputTrackParameters="start_parameters", + inputTrackParameters="params_particles_input", outputPropagationSteps="propagation_steps", outputMaterialTracks="material-tracks", ) - s.addAlgorithm(alg) s.addWriter( diff --git a/Examples/Scripts/Python/propagation.py b/Examples/Scripts/Python/propagation.py index ea54919a89f..59be3385ca0 100755 --- a/Examples/Scripts/Python/propagation.py +++ b/Examples/Scripts/Python/propagation.py @@ -31,19 +31,12 @@ def runPropagation(trackingGeometry, field, outputDir, s=None, decorators=[]): rnd=rnd, ) - # Run particle smearing - trackParametersGenerator = acts.examples.ParticleSmearing( - level=acts.logging.INFO, + trkParamExtractor = acts.examples.ParticleTrackParamExtractor( + level=acts.logging.WARNING, inputParticles="particles_input", - outputTrackParameters="start_parameters", - randomNumbers=rnd, - sigmaD0=0.0, - sigmaZ0=0.0, - sigmaPhi=0.0, - sigmaTheta=0.0, - sigmaPtRel=0.0, + outputTrackParameters="params_particles_input", ) - s.addAlgorithm(trackParametersGenerator) + s.addAlgorithm(trkParamExtractor) nav = acts.Navigator(trackingGeometry=trackingGeometry) @@ -57,7 +50,7 @@ def runPropagation(trackingGeometry, field, outputDir, s=None, decorators=[]): propagatorImpl=propagator, level=acts.logging.INFO, sterileLogger=True, - inputTrackParameters="start_parameters", + inputTrackParameters="params_particles_input", outputSummaryCollection="propagation_summary", ) s.addAlgorithm(propagationAlgorithm) diff --git a/Examples/Scripts/Python/vertex_fitting.py b/Examples/Scripts/Python/vertex_fitting.py index e8797a5ed12..c6088f618a6 100755 --- a/Examples/Scripts/Python/vertex_fitting.py +++ b/Examples/Scripts/Python/vertex_fitting.py @@ -6,7 +6,7 @@ from acts.examples import ( Sequencer, ParticleSelector, - ParticleSmearing, + TrackParameterSmearing, TrackParameterSelector, ) from acts.examples.simulation import addPythia8 @@ -65,9 +65,16 @@ def runVertexFitting( if inputTrackSummary is None or inputParticlePath is None: logger.info("Using smeared particles") - ptclSmearing = ParticleSmearing( - level=acts.logging.INFO, + trkParamExtractor = acts.examples.ParticleTrackParamExtractor( + level=acts.logging.WARNING, inputParticles=selectedParticles, + outputTrackParameters="params_particles_input", + ) + s.addAlgorithm(trkParamExtractor) + + ptclSmearing = TrackParameterSmearing( + level=acts.logging.INFO, + inputTrackParameters="params_particles_input", outputTrackParameters=trackParameters, randomNumbers=rnd, ) From eb6a5f11df765261ac9f1b75e0eeb8f3e855eb59 Mon Sep 17 00:00:00 2001 From: Paul Gessinger Date: Fri, 29 Nov 2024 18:10:50 +0100 Subject: [PATCH 10/12] feat: compatibility for EDM4hep < `0.99` & >= `0.99` (#3921) This updates our code so it compiles with both EDM4hep versions below `0.99` and above/equal to `0.99`. Breaking changes are: - `TrackerHit` becomes `TrackerHit3D`. - `SimTrackerHit::getMCParticle` becomes `SimTrackerHit::getParticle`, with the original name being deprecated. I'm aliasing the new name `TrackerHit3D` and `TrackerHit3DCollection` to the old types, so that when we drop support for < `0.99` versions, they're already correct. ## Summary by CodeRabbit - **New Features** - Enhanced compatibility with different versions of the EDM4hep library for particle handling. - Introduced utility functions for retrieving and setting particle information in `SimTrackerHit` objects. - Added type aliases to streamline the handling of tracker hit collections. - **Bug Fixes** - Improved error handling in the `EDM4hepReader` for missing particles. - **Refactor** - Updated function signatures and internal logic to utilize new utility functions for better maintainability. - Streamlined the `EDM4hepMeasurementWriter` and `EDM4hepMeasurementReader` to accommodate new data structures. - Adjusted header inclusions and conditional compilation for better flexibility. - **Documentation** - Added comments to indicate changes in parameter handling for clarity. --- .../Io/EDM4hep/EDM4hepMeasurementWriter.hpp | 3 - .../ActsExamples/Io/EDM4hep/EDM4hepUtil.hpp | 21 +++--- .../EDM4hep/src/EDM4hepMeasurementReader.cpp | 5 +- .../EDM4hep/src/EDM4hepMeasurementWriter.cpp | 5 +- Examples/Io/EDM4hep/src/EDM4hepReader.cpp | 6 +- Examples/Io/EDM4hep/src/EDM4hepUtil.cpp | 73 ++++++------------- .../Acts/Plugins/EDM4hep/EDM4hepUtil.hpp | 12 ++- .../EDM4hep/TrackerHitCompatibility.hpp | 22 ++++++ Plugins/EDM4hep/src/EDM4hepUtil.cpp | 34 ++++++++- 9 files changed, 105 insertions(+), 76 deletions(-) create mode 100644 Plugins/EDM4hep/include/Acts/Plugins/EDM4hep/TrackerHitCompatibility.hpp diff --git a/Examples/Io/EDM4hep/include/ActsExamples/Io/EDM4hep/EDM4hepMeasurementWriter.hpp b/Examples/Io/EDM4hep/include/ActsExamples/Io/EDM4hep/EDM4hepMeasurementWriter.hpp index d559ee9a5e4..04cf8805df4 100644 --- a/Examples/Io/EDM4hep/include/ActsExamples/Io/EDM4hep/EDM4hepMeasurementWriter.hpp +++ b/Examples/Io/EDM4hep/include/ActsExamples/Io/EDM4hep/EDM4hepMeasurementWriter.hpp @@ -16,9 +16,6 @@ #include -#include -#include - namespace ActsExamples { /// Write out a measurement cluster collection to EDM4hep. diff --git a/Examples/Io/EDM4hep/include/ActsExamples/Io/EDM4hep/EDM4hepUtil.hpp b/Examples/Io/EDM4hep/include/ActsExamples/Io/EDM4hep/EDM4hepUtil.hpp index bdce08bc876..4973763a087 100644 --- a/Examples/Io/EDM4hep/include/ActsExamples/Io/EDM4hep/EDM4hepUtil.hpp +++ b/Examples/Io/EDM4hep/include/ActsExamples/Io/EDM4hep/EDM4hepUtil.hpp @@ -8,6 +8,7 @@ #pragma once #include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Plugins/EDM4hep/TrackerHitCompatibility.hpp" #include "ActsExamples/EventData/Cluster.hpp" #include "ActsExamples/EventData/Measurement.hpp" #include "ActsExamples/EventData/SimParticle.hpp" @@ -16,15 +17,13 @@ #include -#include "edm4hep/MCParticle.h" -#include "edm4hep/MutableMCParticle.h" -#include "edm4hep/MutableSimTrackerHit.h" -#include "edm4hep/MutableTrack.h" -#include "edm4hep/MutableTrackerHitPlane.h" -#include "edm4hep/SimTrackerHit.h" -#include "edm4hep/TrackerHit.h" -#include "edm4hep/TrackerHitCollection.h" -#include "edm4hep/TrackerHitPlane.h" +#include +#include +#include +#include +#include +#include +#include namespace ActsExamples::EDM4hepUtil { @@ -91,7 +90,7 @@ void writeSimHit(const ActsFatras::Hit& from, edm4hep::MutableSimTrackerHit to, /// - local 2D coordinates and time are read from position VariableBoundMeasurementProxy readMeasurement( MeasurementContainer& container, const edm4hep::TrackerHitPlane& from, - const edm4hep::TrackerHitCollection* fromClusters, Cluster* toCluster, + const edm4hep::TrackerHit3DCollection* fromClusters, Cluster* toCluster, const MapGeometryIdFrom& geometryMapper); /// Writes a measurement cluster to EDM4hep. @@ -107,7 +106,7 @@ VariableBoundMeasurementProxy readMeasurement( void writeMeasurement(const ConstVariableBoundMeasurementProxy& from, edm4hep::MutableTrackerHitPlane to, const Cluster* fromCluster, - edm4hep::TrackerHitCollection& toClusters, + edm4hep::TrackerHit3DCollection& toClusters, const MapGeometryIdTo& geometryMapper); /// Writes a trajectory to EDM4hep. diff --git a/Examples/Io/EDM4hep/src/EDM4hepMeasurementReader.cpp b/Examples/Io/EDM4hep/src/EDM4hepMeasurementReader.cpp index 237ff19e3b6..5299da121ca 100644 --- a/Examples/Io/EDM4hep/src/EDM4hepMeasurementReader.cpp +++ b/Examples/Io/EDM4hep/src/EDM4hepMeasurementReader.cpp @@ -9,6 +9,7 @@ #include "ActsExamples/Io/EDM4hep/EDM4hepMeasurementReader.hpp" #include "Acts/Definitions/Units.hpp" +#include "Acts/Plugins/EDM4hep/TrackerHitCompatibility.hpp" #include "Acts/Plugins/Podio/PodioUtil.hpp" #include "ActsExamples/EventData/Cluster.hpp" #include "ActsExamples/EventData/Measurement.hpp" @@ -18,8 +19,6 @@ #include #include -#include -#include #include #include @@ -60,7 +59,7 @@ ProcessCode EDM4hepMeasurementReader::read(const AlgorithmContext& ctx) { const auto& trackerHitPlaneCollection = frame.get("ActsTrackerHitsPlane"); const auto& trackerHitRawCollection = - frame.get("ActsTrackerHitsRaw"); + frame.get("ActsTrackerHitsRaw"); for (const auto& trackerHitPlane : trackerHitPlaneCollection) { Cluster cluster; diff --git a/Examples/Io/EDM4hep/src/EDM4hepMeasurementWriter.cpp b/Examples/Io/EDM4hep/src/EDM4hepMeasurementWriter.cpp index 0f9e9422d28..23e291cc2dd 100644 --- a/Examples/Io/EDM4hep/src/EDM4hepMeasurementWriter.cpp +++ b/Examples/Io/EDM4hep/src/EDM4hepMeasurementWriter.cpp @@ -9,6 +9,7 @@ #include "ActsExamples/Io/EDM4hep/EDM4hepMeasurementWriter.hpp" #include "Acts/Definitions/Units.hpp" +#include "Acts/Plugins/EDM4hep/TrackerHitCompatibility.hpp" #include "ActsExamples/EventData/Cluster.hpp" #include "ActsExamples/EventData/Measurement.hpp" #include "ActsExamples/Framework/WhiteBoard.hpp" @@ -16,6 +17,8 @@ #include +#include +#include #include namespace ActsExamples { @@ -44,7 +47,7 @@ ActsExamples::ProcessCode EDM4hepMeasurementWriter::writeT( podio::Frame frame; edm4hep::TrackerHitPlaneCollection hitsPlane; - edm4hep::TrackerHitCollection hits; + edm4hep::TrackerHit3DCollection hits; if (!m_cfg.inputClusters.empty()) { ACTS_VERBOSE("Fetch clusters for writing: " << m_cfg.inputClusters); diff --git a/Examples/Io/EDM4hep/src/EDM4hepReader.cpp b/Examples/Io/EDM4hep/src/EDM4hepReader.cpp index 4561bc61db0..0b82a20181b 100644 --- a/Examples/Io/EDM4hep/src/EDM4hepReader.cpp +++ b/Examples/Io/EDM4hep/src/EDM4hepReader.cpp @@ -10,6 +10,7 @@ #include "Acts/Definitions/Units.hpp" #include "Acts/Plugins/DD4hep/DD4hepDetectorElement.hpp" +#include "Acts/Plugins/EDM4hep/EDM4hepUtil.hpp" #include "ActsExamples/DD4hepDetector/DD4hepDetector.hpp" #include "ActsExamples/EventData/SimHit.hpp" #include "ActsExamples/EventData/SimParticle.hpp" @@ -305,8 +306,9 @@ ProcessCode EDM4hepReader::read(const AlgorithmContext& ctx) { auto simHit = EDM4hepUtil::readSimHit( hit, [&](const auto& inParticle) { - ACTS_VERBOSE("SimHit has source particle: " - << hit.getMCParticle().getObjectID().index); + ACTS_VERBOSE( + "SimHit has source particle: " + << Acts::EDM4hepUtil::getParticle(hit).getObjectID().index); auto it = edm4hepParticleMap.find(inParticle.getObjectID().index); if (it == edm4hepParticleMap.end()) { ACTS_ERROR( diff --git a/Examples/Io/EDM4hep/src/EDM4hepUtil.cpp b/Examples/Io/EDM4hep/src/EDM4hepUtil.cpp index 38e26038779..adb433891d9 100644 --- a/Examples/Io/EDM4hep/src/EDM4hepUtil.cpp +++ b/Examples/Io/EDM4hep/src/EDM4hepUtil.cpp @@ -70,9 +70,10 @@ void EDM4hepUtil::writeParticle(const SimParticle& from, ActsFatras::Hit EDM4hepUtil::readSimHit( const edm4hep::SimTrackerHit& from, const MapParticleIdFrom& particleMapper, const MapGeometryIdFrom& geometryMapper) { - ActsFatras::Barcode particleId = particleMapper(from.getMCParticle()); + auto particle = Acts::EDM4hepUtil::getParticle(from); + ActsFatras::Barcode particleId = particleMapper(particle); - const auto mass = from.getMCParticle().getMass() * 1_GeV; + const auto mass = particle.getMass() * 1_GeV; const Acts::Vector3 momentum{ from.getMomentum().x * 1_GeV, from.getMomentum().y * 1_GeV, @@ -116,7 +117,7 @@ void EDM4hepUtil::writeSimHit(const ActsFatras::Hit& from, const auto delta4 = from.momentum4After() - momentum4Before; if (particleMapper) { - to.setMCParticle(particleMapper(from.particleId())); + Acts::EDM4hepUtil::setParticle(to, particleMapper(from.particleId())); } if (geometryMapper) { @@ -146,8 +147,8 @@ void EDM4hepUtil::writeSimHit(const ActsFatras::Hit& from, VariableBoundMeasurementProxy EDM4hepUtil::readMeasurement( MeasurementContainer& container, const edm4hep::TrackerHitPlane& from, - const edm4hep::TrackerHitCollection* fromClusters, Cluster* toCluster, - const MapGeometryIdFrom& geometryMapper) { + const edm4hep::TrackerHit3DCollection* /*fromClusters*/, + Cluster* /*toCluster*/, const MapGeometryIdFrom& geometryMapper) { // no need for digitization as we only want to identify the sensor Acts::GeometryIdentifier geometryId = geometryMapper(from.getCellID()); @@ -171,32 +172,15 @@ VariableBoundMeasurementProxy EDM4hepUtil::readMeasurement( auto to = createMeasurement(container, geometryId, dParameters); - if (fromClusters != nullptr) { - for (const auto objectId : from.getRawHits()) { - const auto& c = fromClusters->at(objectId.index); - - // TODO get EDM4hep fixed - // misusing some fields to store ACTS specific information - // don't ask ... - ActsFatras::Segmentizer::Bin2D bin{ - static_cast(c.getType()), - static_cast(c.getQuality())}; - ActsFatras::Segmentizer::Segment2D path2D{ - {Acts::Vector2::Zero(), Acts::Vector2::Zero()}}; - double activation = c.getTime(); - ActsFatras::Segmentizer::ChannelSegment cell{bin, path2D, activation}; - - toCluster->channels.push_back(cell); - } - } + // @TODO: Figure out if cell information is accessible return to; } void EDM4hepUtil::writeMeasurement( const ConstVariableBoundMeasurementProxy& from, - edm4hep::MutableTrackerHitPlane to, const Cluster* fromCluster, - edm4hep::TrackerHitCollection& toClusters, + edm4hep::MutableTrackerHitPlane to, const Cluster* /*fromCluster*/, + edm4hep::TrackerHit3DCollection& /*toClusters*/, const MapGeometryIdTo& geometryMapper) { Acts::GeometryIdentifier geoId = from.geometryId(); @@ -224,21 +208,7 @@ void EDM4hepUtil::writeMeasurement( 0, }); - if (fromCluster != nullptr) { - for (const auto& c : fromCluster->channels) { - auto toChannel = toClusters.create(); - to.addToRawHits(toChannel.getObjectID()); - - // TODO digitization channel - - // TODO get EDM4hep fixed - // misusing some fields to store ACTS specific information - // don't ask ... - toChannel.setType(c.bin[0]); - toChannel.setQuality(c.bin[1]); - toChannel.setTime(c.activation); - } - } + // @TODO: Check if we can write cell info } void EDM4hepUtil::writeTrajectory( @@ -296,17 +266,18 @@ void EDM4hepUtil::writeTrajectory( trackState.referencePoint.z = center.z(); if (converted.covariance) { - const auto& c = converted.covariance.value(); - - trackState.covMatrix = { - static_cast(c(0, 0)), static_cast(c(1, 0)), - static_cast(c(1, 1)), static_cast(c(2, 0)), - static_cast(c(2, 1)), static_cast(c(2, 2)), - static_cast(c(3, 0)), static_cast(c(3, 1)), - static_cast(c(3, 2)), static_cast(c(3, 3)), - static_cast(c(4, 0)), static_cast(c(4, 1)), - static_cast(c(4, 2)), static_cast(c(4, 3)), - static_cast(c(4, 4))}; + auto c = [&](std::size_t row, std::size_t col) { + return static_cast(converted.covariance.value()(row, col)); + }; + + // clang-format off + trackState.covMatrix = {c(0, 0), + c(1, 0), c(1, 1), + c(2, 0), c(2, 1), c(2, 2), + c(3, 0), c(3, 1), c(3, 2), c(3, 3), + c(4, 0), c(4, 1), c(4, 2), c(4, 3), c(4, 4), + c(5, 0), c(5, 1), c(5, 2), c(5, 3), c(5, 4), c(5, 5)}; + // clang-format on } to.addToTrackStates(trackState); diff --git a/Plugins/EDM4hep/include/Acts/Plugins/EDM4hep/EDM4hepUtil.hpp b/Plugins/EDM4hep/include/Acts/Plugins/EDM4hep/EDM4hepUtil.hpp index c5fda03bc82..e4836862769 100644 --- a/Plugins/EDM4hep/include/Acts/Plugins/EDM4hep/EDM4hepUtil.hpp +++ b/Plugins/EDM4hep/include/Acts/Plugins/EDM4hep/EDM4hepUtil.hpp @@ -26,11 +26,13 @@ #include #include +#include +#include +#include +#include #include #include -#include "edm4hep/MutableTrack.h" - namespace Acts::EDM4hepUtil { static constexpr std::int32_t EDM4HEP_ACTS_POSITION_TYPE = 42; @@ -61,6 +63,12 @@ BoundTrackParameters convertTrackParametersFromEdm4hep( } // namespace detail +// Compatibility with EDM4hep < 0.99 and >= 0.99 +edm4hep::MCParticle getParticle(const edm4hep::SimTrackerHit& hit); + +void setParticle(edm4hep::MutableSimTrackerHit& hit, + const edm4hep::MCParticle& particle); + template void writeTrack(const Acts::GeometryContext& gctx, track_proxy_t track, edm4hep::MutableTrack to, double Bz, diff --git a/Plugins/EDM4hep/include/Acts/Plugins/EDM4hep/TrackerHitCompatibility.hpp b/Plugins/EDM4hep/include/Acts/Plugins/EDM4hep/TrackerHitCompatibility.hpp new file mode 100644 index 00000000000..11115e7cbe5 --- /dev/null +++ b/Plugins/EDM4hep/include/Acts/Plugins/EDM4hep/TrackerHitCompatibility.hpp @@ -0,0 +1,22 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +// Compatibility with EDM4hep < 0.99 and >= 0.99 +#if __has_include() +#include "edm4hep/TrackerHit3D.h" +#include "edm4hep/TrackerHit3DCollection.h" +#else +#include "edm4hep/TrackerHit.h" +#include "edm4hep/TrackerHitCollection.h" +namespace edm4hep { +using TrackerHit3DCollection = edm4hep::TrackerHitCollection; +using TrackerHit3D = edm4hep::TrackerHit; +} // namespace edm4hep +#endif diff --git a/Plugins/EDM4hep/src/EDM4hepUtil.cpp b/Plugins/EDM4hep/src/EDM4hepUtil.cpp index 515063da679..60d466d0427 100644 --- a/Plugins/EDM4hep/src/EDM4hepUtil.cpp +++ b/Plugins/EDM4hep/src/EDM4hepUtil.cpp @@ -18,9 +18,14 @@ #include -#include "edm4hep/TrackState.h" +#include +#include +#include +#include +#include -namespace Acts::EDM4hepUtil::detail { +namespace Acts::EDM4hepUtil { +namespace detail { ActsSquareMatrix<6> jacobianToEdm4hep(double theta, double qOverP, double Bz) { // Calculate jacobian from our internal parametrization (d0, z0, phi, theta, @@ -185,4 +190,27 @@ BoundTrackParameters convertTrackParametersFromEdm4hep( return {params.surface, targetPars, cov, params.particleHypothesis}; } -} // namespace Acts::EDM4hepUtil::detail +} // namespace detail + +#if EDM4HEP_VERSION_MAJOR >= 1 || \ + (EDM4HEP_VERSION_MAJOR == 0 && EDM4HEP_VERSION_MINOR == 99) +edm4hep::MCParticle getParticle(const edm4hep::SimTrackerHit& hit) { + return hit.getParticle(); +} + +void setParticle(edm4hep::MutableSimTrackerHit& hit, + const edm4hep::MCParticle& particle) { + hit.setParticle(particle); +} +#else +edm4hep::MCParticle getParticle(const edm4hep::SimTrackerHit& hit) { + return hit.getMCParticle(); +} + +void setParticle(edm4hep::MutableSimTrackerHit& hit, + const edm4hep::MCParticle& particle) { + hit.setMCParticle(particle); +} +#endif + +} // namespace Acts::EDM4hepUtil From 6a836db2a62deec29f0f1913f557a59088bb2978 Mon Sep 17 00:00:00 2001 From: Paul Gessinger Date: Fri, 29 Nov 2024 21:52:08 +0100 Subject: [PATCH 11/12] ci: Add LCG 106a job (#3918) This adds jobs for LCG 106a to the GitLab CI. I'm bumping ODD to the [`v4.0.3`](https://gitlab.cern.ch/acts/OpenDataDetector/-/tags/v4.0.3) where I cherry picked a tiny code fix that was breaking the build here. Blocked by: - #3921 ## Summary by CodeRabbit - **New Features** - Introduced a new CI/CD job `lcg_106a` for enhanced build configurations. - **Improvements** - Simplified the `lcg_105` job by directly setting `LCG_PLATFORM` for the `alma9` OS. - **Updates** - Updated the commit reference for the `OpenDataDetector` subproject to the latest version. --- .gitlab-ci.yml | 20 +++++++++++++++----- thirdparty/OpenDataDetector | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b0a213e607d..c897c947010 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -382,11 +382,7 @@ linux_ubuntu_2204_clang: # Figure out LCG platform name based on version number and OS - > if [ "$OS" = "alma9" ]; then - if [ "$LCG_VERSION" -ge "104" ]; then - export LCG_PLATFORM="el9" - else - export LCG_PLATFORM="centos9" - fi + export LCG_PLATFORM="el9" else export LCG_PLATFORM="$OS" fi @@ -431,3 +427,17 @@ lcg_105: COMPILER: - gcc13 - clang16 + +lcg_106a: + extends: .lcg_base_job + + variables: + LCG_VERSION: "106a" + + parallel: + matrix: + - OS: [alma9] + COMPILER: + - gcc13 + - gcc14 + - clang16 diff --git a/thirdparty/OpenDataDetector b/thirdparty/OpenDataDetector index 0bf11ff33bd..4c5e7413a50 160000 --- a/thirdparty/OpenDataDetector +++ b/thirdparty/OpenDataDetector @@ -1 +1 @@ -Subproject commit 0bf11ff33bd10d3070e6ecbc4bea0a7c42d86fa0 +Subproject commit 4c5e7413a505a7743cbec9544901e8c55172e513 From 8895da1c915b56c9ea2498e32bf86dadb4f8b018 Mon Sep 17 00:00:00 2001 From: Paul Gessinger Date: Fri, 29 Nov 2024 23:19:49 +0100 Subject: [PATCH 12/12] fix: Remove `final` on template derived classes (#3923) This seems to cause issues when using `dynamic_cast` on AppleClang 16 and llvm 18 on macOS 15 (at least). Reproducer: https://gist.github.com/paulgessinger/2c1d2abdeb322072c507878ab5833728 ## Summary by CodeRabbit - **New Features** - Enhanced extensibility of the `GridPortalLinkT`, `Axis`, `Affine3Transformed`, `GlobalSubspace`, and `LocalSubspace` classes by allowing subclassing. - Updated constructors and methods in `GridPortalLinkT` to improve error handling and functionality. - **Bug Fixes** - Improved validation in the `resolveVolume` method to ensure positions are within valid bounds. - **Documentation** - Clarified class hierarchies and relationships due to changes in access specifiers. --- Core/include/Acts/Geometry/GridPortalLink.hpp | 2 +- Core/include/Acts/Utilities/Axis.hpp | 4 ++-- Core/include/Acts/Utilities/GridAccessHelpers.hpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Core/include/Acts/Geometry/GridPortalLink.hpp b/Core/include/Acts/Geometry/GridPortalLink.hpp index 411e6bb9962..8bf1d06ee08 100644 --- a/Core/include/Acts/Geometry/GridPortalLink.hpp +++ b/Core/include/Acts/Geometry/GridPortalLink.hpp @@ -396,7 +396,7 @@ class GridPortalLink : public PortalLinkBase { /// @tparam Axes The axis types of the grid template requires(sizeof...(Axes) <= 2) -class GridPortalLinkT final : public GridPortalLink { +class GridPortalLinkT : public GridPortalLink { public: /// The internal grid type using GridType = Grid; diff --git a/Core/include/Acts/Utilities/Axis.hpp b/Core/include/Acts/Utilities/Axis.hpp index 5b55d27cd77..758a8c2ec3c 100644 --- a/Core/include/Acts/Utilities/Axis.hpp +++ b/Core/include/Acts/Utilities/Axis.hpp @@ -97,7 +97,7 @@ class NeighborHoodIndices { /// This class provides some basic functionality for calculating bin indices /// for a given equidistant binning. template -class Axis final : public IAxis { +class Axis : public IAxis { public: static constexpr AxisType type = AxisType::Equidistant; @@ -417,7 +417,7 @@ class Axis final : public IAxis { /// This class provides some basic functionality for calculating bin indices /// for a given binning with variable bin sizes. template -class Axis final : public IAxis { +class Axis : public IAxis { public: static constexpr AxisType type = AxisType::Variable; diff --git a/Core/include/Acts/Utilities/GridAccessHelpers.hpp b/Core/include/Acts/Utilities/GridAccessHelpers.hpp index 085ea318f26..fbaf7f3acbd 100644 --- a/Core/include/Acts/Utilities/GridAccessHelpers.hpp +++ b/Core/include/Acts/Utilities/GridAccessHelpers.hpp @@ -110,7 +110,7 @@ class IBoundToGridLocal { }; template -class Affine3Transformed final : public IGlobalToGridLocal { +class Affine3Transformed : public IGlobalToGridLocal { public: using grid_local_t = typename global_to_grid_local_t::grid_local_t; @@ -142,7 +142,7 @@ class Affine3Transformed final : public IGlobalToGridLocal { /// position /// @tparam ...Args template -class GlobalSubspace final : public IGlobalToGridLocal { +class GlobalSubspace : public IGlobalToGridLocal { public: using grid_local_t = std::array; @@ -179,7 +179,7 @@ class GlobalSubspace final : public IGlobalToGridLocal { // The bound to grid local transformation, if only access of a subspace // is requested template -class LocalSubspace final : public IBoundToGridLocal { +class LocalSubspace : public IBoundToGridLocal { public: using grid_local_t = std::array;