ATLAS Offline Software
Loading...
Searching...
No Matches
TrackFindingBaseAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7// ActsTrk
14#include "Acts/Surfaces/PerigeeSurface.hpp"
15
16namespace ActsTrk {
18
21
22 TrackFindingBaseAlg::TrackFindingBaseAlg(const std::string &name, ISvcLocator *pSvcLocator) : AthReentrantAlgorithm(name, pSvcLocator) {}
23
25
27 ATH_MSG_DEBUG("Properties Summary:");
39 ATH_MSG_DEBUG(" " << m_phiMin);
40 ATH_MSG_DEBUG(" " << m_phiMax);
41 ATH_MSG_DEBUG(" " << m_etaMin);
42 ATH_MSG_DEBUG(" " << m_etaMax);
45 ATH_MSG_DEBUG(" " << m_ptMin);
46 ATH_MSG_DEBUG(" " << m_ptMax);
47 ATH_MSG_DEBUG(" " << m_d0Min);
48 ATH_MSG_DEBUG(" " << m_d0Max);
49 ATH_MSG_DEBUG(" " << m_z0Min);
50 ATH_MSG_DEBUG(" " << m_z0Max);
67
68 m_logger = makeActsAthenaLogger(this, "Acts");
69
70 // Read and Write handles
71 ATH_CHECK(m_trackContainerKey.initialize());
73
74 ATH_CHECK(m_monTool.retrieve(EnableTool{not m_monTool.empty()}));
77 ATH_CHECK(m_trackStatePrinter.retrieve(EnableTool{not m_trackStatePrinter.empty()}));
79 ATH_CHECK(m_fitterTool.retrieve());
80 ATH_CHECK(m_pixelCalibTool.retrieve(EnableTool{not m_pixelCalibTool.empty()}));
81 ATH_CHECK(m_stripCalibTool.retrieve(EnableTool{not m_stripCalibTool.empty()}));
82 ATH_CHECK(m_hgtdCalibTool.retrieve(EnableTool{not m_hgtdCalibTool.empty()}));
83
84 auto magneticField = std::make_unique<ATLASMagneticFieldWrapper>();
85 auto trackingGeometry = m_trackingGeometryTool->trackingGeometry();
86
87 detail::Stepper stepper(std::move(magneticField));
88 detail::Navigator::Config config{trackingGeometry};
89 config.resolvePassive = false;
90 config.resolveMaterial = true;
91 config.resolveSensitive = true;
92 detail::Navigator navigator(config, logger().cloneWithSuffix("Navigator"));
93 detail::Propagator propagator(std::move(stepper), std::move(navigator), logger().cloneWithSuffix("Prop"));
94
95 // Using the CKF propagator as extrapolator
96 detail::Extrapolator extrapolator = propagator;
97
98 // m_etaBins (from flags.Tracking.ActiveConfig.etaBins) includes a dummy first and last bin, which we ignore
99 std::vector<double> absEtaEdges;
100 if (m_etaBins.size() <= 2)
101 {
102 absEtaEdges.reserve(2ul);
103 absEtaEdges.push_back(0.0);
104 absEtaEdges.push_back(std::numeric_limits<double>::infinity());
105 }
106 else
107 {
108 absEtaEdges.reserve(m_etaBins.size());
109 absEtaEdges.push_back(m_absEtaMin);
110 absEtaEdges.insert(absEtaEdges.end(), m_etaBins.begin() + 1, m_etaBins.end() - 1);
111 absEtaEdges.push_back(m_absEtaMax);
112 }
113
114 auto setCut = [](auto &cfgVal, const auto &cuts, size_t ind) -> void
115 {
116 if (cuts.empty())
117 return;
118 cfgVal = (ind < cuts.size()) ? cuts[ind] : cuts[cuts.size() - 1];
119 };
120
121 Acts::TrackSelector::EtaBinnedConfig trackSelectorCfg{std::move(absEtaEdges)};
122 if (m_etaBins.size() <= 2)
123 {
124 assert(trackSelectorCfg.cutSets.size() == 1);
125 trackSelectorCfg.cutSets[0].absEtaMin = m_absEtaMin;
126 trackSelectorCfg.cutSets[0].absEtaMax = m_absEtaMax;
127 }
128 size_t cutIndex = 0;
129 for (auto &cfg : trackSelectorCfg.cutSets)
130 {
131 setCut(cfg.phiMin, m_phiMin, cutIndex);
132 setCut(cfg.phiMax, m_phiMax, cutIndex);
133 setCut(cfg.etaMin, m_etaMin, cutIndex);
134 setCut(cfg.etaMax, m_etaMax, cutIndex);
135 setCut(cfg.ptMin, m_ptMin, cutIndex);
136 setCut(cfg.ptMax, m_ptMax, cutIndex);
137 setCut(cfg.loc0Min, m_d0Min, cutIndex);
138 setCut(cfg.loc0Max, m_d0Max, cutIndex);
139 setCut(cfg.loc1Min, m_z0Min, cutIndex);
140 setCut(cfg.loc1Max, m_z0Max, cutIndex);
141 setCut(cfg.minMeasurements, m_minMeasurements, cutIndex);
142 setCut(cfg.maxHoles, m_maxHoles, cutIndex);
143 setCut(cfg.maxOutliers, m_maxOutliers, cutIndex);
144 setCut(cfg.maxSharedHits, m_maxSharedHits, cutIndex);
145 setCut(cfg.maxChi2, m_maxChi2, cutIndex);
146 ++cutIndex;
147 }
148
149 ATH_MSG_DEBUG(trackSelectorCfg);
150
151 // initializer measurement selector and connect it to the delegates of the track finder optins
153
154 detail::CKF_config ckfConfig{
155 std::move(extrapolator),
156 detail::CKF{std::move(propagator), logger().cloneWithSuffix("CKF")},
157 {},
158 Acts::TrackSelector{trackSelectorCfg}};
159
160 m_trackFinder = std::make_unique<CKF_pimpl>(std::move(ckfConfig));
161
163
165
167
168 return StatusCode::SUCCESS;
169 }
170
171 StatusCode TrackFindingBaseAlg::execute(const EventContext &) const {
172 ATH_MSG_FATAL("execute() method from the base class was called! Implement proper execute() method in the derived class!");
173
174 return StatusCode::FAILURE;
175 }
176
179
180 return StatusCode::SUCCESS;
181 }
182
183 std::unique_ptr<ActsTrk::IMeasurementSelector> TrackFindingBaseAlg::setMeasurementSelector(
184 const EventContext &ctx,
185 const detail::TrackFindingMeasurements &measurements,
186 TrackFinderOptions &options) const {
187
188 std::unique_ptr<ActsTrk::IMeasurementSelector> measurementSelector = ActsTrk::detail::getMeasurementSelector(
189 ctx,
190 m_pixelCalibTool.isEnabled() ? &(*m_pixelCalibTool) : nullptr,
191 m_stripCalibTool.isEnabled() ? &(*m_stripCalibTool) : nullptr,
192 m_hgtdCalibTool.isEnabled() ? &(*m_hgtdCalibTool) : nullptr,
193 measurements.measurementRanges(),
195 m_measurementSelectorConfig.m_chi2CutOffOutlier,
197 m_edgeHoleBorderWidth.value());
198
199 measurementSelector->connect(&options.extensions.createTrackStates);
200
201 return measurementSelector;
202 }
203
205 const EventContext &ctx,
206 const DetectorContextHolder &detContext,
207 const detail::TrackFindingMeasurements &measurements,
208 const Acts::PerigeeSurface* pSurface) const {
209 Acts::PropagatorPlainOptions plainOptions{detContext.geometry, detContext.magField};
210 plainOptions.maxSteps = m_maxPropagationStep;
211 plainOptions.direction = Acts::Direction::Forward();
212 plainOptions.endOfWorldVolumeIds = m_endOfWorldVolumeIds;
213
214 // Set the CombinatorialKalmanFilter options
215 TrackFinderOptions options(detContext.geometry, detContext.magField, detContext.calib,
216 trackFinder().ckfExtensions, plainOptions, pSurface);
217
218 std::unique_ptr<ActsTrk::IMeasurementSelector> measurementSelector = setMeasurementSelector(ctx, measurements, options);
219
220 Acts::PropagatorPlainOptions plainSecondOptions{detContext.geometry, detContext.magField};
221 plainSecondOptions.maxSteps = m_maxPropagationStep;
222 plainSecondOptions.direction = plainOptions.direction.invert();
223
224 TrackFinderOptions secondOptions(detContext.geometry, detContext.magField, detContext.calib,
225 options.extensions, plainSecondOptions, pSurface);
226 secondOptions.targetSurface = pSurface;
227 secondOptions.skipPrePropagationUpdate = true;
228
229 return {std::move(options), std::move(secondOptions), std::move(measurementSelector)};
230 };
231
232 const Acts::TrackSelector::Config& TrackFindingBaseAlg::getCuts (double eta) const {
233 const auto &trackSelectorCfg = trackFinder().trackSelector.config();
234 // return the last bin for |eta|>=4 or nan
235 return (!(std::abs(eta) < trackSelectorCfg.absEtaEdges.back())) ? trackSelectorCfg.cutSets.back()
236 : (std::abs(eta) < trackSelectorCfg.absEtaEdges.front()) ? trackSelectorCfg.cutSets.front()
237 : trackSelectorCfg.getCuts(eta);
238 };
239
240 std::vector<typename detail::RecoTrackContainer::TrackProxy>
242 const TrkProxy &trackProxy,
243 detail::RecoTrackContainer &tracksContainerTemp,
244 const TrackFinderOptions &options) const {
245 if (not m_doTwoWay) return {};
246
247 // Create initial parameters for the propagation
248 Acts::BoundTrackParameters secondInitialParameters = trackProxy.createParametersFromState(detail::RecoConstTrackStateContainerProxy{firstMeasurement});
249 if (!secondInitialParameters.referenceSurface().insideBounds(secondInitialParameters.localPosition())) { // #3751
250 return {};
251 }
252
253 // First, inflate the covariance matrix if configured
255 ATH_MSG_DEBUG("Inflating covariance matrix for second track finding with factor = " << m_twoWayinflateCovarianceFactor.value());
256 ATH_MSG_VERBOSE("Original parameters before inflation: \n" << secondInitialParameters);
257
258 auto inflatedCovariance = secondInitialParameters.covariance().value();
259 inflatedCovariance *= m_twoWayinflateCovarianceFactor;
260
261 const auto& origSurface = secondInitialParameters.referenceSurface();
262 auto surfacePtr = const_cast<Acts::Surface&>(origSurface).shared_from_this();
263
264 Acts::BoundTrackParameters newParams(
265 std::static_pointer_cast<const Acts::Surface>(surfacePtr),
266 secondInitialParameters.parameters(),
267 std::make_optional(inflatedCovariance),
268 secondInitialParameters.particleHypothesis());
269 secondInitialParameters = std::move(newParams);
270
271 ATH_MSG_VERBOSE("Inflated covariance matrix : \n" << secondInitialParameters.covariance().value());
272 }
273
274 auto rootBranch = tracksContainerTemp.makeTrack();
275 rootBranch.copyFromWithoutStates(trackProxy); // #3534
276
277 // perform track finding
278 auto secondResult =
279 trackFinder().ckf.findTracks(secondInitialParameters, options, tracksContainerTemp, rootBranch);
280 if (not secondResult.ok()) {
281 return {};
282 }
283 return secondResult.value();
284 }
285
286 xAOD::UncalibMeasType TrackFindingBaseAlg::measurementType (const detail::RecoTrackContainer::TrackStateProxy &trackState) {
287 if (trackState.hasReferenceSurface()) {
288 if (const auto *actsDetElem = dynamic_cast<const IDetectorElementBase *>(trackState.referenceSurface().surfacePlacement())) {
289 switch (actsDetElem->detectorType()) {
296 default:
297 break;
298 }
299 }
300 }
302 }
303
305 const detail::RecoTrackContainer::TrackProxy &track,
306 const detail::RecoTrackContainer::TrackStateProxy &trackState,
307 const Acts::TrackSelector::EtaBinnedConfig &trackSelectorCfg,
308 const Acts::GeometryContext &tgContext,
309 const detail::MeasurementIndex &measurementIndex,
310 const std::size_t typeIndex,
311 EventStats::value_type &event_stat_category_i) const {
312 if (m_addCounts) {
313 updateCounts(track, trackState.typeFlags(),
314 measurementType(trackState));
315 if (m_checkCounts) {
316 checkCounts(track);
317 }
318 }
319
320 if (m_trackStatePrinter.isSet()) {
321 m_trackStatePrinter->printTrackState(tgContext, trackState,
322 measurementIndex, true);
323 }
324
325 if (!m_doBranchStopper) {
326 return BranchStopperResult::Continue;
327 }
328
329 const auto &parameters = trackState.hasFiltered() ? trackState.filtered()
330 : trackState.predicted();
331 double eta = -std::log(std::tan(0.5 * parameters[Acts::eBoundTheta]));
332 const auto &cutSet = getCuts(eta);
333
334 if (typeIndex < m_ptMinMeasurements.size() &&
335 !(track.nMeasurements() < m_ptMinMeasurements[typeIndex])) {
336 double pT = std::sin(parameters[Acts::eBoundTheta]) /
337 parameters[Acts::eBoundQOverP];
338 if (std::abs(pT) < cutSet.ptMin * m_branchStopperPtMinFactor) {
339 ++event_stat_category_i[kNStoppedTracksMinPt];
340 ATH_MSG_DEBUG("CkfBranchStopper: drop branch with q*pT="
341 << pT << " after " << track.nMeasurements()
342 << " measurements");
343 return BranchStopperResult::StopAndDrop;
344 }
345 }
346
347 if (typeIndex < m_absEtaMaxMeasurements.size() &&
348 !(track.nMeasurements() < m_absEtaMaxMeasurements[typeIndex]) &&
349 !(std::abs(eta) < trackSelectorCfg.absEtaEdges.back() +
351 ++event_stat_category_i[kNStoppedTracksMaxEta];
352 ATH_MSG_DEBUG("CkfBranchStopper: drop branch with eta="
353 << eta << " after " << track.nMeasurements()
354 << " measurements");
355 return BranchStopperResult::StopAndDrop;
356 }
357
358
359 // In the pixel endcap regions relax the requirement for minMeasurements before cutting the branch off
360 auto minMeasurementsBranchStop = std::abs(eta) > m_branchStopperAbsEtaMeasCut ? cutSet.minMeasurements - m_branchStopperMeasCutReduce : cutSet.minMeasurements;
361 bool enoughMeasurements = (track.nMeasurements() >= minMeasurementsBranchStop);
362 bool tooManyHoles = (track.nHoles() > cutSet.maxHoles);
363 bool tooManyOutliers = (track.nOutliers() > cutSet.maxOutliers);
364
365 if (m_addCounts) {
366 auto [enoughMeasurementsPS, tooManyHolesPS, tooManyOutliersPS] =
367 selectCounts(track, eta);
368 enoughMeasurements = enoughMeasurements && enoughMeasurementsPS;
369 tooManyHoles = tooManyHoles || tooManyHolesPS;
370 tooManyOutliers = tooManyOutliers || tooManyOutliersPS;
371 }
372
373 if (!(tooManyHoles || tooManyOutliers)) {
374 return BranchStopperResult::Continue;
375 }
376
377 if (!enoughMeasurements) {
378 ++event_stat_category_i[kNStoppedTracksMaxHoles];
379 }
380
381 if (m_addCounts) {
382 ATH_MSG_DEBUG("CkfBranchStopper: stop and "
383 << (enoughMeasurements ? "keep" : "drop")
384 << " branch with nHoles=" << track.nHoles() << " ("
385 << s_branchState.nPixelHoles(track) << " pixel+"
386 << s_branchState.nStripHoles(track) << " strip+"
387 << s_branchState.nHgtdHoles(track)
388 << " hgtd), nOutliers=" << track.nOutliers() << " ("
389 << s_branchState.nPixelOutliers(track) << "+"
390 << s_branchState.nStripOutliers(track) << "+"
391 << s_branchState.nHgtdOutliers(track)
392 << "), nMeasurements=" << track.nMeasurements() << " ("
393 << s_branchState.nPixelHits(track) << "+"
394 << s_branchState.nStripHits(track) << "+"
395 << s_branchState.nHgtdHits(track) << ")");
396 } else {
397 ATH_MSG_DEBUG("CkfBranchStopper: stop and "
398 << (enoughMeasurements ? "keep" : "drop")
399 << " branch with nHoles=" << track.nHoles()
400 << ", nOutliers=" << track.nOutliers()
401 << ", nMeasurements=" << track.nMeasurements());
402 }
403
404 return enoughMeasurements ? BranchStopperResult::StopAndKeep
405 : BranchStopperResult::StopAndDrop;
406 }
407
408
410 {
411 tracksContainer.addColumn<unsigned int>("nPixelHits");
412 tracksContainer.addColumn<unsigned int>("nStripHits");
413 tracksContainer.addColumn<unsigned int>("nHgtdHits");
414 tracksContainer.addColumn<unsigned int>("nPixelHoles");
415 tracksContainer.addColumn<unsigned int>("nStripHoles");
416 tracksContainer.addColumn<unsigned int>("nHgtdHoles");
417 tracksContainer.addColumn<unsigned int>("nPixelOutliers");
418 tracksContainer.addColumn<unsigned int>("nStripOutliers");
419 tracksContainer.addColumn<unsigned int>("nHgtdOutliers");
420 }
421
422 void TrackFindingBaseAlg::initCounts(const detail::RecoTrackContainer::TrackProxy &track)
423 {
424 s_branchState.nPixelHits(track) = 0;
425 s_branchState.nStripHits(track) = 0;
426 s_branchState.nHgtdHits(track) = 0;
427 s_branchState.nPixelHoles(track) = 0;
428 s_branchState.nStripHoles(track) = 0;
429 s_branchState.nHgtdHoles(track) = 0;
430 s_branchState.nPixelOutliers(track) = 0;
431 s_branchState.nStripOutliers(track) = 0;
432 s_branchState.nHgtdOutliers(track) = 0;
433 }
434
436 const detail::RecoTrackContainer::TrackProxy &track,
437 Acts::ConstTrackStateTypeMap typeFlags, xAOD::UncalibMeasType detType) {
439 if (typeFlags.isHole()) {
440 s_branchState.nPixelHoles(track)++;
441 } else if (typeFlags.isOutlier()) {
442 s_branchState.nPixelOutliers(track)++;
443 } else if (typeFlags.isMeasurement()) {
444 s_branchState.nPixelHits(track)++;
445 }
446 } else if (detType == xAOD::UncalibMeasType::StripClusterType) {
447 if (typeFlags.isHole()) {
448 s_branchState.nStripHoles(track)++;
449 } else if (typeFlags.isOutlier()) {
450 s_branchState.nStripOutliers(track)++;
451 } else if (typeFlags.isMeasurement()) {
452 s_branchState.nStripHits(track)++;
453 }
454 } else if (detType == xAOD::UncalibMeasType::HGTDClusterType) {
455 if (typeFlags.isHole()) {
456 s_branchState.nHgtdHoles(track)++;
457 } else if (typeFlags.isOutlier()) {
458 s_branchState.nHgtdOutliers(track)++;
459 } else if (typeFlags.isMeasurement()) {
460 s_branchState.nHgtdHits(track)++;
461 }
462 }
463 }
464
465 void TrackFindingBaseAlg::checkCounts(const detail::RecoTrackContainer::TrackProxy &track) const {
466 // This check will fail if there are other types (HGTD, MS?) of hits, holes, or outliers.
467 // The check can be removed when it is no longer appropriate.
468 if (track.nMeasurements() != s_branchState.nPixelHits(track) + s_branchState.nStripHits(track) + s_branchState.nHgtdHits(track))
469 ATH_MSG_WARNING("mismatched hit count: total (" << track.nMeasurements()
470 << ") != pixel (" << s_branchState.nPixelHits(track)
471 << ") + strip (" << s_branchState.nStripHits(track)
472 << ") + hgtd (" << s_branchState.nHgtdHits(track)
473 << ")");
474 if (track.nHoles() != s_branchState.nPixelHoles(track) + s_branchState.nStripHoles(track) + s_branchState.nHgtdHoles(track))
475 ATH_MSG_WARNING("mismatched hole count: total (" << track.nHoles()
476 << ") < pixel (" << s_branchState.nPixelHoles(track)
477 << ") + strip (" << s_branchState.nStripHoles(track)
478 << ") + hgtd (" << s_branchState.nHgtdHoles(track)
479 << ")");
480 if (track.nOutliers() != s_branchState.nPixelOutliers(track) + s_branchState.nStripOutliers(track) + s_branchState.nHgtdOutliers(track))
481 ATH_MSG_WARNING("mismatched outlier count: total (" << track.nOutliers()
482 << ") != pixel (" << s_branchState.nPixelOutliers(track)
483 << ") + strip (" << s_branchState.nStripOutliers(track)
484 << ") + hgtd (" << s_branchState.nHgtdOutliers(track)
485 << ")");
486 };
487
488 std::array<bool, 3> TrackFindingBaseAlg::selectCounts(const detail::RecoTrackContainer::TrackProxy &track, double eta) const {
489 bool enoughMeasurements = true, tooManyHoles = false, tooManyOutliers = false;
490 const auto &trackSelectorCfg = trackFinder().trackSelector.config();
491 std::size_t etaBin = (std::abs(eta) < trackSelectorCfg.absEtaEdges.front()) ? 0
492 : (std::abs(eta) >= trackSelectorCfg.absEtaEdges.back()) ? trackSelectorCfg.absEtaEdges.size() - 1
493 : trackSelectorCfg.binIndex(eta);
494 auto cutMin = [etaBin](std::size_t val, const std::vector<std::size_t> &cutSet) {
495 return !cutSet.empty() && (val < (etaBin < cutSet.size() ? cutSet[etaBin] : cutSet.back()));
496 };
497 auto cutMax = [etaBin](std::size_t val, const std::vector<std::size_t> &cutSet) {
498 return !cutSet.empty() && (val > (etaBin < cutSet.size() ? cutSet[etaBin] : cutSet.back()));
499 };
500
501 enoughMeasurements = enoughMeasurements && !cutMin(s_branchState.nPixelHits(track), m_minPixelHits);
502 enoughMeasurements = enoughMeasurements && !cutMin(s_branchState.nStripHits(track), m_minStripHits);
503 enoughMeasurements = enoughMeasurements && !cutMin(s_branchState.nHgtdHits(track), m_minHgtdHits);
504 tooManyHoles = tooManyHoles || cutMax(s_branchState.nPixelHoles(track), m_maxPixelHoles);
505 tooManyHoles = tooManyHoles || cutMax(s_branchState.nStripHoles(track), m_maxStripHoles);
506 tooManyHoles = tooManyHoles || cutMax(s_branchState.nHgtdHoles(track), m_maxHgtdHoles);
507 tooManyOutliers = tooManyOutliers || cutMax(s_branchState.nPixelOutliers(track), m_maxPixelOutliers);
508 tooManyOutliers = tooManyOutliers || cutMax(s_branchState.nStripOutliers(track), m_maxStripOutliers);
509 tooManyOutliers = tooManyOutliers || cutMax(s_branchState.nHgtdOutliers(track), m_maxHgtdOutliers);
510
511 return {enoughMeasurements, tooManyHoles, tooManyOutliers};
512 }
513
515 std::vector<std::pair<float, float> > &chi2CutOffOutlier = m_measurementSelectorConfig.m_chi2CutOffOutlier;
516 chi2CutOffOutlier .reserve( m_chi2CutOff.size() );
517 if (!m_chi2OutlierCutOff.empty()) {
518 if (m_chi2CutOff.size() != m_chi2OutlierCutOff.size()) {
519 ATH_MSG_ERROR("Outlier chi2 cut off provided but number of elements does not agree with"
520 " chi2 cut off for measurements which however is required: "
521 << m_chi2CutOff.size() << " != " << m_chi2OutlierCutOff.size());
522 return StatusCode::FAILURE;
523 }
524 }
525 unsigned int idx=0;
526 for (const auto &elm : m_chi2CutOff) {
527 chi2CutOffOutlier.push_back( std::make_pair(static_cast<float>(elm),
528 idx < m_chi2OutlierCutOff.size()
529 ? static_cast<float>(m_chi2OutlierCutOff[idx])
530 : std::numeric_limits<float>::max()) );
531 ++idx;
532 }
533 if (m_etaBins.size() > 2) {
534 std::vector<float> &etaBinsf = m_measurementSelectorConfig.m_etaBins;
535 etaBinsf.assign(m_etaBins.begin() + 1, m_etaBins.end() - 1);
536 }
537
538 return /*m_measurementSelector ?*/ StatusCode::SUCCESS /*: StatusCode::FAILURE*/;
539 }
540
541 // === Statistics printout =================================================
542
544 if (!m_statEtaBins.empty())
545 {
547 float last_eta = m_statEtaBins[0];
548 for (float eta : m_statEtaBins)
549 {
550 if (eta < last_eta)
551 {
552 ATH_MSG_FATAL("Eta bins for statistics counter not in ascending order.");
553 }
554 last_eta = eta;
555 }
556 }
557 m_stat.resize(nSeedCollections() * seedCollectionStride());
558 }
559
560 // copy statistics
561 void TrackFindingBaseAlg::copyStats(const EventStats &event_stat) const {
562 std::lock_guard<std::mutex> lock(m_mutex);
563 std::size_t category_i = 0;
564 for (const std::array<unsigned int, kNStat> &src_stat : event_stat)
565 {
566 std::array<std::size_t, kNStat> &dest_stat = m_stat[category_i++];
567 for (std::size_t i = 0; i < src_stat.size(); ++i)
568 {
569 assert(i < dest_stat.size());
570 dest_stat[i] += src_stat[i];
571 }
572 }
573 }
574
575 // print statistics
577 if (msgLvl(MSG::INFO))
578 {
579 std::vector<std::string> stat_labels =
581 {
582 std::make_pair(kNTotalSeeds, "Input seeds"),
583 std::make_pair(kNoTrackParam, "No track parameters"),
584 std::make_pair(kNUsedSeeds, "Used seeds"),
585 std::make_pair(kNoTrack, "Cannot find track"),
586 std::make_pair(kNDuplicateSeeds, "Duplicate seeds"),
587 std::make_pair(kNNoEstimatedParams, "Initial param estimation failed"),
588 std::make_pair(kNRejectedRefinedSeeds, "Rejected refined parameters"),
589 std::make_pair(kNOutputTracks, "CKF tracks"),
590 std::make_pair(kNSelectedTracks, "selected tracks"),
591 std::make_pair(kNResolvedTracks, "resolved tracks"),
592 std::make_pair(kNStoppedTracksMaxHoles, "Stopped tracks reaching max holes"),
593 std::make_pair(kMultipleBranches, "Seeds with more than one branch"),
594 std::make_pair(kNoSecond, "Tracks failing second CKF"),
595 std::make_pair(kNStoppedTracksMinPt, "Stopped tracks below pT cut"),
596 std::make_pair(kNStoppedTracksMaxEta, "Stopped tracks above max eta"),
597 std::make_pair(kNTotalSharedHits, "Total shared hits"),
598 std::make_pair(kNForcedSeedMeasurements, "Total forced measurements")
599 });
600 assert(stat_labels.size() == kNStat);
601 std::vector<std::string> categories;
602 categories.reserve(m_seedLabels.size() + 1);
603 categories.insert(categories.end(), m_seedLabels.begin(), m_seedLabels.end());
604 categories.push_back("ALL");
605
606 std::vector<std::string> eta_labels;
607 eta_labels.reserve(m_statEtaBins.size() + 2);
608 for (std::size_t eta_bin_i = 0; eta_bin_i < m_statEtaBins.size() + 2; ++eta_bin_i)
609 {
610 eta_labels.push_back(TableUtils::makeEtaBinLabel(m_statEtaBins, eta_bin_i, m_useAbsEtaForStat));
611 }
612
613 // vector used as 3D array stat[ eta_bin ][ stat_i ][ seed_type]
614 // stat_i = [0, kNStat)
615 // eta_bin = [0, m_statEtaBins.size()+2 ); eta_bin == m_statEtaBinsSize()+1 means sum of all etaBins
616 // seed_type = [0, nSeedCollections()+1) seed_type == nSeedCollections() means sum of all seed collections
617 std::vector<std::size_t> stat =
619 m_statEtaBins.size() + 1,
620 m_stat);
621
622 // the extra columns and rows for the projections are addeded internally:
623 std::size_t stat_stride =
625 m_statEtaBins.size() + 1,
626 kNStat);
627 std::size_t eta_stride =
629 m_statEtaBins.size() + 1,
630 kNStat);
631 std::stringstream table_out;
632
633 if (m_dumpAllStatEtaBins.value())
634 {
635 // dump for each counter a table with one row per eta bin
636 std::size_t max_label_width = TableUtils::maxLabelWidth(stat_labels) + TableUtils::maxLabelWidth(eta_labels);
637 for (std::size_t stat_i = 0; stat_i < kNStat; ++stat_i)
638 {
639 std::size_t dest_idx_offset = stat_i * stat_stride;
640 table_out << makeTable(stat, dest_idx_offset, eta_stride,
641 eta_labels,
642 categories)
643 .columnWidth(10)
644 // only dump the footer for the last eta bin i.e. total
645 .dumpHeader(stat_i == 0)
646 .dumpFooter(stat_i + 1 == kNStat)
647 .separateLastRow(true) // separate the sum of all eta bins
648 .minLabelWidth(max_label_width)
649 .labelPrefix(stat_labels.at(stat_i));
650 }
651 }
652 else
653 {
654 // dump one table with one row per counter showing the total eta range
655 for (std::size_t eta_bin_i = (m_dumpAllStatEtaBins.value() ? 0 : m_statEtaBins.size() + 1);
656 eta_bin_i < m_statEtaBins.size() + 2;
657 ++eta_bin_i)
658 {
659 std::size_t dest_idx_offset = eta_bin_i * eta_stride;
660 table_out << makeTable(stat, dest_idx_offset, stat_stride,
661 stat_labels,
662 categories,
663 eta_labels.at(eta_bin_i))
664 .columnWidth(10)
665 // only dump the footer for the last eta bin i.e. total
666 .dumpFooter(!m_dumpAllStatEtaBins.value() || eta_bin_i == m_statEtaBins.size() + 1);
667 }
668 }
669 ATH_MSG_INFO("statistics:\n"
670 << table_out.str());
671 table_out.str("");
672
673 // define retios first element numerator, second element denominator
674 // each element contains a vector of counter and a multiplier e.g. +- 1
675 // ratios are computed as (sum_i stat[stat_i] * multiplier_i ) / (sum_j stat[stat_j] * multiplier_j )
676 auto [ratio_labels, ratio_def] =
678 std::vector<TableUtils::SummandDefinition>{
682 // no track counted as used but want to include it as failed
684 }, // failed seeds i.e. seeds which are not duplicates but did not produce a track
685 std::vector<TableUtils::SummandDefinition>{TableUtils::defineSummand(kNTotalSeeds, 1)}),
687 TableUtils::defineSimpleRatio("Rejected refined params / seeds", kNRejectedRefinedSeeds, kNTotalSeeds),
689 TableUtils::defineSimpleRatio("selected tracks / used seeds", kNSelectedTracks, kNUsedSeeds),
691 TableUtils::defineSimpleRatio("resolved tracks / used seeds", kNResolvedTracks, kNUsedSeeds),
692 TableUtils::defineSimpleRatio("branched tracks / used seeds", kMultipleBranches, kNUsedSeeds),
693 TableUtils::defineSimpleRatio("no 2nd CKF / CKF tracks", kNoSecond, kNOutputTracks),
695 TableUtils::defineSimpleRatio("forced measurements / used seeds", kNForcedSeedMeasurements, kNUsedSeeds)});
696
697 std::vector<float> ratio = TableUtils::computeRatios(ratio_def,
698 nSeedCollections() + 1,
699 m_statEtaBins.size() + 2,
700 stat);
701
702 // the extra columns and rows for the projections are _not_ added internally
703 std::size_t ratio_stride = TableUtils::ratioStride(nSeedCollections() + 1,
704 m_statEtaBins.size() + 2,
705 ratio_def);
706 std::size_t ratio_eta_stride = TableUtils::subCategoryStride(nSeedCollections() + 1,
707 m_statEtaBins.size() + 2,
708 ratio_def);
709
710 std::size_t max_label_width = TableUtils::maxLabelWidth(ratio_labels) + TableUtils::maxLabelWidth(eta_labels);
711 if (m_dumpAllStatEtaBins.value())
712 {
713 // show for each ratio a table with one row per eta bin
714 for (std::size_t ratio_i = 0; ratio_i < ratio_labels.size(); ++ratio_i)
715 {
716 table_out << makeTable(ratio,
717 ratio_i * ratio_stride,
718 ratio_eta_stride,
719 eta_labels,
720 categories)
721 .columnWidth(10)
722 // only dump the footer for the last eta bin i.e. total
723 .dumpHeader(ratio_i == 0)
724 .dumpFooter(ratio_i + 1 == ratio_labels.size())
725 .separateLastRow(true) // separate the sum of las
726 .minLabelWidth(max_label_width)
727 .labelPrefix(ratio_labels.at(ratio_i));
728 }
729 }
730 else
731 {
732 // dump one table with one row per ratio showing the total eta range
733 table_out << makeTable(ratio,
734 (m_statEtaBins.size() + 1) * ratio_eta_stride + 0 * ratio_stride,
735 ratio_stride,
736 ratio_labels,
737 categories)
738 .columnWidth(10)
739 // only dump the footer for the last eta bin i.e. total
740 .minLabelWidth(max_label_width)
741 .dumpFooter(false);
742
743 // also dump a table for final tracks over used seeds (ratio_i==6 or 4) showing one row per eta bin
744 eta_labels.erase(eta_labels.end() - 1); // drop last line of table which shows again all eta bins summed.
745 std::size_t ratio_i = m_showResolvedStats ? 6 : 4;
746 table_out << makeTable(ratio,
747 ratio_i * ratio_stride,
748 ratio_eta_stride,
749 eta_labels,
750 categories)
751 .columnWidth(10)
752 .dumpHeader(false)
753 // only dump the footer for the last eta bin i.e. total
754 .dumpFooter(!m_dumpAllStatEtaBins.value() || ratio_i + 1 == ratio_labels.size())
755 .separateLastRow(false)
756 .minLabelWidth(max_label_width)
757 .labelPrefix(ratio_labels.at(ratio_i));
758 }
759
760 ATH_MSG_INFO("Ratios:\n"
761 << table_out.str());
762 }
763 }
764
765 std::size_t TrackFindingBaseAlg::getStatCategory(std::size_t seed_collection, float eta) const {
766 std::vector<float>::const_iterator bin_iter = std::upper_bound(m_statEtaBins.begin(),
767 m_statEtaBins.end(),
768 m_useAbsEtaForStat ? std::abs(eta) : eta);
769 std::size_t category_i = seed_collection * seedCollectionStride() + static_cast<std::size_t>(bin_iter - m_statEtaBins.begin());
770 assert(category_i < m_stat.size());
771 return category_i;
772 }
773
774 std::size_t TrackFindingBaseAlg::computeStatSum(std::size_t seed_collection, EStat counter_i, const EventStats &stat) const {
775 std::size_t out = 0u;
776 for (std::size_t category_i = seed_collection * seedCollectionStride();
777 category_i < (seed_collection + 1) * seedCollectionStride();
778 ++category_i)
779 {
780 assert(category_i < stat.size());
781 out += stat[category_i][counter_i];
782 }
783 return out;
784 }
785
786 bool TrackFindingBaseAlg::selectCountsFinal(const detail::RecoTrackContainer::TrackProxy &track) const {
787 if (not m_addCounts) return true;
788 double eta = -std::log(std::tan(0.5 * track.theta()));
789 auto [enoughMeasurementsPS, tooManyHolesPS, tooManyOutliersPS] = selectCounts(track, eta);
790 return enoughMeasurementsPS && !tooManyHolesPS && !tooManyOutliersPS;
791 }
792
793} // namespace ActsTrk
Scalar eta() const
pseudorapidity method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
TableUtils::StatTable< T > makeTable(const std::array< T, N > &counter, const std::array< std::string, N > &label)
Definition TableUtils.h:543
std::unique_ptr< const Acts::Logger > makeActsAthenaLogger(IMessageSvc *svc, const std::string &name, int level, std::optional< std::string > parent_name)
base class interface providing the bare minimal interface extension.
Gaudi::Property< std::vector< std::size_t > > m_maxStripHoles
Gaudi::Property< double > m_branchStopperAbsEtaMeasCut
Gaudi::Property< std::vector< float > > m_statEtaBins
Gaudi::Property< double > m_branchStopperPtMinFactor
Gaudi::Property< std::vector< std::size_t > > m_maxOutliers
Gaudi::Property< std::vector< std::size_t > > m_maxHgtdHoles
std::unique_ptr< const Acts::Logger > m_logger
logging instance
Gaudi::Property< std::vector< double > > m_etaBins
Gaudi::Property< bool > m_doTwoWay
Gaudi::Property< bool > m_dumpAllStatEtaBins
Gaudi::Property< std::vector< size_t > > m_numMeasurementsCutOff
Gaudi::Property< std::vector< std::size_t > > m_maxSharedHits
Gaudi::Property< unsigned int > m_maxPropagationStep
static xAOD::UncalibMeasType measurementType(const detail::RecoTrackContainer::TrackStateProxy &trackState)
ToolHandle< ActsTrk::TrackStatePrinterTool > m_trackStatePrinter
Gaudi::Property< double > m_edgeHoleBorderWidth
Gaudi::Property< std::vector< double > > m_etaMax
Gaudi::Property< std::vector< double > > m_ptMin
Gaudi::Property< std::vector< std::size_t > > m_minPixelHits
Gaudi::Property< std::vector< std::size_t > > m_maxStripOutliers
SG::WriteHandleKey< ActsTrk::TrackContainer > m_trackContainerKey
Gaudi::Property< std::vector< double > > m_ptMax
Gaudi::Property< std::vector< double > > m_chi2CutOff
detail::RecoTrackContainer::TrackProxy TrkProxy
Gaudi::Property< std::vector< std::size_t > > m_maxPixelHoles
static constexpr BranchState s_branchState
void copyStats(const EventStats &event_stat) const
Gaudi::Property< std::vector< double > > m_phiMin
Gaudi::Property< double > m_branchStopperMeasCutReduce
ToolHandle< ActsTrk::IPixelOnTrackCalibratorTool< detail::RecoTrackStateContainer > > m_pixelCalibTool
Gaudi::Property< std::vector< std::uint32_t > > m_endOfWorldVolumeIds
Gaudi::Property< std::vector< std::size_t > > m_minStripHits
ActsTrk::MutableTrackContainerHandlesHelper m_tracksBackendHandlesHelper
std::size_t getStatCategory(std::size_t seed_collection, float eta) const
std::size_t seedCollectionStride() const
Gaudi::Property< double > m_branchStopperAbsEtaMaxExtra
ToolHandle< GenericMonitoringTool > m_monTool
static void addCounts(detail::RecoTrackContainer &tracksContainer)
std::vector< typename detail::RecoTrackContainer::TrackProxy > doTwoWayTrackFinding(const detail::RecoTrackStateContainerProxy &firstMeasurement, const TrkProxy &trackProxy, detail::RecoTrackContainer &tracksContainerTemp, const TrackFinderOptions &options) const
Perform two-way track finding.
Gaudi::Property< std::vector< std::size_t > > m_absEtaMaxMeasurements
TrackFindingBaseAlg(const std::string &name, ISvcLocator *pSvcLocator)
Gaudi::Property< std::vector< double > > m_etaMin
Gaudi::Property< std::vector< double > > m_d0Min
virtual StatusCode execute(const EventContext &ctx) const override
PublicToolHandle< ActsTrk::ITrackingGeometryTool > m_trackingGeometryTool
ToolHandle< ActsTrk::IActsToTrkConverterTool > m_ATLASConverterTool
Gaudi::Property< std::vector< std::size_t > > m_maxHgtdOutliers
Gaudi::Property< std::vector< double > > m_z0Max
Gaudi::Property< double > m_absEtaMax
ToolHandle< ActsTrk::IExtrapolationTool > m_extrapolationTool
std::size_t computeStatSum(std::size_t seed_collection, EStat counter_i, const EventStats &stat) const
virtual StatusCode initialize() override
Gaudi::Property< std::vector< double > > m_z0Min
void checkCounts(const detail::RecoTrackContainer::TrackProxy &track) const
Gaudi::Property< bool > m_doBranchStopper
Gaudi::Property< std::vector< std::size_t > > m_minMeasurements
Gaudi::Property< std::vector< double > > m_maxChi2
const Acts::Logger & logger() const
Private access to the logger.
Gaudi::Property< double > m_absEtaMin
BranchStopperResult stopBranch(const detail::RecoTrackContainer::TrackProxy &track, const detail::RecoTrackContainer::TrackStateProxy &trackState, const Acts::TrackSelector::EtaBinnedConfig &trackSelectorCfg, const Acts::GeometryContext &tgContext, const detail::MeasurementIndex &measurementIndex, const std::size_t typeIndex, EventStats::value_type &event_stat_category_i) const
Branch stopper.
static void initCounts(const detail::RecoTrackContainer::TrackProxy &track)
Gaudi::Property< std::vector< std::size_t > > m_maxPixelOutliers
const Acts::TrackSelector::Config & getCuts(double eta) const
Retrieves track selector configuration for given eta value.
Gaudi::Property< bool > m_checkCounts
Gaudi::Property< std::vector< std::size_t > > m_maxHoles
ToolHandle< ActsTrk::IStripOnTrackCalibratorTool< detail::RecoTrackStateContainer > > m_stripCalibTool
std::array< bool, 3 > selectCounts(const detail::RecoTrackContainer::TrackProxy &track, double eta) const
std::unique_ptr< CKF_pimpl > m_trackFinder
TrackFindingDefaultOptions getDefaultOptions(const EventContext &ctx, const DetectorContextHolder &detContext, const detail::TrackFindingMeasurements &measurements, const Acts::PerigeeSurface *pSurface) const
Get CKF options for first and second pass + pointer to MeasurementSelector.
Acts::CombinatorialKalmanFilterOptions< detail::RecoTrackContainer > TrackFinderOptions
virtual StatusCode finalize() override
std::vector< std::array< unsigned int, kNStat > > EventStats
ToolHandle< ActsTrk::IHGTDOnTrackCalibratorTool< detail::RecoTrackStateContainer > > m_hgtdCalibTool
detail::xAODUncalibMeasSurfAcc m_unalibMeasSurfAcc
Gaudi::Property< double > m_twoWayinflateCovarianceFactor
static void updateCounts(const detail::RecoTrackContainer::TrackProxy &track, Acts::ConstTrackStateTypeMap typeFlags, xAOD::UncalibMeasType detType)
Gaudi::Property< bool > m_addCounts
Gaudi::Property< std::vector< std::size_t > > m_minHgtdHits
struct ActsTrk::TrackFindingBaseAlg::MeasurementSelectorConfig m_measurementSelectorConfig
Gaudi::Property< std::vector< double > > m_phiMax
Gaudi::Property< std::vector< std::size_t > > m_ptMinMeasurements
Gaudi::Property< std::vector< double > > m_d0Max
ToolHandle< ActsTrk::IFitterTool > m_fitterTool
Gaudi::Property< bool > m_inflateCovarianceTwoWay
Gaudi::Property< std::vector< double > > m_chi2OutlierCutOff
Acts::CombinatorialKalmanFilterBranchStopperResult BranchStopperResult
std::unique_ptr< ActsTrk::IMeasurementSelector > setMeasurementSelector(const EventContext &ctx, const detail::TrackFindingMeasurements &measurements, TrackFinderOptions &options) const
Setup and attach measurement selector to KF options.
bool selectCountsFinal(const detail::RecoTrackContainer::TrackProxy &track) const
Gaudi::Property< std::vector< std::string > > m_seedLabels
const MeasurementRangeList & measurementRanges() const
Helper class to access the Acts::surface associated with an Uncalibrated xAOD measurement.
bool msgLvl(const MSG::Level lvl) const
An algorithm that can be simultaneously executed in multiple threads.
Acts::Result< void > gainMatrixUpdate(const Acts::GeometryContext &gctx, typename trajectory_t::TrackStateProxy trackState, const Acts::Logger &logger)
Acts::SympyStepper Stepper
Adapted from Acts Examples/Algorithms/TrackFinding/src/TrackFindingAlgorithmFunction....
RecoTrackStateContainer::TrackStateProxy RecoTrackStateContainerProxy
Acts::TrackContainer< Acts::VectorTrackContainer, Acts::VectorMultiTrajectory > RecoTrackContainer
RecoTrackStateContainer::ConstTrackStateProxy RecoConstTrackStateContainerProxy
Acts::CombinatorialKalmanFilter< Propagator, RecoTrackContainer > CKF
std::unique_ptr< ActsTrk::IMeasurementSelector > getMeasurementSelector(const EventContext &ctx, const ActsTrk::IPixelOnBoundStateCalibratorTool *pixelOnTrackCalibratorTool, const ActsTrk::IStripOnBoundStateCalibratorTool *stripOnTrackCalibratorTool, const ActsTrk::IHGTDOnBoundStateCalibratorTool *hgtdOnTrackCalibratorTool, const ActsTrk::detail::MeasurementRangeList &measurementRanges, const std::vector< float > &etaBinsf, const std::vector< std::pair< float, float > > &chi2CutOffOutlier, const std::vector< size_t > &numMeasurementsCutOff, double edge_hole_border_width)
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
std::string prefixFromTrackContainerName(const std::string &tracks)
Parse TrackContainer name to get the prefix for backends The name has to contain XYZTracks,...
@ Pixel
Inner detector legacy.
std::tuple< std::vector< std::string >, std::vector< RatioDefinition > > splitRatioDefinitionsAndLabels(std::initializer_list< std::tuple< std::string, RatioDefinition > > a_ratio_list)
Definition TableUtils.h:468
SummandDefinition defineSummand(T counter_idx, int multiplier)
Definition TableUtils.h:422
std::size_t maxLabelWidth(const T_Collection &col)
Definition TableUtils.h:310
RatioDefinition defineSimpleRatio(T numerator, T denominator)
Definition TableUtils.h:404
std::vector< std::string > makeLabelVector(T_index n_entries, std::initializer_list< std::pair< T_index, T_string > > a_list)
Definition TableUtils.h:295
constexpr std::size_t subCategoryStride(const std::size_t categories, const std::size_t sub_categories, const std::size_t n_counter)
Definition TableUtils.h:324
constexpr std::size_t counterStride(const std::size_t categories, const std::size_t sub_categories, const std::size_t n_counter)
Definition TableUtils.h:329
std::string makeEtaBinLabel(const std::vector< float > &eta_bins, std::size_t eta_bin_i, bool abs_eta=false)
Definition TableUtils.h:534
std::tuple< std::string, RatioDefinition > makeRatioDefinition(std::string &&name, std::vector< SummandDefinition > &&numerator, std::vector< SummandDefinition > &&denominator)
Definition TableUtils.h:458
std::vector< float > computeRatios(const std::vector< RatioDefinition > &ratio_def, const std::size_t categories, const std::size_t sub_categories, const std::vector< std::size_t > &counter)
constexpr std::size_t ratioStride(const std::size_t categories, const std::size_t sub_categories, const std::vector< RatioDefinition > &ratio_def)
Definition TableUtils.h:493
std::vector< T_Output > createCounterArrayWithProjections(const std::size_t categories, const std::size_t sub_categories, const std::vector< std::array< T_Input, N > > &input_counts)
Definition TableUtils.h:342
UncalibMeasType
Define the type of the uncalibrated measurement.
Acts::CombinatorialKalmanFilterExtensions< RecoTrackContainer > ckfExtensions