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