Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-23 08:20:39

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
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   // trajectories collection name is already checked by base ctor
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   // the output file can not be given externally since TFile accesses to the
0057   // same file from multiple threads are unsafe.
0058   // must always be opened internally
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   // Helper lambda to write 2D histogram and extract mean/width profiles
0084   const auto writeWithRefinement = [this](auto& hist,
0085                                           const std::string& meanPrefix,
0086                                           const std::string& widthPrefix) {
0087     hist.Write();
0088 
0089     // Get the histogram name and extract the suffix (e.g., "_d0_vs_eta")
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   // Write residual histograms
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   // Write pull histograms
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   // Write efficiency histograms
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   // Write track summary histograms
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   // Read truth input collections
0172   const auto& particles = m_inputParticles(ctx);
0173   const auto& trackParticleMatching = m_inputTrackParticleMatching(ctx);
0174 
0175   // Exclusive access to the histograms while filling
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 }  // namespace ActsExamples