20 #include "Acts/Definitions/Units.hpp"
21 #include "Acts/Geometry/TrackingGeometry.hpp"
22 #include "Acts/Geometry/GeometryIdentifier.hpp"
23 #include "Acts/MagneticField/MagneticFieldProvider.hpp"
24 #include "Acts/Surfaces/Surface.hpp"
25 #include "Acts/TrackFinding/MeasurementSelector.hpp"
26 #include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp"
27 #include "Acts/Surfaces/PerigeeSurface.hpp"
28 #include "Acts/Utilities/TrackHelpers.hpp"
58 ISvcLocator *pSvcLocator)
110 return StatusCode::FAILURE;
116 return StatusCode::FAILURE;
122 return StatusCode::FAILURE;
136 auto magneticField = std::make_unique<ATLASMagneticFieldWrapper>();
139 Stepper stepper(std::move(magneticField));
140 Navigator::Config
cfg{trackingGeometry};
141 cfg.resolvePassive =
false;
142 cfg.resolveMaterial =
true;
143 cfg.resolveSensitive =
true;
144 Navigator navigator(
cfg,
logger().cloneWithSuffix(
"Navigator"));
145 Propagator propagator(std::move(stepper), std::move(navigator),
logger().cloneWithSuffix(
"Prop"));
148 Extrapolator extrapolator = propagator;
155 Acts::MeasurementSelectorCuts measurementSelectorCuts{
etaBins};
162 Acts::MeasurementSelector::Config measurementSelectorCfg{{Acts::GeometryIdentifier(), std::move(measurementSelectorCuts)}};
163 Acts::MeasurementSelector measurementSelector(measurementSelectorCfg);
165 std::vector<double> absEtaEdges;
166 absEtaEdges.reserve(
etaBins.size() + 2);
169 absEtaEdges.push_back(0.0);
170 absEtaEdges.push_back(std::numeric_limits<double>::infinity());
175 absEtaEdges.insert(absEtaEdges.end(),
etaBins.begin(),
etaBins.end());
179 auto setCut = [](
auto &cfgVal,
const auto &
cuts,
size_t ind) ->
void
186 Acts::TrackSelector::EtaBinnedConfig trackSelectorCfg{std::move(absEtaEdges)};
189 assert(trackSelectorCfg.cutSets.size() == 1);
190 trackSelectorCfg.cutSets[0].absEtaMin =
m_absEtaMin;
191 trackSelectorCfg.cutSets[0].absEtaMax =
m_absEtaMax;
194 for (
auto &
cfg : trackSelectorCfg.cutSets)
217 ATH_MSG_DEBUG(
"chi2OutlierCutOff set but not supported when using the default measurement selector.");
220 m_trackFinder.reset(
new CKF_pimpl{CKF_config{std::move(extrapolator), {std::move(propagator),
logger().cloneWithSuffix(
"CKF")}, measurementSelector, {}, {}, {}, trackSelectorCfg}});
224 trackFinder().pOptions.direction = Acts::Direction::Forward;
227 trackFinder().ckfExtensions.updater.connect<&ActsTrk::FitterHelperFunctions::gainMatrixUpdate<RecoTrackStateContainer>>();
228 trackFinder().ckfExtensions.measurementSelector.connect<&Acts::MeasurementSelector::select<RecoTrackStateContainer>>(&
trackFinder().measurementSelector);
231 return StatusCode::SUCCESS;
239 return StatusCode::SUCCESS;
257 std::vector<const ActsTrk::BoundTrackParametersContainer *> estimatedTrackParametersContainers;
261 ATH_MSG_DEBUG(
"Reading input collection with key " << estimatedTrackParametersKey.key());
264 estimatedTrackParametersContainers.push_back(estimatedTrackParametersHandle.
cptr());
265 ATH_MSG_DEBUG(
"Retrieved " << estimatedTrackParametersContainers.back()->size() <<
" input elements from key " << estimatedTrackParametersKey.key());
269 std::vector<const ActsTrk::SeedContainer *> seedContainers;
271 std::size_t total_seeds = 0;
274 ATH_MSG_DEBUG(
"Reading input collection with key " << seedContainerKey.key());
277 seedContainers.push_back(seedsHandle.
cptr());
278 ATH_MSG_DEBUG(
"Retrieved " << seedContainers.back()->size() <<
" input elements from key " << seedContainerKey.key());
279 total_seeds += seedContainers.back()->size();
283 std::vector<const xAOD::UncalibratedMeasurementContainer *> uncalibratedMeasurementContainers;
285 std::size_t measTotal = 0;
288 ATH_MSG_DEBUG(
"Reading input collection with key " << uncalibratedMeasurementContainerKey.key());
291 uncalibratedMeasurementContainers.push_back(uncalibratedMeasurementContainerHandle.
cptr());
292 ATH_MSG_DEBUG(
"Retrieved " << uncalibratedMeasurementContainers.back()->size() <<
" input elements from key " << uncalibratedMeasurementContainerKey.key());
293 measTotal += uncalibratedMeasurementContainers.back()->size();
296 std::vector<const InDetDD::SiDetectorElementCollection *> detEleColl;
300 ATH_MSG_DEBUG(
"Reading input condition data with key " << detEleCollKey.key());
303 detEleColl.push_back(detEleCollHandle.
retrieve());
304 if (detEleColl.back() ==
nullptr)
306 ATH_MSG_FATAL(detEleCollKey.fullKey() <<
" is not available.");
307 return StatusCode::FAILURE;
309 ATH_MSG_DEBUG(
"Retrieved " << detEleColl.back()->size() <<
" input condition elements from key " << detEleCollKey.key());
313 for (std::size_t icontainer = 0; icontainer < seedContainers.size(); ++icontainer)
315 if (!seedContainers[icontainer])
317 duplicateSeedDetector.addSeeds(icontainer, *seedContainers[icontainer]);
320 TrackFindingMeasurements measurements(measTotal);
323 for (std::size_t icontainer = 0; icontainer < detEleColl.size(); ++icontainer) {
325 !uncalibratedMeasurementContainers[icontainer]->empty() ? uncalibratedMeasurementContainers[icontainer]->at(0)->type()
331 for (std::size_t icontainer = 0; icontainer < uncalibratedMeasurementContainers.size(); ++icontainer) {
333 measurements.addMeasurements(icontainer, *uncalibratedMeasurementContainers[icontainer], *detEleColl[icontainer],
m_ATLASConverterTool);
337 m_trackStatePrinter->printMeasurements(ctx, uncalibratedMeasurementContainers, detEleColl, measurements.measurementOffsets());
346 event_stat.resize(m_stat.size());
352 for (std::size_t icontainer = 0; icontainer < estimatedTrackParametersContainers.size(); ++icontainer)
354 if (estimatedTrackParametersContainers[icontainer]->
empty())
358 duplicateSeedDetector,
359 *estimatedTrackParametersContainers[icontainer],
360 seedContainers[icontainer],
367 ATH_MSG_DEBUG(
" \\__ Created " << tracksContainer.size() <<
" tracks");
369 mon_nTracks = tracksContainer.size();
381 ATH_CHECK(trackContainerHandle.record(std::move(constTracksContainer)));
382 if (!trackContainerHandle.isValid())
385 return StatusCode::FAILURE;
388 return StatusCode::SUCCESS;
395 const TrackFindingMeasurements &measurements,
396 DuplicateSeedDetector &duplicateSeedDetector,
401 const char *seedType,
406 if (seeds && seeds->
size() != estimatedTrackParameters.
size())
409 ATH_MSG_WARNING(
"Have " << seeds->
size() <<
" " << seedType <<
" seeds, but " << estimatedTrackParameters.
size() <<
"estimated track parameters");
418 Acts::CalibrationContext calContext = Acts::CalibrationContext();
422 AtlUncalibSourceLinkAccessor slAccessor(measurements.orderedGeoIds(),
423 measurements.measurementRanges());
424 Acts::SourceLinkAccessorDelegate<UncalibSourceLinkAccessor::Iterator> slAccessorDelegate;
428 using TrackFinderOptions = Acts::CombinatorialKalmanFilterOptions<UncalibSourceLinkAccessor::Iterator, RecoTrackStateContainer>;
429 TrackFinderOptions
options(tgContext,
439 std::optional<TrackFinderOptions> secondOptions;
441 secondOptions.emplace(tgContext,
448 secondOptions->targetSurface = pSurface.get();
455 Acts::VectorTrackContainer trackBackend;
456 Acts::VectorMultiTrajectory trackStateBackend;
465 measurements.trackingSurfaceHelper(),
477 const auto &trackSelectorCfg =
trackFinder().trackSelector.config();
478 auto getCuts = [&trackSelectorCfg](
double eta) ->
const Acts::TrackSelector::Config & {
479 return (std::abs(
eta) < trackSelectorCfg.absEtaEdges.front()) ? trackSelectorCfg.cutSets.front()
480 : (std::abs(
eta) >= trackSelectorCfg.absEtaEdges.back()) ? trackSelectorCfg.cutSets.back()
481 : trackSelectorCfg.getCuts(
eta);
484 std::size_t category_i = 0;
485 const auto measurementContainerOffsets = measurements.measurementContainerOffsets();
487 using BranchStopperResult = Acts::CombinatorialKalmanFilterBranchStopperResult;
488 auto stopBranch = [&](
const Acts::CombinatorialKalmanFilterTipState &tipState,
489 RecoTrackStateContainer::TrackStateProxy &trackState) -> BranchStopperResult {
491 m_trackStatePrinter->printTrackState(tgContext, trackState, measurementContainerOffsets,
true);
495 return BranchStopperResult::Continue;
497 const auto &
parameters = trackState.hasFiltered() ? trackState.filtered() : trackState.predicted();
499 const auto &cutSet = getCuts(
eta);
504 if (std::abs(
pT) < cutSet.ptMin) {
508 << tipState.nMeasurements <<
" measurements");
509 return BranchStopperResult::StopAndDrop;
515 !(std::abs(
eta) < trackSelectorCfg.absEtaEdges.back())) {
519 << tipState.nMeasurements <<
" measurements");
520 return BranchStopperResult::StopAndDrop;
526 if (!(tipState.nHoles > cutSet.maxHoles || tipState.nOutliers > cutSet.maxOutliers))
527 return BranchStopperResult::Continue;
529 bool enoughMeasurements = !(tipState.nMeasurements < cutSet.minMeasurements);
530 if (!enoughMeasurements)
533 << (enoughMeasurements ?
"keep" :
"drop")
534 <<
" branch with nHoles=" << tipState.nHoles
535 <<
", nOutliers=" << tipState.nOutliers
536 <<
", nMeasurements=" << tipState.nMeasurements);
537 return enoughMeasurements ? BranchStopperResult::StopAndKeep
538 : BranchStopperResult::StopAndDrop;
541 options.extensions.branchStopper.connect(stopBranch);
543 secondOptions->extensions.branchStopper.connect(stopBranch);
545 Acts::PropagatorOptions<Acts::ActionList<Acts::MaterialInteractor>,
546 Acts::AbortList<Acts::EndOfWorldReached>>
547 extrapolationOptions(tgContext, mfContext);
549 Acts::TrackExtrapolationStrategy extrapolationStrategy =
550 Acts::TrackExtrapolationStrategy::firstOrLast;
553 ATH_MSG_DEBUG(
"Invoke track finding with " << estimatedTrackParameters.
size() <<
' ' << seedType <<
" seeds.");
555 std::size_t nPrinted = 0;
556 auto printSeed = [&](std::size_t iseed,
const Acts::BoundTrackParameters &seedParameters,
bool isKF =
false)
562 ATH_MSG_INFO(
"CKF results for " << estimatedTrackParameters.
size() <<
' ' << seedType <<
" seeds:");
564 m_trackStatePrinter->printSeed(tgContext, *(*seeds)[iseed], seedParameters, measurements.measurementOffset(typeIndex), iseed, isKF);
568 for (std::size_t iseed = 0; iseed < estimatedTrackParameters.
size(); ++iseed)
571 tracksContainerTemp.clear();
573 if (!estimatedTrackParameters[iseed])
580 const Acts::BoundTrackParameters *initialParameters = estimatedTrackParameters[iseed];
581 printSeed(iseed, *initialParameters);
587 if (duplicateSeedDetector.isDuplicate(typeIndex, iseed))
589 ATH_MSG_DEBUG(
"skip " << seedType <<
" seed " << iseed <<
" - already found");
598 std::unique_ptr<Acts::BoundTrackParameters> seedParameters;
602 const auto fittedSeedCollection =
m_fitterTool->fit(ctx, *(*seeds)[iseed], *initialParameters,
603 tgContext, mfContext, calContext,
604 measurements.trackingSurfaceHelper());
605 if (not fittedSeedCollection)
609 else if (fittedSeedCollection->size() != 1)
611 ATH_MSG_WARNING(
"KF produced " << fittedSeedCollection->size() <<
" tracks but should produce 1!");
616 const auto fittedSeed = fittedSeedCollection->getTrack(0);
618 double etaSeed = -
std::log(
std::tan(0.5 * fittedSeed.parameters()[Acts::eBoundTheta]));
619 const auto &cutSet = getCuts(etaSeed);
620 if (fittedSeed.transverseMomentum() < cutSet.ptMin)
622 ATH_MSG_VERBOSE(
"min pt requirement not satisfied after param refinement: pt min is " << cutSet.ptMin <<
" but Refined params have pt of " << fittedSeed.transverseMomentum());
627 seedParameters.reset(
new Acts::BoundTrackParameters(fittedSeed.referenceSurface().getSharedPtr(),
628 fittedSeed.parameters(),
629 fittedSeed.covariance(),
630 fittedSeed.particleHypothesis()));
631 printSeed(iseed, *seedParameters,
true);
634 initialParameters = seedParameters.get();
642 ATH_MSG_WARNING(
"Track finding failed for " << seedType <<
" seed " << iseed <<
" with error" <<
result.error());
645 auto &tracksForSeed =
result.value();
665 auto destProxy = tracksContainer.getTrack(tracksContainer.addTrack());
666 destProxy.copyFrom(
track,
true);
669 ATH_MSG_DEBUG(
"Track " << ntracks <<
" from " << seedType <<
" seed " << iseed <<
" failed track selection");
673 std::size_t nfirst = 0;
674 for (
auto &firstTrack : tracksForSeed) {
675 std::size_t nsecond = 0;
677 auto smoothingResult = Acts::smoothTrack(tgContext, firstTrack,
logger());
678 if (!smoothingResult.ok()) {
680 << iseed <<
" and first track " << firstTrack.index()
681 <<
" failed with error " << smoothingResult.error());
686 std::optional<RecoTrackStateContainerProxy> firstState;
687 for (
auto st : firstTrack.trackStatesReversed()) {
688 bool isMeasurement = st.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag);
689 bool isOutlier = st.typeFlags().test(Acts::TrackStateFlag::OutlierFlag);
693 if (isMeasurement && !isOutlier)
697 if (firstState.has_value()) {
698 Acts::BoundTrackParameters secondInitialParameters(
699 firstState->referenceSurface().getSharedPtr(),
700 firstState->parameters(), firstState->covariance(),
701 initialParameters->particleHypothesis());
703 auto secondResult =
trackFinder().ckf.findTracks(secondInitialParameters, *secondOptions, tracksContainerTemp);
705 if (not secondResult.ok()) {
706 ATH_MSG_WARNING(
"Second track finding failed for " << seedType <<
" seed " << iseed <<
" track " << nfirst <<
" with error" << secondResult.error());
708 auto firstFirstState =
std::next(firstTrack.trackStatesReversed().begin(),
709 firstTrack.nTrackStates() - 1);
711 auto &secondTracksForSeed = secondResult.value();
712 for (
auto &secondTrack : secondTracksForSeed) {
713 if (secondTrack.nTrackStates() < 2) {
714 ATH_MSG_DEBUG(
"Second track from " << seedType <<
" seed " << iseed <<
" track " << nfirst <<
" has only " << secondTrack.nTrackStates() <<
" track states");
718 secondTrack.reverseTrackStates(
true);
720 (*firstFirstState).previous() = (*
std::next(secondTrack.trackStatesReversed().begin())).
index();
721 secondTrack.tipIndex() = firstTrack.tipIndex();
723 Acts::calculateTrackQuantities(secondTrack);
725 auto extrapolationResult = Acts::extrapolateTrackToReferenceSurface(
726 secondTrack, *pSurface,
trackFinder().extrapolator, extrapolationOptions,
727 extrapolationStrategy,
logger());
728 if (!extrapolationResult.ok()) {
730 << iseed <<
" and second track " << secondTrack.index()
731 <<
" failed with error " << extrapolationResult.error());
734 (*firstFirstState).previous() = Acts::kTrackIndexInvalid;
742 (*firstFirstState).previous() = Acts::kTrackIndexInvalid;
751 ATH_MSG_DEBUG(
"No viable result from second track finding for " << seedType <<
" seed " << iseed <<
" track " << nfirst);
755 auto extrapolationResult = Acts::extrapolateTrackToReferenceSurface(
756 firstTrack, *pSurface,
trackFinder().extrapolator, extrapolationOptions,
757 extrapolationStrategy,
logger());
758 if (!extrapolationResult.ok()) {
760 << iseed <<
" and first " << firstTrack.index()
761 <<
" failed with error " << extrapolationResult.error());
770 ATH_MSG_DEBUG(
"Track finding found no track candidates for " << seedType <<
" seed " << iseed);
772 }
else if (ntracks >= 2) {
781 return StatusCode::SUCCESS;
787 DuplicateSeedDetector &duplicateSeedDetector)
const {
789 const auto lastMeasurementIndex =
track.tipIndex();
790 duplicateSeedDetector.newTrajectory();
792 tracksContainer.trackStateContainer().visitBackwards(
793 lastMeasurementIndex,
794 [&duplicateSeedDetector](
const RecoTrackStateContainer::ConstTrackStateProxy &state) ->
void
797 if (not state.hasUncalibratedSourceLink())
801 auto sl = state.getUncalibratedSourceLink().template get<ATLASUncalibSourceLink>();
802 duplicateSeedDetector.addMeasurement(sl);
818 ATH_MSG_FATAL(
"Eta bins for statistics counter not in ascending order.");
829 std::lock_guard<std::mutex> lock(m_mutex);
830 std::size_t category_i = 0;
831 for (
const std::array<unsigned int, kNStat> &src_stat : event_stat)
833 std::array<std::size_t, kNStat> &dest_stat = m_stat[category_i++];
834 for (std::size_t
i = 0;
i < src_stat.size(); ++
i)
836 assert(
i < dest_stat.size());
837 dest_stat[
i] += src_stat[
i];
847 std::vector<std::string> stat_labels =
853 std::make_pair(
kNoTrack,
"Cannot find track"),
860 std::make_pair(
kNoSecond,
"Tracks failing second CKF"),
864 assert(stat_labels.size() ==
kNStat);
870 std::vector<std::string> eta_labels;
872 for (std::size_t eta_bin_i = 0; eta_bin_i <
m_statEtaBins.size() + 2; ++eta_bin_i)
881 std::vector<std::size_t>
stat =
882 TableUtils::createCounterArrayWithProjections<std::size_t>(
nSeedCollections(),
887 std::size_t stat_stride =
891 std::size_t eta_stride =
895 std::stringstream table_out;
901 for (std::size_t stat_i = 0; stat_i <
kNStat; ++stat_i)
903 std::size_t dest_idx_offset = stat_i * stat_stride;
909 .dumpHeader(stat_i == 0)
910 .dumpFooter(stat_i + 1 ==
kNStat)
911 .separateLastRow(
true)
912 .minLabelWidth(max_label_width)
913 .labelPrefix(stat_labels.at(stat_i));
923 std::size_t dest_idx_offset = eta_bin_i * eta_stride;
927 eta_labels.at(eta_bin_i))
940 auto [ratio_labels, ratio_def] =
942 std::vector<TableUtils::SummandDefinition>{
974 for (std::size_t ratio_i = 0; ratio_i < ratio_labels.size(); ++ratio_i)
977 ratio_i * ratio_stride,
983 .dumpHeader(ratio_i == 0)
984 .dumpFooter(ratio_i + 1 == ratio_labels.size())
985 .separateLastRow(
true)
986 .minLabelWidth(max_label_width)
987 .labelPrefix(ratio_labels.at(ratio_i));
994 (
m_statEtaBins.size() + 1) * ratio_eta_stride + 0 * ratio_stride,
1000 .minLabelWidth(max_label_width)
1004 eta_labels.erase(eta_labels.end() - 1);
1005 constexpr std::size_t ratio_i = 3;
1007 ratio_i * ratio_stride,
1015 .separateLastRow(
false)
1016 .minLabelWidth(max_label_width)
1017 .labelPrefix(ratio_labels.at(ratio_i));
1021 << table_out.str());
1027 std::vector<float>::const_iterator bin_iter = std::upper_bound(
m_statEtaBins.begin(),
1031 assert(category_i < m_stat.size());
1037 std::size_t
out = 0
u;
1038 for (std::size_t category_i = seed_collection *
seedCollectionStride() +
static_cast<std::size_t
>(counter_i);
1042 assert(category_i <
stat.size());
1043 out +=
stat[category_i][counter_i];
1050 std::vector<std::pair<float, float> > chi2CutOffOutlier ;
1054 ATH_MSG_ERROR(
"Outlier chi2 cut off provided but number of elements does not agree with"
1055 " chi2 cut off for measurements which however is required: "
1057 return StatusCode::FAILURE;
1062 chi2CutOffOutlier.push_back( std::make_pair(
static_cast<float>(elm),
1068 std::vector<float> etaBinsf;