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( clusterHandle.isValid() );
89 const xAOD::UncalibratedMeasurementContainer *clusters = clusterHandle.cptr();
90
91 if (clusters->empty()) continue;
92 xAOD::UncalibMeasType elementType = clusters->front()->type();
93
94 ATH_MSG_DEBUG( "Retrieving Measurement to Truth Particle Association map with key: " << m_associationMap_key.at(i).key() );
96 ATH_CHECK( truthHandle.isValid() );
97 truths[static_cast<std::size_t>(elementType)] = truthHandle.cptr();
98
99 // Check truth and clusters are compatible
100 ATH_CHECK( truths[static_cast<std::size_t>(elementType)]->isCompatibleWith(clusters) );
101
102 ATH_CHECK( fillStatClusters(*clusters,
103 *truths[static_cast<std::size_t>(elementType)],
104 clusterStat) );
105 }
106
107 ATH_CHECK( copyStatTable(clusterStat, m_clusterStat) );
108
109 for (std::size_t i(0); i<m_seeds.size(); ++i) {
110 ATH_MSG_DEBUG( "Retrieving seed collection with key: " << m_seeds.at(i).key() );
112 ATH_CHECK( seedHandle.isValid() );
113 const ActsTrk::SeedContainer* seeds = seedHandle.cptr();
114
115 ATH_CHECK( fillStatSeeds(*seeds,
116 truths,
117 seedStat) );
118 }
119
120 ATH_CHECK( copyStatTable(seedStat, m_seedStat) );
121
122 for (std::size_t i(0); i<m_tracks.size(); ++i) {
123 ATH_MSG_DEBUG( "Retrieving tracks collection with key " << m_tracks.at(i).key() );
125 ATH_CHECK( trackHandle.isValid() );
126 const ActsTrk::TrackContainer* tracks = trackHandle.cptr();
127
128 cluster_stat_t onTrack_clusterStat {};
129 track_stat_t trackStat {};
130 ATH_CHECK( fillStatTracks(*tracks,
131 truths,
132 trackStat,
133 onTrack_clusterStat) );
134
135 ATH_CHECK( copyStatTable(trackStat, m_trackStat.at(i).second) );
136 ATH_CHECK( copyStatTable(onTrack_clusterStat, m_onTrack_clusterStat.at(i).second) );
137 }
138
139 return StatusCode::SUCCESS;
140 }
141
142
146 {
147 ATH_MSG_DEBUG( "Checking truth for clusters ..." );
148 for (const xAOD::UncalibratedMeasurement* meas : container) {
149 std::size_t clusterTypeIndex = static_cast<std::size_t>(meas->type());
150 ++stat[Acts::toUnderlying(EStatClusters::kNTotal)][clusterTypeIndex];
151 const auto& tps = truth.at(meas->index());
152
153 // get number of (valid) contributions
154 if (tps.empty()) {
155 ++stat[Acts::toUnderlying(EStatClusters::kNClustersWithNoBarcode)][clusterTypeIndex];
156 continue;
157 }
158
159 // Check all barcodes are from primary particles
160 bool allValidParticles = true;
161 for (const auto* tp : tps) {
162 if ( not HepMC::is_simulation_particle(*tp) ) continue;
163 allValidParticles = false;
164 break;
165 }
166
167 if (tps.size() == 1) {
168 ++stat[Acts::toUnderlying(EStatClusters::kNClustersWith1Contribution)][clusterTypeIndex];
169 if (allValidParticles) ++stat[Acts::toUnderlying(EStatClusters::kNClustersWith1ValidContribution)][clusterTypeIndex];
170 }
171 else if (tps.size() == 2) {
172 ++stat[Acts::toUnderlying(EStatClusters::kNClustersWith2Contribution)][clusterTypeIndex];
173 if (allValidParticles) ++stat[Acts::toUnderlying(EStatClusters::kNClustersWith2ValidContribution)][clusterTypeIndex];
174 }
175 else {
176 ++stat[Acts::toUnderlying(EStatClusters::kNClustersWith3Contribution)][clusterTypeIndex];
177 if (allValidParticles) ++stat[Acts::toUnderlying(EStatClusters::kNClustersWith3ValidContribution)][clusterTypeIndex];
178 }
179
180 // get main contribution
181 bool hasContributionFromPrimaryParticle = false;
182 for (const auto* tp : tps) {
183 if ( HepMC::is_simulation_particle(*tp) ) continue;
184 hasContributionFromPrimaryParticle = true;
185 break;
186 }
187
188 if (not hasContributionFromPrimaryParticle) ++stat[Acts::toUnderlying(EStatClusters::kNClustersWith200kBarcode)][clusterTypeIndex];
189 else ++stat[Acts::toUnderlying(EStatClusters::kNClustersFromPrimaries)][clusterTypeIndex];
190 }
191
192 return StatusCode::SUCCESS;
193 }
194
195
197 std::array<const ActsTrk::MeasurementToTruthParticleAssociation*, s_nClusterTypes>& truths,
198 seed_stat_t& stat) const
199 {
200 ATH_MSG_DEBUG( "Checking truth for seeds ..." );
201 for (std::size_t i(0); i<seeds.size(); ++i) {
202 ActsTrk::Seed seed = seeds.at(i);
203
204 int nMatches = 0;
205 int nMeasurements = 0;
206 std::unordered_map<std::size_t, int> particleIds {};
207
208 std::size_t seedType = Acts::toUnderlying(deduceSeedType(seed));
209 ++stat[Acts::toUnderlying(EStatSeeds::kNTotal)][seedType];
210
211 const auto& sps = seed.sp();
212 for ( const xAOD::SpacePoint* sp : sps ) {
213 const auto& measurements = sp->measurements();
214 for (const xAOD::UncalibratedMeasurement* meas : measurements ) {
215 ++nMeasurements;
216
217 std::size_t clusterTypeIndex = Acts::toUnderlying(meas->type());
218 const ActsTrk::MeasurementToTruthParticleAssociation* truth = truths.at(clusterTypeIndex);
219 auto tps = truth->at(meas->index());
220
221 if (tps.empty()) continue;
222
223 bool contributionOnlyFromSimulationParticles = true;
224 for (const auto* tp : tps) {
225 if ( HepMC::is_simulation_particle(*tp) ) continue;
226 contributionOnlyFromSimulationParticles = false;
227
228 std::size_t pid = HepMC::uniqueID(tp);
229 particleIds.try_emplace( pid, 0 );
230 ++particleIds[pid];
231 }
232 if (contributionOnlyFromSimulationParticles) continue;
233
234 ++nMatches;
235 } // loop on measurements
236 } // loop on space points
237
238 // check if we have measurements associated to the same particle id
239 // if the number of entries for the same id (the key) is the same as the
240 // number of measurements in the seed, then we have a match
241 bool isFromSameParticle = false;
242 for (const auto [pid, nEntries] : particleIds) {
243 if (nEntries != nMeasurements) continue;
244 isFromSameParticle = true;
245 break;
246 }
247
248
249 if (nMatches == 0) {
250 ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsWith0Matches)][seedType];
251 } else if (nMatches == 1) {
252 ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsWith1Matches)][seedType];
253 } else if (nMatches == 2) {
254 ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsWith2Matches)][seedType];
255 if (isFromSameParticle) ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsSame2Matches)][seedType];
256 } else if (nMatches == 3) {
257 ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsWith3Matches)][seedType];
258 if (isFromSameParticle) ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsSame3Matches)][seedType];
259 } else if (nMatches == 4) {
260 ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsWith4Matches)][seedType];
261 if (isFromSameParticle) ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsSame4Matches)][seedType];
262 } else if (nMatches == 5) {
263 ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsWith5Matches)][seedType];
264 if (isFromSameParticle) ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsSame5Matches)][seedType];
265 } else if (nMatches == 6) {
266 ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsWith6Matches)][seedType];
267 if (isFromSameParticle) ++stat[Acts::toUnderlying(EStatSeeds::nKSeedsSame6Matches)][seedType];
268 }
269 } // loop on seed
270
271 return StatusCode::SUCCESS;
272 }
273
275 assert(seed.sp().size() == 3ul);
276 const auto& bottom = seed.sp().at(0);
277 const auto& middle = seed.sp().at(1);
278 const auto& top = seed.sp().at(2);
279 xAOD::UncalibMeasType bottom_type = bottom->measurements().front()->type();
280 xAOD::UncalibMeasType middle_type = middle->measurements().front()->type();
281 xAOD::UncalibMeasType top_type = top->measurements().front()->type();
282
283 if (bottom_type == xAOD::UncalibMeasType::PixelClusterType and
286 return SeedType::PPP;
287 } else if (bottom_type == xAOD::UncalibMeasType::PixelClusterType and
290 return SeedType::PPS;
291 } else if (bottom_type == xAOD::UncalibMeasType::PixelClusterType and
294 return SeedType::PSS;
295 } else if (bottom_type == xAOD::UncalibMeasType::StripClusterType and
298 return SeedType::SSS;
299 } else {
300 return SeedType::Others;
301 }
302 }
303
304
306 std::array<const ActsTrk::MeasurementToTruthParticleAssociation*, s_nClusterTypes>& truths,
307 track_stat_t& trackStat,
308 cluster_stat_t& onTrackStat) const {
309 ATH_MSG_DEBUG( "Checking truth for tracks ..." );
310 for (const auto track : tracks) {
311 ++trackStat[Acts::toUnderlying(EStatTracks::kNTotal)][0];
312 std::size_t nHoles = track.nHoles();
313 if (nHoles == 0) ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks0Holes)][0];
314 else if (nHoles == 1) ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks1Holes)][0];
315 else if (nHoles == 2) ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks2Holes)][0];
316 else ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks3Holes)][0];
317
318 std::size_t nOutliers = track.nOutliers();
319 if (nOutliers == 0) ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks0Outliers)][0];
320 else if (nOutliers == 1) ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks1Outliers)][0];
321 else if (nOutliers == 2) ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks2Outliers)][0];
322 else ++trackStat[Acts::toUnderlying(EStatTracks::kNTracks3Outliers)][0];
323
324
325 bool AllValids = true;
326 int nConsideredMeasurements = 0;
327 std::unordered_map<std::size_t, int> particleIds {};
328
329 // on track clusters
330 track.container()
331 .trackStateContainer().visitBackwards(track.tipIndex(),
332 [&truths, &onTrackStat,
333 &AllValids,
334 &nConsideredMeasurements, &particleIds]
335 (const auto& state) {
336 auto flags = state.typeFlags();
337 if (not flags.hasMeasurement()) return;
338 ++nConsideredMeasurements;
339
340 // get cluster
341 auto meas = detail::xAODUncalibMeasCalibrator::unpack(state.getUncalibratedSourceLink());
342 assert( meas != nullptr);
343
344
345 std::size_t clusterTypeIndex = Acts::toUnderlying(meas->type());
346 ++onTrackStat[Acts::toUnderlying(EStatClusters::kNTotal)][clusterTypeIndex];
347
348 const ActsTrk::MeasurementToTruthParticleAssociation* truth = truths[clusterTypeIndex];
349 const auto& tps = truth->at(meas->index());
350
351 if (tps.empty()) {
352 ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWithNoBarcode)][clusterTypeIndex];
353 AllValids = false;
354 return;
355 }
356
357 bool allBarcodesValid = true;
358 bool hasContributionFromPrimaryParticle = false;
359 for (const auto* tp : tps) {
360 if ( not HepMC::is_simulation_particle(*tp) ) {
361 hasContributionFromPrimaryParticle = true;
362 continue;
363 }
364 allBarcodesValid = false;
365 break;
366 }
367 if (not hasContributionFromPrimaryParticle) AllValids = false;
368
369 if (tps.size() == 1) {
370 ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWith1Contribution)][clusterTypeIndex];
371 if (allBarcodesValid) ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWith1ValidContribution)][clusterTypeIndex];
372 }
373 else if (tps.size() == 2) {
374 ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWith2Contribution)][clusterTypeIndex];
375 if (allBarcodesValid) ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWith2ValidContribution)][clusterTypeIndex];
376 }
377 else {
378 ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWith3Contribution)][clusterTypeIndex];
379 if (allBarcodesValid) ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWith3ValidContribution)][clusterTypeIndex];
380 }
381
382 bool contributionOnlyFromSimulationParticles = true;
383 for (const auto* tp : tps) {
384 if ( HepMC::is_simulation_particle(*tp) ) continue;
385 contributionOnlyFromSimulationParticles = false;
386
387 std::size_t pid = HepMC::uniqueID(tp);
388 particleIds.try_emplace( pid, 0 );
389 ++particleIds[pid];
390 }
391
392 // get main contribution
393 if (contributionOnlyFromSimulationParticles) ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersWith200kBarcode)][clusterTypeIndex];
394 else ++onTrackStat[Acts::toUnderlying(EStatClusters::kNClustersFromPrimaries)][clusterTypeIndex];
395 }); // llop on states
396
397 bool AllSameBarcode = false;
398 for ( const auto [pid, nEntries] : particleIds ) {
399 if (nEntries != nConsideredMeasurements) continue;
400 AllSameBarcode = true;
401 break;
402 }
403
404 if (AllValids) ++trackStat[Acts::toUnderlying(EStatTracks::kNFullMatch)][0];
405 if (AllSameBarcode) ++trackStat[Acts::toUnderlying(EStatTracks::kNPerfectMatch)][0];
406 } // loop on tracks
407
408 return StatusCode::SUCCESS;
409 }
410
411} // namespace
412
#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())
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