File indexing completed on 2026-05-07 07:59:54
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Utilities/Logger.hpp"
0010 #include "ActsExamples/EventData/Index.hpp"
0011 #include "ActsExamples/EventData/SimParticle.hpp"
0012 #include "ActsExamples/EventData/Track.hpp"
0013 #include "ActsExamples/EventData/TruthMatching.hpp"
0014 #include "ActsExamples/Framework/DataHandle.hpp"
0015 #include "ActsExamples/Framework/IWriter.hpp"
0016 #include "ActsExamples/Framework/ProcessCode.hpp"
0017 #include "ActsExamples/Framework/WriterT.hpp"
0018 #include "ActsExamples/Validation/TrackFinderPerformanceCollector.hpp"
0019 #include "ActsPython/Utilities/Macros.hpp"
0020
0021 #include <mutex>
0022 #include <stdexcept>
0023 #include <string>
0024
0025 #include <pybind11/pybind11.h>
0026 #include <pybind11/stl.h>
0027
0028 namespace py = pybind11;
0029 using namespace pybind11::literals;
0030
0031 using namespace Acts;
0032 using namespace ActsExamples;
0033
0034 namespace {
0035
0036
0037
0038 class PythonTrackFinderPerformanceWriter final
0039 : public WriterT<ConstTrackContainer> {
0040 public:
0041 struct Config {
0042
0043 std::string inputTracks;
0044
0045 std::string inputParticles;
0046
0047 std::string inputTrackParticleMatching;
0048
0049 std::string inputParticleTrackMatching;
0050
0051 std::string inputParticleMeasurementsMap;
0052
0053 EffPlotTool::Config effPlotToolConfig;
0054 FakePlotTool::Config fakePlotToolConfig;
0055 DuplicationPlotTool::Config duplicationPlotToolConfig;
0056 TrackSummaryPlotTool::Config trackSummaryPlotToolConfig;
0057 TrackQualityPlotTool::Config trackQualityPlotToolConfig;
0058
0059 std::map<std::string, std::set<int>> subDetectorTrackSummaryVolumes;
0060 };
0061
0062 PythonTrackFinderPerformanceWriter(Config cfg, Acts::Logging::Level lvl)
0063 : WriterT(cfg.inputTracks, "PythonTrackFinderPerformanceWriter", lvl),
0064 m_cfg(std::move(cfg)),
0065 m_collector(
0066 TrackFinderPerformanceCollector::Config{
0067 m_cfg.effPlotToolConfig, m_cfg.fakePlotToolConfig,
0068 m_cfg.duplicationPlotToolConfig,
0069 m_cfg.trackSummaryPlotToolConfig,
0070 m_cfg.trackQualityPlotToolConfig,
0071 m_cfg.subDetectorTrackSummaryVolumes},
0072 logger().clone()) {
0073 if (m_cfg.inputParticles.empty()) {
0074 throw std::invalid_argument("Missing particles input collection");
0075 }
0076 if (m_cfg.inputTrackParticleMatching.empty()) {
0077 throw std::invalid_argument("Missing input track particles matching");
0078 }
0079 if (m_cfg.inputParticleTrackMatching.empty()) {
0080 throw std::invalid_argument("Missing input particle track matching");
0081 }
0082 if (m_cfg.inputParticleMeasurementsMap.empty()) {
0083 throw std::invalid_argument("Missing input measurement particles map");
0084 }
0085
0086 m_inputParticles.initialize(m_cfg.inputParticles);
0087 m_inputTrackParticleMatching.initialize(m_cfg.inputTrackParticleMatching);
0088 m_inputParticleTrackMatching.initialize(m_cfg.inputParticleTrackMatching);
0089 m_inputParticleMeasurementsMap.initialize(
0090 m_cfg.inputParticleMeasurementsMap);
0091 }
0092
0093 ProcessCode finalize() override {
0094 m_collector.logSummary();
0095 return ProcessCode::SUCCESS;
0096 }
0097
0098 const Config& config() const { return m_cfg; }
0099
0100
0101 py::dict histograms() const {
0102 py::dict d;
0103 const auto& coll = m_collector;
0104
0105 for (const auto& [name, eff] : coll.effPlotTool().efficiencies1D()) {
0106 d[py::str(name)] = py::cast(eff, py::return_value_policy::copy);
0107 }
0108 for (const auto& [name, eff] : coll.effPlotTool().efficiencies2D()) {
0109 d[py::str(name)] = py::cast(eff, py::return_value_policy::copy);
0110 }
0111 for (const auto& eff : coll.effPlotTool().trackEffVsEtaInPtRanges()) {
0112 d[py::str(eff.name())] = py::cast(eff, py::return_value_policy::copy);
0113 }
0114 for (const auto& eff : coll.effPlotTool().trackEffVsPtInAbsEtaRanges()) {
0115 d[py::str(eff.name())] = py::cast(eff, py::return_value_policy::copy);
0116 }
0117
0118 for (const auto& [name, hist] : coll.fakePlotTool().histograms()) {
0119 d[py::str(name)] = py::cast(hist, py::return_value_policy::copy);
0120 }
0121 for (const auto& [name, eff] : coll.fakePlotTool().efficiencies()) {
0122 d[py::str(name)] = py::cast(eff, py::return_value_policy::copy);
0123 }
0124
0125 for (const auto& [name, prof] : coll.duplicationPlotTool().profiles()) {
0126 d[py::str(name)] = py::cast(prof, py::return_value_policy::copy);
0127 }
0128 for (const auto& [name, eff] : coll.duplicationPlotTool().efficiencies()) {
0129 d[py::str(name)] = py::cast(eff, py::return_value_policy::copy);
0130 }
0131
0132 for (const auto& [name, prof] : coll.trackSummaryPlotTool().profiles()) {
0133 d[py::str(name)] = py::cast(prof, py::return_value_policy::copy);
0134 }
0135 for (const auto& [key, tool] : coll.subDetectorSummaryTools()) {
0136 for (const auto& [name, prof] : tool.profiles()) {
0137 d[py::str(name)] = py::cast(prof, py::return_value_policy::copy);
0138 }
0139 }
0140
0141 for (const auto& [name, prof] : coll.trackQualityPlotTool().profiles()) {
0142 d[py::str(name)] = py::cast(prof, py::return_value_policy::copy);
0143 }
0144
0145 return d;
0146 }
0147
0148 private:
0149 ProcessCode writeT(const AlgorithmContext& ctx,
0150 const ConstTrackContainer& tracks) override {
0151 const auto& particles = m_inputParticles(ctx);
0152 const auto& trackParticleMatching = m_inputTrackParticleMatching(ctx);
0153 const auto& particleTrackMatching = m_inputParticleTrackMatching(ctx);
0154 const auto& particleMeasurementsMap = m_inputParticleMeasurementsMap(ctx);
0155
0156 std::lock_guard<std::mutex> lock(m_writeMutex);
0157 return m_collector.fill(ctx.geoContext, tracks, particles,
0158 trackParticleMatching, particleTrackMatching,
0159 particleMeasurementsMap);
0160 }
0161
0162 Config m_cfg;
0163 std::mutex m_writeMutex;
0164 TrackFinderPerformanceCollector m_collector;
0165
0166 ReadDataHandle<SimParticleContainer> m_inputParticles{this, "InputParticles"};
0167 ReadDataHandle<TrackParticleMatching> m_inputTrackParticleMatching{
0168 this, "InputTrackParticleMatching"};
0169 ReadDataHandle<ParticleTrackMatching> m_inputParticleTrackMatching{
0170 this, "InputParticleTrackMatching"};
0171 ReadDataHandle<InverseMultimap<SimBarcode>> m_inputParticleMeasurementsMap{
0172 this, "InputParticleMeasurementsMap"};
0173 };
0174
0175 }
0176
0177 namespace ActsPython {
0178
0179 void addPythonSpecific(py::module_& mex) {
0180 using Writer = PythonTrackFinderPerformanceWriter;
0181 using Config = Writer::Config;
0182
0183 auto w = py::class_<Writer, IWriter, std::shared_ptr<Writer>>(
0184 mex, "PythonTrackFinderPerformanceWriter")
0185 .def(py::init<const Config&, Acts::Logging::Level>(),
0186 py::arg("config"), py::arg("level"))
0187 .def_property_readonly("config", &Writer::config)
0188 .def("histograms", &Writer::histograms);
0189
0190 auto c = py::class_<Config>(w, "Config").def(py::init<>());
0191 ACTS_PYTHON_STRUCT(c, inputTracks, inputParticles, inputTrackParticleMatching,
0192 inputParticleTrackMatching, inputParticleMeasurementsMap,
0193 effPlotToolConfig, fakePlotToolConfig,
0194 duplicationPlotToolConfig, trackSummaryPlotToolConfig,
0195 trackQualityPlotToolConfig,
0196 subDetectorTrackSummaryVolumes);
0197 }
0198
0199 }