Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-05 08:23:23

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/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   // Truth particles with corresponding reconstructed tracks
0032   std::vector<SimBarcode> reconParticleIds;
0033   reconParticleIds.reserve(tracks.size());
0034 
0035   // Loop over all tracks
0036   for (const auto& track : tracks) {
0037     ++m_stats.nTotalTracks;
0038 
0039     // Select reco track with fitted parameters
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     // Get the truth-matched particle
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     // Get the barcode of the majority truth particle
0061     SimBarcode majorityParticleId = particleMatch.particle.value();
0062 
0063     // Find the truth particle via the barcode
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     // Record this majority particle ID
0071     reconParticleIds.push_back(ip->particleId());
0072 
0073     // Fill residual plots
0074     m_resPlotTool.fill(geoContext, ip->initialState(), fittedParameters);
0075 
0076     // Fill track summary info
0077     m_trackSummaryPlotTool.fill(fittedParameters, track.nTrackStates(),
0078                                 track.nMeasurements(), track.nOutliers(),
0079                                 track.nHoles(), track.nSharedHits());
0080   }
0081 
0082   // Fill the efficiency
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 }  // namespace ActsExamples