29 #include <TVectorFfwd.h>
32 namespace ActsExamples {
33 struct AlgorithmContext;
40 m_effPlotTool(
m_cfg.effPlotToolConfig, lvl),
41 m_fakeRatePlotTool(
m_cfg.fakeRatePlotToolConfig, lvl),
42 m_duplicationPlotTool(
m_cfg.duplicationPlotToolConfig, lvl),
43 m_trackSummaryPlotTool(
m_cfg.trackSummaryPlotToolConfig, lvl) {
46 throw std::invalid_argument(
"Missing particles input collection");
49 throw std::invalid_argument(
"Missing hit-particles map input collection");
52 throw std::invalid_argument(
"Missing output filename");
63 throw std::invalid_argument(
"Could not open '" +
m_cfg.
filePath +
"'");
74 m_effPlotTool.clear(m_effPlotCache);
75 m_fakeRatePlotTool.clear(m_fakeRatePlotCache);
76 m_duplicationPlotTool.clear(m_duplicationPlotCache);
77 m_trackSummaryPlotTool.clear(m_trackSummaryPlotCache);
78 if (m_outputFile !=
nullptr) {
79 m_outputFile->Close();
84 float eff_tracks = float(m_nTotalMatchedTracks) / m_nTotalTracks;
85 float fakeRate_tracks = float(m_nTotalFakeTracks) / m_nTotalTracks;
86 float duplicationRate_tracks =
87 float(m_nTotalDuplicateTracks) / m_nTotalTracks;
89 float eff_particle = float(m_nTotalMatchedParticles) / m_nTotalParticles;
90 float fakeRate_particle = float(m_nTotalFakeParticles) / m_nTotalParticles;
91 float duplicationRate_particle =
92 float(m_nTotalDuplicateParticles) / m_nTotalParticles;
94 ACTS_DEBUG(
"nTotalTracks = " << m_nTotalTracks);
95 ACTS_DEBUG(
"nTotalMatchedTracks = " << m_nTotalMatchedTracks);
96 ACTS_DEBUG(
"nTotalDuplicateTracks = " << m_nTotalDuplicateTracks);
97 ACTS_DEBUG(
"nTotalFakeTracks = " << m_nTotalFakeTracks);
100 "Efficiency with tracks (nMatchedTracks/ nAllTracks) = " << eff_tracks);
102 "Fake rate with tracks (nFakeTracks/nAllTracks) = " << fakeRate_tracks);
103 ACTS_INFO(
"Duplicate rate with tracks (nDuplicateTracks/nAllTracks) = "
104 << duplicationRate_tracks);
105 ACTS_INFO(
"Efficiency with particles (nMatchedParticles/nTrueParticles) = "
107 ACTS_INFO(
"Fake rate with particles (nFakeParticles/nTrueParticles) = "
108 << fakeRate_particle);
110 "Duplicate rate with particles (nDuplicateParticles/nTrueParticles) = "
111 << duplicationRate_particle);
113 auto write_float = [&](
float f,
const char*
name) {
116 m_outputFile->WriteObject(&v,
name);
119 if (m_outputFile !=
nullptr) {
121 m_effPlotTool.write(m_effPlotCache);
122 m_fakeRatePlotTool.write(m_fakeRatePlotCache);
123 m_duplicationPlotTool.write(m_duplicationPlotCache);
124 m_trackSummaryPlotTool.write(m_trackSummaryPlotCache);
125 write_float(eff_tracks,
"eff_tracks");
126 write_float(fakeRate_tracks,
"fakerate_tracks");
127 write_float(duplicationRate_tracks,
"duplicaterate_tracks");
128 write_float(eff_particle,
"eff_particles");
129 write_float(fakeRate_particle,
"fakerate_particles");
130 write_float(duplicationRate_particle,
"duplicaterate_particles");
131 ACTS_INFO(
"Wrote performance plots to '" << m_outputFile->GetPath() <<
"'");
139 using RecoTrackInfo = std::pair<size_t, Acts::BoundTrackParameters>;
143 const auto&
particles = m_inputParticles(ctx);
144 const auto& hitParticlesMap = m_inputMeasurementParticlesMap(ctx);
146 std::map<ActsFatras::Barcode, std::size_t> particleTruthHitCount;
147 for (
const auto& [
_,
pid] : hitParticlesMap) {
148 particleTruthHitCount[
pid]++;
152 std::map<ActsFatras::Barcode, std::vector<RecoTrackInfo>> matched;
154 std::map<ActsFatras::Barcode, size_t> unmatched;
156 std::vector<ParticleHitCount> particleHitCounts;
159 std::lock_guard<std::mutex> lock(m_writeMutex);
162 std::vector<float> inputFeatures(3);
165 for (std::size_t iTraj = 0; iTraj < trajectories.size(); ++iTraj) {
166 const auto& traj = trajectories[iTraj];
167 const auto& mj = traj.multiTrajectory();
168 for (
auto trackTip : traj.tips()) {
174 if (not traj.hasTrackParameters(trackTip)) {
176 "No fitted track parameters for trajectory with entry index = "
180 const auto& fittedParameters = traj.trackParameters(trackTip);
182 m_trackSummaryPlotTool.fill(m_trackSummaryPlotCache, fittedParameters,
183 trajState.nStates, trajState.nMeasurements,
184 trajState.nOutliers, trajState.nHoles,
185 trajState.nSharedHits);
190 if (particleHitCounts.empty()) {
192 "No truth particle associated with this trajectory with entry "
201 particleHitCounts.front().particleId;
202 size_t nMajorityHits = particleHitCounts.front().hitCount;
206 const bool recoMatched =
207 static_cast<float>(nMajorityHits) / trajState.nMeasurements >=
208 m_cfg.truthMatchProbMin;
209 const bool truthMatched =
210 static_cast<float>(nMajorityHits) /
211 particleTruthHitCount.at(majorityParticleId) >=
212 m_cfg.truthMatchProbMin;
215 if (not
m_cfg.doubleMatching and recoMatched) {
216 matched[majorityParticleId].push_back(
217 {nMajorityHits, fittedParameters});
218 }
else if (
m_cfg.doubleMatching and recoMatched and truthMatched) {
219 matched[majorityParticleId].push_back(
220 {nMajorityHits, fittedParameters});
223 unmatched[majorityParticleId]++;
227 m_fakeRatePlotTool.fill(m_fakeRatePlotCache, fittedParameters, isFake);
232 if (
m_cfg.duplicatedPredictor && !isFake) {
233 inputFeatures[0] = trajState.nMeasurements;
234 inputFeatures[1] = trajState.nOutliers;
235 inputFeatures[2] = trajState.chi2Sum * 1.0 / trajState.NDF;
237 bool isDuplicated =
m_cfg.duplicatedPredictor(inputFeatures);
240 m_nTotalDuplicateTracks++;
243 m_duplicationPlotTool.fill(m_duplicationPlotCache, fittedParameters,
252 if (!
m_cfg.duplicatedPredictor) {
254 for (
auto& [particleId, matchedTracks] : matched) {
257 std::sort(matchedTracks.begin(), matchedTracks.end(),
259 return lhs.first >
rhs.first;
261 for (
size_t itrack = 0; itrack < matchedTracks.size(); itrack++) {
262 const auto& [nMajorityHits, fittedParameters] =
263 matchedTracks.at(itrack);
266 bool isDuplicated = (itrack != 0);
269 m_nTotalDuplicateTracks++;
272 m_duplicationPlotTool.fill(m_duplicationPlotCache, fittedParameters,
281 auto particleId =
particle.particleId();
283 size_t nMatchedTracks = 0;
284 bool isReconstructed =
false;
285 auto imatched = matched.find(particleId);
286 if (imatched != matched.end()) {
287 nMatchedTracks = imatched->second.size();
289 m_nTotalMatchedTracks += nMatchedTracks;
290 m_nTotalMatchedParticles += 1;
293 if (nMatchedTracks > 1) {
294 m_nTotalDuplicateParticles += 1;
296 isReconstructed =
true;
299 m_effPlotTool.fill(m_effPlotCache,
particle, isReconstructed);
301 m_duplicationPlotTool.fill(m_duplicationPlotCache,
particle,
305 size_t nFakeTracks = 0;
306 auto ifake = unmatched.find(particleId);
307 if (ifake != unmatched.end()) {
308 nFakeTracks = ifake->second;
309 m_nTotalFakeTracks += nFakeTracks;
312 m_nTotalFakeParticles += 1;
315 m_fakeRatePlotTool.fill(m_fakeRatePlotCache,
particle, nMatchedTracks,
317 m_nTotalParticles += 1;