5 #include "Acts/Propagator/PropagatorOptions.hpp"
22 #include "Acts/Definitions/Units.hpp"
23 #include "Acts/Geometry/TrackingGeometry.hpp"
24 #include "Acts/Geometry/GeometryIdentifier.hpp"
25 #include "Acts/MagneticField/MagneticFieldProvider.hpp"
26 #include "Acts/Surfaces/Surface.hpp"
27 #include "Acts/TrackFinding/MeasurementSelector.hpp"
28 #include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp"
29 #include "Acts/Surfaces/PerigeeSurface.hpp"
30 #include "Acts/Utilities/TrackHelpers.hpp"
31 #include "Acts/TrackFitting/MbfSmoother.hpp"
59 ISvcLocator *pSvcLocator)
114 return StatusCode::FAILURE;
120 return StatusCode::FAILURE;
133 auto magneticField = std::make_unique<ATLASMagneticFieldWrapper>();
137 detail::Navigator::Config
cfg{trackingGeometry};
138 cfg.resolvePassive =
false;
139 cfg.resolveMaterial =
true;
140 cfg.resolveSensitive =
true;
152 Acts::MeasurementSelectorCuts measurementSelectorCuts{
etaBins};
159 Acts::MeasurementSelector::Config measurementSelectorCfg{{Acts::GeometryIdentifier(), std::move(measurementSelectorCuts)}};
160 Acts::MeasurementSelector measurementSelector(measurementSelectorCfg);
162 std::vector<double> absEtaEdges;
163 absEtaEdges.reserve(
etaBins.size() + 2);
166 absEtaEdges.push_back(0.0);
167 absEtaEdges.push_back(std::numeric_limits<double>::infinity());
172 absEtaEdges.insert(absEtaEdges.end(),
etaBins.begin(),
etaBins.end());
176 auto setCut = [](
auto &cfgVal,
const auto &
cuts,
size_t ind) ->
void
183 Acts::TrackSelector::EtaBinnedConfig trackSelectorCfg{std::move(absEtaEdges)};
186 assert(trackSelectorCfg.cutSets.size() == 1);
187 trackSelectorCfg.cutSets[0].absEtaMin =
m_absEtaMin;
188 trackSelectorCfg.cutSets[0].absEtaMax =
m_absEtaMax;
191 for (
auto &
cfg : trackSelectorCfg.cutSets)
214 ATH_MSG_DEBUG(
"chi2OutlierCutOff set but not supported when using the default measurement selector.");
218 std::move(extrapolator),
219 {std::move(propagator),
logger().cloneWithSuffix(
"CKF")},
224 m_trackFinder = std::make_unique<CKF_pimpl>(std::move(ckfConfig));
226 trackFinder().
ckfExtensions.updater.connect<&ActsTrk::detail::FitterHelperFunctions::gainMatrixUpdate<detail::RecoTrackStateContainer>>();
230 return StatusCode::SUCCESS;
238 return StatusCode::SUCCESS;
256 std::vector<const ActsTrk::BoundTrackParametersContainer *> estimatedTrackParametersContainers;
260 ATH_MSG_DEBUG(
"Reading input collection with key " << estimatedTrackParametersKey.key());
263 estimatedTrackParametersContainers.push_back(estimatedTrackParametersHandle.
cptr());
264 ATH_MSG_DEBUG(
"Retrieved " << estimatedTrackParametersContainers.back()->size() <<
" input elements from key " << estimatedTrackParametersKey.key());
268 std::vector<const ActsTrk::SeedContainer *> seedContainers;
270 std::size_t total_seeds = 0;
273 ATH_MSG_DEBUG(
"Reading input collection with key " << seedContainerKey.key());
276 seedContainers.push_back(seedsHandle.
cptr());
277 ATH_MSG_DEBUG(
"Retrieved " << seedContainers.back()->size() <<
" input elements from key " << seedContainerKey.key());
278 total_seeds += seedContainers.back()->size();
282 std::vector<const xAOD::UncalibratedMeasurementContainer *> uncalibratedMeasurementContainers;
286 ATH_MSG_DEBUG(
"Reading input collection with key " << uncalibratedMeasurementContainerKey.key());
289 uncalibratedMeasurementContainers.push_back(uncalibratedMeasurementContainerHandle.
cptr());
290 ATH_MSG_DEBUG(
"Retrieved " << uncalibratedMeasurementContainers.back()->size() <<
" input elements from key " << uncalibratedMeasurementContainerKey.key());
295 ATH_CHECK(detectorElementToGeometryIdMap.isValid());
298 for (std::size_t icontainer = 0; icontainer < seedContainers.size(); ++icontainer)
300 if (!seedContainers[icontainer])
302 duplicateSeedDetector.
addSeeds(icontainer, *seedContainers[icontainer]);
306 const Acts::TrackingGeometry *
308 ATH_CHECK(acts_tracking_geometry !=
nullptr);
310 for (std::size_t icontainer = 0; icontainer < uncalibratedMeasurementContainers.size(); ++icontainer) {
313 *uncalibratedMeasurementContainers[icontainer],
314 **detectorElementToGeometryIdMap);
327 event_stat.resize(m_stat.size());
330 for (std::size_t icontainer = 0; icontainer < estimatedTrackParametersContainers.size(); ++icontainer)
332 if (estimatedTrackParametersContainers[icontainer]->
empty())
335 *acts_tracking_geometry,
336 **detectorElementToGeometryIdMap,
338 duplicateSeedDetector,
339 *estimatedTrackParametersContainers[icontainer],
340 seedContainers[icontainer],
347 ATH_MSG_DEBUG(
" \\__ Created " << tracksContainer.size() <<
" tracks");
349 mon_nTracks = tracksContainer.size();
361 ATH_CHECK(trackContainerHandle.record(std::move(constTracksContainer)));
362 if (!trackContainerHandle.isValid())
365 return StatusCode::FAILURE;
368 return StatusCode::SUCCESS;
375 const Acts::TrackingGeometry &trackingGeometry,
383 const char *seedType,
388 if (seeds && seeds->
size() != estimatedTrackParameters.
size())
391 ATH_MSG_WARNING(
"Have " << seeds->
size() <<
" " << seedType <<
" seeds, but " << estimatedTrackParameters.
size() <<
"estimated track parameters");
400 Acts::CalibrationContext calContext = Acts::CalibrationContext();
405 Acts::SourceLinkAccessorDelegate<detail::UncalibSourceLinkAccessor::Iterator> slAccessorDelegate;
408 Acts::PropagatorPlainOptions plainOptions{tgContext, mfContext};
409 Acts::PropagatorPlainOptions plainSecondOptions{tgContext, mfContext};
413 plainOptions.direction = reverseSearch ? Acts::Direction::Backward : Acts::Direction::Forward;
415 plainSecondOptions.direction = plainOptions.direction.invert();
418 using TrackFinderOptions = Acts::CombinatorialKalmanFilterOptions<detail::UncalibSourceLinkAccessor::Iterator, detail::RecoTrackContainer>;
419 TrackFinderOptions
options(tgContext,
426 if (reverseSearch)
options.targetSurface = pSurface.get();
430 std::optional<TrackFinderOptions> secondOptions;
432 secondOptions.emplace(tgContext,
439 if (!reverseSearch) secondOptions->targetSurface = pSurface.get();
443 secondOptions->skipPrePropagationUpdate =
true;
447 Acts::VectorTrackContainer trackBackend;
448 Acts::VectorMultiTrajectory trackStateBackend;
456 detectorElementToGeoId,
469 auto getCuts = [&trackSelectorCfg](
double eta) ->
const Acts::TrackSelector::Config & {
471 return (!(std::abs(eta) < trackSelectorCfg.absEtaEdges.back())) ? trackSelectorCfg.cutSets.back()
472 : (std::abs(eta) < trackSelectorCfg.absEtaEdges.front()) ? trackSelectorCfg.cutSets.front()
473 : trackSelectorCfg.getCuts(eta);
476 std::size_t category_i = 0;
479 using BranchStopperResult = Acts::CombinatorialKalmanFilterBranchStopperResult;
480 auto stopBranch = [&](
const detail::RecoTrackContainer::TrackProxy &
track,
481 const detail::RecoTrackContainer::TrackStateProxy &trackState) -> BranchStopperResult {
483 m_trackStatePrinter->printTrackState(tgContext, trackState, measurementContainerOffsets,
true);
487 return BranchStopperResult::Continue;
489 const auto &
parameters = trackState.hasFiltered() ? trackState.filtered() : trackState.predicted();
491 const auto &cutSet = getCuts(eta);
500 <<
track.nMeasurements() <<
" measurements");
501 return BranchStopperResult::StopAndDrop;
511 <<
track.nMeasurements() <<
" measurements");
512 return BranchStopperResult::StopAndDrop;
515 if (!(
track.nHoles() > cutSet.maxHoles ||
track.nOutliers() > cutSet.maxOutliers))
516 return BranchStopperResult::Continue;
518 bool enoughMeasurements = !(
track.nMeasurements() < cutSet.minMeasurements);
519 if (!enoughMeasurements)
522 << (enoughMeasurements ?
"keep" :
"drop")
523 <<
" branch with nHoles=" <<
track.nHoles()
524 <<
", nOutliers=" <<
track.nOutliers()
525 <<
", nMeasurements=" <<
track.nMeasurements());
526 return enoughMeasurements ? BranchStopperResult::StopAndKeep
527 : BranchStopperResult::StopAndDrop;
530 options.extensions.branchStopper.connect(stopBranch);
536 secondOptions->extensions.branchStopper.connect(stopBranch);
540 Acts::ActorList<Acts::MaterialInteractor>>
541 extrapolationOptions(tgContext, mfContext);
543 Acts::TrackExtrapolationStrategy extrapolationStrategy =
547 ATH_MSG_DEBUG(
"Invoke track finding with " << estimatedTrackParameters.
size() <<
' ' << seedType <<
" seeds.");
549 std::size_t nPrinted = 0;
550 auto printSeed = [&](std::size_t iseed,
const Acts::BoundTrackParameters &seedParameters,
bool isKF =
false)
556 ATH_MSG_INFO(
"CKF results for " << estimatedTrackParameters.
size() <<
' ' << seedType <<
" seeds:");
558 m_trackStatePrinter->printSeed(tgContext, *(*seeds)[iseed], seedParameters, measurementContainerOffsets, iseed, isKF);
562 for (std::size_t iseed = 0; iseed < estimatedTrackParameters.
size(); ++iseed)
565 tracksContainerTemp.clear();
567 if (!estimatedTrackParameters[iseed])
574 const Acts::BoundTrackParameters *initialParameters = estimatedTrackParameters[iseed];
575 printSeed(iseed, *initialParameters);
581 if (duplicateSeedDetector.
isDuplicate(typeIndex, iseed))
583 ATH_MSG_DEBUG(
"skip " << seedType <<
" seed " << iseed <<
" - already found");
592 std::unique_ptr<Acts::BoundTrackParameters> seedParameters;
597 const auto fittedSeedCollection =
m_fitterTool->fit(ctx, *(*seeds)[iseed], *initialParameters,
598 tgContext, mfContext, calContext,
599 detectorElementToGeoId);
600 if (not fittedSeedCollection)
604 else if (fittedSeedCollection->size() != 1)
606 ATH_MSG_WARNING(
"KF produced " << fittedSeedCollection->size() <<
" tracks but should produce 1!");
611 const auto fittedSeed = fittedSeedCollection->getTrack(0);
613 double etaSeed = -
std::log(
std::tan(0.5 * fittedSeed.parameters()[Acts::eBoundTheta]));
614 const auto &cutSet = getCuts(etaSeed);
615 if (fittedSeed.transverseMomentum() < cutSet.ptMin)
617 ATH_MSG_VERBOSE(
"min pt requirement not satisfied after param refinement: pt min is " << cutSet.ptMin <<
" but Refined params have pt of " << fittedSeed.transverseMomentum());
622 seedParameters.reset(
new Acts::BoundTrackParameters(fittedSeed.referenceSurface().getSharedPtr(),
623 fittedSeed.parameters(),
624 initialParameters->covariance(),
625 fittedSeed.particleHypothesis()));
626 printSeed(iseed, *seedParameters,
true);
629 initialParameters = seedParameters.get();
637 ATH_MSG_WARNING(
"Track finding failed for " << seedType <<
" seed " << iseed <<
" with error" <<
result.error());
640 auto &tracksForSeed =
result.value();
649 if (!
track.hasReferenceSurface()) {
650 auto extrapolationResult = Acts::extrapolateTrackToReferenceSurface(
652 extrapolationStrategy,
logger());
653 if (!extrapolationResult.ok()) {
655 << iseed <<
" and " <<
track.index()
656 <<
" failed with error " << extrapolationResult.error()
657 <<
" dropping track candidate.");
662 Acts::trimTrack(
track,
true,
true,
true);
663 Acts::calculateTrackQuantities(
track);
673 auto isValidEta = [&](
const detail::RecoTrackContainer::TrackProxy &
track) {
680 auto destProxy = tracksContainer.getTrack(tracksContainer.addTrack());
681 destProxy.copyFrom(
track,
true);
689 ATH_MSG_DEBUG(
"Track " << ntracks <<
" from " << seedType <<
" seed " << iseed <<
" failed track selection");
693 std::size_t nfirst = 0;
694 for (
auto &firstTrack : tracksForSeed) {
695 std::size_t nsecond = 0;
697 auto smoothingResult = Acts::smoothTrack(tgContext, firstTrack,
logger(), Acts::MbfSmoother());
698 if (!smoothingResult.ok()) {
700 << iseed <<
" and first track " << firstTrack.index()
701 <<
" failed with error " << smoothingResult.error());
706 std::optional<detail::RecoTrackStateContainerProxy> firstMeasurement;
707 for (
auto st : firstTrack.trackStatesReversed()) {
708 bool isMeasurement = st.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag);
709 bool isOutlier = st.typeFlags().test(Acts::TrackStateFlag::OutlierFlag);
713 if (isMeasurement && !isOutlier)
714 firstMeasurement = st;
717 if (firstMeasurement.has_value()) {
718 Acts::BoundTrackParameters secondInitialParameters(
719 firstMeasurement->referenceSurface().getSharedPtr(),
720 firstMeasurement->parameters(), firstMeasurement->covariance(),
721 initialParameters->particleHypothesis());
723 auto secondResult =
trackFinder().
ckf.findTracks(secondInitialParameters, *secondOptions, tracksContainerTemp);
725 if (not secondResult.ok()) {
726 ATH_MSG_WARNING(
"Second track finding failed for " << seedType <<
" seed " << iseed <<
" track " << nfirst <<
" with error" << secondResult.error());
730 auto originalFirstMeasurementPrevious = firstMeasurement->previous();
732 auto &secondTracksForSeed = secondResult.value();
733 for (
auto &secondTrack : secondTracksForSeed) {
734 secondTrack.reverseTrackStates(
true);
736 firstMeasurement->previous() = secondTrack.outermostTrackState().index();
737 secondTrack.tipIndex() = firstTrack.tipIndex();
741 auto secondSmoothingResult = Acts::smoothTrack(tgContext, secondTrack,
logger());
742 if (!secondSmoothingResult.ok()) {
743 ATH_MSG_WARNING(
"Second smoothing for seed " << iseed <<
" and track " << secondTrack.index() <<
" failed with error " << secondSmoothingResult.error());
747 secondTrack.reverseTrackStates(
true);
756 firstMeasurement->previous() = originalFirstMeasurementPrevious;
762 ATH_MSG_DEBUG(
"No viable result from second track finding for " << seedType <<
" seed " << iseed <<
" track " << nfirst);
771 ATH_MSG_DEBUG(
"Track finding found no track candidates for " << seedType <<
" seed " << iseed);
773 }
else if (ntracks >= 2) {
782 return StatusCode::SUCCESS;
790 const auto lastMeasurementIndex =
track.tipIndex();
793 tracksContainer.trackStateContainer().visitBackwards(
794 lastMeasurementIndex,
795 [&duplicateSeedDetector](
const detail::RecoTrackStateContainer::ConstTrackStateProxy &state) ->
void
798 if (not state.hasUncalibratedSourceLink())
802 auto sl = state.getUncalibratedSourceLink().template get<ATLASUncalibSourceLink>();
819 ATH_MSG_FATAL(
"Eta bins for statistics counter not in ascending order.");
830 std::lock_guard<std::mutex> lock(m_mutex);
831 std::size_t category_i = 0;
832 for (
const std::array<unsigned int, kNStat> &src_stat : event_stat)
834 std::array<std::size_t, kNStat> &dest_stat = m_stat[category_i++];
835 for (std::size_t
i = 0;
i < src_stat.size(); ++
i)
837 assert(
i < dest_stat.size());
838 dest_stat[
i] += src_stat[
i];
848 std::vector<std::string> stat_labels =
854 std::make_pair(
kNoTrack,
"Cannot find track"),
861 std::make_pair(
kNoSecond,
"Tracks failing second CKF"),
865 assert(stat_labels.size() ==
kNStat);
871 std::vector<std::string> eta_labels;
873 for (std::size_t eta_bin_i = 0; eta_bin_i <
m_statEtaBins.size() + 2; ++eta_bin_i)
882 std::vector<std::size_t>
stat =
883 TableUtils::createCounterArrayWithProjections<std::size_t>(
nSeedCollections(),
888 std::size_t stat_stride =
892 std::size_t eta_stride =
896 std::stringstream table_out;
902 for (std::size_t stat_i = 0; stat_i <
kNStat; ++stat_i)
904 std::size_t dest_idx_offset = stat_i * stat_stride;
910 .dumpHeader(stat_i == 0)
911 .dumpFooter(stat_i + 1 ==
kNStat)
912 .separateLastRow(
true)
913 .minLabelWidth(max_label_width)
914 .labelPrefix(stat_labels.at(stat_i));
924 std::size_t dest_idx_offset = eta_bin_i * eta_stride;
928 eta_labels.at(eta_bin_i))
941 auto [ratio_labels, ratio_def] =
943 std::vector<TableUtils::SummandDefinition>{
975 for (std::size_t ratio_i = 0; ratio_i < ratio_labels.size(); ++ratio_i)
978 ratio_i * ratio_stride,
984 .dumpHeader(ratio_i == 0)
985 .dumpFooter(ratio_i + 1 == ratio_labels.size())
986 .separateLastRow(
true)
987 .minLabelWidth(max_label_width)
988 .labelPrefix(ratio_labels.at(ratio_i));
995 (
m_statEtaBins.size() + 1) * ratio_eta_stride + 0 * ratio_stride,
1001 .minLabelWidth(max_label_width)
1005 eta_labels.erase(eta_labels.end() - 1);
1006 constexpr std::size_t ratio_i = 3;
1008 ratio_i * ratio_stride,
1016 .separateLastRow(
false)
1017 .minLabelWidth(max_label_width)
1018 .labelPrefix(ratio_labels.at(ratio_i));
1022 << table_out.str());
1028 std::vector<float>::const_iterator bin_iter = std::upper_bound(
m_statEtaBins.begin(),
1032 assert(category_i < m_stat.size());
1038 std::size_t
out = 0
u;
1039 for (std::size_t category_i = seed_collection *
seedCollectionStride() +
static_cast<std::size_t
>(counter_i);
1043 assert(category_i <
stat.size());
1044 out +=
stat[category_i][counter_i];
1051 std::vector<std::pair<float, float> > chi2CutOffOutlier ;
1055 ATH_MSG_ERROR(
"Outlier chi2 cut off provided but number of elements does not agree with"
1056 " chi2 cut off for measurements which however is required: "
1058 return StatusCode::FAILURE;
1063 chi2CutOffOutlier.push_back( std::make_pair(
static_cast<float>(elm),
1069 std::vector<float> etaBinsf;