File indexing completed on 2025-10-29 07:54:27
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/TrackFinding/TrackFindingAlgorithm.hpp"
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/Direction.hpp"
0013 #include "Acts/Definitions/TrackParametrization.hpp"
0014 #include "Acts/EventData/MultiTrajectory.hpp"
0015 #include "Acts/EventData/ProxyAccessor.hpp"
0016 #include "Acts/EventData/SourceLink.hpp"
0017 #include "Acts/EventData/TrackContainer.hpp"
0018 #include "Acts/EventData/TrackParameters.hpp"
0019 #include "Acts/EventData/VectorMultiTrajectory.hpp"
0020 #include "Acts/EventData/VectorTrackContainer.hpp"
0021 #include "Acts/Geometry/GeometryIdentifier.hpp"
0022 #include "Acts/Propagator/MaterialInteractor.hpp"
0023 #include "Acts/Propagator/Navigator.hpp"
0024 #include "Acts/Propagator/Propagator.hpp"
0025 #include "Acts/Propagator/StandardAborters.hpp"
0026 #include "Acts/Propagator/SympyStepper.hpp"
0027 #include "Acts/Surfaces/PerigeeSurface.hpp"
0028 #include "Acts/Surfaces/Surface.hpp"
0029 #include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp"
0030 #include "Acts/TrackFinding/TrackStateCreator.hpp"
0031 #include "Acts/TrackFitting/GainMatrixUpdater.hpp"
0032 #include "Acts/Utilities/Enumerate.hpp"
0033 #include "Acts/Utilities/Logger.hpp"
0034 #include "Acts/Utilities/TrackHelpers.hpp"
0035 #include "ActsExamples/EventData/IndexSourceLink.hpp"
0036 #include "ActsExamples/EventData/Measurement.hpp"
0037 #include "ActsExamples/EventData/MeasurementCalibration.hpp"
0038 #include "ActsExamples/EventData/SimSeed.hpp"
0039 #include "ActsExamples/EventData/Track.hpp"
0040 #include "ActsExamples/Framework/AlgorithmContext.hpp"
0041 #include "ActsExamples/Framework/ProcessCode.hpp"
0042
0043 #include <cmath>
0044 #include <functional>
0045 #include <memory>
0046 #include <optional>
0047 #include <ostream>
0048 #include <stdexcept>
0049 #include <system_error>
0050 #include <unordered_map>
0051 #include <utility>
0052
0053 #include <boost/functional/hash.hpp>
0054
0055
0056
0057 template <class T, std::size_t N>
0058 struct std::hash<std::array<T, N>> {
0059 std::size_t operator()(const std::array<T, N>& array) const {
0060 std::hash<T> hasher;
0061 std::size_t result = 0;
0062 for (auto&& element : array) {
0063 boost::hash_combine(result, hasher(element));
0064 }
0065 return result;
0066 }
0067 };
0068
0069 namespace ActsExamples {
0070
0071 namespace {
0072
0073 class MeasurementSelector {
0074 public:
0075 using Traj = Acts::VectorMultiTrajectory;
0076
0077 explicit MeasurementSelector(Acts::MeasurementSelector selector)
0078 : m_selector(std::move(selector)) {}
0079
0080 void setSeed(const std::optional<SimSeed>& seed) { m_seed = seed; }
0081
0082 Acts::Result<std::pair<std::vector<Traj::TrackStateProxy>::iterator,
0083 std::vector<Traj::TrackStateProxy>::iterator>>
0084 select(std::vector<Traj::TrackStateProxy>& candidates, bool& isOutlier,
0085 const Acts::Logger& logger) const {
0086 if (m_seed.has_value()) {
0087 std::vector<Traj::TrackStateProxy> newCandidates;
0088
0089 for (const auto& candidate : candidates) {
0090 if (isSeedCandidate(candidate)) {
0091 newCandidates.push_back(candidate);
0092 }
0093 }
0094
0095 if (!newCandidates.empty()) {
0096 candidates = std::move(newCandidates);
0097 }
0098 }
0099
0100 return m_selector.select<Acts::VectorMultiTrajectory>(candidates, isOutlier,
0101 logger);
0102 }
0103
0104 private:
0105 Acts::MeasurementSelector m_selector;
0106 std::optional<SimSeed> m_seed;
0107
0108 bool isSeedCandidate(const Traj::TrackStateProxy& candidate) const {
0109 assert(candidate.hasUncalibratedSourceLink());
0110
0111 const Acts::SourceLink& sourceLink = candidate.getUncalibratedSourceLink();
0112
0113 for (const auto& sp : m_seed->sp()) {
0114 for (const auto& sl : sp->sourceLinks()) {
0115 if (sourceLink.get<IndexSourceLink>() == sl.get<IndexSourceLink>()) {
0116 return true;
0117 }
0118 }
0119 }
0120
0121 return false;
0122 }
0123 };
0124
0125
0126
0127 using SeedIdentifier = std::array<Index, 3>;
0128
0129
0130
0131
0132
0133 SeedIdentifier makeSeedIdentifier(const SimSeed& seed) {
0134 SeedIdentifier result;
0135
0136 for (const auto& [i, sp] : Acts::enumerate(seed.sp())) {
0137 const Acts::SourceLink& firstSourceLink = sp->sourceLinks().front();
0138 result.at(i) = firstSourceLink.get<IndexSourceLink>().index();
0139 }
0140
0141 return result;
0142 }
0143
0144
0145
0146
0147
0148 template <typename Visitor>
0149 void visitSeedIdentifiers(const TrackProxy& track, Visitor visitor) {
0150
0151 std::vector<Index> sourceLinkIndices;
0152 sourceLinkIndices.reserve(track.nMeasurements());
0153 for (const auto& trackState : track.trackStatesReversed()) {
0154 if (!trackState.hasUncalibratedSourceLink()) {
0155 continue;
0156 }
0157 const Acts::SourceLink& sourceLink = trackState.getUncalibratedSourceLink();
0158 sourceLinkIndices.push_back(sourceLink.get<IndexSourceLink>().index());
0159 }
0160
0161
0162 for (std::size_t i = 0; i < sourceLinkIndices.size(); ++i) {
0163 for (std::size_t j = i + 1; j < sourceLinkIndices.size(); ++j) {
0164 for (std::size_t k = j + 1; k < sourceLinkIndices.size(); ++k) {
0165
0166
0167 visitor({sourceLinkIndices.at(k), sourceLinkIndices.at(j),
0168 sourceLinkIndices.at(i)});
0169 }
0170 }
0171 }
0172 }
0173
0174 class BranchStopper {
0175 public:
0176 using BranchStopperResult =
0177 Acts::CombinatorialKalmanFilterBranchStopperResult;
0178
0179 struct BranchState {
0180 std::size_t nPixelHoles = 0;
0181 std::size_t nStripHoles = 0;
0182 };
0183
0184 static constexpr Acts::ProxyAccessor<BranchState> branchStateAccessor =
0185 Acts::ProxyAccessor<BranchState>(Acts::hashString("MyBranchState"));
0186
0187 mutable std::atomic<std::size_t> m_nStoppedBranches{0};
0188
0189 explicit BranchStopper(const TrackFindingAlgorithm::Config& config)
0190 : m_cfg(config) {}
0191
0192 BranchStopperResult operator()(
0193 const TrackContainer::TrackProxy& track,
0194 const TrackContainer::TrackStateProxy& trackState) const {
0195 if (!m_cfg.trackSelectorCfg.has_value()) {
0196 return BranchStopperResult::Continue;
0197 }
0198
0199 const Acts::TrackSelector::Config* singleConfig = std::visit(
0200 [&](const auto& config) -> const Acts::TrackSelector::Config* {
0201 using T = std::decay_t<decltype(config)>;
0202 if constexpr (std::is_same_v<T, Acts::TrackSelector::Config>) {
0203 return &config;
0204 } else if constexpr (std::is_same_v<
0205 T, Acts::TrackSelector::EtaBinnedConfig>) {
0206 double theta = trackState.parameters()[Acts::eBoundTheta];
0207 double eta = Acts::AngleHelpers::etaFromTheta(theta);
0208 return config.hasCuts(eta) ? &config.getCuts(eta) : nullptr;
0209 }
0210 },
0211 *m_cfg.trackSelectorCfg);
0212
0213 if (singleConfig == nullptr) {
0214 ++m_nStoppedBranches;
0215 return BranchStopperResult::StopAndDrop;
0216 }
0217
0218 bool tooManyHolesPS = false;
0219 if (!(m_cfg.pixelVolumeIds.empty() && m_cfg.stripVolumeIds.empty())) {
0220 auto& branchState = branchStateAccessor(track);
0221
0222 if (trackState.typeFlags().test(Acts::TrackStateFlag::HoleFlag) ||
0223 trackState.typeFlags().test(Acts::TrackStateFlag::OutlierFlag)) {
0224 auto volumeId = trackState.referenceSurface().geometryId().volume();
0225 if (std::find(m_cfg.pixelVolumeIds.begin(), m_cfg.pixelVolumeIds.end(),
0226 volumeId) != m_cfg.pixelVolumeIds.end()) {
0227 ++branchState.nPixelHoles;
0228 } else if (std::find(m_cfg.stripVolumeIds.begin(),
0229 m_cfg.stripVolumeIds.end(),
0230 volumeId) != m_cfg.stripVolumeIds.end()) {
0231 ++branchState.nStripHoles;
0232 }
0233 }
0234 tooManyHolesPS = branchState.nPixelHoles > m_cfg.maxPixelHoles ||
0235 branchState.nStripHoles > m_cfg.maxStripHoles;
0236 }
0237
0238 bool enoughMeasurements =
0239 track.nMeasurements() >= singleConfig->minMeasurements;
0240 bool tooManyHoles =
0241 track.nHoles() > singleConfig->maxHoles || tooManyHolesPS;
0242 bool tooManyOutliers = track.nOutliers() > singleConfig->maxOutliers;
0243 bool tooManyHolesAndOutliers = (track.nHoles() + track.nOutliers()) >
0244 singleConfig->maxHolesAndOutliers;
0245
0246 if (tooManyHoles || tooManyOutliers || tooManyHolesAndOutliers) {
0247 ++m_nStoppedBranches;
0248 return enoughMeasurements ? BranchStopperResult::StopAndKeep
0249 : BranchStopperResult::StopAndDrop;
0250 }
0251
0252 return BranchStopperResult::Continue;
0253 }
0254
0255 private:
0256 const TrackFindingAlgorithm::Config& m_cfg;
0257 };
0258
0259 }
0260
0261 TrackFindingAlgorithm::TrackFindingAlgorithm(Config config,
0262 Acts::Logging::Level level)
0263 : IAlgorithm("TrackFindingAlgorithm", level), m_cfg(std::move(config)) {
0264 if (m_cfg.inputMeasurements.empty()) {
0265 throw std::invalid_argument("Missing measurements input collection");
0266 }
0267 if (m_cfg.inputInitialTrackParameters.empty()) {
0268 throw std::invalid_argument(
0269 "Missing initial track parameters input collection");
0270 }
0271 if (m_cfg.outputTracks.empty()) {
0272 throw std::invalid_argument("Missing tracks output collection");
0273 }
0274
0275 if (m_cfg.seedDeduplication && m_cfg.inputSeeds.empty()) {
0276 throw std::invalid_argument(
0277 "Missing seeds input collection. This is "
0278 "required for seed deduplication.");
0279 }
0280 if (m_cfg.stayOnSeed && m_cfg.inputSeeds.empty()) {
0281 throw std::invalid_argument(
0282 "Missing seeds input collection. This is "
0283 "required for staying on seed.");
0284 }
0285
0286 if (m_cfg.trackSelectorCfg.has_value()) {
0287 m_trackSelector = std::visit(
0288 [](const auto& cfg) -> std::optional<Acts::TrackSelector> {
0289 return Acts::TrackSelector(cfg);
0290 },
0291 m_cfg.trackSelectorCfg.value());
0292 }
0293
0294 m_inputMeasurements.initialize(m_cfg.inputMeasurements);
0295 m_inputInitialTrackParameters.initialize(m_cfg.inputInitialTrackParameters);
0296 m_inputSeeds.maybeInitialize(m_cfg.inputSeeds);
0297 m_outputTracks.initialize(m_cfg.outputTracks);
0298 }
0299
0300 ProcessCode TrackFindingAlgorithm::execute(const AlgorithmContext& ctx) const {
0301
0302 const auto& measurements = m_inputMeasurements(ctx);
0303 const auto& initialParameters = m_inputInitialTrackParameters(ctx);
0304 const SimSeedContainer* seeds = nullptr;
0305
0306 if (m_inputSeeds.isInitialized()) {
0307 seeds = &m_inputSeeds(ctx);
0308
0309 if (initialParameters.size() != seeds->size()) {
0310 ACTS_ERROR("Number of initial parameters and seeds do not match. "
0311 << initialParameters.size() << " != " << seeds->size());
0312 }
0313 }
0314
0315
0316 auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(
0317 Acts::Vector3{0., 0., 0.});
0318
0319 PassThroughCalibrator pcalibrator;
0320 MeasurementCalibratorAdapter calibrator(pcalibrator, measurements);
0321 Acts::GainMatrixUpdater kfUpdater;
0322
0323 using Extensions = Acts::CombinatorialKalmanFilterExtensions<TrackContainer>;
0324
0325 BranchStopper branchStopper(m_cfg);
0326 MeasurementSelector measSel{
0327 Acts::MeasurementSelector(m_cfg.measurementSelectorCfg)};
0328
0329 IndexSourceLinkAccessor slAccessor;
0330 slAccessor.container = &measurements.orderedIndices();
0331
0332 using TrackStateCreatorType =
0333 Acts::TrackStateCreator<IndexSourceLinkAccessor::Iterator,
0334 TrackContainer>;
0335 TrackStateCreatorType trackStateCreator;
0336 trackStateCreator.sourceLinkAccessor
0337 .template connect<&IndexSourceLinkAccessor::range>(&slAccessor);
0338 trackStateCreator.calibrator
0339 .template connect<&MeasurementCalibratorAdapter::calibrate>(&calibrator);
0340 trackStateCreator.measurementSelector
0341 .template connect<&MeasurementSelector::select>(&measSel);
0342
0343 Extensions extensions;
0344 extensions.updater.connect<&Acts::GainMatrixUpdater::operator()<
0345 typename TrackContainer::TrackStateContainerBackend>>(&kfUpdater);
0346 extensions.branchStopper.connect<&BranchStopper::operator()>(&branchStopper);
0347 extensions.createTrackStates
0348 .template connect<&TrackStateCreatorType ::createTrackStates>(
0349 &trackStateCreator);
0350
0351 Acts::PropagatorPlainOptions firstPropOptions(ctx.geoContext,
0352 ctx.magFieldContext);
0353 firstPropOptions.maxSteps = m_cfg.maxSteps;
0354 firstPropOptions.direction = m_cfg.reverseSearch ? Acts::Direction::Backward()
0355 : Acts::Direction::Forward();
0356 firstPropOptions.constrainToVolumeIds = m_cfg.constrainToVolumeIds;
0357 firstPropOptions.endOfWorldVolumeIds = m_cfg.endOfWorldVolumeIds;
0358
0359 Acts::PropagatorPlainOptions secondPropOptions(ctx.geoContext,
0360 ctx.magFieldContext);
0361 secondPropOptions.maxSteps = m_cfg.maxSteps;
0362 secondPropOptions.direction = firstPropOptions.direction.invert();
0363 secondPropOptions.constrainToVolumeIds = m_cfg.constrainToVolumeIds;
0364 secondPropOptions.endOfWorldVolumeIds = m_cfg.endOfWorldVolumeIds;
0365
0366
0367 TrackFinderOptions firstOptions(ctx.geoContext, ctx.magFieldContext,
0368 ctx.calibContext, extensions,
0369 firstPropOptions);
0370
0371 firstOptions.targetSurface = m_cfg.reverseSearch ? pSurface.get() : nullptr;
0372
0373 TrackFinderOptions secondOptions(ctx.geoContext, ctx.magFieldContext,
0374 ctx.calibContext, extensions,
0375 secondPropOptions);
0376 secondOptions.targetSurface = m_cfg.reverseSearch ? nullptr : pSurface.get();
0377 secondOptions.skipPrePropagationUpdate = true;
0378
0379 using Extrapolator = Acts::Propagator<Acts::SympyStepper, Acts::Navigator>;
0380 using ExtrapolatorOptions = Extrapolator::template Options<
0381 Acts::ActorList<Acts::MaterialInteractor, Acts::EndOfWorldReached>>;
0382
0383 Extrapolator extrapolator(
0384 Acts::SympyStepper(m_cfg.magneticField),
0385 Acts::Navigator({m_cfg.trackingGeometry},
0386 logger().cloneWithSuffix("Navigator")),
0387 logger().cloneWithSuffix("Propagator"));
0388
0389 ExtrapolatorOptions extrapolationOptions(ctx.geoContext, ctx.magFieldContext);
0390 extrapolationOptions.constrainToVolumeIds = m_cfg.constrainToVolumeIds;
0391 extrapolationOptions.endOfWorldVolumeIds = m_cfg.endOfWorldVolumeIds;
0392
0393
0394 ACTS_DEBUG("Invoke track finding with " << initialParameters.size()
0395 << " seeds.");
0396
0397 auto trackContainer = std::make_shared<Acts::VectorTrackContainer>();
0398 auto trackStateContainer = std::make_shared<Acts::VectorMultiTrajectory>();
0399
0400 auto trackContainerTemp = std::make_shared<Acts::VectorTrackContainer>();
0401 auto trackStateContainerTemp =
0402 std::make_shared<Acts::VectorMultiTrajectory>();
0403
0404 TrackContainer tracks(trackContainer, trackStateContainer);
0405 TrackContainer tracksTemp(trackContainerTemp, trackStateContainerTemp);
0406
0407
0408 tracks.addColumn<BranchStopper::BranchState>("MyBranchState");
0409 tracksTemp.addColumn<BranchStopper::BranchState>("MyBranchState");
0410
0411 tracks.addColumn<unsigned int>("trackGroup");
0412 tracksTemp.addColumn<unsigned int>("trackGroup");
0413 Acts::ProxyAccessor<unsigned int> seedNumber("trackGroup");
0414
0415 unsigned int nSeed = 0;
0416
0417
0418 std::unordered_map<SeedIdentifier, bool> discoveredSeeds;
0419
0420 auto addTrack = [&](const TrackProxy& track) {
0421 ++m_nFoundTracks;
0422
0423
0424 if (m_cfg.trimTracks) {
0425 Acts::trimTrack(track, true, true, true, true);
0426 }
0427 Acts::calculateTrackQuantities(track);
0428
0429 if (m_trackSelector.has_value() && !m_trackSelector->isValidTrack(track)) {
0430 return;
0431 }
0432
0433
0434 visitSeedIdentifiers(track, [&](const SeedIdentifier& seedIdentifier) {
0435 if (auto it = discoveredSeeds.find(seedIdentifier);
0436 it != discoveredSeeds.end()) {
0437 it->second = true;
0438 }
0439 });
0440
0441 ++m_nSelectedTracks;
0442
0443 auto destProxy = tracks.makeTrack();
0444
0445 destProxy.copyFrom(track);
0446 };
0447
0448 if (seeds != nullptr && m_cfg.seedDeduplication) {
0449
0450 for (const auto& seed : *seeds) {
0451 SeedIdentifier seedIdentifier = makeSeedIdentifier(seed);
0452 discoveredSeeds.emplace(seedIdentifier, false);
0453 }
0454 }
0455
0456 for (std::size_t iSeed = 0; iSeed < initialParameters.size(); ++iSeed) {
0457 m_nTotalSeeds++;
0458
0459 if (seeds != nullptr) {
0460 const SimSeed& seed = seeds->at(iSeed);
0461
0462 if (m_cfg.seedDeduplication) {
0463 SeedIdentifier seedIdentifier = makeSeedIdentifier(seed);
0464
0465 if (auto it = discoveredSeeds.find(seedIdentifier);
0466 it != discoveredSeeds.end() && it->second) {
0467 m_nDeduplicatedSeeds++;
0468 ACTS_VERBOSE("Skipping seed " << iSeed << " due to deduplication.");
0469 continue;
0470 }
0471 }
0472
0473 if (m_cfg.stayOnSeed) {
0474 measSel.setSeed(seed);
0475 }
0476 }
0477
0478
0479 tracksTemp.clear();
0480
0481 const Acts::BoundTrackParameters& firstInitialParameters =
0482 initialParameters.at(iSeed);
0483
0484 auto firstRootBranch = tracksTemp.makeTrack();
0485 auto firstResult = (*m_cfg.findTracks)(firstInitialParameters, firstOptions,
0486 tracksTemp, firstRootBranch);
0487 nSeed++;
0488
0489 if (!firstResult.ok()) {
0490 m_nFailedSeeds++;
0491 ACTS_WARNING("Track finding failed for seed " << iSeed << " with error"
0492 << firstResult.error());
0493 continue;
0494 }
0495
0496 auto& firstTracksForSeed = firstResult.value();
0497 for (auto& firstTrack : firstTracksForSeed) {
0498
0499
0500
0501
0502 auto trackCandidate = tracksTemp.makeTrack();
0503 trackCandidate.copyFrom(firstTrack);
0504
0505 Acts::Result<void> firstSmoothingResult{
0506 Acts::smoothTrack(ctx.geoContext, trackCandidate, logger())};
0507 if (!firstSmoothingResult.ok()) {
0508 m_nFailedSmoothing++;
0509 ACTS_ERROR("First smoothing for seed "
0510 << iSeed << " and track " << firstTrack.index()
0511 << " failed with error " << firstSmoothingResult.error());
0512 continue;
0513 }
0514
0515
0516 std::size_t nSecond = 0;
0517
0518
0519
0520 seedNumber(trackCandidate) = nSeed - 1;
0521
0522 if (m_cfg.twoWay) {
0523 std::optional<Acts::VectorMultiTrajectory::TrackStateProxy>
0524 firstMeasurementOpt;
0525 for (auto trackState : trackCandidate.trackStatesReversed()) {
0526 bool isMeasurement = trackState.typeFlags().test(
0527 Acts::TrackStateFlag::MeasurementFlag);
0528 bool isOutlier =
0529 trackState.typeFlags().test(Acts::TrackStateFlag::OutlierFlag);
0530
0531
0532
0533 if (isMeasurement && !isOutlier) {
0534 firstMeasurementOpt = trackState;
0535 }
0536 }
0537
0538 if (firstMeasurementOpt.has_value()) {
0539 TrackContainer::TrackStateProxy firstMeasurement{
0540 firstMeasurementOpt.value()};
0541 TrackContainer::ConstTrackStateProxy firstMeasurementConst{
0542 firstMeasurement};
0543
0544 Acts::BoundTrackParameters secondInitialParameters =
0545 trackCandidate.createParametersFromState(firstMeasurementConst);
0546
0547 if (!secondInitialParameters.referenceSurface().insideBounds(
0548 secondInitialParameters.localPosition())) {
0549 m_nSkippedSecondPass++;
0550 ACTS_DEBUG(
0551 "Smoothing of first pass fit produced out-of-bounds parameters "
0552 "relative to the surface. Skipping second pass.");
0553 continue;
0554 }
0555
0556 auto secondRootBranch = tracksTemp.makeTrack();
0557 secondRootBranch.copyFromWithoutStates(trackCandidate);
0558 auto secondResult =
0559 (*m_cfg.findTracks)(secondInitialParameters, secondOptions,
0560 tracksTemp, secondRootBranch);
0561
0562 if (!secondResult.ok()) {
0563 ACTS_WARNING("Second track finding failed for seed "
0564 << iSeed << " with error" << secondResult.error());
0565 } else {
0566
0567 auto originalFirstMeasurementPrevious = firstMeasurement.previous();
0568
0569 auto& secondTracksForSeed = secondResult.value();
0570 for (auto& secondTrack : secondTracksForSeed) {
0571
0572
0573
0574
0575 auto secondTrackCopy = tracksTemp.makeTrack();
0576 secondTrackCopy.copyFrom(secondTrack);
0577
0578
0579
0580
0581 secondTrackCopy.reverseTrackStates(true);
0582
0583 firstMeasurement.previous() =
0584 secondTrackCopy.outermostTrackState().index();
0585
0586
0587 auto tipIndex = trackCandidate.tipIndex();
0588 auto stemIndex = trackCandidate.stemIndex();
0589 trackCandidate.copyFromWithoutStates(secondTrackCopy);
0590 trackCandidate.tipIndex() = tipIndex;
0591 trackCandidate.stemIndex() = stemIndex;
0592
0593
0594
0595 bool doExtrapolate = true;
0596
0597 if (!m_cfg.reverseSearch) {
0598
0599
0600
0601
0602
0603 doExtrapolate = !trackCandidate.hasReferenceSurface();
0604 } else {
0605
0606
0607 auto secondSmoothingResult =
0608 Acts::smoothTrack(ctx.geoContext, trackCandidate, logger());
0609 if (!secondSmoothingResult.ok()) {
0610 m_nFailedSmoothing++;
0611 ACTS_ERROR("Second smoothing for seed "
0612 << iSeed << " and track " << secondTrack.index()
0613 << " failed with error "
0614 << secondSmoothingResult.error());
0615 continue;
0616 }
0617
0618 trackCandidate.reverseTrackStates(true);
0619 }
0620
0621 if (doExtrapolate) {
0622 auto secondExtrapolationResult =
0623 Acts::extrapolateTrackToReferenceSurface(
0624 trackCandidate, *pSurface, extrapolator,
0625 extrapolationOptions, m_cfg.extrapolationStrategy,
0626 logger());
0627 if (!secondExtrapolationResult.ok()) {
0628 m_nFailedExtrapolation++;
0629 ACTS_ERROR("Second extrapolation for seed "
0630 << iSeed << " and track " << secondTrack.index()
0631 << " failed with error "
0632 << secondExtrapolationResult.error());
0633 continue;
0634 }
0635 }
0636
0637 addTrack(trackCandidate);
0638
0639 ++nSecond;
0640 }
0641
0642
0643 firstMeasurement.previous() = originalFirstMeasurementPrevious;
0644 }
0645 }
0646 }
0647
0648
0649 if (nSecond == 0) {
0650
0651 auto tipIndex = trackCandidate.tipIndex();
0652 auto stemIndex = trackCandidate.stemIndex();
0653 trackCandidate.copyFromWithoutStates(firstTrack);
0654 trackCandidate.tipIndex() = tipIndex;
0655 trackCandidate.stemIndex() = stemIndex;
0656
0657 auto firstExtrapolationResult =
0658 Acts::extrapolateTrackToReferenceSurface(
0659 trackCandidate, *pSurface, extrapolator, extrapolationOptions,
0660 m_cfg.extrapolationStrategy, logger());
0661 if (!firstExtrapolationResult.ok()) {
0662 m_nFailedExtrapolation++;
0663 ACTS_ERROR("Extrapolation for seed "
0664 << iSeed << " and track " << firstTrack.index()
0665 << " failed with error "
0666 << firstExtrapolationResult.error());
0667 continue;
0668 }
0669
0670 addTrack(trackCandidate);
0671 }
0672 }
0673 }
0674
0675
0676 if (m_cfg.computeSharedHits) {
0677 computeSharedHits(tracks, measurements);
0678 }
0679
0680 ACTS_DEBUG("Finalized track finding with " << tracks.size()
0681 << " track candidates.");
0682
0683 m_nStoppedBranches += branchStopper.m_nStoppedBranches;
0684
0685 m_memoryStatistics.local().hist +=
0686 tracks.trackStateContainer().statistics().hist;
0687
0688 auto constTrackStateContainer =
0689 std::make_shared<Acts::ConstVectorMultiTrajectory>(
0690 std::move(*trackStateContainer));
0691
0692 auto constTrackContainer = std::make_shared<Acts::ConstVectorTrackContainer>(
0693 std::move(*trackContainer));
0694
0695 ConstTrackContainer constTracks{constTrackContainer,
0696 constTrackStateContainer};
0697
0698 m_outputTracks(ctx, std::move(constTracks));
0699 return ProcessCode::SUCCESS;
0700 }
0701
0702 ProcessCode TrackFindingAlgorithm::finalize() {
0703 ACTS_INFO("TrackFindingAlgorithm statistics:");
0704 ACTS_INFO("- total seeds: " << m_nTotalSeeds);
0705 ACTS_INFO("- deduplicated seeds: " << m_nDeduplicatedSeeds);
0706 ACTS_INFO("- failed seeds: " << m_nFailedSeeds);
0707 ACTS_INFO("- failed smoothing: " << m_nFailedSmoothing);
0708 ACTS_INFO("- failed extrapolation: " << m_nFailedExtrapolation);
0709 ACTS_INFO("- failure ratio seeds: " << static_cast<double>(m_nFailedSeeds) /
0710 m_nTotalSeeds);
0711 ACTS_INFO("- found tracks: " << m_nFoundTracks);
0712 ACTS_INFO("- selected tracks: " << m_nSelectedTracks);
0713 ACTS_INFO("- stopped branches: " << m_nStoppedBranches);
0714 ACTS_INFO("- skipped second pass: " << m_nSkippedSecondPass);
0715
0716 auto memoryStatistics =
0717 m_memoryStatistics.combine([](const auto& a, const auto& b) {
0718 Acts::VectorMultiTrajectory::Statistics c;
0719 c.hist = a.hist + b.hist;
0720 return c;
0721 });
0722 std::stringstream ss;
0723 memoryStatistics.toStream(ss);
0724 ACTS_DEBUG("Track State memory statistics (averaged):\n" << ss.str());
0725 return ProcessCode::SUCCESS;
0726 }
0727
0728
0729
0730 void TrackFindingAlgorithm::computeSharedHits(
0731 TrackContainer& tracks, const MeasurementContainer& measurements) const {
0732
0733
0734
0735
0736 std::vector<std::size_t> firstTrackOnTheHit(
0737 measurements.size(), std::numeric_limits<std::size_t>::max());
0738 std::vector<std::size_t> firstStateOnTheHit(
0739 measurements.size(), std::numeric_limits<std::size_t>::max());
0740
0741 for (auto track : tracks) {
0742 for (auto state : track.trackStatesReversed()) {
0743 if (!state.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) {
0744 continue;
0745 }
0746
0747 std::size_t hitIndex = state.getUncalibratedSourceLink()
0748 .template get<IndexSourceLink>()
0749 .index();
0750
0751
0752 if (firstTrackOnTheHit.at(hitIndex) ==
0753 std::numeric_limits<std::size_t>::max()) {
0754 firstTrackOnTheHit.at(hitIndex) = track.index();
0755 firstStateOnTheHit.at(hitIndex) = state.index();
0756 continue;
0757 }
0758
0759
0760
0761 int indexFirstTrack = firstTrackOnTheHit.at(hitIndex);
0762 int indexFirstState = firstStateOnTheHit.at(hitIndex);
0763
0764 auto firstState = tracks.getTrack(indexFirstTrack)
0765 .container()
0766 .trackStateContainer()
0767 .getTrackState(indexFirstState);
0768 if (!firstState.typeFlags().test(Acts::TrackStateFlag::SharedHitFlag)) {
0769 firstState.typeFlags().set(Acts::TrackStateFlag::SharedHitFlag);
0770 }
0771
0772
0773 state.typeFlags().set(Acts::TrackStateFlag::SharedHitFlag);
0774 }
0775 }
0776 }
0777
0778 }