ATLAS Offline Software
Loading...
Searching...
No Matches
HGTDTruthTrackDecorationAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration.
3*/
4
7
15
16
17// ActsTrk
27
28// STL
30
32#include "Acts/Utilities/Helpers.hpp"
33
34#include <algorithm>
35
36
37namespace ActsTrk{
38
40 {
41 ATH_MSG_DEBUG("Initializing " << name() << "...");
42
44
47 ATH_CHECK( m_layerClusterMergedKey.initialize() );
49 ATH_CHECK( m_trackContainerKey.initialize() );
50 ATH_CHECK( m_hgtdTrackLinkKey.initialize() );
51 ATH_CHECK( m_truthParticleLinkKey.initialize() );
53 ATH_CHECK(detStore()->retrieve(m_id_helper, "HGTD_ID"));
55
56 // Initialize surface accessor
59
60 return StatusCode::SUCCESS;
61 }
62
63 StatusCode HGTDTruthTrackDecorationAlg::execute(const EventContext& ctx) const
64 {
65 ATH_MSG_DEBUG("Executing " << name() << "...");
66
67 const xAOD::TrackParticleContainer* trackParticles {nullptr};
68 ATH_CHECK(SG::get(trackParticles, m_trackParticleContainerName, ctx));
69
70 ATH_MSG_DEBUG("Size of trackParticles collection " << trackParticles->size());
71 // ================================================== //
72 // ============ RETRIEVE MEASUREMENTS =============== //
73 // ================================================== //
74
75 ATH_MSG_DEBUG("Reading input collection with key " << m_uncalibratedMeasurementContainerKey_HGTD.key());
76
77 const xAOD::UncalibratedMeasurementContainer* uncalibratedMeasurementContainer{nullptr};
78 ATH_CHECK(SG::get(uncalibratedMeasurementContainer ,m_uncalibratedMeasurementContainerKey_HGTD, ctx));
79
80 ATH_MSG_DEBUG("Retrieved " << uncalibratedMeasurementContainer->size()
81 << " input elements from key " << m_uncalibratedMeasurementContainerKey_HGTD.key());
82
83
84 // ================================================== //
85 // ============ TRUTH MATCHING BLOCK ================ //
86 // ================================================== //
87
89
91
93 Acts::toUnderlying(xAOD::UncalibMeasType::nTypes)>
94 measurement_to_truth_association_maps{};
95
96 if (!m_hgtdClustersToTruth.key().empty()) {
97 const ActsTrk::MeasurementToTruthParticleAssociation* hgtdClustersToTruthAssociation{};
98 ATH_CHECK(SG::get(hgtdClustersToTruthAssociation, m_hgtdClustersToTruth, ctx));
99 measurement_to_truth_association_maps[Acts::toUnderlying(xAOD::UncalibMeasType::HGTDClusterType)]=hgtdClustersToTruthAssociation;
100 }
101 auto assocSize = [&measurement_to_truth_association_maps](xAOD::UncalibMeasType type) {
102 const ActsTrk::MeasurementToTruthParticleAssociation *assoc = measurement_to_truth_association_maps[Acts::toUnderlying(type)];
103 return assoc ? assoc->size() : 0ul;
104 };
105
106 ATH_MSG_DEBUG("Measurement association entries: " << assocSize(xAOD::UncalibMeasType::PixelClusterType)
107 << " + " << assocSize(xAOD::UncalibMeasType::StripClusterType)
108 << " + " << assocSize(xAOD::UncalibMeasType::HGTDClusterType)
109 );
110
111
113 if (!tracksContainer.isValid()) {
114 ATH_MSG_ERROR("No tracks for key " << m_trackContainerKey.key() );
115 return StatusCode::FAILURE;
116 }
117 // Create WriteDecorHandles for all decorations
122
123 // The HGTD layers in which a given truth particle left a cluster depend only on the
124 // measurements, not on the track being decorated. Evaluate it once per event instead
125 // of rescanning the whole HGTD measurement container for every TrackParticle.
126 PrimaryExpectedLookup primaryExpectedLookup;
128 *uncalibratedMeasurementContainer,
129 measurement_to_truth_association_maps[Acts::toUnderlying(xAOD::UncalibMeasType::HGTDClusterType)],
130 primaryExpectedLookup));
131
133
134 for (const xAOD::TrackParticle* trackParticle : *trackParticles) {
135
136 // get the truth particle
137 ElementLink<xAOD::TruthParticleContainer> link_to_truth = truthParticleLink(*trackParticle);
138 const xAOD::TruthParticle* truthParticle = nullptr;
139 if (!link_to_truth.isValid()) {
140 layerClusterTruthClassHandle(*trackParticle) = {-1, -1, -1, -1};
141 layerClusterShadowedHandle(*trackParticle) = {false, false, false, false};
142 layerClusterMergedHandle(*trackParticle) = {false, false, false, false};
143 layerPrimaryExpectedHandle(*trackParticle) = {false, false, false, false};
144 ATH_MSG_DEBUG("TrackParticle " << trackParticle->index() << ": invalid truth link");
145 continue;
146 }
147 else {
148 truthParticle = *link_to_truth;
149 }
150 // Check if the TrackParticle has a link to an hgtd extension track
151 if(hgtdTrackLink.isAvailable()){
152 ElementLink<ActsTrk::TrackContainer> link_to_track = hgtdTrackLink(*trackParticle);
153 if (!link_to_track.isValid()) {
154 ATH_MSG_DEBUG("TrackParticle " << trackParticle->index() << ": invalid extension link");
155 data.truthClassVec = {-1, -1, -1, -1};
156 data.isShadowedVec = {false, false, false, false};
157 data.isMergedVec = {false, false, false, false};
158 }
159 else{
160 std::optional<ActsTrk::TrackContainer::ConstTrackProxy> optional_track = *link_to_track;
161 const ActsTrk::TrackContainer::ConstTrackProxy& track = optional_track.value();
162 ATH_MSG_DEBUG("TrackParticle " << trackParticle->index() << ": extension with chi2 " << track.chi2() << " and nHits " << track.nMeasurements());
163 data = createTruthDecoration(truthParticle, track, measurement_to_truth_association_maps[Acts::toUnderlying(xAOD::UncalibMeasType::HGTDClusterType)]);
164 }
165 }
166
167
168 data.primaryExistsVec.assign(s_nHgtdLayers, false);
169 if (auto itr = primaryExpectedLookup.find(truthParticle->index());
170 itr != primaryExpectedLookup.end()) {
171 std::copy(itr->second.begin(), itr->second.end(), data.primaryExistsVec.begin());
172 }
173
174 layerClusterTruthClassHandle(*trackParticle) = data.truthClassVec;
175 layerClusterShadowedHandle(*trackParticle) = data.isShadowedVec;
176 layerClusterMergedHandle(*trackParticle) = data.isMergedVec;
177 layerPrimaryExpectedHandle(*trackParticle) = data.primaryExistsVec;
178
179 }
180 ATH_MSG_DEBUG("Finshed truth matching");
181
182 return StatusCode::SUCCESS;
183 }
184
186 const xAOD::TruthParticle* truthParticle,
187 const typename ActsTrk::TrackContainer::ConstTrackProxy trackProxy,
188 const ActsTrk::MeasurementToTruthParticleAssociation* association_map) const{
189
191
192 std::vector<int> truthClassPerLayer = {-1, -1, -1, -1};
193 std::vector<char> isShadowedPerLayer = {false, false, false, false};
194 std::vector<char> isMergedPerLayer = {false, false, false, false};
195 std::vector<char> isPrimaryExistsVec = {false, false, false, false};
196
197 for (auto state : trackProxy.trackStatesReversed()) {
198 auto flags = state.typeFlags();
199 if (flags.isMeasurement()) {
200 // Check if this is an HGTD hit
201 const auto& surface = state.referenceSurface();
202 const auto* detElem = getActsDetectorElement(surface);
203 if(detElem->detectorType() != DetectorType::Hgtd){
204 continue;
205 }
206
207 Acts::GeometryIdentifier geoID = surface.geometryId();
208 std::size_t layerIndex = m_id_helper->layer(detElem->identify());
209
210 ClusterTruthInfo cluster_truth_info;
211
212 assert( state.hasUncalibratedSourceLink() );
213 auto uncalibMeas = detail::xAODUncalibMeasCalibrator::unpack(state.getUncalibratedSourceLink());
214 if (association_map->at(uncalibMeas->index()).empty()) {
216 ATH_MSG_DEBUG(" \\__Layer "<< layerIndex << " SECONDARY: hit doesnt have truth particle associated with it");
217 }
218 else if(association_map->at(uncalibMeas->index()).size() == 1) {
219 const xAOD::TruthParticle *truth_particle = association_map->at(uncalibMeas->index()).at(0);
220 if(truthParticle->index() == truth_particle->index()){
222 ATH_MSG_DEBUG(" \\__Layer "<< layerIndex<< " TRUTH_PARTICLE: hit matches ITk track");
223 }
224 else{
226 ATH_MSG_DEBUG(" \\__Layer "<< layerIndex<< " UNRELATED_PARTICLE: hit doesnt match ITk track");
227 }
228 }
229 else {
230 cluster_truth_info.is_merged = true;
232 ATH_MSG_DEBUG(" \\__Layer "<< layerIndex<< " MERGED: hit with more than one contributing particle");
233 for (const xAOD::TruthParticle *truth_particle : association_map->at(uncalibMeas->index()) ) {
234 if(truthParticle->index() == truth_particle->index()){
236 ATH_MSG_DEBUG(" \\__TRUTH_PARTICLE: hit matches ITk track");
237 }
238 }
239 }
240
241 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - "<<uncalibMeas->type()<<", geoID: "<<geoID<<", layerIndex: "<<layerIndex);
242 if (layerIndex >= truthClassPerLayer.size()) {
243 ATH_MSG_WARNING(__func__<<"() "<<__LINE__<<" - "<<uncalibMeas->type()<<", geoID: "<<geoID<<" results in an invalid index "<<layerIndex);
244 continue;
245 }
246 truthClassPerLayer.at(layerIndex) = Acts::toUnderlying(cluster_truth_info.origin);
247 isShadowedPerLayer.at(layerIndex) = cluster_truth_info.is_shadowed;
248 isMergedPerLayer.at(layerIndex) = cluster_truth_info.is_merged;
249 }
250 }
251
252 // Fill the data structure with results
253 data.truthClassVec = std::move(truthClassPerLayer);
254 data.isShadowedVec = std::move(isShadowedPerLayer);
255 data.isMergedVec = std::move(isMergedPerLayer);
256 data.primaryExistsVec = std::move(isPrimaryExistsVec);
257 return data;
258 }
259
261 const xAOD::UncalibratedMeasurementContainer & measurementContainer,
263 PrimaryExpectedLookup& lookup) const {
264
265 if (association_map == nullptr) {
266 return StatusCode::SUCCESS;
267 }
268
269 for (const xAOD::UncalibratedMeasurement* uncalibMeas : measurementContainer) {
270
271 const Acts::Surface* surface = m_surfAcc.get(uncalibMeas);
272 const auto* detElem = getActsDetectorElement(surface);
273 if (detElem == nullptr || detElem->detectorType() != DetectorType::Hgtd) {
274 continue;
275 }
276
277 const std::size_t layerIndex = m_id_helper->layer(detElem->identify());
278
279 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - "<<uncalibMeas->type()
280 <<", geoID: "<<surface->geometryId()<<", layerIndex: "<<layerIndex);
281 if (layerIndex >= s_nHgtdLayers) {
282 ATH_MSG_WARNING(__func__<<"() "<<__LINE__<<" - "<<uncalibMeas->type()
283 <<", geoID: "<<surface->geometryId()<<" results in an invalid index "<<layerIndex);
284 continue;
285 }
286
287 for (const xAOD::TruthParticle* measTruthParticle : association_map->at(uncalibMeas->index())) {
288 lookup.try_emplace(measTruthParticle->index(), HgtdLayerFlags{})
289 .first->second[layerIndex] = true;
290 }
291 }
292
293 return StatusCode::SUCCESS;
294 }
295
296}
const ActsDetectorElement * getActsDetectorElement(const Acts::Surface &surf)
Attempts to retrieve the ActsDetectorElement associated to the passed ActsSurface.
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
Handle class for reading a decoration on an object.
Handle class for adding a decoration to an object.
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_trackParticleContainerName
ServiceHandle< ActsTrk::ITrackingGeometrySvc > m_trackingGeometrySvc
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_layerClusterShadowedKey
const HGTD_ID * m_id_helper
Handle to the ID helper.
SG::ReadHandleKey< MeasurementToTruthParticleAssociation > m_hgtdClustersToTruth
SG::ReadHandleKey< xAOD::UncalibratedMeasurementContainer > m_uncalibratedMeasurementContainerKey_HGTD
StatusCode buildPrimaryExpectedLookup(const xAOD::UncalibratedMeasurementContainer &measurementContainer, const ActsTrk::MeasurementToTruthParticleAssociation *association_map, PrimaryExpectedLookup &lookup) const
Builds, once per event, the map from truth particle index onto the set of HGTD layers in which that p...
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_layerClusterMergedKey
std::array< char, s_nHgtdLayers > HgtdLayerFlags
Per-layer flags for a single truth particle.
virtual StatusCode execute(const EventContext &) const override
static constexpr std::size_t s_nHgtdLayers
Number of HGTD layers the per-track decorations are indexed by.
std::unordered_map< std::size_t, HgtdLayerFlags > PrimaryExpectedLookup
Maps the index of a truth particle onto the HGTD layers it deposited a hit in.
SG::ReadHandleKey< ActsTrk::TrackContainer > m_trackContainerKey
SG::ReadDecorHandleKey< xAOD::TrackParticleContainer > m_truthParticleLinkKey
ActsTrk::detail::xAODUncalibMeasSurfAcc m_surfAcc
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_layerPrimaryExpectedKey
TruthTrackExtensionData createTruthDecoration(const xAOD::TruthParticle *truthParticle, const typename ActsTrk::TrackContainer::ConstTrackProxy trackProxy, const ActsTrk::MeasurementToTruthParticleAssociation *association_map) const
Generate TruthTrackExtensionData from extension.
SG::ReadDecorHandleKey< xAOD::TrackParticleContainer > m_hgtdTrackLinkKey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_layerClusterTruthClassKey
static const xAOD::UncalibratedMeasurement * unpack(const Acts::SourceLink &sl)
Helper method to unpack an Acts source link to an uncalibrated measurement.
Helper class to access the Acts::surface associated with an Uncalibrated xAOD measurement.
const ServiceHandle< StoreGateSvc > & detStore() const
size_type size() const noexcept
Returns the number of elements in the collection.
Handle class for reading a decoration on an object.
bool isAvailable()
Test to see if this variable exists in the store, for the referenced object.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
Handle class for adding a decoration to an object.
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
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.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
TruthParticle_v1 TruthParticle
Typedef to implementation.
UncalibMeasType
Define the type of the uncalibrated measurement.
TrackParticleContainer_v1 TrackParticleContainer
Definition of the current "TrackParticle container version".
UncalibratedMeasurementContainer_v1 UncalibratedMeasurementContainer
Define the version of the uncalibrated measurement container.
bool is_merged
A cluster is considered to be merged if more than one particle deposited energy in a given pad.
bool is_shadowed
Shadowing means that a deposit was left by the truth particle, but it was not the first deposit and i...
Data structure to hold truth information about the HGTD track extension.