ATLAS Offline Software
Loading...
Searching...
No Matches
MeasurementToTrackParticleDecorationAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
15#include "Acts/Surfaces/AnnulusBounds.hpp"
16#include "Acts/Utilities/TrackHelpers.hpp"
19
20
21using namespace Acts::UnitLiterals;
22
23
24namespace ActsTrk {
25
26
28 {
29 ATH_MSG_DEBUG("Initializing " << name() << " ...");
30
31 ATH_CHECK(m_trackParticlesKey.initialize());
32
33 // Decorations
36 ATH_CHECK(m_measurementLayerKey.initialize());
37 ATH_CHECK(m_chi2HitPredictedKey.initialize());
38 ATH_CHECK(m_chi2HitFilteredKey.initialize());
39 ATH_CHECK(m_measurementTypeKey.initialize());
42 ATH_CHECK(m_residualLocXkey.initialize());
43 ATH_CHECK(m_pullLocXkey.initialize());
44 ATH_CHECK(m_measurementLocXkey.initialize());
48 ATH_CHECK(m_residualLocYkey.initialize());
49 ATH_CHECK(m_pullLocYkey.initialize());
50 ATH_CHECK(m_measurementLocYkey.initialize());
54
55 ATH_CHECK(m_ctxProvider.initialize());
56 return StatusCode::SUCCESS;
57 }
58
59 StatusCode MeasurementToTrackParticleDecorationAlg::execute(const EventContext& ctx) const
60 {
61 ATH_MSG_DEBUG("Executing " << name() << " ...");
62
63 auto tgContext = m_ctxProvider.getGeometryContext(ctx);
64
71
74
81
88
90 ATH_CHECK(trackParticlesHandle.isValid());
91 const xAOD::TrackParticleContainer *track_particles = trackParticlesHandle.cptr();
92
93 for (const xAOD::TrackParticle *track_particle : *track_particles) {
94
95 std::optional<ActsTrk::TrackContainer::ConstTrackProxy> optional_track = getActsTrack(*track_particle);
96
97 if ( not optional_track.has_value() ) {
98 ATH_MSG_WARNING("Invalid track link for particle " << track_particle->index() << ". Skipping track..");
99 continue;
100 }
101
102 ATH_MSG_DEBUG("Track link found for track particle with index " << track_particle->index());
103 ActsTrk::TrackContainer::ConstTrackProxy track = optional_track.value();
104
105 std::vector<int>& regions{measurementRegionHandle(*track_particle)};
106 regions.reserve(track.nMeasurements());
107 std::vector<int>& detectors{measurementDetectorHandle(*track_particle)};
108 detectors.reserve(track.nMeasurements());
109 std::vector<int>& layers{measurementLayerHandle(*track_particle)};
110 layers.reserve(track.nMeasurements());
111 std::vector<int>& types{measurementTypeHandle(*track_particle)};
112 types.reserve(track.nMeasurements());
113 std::vector<float>& predchi2s{chi2HitPredictedHandle(*track_particle)};
114 predchi2s.reserve(track.nMeasurements());
115 std::vector<float>& filtchi2s{chi2HitFilteredHandle(*track_particle)};
116 filtchi2s.reserve(track.nMeasurements());
117
118 std::vector<int>& sizesPhi{measurementPhiWidthHandle(*track_particle)};
119 sizesPhi.reserve(track.nMeasurements());
120 std::vector<int>& sizesEta{measurementEtaWidthHandle(*track_particle)};
121 sizesEta.reserve(track.nMeasurements());
122 std::vector<float>& residualsLocX{residualLocXhandle(*track_particle)};
123 residualsLocX.reserve(track.nMeasurements());
124 std::vector<float>& pullsLocX{pullLocXhandle(*track_particle)};
125 pullsLocX.reserve(track.nMeasurements());
126 std::vector<float>& measurementsLocX{measurementLocXhandle(*track_particle)};
127 measurementsLocX.reserve(track.nMeasurements());
128 std::vector<float>& trackParametersLocX{trackParameterLocXhandle(*track_particle)};
129 trackParametersLocX.reserve(track.nMeasurements());
130 std::vector<float>& measurementsLocCovX{measurementLocCovXhandle(*track_particle)};
131 measurementsLocCovX.reserve(track.nMeasurements());
132 std::vector<float>& trackParametersLocCovX{trackParameterLocCovXhandle(*track_particle)};
133 trackParametersLocCovX.reserve(track.nMeasurements());
134 std::vector<float>& residualsLocY{residualLocYhandle(*track_particle)};
135 residualsLocY.reserve(track.nMeasurements());
136 std::vector<float>& pullsLocY{pullLocYhandle(*track_particle)};
137 pullsLocY.reserve(track.nMeasurements());
138 std::vector<float>& measurementsLocY{measurementLocYhandle(*track_particle)};
139 measurementsLocY.reserve(track.nMeasurements());
140 std::vector<float>& trackParametersLocY{trackParameterLocYhandle(*track_particle)};
141 trackParametersLocY.reserve(track.nMeasurements());
142 std::vector<float>& measurementsLocCovY{measurementLocCovYhandle(*track_particle)};
143 measurementsLocCovY.reserve(track.nMeasurements());
144 std::vector<float>& trackParametersLocCovY{trackParameterLocCovYhandle(*track_particle)};
145 trackParametersLocCovY.reserve(track.nMeasurements());
146
147 for (const auto & state : track.trackStatesReversed()) {
148
149 auto flag = state.typeFlags();
150 // consider holes and measurements (also outliers)
151 bool anyHit = flag.isHole() or flag.hasMeasurement() or state.hasUncalibratedSourceLink();
152 if (not anyHit) {
153 ATH_MSG_DEBUG("--- This is not a hit measurement, skipping...");
154 continue;
155 }
156
157 // starting with invalid values and setting them where needed.
158
159 int detector = -999;
160 int region = -999;
161 int layer = -999;
162 int type = -999;
163 float chi2_hit_predicted = -999.;
164 float chi2_hit_filtered = -999.;
165 int sizePhi = -999;
166 int sizeEta = -999;
167 float residualLocX = -999.;
168 float pullLocX = -999.;
169 float measurementLocX = -999.;
170 float trackParameterLocX = -999.;
171 float measurementLocCovX = -999.;
172 float trackParameterLocCovX = -999;
173 float residualLocY = -999.;
174 float pullLocY = -999.;
175 float measurementLocY = -999.;
176 float trackParameterLocY = -999.;
177 float measurementLocCovY = -999.;
178 float trackParameterLocCovY = -999.;
179 bool isAnnulusBound = false;
180
181 // Get the measurement type
182 if (flag.isHole()) {
184 ATH_MSG_DEBUG("--- This is a hole");
185 } else if (flag.isOutlier()) {
187 ATH_MSG_DEBUG("--- This is an outlier");
188 } else if (flag.hasMeasurement()) {
190 ATH_MSG_DEBUG("--- This is a hit");
191 }
192
193 // Check the location of the state
194 if (state.hasReferenceSurface() and state.referenceSurface().isSensitive()) {
195 const auto* detectorElement = getActsDetectorElement(state.referenceSurface());
196 if (!detectorElement) {
197 ATH_MSG_WARNING("--- TrackState reference surface returned an invalid associated detector element");
198 continue;
199 }
200 const InDetDD::SiDetectorElement * siliconDetectorElement = dynamic_cast<const InDetDD::SiDetectorElement *>(detectorElement->upstreamDetectorElement());
201 if (!siliconDetectorElement) {
202 ATH_MSG_WARNING("--- TrackState associated detector element is not silicon");
203 continue;
204 }
205
206 const Acts::AnnulusBounds* annulusBounds = dynamic_cast<const Acts::AnnulusBounds*>(&(state.referenceSurface().bounds()));
207 isAnnulusBound = annulusBounds ? true : false;
208
209 if (siliconDetectorElement) {
210 Identifier detectorIdentifier = siliconDetectorElement->identify();
211 if (siliconDetectorElement->isPixel()) {
212 const PixelID* pixel_id = static_cast<const PixelID *>(siliconDetectorElement->getIdHelper());
213 int layer_disk = pixel_id->layer_disk(detectorIdentifier);
214 layer = layer_disk;
215 if (pixel_id->barrel_ec(detectorIdentifier) == 0) {
216 if (layer_disk == 0) {
218 } else detector = Subdetector::PIXEL;
219 region = Region::BARREL;
220 } else {
221 detector = Subdetector::PIXEL;
222 region = Region::ENDCAP;
223 }
224 } else if (siliconDetectorElement->isSCT()) {
225 const SCT_ID* sct_id = static_cast<const SCT_ID *>(siliconDetectorElement->getIdHelper());
226 detector = Subdetector::STRIP;
227 region = sct_id->barrel_ec(detectorIdentifier) == 0 ?
229 layer = sct_id->layer_disk(detectorIdentifier);;
230 } else ATH_MSG_WARNING("--- Unknown detector type - It is not pixel nor strip detecor element!");
231 } else ATH_MSG_WARNING("--- Missing silicon detector element!");
232 } else ATH_MSG_WARNING("--- Missing reference surface or associated detector element!");
233
234
235
236 // If I have a measurement (hit or outlier) then proceed with computing the residuals / pulls
237
239
240 //Get the Chi2 computation
241
242 if (type == MeasurementType::HIT) {
243 chi2_hit_filtered = state.chi2();
244 }
245
246 if (state.hasUncalibratedSourceLink()) {
247 chi2_hit_predicted = getChi2Contribution(state);
248 }
249
250 // Skip all states without smoothed parameters or without projector
251 if (!state.hasSmoothed() || !state.hasProjector())
252 continue;
253
254 // Calling effective Calibrated has some runtime overhead
255 const auto &calibratedParameters = state.effectiveCalibrated();
256 const auto &calibratedCovariance = state.effectiveCalibratedCovariance();
257
258 // We evaluate the unbiased parameters for:
259 // - measurements added to the fit. For outliers, the measurement is not part of the fit, hence track parameters are already unbiased
260 // - if the filtered parameters and the projector exist.
261 bool evaluateUnbiased = flag.isMeasurement();
262
263 if (evaluateUnbiased) {
264 ATH_MSG_DEBUG("--- Good for unbiased parameters evaluation!");
266 // if unbiased, access the associated uncalibrated measurement and store the size
267 if (state.hasUncalibratedSourceLink()) {
268 const xAOD::UncalibratedMeasurement* uncalibratedMeasurement = detail::xAODUncalibMeasCalibrator::unpack(state.getUncalibratedSourceLink());;
269 const xAOD::UncalibMeasType measurementType = uncalibratedMeasurement->type();
270 if (measurementType == xAOD::UncalibMeasType::PixelClusterType) {
271 auto pixelCluster = static_cast<const xAOD::PixelCluster *>(uncalibratedMeasurement);
272 sizePhi = pixelCluster->channelsInPhi();
273 sizeEta = pixelCluster->channelsInEta();
274 } else if (measurementType == xAOD::UncalibMeasType::StripClusterType) {
275 auto stripCluster = static_cast<const xAOD::StripCluster *>(uncalibratedMeasurement);
276 sizePhi = stripCluster->channelsInPhi();
277 } else {
278 ATH_MSG_DEBUG("xAOD::UncalibratedMeasurement is neither xAOD::PixelCluster nor xAOD::StripCluster");
279 }
280 }
281 }
282
283 const auto& [unbiasedParameters, unbiasedCovariance] =
284 evaluateUnbiased ? Acts::calculateUnbiasedParametersCovariance(Acts::AnyConstTrackStateProxy{state}) : std::make_pair(state.parameters(), state.covariance());
285
286 measurementLocX = calibratedParameters[Acts::eBoundLoc0];
287 measurementLocCovX = calibratedCovariance(Acts::eBoundLoc0, Acts::eBoundLoc0);
288
289 if (!isAnnulusBound) {
290
291 trackParameterLocX = unbiasedParameters[Acts::eBoundLoc0];
292 residualLocX = (measurementLocX - trackParameterLocX) / 1_um; //in um
293 trackParameterLocCovX = unbiasedCovariance(Acts::eBoundLoc0, Acts::eBoundLoc0);
294 }
295 else {
296 // TODO:: use directly phi instead of r*phi in the future
297
298 float locR = unbiasedParameters[Acts::eBoundLoc0];
299 float covR = unbiasedCovariance(Acts::eBoundLoc0,Acts::eBoundLoc0);
300 float locphi = unbiasedParameters[Acts::eBoundLoc1];
301 float covphi = unbiasedCovariance(Acts::eBoundLoc1,Acts::eBoundLoc1);
302 float covRphi = unbiasedCovariance(Acts::eBoundLoc0,Acts::eBoundLoc1);
303
304 trackParameterLocX = locphi;
305 residualLocX = locR * (measurementLocX - trackParameterLocX) / 1_um;
306 // Compute the error on the local rphi
307 trackParameterLocCovX = locR*locR*covphi + locphi*locphi*covR + 2*locphi*locR*covRphi;
308
309 // Rescale the error of the measurement to Rphi.
310 measurementLocCovX = locR*locR * measurementLocCovX;
311 }
312
313 pullLocX = evaluatePull(residualLocX, measurementLocCovX,
314 trackParameterLocCovX, evaluateUnbiased);
315
316 if (state.calibratedSize() == 2) {
317 measurementLocY = calibratedParameters[Acts::eBoundLoc1];
318 trackParameterLocY = unbiasedParameters[Acts::eBoundLoc1];
319 residualLocY = (measurementLocY - trackParameterLocY) / 1_um;
320 measurementLocCovY = calibratedCovariance(Acts::eBoundLoc1, Acts::eBoundLoc1);
321 trackParameterLocCovY = unbiasedCovariance(Acts::eBoundLoc1, Acts::eBoundLoc1);
322 pullLocY = evaluatePull(residualLocY, measurementLocCovY,
323 trackParameterLocCovY, evaluateUnbiased);
324 }
325
326 } // hit or outliers
327
328 else if (type == MeasurementType::HOLE) {
329
330 // Get the predicted position on sensor
331 auto pred = state.predicted();
332 trackParameterLocX = pred[Acts::eBoundLoc0];
333 trackParameterLocY = pred[Acts::eBoundLoc1];
334 } // holes
335
336 else {
337 ATH_MSG_DEBUG("--- This is a seed hit");
339 } // seed hits
340
341 // Always fill with this information
342
343 regions.push_back(region);
344 detectors.push_back(detector);
345 layers.push_back(layer);
346 types.push_back(type);
347 predchi2s.push_back(chi2_hit_predicted);
348 filtchi2s.push_back(chi2_hit_filtered);
349 sizesPhi.push_back(sizePhi);
350 sizesEta.push_back(sizeEta);
351 residualsLocX.push_back(residualLocX);
352 pullsLocX.push_back(pullLocX);
353 measurementsLocX.push_back(measurementLocX);
354 trackParametersLocX.push_back(trackParameterLocX);
355 measurementsLocCovX.push_back(measurementLocCovX);
356 trackParametersLocCovX.push_back(trackParameterLocCovX);
357 residualsLocY.push_back(residualLocY);
358 pullsLocY.push_back(pullLocY);
359 measurementsLocY.push_back(measurementLocY);
360 trackParametersLocY.push_back(trackParameterLocY);
361 measurementsLocCovY.push_back(measurementLocCovY);
362 trackParametersLocCovY.push_back(trackParameterLocCovY);
363
364
365 } // loop on states
366
367 } // loop on tracks
368
369 return StatusCode::SUCCESS;
370 }
371
372 float MeasurementToTrackParticleDecorationAlg::getChi2Contribution(const typename ActsTrk::TrackStateBackend::ConstTrackStateProxy &state) const {
373
374 // Seed tracks (TSOS mask = None) have no predicted parameters — return 0
375 if (state.getMask() == Acts::TrackStatePropMask::None) {
376 return 0.f;
377 }
378
379 auto pred = state.predicted();
380 auto predC = state.predictedCovariance();
381
382 return Acts::visit_measurement(
383 state.calibratedSize(),
384 [&]<std::size_t measdim>(std::integral_constant<std::size_t, measdim>) {
385 Acts::FixedBoundSubspaceHelper<measdim> subspaceHelper =
386 state.template projectorSubspaceHelper<measdim>();
387
388 // TODO use subspace helper for projection instead
389 auto H = subspaceHelper.projector();
390
391 const auto calibrated = state.template calibrated<measdim>();
392 const auto calibratedCov = state.template calibratedCovariance<measdim>();
393
394 auto residual = (H * pred - calibrated).eval();
395 auto rescov = (H * predC * H.transpose() + calibratedCov).eval();
396
397 return ((residual.transpose() * rescov.inverse() * residual).eval())(0,0);
398 });
399
400
401
402 }
403
404
406 const float measurementCovariance,
407 const float trackParameterCovariance,
408 const bool evaluateUnbiased) const {
409 float correlation = evaluateUnbiased ? 1. : -1.;
410 float residualCovariance = measurementCovariance + correlation*trackParameterCovariance;
411 if (residualCovariance<=0.) {
412 // If the total covariance is non-positive return 0
413 ATH_MSG_DEBUG("--- Total covariance for pull evaluation is non-positive! Returning pulls = 0!");
414 return 0.;
415 }
416 return 0.001 * residual/std::sqrt(residualCovariance);
417 }
418
419} // namespace
420
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_WARNING(x)
#define ATH_MSG_DEBUG(x)
static const std::vector< std::string > types
static const std::vector< std::string > regions
This is an Identifier helper class for the Pixel subdetector.
This is an Identifier helper class for the SCT subdetector.
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_chi2HitPredictedKey
ContextUtility m_ctxProvider
Context provider for geometry, magnetic field and calibration contexts.
float evaluatePull(const float residual, const float measurementCovariance, const float trackParameterCovariance, const bool evaluateUnbiased) const
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_measurementRegionKey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_residualLocYkey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_trackParameterLocYkey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_measurementLayerKey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_measurementDetectorKey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_measurementLocYkey
float getChi2Contribution(const typename ActsTrk::TrackStateBackend::ConstTrackStateProxy &state) const
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_measurementEtaWidthKey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_pullLocYkey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_measurementLocXkey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_measurementTypeKey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_residualLocXkey
virtual StatusCode execute(const EventContext &ctx) const override
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_pullLocXkey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_measurementLocCovXkey
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_trackParticlesKey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_trackParameterLocXkey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_trackParameterLocCovYkey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_measurementLocCovYkey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_trackParameterLocCovXkey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_chi2HitFilteredKey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_measurementPhiWidthKey
static const xAOD::UncalibratedMeasurement * unpack(const Acts::SourceLink &sl)
Helper method to unpack an Acts source link to an uncalibrated measurement.
Class to hold geometrical description of a silicon detector element.
virtual Identifier identify() const override final
identifier of this detector element (inline)
const AtlasDetectorID * getIdHelper() const
Returns the id helper (inline).
This is an Identifier helper class for the Pixel subdetector.
Definition PixelID.h:69
int layer_disk(const Identifier &id) const
Definition PixelID.h:602
int barrel_ec(const Identifier &id) const
Values of different levels (failure returns 0).
Definition PixelID.h:595
This is an Identifier helper class for the SCT subdetector.
Definition SCT_ID.h:68
int layer_disk(const Identifier &id) const
Definition SCT_ID.h:687
int barrel_ec(const Identifier &id) const
Values of different levels (failure returns 0).
Definition SCT_ID.h:681
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.
virtual xAOD::UncalibMeasType type() const =0
Returns the type of the measurement type as a simple enumeration.
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
std::optional< ActsTrk::TrackContainer::ConstTrackProxy > getActsTrack(const xAOD::TrackParticle &trkPart)
Return the proxy to the Acts track from which the track particle was made frome.
Definition Decoration.cxx:9
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
StripCluster_v1 StripCluster
Define the version of the strip cluster class.
UncalibratedMeasurement_v1 UncalibratedMeasurement
Define the version of the uncalibrated measurement 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".