File indexing completed on 2026-08-05 08:23:23
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Validation/TrackFitterPerformanceCollector.hpp"
0010
0011 #include "Acts/Utilities/Logger.hpp"
0012 #include "Acts/Utilities/VectorHelpers.hpp"
0013
0014 #include <utility>
0015
0016 namespace ActsExamples {
0017
0018 TrackFitterPerformanceCollector::TrackFitterPerformanceCollector(
0019 Config cfg, std::unique_ptr<const Acts::Logger> logger)
0020 : m_cfg(std::move(cfg)),
0021 m_logger(std::move(logger)),
0022 m_resPlotTool(m_cfg.resPlotToolConfig, m_logger->level()),
0023 m_effPlotTool(m_cfg.effPlotToolConfig, m_logger->level()),
0024 m_trackSummaryPlotTool(m_cfg.trackSummaryPlotToolConfig,
0025 m_logger->level()) {}
0026
0027 void TrackFitterPerformanceCollector::fill(
0028 const Acts::GeometryContext& geoContext, const ConstTrackContainer& tracks,
0029 const SimParticleContainer& particles,
0030 const TrackParticleMatching& trackParticleMatching) {
0031
0032 std::vector<SimBarcode> reconParticleIds;
0033 reconParticleIds.reserve(tracks.size());
0034
0035
0036 for (const auto& track : tracks) {
0037 ++m_stats.nTotalTracks;
0038
0039
0040 if (!track.hasReferenceSurface()) {
0041 ACTS_DEBUG("No fitted track parameters for track " << track.index());
0042 continue;
0043 }
0044 Acts::BoundTrackParameters fittedParameters =
0045 track.createParametersAtReference();
0046
0047
0048 auto imatched = trackParticleMatching.find(track.index());
0049 if (imatched == trackParticleMatching.end()) {
0050 ACTS_DEBUG("No truth particle associated with track " << track.index());
0051 continue;
0052 }
0053 const auto& particleMatch = imatched->second;
0054
0055 if (!particleMatch.particle.has_value()) {
0056 ACTS_DEBUG("No truth particle associated with track " << track.index());
0057 continue;
0058 }
0059
0060
0061 SimBarcode majorityParticleId = particleMatch.particle.value();
0062
0063
0064 auto ip = particles.find(majorityParticleId);
0065 if (ip == particles.end()) {
0066 ACTS_DEBUG("Majority particle not found for track " << track.index());
0067 continue;
0068 }
0069
0070
0071 reconParticleIds.push_back(ip->particleId());
0072
0073
0074 m_resPlotTool.fill(geoContext, ip->initialState(), fittedParameters);
0075
0076
0077 m_trackSummaryPlotTool.fill(fittedParameters, track.nTrackStates(),
0078 track.nMeasurements(), track.nOutliers(),
0079 track.nHoles(), track.nSharedHits());
0080 }
0081
0082
0083 for (const auto& particle : particles) {
0084 ++m_stats.nTotalParticles;
0085
0086 bool isReconstructed = false;
0087 if (Acts::rangeContainsValue(reconParticleIds, particle.particleId())) {
0088 isReconstructed = true;
0089 ++m_stats.nTotalMatchedTracks;
0090 ++m_stats.nTotalMatchedParticles;
0091 }
0092
0093 double minDeltaR = -1;
0094 for (const auto& closeParticle : particles) {
0095 if (closeParticle.particleId() == particle.particleId()) {
0096 continue;
0097 }
0098 double distance = Acts::VectorHelpers::deltaR(particle.direction(),
0099 closeParticle.direction());
0100 if (minDeltaR == -1 || distance < minDeltaR) {
0101 minDeltaR = distance;
0102 }
0103 }
0104
0105 m_effPlotTool.fill(geoContext, particle.initialState(), minDeltaR,
0106 isReconstructed);
0107 }
0108 }
0109
0110 void TrackFitterPerformanceCollector::logSummary() const {
0111 ACTS_INFO("=== Track Fitter Performance Summary ===");
0112 ACTS_INFO("Total tracks: " << m_stats.nTotalTracks);
0113 ACTS_INFO("Total matched tracks: " << m_stats.nTotalMatchedTracks);
0114 ACTS_INFO("Total particles: " << m_stats.nTotalParticles);
0115 ACTS_INFO("Total matched particles: " << m_stats.nTotalMatchedParticles);
0116
0117 if (m_stats.nTotalTracks > 0) {
0118 double efficiency =
0119 static_cast<double>(m_stats.nTotalMatchedTracks) / m_stats.nTotalTracks;
0120 ACTS_INFO("Track efficiency: " << efficiency * 100 << "%");
0121 }
0122 }
0123
0124 }