ATLAS Offline Software
Loading...
Searching...
No Matches
HGTD_IterativeExtensionTool.cxx
Go to the documentation of this file.
1
10
12
25
26#include <iostream>
27#include <vector>
28
30 const std::string& n,
31 const IInterface* p)
32 : base_class(t, n, p) {}
33
35 StatusCode sc = AthAlgTool::initialize();
36
37 ATH_CHECK(m_extrapolator.retrieve());
38
39 ATH_CHECK(m_updator.retrieve());
40
41 ATH_CHECK(m_tof_corr_tool.retrieve());
42
43 ATH_CHECK(m_truth_tool.retrieve());
44
45 // get HGTD Detector Description Manager and HGTD Helper
46 ATH_CHECK(detStore()->retrieve(m_hgtd_det_mgr, "HGTD"));
47 ATH_CHECK(detStore()->retrieve(m_hgtd_id_helper, "HGTD_ID"));
48
49 return sc;
50}
51
53 const EventContext& ctx, const xAOD::TrackParticle& track_ptkl,
54 const HGTD_ClusterContainer* container, const HepMC::GenEvent* hs_event,
55 const InDetSimDataCollection* sim_data) const {
56
57 ATH_MSG_DEBUG("Start extending");
58
59 const Trk::Track* track = track_ptkl.track();
60
62
63 // get last hit on track in ITk as a starting point for the extrapolation
64 const Trk::TrackStateOnSurface* last_hit = getLastHitOnTrack(*track);
65 const Trk::TrackParameters* last_param = last_hit->trackParameters();
66
67 ATH_MSG_DEBUG("last param x: " << last_param->position().x()
68 << ", y: " << last_param->position().y()
69 << ", z: " << last_param->position().z());
70 ATH_MSG_DEBUG("last param px: " << last_param->momentum().x()
71 << ", py: " << last_param->momentum().y()
72 << ", pz: " << last_param->momentum().z());
73
74 const xAOD::TruthParticle* truth_ptkl =
76
77 // get the tracking geometry
78 const Trk::TrackingGeometry* trk_geom = m_extrapolator->trackingGeometry();
79 if (not trk_geom) {
80 ATH_MSG_DEBUG("trackingGeometry returns null");
81 return result;
82 }
83
84 bool is_pos_endcap = last_param->eta() > 0;
85
86 // get the target volume
87 const Trk::TrackingVolume* hgtd_trk_volume = trk_geom->trackingVolume(
88 is_pos_endcap ? "HGTD::PositiveEndcap" : "HGTD::NegativeEndcap");
89
90 if (not hgtd_trk_volume) {
91 ATH_MSG_DEBUG("trackingVolume returns null");
92 return result;
93 }
94
95 const Trk::BinnedArray<Trk::Layer>* confined_layers =
96 hgtd_trk_volume->confinedLayers();
97 // careful, this array is not ordered from inside out (only in pos endcap)
98 if (not confined_layers) {
99 ATH_MSG_DEBUG("confinedLayers returns null");
100 return result;
101 }
102
103 // get the layers, traverse depending on endcap used
104 // since they are not in ascending z order!!
105 std::span<Trk::Layer const * const> layers = confined_layers->arrayObjects();
106 size_t layer_size = layers.size();
107
108 short position = is_pos_endcap ? 0 : layer_size - 1;
109 short step = is_pos_endcap ? 1 : -1;
110 short hgtd_layer_i = -1; // start at -1 since the ++ happens at the beginning
111 for (size_t i = 0; i < layer_size - 1; i++, position = position + step) {
112
113 const Trk::Layer* layer = layers[position];
114 // only use it, if it is an active one
115 if (layer->layerType() != 1) {
116 continue;
117 }
118 hgtd_layer_i++;
119
120 const Trk::Surface& surf_obj = layer->surfaceRepresentation();
121 ATH_MSG_DEBUG("extrapolation surface z: " << surf_obj.center().z());
122
123 // if it is a good surface, extrapolate to this surface
124 // uses same particle hypothesis used for the track itself
125 // TODO: BoundaryCheck set to false as in 20.20 -> what does this do?
126 std::unique_ptr<const Trk::TrackParameters> extrap_result = nullptr;
127
128 Trk::ParticleHypothesis part = track->info().particleHypothesis();
129 if (part == Trk::undefined) {
130 part = static_cast<Trk::ParticleHypothesis>(m_particle_hypot.value());
131 }
132 extrap_result = m_extrapolator->extrapolate(
133 ctx, *last_param, surf_obj, Trk::PropDirection::alongMomentum, false,
134 part);
135
136 //
137 if (not extrap_result) {
138 ATH_MSG_WARNING("Extrapolator returned null");
139 result.m_hits.at(hgtd_layer_i) = nullptr;
140 result.m_truth_primary_hits.at(hgtd_layer_i) = nullptr;
141 result.m_truth_primary_info.at(hgtd_layer_i) = HGTD::ClusterTruthInfo();
142 continue;
143 }
144
145 // get the extrapolation position info only on the first layer
146 if (hgtd_layer_i == 0) {
147 result.m_extrap_x = extrap_result->position().x();
148 result.m_extrap_y = extrap_result->position().y();
149 }
150
151 ATH_MSG_DEBUG("extrap. params x: "
152 << extrap_result->position().x()
153 << ", y: " << extrap_result->position().y()
154 << ", z: " << extrap_result->position().z());
155 ATH_MSG_DEBUG("extrap. params px: "
156 << extrap_result->momentum().x()
157 << ", py: " << extrap_result->momentum().y()
158 << ", pz: " << extrap_result->momentum().z());
159
160 // find active surfaces in the vincinity
161 auto compatible_surfaces = getCompatibleSurfaces(*extrap_result, layer);
162
163 if (compatible_surfaces.empty()) {
164 ATH_MSG_WARNING("No compatible surfaces for position");
165 result.m_hits.at(hgtd_layer_i) = nullptr;
166 result.m_truth_primary_hits.at(hgtd_layer_i) = nullptr;
167 result.m_truth_primary_info.at(hgtd_layer_i) = HGTD::ClusterTruthInfo();
168 continue;
169 }
170
171 auto extrapolated_params =
172 extrapolateToSurfaces(ctx, *last_param, compatible_surfaces);
173
174 std::unique_ptr<const Trk::TrackStateOnSurface> updated_state =
175 updateStateWithBestFittingCluster(track, extrapolated_params,
176 container);
177
178 if (not updated_state) {
179 result.m_hits.at(hgtd_layer_i) = nullptr;
180 result.m_truth_primary_hits.at(hgtd_layer_i) = nullptr;
181 result.m_truth_primary_info.at(hgtd_layer_i) = HGTD::ClusterTruthInfo();
182 continue;
183 }
184 // if the state was updated with a measurement, the it becomes the new last
185 // parameter
186 last_param = updated_state->trackParameters();
187 // store the last track state to be returned
188
189 std::pair<const HGTD_Cluster*, HGTD::ClusterTruthInfo> truth_info =
190 getTruthMatchedCluster(compatible_surfaces, container, truth_ptkl,
191 hs_event, sim_data);
192
193 result.m_hits.at(hgtd_layer_i) = std::move(updated_state);
194 result.m_truth_primary_hits.at(hgtd_layer_i) = truth_info.first;
195 result.m_truth_primary_info.at(hgtd_layer_i) = truth_info.second;
196 }
197
198 return result;
199}
200
203
204 const Trk::TrackStates* tsos =
205 track.trackStateOnSurfaces();
206 if (not tsos) {
207 ATH_MSG_ERROR("Failed to retrieve track state on surfaces");
208 return nullptr;
209 }
210 // loop over the associated hits in ITk in reverse order, since we want to
211 // select the one closest to HGTD to start the extrapolation
212 for (auto i = tsos->rbegin(); i != tsos->rend(); ++i) {
213 const auto* curr_last_tsos = *i;
214 if (not curr_last_tsos) {
215 continue;
216 }
217 if (curr_last_tsos->type(Trk::TrackStateOnSurface::Measurement) and
218 curr_last_tsos->trackParameters() and
219 curr_last_tsos->measurementOnTrack()) {
220 return curr_last_tsos;
221 }
222 }
223 return nullptr;
224}
225
226std::vector<const Trk::Surface*>
228 const Trk::TrackParameters& param, const Trk::Layer* layer) {
229
230 std::vector<const Trk::Surface*> surfaces;
231
232 // point of extrapolation as global position
233 const Amg::Vector3D& position = param.position();
234 // get the surface at the point of extrapolation
235 const auto* surface_arr = layer->surfaceArray(); // these are the modules
236 if (!surface_arr) {
237 return surfaces;
238 }
239 const Trk::Surface* module_surface = surface_arr->object(
240 position); // from this binned object, get the module closeby
241 if (!module_surface) {
242 return surfaces;
243 }
244 surfaces.push_back(module_surface);
245
246 // pick up additional surfaces in a 4cm radius
247 // TODO REPLACE THIS BY NEIGHBOUR FUNCTIONALITY IN FUTURE!!
248 short steps = 16;
249 float delta_angle = 6.2831853 / (float)steps;
250 float angle = 0.;
251 float radius = 20.0;
252 for (short i = 0; i < steps; i++, angle = angle + delta_angle) {
253 Amg::Vector3D delta(radius * std::cos(angle), radius * std::sin(angle), 0);
254 Amg::Vector3D result = position + delta;
255 const Trk::Surface* additional_surface = surface_arr->object(result);
256 if (!additional_surface) {
257 continue;
258 }
259 // check if surface was added to avoid duplicates
260 if (std::find(surfaces.begin(), surfaces.end(), additional_surface) ==
261 surfaces.end()) {
262 surfaces.push_back(additional_surface);
263 }
264 }
265
266 return surfaces;
267}
268
269std::vector<std::unique_ptr<const Trk::TrackParameters>>
271 const EventContext& ctx, const Trk::TrackParameters& param,
272 const std::vector<const Trk::Surface*>& surfaces) const {
273
274 std::vector<std::unique_ptr<const Trk::TrackParameters>> params;
275 params.reserve(surfaces.size());
276
277 for (const auto* surface : surfaces) {
278 std::unique_ptr<const Trk::TrackParameters> extrapolated_params = nullptr;
279
280 extrapolated_params = m_extrapolator->extrapolate(
281 ctx, param, *surface, Trk::alongMomentum, false,
282 static_cast<Trk::ParticleHypothesis>(m_particle_hypot.value()));
283 if (not extrapolated_params) {
284 continue;
285 }
286 params.push_back(std::move(extrapolated_params));
287 }
288
289 return params;
290}
291
292std::unique_ptr<const Trk::TrackStateOnSurface>
294 const Trk::Track* track,
295 const std::vector<std::unique_ptr<const Trk::TrackParameters>>& params,
296 const HGTD_ClusterContainer* container) const {
297 ATH_MSG_DEBUG("[updateStateWithBestFittingCluster] start updating");
298
299 std::unique_ptr<const Trk::TrackStateOnSurface> updated_state = nullptr;
300
301 double lowest_chi2 = -1.;
302 // all compatible surfaces are tested for the best fitting cluster
303 for (const auto& param : params) {
304 std::unique_ptr<const Trk::TrackStateOnSurface> best_tsos =
305 findBestCompatibleCluster(track, param.get(), container);
306 if (not best_tsos) {
307 ATH_MSG_DEBUG("[updateStateWithBestFittingCluster] tsos is null");
308 continue;
309 }
310 ATH_MSG_DEBUG("[updateStateWithBestFittingCluster] tsos found");
311
312 double chi2 = best_tsos->fitQualityOnSurface().chiSquared() /
313 best_tsos->fitQualityOnSurface().doubleNumberDoF();
315 "[updateStateWithBestFittingCluster] found state with chi2 of "
316 << chi2);
317 // make sure only one TSOS is kept
318 if (!updated_state or chi2 < lowest_chi2) {
319 updated_state.swap(best_tsos);
320 lowest_chi2 = chi2;
321 }
322 }
323
324 return updated_state; // no need to std::move thanks to Return Value
325 // Optimization (RVO)
326}
327
328std::unique_ptr<const Trk::TrackStateOnSurface>
330 const Trk::Track* track, const Trk::TrackParameters* param,
331 const HGTD_ClusterContainer* container) const {
332
333 ATH_MSG_DEBUG("[findBestCompatibleCluster] start");
334
335 std::unique_ptr<const Trk::TrackStateOnSurface> tsos = nullptr;
336
337 double lowest_chi2 = -1;
338 for (const auto* collection : *container) {
339 // find the one collection that can be associated to the surface
340 if (collection->identify() !=
342 continue;
343 }
345 "[findBestCompatibleCluster] found collection of given surface");
346 // test the clusters on this surface for compatibility, keep the best
347 for (const auto* cluster : *collection) {
348 // update the track parameters with the found cluster
349 std::unique_ptr<const Trk::TrackStateOnSurface> candidate =
350 updateState(track, param, cluster);
351
352 if (not candidate) {
353 continue;
354 }
355 if (not candidate->measurementOnTrack() and
356 not candidate->fitQualityOnSurface()) {
357 continue;
358 }
359 double chi2 = candidate->fitQualityOnSurface().chiSquared() /
360 candidate->fitQualityOnSurface().doubleNumberDoF();
361 ATH_MSG_DEBUG("found cluster with chi2 of " << chi2);
362 // apply cut on the chi2
363 if (chi2 > m_chi2_cut) {
364 continue;
365 }
366 // make sure only one TSOS is kept
367 if (not tsos or chi2 < lowest_chi2) {
368 tsos.swap(candidate);
369 lowest_chi2 = chi2;
370 }
371 }
372 // per trackparameter, there is only one fitting surface
373 // break after having found it
374 break;
375 }
376
377 return tsos; // no need to std::move thanks to Return Value Optimization (RVO)
378}
379
380std::unique_ptr<const Trk::TrackStateOnSurface>
382 const HGTD_Cluster* cluster) const {
383 ATH_MSG_DEBUG("[updateState] calling the updator");
384
385 // FIXME: the HGTD_Cluster should know its detector element here. needs
386 // to be set up in the converter at some point!!
387 const auto* det_el = m_hgtd_det_mgr->getDetectorElement(cluster->identify());
388
389 // apply the time of flight correction before setting the time and resolution
390 // in the HGTD_ClusterOnTrack
391 std::pair<float, float> corr_time_and_res =
392 m_tof_corr_tool->correctTimeAndResolution(
393 *track, *cluster, cluster->time(), cluster->timeResolution());
394
395 std::unique_ptr<HGTD_ClusterOnTrack> cot =
396 std::make_unique<HGTD_ClusterOnTrack>(
397 cluster, Trk::LocalParameters(cluster->localPosition()),
398 Amg::MatrixX(cluster->localCovariance()), corr_time_and_res.first,
399 corr_time_and_res.second, det_el->identifyHash());
400
401 Trk::FitQualityOnSurface* quality = nullptr;
402
403 std::unique_ptr<Trk::TrackParameters> pars = m_updator->addToState(
404 *param, cot->localParameters(), cot->localCovariance(), quality);
405 //Here one could fix the addToState intefaces to
406 //avoid them allocating memory for Fit Quality On Surface
407 auto uniqueQuality= std::unique_ptr<Trk::FitQualityOnSurface>(quality);
408 auto QoS = uniqueQuality? *uniqueQuality : Trk::FitQualityOnSurface{};
409 return std::make_unique<const Trk::TrackStateOnSurface>(QoS, std::move(cot),
410 std::move(pars));
411}
412
413std::pair<const HGTD_Cluster*, HGTD::ClusterTruthInfo>
415 const std::vector<const Trk::Surface*>& surfaces,
417 const xAOD::TruthParticle* truth_ptkl, const HepMC::GenEvent* hs_event,
418 const InDetSimDataCollection* sim_data) const {
419
420 if (not truth_ptkl or not sim_data) {
421 if (not truth_ptkl)
422 ATH_MSG_DEBUG("truth_ptkl is null");
423 if (not sim_data)
424 ATH_MSG_DEBUG("sim_data is null");
425
426 return {nullptr, HGTD::ClusterTruthInfo()};
427 }
428
429 std::vector<Identifier> ids;
430 std::for_each(surfaces.begin(), surfaces.end(),
431 [&](const Trk::Surface* surf) {
432 ids.push_back(surf->associatedDetectorElementIdentifier());
433 });
434
435 for (const auto *const collection : *container) {
436 // if the ID corresponding to this collection is not in the list, skip
437
438 if (std::find(ids.begin(), ids.end(), collection->identify()) ==
439 ids.end()) {
440 continue;
441 }
442 for (const auto* cluster : *collection) {
443
444 HGTD::ClusterTruthInfo truth_info = m_truth_tool->classifyCluster(
445 cluster, truth_ptkl, sim_data, hs_event);
446 // return cluster and truth info if the hit is matched to the truth
447 // particle
449 return {cluster, truth_info};
450 }
451 }
452 }
453 // no matched cluster found
454 return {nullptr, HGTD::ClusterTruthInfo()};
455}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Trk::PrepRawDataContainer< HGTD_ClusterCollection > HGTD_ClusterContainer
Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration.
Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration.
static Double_t sc
double angle(const GeoTrf::Vector2D &a, const GeoTrf::Vector2D &b)
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.
virtual float time() const
virtual float timeResolution() const
ToolHandle< Trk::IExtrapolator > m_extrapolator
ToolHandle< IHGTD_TOFcorrectionTool > m_tof_corr_tool
static std::vector< const Trk::Surface * > getCompatibleSurfaces(const Trk::TrackParameters &param, const Trk::Layer *layer)
Select all within the vincinity of the point of extrapolation.
const Trk::TrackStateOnSurface * getLastHitOnTrack(const Trk::Track &track) const
Retrieve the last hit on track stored in the Trk::Track.
std::vector< std::unique_ptr< const Trk::TrackParameters > > extrapolateToSurfaces(const EventContext &ctx, const Trk::TrackParameters &param, const std::vector< const Trk::Surface * > &surfaces) const
After the compatible surfaces have been selected, the extrapolation is repeated to each of them.
virtual StatusCode initialize() override final
FloatProperty m_chi2_cut
Track extensions are only kept if the chi2/ndof is lower than the defined cut.
HGTD_IterativeExtensionTool(const std::string &, const std::string &, const IInterface *)
std::unique_ptr< const Trk::TrackStateOnSurface > updateStateWithBestFittingCluster(const Trk::Track *track, const std::vector< std::unique_ptr< const Trk::TrackParameters > > &params, const HGTD_ClusterContainer *container) const
Finds the overall best fitting cluster by keeping the one that gave the lowest chi2 after testing eac...
ToolHandle< IHGTD_ClusterTruthTool > m_truth_tool
const HGTD_DetectorManager * m_hgtd_det_mgr
std::pair< const HGTD_Cluster *, HGTD::ClusterTruthInfo > getTruthMatchedCluster(const std::vector< const Trk::Surface * > &surfaces, const HGTD_ClusterContainer *container, const xAOD::TruthParticle *truth_ptkl, const HepMC::GenEvent *hs_event, const InDetSimDataCollection *sim_data) const
std::unique_ptr< const Trk::TrackStateOnSurface > updateState(const Trk::Track *track, const Trk::TrackParameters *param, const HGTD_Cluster *cluster) const
Calls the TOF correction tool to build an HGTD_ClusterOnTrack with a calibrated time and resolution a...
IntegerProperty m_particle_hypot
Particle hypothesis used for the extrapolation.
virtual HGTD::ExtensionObject extendTrackToHGTD(const EventContext &ctx, const xAOD::TrackParticle &track_ptkl, const HGTD_ClusterContainer *container, const HepMC::GenEvent *hs_event=nullptr, const InDetSimDataCollection *sim_data=nullptr) const override final
Finds the (up to) four measurements in HGTD that can be associated to the track.
ToolHandle< Trk::IUpdator > m_updator
std::unique_ptr< const Trk::TrackStateOnSurface > findBestCompatibleCluster(const Trk::Track *track, const Trk::TrackParameters *param, const HGTD_ClusterContainer *container) const
Find the cluster on a given surface that has the best chi2 passing the cut.
Binned Array for avoiding map searches/.
Definition BinnedArray.h:36
virtual std::span< T *const > arrayObjects()=0
Return all objects of the Array non-const we can still modify the T.
Base Class for a Detector Layer in the Tracking realm.
Definition Layer.h:72
double eta() const
Access method for pseudorapidity - from momentum.
const Amg::Vector3D & momentum() const
Access method for the momentum.
const Amg::Vector3D & position() const
Access method for the position.
virtual const Surface & associatedSurface() const override=0
Access to the Surface associated to the Parameters.
const Amg::Vector2D & localPosition() const
return the local position reference
Identifier identify() const
return the identifier
const Amg::MatrixX & localCovariance() const
return const ref to the error matrix
Abstract Base Class for tracking surfaces.
Identifier associatedDetectorElementIdentifier() const
return Identifier of the associated Detector Element
const Amg::Vector3D & center() const
Returns the center position of the Surface.
represents the track state (measurement, material, fit parameters and quality) at a surface.
const TrackParameters * trackParameters() const
return ptr to trackparameters const overload
@ Measurement
This is a measurement, and will at least contain a Trk::MeasurementBase.
The TrackingGeometry class is the owner of the constructed TrackingVolumes.
const TrackingVolume * trackingVolume(const std::string &name) const
return the tracking Volume by name, 0 if it doesn't exist
Full Volume description used in Tracking, it inherits from Volume to get the geometrical structure,...
const LayerArray * confinedLayers() const
Return the subLayer array.
const Trk::Track * track() const
Returns a pointer (which can be NULL) to the Trk::Track which was used to make this TrackParticle.
double chi2(TH1 *h0, TH1 *h1)
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Eigen::Matrix< double, 3, 1 > Vector3D
@ alongMomentum
DataVector< const Trk::TrackStateOnSurface > TrackStates
ParticleHypothesis
Enumeration for Particle hypothesis respecting the interaction with material.
ParametersBase< TrackParametersDim, Charged > TrackParameters
const xAOD::TruthParticle * getTruthParticle(const xAOD::IParticle &p)
Return the truthParticle associated to the given IParticle (if any)
TrackParticle_v1 TrackParticle
Reference the current persistent version:
TruthParticle_v1 TruthParticle
Typedef to implementation.