13 #include "Acts/Surfaces/AnnulusBounds.hpp"
14 #include "Acts/Utilities/TrackHelpers.hpp"
49 return StatusCode::SUCCESS;
54 ATH_MSG_DEBUG(
"Executing MeasurementToTrackParticleDecoration...");
94 std::optional<ActsTrk::TrackContainer::ConstTrackProxy> >::
value);
95 std::optional<ActsTrk::TrackContainer::ConstTrackProxy> optional_track = *link_to_track;
97 if ( not optional_track.has_value() ) {
98 ATH_MSG_WARNING(
"Invalid track link for particle " << track_particle->index() <<
". Skipping track..");
102 ATH_MSG_DEBUG(
"Track link found for track particle with index " << track_particle->index());
103 ActsTrk::TrackContainer::ConstTrackProxy
track = optional_track.value();
105 std::vector<int>& regions{measurementRegionHandle(*track_particle)};
106 regions.reserve(
track.nMeasurements());
107 std::vector<int>&
detectors{measurementDetectorHandle(*track_particle)};
109 std::vector<int>&
layers{measurementLayerHandle(*track_particle)};
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());
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());
147 for (
const auto& state :
track.trackStatesReversed()) {
149 auto flag = state.typeFlags();
151 bool anyHit =
flag.test(Acts::TrackStateFlag::HoleFlag) or
flag.test(Acts::TrackStateFlag::MeasurementFlag);
153 ATH_MSG_DEBUG(
"--- This is not a hit measurement, skipping...");
163 float chi2_hit_predicted = -999.;
164 float chi2_hit_filtered = -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;
182 if (
flag.test(Acts::TrackStateFlag::HoleFlag)) {
183 type = MeasurementType::HOLE;
185 }
else if (
flag.test(Acts::TrackStateFlag::OutlierFlag)) {
186 type = MeasurementType::OUTLIER;
189 type = MeasurementType::HIT;
194 if (state.hasReferenceSurface() and state.referenceSurface().associatedDetectorElement()) {
196 if (!detectorElement) {
197 ATH_MSG_WARNING(
"--- TrackState reference surface returned an invalid associated detector element");
201 if (!siliconDetectorElement) {
202 ATH_MSG_WARNING(
"--- TrackState associated detector element is not silicon");
206 const Acts::AnnulusBounds* annulusBounds =
dynamic_cast<const Acts::AnnulusBounds*
>(&(state.referenceSurface().bounds()));
207 isAnnulusBound = annulusBounds ? true :
false;
209 if (siliconDetectorElement) {
211 if (siliconDetectorElement->
isPixel()) {
213 int layer_disk = pixel_id->
layer_disk(detectorIdentifier);
215 if (pixel_id->
barrel_ec(detectorIdentifier) == 0) {
216 if (layer_disk == 0) {
217 detector = Subdetector::INNERMOST_PIXEL;
224 }
else if (siliconDetectorElement->
isSCT()) {
227 region = sct_id->
barrel_ec(detectorIdentifier) == 0 ?
230 }
else ATH_MSG_WARNING(
"--- Unknown detector type - It is not pixel nor strip detecor element!");
232 }
else ATH_MSG_WARNING(
"--- Missing reference surface or associated detector element!");
238 if (
type == MeasurementType::OUTLIER ||
type == MeasurementType::HIT) {
242 if (
type == MeasurementType::HIT) {
243 chi2_hit_filtered = state.chi2();
246 if (state.hasUncalibratedSourceLink()) {
251 if (!state.hasSmoothed() || !state.hasProjector())
255 const auto &calibratedParameters = state.effectiveCalibrated();
256 const auto &calibratedCovariance = state.effectiveCalibratedCovariance();
261 bool evaluateUnbiased = (!
flag.test(Acts::TrackStateFlag::OutlierFlag));
263 if (evaluateUnbiased) {
264 ATH_MSG_DEBUG(
"--- Good for unbiased parameters evaluation!");
265 type = MeasurementType::UNBIASED;
267 if (state.hasUncalibratedSourceLink()) {
268 ATLASUncalibSourceLink sourceLink = state.getUncalibratedSourceLink().template get<ATLASUncalibSourceLink>();
279 ATH_MSG_DEBUG(
"xAOD::UncalibratedMeasurement is neither xAOD::PixelCluster nor xAOD::StripCluster");
284 const auto& [unbiasedParameters, unbiasedCovariance] =
285 evaluateUnbiased ? Acts::calculateUnbiasedParametersCovariance(state) : std::make_pair(state.parameters(), state.covariance());
287 measurementLocX = calibratedParameters[Acts::eBoundLoc0];
288 measurementLocCovX = calibratedCovariance(Acts::eBoundLoc0, Acts::eBoundLoc0);
290 if (!isAnnulusBound) {
292 trackParameterLocX = unbiasedParameters[Acts::eBoundLoc0];
293 residualLocX = (measurementLocX - trackParameterLocX) / 1_um;
294 trackParameterLocCovX = unbiasedCovariance(Acts::eBoundLoc0, Acts::eBoundLoc0);
299 float locR = unbiasedParameters[Acts::eBoundLoc0];
300 float covR = unbiasedCovariance(Acts::eBoundLoc0,Acts::eBoundLoc0);
301 float locphi = unbiasedParameters[Acts::eBoundLoc1];
302 float covphi = unbiasedCovariance(Acts::eBoundLoc1,Acts::eBoundLoc1);
303 float covRphi = unbiasedCovariance(Acts::eBoundLoc0,Acts::eBoundLoc1);
305 trackParameterLocX = locphi;
306 residualLocX =
locR * (measurementLocX - trackParameterLocX) / 1_um;
308 trackParameterLocCovX =
locR*
locR*covphi + locphi*locphi*covR + 2*locphi*
locR*covRphi;
311 measurementLocCovX =
locR*
locR * measurementLocCovX;
314 pullLocX =
evaluatePull(residualLocX, measurementLocCovX,
315 trackParameterLocCovX, evaluateUnbiased);
317 if (state.calibratedSize() == 2) {
318 measurementLocY = calibratedParameters[Acts::eBoundLoc1];
319 trackParameterLocY = unbiasedParameters[Acts::eBoundLoc1];
320 residualLocY = (measurementLocY - trackParameterLocY) / 1_um;
321 measurementLocCovY = calibratedCovariance(Acts::eBoundLoc1, Acts::eBoundLoc1);
322 trackParameterLocCovY = unbiasedCovariance(Acts::eBoundLoc1, Acts::eBoundLoc1);
323 pullLocY =
evaluatePull(residualLocY, measurementLocCovY,
324 trackParameterLocCovY, evaluateUnbiased);
329 else if (
type == MeasurementType::HOLE) {
332 auto pred = state.predicted();
333 trackParameterLocX = pred[Acts::eBoundLoc0];
334 trackParameterLocY = pred[Acts::eBoundLoc1];
339 regions.push_back(region);
342 types.push_back(
type);
343 predchi2s.push_back(chi2_hit_predicted);
344 filtchi2s.push_back(chi2_hit_filtered);
345 sizesPhi.push_back(sizePhi);
346 sizesEta.push_back(sizeEta);
347 residualsLocX.push_back(residualLocX);
348 pullsLocX.push_back(pullLocX);
349 measurementsLocX.push_back(measurementLocX);
350 trackParametersLocX.push_back(trackParameterLocX);
351 measurementsLocCovX.push_back(measurementLocCovX);
352 trackParametersLocCovX.push_back(trackParameterLocCovX);
353 residualsLocY.push_back(residualLocY);
354 pullsLocY.push_back(pullLocY);
355 measurementsLocY.push_back(measurementLocY);
356 trackParametersLocY.push_back(trackParameterLocY);
357 measurementsLocCovY.push_back(measurementLocCovY);
358 trackParametersLocCovY.push_back(trackParameterLocCovY);
365 return StatusCode::SUCCESS;
370 auto pred = state.predicted();
371 auto predC = state.predictedCovariance();
373 return Acts::visit_measurement(
374 state.calibratedSize(),
375 [&]<std::size_t measdim>(std::integral_constant<std::size_t, measdim>) {
376 Acts::FixedBoundSubspaceHelper<measdim> subspaceHelper =
377 state.template projectorSubspaceHelper<measdim>();
380 auto H = subspaceHelper.projector();
382 const auto calibrated = state.template calibrated<measdim>();
383 const auto calibratedCov = state.template calibratedCovariance<measdim>();
385 auto residual = (H * pred - calibrated).eval();
386 auto rescov = (H * predC * H.transpose() + calibratedCov).eval();
388 return ((residual.transpose() * rescov.inverse() * residual).eval())(0,0);
397 const float measurementCovariance,
398 const float trackParameterCovariance,
399 const bool evaluateUnbiased)
const {
400 float correlation = evaluateUnbiased ? 1. : -1.;
401 float residualCovariance = measurementCovariance + correlation*trackParameterCovariance;
402 if (residualCovariance<=0.) {
404 ATH_MSG_DEBUG(
"--- Total covariance for pull evaluation is non-positive! Returning pulls = 0!");
407 return 0.001 *
residual/std::sqrt(residualCovariance);