ATLAS Offline Software
Loading...
Searching...
No Matches
TrackTimeDefAndQualityAlg.cxx
Go to the documentation of this file.
1
10
12
16
19#include "Acts/Utilities/TrackHelpers.hpp"
20
23
24namespace HGTD {
25
27 ISvcLocator* pSvcLocator)
28 : AthReentrantAlgorithm(name, pSvcLocator) {}
29
31
34 ATH_CHECK(m_layerClusterTimeKey.initialize());
36 ATH_CHECK(m_time_dec_key.initialize());
37 ATH_CHECK(m_time_res_dec_key.initialize());
40
41 return StatusCode::SUCCESS;
42}
43
46
47StatusCode TrackTimeDefAndQualityAlg::execute(const EventContext& ctx) const {
48
49 SG::ReadHandle<xAOD::TrackParticleContainer> trk_ptkl_container_handle(
51 ATH_CHECK( trk_ptkl_container_handle.isValid() );
52 const xAOD::TrackParticleContainer* track_particles =
53 trk_ptkl_container_handle.cptr();
54 if (not track_particles) {
56 "[TrackTimeDefAndQualityAlg] TrackParticleContainer not found, "
57 "aborting execute!");
58 return StatusCode::FAILURE;
59 }
60
62 m_time_dec_key, ctx);
69
71 layerClusterTimeHandle(m_layerClusterTimeKey, ctx);
72 ATH_CHECK(layerClusterTimeHandle.isValid());
73
75 layerHasExtensionHandle(m_layerHasExtensionKey, ctx);
76 ATH_CHECK(layerHasExtensionHandle.isValid());
77
79 layerClusterTruthClassHandle(m_layerClusterTruthClassKey, ctx);
80 ATH_CHECK(layerClusterTruthClassHandle.isValid());
81
82
83 for (const auto* track_ptkl : *track_particles) {
84 // runs the time consistency checks
85 // if no hits are found in HGTD, returns a default time
86 const std::vector<float>& times = layerClusterTimeHandle(*track_ptkl);
87 const std::vector<bool>& has_clusters = layerHasExtensionHandle(*track_ptkl);
88 const std::vector<int>& hit_classification = layerClusterTruthClassHandle(*track_ptkl);
89
91 has_clusters,
92 hit_classification);
93
94 // check if the last hit on track was within the predefined area
95 if (lastHitIsOnLastSurface(*track_ptkl)) {
96 res.m_field |= (0b0000 << m_holes_ptrn_sft);
97 } else {
98 res.m_field |= (0b0001 << m_holes_ptrn_sft);
99 }
100
101 // keep which of the hits associated in reco were primary hits (truth info!)
102 short prime_pattern = 0x0;
103 for (short i = 0; i < s_hgtd_layers; i++) {
104 if (res.m_hits.at(i).m_isprime) {
105 prime_pattern |= (1 << i);
106 }
107 }
108 res.m_field |= (prime_pattern << m_primes_ptrn_sft);
109
110 // decorate the track again with this info
111 time_handle(*track_ptkl) = res.m_time;
112 timeres_handle(*track_ptkl) = res.m_resolution;
113 hasValidTime_handle(*track_ptkl) = res.m_hasValidTime;
114 summary_handle(*track_ptkl) = res.m_field;
115 }
116 return StatusCode::SUCCESS;
117}
118
121
124 const std::vector<bool>& has_clusters,
125 const std::vector<int>& hit_classification) const {
126 // get all available hits (see the struct Hit) in a first step
127 std::array<Hit, s_hgtd_layers> valid_hits = getValidHits(times,
128 has_clusters,
129 hit_classification);
130
132 result.m_hits = valid_hits;
133 result.m_field = 0x0;
134 result.m_time = m_default_time;
135 result.m_resolution = m_default_time_res;
136 result.m_hasValidTime = 0;
137
138 short recoed_pattern = getValidPattern(valid_hits);
139 // stored the pattern of hits as retrieved from the iterative extension
140 result.m_field |= (recoed_pattern << m_recoed_ptrn_sft);
141
142 short nhits = std::count_if(valid_hits.begin(), valid_hits.end(),
143 [](const Hit& hit) { return hit.m_isvalid; });
144 if (nhits < 2) {
145 // fill the patern with the 1 hit (or none) and return
146 result.m_field |= (recoed_pattern << m_comp_ptrn_sft);
147 result.m_time = meanTime(valid_hits);
148 result.m_resolution = trackTimeResolution(valid_hits);
149 result.m_hasValidTime = recoed_pattern ? 1 : 0;
150 return result;
151 } else if (nhits == 2) {
152 // if the deltaT cut is passed, the pattern stays the same, otherwise set
153 // to 0 as no hit passes
154 // TODO: find better way to treat this!
155 if (passesDeltaT(valid_hits)) {
156 result.m_field |= (recoed_pattern << m_comp_ptrn_sft); // stays the same
157 result.m_time = meanTime(valid_hits);
158 result.m_resolution = trackTimeResolution(valid_hits);
159 result.m_hasValidTime = 1;
160 return result;
161 } else {
162 result.m_field |= (0b0000 << m_comp_ptrn_sft); // no hit passes
163 result.m_time = m_default_time; // TODO should I just use the mean?
164 result.m_resolution = m_default_time_res;
165 return result;
166 }
167
168 } else {
169 // for 3 or 4 hits, remove hit(s) with worst chi2 if needed
170 float chi2 = calculateChi2(valid_hits);
171 // if the chi2 is below the threshold, keep all hits
172 bool searching = chi2 > m_chi2_threshold;
173 while (searching) {
174 short remove_layer = findLayerWithBadChi2(valid_hits);
175 setLayerAsInvalid(valid_hits, remove_layer);
176 float new_chi2 = calculateChi2(valid_hits);
177 nhits = std::count_if(valid_hits.begin(), valid_hits.end(),
178 [](const Hit& hit) { return hit.m_isvalid; });
179 if (new_chi2 <= m_chi2_threshold or nhits < 3) {
180 searching = false;
181 }
182 } // while loop ended
183
184 short chi2_rej_pattern = getValidPattern(valid_hits);
185
186 if (nhits == 2) {
187 if (passesDeltaT(valid_hits)) {
188 result.m_field |= (chi2_rej_pattern << m_comp_ptrn_sft);
189 result.m_time = meanTime(valid_hits);
190 result.m_resolution = trackTimeResolution(valid_hits);
191 result.m_hasValidTime = 1;
192 return result;
193 } else {
194 result.m_field |= (0b0000 << m_comp_ptrn_sft); // no hit passes
195 result.m_time = m_default_time; // TODO should I just use the mean?
196 result.m_resolution = m_default_time_res;
197 return result;
198 }
199 } else {
200 // 3 or 4 hits, chi2 passed
201 result.m_field |= (chi2_rej_pattern << m_comp_ptrn_sft);
202 result.m_time = meanTime(valid_hits);
203 result.m_resolution = trackTimeResolution(valid_hits);
204 result.m_hasValidTime = 1;
205 return result;
206 }
207 }
208}
209
210std::array<TrackTimeDefAndQualityAlg::Hit, s_hgtd_layers>
211TrackTimeDefAndQualityAlg::getValidHits(const std::vector<float>& times,
212 const std::vector<bool>& has_clusters,
213 const std::vector<int>& hit_classification) const {
214 std::array<Hit, s_hgtd_layers> valid_hits {};
215
216 for (size_t i = 0; i < s_hgtd_layers; i++) {
217 Hit& newhit = valid_hits[i];
218 if (has_clusters.at(i)) {
219 newhit.m_time = times.at(i);
220 newhit.m_isprime = hit_classification.at(i) == 1;
221 newhit.m_isvalid = true;
222 }
223 newhit.m_layer = i;
224 }
225
226 return valid_hits;
227}
228
230 const std::array<TrackTimeDefAndQualityAlg::Hit, s_hgtd_layers>& hits)
231 const {
232 short pattern = 0x0;
233 for (short i = 0; i < s_hgtd_layers; i++) {
234 if (hits.at(i).m_isvalid) {
235 pattern |= (1 << i);
236 }
237 }
238 return pattern;
239}
240
242 const std::array<Hit, s_hgtd_layers>& hits) const {
243
244 float mean = meanTime(hits);
245
246 float chi2 = 0.;
247 for (const auto& hit : hits) {
248 if (hit.m_isvalid) {
249 chi2 += (hit.m_time - mean) * (hit.m_time - mean) /
250 (hit.m_resolution * hit.m_resolution);
251 }
252 }
253 return chi2;
254}
255
257 const std::array<TrackTimeDefAndQualityAlg::Hit, s_hgtd_layers>& hits)
258 const {
259 // don't trust the user here.
260 short n_valid = std::count_if(hits.begin(), hits.end(),
261 [](const Hit& hit) { return hit.m_isvalid; });
262 if (n_valid != 2) {
263 return false;
264 }
265 // FIXME this should be doable in a simpler manner...
266 std::vector<float> times;
267 std::vector<float> res;
268 for (const auto& hit : hits) {
269 if (hit.m_isvalid) {
270 times.push_back(hit.m_time);
271 res.push_back(hit.m_resolution);
272 }
273 }
274 // pass if the distance in units of the resolution passes the cut
275 return std::abs(times.at(0) - times.at(1)) <
276 m_deltat_cut * hypot(res.at(0), res.at(1));
277}
278
280 const std::array<TrackTimeDefAndQualityAlg::Hit, s_hgtd_layers>& hits)
281 const {
282 float sum = 0.;
283 short n = 0;
284 for (const auto& hit : hits) {
285 if (hit.m_isvalid) {
286 sum += hit.m_time;
287 n++;
288 }
289 }
290 return n == 0 ? m_default_time.value() : sum / (float)n;
291}
292
294 const std::array<TrackTimeDefAndQualityAlg::Hit, s_hgtd_layers>& hits)
295 const {
296
297 float sum = 0.;
298 for (const auto& hit : hits) {
299 if (hit.m_isvalid) {
300 sum += 1. / (hit.m_resolution * hit.m_resolution);
301 }
302 }
303 return sum == 0. ? m_default_time_res.value()
304 : static_cast<float>(std::sqrt(1. / sum));
305}
306
308 std::array<TrackTimeDefAndQualityAlg::Hit, s_hgtd_layers> hits) const {
309 short remove_layer = -1;
310 float local_min_chi2 = 999999;
311 for (auto& hit : hits) {
312 // "turn off" hits one after the other to test their impact on the chi2
313 bool validbuff = hit.m_isvalid;
314 hit.m_isvalid = false;
315 float local_chi2 = calculateChi2(hits);
316 hit.m_isvalid = validbuff;
317 if (local_chi2 < local_min_chi2) {
318 local_min_chi2 = local_chi2;
319 remove_layer = hit.m_layer;
320 }
321 }
322 return remove_layer;
323}
324
326 std::array<TrackTimeDefAndQualityAlg::Hit, s_hgtd_layers>& hits,
327 short layer) const {
328 for (auto& hit : hits) {
329 if (hit.m_layer == layer) {
330 hit.m_isvalid = false;
331 }
332 }
333}
334
337
338 const Trk::TrackStates* tsos =
339 track.trackStateOnSurfaces();
340 if (not tsos) {
341 ATH_MSG_ERROR("Failed to retrieve track state on surfaces");
342 return nullptr;
343 }
344 // loop over the associated hits in ITk in reverse order, since we want to
345 // select the one closest to HGTD to start the extrapolation
346 for (auto i = tsos->rbegin(); i != tsos->rend(); ++i) {
347 const auto* curr_last_tsos = *i;
348 if (not curr_last_tsos) {
349 continue;
350 }
351
352 if (curr_last_tsos->type(Trk::TrackStateOnSurface::Measurement) and
353 curr_last_tsos->trackParameters() and
354 curr_last_tsos->measurementOnTrack()) {
355 return curr_last_tsos->trackParameters();
356 }
357 }
358
359 return nullptr;
360}
361
362std::pair<float, float> TrackTimeDefAndQualityAlg::getRadiusAndZ(const xAOD::TrackParticle& track_particle) const
363{
364 float radius = 0.f;
365 float abs_z = 0.f;
366
367 if (not m_doActs) {
368 const Trk::Track* track = track_particle.track();
369 if (not track) throw std::runtime_error("Cannot retrieve Trk track from Track Particle");
370 const Trk::TrackParameters* last_hit_param = getLastHitOnTrack(*track);
371 if (not last_hit_param) throw std::runtime_error("Cannot retrieve Trk track parameters from Trk track");
372
373 radius = std::hypot(last_hit_param->position().x(),
374 last_hit_param->position().y());
375 abs_z = std::abs(last_hit_param->position().z());
376 } else {
377 // ACTS
378 static const SG::ConstAccessor< ElementLink<ActsTrk::TrackContainer> > actsTrackLink("actsTrack");
379 if (not actsTrackLink.isAvailable(track_particle)) throw std::runtime_error("Track particle does not have link to acts track");
380
381 ElementLink<ActsTrk::TrackContainer> link_to_track = actsTrackLink(track_particle);
382 if (not link_to_track.isValid()) throw std::runtime_error("Element link to acts track is not valid");
383
384 std::optional<ActsTrk::TrackContainer::ConstTrackProxy> optional_track = *link_to_track;
385 if (not optional_track.has_value()) throw std::runtime_error("Link to acts track has no value");
386
387 const ActsTrk::TrackContainer::ConstTrackProxy& track = optional_track.value();
388 const auto lastMeasurementState = Acts::findLastMeasurementState(track);
389 const auto state = lastMeasurementState.value();
390
391 auto sl = state.getUncalibratedSourceLink().template get<ActsTrk::ATLASUncalibSourceLink>();
392 assert( sl != nullptr);
394 xAOD::UncalibMeasType clusterType = cluster.type();
395
396 switch (clusterType) {
398 {
399 auto glob = static_cast<const xAOD::PixelCluster*>(&cluster)->globalPosition();
400 radius = std::sqrt( glob(0, 0) * glob(0, 0) + glob(1, 0) * glob(1, 0) );
401 abs_z = std::abs( glob(2, 0) );
402 }
403 break;
405 {
406 auto glob = static_cast<const xAOD::StripCluster*>(&cluster)->globalPosition();
407 radius = std::sqrt( glob(0, 0) * glob(0, 0) + glob(1, 0) * glob(1, 0) );
408 abs_z = std::abs( glob(2, 0) );
409 }
410 break;
412 // return some default numbers
413 return std::make_pair(700, 3000);
414 default:
415 return std::make_pair(radius, abs_z);
416 }; // switch
417 } // acts
418
419 return std::make_pair(radius, abs_z);
420}
421
423 const xAOD::TrackParticle& track_particle) const {
424 auto [radius, abs_z] = getRadiusAndZ(track_particle);
425
426 if (abs_z > 2700) {
427 return true;
428 }
429 if (radius < 350 and abs_z > 2400) {
430 return true;
431 }
432 // region 2
433 if (radius > 205 and radius < 350 and abs_z > 2100) {
434 return true;
435 }
436 // region 3
437 if (radius < 220 and abs_z > 2200) {
438 return true;
439 }
440
441 if (radius < 140 and abs_z > 1890) {
442 return true;
443 }
444
445 return false;
446}
447
448} // namespace HGTD
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
std::pair< std::vector< unsigned int >, bool > res
Handle class for reading a decoration on an object.
Handle class for reading from StoreGate.
Handle class for adding a decoration to an object.
An algorithm that can be simultaneously executed in multiple threads.
const_reverse_iterator rend() const noexcept
Return a const_reverse_iterator pointing at the beginning of the collection.
const_reverse_iterator rbegin() const noexcept
Return a const_reverse_iterator pointing past the end of the collection.
float calculateChi2(const std::array< Hit, s_hgtd_layers > &hits) const
Calculates the chi2 of the hit times given their resolution.
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_time_dec_key
SG::ReadDecorHandleKey< xAOD::TrackParticleContainer > m_layerClusterTruthClassKey
std::array< Hit, s_hgtd_layers > getValidHits(const std::vector< float > &times, const std::vector< bool > &has_clusters, const std::vector< int > &hit_classification) const
CleaningResult runTimeConsistencyCuts(const std::vector< float > &times, const std::vector< bool > &has_clusters, const std::vector< int > &hit_classification) const
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_time_res_dec_key
std::pair< float, float > getRadiusAndZ(const xAOD::TrackParticle &track_particle) const
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_trackParticleContainerKey
float meanTime(const std::array< Hit, s_hgtd_layers > &hits) const
Calculates the arithmetic mean of the valid hit times;.
void setLayerAsInvalid(std::array< Hit, s_hgtd_layers > &hits, short layer) const
Given a layer number, the hit sitting on this layer is flagged as invalid.
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_hasValidTime_dec_key
float trackTimeResolution(const std::array< Hit, s_hgtd_layers > &hits) const
Calculates the combined resolution.
short findLayerWithBadChi2(std::array< Hit, s_hgtd_layers > hits) const
Identifies time outliers by finding the layer within which a hit contributes negatively to the overal...
SG::ReadDecorHandleKey< xAOD::TrackParticleContainer > m_layerClusterTimeKey
bool lastHitIsOnLastSurface(const xAOD::TrackParticle &track_particle) const
Checks if the last hit on track was found on a pre-specified set of Pixel and Strip layers close to t...
bool passesDeltaT(const std::array< Hit, s_hgtd_layers > &hits) const
Checks two hits for time compatibility.
virtual StatusCode execute(const EventContext &ctx) const override final
short getValidPattern(const std::array< Hit, s_hgtd_layers > &hits) const
Returns the pattern of valid hits in HGTD as a 4-bit bitfield, where a 1 encodes that a valid hit was...
TrackTimeDefAndQualityAlg(const std::string &name, ISvcLocator *pSvcLocator)
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_summarypattern_dec_key
SG::ReadDecorHandleKey< xAOD::TrackParticleContainer > m_layerHasExtensionKey
const Trk::TrackParameters * getLastHitOnTrack(const Trk::Track &track) const
virtual StatusCode initialize() override final
Helper class to provide constant type-safe access to aux data.
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
Handle class for reading a decoration on an object.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type cptr()
Dereference the pointer.
Handle class for adding a decoration to an object.
const Amg::Vector3D & position() const
Access method for the position.
@ Measurement
This is a measurement, and will at least contain a Trk::MeasurementBase.
const Trk::Track * track() const
Returns a pointer (which can be NULL) to the Trk::Track which was used to make this TrackParticle.
virtual xAOD::UncalibMeasType type() const =0
Returns the type of the measurement type as a simple enumeration.
double chi2(TH1 *h0, TH1 *h1)
void mean(std::vector< double > &bins, std::vector< double > &values, const std::vector< std::string > &files, const std::string &histname, const std::string &tplotname, const std::string &label="")
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:130
const xAOD::UncalibratedMeasurement & getUncalibratedMeasurement(const ATLASUncalibSourceLink &source_link)
Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration.
DataVector< const Trk::TrackStateOnSurface > TrackStates
ParametersBase< TrackParametersDim, Charged > TrackParameters
StripCluster_v1 StripCluster
Define the version of the strip cluster class.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
PixelCluster_v1 PixelCluster
Define the version of the pixel cluster class.
UncalibMeasType
Define the type of the uncalibrated measurement.
TrackParticleContainer_v1 TrackParticleContainer
Definition of the current "TrackParticle container version".
UncalibratedMeasurement_v1 UncalibratedMeasurement
Define the version of the uncalibrated measurement class.