File indexing completed on 2026-05-22 08:00:39
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Common.hpp"
0012 #include "Acts/EventData/MultiTrajectory.hpp"
0013 #include "Acts/EventData/MultiTrajectoryHelpers.hpp"
0014 #include "Acts/EventData/TrackParameters.hpp"
0015 #include "Acts/EventData/TrackStatePropMask.hpp"
0016 #include "Acts/EventData/Types.hpp"
0017 #include "Acts/Geometry/GeometryContext.hpp"
0018 #include "Acts/MagneticField/MagneticFieldContext.hpp"
0019 #include "Acts/Propagator/ActorList.hpp"
0020 #include "Acts/Propagator/ConstrainedStep.hpp"
0021 #include "Acts/Propagator/PropagatorState.hpp"
0022 #include "Acts/Propagator/StandardAborters.hpp"
0023 #include "Acts/Propagator/detail/LoopProtection.hpp"
0024 #include "Acts/Propagator/detail/PointwiseMaterialInteraction.hpp"
0025 #include "Acts/TrackFinding/CombinatorialKalmanFilterError.hpp"
0026 #include "Acts/TrackFinding/CombinatorialKalmanFilterExtensions.hpp"
0027 #include "Acts/Utilities/CalibrationContext.hpp"
0028 #include "Acts/Utilities/Logger.hpp"
0029 #include "Acts/Utilities/Result.hpp"
0030
0031 #include <functional>
0032 #include <limits>
0033 #include <memory>
0034 #include <type_traits>
0035
0036 namespace Acts {
0037
0038
0039
0040
0041
0042
0043
0044
0045 template <typename track_container_t>
0046 struct CombinatorialKalmanFilterOptions {
0047
0048 using TrackStateContainerBackend =
0049 typename track_container_t::TrackStateContainerBackend;
0050
0051 using TrackStateProxy = typename track_container_t::TrackStateProxy;
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062 CombinatorialKalmanFilterOptions(
0063 const GeometryContext& gctx, const MagneticFieldContext& mctx,
0064 std::reference_wrapper<const CalibrationContext> cctx,
0065 CombinatorialKalmanFilterExtensions<track_container_t> extensions_,
0066 const PropagatorPlainOptions& pOptions, bool mScattering = true,
0067 bool eLoss = true)
0068 : geoContext(gctx),
0069 magFieldContext(mctx),
0070 calibrationContext(cctx),
0071 extensions(extensions_),
0072 propagatorPlainOptions(pOptions),
0073 multipleScattering(mScattering),
0074 energyLoss(eLoss) {}
0075
0076
0077 CombinatorialKalmanFilterOptions() = delete;
0078
0079
0080 std::reference_wrapper<const GeometryContext> geoContext;
0081
0082 std::reference_wrapper<const MagneticFieldContext> magFieldContext;
0083
0084 std::reference_wrapper<const CalibrationContext> calibrationContext;
0085
0086
0087 CombinatorialKalmanFilterExtensions<track_container_t> extensions;
0088
0089
0090 PropagatorPlainOptions propagatorPlainOptions;
0091
0092
0093
0094
0095 const Surface* targetSurface = nullptr;
0096
0097
0098 bool multipleScattering = true;
0099
0100
0101 bool energyLoss = true;
0102
0103
0104
0105 bool skipPrePropagationUpdate = false;
0106 };
0107
0108
0109
0110
0111 template <typename track_container_t>
0112 struct CombinatorialKalmanFilterResult {
0113
0114 using TrackStateContainerBackend =
0115 typename track_container_t::TrackStateContainerBackend;
0116
0117 using TrackProxy = typename track_container_t::TrackProxy;
0118
0119 using TrackStateProxy = typename track_container_t::TrackStateProxy;
0120
0121
0122 track_container_t* tracks{nullptr};
0123
0124
0125 TrackStateContainerBackend* trackStates{nullptr};
0126
0127
0128 std::vector<TrackProxy> activeBranches;
0129
0130
0131 std::vector<TrackProxy> collectedTracks;
0132
0133
0134 std::vector<TrackStateProxy> trackStateCandidates;
0135
0136
0137 bool finished = false;
0138
0139
0140 PathLimitReached pathLimitReached;
0141 };
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162 template <typename propagator_t, typename track_container_t>
0163 class CombinatorialKalmanFilter {
0164 public:
0165
0166 CombinatorialKalmanFilter() = delete;
0167
0168
0169
0170
0171 explicit CombinatorialKalmanFilter(propagator_t pPropagator,
0172 std::unique_ptr<const Logger> _logger =
0173 getDefaultLogger("CKF", Logging::INFO))
0174 : m_propagator(std::move(pPropagator)),
0175 m_logger(std::move(_logger)),
0176 m_actorLogger{m_logger->cloneWithSuffix("Actor")},
0177 m_updaterLogger{m_logger->cloneWithSuffix("Updater")} {}
0178
0179 private:
0180 using BoundState = std::tuple<BoundTrackParameters, BoundMatrix, double>;
0181 using TrackStateContainerBackend =
0182 typename track_container_t::TrackStateContainerBackend;
0183 using TrackProxy = typename track_container_t::TrackProxy;
0184 using TrackStateProxy = typename track_container_t::TrackStateProxy;
0185
0186
0187 propagator_t m_propagator;
0188
0189 std::unique_ptr<const Logger> m_logger;
0190 std::shared_ptr<const Logger> m_actorLogger;
0191 std::shared_ptr<const Logger> m_updaterLogger;
0192
0193 const Logger& logger() const { return *m_logger; }
0194
0195
0196
0197
0198
0199 class Actor {
0200 public:
0201 using BoundState = std::tuple<BoundTrackParameters, BoundMatrix, double>;
0202
0203 using result_type = CombinatorialKalmanFilterResult<track_container_t>;
0204
0205 using BranchStopperResult = CombinatorialKalmanFilterBranchStopperResult;
0206
0207
0208 SurfaceReached targetReached{std::numeric_limits<double>::lowest()};
0209
0210
0211 bool multipleScattering = true;
0212
0213
0214 bool energyLoss = true;
0215
0216
0217 bool skipPrePropagationUpdate = false;
0218
0219
0220 const CalibrationContext* calibrationContextPtr{nullptr};
0221
0222 CombinatorialKalmanFilterExtensions<track_container_t> extensions;
0223
0224
0225 EndOfWorldReached endOfWorldReached;
0226
0227
0228 VolumeConstraintAborter volumeConstraintAborter;
0229
0230
0231 const Logger* actorLogger{nullptr};
0232
0233 const Logger* updaterLogger{nullptr};
0234
0235 const Logger& logger() const { return *actorLogger; }
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246 template <typename propagator_state_t, typename stepper_t,
0247 typename navigator_t>
0248 Result<void> act(propagator_state_t& state, const stepper_t& stepper,
0249 const navigator_t& navigator, result_type& result,
0250 const Logger& ) const {
0251 ACTS_VERBOSE("CKF Actor called");
0252
0253 assert(result.trackStates && "No MultiTrajectory set");
0254
0255 if (state.stage == PropagatorStage::prePropagation &&
0256 skipPrePropagationUpdate) {
0257 ACTS_VERBOSE("Skip pre-propagation update (first surface)");
0258 return Result<void>::success();
0259 }
0260 if (state.stage == PropagatorStage::postPropagation) {
0261 ACTS_VERBOSE("Skip post-propagation action");
0262 return Result<void>::success();
0263 }
0264
0265 ACTS_VERBOSE("CombinatorialKalmanFilter step");
0266
0267 assert(!result.activeBranches.empty() && "No active branches");
0268 assert(!result.finished && "Should never reach this when finished");
0269
0270
0271 if (result.pathLimitReached.internalLimit ==
0272 std::numeric_limits<double>::max()) {
0273 detail::setupLoopProtection(state, stepper, result.pathLimitReached,
0274 true, logger());
0275 }
0276
0277
0278
0279 if (const Surface* surface = navigator.currentSurface(state.navigation);
0280 surface != nullptr) {
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295 ACTS_VERBOSE("Perform filter step");
0296 auto res = filter(*surface, state, stepper, navigator, result);
0297 if (!res.ok()) {
0298 ACTS_DEBUG("Error in filter: " << res.error().message());
0299 return res.error();
0300 }
0301
0302 if (result.finished) {
0303 ACTS_VERBOSE("CKF Actor returns after filter step");
0304 return Result<void>::success();
0305 }
0306 }
0307
0308 assert(!result.activeBranches.empty() && "No active branches");
0309
0310 const bool isEndOfWorldReached =
0311 endOfWorldReached.checkAbort(state, stepper, navigator, logger());
0312 const bool isVolumeConstraintReached = volumeConstraintAborter.checkAbort(
0313 state, stepper, navigator, logger());
0314 const bool isPathLimitReached = result.pathLimitReached.checkAbort(
0315 state, stepper, navigator, logger());
0316 const bool isTargetReached =
0317 targetReached.checkAbort(state, stepper, navigator, logger());
0318 if (isEndOfWorldReached || isVolumeConstraintReached ||
0319 isPathLimitReached || isTargetReached) {
0320 if (isEndOfWorldReached) {
0321 ACTS_VERBOSE("End of world reached");
0322 } else if (isVolumeConstraintReached) {
0323 ACTS_VERBOSE("Volume constraint reached");
0324 } else if (isPathLimitReached) {
0325 ACTS_VERBOSE("Path limit reached");
0326 } else if (isTargetReached) {
0327 ACTS_VERBOSE("Target surface reached");
0328
0329
0330 auto res = stepper.boundState(state.stepping, *targetReached.surface);
0331 if (!res.ok()) {
0332 ACTS_DEBUG("Error while acquiring bound state for target surface: "
0333 << res.error() << " " << res.error().message());
0334 return res.error();
0335 }
0336
0337 const auto& [boundParams, jacobian, pathLength] = *res;
0338 auto currentBranch = result.activeBranches.back();
0339
0340 currentBranch.parameters() = boundParams.parameters();
0341 currentBranch.covariance() = *boundParams.covariance();
0342 currentBranch.setReferenceSurface(
0343 boundParams.referenceSurface().getSharedPtr());
0344
0345 stepper.releaseStepSize(state.stepping,
0346 ConstrainedStep::Type::Navigator);
0347 }
0348
0349
0350 storeLastActiveBranch(result);
0351 result.activeBranches.pop_back();
0352
0353
0354 auto resetRes = reset(state, stepper, navigator, result);
0355 if (!resetRes.ok()) {
0356 return resetRes.error();
0357 }
0358 }
0359
0360 return Result<void>::success();
0361 }
0362
0363 template <typename propagator_state_t, typename stepper_t,
0364 typename navigator_t>
0365 bool checkAbort(propagator_state_t& , const stepper_t& ,
0366 const navigator_t& , const result_type& result,
0367 const Logger& ) const {
0368 return result.finished;
0369 }
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381 template <typename propagator_state_t, typename stepper_t,
0382 typename navigator_t>
0383 Result<void> reset(propagator_state_t& state, const stepper_t& stepper,
0384 const navigator_t& navigator,
0385 result_type& result) const {
0386 if (result.activeBranches.empty()) {
0387 ACTS_VERBOSE("Stop CKF with " << result.collectedTracks.size()
0388 << " found tracks");
0389 result.finished = true;
0390
0391 return Result<void>::success();
0392 }
0393
0394 auto currentBranch = result.activeBranches.back();
0395 auto currentState = currentBranch.outermostTrackState();
0396
0397 ACTS_VERBOSE("Propagation jumps to branch with tip = "
0398 << currentBranch.tipIndex());
0399
0400
0401 stepper.initialize(state.stepping, currentState.filtered(),
0402 currentState.filteredCovariance(),
0403 stepper.particleHypothesis(state.stepping),
0404 currentState.referenceSurface());
0405
0406
0407
0408 state.navigation.options.startSurface = ¤tState.referenceSurface();
0409 state.navigation.options.targetSurface = nullptr;
0410 auto navInitRes = navigator.initialize(
0411 state.navigation, stepper.position(state.stepping),
0412 stepper.direction(state.stepping), state.options.direction);
0413 if (!navInitRes.ok()) {
0414 ACTS_DEBUG("Navigation initialization failed: " << navInitRes.error());
0415 return navInitRes.error();
0416 }
0417
0418
0419
0420 detail::performMaterialInteraction(
0421 state, stepper, navigator,
0422 detail::determineMaterialUpdateMode(state, navigator,
0423 MaterialUpdateMode::PostUpdate),
0424 NoiseUpdateMode::addNoise, multipleScattering, energyLoss, logger());
0425
0426
0427 detail::setupLoopProtection(state, stepper, result.pathLimitReached, true,
0428 logger());
0429
0430
0431 targetReached.checkAbort(state, stepper, navigator, logger());
0432
0433 return Result<void>::success();
0434 }
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450 template <typename propagator_state_t, typename stepper_t,
0451 typename navigator_t>
0452 Result<void> filter(const Surface& surface, propagator_state_t& state,
0453 const stepper_t& stepper, const navigator_t& navigator,
0454 result_type& result) const {
0455 using PM = TrackStatePropMask;
0456
0457 bool isSensitive = surface.isSensitive();
0458 bool hasMaterial = surface.surfaceMaterial() != nullptr;
0459 bool isMaterialOnly = hasMaterial && !isSensitive;
0460 bool expectMeasurements = isSensitive;
0461
0462 if (isSensitive) {
0463 ACTS_VERBOSE("Measurement surface " << surface.geometryId()
0464 << " detected.");
0465 } else if (isMaterialOnly) {
0466 ACTS_VERBOSE("Material surface " << surface.geometryId()
0467 << " detected.");
0468 } else {
0469 ACTS_VERBOSE("Passive surface " << surface.geometryId()
0470 << " detected.");
0471 return Result<void>::success();
0472 }
0473
0474
0475 if (isMaterialOnly) {
0476 stepper.transportCovarianceToCurvilinear(state.stepping);
0477 } else {
0478 stepper.transportCovarianceToBound(state.stepping, surface);
0479 }
0480
0481
0482 detail::performMaterialInteraction(
0483 state, stepper, navigator,
0484 detail::determineMaterialUpdateMode(state, navigator,
0485 MaterialUpdateMode::PreUpdate),
0486 NoiseUpdateMode::addNoise, multipleScattering, energyLoss, logger());
0487
0488
0489 auto boundStateRes = stepper.boundState(state.stepping, surface, false);
0490 if (!boundStateRes.ok()) {
0491 return boundStateRes.error();
0492 }
0493 auto& boundState = *boundStateRes;
0494 auto& [boundParams, jacobian, pathLength] = boundState;
0495 boundParams.covariance() = state.stepping.cov;
0496
0497 auto currentBranch = result.activeBranches.back();
0498 TrackIndexType prevTip = currentBranch.tipIndex();
0499
0500 using TrackStatesResult = Result<CkfTypes::BranchVector<TrackIndexType>>;
0501 TrackStatesResult tsRes = TrackStatesResult::success({});
0502 if (isSensitive) {
0503
0504
0505
0506 tsRes = extensions.createTrackStates(
0507 state.geoContext, *calibrationContextPtr, surface, boundState,
0508 prevTip, result.trackStateCandidates, *result.trackStates,
0509 logger());
0510 }
0511
0512 if (tsRes.ok() && !(*tsRes).empty()) {
0513 const CkfTypes::BranchVector<TrackIndexType>& newTrackStateList =
0514 *tsRes;
0515 Result<unsigned int> procRes =
0516 processNewTrackStates(state.geoContext, newTrackStateList, result);
0517 if (!procRes.ok()) {
0518 ACTS_DEBUG("Processing of selected track states failed: "
0519 << procRes.error().message());
0520 return procRes.error();
0521 }
0522 unsigned int nBranchesOnSurface = *procRes;
0523
0524 if (nBranchesOnSurface == 0) {
0525 ACTS_VERBOSE("All branches on surface " << surface.geometryId()
0526 << " have been stopped");
0527
0528 reset(state, stepper, navigator, result);
0529
0530 return Result<void>::success();
0531 }
0532
0533
0534 currentBranch = result.activeBranches.back();
0535 prevTip = currentBranch.tipIndex();
0536 } else {
0537 if (!tsRes.ok()) {
0538 if (static_cast<CombinatorialKalmanFilterError>(
0539 tsRes.error().value()) ==
0540 CombinatorialKalmanFilterError::NoMeasurementExpected) {
0541
0542 expectMeasurements = false;
0543 } else {
0544 ACTS_DEBUG("Track state creation failed on surface "
0545 << surface.geometryId() << ": " << tsRes.error());
0546 return tsRes.error();
0547 }
0548 }
0549
0550 if (expectMeasurements) {
0551 ACTS_VERBOSE("Detected hole after measurement selection on surface "
0552 << surface.geometryId());
0553 }
0554
0555 auto stateMask = PM::Predicted | PM::Jacobian;
0556
0557
0558 TrackIndexType currentTip =
0559 addNonSourcelinkState(stateMask, boundState, result, isSensitive,
0560 expectMeasurements, prevTip);
0561 currentBranch.tipIndex() = currentTip;
0562 auto currentState = currentBranch.outermostTrackState();
0563 if (expectMeasurements) {
0564 currentBranch.nHoles()++;
0565 }
0566
0567 BranchStopperResult branchStopperResult =
0568 extensions.branchStopper(currentBranch, currentState);
0569
0570
0571 if (branchStopperResult == BranchStopperResult::Continue) {
0572
0573 } else {
0574
0575 if (branchStopperResult == BranchStopperResult::StopAndKeep) {
0576 storeLastActiveBranch(result);
0577 }
0578
0579 result.activeBranches.pop_back();
0580
0581
0582 ACTS_VERBOSE("Branch on surface " << surface.geometryId()
0583 << " has been stopped");
0584
0585 reset(state, stepper, navigator, result);
0586
0587 return Result<void>::success();
0588 }
0589 }
0590
0591 auto currentState = currentBranch.outermostTrackState();
0592
0593 if (currentState.typeFlags().isOutlier()) {
0594
0595 ACTS_VERBOSE("Outlier state detected on surface "
0596 << surface.geometryId());
0597 } else if (currentState.typeFlags().isMeasurement()) {
0598
0599
0600
0601 stepper.update(state.stepping,
0602 MultiTrajectoryHelpers::freeFiltered(
0603 state.options.geoContext, currentState),
0604 currentState.filtered(),
0605 currentState.filteredCovariance(), surface);
0606 ACTS_VERBOSE("Stepping state is updated with filtered parameter:");
0607 ACTS_VERBOSE("-> " << currentState.filtered().transpose()
0608 << " of track state with tip = "
0609 << currentState.index());
0610 }
0611
0612
0613 detail::performMaterialInteraction(
0614 state, stepper, navigator,
0615 detail::determineMaterialUpdateMode(state, navigator,
0616 MaterialUpdateMode::PostUpdate),
0617 NoiseUpdateMode::addNoise, multipleScattering, energyLoss, logger());
0618
0619 return Result<void>::success();
0620 }
0621
0622
0623
0624
0625
0626
0627
0628
0629
0630
0631
0632 Result<unsigned int> processNewTrackStates(
0633 const GeometryContext& gctx,
0634 const CkfTypes::BranchVector<TrackIndexType>& newTrackStateList,
0635 result_type& result) const {
0636 using PM = TrackStatePropMask;
0637
0638 unsigned int nBranchesOnSurface = 0;
0639
0640 auto rootBranch = result.activeBranches.back();
0641
0642
0643
0644 CkfTypes::BranchVector<TrackProxy> newBranches;
0645 for (auto it = newTrackStateList.rbegin(); it != newTrackStateList.rend();
0646 ++it) {
0647
0648
0649 auto shallowCopy = [&] {
0650 auto sc = rootBranch.container().makeTrack();
0651 sc.copyFromShallow(rootBranch);
0652 return sc;
0653 };
0654 auto newBranch =
0655 (it == newTrackStateList.rbegin()) ? rootBranch : shallowCopy();
0656 newBranch.tipIndex() = *it;
0657 newBranches.push_back(newBranch);
0658 }
0659
0660
0661 result.activeBranches.pop_back();
0662
0663
0664 for (TrackProxy newBranch : newBranches) {
0665 auto trackState = newBranch.outermostTrackState();
0666 TrackStateTypeMap typeFlags = trackState.typeFlags();
0667
0668 if (typeFlags.isOutlier()) {
0669
0670
0671
0672 trackState.shareFrom(PM::Predicted, PM::Filtered);
0673
0674 newBranch.nOutliers()++;
0675 } else if (typeFlags.isMeasurement()) {
0676
0677 auto updateRes = extensions.updater(gctx, trackState, *updaterLogger);
0678 if (!updateRes.ok()) {
0679 ACTS_DEBUG("Update step failed: " << updateRes.error().message());
0680 return updateRes.error();
0681 }
0682 ACTS_VERBOSE("Appended measurement track state with tip = "
0683 << newBranch.tipIndex());
0684
0685 newBranch.nMeasurements()++;
0686 newBranch.nDoF() += trackState.calibratedSize();
0687 newBranch.chi2() += trackState.chi2();
0688 } else {
0689 ACTS_WARNING("Cannot handle this track state flags");
0690 continue;
0691 }
0692
0693 result.activeBranches.push_back(newBranch);
0694
0695 BranchStopperResult branchStopperResult =
0696 extensions.branchStopper(newBranch, trackState);
0697
0698
0699 if (branchStopperResult == BranchStopperResult::Continue) {
0700
0701 nBranchesOnSurface++;
0702 } else {
0703
0704 if (branchStopperResult == BranchStopperResult::StopAndKeep) {
0705 storeLastActiveBranch(result);
0706 }
0707
0708 result.activeBranches.pop_back();
0709 }
0710 }
0711
0712 return nBranchesOnSurface;
0713 }
0714
0715
0716
0717
0718
0719
0720
0721
0722
0723
0724
0725 TrackIndexType addNonSourcelinkState(TrackStatePropMask stateMask,
0726 const BoundState& boundState,
0727 result_type& result, bool isSensitive,
0728 bool expectMeasurements,
0729 TrackIndexType prevTip) const {
0730 using PM = TrackStatePropMask;
0731
0732
0733 auto trackStateProxy =
0734 result.trackStates->makeTrackState(stateMask, prevTip);
0735 ACTS_VERBOSE("Create "
0736 << (isSensitive
0737 ? (expectMeasurements ? "Hole"
0738 : "noMeasurementExpected")
0739 : "Material")
0740 << " output track state #" << trackStateProxy.index()
0741 << " with mask: " << stateMask);
0742
0743 const auto& [boundParams, jacobian, pathLength] = boundState;
0744
0745 trackStateProxy.predicted() = boundParams.parameters();
0746 trackStateProxy.predictedCovariance() = boundParams.covariance().value();
0747 trackStateProxy.jacobian() = jacobian;
0748 trackStateProxy.pathLength() = pathLength;
0749
0750 trackStateProxy.setReferenceSurface(
0751 boundParams.referenceSurface().getSharedPtr());
0752
0753
0754 auto typeFlags = trackStateProxy.typeFlags();
0755 if (trackStateProxy.referenceSurface().surfaceMaterial() != nullptr) {
0756 typeFlags.setHasMaterial();
0757 }
0758 typeFlags.setHasParameters();
0759 if (isSensitive) {
0760 if (expectMeasurements) {
0761 typeFlags.setIsHole();
0762 } else {
0763 typeFlags.setHasNoExpectedHit();
0764 }
0765 }
0766
0767
0768
0769 trackStateProxy.shareFrom(PM::Predicted, PM::Filtered);
0770
0771 return trackStateProxy.index();
0772 }
0773
0774 void storeLastActiveBranch(result_type& result) const {
0775 auto currentBranch = result.activeBranches.back();
0776 TrackIndexType currentTip = currentBranch.tipIndex();
0777
0778 ACTS_VERBOSE("Storing track "
0779 << currentBranch.index() << " with tip index " << currentTip
0780 << ". nMeasurements = " << currentBranch.nMeasurements()
0781 << ", nOutliers = " << currentBranch.nOutliers()
0782 << ", nHoles = " << currentBranch.nHoles());
0783
0784 result.collectedTracks.push_back(currentBranch);
0785 }
0786 };
0787
0788
0789
0790 struct StubPathLimitReached {
0791 double internalLimit{};
0792
0793 template <typename propagator_state_t, typename stepper_t,
0794 typename navigator_t>
0795 bool checkAbort(propagator_state_t& , const stepper_t& ,
0796 const navigator_t& ,
0797 const Logger& ) const {
0798 return false;
0799 }
0800 };
0801
0802 public:
0803
0804
0805
0806
0807
0808
0809
0810
0811
0812
0813
0814
0815
0816
0817 auto findTracks(
0818 const BoundTrackParameters& initialParameters,
0819 const CombinatorialKalmanFilterOptions<track_container_t>& tfOptions,
0820 track_container_t& trackContainer,
0821 typename track_container_t::TrackProxy rootBranch) const
0822 -> Result<std::vector<
0823 typename std::decay_t<decltype(trackContainer)>::TrackProxy>> {
0824
0825 using CombinatorialKalmanFilterActor = Actor;
0826 using Actors = ActorList<CombinatorialKalmanFilterActor>;
0827
0828
0829 using PropagatorOptions = typename propagator_t::template Options<Actors>;
0830 PropagatorOptions propOptions(tfOptions.geoContext,
0831 tfOptions.magFieldContext);
0832
0833
0834 propOptions.setPlainOptions(tfOptions.propagatorPlainOptions);
0835
0836
0837 auto& combKalmanActor =
0838 propOptions.actorList.template get<CombinatorialKalmanFilterActor>();
0839 combKalmanActor.targetReached.surface = tfOptions.targetSurface;
0840 combKalmanActor.multipleScattering = tfOptions.multipleScattering;
0841 combKalmanActor.energyLoss = tfOptions.energyLoss;
0842 combKalmanActor.skipPrePropagationUpdate =
0843 tfOptions.skipPrePropagationUpdate;
0844 combKalmanActor.actorLogger = m_actorLogger.get();
0845 combKalmanActor.updaterLogger = m_updaterLogger.get();
0846 combKalmanActor.calibrationContextPtr = &tfOptions.calibrationContext.get();
0847
0848
0849 combKalmanActor.extensions = tfOptions.extensions;
0850
0851 auto propState =
0852 m_propagator
0853 .template makeState<PropagatorOptions, StubPathLimitReached>(
0854 propOptions);
0855
0856 auto initResult = m_propagator.template initialize<
0857 decltype(propState), BoundTrackParameters, StubPathLimitReached>(
0858 propState, initialParameters);
0859 if (!initResult.ok()) {
0860 ACTS_DEBUG("Propagation initialization failed: " << initResult.error());
0861 return initResult.error();
0862 }
0863
0864 auto& r =
0865 propState
0866 .template get<CombinatorialKalmanFilterResult<track_container_t>>();
0867 r.tracks = &trackContainer;
0868 r.trackStates = &trackContainer.trackStateContainer();
0869
0870
0871 rootBranch.setParticleHypothesis(initialParameters.particleHypothesis());
0872
0873 r.activeBranches.push_back(rootBranch);
0874
0875 auto propagationResult = m_propagator.propagate(propState);
0876
0877 auto result = m_propagator.makeResult(
0878 std::move(propState), propagationResult, propOptions, false);
0879
0880 if (!result.ok()) {
0881 ACTS_DEBUG("Propagation failed: " << result.error() << " "
0882 << result.error().message()
0883 << " with the initial parameters: \n"
0884 << initialParameters.parameters());
0885 return result.error();
0886 }
0887
0888 auto& propRes = *result;
0889
0890
0891 auto combKalmanResult =
0892 std::move(propRes.template get<
0893 CombinatorialKalmanFilterResult<track_container_t>>());
0894
0895
0896 if (!combKalmanResult.finished) {
0897 ACTS_DEBUG("CombinatorialKalmanFilter failed: "
0898 << "Propagation reached max steps "
0899 << "with the initial parameters: "
0900 << initialParameters.parameters().transpose());
0901 return CombinatorialKalmanFilterError::PropagationReachesMaxSteps;
0902 }
0903
0904 return std::move(combKalmanResult.collectedTracks);
0905 }
0906
0907
0908
0909
0910
0911
0912
0913
0914
0915
0916
0917
0918
0919 auto findTracks(
0920 const BoundTrackParameters& initialParameters,
0921 const CombinatorialKalmanFilterOptions<track_container_t>& tfOptions,
0922 track_container_t& trackContainer) const
0923 -> Result<std::vector<
0924 typename std::decay_t<decltype(trackContainer)>::TrackProxy>> {
0925 auto rootBranch = trackContainer.makeTrack();
0926 return findTracks(initialParameters, tfOptions, trackContainer, rootBranch);
0927 }
0928 };
0929
0930
0931
0932 }