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