From 5addf0249d53d3553f5f0ae2e5e8d58619366304 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Thu, 3 Nov 2022 12:29:39 +0100 Subject: [PATCH] feat: add whiteboard aliases (#1588) I noticed that a lot of information on the whiteboard rolls from one algorithm to the next but requires a different name in the process. that makes it hard to use the correct name downstream. this PR adds an alias mechanism to the sequencer. the alias can be changes from one entry to the next. when queried the sequencer will return the entry behind the alias. --- CI/physmon/physmon.py | 16 +--- .../ActsExamples/Framework/Sequencer.hpp | 13 ++- .../ActsExamples/Framework/WhiteBoard.hpp | 18 +++-- .../Framework/src/Framework/Sequencer.cpp | 16 +++- .../Io/Root/RootVertexPerformanceWriter.hpp | 17 ++-- .../Python/python/acts/examples/__init__.py | 2 +- .../python/acts/examples/reconstruction.py | 81 ++++++++++++------- Examples/Python/src/ModuleEntry.cpp | 1 + Examples/Scripts/Python/vertex_fitting.py | 3 +- 9 files changed, 103 insertions(+), 64 deletions(-) diff --git a/CI/physmon/physmon.py b/CI/physmon/physmon.py index e3f53faba92..23a42a0b4b1 100755 --- a/CI/physmon/physmon.py +++ b/CI/physmon/physmon.py @@ -188,9 +188,7 @@ if label == "seeded": addAmbiguityResolution( s, - AmbiguityResolutionConfig( - maximumSharedHits=3, - ), + AmbiguityResolutionConfig(maximumSharedHits=3), CKFPerformanceConfig(ptMin=400.0 * u.MeV, nMeasurementsMin=6), outputDirRoot=tp, ) @@ -198,13 +196,7 @@ addVertexFitting( s, field, - trajectories="trajectories" if label == "seeded" else None, - trackParameters="filteredTrackParameters" - if label == "seeded" - else "fittedTrackParameters", - trackParametersTips="filteredTrackParametersTips" - if label == "seeded" - else "fittedTrackParametersTips", + associatedParticles=None if label == "seeded" else "particles_input", vertexFinder=VertexFinder.Iterative, outputDirRoot=tp, ) @@ -326,9 +318,7 @@ addAmbiguityResolution( s, - AmbiguityResolutionConfig( - maximumSharedHits=3, - ), + AmbiguityResolutionConfig(maximumSharedHits=3), CKFPerformanceConfig(ptMin=400.0 * u.MeV, nMeasurementsMin=6), outputDirRoot=None, ) diff --git a/Examples/Framework/include/ActsExamples/Framework/Sequencer.hpp b/Examples/Framework/include/ActsExamples/Framework/Sequencer.hpp index f58e431e74b..a179fb54641 100644 --- a/Examples/Framework/include/ActsExamples/Framework/Sequencer.hpp +++ b/Examples/Framework/include/ActsExamples/Framework/Sequencer.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,7 @@ class Sequencer { IterationCallback iterationCallback = []() {}; }; - Sequencer(const Config& cfg); + Sequencer(const Config &cfg); /// Add a service to the set of services. /// @@ -75,6 +76,10 @@ class Sequencer { /// @throws std::invalid_argument if the writer is NULL. void addWriter(std::shared_ptr writer); + /// Add an alias to the whiteboard. + void addWhiteboardAlias(const std::string &aliasName, + const std::string &objectName); + /// Run the event loop. /// /// @return status code compatible with the `main()` return code @@ -104,7 +109,7 @@ class Sequencer { int run(); /// Get const access to the config - const Config& config() const { return m_cfg; } + const Config &config() const { return m_cfg; } private: /// List of all configured algorithm names. @@ -121,7 +126,9 @@ class Sequencer { std::vector> m_writers; std::unique_ptr m_logger; - const Acts::Logger& logger() const { return *m_logger; } + std::unordered_map m_whiteboardObjectAliases; + + const Acts::Logger &logger() const { return *m_logger; } }; } // namespace ActsExamples diff --git a/Examples/Framework/include/ActsExamples/Framework/WhiteBoard.hpp b/Examples/Framework/include/ActsExamples/Framework/WhiteBoard.hpp index f618813b407..4dd88a36e3c 100644 --- a/Examples/Framework/include/ActsExamples/Framework/WhiteBoard.hpp +++ b/Examples/Framework/include/ActsExamples/Framework/WhiteBoard.hpp @@ -29,7 +29,8 @@ namespace ActsExamples { class WhiteBoard { public: WhiteBoard(std::unique_ptr logger = - Acts::getDefaultLogger("WhiteBoard", Acts::Logging::INFO)); + Acts::getDefaultLogger("WhiteBoard", Acts::Logging::INFO), + std::unordered_map objectAliases = {}); // A WhiteBoard holds unique elements and can not be copied WhiteBoard(const WhiteBoard& other) = delete; @@ -75,7 +76,8 @@ class WhiteBoard { }; std::unique_ptr m_logger; - std::unordered_map> m_store; + std::unordered_map> m_store; + std::unordered_map m_objectAliases; const Acts::Logger& logger() const { return *m_logger; } }; @@ -83,8 +85,9 @@ class WhiteBoard { } // namespace ActsExamples inline ActsExamples::WhiteBoard::WhiteBoard( - std::unique_ptr logger) - : m_logger(std::move(logger)) {} + std::unique_ptr logger, + std::unordered_map objectAliases) + : m_logger(std::move(logger)), m_objectAliases(std::move(objectAliases)) {} template inline void ActsExamples::WhiteBoard::add(const std::string& name, T&& object) { @@ -94,8 +97,13 @@ inline void ActsExamples::WhiteBoard::add(const std::string& name, T&& object) { if (0 < m_store.count(name)) { throw std::invalid_argument("Object '" + name + "' already exists"); } - m_store.emplace(name, std::make_unique>(std::forward(object))); + auto holder = std::make_shared>(std::forward(object)); + m_store.emplace(name, holder); ACTS_VERBOSE("Added object '" << name << "'"); + if (auto it = m_objectAliases.find(name); it != m_objectAliases.end()) { + m_store[it->second] = holder; + ACTS_VERBOSE("Added alias object '" << it->second << "'"); + } } template diff --git a/Examples/Framework/src/Framework/Sequencer.cpp b/Examples/Framework/src/Framework/Sequencer.cpp index 2d5c49e5f9e..290c408ba79 100644 --- a/Examples/Framework/src/Framework/Sequencer.cpp +++ b/Examples/Framework/src/Framework/Sequencer.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #ifndef ACTS_EXAMPLES_NO_TBB #include @@ -83,6 +84,15 @@ void ActsExamples::Sequencer::addWriter(std::shared_ptr writer) { ACTS_INFO("Added writer '" << m_writers.back()->name() << "'"); } +void ActsExamples::Sequencer::addWhiteboardAlias( + const std::string& aliasName, const std::string& objectName) { + auto [it, success] = + m_whiteboardObjectAliases.insert({objectName, aliasName}); + if (!success) { + throw std::invalid_argument("Alias to '" + objectName + "' already set"); + } +} + std::vector ActsExamples::Sequencer::listAlgorithmNames() const { std::vector names; @@ -291,8 +301,10 @@ int ActsExamples::Sequencer::run() { for (size_t event = r.begin(); event != r.end(); ++event) { m_cfg.iterationCallback(); // Use per-event store - WhiteBoard eventStore(Acts::getDefaultLogger( - "EventStore#" + std::to_string(event), m_cfg.logLevel)); + WhiteBoard eventStore( + Acts::getDefaultLogger("EventStore#" + std::to_string(event), + m_cfg.logLevel), + m_whiteboardObjectAliases); // If we ever wanted to run algorithms in parallel, this needs to be // changed to Algorithm context copies AlgorithmContext context(0, event, eventStore); diff --git a/Examples/Io/Root/include/ActsExamples/Io/Root/RootVertexPerformanceWriter.hpp b/Examples/Io/Root/include/ActsExamples/Io/Root/RootVertexPerformanceWriter.hpp index 6492505ff8c..ee13cbf6f06 100644 --- a/Examples/Io/Root/include/ActsExamples/Io/Root/RootVertexPerformanceWriter.hpp +++ b/Examples/Io/Root/include/ActsExamples/Io/Root/RootVertexPerformanceWriter.hpp @@ -33,18 +33,19 @@ class RootVertexPerformanceWriter final : public WriterT>> { public: struct Config { - /// All input truth particle collection + /// All input truth particle collection. std::string inputAllTruthParticles; - /// Selected input truth particle collection + /// Selected input truth particle collection. std::string inputSelectedTruthParticles; - /// Truth particles associated to tracks + /// Optional. Truth particles associated to tracks. Using 1:1 matching if + /// given. std::string inputAssociatedTruthParticles; - /// Input track parameters + /// Input track parameters. std::string inputTrackParameters; /// Input track parameters tips (points from `inputTrackParameters` to - /// `inputTrajectories`) + /// `inputTrajectories`). std::string inputTrackParametersTips; - /// Trajectories object from track finidng + /// Trajectories object from track finidng. std::string inputTrajectories; /// Input hit-particles map collection. std::string inputMeasurementParticlesMap; @@ -59,10 +60,10 @@ class RootVertexPerformanceWriter final /// File access mode. std::string fileMode = "RECREATE"; /// Minimum fraction of tracks matched between truth - /// and reco vertices to be matched for resolution plots + /// and reco vertices to be matched for resolution plots. double minTrackVtxMatchFraction = 0.5; /// Minimum fraction of hits associated to particle to consider - /// as truth matched + /// as truth matched. double truthMatchProbMin = 0.5; }; diff --git a/Examples/Python/python/acts/examples/__init__.py b/Examples/Python/python/acts/examples/__init__.py index e8bb03f30a0..f89da8da137 100644 --- a/Examples/Python/python/acts/examples/__init__.py +++ b/Examples/Python/python/acts/examples/__init__.py @@ -1,5 +1,5 @@ import sys, inspect -from typing import Optional, Protocol, Dict +from typing import Optional, Protocol from acts.ActsPythonBindings._examples import * from acts import ActsPythonBindings diff --git a/Examples/Python/python/acts/examples/reconstruction.py b/Examples/Python/python/acts/examples/reconstruction.py index 1a273ac1f4d..0e35ad81f74 100644 --- a/Examples/Python/python/acts/examples/reconstruction.py +++ b/Examples/Python/python/acts/examples/reconstruction.py @@ -712,9 +712,6 @@ def addCKFTracks( customLogLevel = acts.examples.defaultLogging(s, logLevel) logger = acts.logging.getLogger("addCKFTracks") - outputTrackParameters = "fittedTrackParameters" - outputTrackParametersTips = "fittedTrackParametersTips" - # Setup the track finding algorithm with CKF # It takes all the source links created from truth hit smearing, seeds from # truth particle smearing and source link selection config @@ -727,27 +724,38 @@ def addCKFTracks( inputSourceLinks="sourcelinks", inputInitialTrackParameters="estimatedparameters", outputTrajectories="trajectories", - outputTrackParameters=outputTrackParameters - + ("" if trackSelectorRanges is None else "Tmp"), - outputTrackParametersTips=outputTrackParametersTips - + ("" if trackSelectorRanges is None else "Tmp"), + outputTrackParameters="fittedTrackParameters", + outputTrackParametersTips="fittedTrackParametersTips", findTracks=acts.examples.TrackFindingAlgorithm.makeTrackFinderFunction( trackingGeometry, field ), ) s.addAlgorithm(trackFinder) + s.addWhiteboardAlias("trajectories", trackFinder.config.outputTrajectories) + s.addWhiteboardAlias("trackParameters", trackFinder.config.outputTrackParameters) + s.addWhiteboardAlias( + "trackParametersTips", trackFinder.config.outputTrackParametersTips + ) + if trackSelectorRanges is not None: - addTrackSelection( + trackSelector = addTrackSelection( s, trackSelectorRanges, inputTrackParameters=trackFinder.config.outputTrackParameters, inputTrackParametersTips=trackFinder.config.outputTrackParametersTips, - outputTrackParameters=outputTrackParameters, - outputTrackParametersTips=outputTrackParametersTips, + outputTrackParameters="selectedFittedTrackParameters", + outputTrackParametersTips="selectedFittedTrackParametersTips", logLevel=customLogLevel(), ) + s.addWhiteboardAlias( + "trackParameters", trackSelector.config.outputTrackParameters + ) + s.addWhiteboardAlias( + "trackParametersTips", trackSelector.config.outputTrackParametersTips + ) + if outputDirRoot is not None: outputDirRoot = Path(outputDirRoot) if not outputDirRoot.exists(): @@ -830,7 +838,7 @@ def addTrackSelection( outputTrackParameters: str, outputTrackParametersTips: str, logLevel: Optional[acts.logging.Level] = None, -): +) -> acts.examples.TrackSelector: customLogLevel = acts.examples.defaultLogging(s, logLevel) @@ -862,6 +870,8 @@ def addTrackSelection( s.addAlgorithm(trackSelector) + return trackSelector + ExaTrkXBackend = Enum("ExaTrkXBackend", "Torch Onnx") @@ -965,9 +975,8 @@ def addAmbiguityResolution( outputDirRoot: Optional[Union[Path, str]] = None, logLevel: Optional[acts.logging.Level] = None, ) -> None: - from acts.examples import ( - AmbiguityResolutionAlgorithm, - ) + + from acts.examples import AmbiguityResolutionAlgorithm customLogLevel = acts.examples.defaultLogging(s, logLevel) @@ -975,8 +984,8 @@ def addAmbiguityResolution( level=customLogLevel(), inputSourceLinks="sourcelinks", inputTrajectories="trajectories", - inputTrackParameters="fittedTrackParameters", - inputTrackParametersTips="fittedTrackParametersTips", + inputTrackParameters="trackParameters", + inputTrackParametersTips="trackParametersTips", outputTrackParameters="filteredTrackParameters", outputTrackParametersTips="filteredTrackParametersTips", **acts.examples.defaultKWArgs( @@ -985,6 +994,9 @@ def addAmbiguityResolution( ) s.addAlgorithm(alg) + s.addWhiteboardAlias("trackParameters", alg.config.outputTrackParameters) + s.addWhiteboardAlias("trackParametersTips", alg.config.outputTrackParametersTips) + if outputDirRoot is not None: outputDirRoot = Path(outputDirRoot) if not outputDirRoot.exists(): @@ -1021,14 +1033,15 @@ def addVertexFitting( s, field, outputDirRoot: Optional[Union[Path, str]] = None, - associatedParticles: str = "particles_input", + associatedParticles: Optional[str] = None, trajectories: Optional[str] = "trajectories", - trackParameters: str = "filteredTrackParameters", - trackParametersTips: Optional[str] = "filteredTrackParametersTips", + trackParameters: str = "trackParameters", + trackParametersTips: Optional[str] = "trackParametersTips", vertexFinder: VertexFinder = VertexFinder.Truth, trackSelectorRanges: Optional[TrackSelectorRanges] = None, logLevel: Optional[acts.logging.Level] = None, ) -> None: + """This function steers the vertex fitting Parameters @@ -1056,22 +1069,26 @@ def addVertexFitting( customLogLevel = acts.examples.defaultLogging(s, logLevel) if trackSelectorRanges is not None: - addTrackSelection( + trackSelector = addTrackSelection( s, trackSelectorRanges, inputTrackParameters=trackParameters, inputTrackParametersTips=trackParametersTips, - outputTrackParameters=trackParameters + "Tmp", - outputTrackParametersTips=trackParametersTips + "Tmp", + outputTrackParameters="selectedTrackParametersVertexing", + outputTrackParametersTips="selectedTrackParametersTipsVertexing", logLevel=customLogLevel(), ) - trackParameters = trackParameters + "Tmp" - trackParametersTips = trackParametersTips + "Tmp" + trackParameters = trackSelector.config.outputTrackParameters + trackParametersTips = ( + trackSelector.config.outputTrackParametersTips + if trackParametersTips is not None + else None + ) inputParticles = "particles_input" - outputVertices = "fittedVertices" selectedParticles = "particles_selected" + outputVertices = "fittedVertices" outputTime = "" if vertexFinder == VertexFinder.Truth: @@ -1127,15 +1144,17 @@ def addVertexFitting( level=customLogLevel(), inputAllTruthParticles=inputParticles, inputSelectedTruthParticles=selectedParticles, - inputTrackParameters=trackParameters, - inputTrackParametersTips=trackParametersTips, + inputAssociatedTruthParticles=associatedParticles + if associatedParticles is not None + else "", inputMeasurementParticlesMap="measurement_particles_map", inputTrajectories=trajectories if trajectories is not None else "", - inputAssociatedTruthParticles="" - if trajectories is not None - else associatedParticles, + inputTrackParameters=trackParameters, + inputTrackParametersTips=trackParametersTips + if trackParametersTips is not None + else "", inputVertices=outputVertices, - minTrackVtxMatchFraction=0.0 if trajectories is not None else 0.5, + minTrackVtxMatchFraction=0.0 if associatedParticles is None else 0.5, inputTime=outputTime, treeName="vertexing", filePath=str(outputDirRoot / "performance_vertexing.root"), diff --git a/Examples/Python/src/ModuleEntry.cpp b/Examples/Python/src/ModuleEntry.cpp index 2282bd1fcf3..1db2b5a28f8 100644 --- a/Examples/Python/src/ModuleEntry.cpp +++ b/Examples/Python/src/ModuleEntry.cpp @@ -208,6 +208,7 @@ PYBIND11_MODULE(ActsPythonBindings, m) { .def("addAlgorithm", &Sequencer::addAlgorithm, py::keep_alive<1, 2>()) .def("addReader", &Sequencer::addReader) .def("addWriter", &Sequencer::addWriter) + .def("addWhiteboardAlias", &Sequencer::addWhiteboardAlias) .def_property_readonly("config", &Sequencer::config); py::class_(sequencer, "Config") diff --git a/Examples/Scripts/Python/vertex_fitting.py b/Examples/Scripts/Python/vertex_fitting.py index 6d42eb5e1f9..16504428241 100755 --- a/Examples/Scripts/Python/vertex_fitting.py +++ b/Examples/Scripts/Python/vertex_fitting.py @@ -99,11 +99,12 @@ def runVertexFitting( addVertexFitting( s, field, - outputDirRoot=outputDir if outputRoot else None, associatedParticles=associatedParticles, trajectories=None, trackParameters=trackParameters, + trackParametersTips=None, vertexFinder=vertexFinder, + outputDirRoot=outputDir if outputRoot else None, ) return s