File indexing completed on 2026-08-23 08:20:39
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Io/Root/RootTrackParameterPerformanceWriter.hpp"
0010
0011 #include "Acts/Utilities/Helpers.hpp"
0012 #include "ActsExamples/Framework/AlgorithmContext.hpp"
0013 #include "ActsPlugins/Root/HistogramConverter.hpp"
0014
0015 #include <stdexcept>
0016 #include <utility>
0017
0018 #include <TEfficiency.h>
0019 #include <TFile.h>
0020 #include <TFitResult.h>
0021 #include <TFitResultPtr.h>
0022 #include <TH1.h>
0023 #include <TH2.h>
0024 #include <TH3.h>
0025 #include <TProfile.h>
0026
0027 using ActsPlugins::toRoot;
0028
0029 namespace ActsExamples {
0030
0031 RootTrackParameterPerformanceWriter::RootTrackParameterPerformanceWriter(
0032 RootTrackParameterPerformanceWriter::Config config,
0033 Acts::Logging::Level level)
0034 : WriterT(config.inputTracks, "RootTrackParameterPerformanceWriter", level),
0035 m_cfg(std::move(config)),
0036 m_collector(
0037 TrackParameterPerformanceCollector::Config{
0038 m_cfg.resPlotToolConfig, m_cfg.effPlotToolConfig,
0039 m_cfg.trackSummaryPlotToolConfig, m_cfg.fitMinEntries,
0040 m_cfg.fitSigmaRange, m_cfg.fitIterations},
0041 logger().clone()) {
0042
0043 if (m_cfg.inputParticles.empty()) {
0044 throw std::invalid_argument("Missing particles input collection");
0045 }
0046 if (m_cfg.inputTrackParticleMatching.empty()) {
0047 throw std::invalid_argument("Missing input track particles matching");
0048 }
0049 if (m_cfg.filePath.empty()) {
0050 throw std::invalid_argument("Missing output filename");
0051 }
0052
0053 m_inputParticles.initialize(m_cfg.inputParticles);
0054 m_inputTrackParticleMatching.initialize(m_cfg.inputTrackParticleMatching);
0055
0056
0057
0058
0059 auto path = m_cfg.filePath;
0060 m_outputFile = TFile::Open(path.c_str(), "RECREATE");
0061 if (m_outputFile == nullptr) {
0062 throw std::invalid_argument("Could not open '" + path + "'");
0063 }
0064 }
0065
0066 RootTrackParameterPerformanceWriter::~RootTrackParameterPerformanceWriter() {
0067 delete m_outputFile;
0068 }
0069
0070 ProcessCode RootTrackParameterPerformanceWriter::finalize() {
0071 if (m_outputFile == nullptr) {
0072 return ProcessCode::SUCCESS;
0073 }
0074
0075 m_collector.logSummary();
0076
0077 m_outputFile->cd();
0078
0079 const auto& resPlotTool = m_collector.resPlotTool();
0080 const auto& effPlotTool = m_collector.effPlotTool();
0081 const auto& trackSummaryPlotTool = m_collector.trackSummaryPlotTool();
0082
0083
0084 const auto writeWithRefinement = [this](auto& hist,
0085 const std::string& meanPrefix,
0086 const std::string& widthPrefix) {
0087 hist.Write();
0088
0089
0090 const std::string baseName = hist.GetName();
0091 const std::string suffix = baseName.substr(baseName.find('_'));
0092
0093 auto [meanHist, widthHist, fitFailureFraction] =
0094 ActsPlugins::extractMeanWidthProfiles(
0095 hist, meanPrefix + suffix, widthPrefix + suffix,
0096 m_cfg.fitMinEntries, m_cfg.fitSigmaRange, m_cfg.fitIterations,
0097 logger());
0098 if (fitFailureFraction >= m_cfg.warningThresholdFitFailureFraction) {
0099 ACTS_WARNING("Fit failures for " << baseName << ": "
0100 << fitFailureFraction * 100 << "%");
0101 }
0102
0103 meanHist->Write();
0104 widthHist->Write();
0105 };
0106
0107
0108 for (const auto& [name, hist] : resPlotTool.res()) {
0109 toRoot(hist)->Write();
0110 }
0111 for (const auto& [name, hist] : resPlotTool.resVsEta()) {
0112 writeWithRefinement(*toRoot(hist), "resmean", "reswidth");
0113 }
0114 for (const auto& [name, hist] : resPlotTool.resVsPt()) {
0115 writeWithRefinement(*toRoot(hist), "resmean", "reswidth");
0116 }
0117 for (const auto& [name, hist] : resPlotTool.resVsEtaPhi()) {
0118 writeWithRefinement(*toRoot(hist), "resmean", "reswidth");
0119 }
0120 for (const auto& [name, hist] : resPlotTool.resVsEtaPt()) {
0121 writeWithRefinement(*toRoot(hist), "resmean", "reswidth");
0122 }
0123
0124
0125 for (const auto& [name, hist] : resPlotTool.pull()) {
0126 toRoot(hist)->Write();
0127 }
0128 for (const auto& [name, hist] : resPlotTool.pullVsEta()) {
0129 writeWithRefinement(*toRoot(hist), "pullmean", "pullwidth");
0130 }
0131 for (const auto& [name, hist] : resPlotTool.pullVsPt()) {
0132 writeWithRefinement(*toRoot(hist), "pullmean", "pullwidth");
0133 }
0134 for (const auto& [name, hist] : resPlotTool.pullVsEtaPhi()) {
0135 writeWithRefinement(*toRoot(hist), "pullmean", "pullwidth");
0136 }
0137 for (const auto& [name, hist] : resPlotTool.pullVsEtaPt()) {
0138 writeWithRefinement(*toRoot(hist), "pullmean", "pullwidth");
0139 }
0140
0141
0142 for (const auto& [name, eff] : effPlotTool.efficiencies1D()) {
0143 toRoot(eff)->Write();
0144 }
0145 for (const auto& [name, eff] : effPlotTool.efficiencies2D()) {
0146 toRoot(eff)->Write();
0147 }
0148
0149 for (const auto& eff : effPlotTool.trackEffVsEtaInPtRanges()) {
0150 toRoot(eff)->Write();
0151 }
0152 for (const auto& eff : effPlotTool.trackEffVsPtInAbsEtaRanges()) {
0153 toRoot(eff)->Write();
0154 }
0155
0156
0157 for (const auto& [name, prof] : trackSummaryPlotTool.profiles()) {
0158 toRoot(prof)->Write();
0159 }
0160
0161 ACTS_INFO("Wrote performance plots to '" << m_outputFile->GetPath() << "'");
0162
0163 if (m_outputFile != nullptr) {
0164 m_outputFile->Close();
0165 }
0166 return ProcessCode::SUCCESS;
0167 }
0168
0169 ProcessCode RootTrackParameterPerformanceWriter::writeT(
0170 const AlgorithmContext& ctx, const ConstTrackContainer& tracks) {
0171
0172 const auto& particles = m_inputParticles(ctx);
0173 const auto& trackParticleMatching = m_inputTrackParticleMatching(ctx);
0174
0175
0176 std::lock_guard<std::mutex> lock(m_writeMutex);
0177
0178 m_collector.fill(ctx.geoContext, tracks, particles, trackParticleMatching);
0179
0180 return ProcessCode::SUCCESS;
0181 }
0182
0183 }