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