ATLAS Offline Software
Loading...
Searching...
No Matches
ActsInspectTruthContentAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
8
10#include <unordered_map>
11
12namespace ActsTrk {
13
15 ISvcLocator* pSvcLocator)
16 : AthReentrantAlgorithm(name, pSvcLocator)
17 {}
18
20 ATH_MSG_INFO( "Initializing " << name() << " ..." );
21
22 ATH_CHECK( m_clusters.initialize() );
23 ATH_CHECK( m_seeds.initialize() );
24 ATH_CHECK( m_associationMap_key.initialize() );
25 ATH_CHECK( m_tracks.initialize() );
26
27 if (m_clusters.size() != m_associationMap_key.size()) {
28 ATH_MSG_ERROR("Inconsistent sizes of Clusters and TruthAssociationMaps");
29 return StatusCode::FAILURE;
30 }
31
32 for (const auto& trackKey : m_tracks) {
33 std::string containerName = trackKey.key();
34 m_onTrack_clusterStat.push_back( std::make_pair(containerName, cluster_stat_t()) );
35 m_trackStat.push_back( std::make_pair(containerName, track_stat_t()) );
36 }
37
38 return StatusCode::SUCCESS;
39 }
40
41
43 ATH_MSG_INFO( "Finalizing " << name() << " ..." );
44 ATH_MSG_INFO( "Statistics from Seed check with truth info:" );
45
47 ATH_MSG_FATAL("Problem dumping Cluster truth information");
48 return StatusCode::FAILURE;
49 }
50
52 ATH_MSG_FATAL("Problem dumping Seed truth information");
53 return StatusCode::FAILURE;
54 }
55
56 for (const auto& [trackCollectionName, onTrackStat] : m_onTrack_clusterStat) {
57 std::string reportName = "On Track Clusters (" + trackCollectionName + ")";
59 ATH_MSG_FATAL("Problem dumping On Track Cluster truth info (" << trackCollectionName << ")");
60 return StatusCode::FAILURE;
61 }
62 }
63
64 for (const auto& [trackCollectionName, trackStat] : m_trackStat) {
65 std::string reportName = "Track (" + trackCollectionName + ")";
67 ATH_MSG_FATAL("Problem dumping Track truth info (" << trackCollectionName << ")");
68 return StatusCode::FAILURE;
69 }
70 }
71
72 return StatusCode::SUCCESS;
73 }
74
75
76 StatusCode ActsInspectTruthContentAlg::execute(const EventContext& ctx) const {
77 ATH_MSG_DEBUG( "Executing " << name() << " ..." );
78
79 // contextual stat collectors
80 cluster_stat_t clusterStat {};
81 seed_stat_t seedStat {};
82
83 std::array<const ActsTrk::MeasurementToTruthParticleAssociation*, s_nClusterTypes> truths {};
84 // Fill Stat info for Cluster collection(s)
85 for (std::size_t i(0); i<m_clusters.size(); ++i) {
86 ATH_MSG_DEBUG( "Retrieving cluster collection with key " << m_clusters.at(i).key() );
88 ATH_CHECK(SG::get(clusters, m_clusters.at(i), ctx));
89
90 if (clusters->empty()) continue;
91 xAOD::UncalibMeasType elementType = clusters->front()->type();
92
93 ATH_MSG_DEBUG( "Retrieving Measurement to Truth Particle Association map with key: " << m_associationMap_key.at(i).key() );
94 ATH_CHECK(SG::get(truths[Acts::toUnderlying(elementType)], m_associationMap_key.at(i), ctx ));
95
96 // Check truth and clusters are compatible
97 ATH_CHECK( truths[Acts::toUnderlying(elementType)]->sourceContainer() == clusters);
98
99 ATH_CHECK( fillStatClusters(*clusters,
100 *truths[Acts::toUnderlying(elementType)],
101 clusterStat) );
102 }
103
104 ATH_CHECK( copyStatTable(clusterStat, m_clusterStat) );
105
106 for (std::size_t i(0); i<m_seeds.size(); ++i) {
107 ATH_MSG_DEBUG( "Retrieving seed collection with key: " << m_seeds.at(i).key() );
108 const ActsTrk::SeedContainer* seeds{};
109 ATH_CHECK(SG::get(seeds, m_seeds.at(i), ctx ));
110 ATH_CHECK( fillStatSeeds(*seeds, truths,seedStat) );
111 }
112
113 ATH_CHECK( copyStatTable(seedStat, m_seedStat) );
114
115 for (std::size_t i(0); i<m_tracks.size(); ++i) {
116 ATH_MSG_DEBUG( "Retrieving tracks collection with key " << m_tracks.at(i).key() );
117 const ActsTrk::TrackContainer* tracks{};
118 ATH_CHECK(SG::get(tracks, m_tracks.at(i), ctx));
119
120 cluster_stat_t onTrack_clusterStat {};
121 track_stat_t trackStat {};
122 ATH_CHECK( fillStatTracks(*tracks,
123 truths,
124 trackStat,
125 onTrack_clusterStat) );
126
127 ATH_CHECK( copyStatTable(trackStat, m_trackStat.at(i).second) );
128 ATH_CHECK( copyStatTable(onTrack_clusterStat, m_onTrack_clusterStat.at(i).second) );
129 }
130
131 return StatusCode::SUCCESS;
132 }
133
134
138 {
139 ATH_MSG_DEBUG( "Checking truth for clusters ..." );
140 for (const xAOD::UncalibratedMeasurement* meas : container) {
141 std::size_t clusterTypeIndex = Acts::toUnderlying(meas->type());
142 ++stat[Acts::toUnderlying(EStatClusters::kNTotal)][clusterTypeIndex];
143 const auto& tps = truth.at(meas->index());
144
145 // get number of (valid) contributions
146 if (tps.empty()) {
147 ++stat[Acts::toUnderlying(EStatClusters::kNClustersWithNoBarcode)][clusterTypeIndex];
148 continue;
149 }
150
151 // Check all barcodes are from primary particles
152 bool allValidParticles = true;
153 for (const auto* tp : tps) {
154 if ( not HepMC::is_simulation_particle(*tp) ) continue;
155 allValidParticles = false;
156 break;
157 }
158
159 if (tps.size() == 1) {
160 ++stat[Acts::toUnderlying(EStatClusters::kNClustersWith1Contribution)][clusterTypeIndex];
161 if (allValidParticles) ++stat[Acts::toUnderlying(EStatClusters::kNClustersWith1ValidContribution)][clusterTypeIndex];
162 }
163 else if (tps.size() == 2) {
164 ++stat[Acts::toUnderlying(EStatClusters::kNClustersWith2Contribution)][clusterTypeIndex];
165 if (allValidParticles) ++stat[Acts::toUnderlying(EStatClusters::kNClustersWith2ValidContribution)][clusterTypeIndex];
166 }
167 else {
168 ++stat[Acts::toUnderlying(EStatClusters::kNClustersWith3Contribution)][clusterTypeIndex];
169 if (allValidParticles) ++stat[Acts::toUnderlying(EStatClusters::kNClustersWith3ValidContribution)][clusterTypeIndex];
170 }
171
172 // get main contribution
173 bool hasContributionFromPrimaryParticle = false;
174 for (const auto* tp : tps) {
175 if ( HepMC::is_simulation_particle(*tp) ) continue;
176 hasContributionFromPrimaryParticle = true;
177 break;
178 }
179
180 if (not hasContributionFromPrimaryParticle) ++stat[Acts::toUnderlying(EStatClusters::kNClustersWith200kBarcode)][clusterTypeIndex];
181 else ++stat[Acts::toUnderlying(EStatClusters::kNClustersFromPrimaries)][clusterTypeIndex];
182 }
183
184 return StatusCode::SUCCESS;
185 }
186
187
189 std::array<const ActsTrk::MeasurementToTruthParticleAssociation*, s_nClusterTypes>& truths,
190 seed_stat_t& stat) const
191 {
192 ATH_MSG_DEBUG( "Checking truth for seeds ..." );
193 for (std::size_t i(0); i<seeds.size(); ++i) {
194 ActsTrk::Seed seed = seeds.at(i);
195
196 int nMatches = 0;
197 int nMeasurements = 0;
198 std::unordered_map<std::size_t, int> particleIds {};
199
200 std::size_t seedType = Acts::toUnderlying(deduceSeedType(seed));
201 ++stat[Acts::toUnderlying(EStatSeeds::kNTotal)][seedType];
202
203 const auto& sps = seed.sp();
204 for ( const xAOD::SpacePoint* sp : sps ) {
205 const auto& measurements = sp->measurements();
206 for (const xAOD::UncalibratedMeasurement* meas : measurements ) {
207 ++nMeasurements;
208
209 std::size_t clusterTypeIndex = Acts::toUnderlying(meas->type());
210 const ActsTrk::MeasurementToTruthParticleAssociation* truth = truths.at(clusterTypeIndex);
211 auto tps = truth->at(meas->index());
212
213 if (tps.empty()) continue;
214
215 bool contributionOnlyFromSimulationParticles = true;
216 for (const auto* tp : tps) {
217 if ( HepMC::is_simulation_particle(*tp) ) continue;
218 contributionOnlyFromSimulationParticles = false;
219
220 std::size_t pid = HepMC::uniqueID(tp);
221 particleIds.try_emplace( pid, 0 );
222 ++particleIds[pid];
223 }
224 if (contributionOnlyFromSimulationParticles) continue;
225
226 ++nMatches;
227 } // loop on measurements
228 } // loop on space points
229
230 // check if we have measurements associated to the same particle id
231 // if the number of entries for the same id (the key) is the same as the
232 // number of measurements in the seed, then we have a match
233 bool isFromSameParticle = false;
234 for (const auto [pid, nEntries] : particleIds) {
235 if (nEntries != nMeasurements) continue;
236 isFromSameParticle = true;
237 break;
238 }
239
240
241 if (nMatches == 0) {
242 ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsWith0Matches)][seedType];
243 } else if (nMatches == 1) {
244 ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsWith1Matches)][seedType];
245 } else if (nMatches == 2) {
246 ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsWith2Matches)][seedType];
247 if (isFromSameParticle) ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsSame2Matches)][seedType];
248 } else if (nMatches == 3) {
249 ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsWith3Matches)][seedType];
250 if (isFromSameParticle) ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsSame3Matches)][seedType];
251 } else if (nMatches == 4) {
252 ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsWith4Matches)][seedType];
253 if (isFromSameParticle) ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsSame4Matches)][seedType];
254 } else if (nMatches == 5) {
255 ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsWith5Matches)][seedType];
256 if (isFromSameParticle) ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsSame5Matches)][seedType];
257 } else if (nMatches == 6) {
258 ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsWith6Matches)][seedType];
259 if (isFromSameParticle) ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsSame6Matches)][seedType];
260 }
261 } // loop on seed
262
263 return StatusCode::SUCCESS;
264 }
265
267 assert(seed.sp().size() == 3ul);
268 const auto& bottom = seed.sp().at(0);
269 const auto& middle = seed.sp().at(1);
270 const auto& top = seed.sp().at(2);
271 xAOD::UncalibMeasType bottom_type = bottom->measurements().front()->type();
272 xAOD::UncalibMeasType middle_type = middle->measurements().front()->type();
273 xAOD::UncalibMeasType top_type = top->measurements().front()->type();
274
275 if (bottom_type == xAOD::UncalibMeasType::PixelClusterType and
278 return SeedType::PPP;
279 } else if (bottom_type == xAOD::UncalibMeasType::PixelClusterType and
282 return SeedType::PPS;
283 } else if (bottom_type == xAOD::UncalibMeasType::PixelClusterType and
286 return SeedType::PSS;
287 } else if (bottom_type == xAOD::UncalibMeasType::StripClusterType and
290 return SeedType::SSS;
291 } else {
292 return SeedType::Others;
293 }
294 }
295
296
298 std::array<const ActsTrk::MeasurementToTruthParticleAssociation*, s_nClusterTypes>& truths,
299 track_stat_t& trackStat,
300 cluster_stat_t& onTrackStat) const {
301 ATH_MSG_DEBUG( "Checking truth for tracks ..." );
302 for (const auto track : tracks) {
303 ++trackStat[Acts::toUnderlying(EStatTracks::kNTotal)][0];
304 std::size_t nHoles = track.nHoles();
305 if (nHoles == 0) ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks0Holes)][0];
306 else if (nHoles == 1) ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks1Holes)][0];
307 else if (nHoles == 2) ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks2Holes)][0];
308 else ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks3Holes)][0];
309
310 std::size_t nOutliers = track.nOutliers();
311 if (nOutliers == 0) ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks0Outliers)][0];
312 else if (nOutliers == 1) ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks1Outliers)][0];
313 else if (nOutliers == 2) ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks2Outliers)][0];
314 else ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks3Outliers)][0];
315
316
317 bool AllValids = true;
318 int nConsideredMeasurements = 0;
319 std::unordered_map<std::size_t, int> particleIds {};
320
321 // on track clusters
322 track.container()
323 .trackStateContainer().visitBackwards(track.tipIndex(),
324 [&truths, &onTrackStat,
325 &AllValids,
326 &nConsideredMeasurements, &particleIds]
327 (const auto& state) {
328 auto flags = state.typeFlags();
329 if (not flags.hasMeasurement()) return;
330 ++nConsideredMeasurements;
331
332 // get cluster
333 auto meas = detail::xAODUncalibMeasCalibrator::unpack(state.getUncalibratedSourceLink());
334 assert( meas != nullptr);
335
336
337 std::size_t clusterTypeIndex = Acts::toUnderlying(meas->type());
338 ++onTrackStat[Acts::toUnderlying(EStatClusters::kNTotal)][clusterTypeIndex];
339
340 const ActsTrk::MeasurementToTruthParticleAssociation* truth = truths[clusterTypeIndex];
341 const auto& tps = truth->at(meas->index());
342
343 if (tps.empty()) {
344 ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWithNoBarcode)][clusterTypeIndex];
345 AllValids = false;
346 return;
347 }
348
349 bool allBarcodesValid = true;
350 bool hasContributionFromPrimaryParticle = false;
351 for (const auto* tp : tps) {
352 if ( not HepMC::is_simulation_particle(*tp) ) {
353 hasContributionFromPrimaryParticle = true;
354 continue;
355 }
356 allBarcodesValid = false;
357 break;
358 }
359 if (not hasContributionFromPrimaryParticle) AllValids = false;
360
361 if (tps.size() == 1) {
362 ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWith1Contribution)][clusterTypeIndex];
363 if (allBarcodesValid) ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWith1ValidContribution)][clusterTypeIndex];
364 }
365 else if (tps.size() == 2) {
366 ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWith2Contribution)][clusterTypeIndex];
367 if (allBarcodesValid) ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWith2ValidContribution)][clusterTypeIndex];
368 }
369 else {
370 ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWith3Contribution)][clusterTypeIndex];
371 if (allBarcodesValid) ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWith3ValidContribution)][clusterTypeIndex];
372 }
373
374 bool contributionOnlyFromSimulationParticles = true;
375 for (const auto* tp : tps) {
376 if ( HepMC::is_simulation_particle(*tp) ) continue;
377 contributionOnlyFromSimulationParticles = false;
378
379 std::size_t pid = HepMC::uniqueID(tp);
380 particleIds.try_emplace( pid, 0 );
381 ++particleIds[pid];
382 }
383
384 // get main contribution
385 if (contributionOnlyFromSimulationParticles) ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWith200kBarcode)][clusterTypeIndex];
386 else ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersFromPrimaries)][clusterTypeIndex];
387 }); // llop on states
388
389 bool AllSameBarcode = false;
390 for ( const auto [pid, nEntries] : particleIds ) {
391 if (nEntries != nConsideredMeasurements) continue;
392 AllSameBarcode = true;
393 break;
394 }
395
396 if (AllValids) ++trackStat[Acts::toUnderlying(EStatTracks::kNFullMatch)][0];
397 if (AllSameBarcode) ++trackStat[Acts::toUnderlying(EStatTracks::kNPerfectMatch)][0];
398 } // loop on tracks
399
400 return StatusCode::SUCCESS;
401 }
402
403} // namespace
404
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_INFO(x,...)
#define ATH_MSG_FATAL(x,...)
static Double_t sp
if(pathvar)
SG::ReadHandleKeyArray< ActsTrk::SeedContainer > m_seeds
StatusCode fillStatClusters(const xAOD::UncalibratedMeasurementContainer &container, const ActsTrk::MeasurementToTruthParticleAssociation &truth, cluster_stat_t &stat) const
virtual StatusCode execute(const EventContext &ctx) const override
SeedType deduceSeedType(const ActsTrk::Seed &) const
std::array< std::array< std::size_t, 1 >, static_cast< std::size_t >(EStatTracks::kNStat)> track_stat_t
std::array< std::array< std::size_t, s_nClusterTypes >, static_cast< std::size_t >(EStatClusters::kNStat)> cluster_stat_t
StatusCode printStatTables(const std::string &objectCollectionName, const stat_t &stat) const
SG::ReadHandleKeyArray< ActsTrk::TrackContainer > m_tracks
StatusCode copyStatTable(const stat_t &contextual, stat_t &global) const
ActsInspectTruthContentAlg(const std::string &name, ISvcLocator *pSvcLocator)
StatusCode fillStatTracks(const ActsTrk::TrackContainer &tracks, std::array< const ActsTrk::MeasurementToTruthParticleAssociation *, s_nClusterTypes > &truths, track_stat_t &trackStat, cluster_stat_t &onTrackClusterStat) const
StatusCode fillStatSeeds(const ActsTrk::SeedContainer &seeds, std::array< const ActsTrk::MeasurementToTruthParticleAssociation *, s_nClusterTypes > &truths, seed_stat_t &stat) const
std::array< std::array< std::size_t, s_nSeedTypes >, static_cast< std::size_t >(EStatSeeds::kNStat)> seed_stat_t
SG::ReadHandleKeyArray< xAOD::UncalibratedMeasurementContainer > m_clusters
SG::ReadHandleKeyArray< ActsTrk::MeasurementToTruthParticleAssociation > m_associationMap_key
An algorithm that can be simultaneously executed in multiple threads.
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
int uniqueID(const T &p)
bool is_simulation_particle(const T &p)
Method to establish if a particle (or barcode) was created during the simulation (TODO update to be s...
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
UncalibratedMeasurement_v1 UncalibratedMeasurement
Define the version of the uncalibrated measurement class.
UncalibMeasType
Define the type of the uncalibrated measurement.
UncalibratedMeasurementContainer_v1 UncalibratedMeasurementContainer
Define the version of the uncalibrated measurement container.
Seed at(Index index) const
std::size_t size() const noexcept