45 #include <type_traits>
46 #include <unordered_map>
79 template <
typename traj_t>
82 typename std::vector<typename traj_t::TrackStateProxy>;
84 Delegate<
Result<std::pair<
typename candidate_container_t::iterator,
85 typename candidate_container_t::iterator>>(
108 calibrator.template connect<&detail::voidFitterCalibrator<traj_t>>();
109 updater.template connect<&detail::voidFitterUpdater<traj_t>>();
110 smoother.template connect<&detail::voidFitterSmoother<traj_t>>();
121 typename std::vector<typename traj_t::TrackStateProxy>::iterator,
122 typename std::vector<typename traj_t::TrackStateProxy>::iterator>>
124 typename std::vector<typename traj_t::TrackStateProxy>& candidates,
128 return std::pair{candidates.begin(), candidates.end()};
143 template <
typename source_link_iterator_t>
152 template <
typename source_link_iterator_t,
typename traj_t>
172 std::reference_wrapper<const CalibrationContext> cctx,
176 bool mScattering =
true,
bool eLoss =
true,
bool rSmoothing =
true)
216 CombinatorialKalmanFilterTargetSurfaceStrategy::firstOrLast;
228 template <
typename traj_t>
246 std::unordered_map<MultiTrajectoryTraits::IndexType, BoundTrackParameters>
256 std::unordered_map<const Surface*, std::unordered_map<size_t, size_t>>
300 template <
typename propagator_t,
typename traj_t>
307 std::unique_ptr<const Logger> _logger =
316 using KalmanNavigator =
typename propagator_t::Navigator;
335 template <
typename source_link_accessor_t,
typename parameters_t>
339 using BoundState = std::tuple<parameters_t, BoundMatrix, double>;
341 std::tuple<CurvilinearTrackParameters, BoundMatrix, double>;
355 CombinatorialKalmanFilterTargetSurfaceStrategy::firstOrLast;
379 template <
typename propagator_state_t,
typename stepper_t,
380 typename navigator_t>
383 const Logger& _logger)
const {
395 navigator.navigationBreak(state.navigation,
true);
396 stepper.releaseStepSize(state.stepping);
401 auto surface = navigator.currentSurface(state.navigation);
418 auto res =
filter(
surface, state, stepper, navigator, result);
420 ACTS_ERROR(
"Error in filter: " << res.error());
428 if (navigator.navigationBreak(state.navigation) and not result.
filtered) {
434 const auto& lastActiveTip = result.
activeTips.back().first;
437 result.
fittedStates->getTrackState(lastActiveTip).previous();
441 const auto& [currentTip, tipState] = result.
activeTips.back();
442 if (result.
fittedStates->getTrackState(currentTip).previous() !=
447 if (tipState.nMeasurements > 0) {
449 << currentTip <<
" and there are nMeasurements = "
450 << tipState.nMeasurements
451 <<
", nOutliers = " << tipState.nOutliers
452 <<
", nHoles = " << tipState.nHoles <<
" on track");
456 auto lastMeasurementIndex = currentTip;
457 auto lastMeasurementState =
458 result.
fittedStates->getTrackState(lastMeasurementIndex);
459 bool isMeasurement = lastMeasurementState.typeFlags().test(
461 while (!isMeasurement) {
462 lastMeasurementIndex = lastMeasurementState.previous();
463 lastMeasurementState =
464 result.
fittedStates->getTrackState(lastMeasurementIndex);
465 isMeasurement = lastMeasurementState.typeFlags().test(
485 reset(state, stepper, navigator, result);
491 navigator.targetReached(state.navigation,
false);
502 reset(state, stepper, navigator, result);
525 "Finalize/run smoothing for track with last measurement "
532 auto res =
finalize(state, stepper, navigator, result);
534 ACTS_ERROR(
"Error in finalize: " << res.error());
540 navigator.preStep(state, stepper);
547 MaterialUpdateStage::FullUpdate);
559 "Completing the track with last measurement index = "
567 ACTS_ERROR(
"Error in finalize: " << res.error());
570 auto fittedState = *res;
574 std::get<BoundTrackParameters>(fittedState));
587 state.options.direction = state.options.direction.invert();
591 operator()(state, stepper, navigator, result, _logger);
613 template <
typename propagator_state_t,
typename stepper_t,
614 typename navigator_t>
621 stepper.resetState(state.stepping, currentState.filtered(),
622 currentState.filteredCovariance(),
623 currentState.referenceSurface(),
624 state.options.maxStepSize);
629 navigator.resetState(
630 state.navigation, state.geoContext, stepper.position(state.stepping),
631 state.options.direction * stepper.direction(state.stepping),
632 ¤tState.referenceSurface(),
nullptr);
657 template <
typename propagator_state_t,
typename stepper_t,
658 typename navigator_t>
663 size_t nBranchesOnSurface = 0;
667 if (slBegin != slEnd) {
673 stepper.transportCovarianceToBound(state.stepping, *surface);
677 MaterialUpdateStage::PreUpdate);
681 stepper.boundState(state.stepping, *surface,
false);
682 if (!boundStateRes.ok()) {
683 return boundStateRes.error();
689 size_t prevTip = SIZE_MAX;
693 prevTipState = result.
activeTips.back().second;
701 prevTip, slBegin, slEnd);
708 bool isOutlier =
false;
712 if (!selectorResult.ok()) {
713 ACTS_ERROR(
"Selection of calibrated measurements failed: "
714 << selectorResult.error());
715 return selectorResult.error();
717 auto selectedTrackStateRange = *selectorResult;
720 state.geoContext, selectedTrackStateRange.first,
721 selectedTrackStateRange.second, result, isOutlier, prevTipState,
726 "Processing of selected track states failed: " << procRes.error())
727 return procRes.error();
730 if (nBranchesOnSurface > 0 and not isOutlier) {
732 ACTS_VERBOSE(
"Filtering step successful with " << nBranchesOnSurface
738 stepper.update(state.stepping,
740 state.options.geoContext, ts),
741 ts.filtered(), ts.filteredCovariance(), *
surface);
742 ACTS_VERBOSE(
"Stepping state is updated with filtered parameter:");
744 <<
" of track state with tip = "
749 MaterialUpdateStage::PostUpdate);
754 nBranchesOnSurface = 1;
757 size_t prevTip = SIZE_MAX;
777 bool createState =
false;
792 ~(TrackStatePropMask::Calibrated | TrackStatePropMask::Filtered);
796 size_t currentTip = SIZE_MAX;
803 auto res = stepper.boundState(state.stepping, *surface);
805 ACTS_ERROR(
"Error in filter: " << res.error());
811 isSensitive, prevTip);
816 result.
activeTips.emplace_back(currentTip, tipState);
819 nBranchesOnSurface = 0;
825 MaterialUpdateStage::FullUpdate);
829 nBranchesOnSurface = 1;
833 if (nBranchesOnSurface == 0) {
839 reset(state, stepper, navigator, result);
858 template <
typename source_link_iterator_t>
863 source_link_iterator_t slBegin,
864 source_link_iterator_t slEnd)
const {
868 if constexpr (std::is_same_v<
869 typename std::iterator_traits<
870 source_link_iterator_t>::iterator_category,
871 std::random_access_iterator_tag>) {
881 for (
auto it = slBegin;
it != slEnd; ++
it) {
883 const auto sourceLink = *
it;
890 mask = PM::Calibrated;
894 "Create temp track state with mask: " << std::bitset<
895 sizeof(std::underlying_type_t<TrackStatePropMask>) * 8>(
896 static_cast<std::underlying_type_t<TrackStatePropMask>
>(mask)));
897 size_t tsi = result.
stateBuffer->addTrackState(mask, prevTip);
905 ts.predicted() = boundParams.parameters();
906 if (boundParams.covariance()) {
907 ts.predictedCovariance() = *boundParams.covariance();
909 ts.jacobian() = jacobian;
913 ts.shareFrom(first, PM::Predicted);
919 ts.setReferenceSurface(boundParams.referenceSurface().getSharedPtr());
938 typename std::vector<typename traj_t::TrackStateProxy>::const_iterator
940 typename std::vector<typename traj_t::TrackStateProxy>::const_iterator
943 size_t& nBranchesOnSurface)
const {
946 std::optional<typename traj_t::TrackStateProxy> firstTrackState{
949 auto& candidateTrackState = *
it;
959 mask &= ~PM::Filtered;
964 typename traj_t::TrackStateProxy trackState =
967 mask, candidateTrackState.previous()));
969 "Create SourceLink output track state #"
970 << trackState.index() <<
" with mask: "
971 << std::bitset<sizeof(std::underlying_type_t<TrackStatePropMask>) *
973 static_cast<std::underlying_type_t<TrackStatePropMask>
>(
978 trackState.shareFrom(*firstTrackState, PM::Predicted);
981 firstTrackState = trackState;
985 trackState.allocateCalibrated(candidateTrackState.calibratedSize());
986 trackState.copyFrom(candidateTrackState, mask,
false);
988 auto typeFlags = trackState.typeFlags();
989 if (trackState.referenceSurface().surfaceMaterial() !=
nullptr) {
997 size_t currentTip = trackState.index();
1005 "Creating outlier track state with tip = " << currentTip);
1013 trackState.shareFrom(PM::Predicted, PM::Filtered);
1019 if (!updateRes.ok()) {
1020 ACTS_ERROR(
"Update step failed: " << updateRes.error());
1021 return updateRes.error();
1024 "Creating measurement track state with tip = " << currentTip);
1034 result.
activeTips.emplace_back(currentTip, tipState);
1036 nBranchesOnSurface++;
1055 size_t prevTip)
const {
1057 auto currentTip = result.
fittedStates->addTrackState(stateMask, prevTip);
1060 << (isSensitive ?
"Hole" :
"Material") <<
" output track state #"
1061 << currentTip <<
" with mask: "
1062 << std::bitset<
sizeof(std::underlying_type_t<TrackStatePropMask>) *
1064 static_cast<std::underlying_type_t<TrackStatePropMask>
>(
1067 auto trackStateProxy = result.
fittedStates->getTrackState(currentTip);
1071 trackStateProxy.predicted() = boundParams.parameters();
1072 if (boundParams.covariance().has_value()) {
1073 trackStateProxy.predictedCovariance() = *boundParams.covariance();
1075 trackStateProxy.jacobian() = jacobian;
1078 trackStateProxy.setReferenceSurface(
1079 boundParams.referenceSurface().getSharedPtr());
1084 auto typeFlags = trackStateProxy.typeFlags();
1085 if (trackStateProxy.referenceSurface().surfaceMaterial() !=
nullptr) {
1093 trackStateProxy.shareFrom(TrackStatePropMask::Predicted,
1094 TrackStatePropMask::Filtered);
1111 template <
typename propagator_state_t,
typename stepper_t,
1112 typename navigator_t>
1117 if (surface ==
nullptr) {
1122 bool hasMaterial =
false;
1140 <<
" at update stage: " << updateStage <<
" are :");
1143 <<
"variancePhi = " << interaction.
variancePhi <<
", "
1153 if (not hasMaterial) {
1156 <<
" at update stage: "
1171 template <
typename propagator_state_t,
typename stepper_t,
1172 typename navigator_t>
1177 const auto& lastMeasurementIndex =
1182 size_t firstStateIndex = lastMeasurementIndex;
1185 result.
fittedStates->applyBackwards(lastMeasurementIndex, [&](
auto st) {
1186 bool isMeasurement =
1192 if (isMeasurement && !isOutlier) {
1193 firstStateIndex = st.index();
1200 ACTS_ERROR(
"Smoothing for a track without measurements.");
1201 return CombinatorialKalmanFilterError::SmoothFailed;
1205 <<
" filtered track states.");
1211 if (!smoothRes.ok()) {
1212 ACTS_ERROR(
"Smoothing step failed: " << smoothRes.error());
1213 return smoothRes.error();
1222 auto firstCreatedState =
1224 auto lastCreatedMeasurement =
1225 result.
fittedStates->getTrackState(lastMeasurementIndex);
1231 state.geoContext, freeVector.segment<3>(
eFreePos0),
1232 state.options.direction * freeVector.segment<3>(
eFreeDir0),
1233 true, state.options.targetTolerance)
1240 state.options.geoContext, firstCreatedState);
1242 state.options.geoContext, lastCreatedMeasurement);
1245 const auto firstIntersection =
target(firstParams);
1246 const auto lastIntersection =
target(lastParams);
1256 bool useFirstTrackState =
true;
1258 case CombinatorialKalmanFilterTargetSurfaceStrategy::first:
1259 useFirstTrackState =
true;
1261 case CombinatorialKalmanFilterTargetSurfaceStrategy::last:
1262 useFirstTrackState =
false;
1264 case CombinatorialKalmanFilterTargetSurfaceStrategy::firstOrLast:
1265 useFirstTrackState = std::abs(firstIntersection.pathLength()) <=
1266 std::abs(lastIntersection.pathLength());
1269 ACTS_ERROR(
"Unknown target surface strategy");
1270 return KalmanFitterError::SmoothFailed;
1272 bool reverseDirection =
false;
1273 if (useFirstTrackState) {
1274 stepper.resetState(state.stepping, firstCreatedState.smoothed(),
1275 firstCreatedState.smoothedCovariance(),
1276 firstCreatedState.referenceSurface(),
1277 state.options.maxStepSize);
1278 reverseDirection = firstIntersection.pathLength() < 0;
1280 stepper.resetState(state.stepping, lastCreatedMeasurement.smoothed(),
1281 lastCreatedMeasurement.smoothedCovariance(),
1282 lastCreatedMeasurement.referenceSurface(),
1283 state.options.maxStepSize);
1284 reverseDirection = lastIntersection.pathLength() < 0;
1287 if (reverseDirection) {
1289 "Reverse navigation direction after smoothing for reaching the "
1291 state.options.direction = state.options.direction.invert();
1293 const auto&
surface = useFirstTrackState
1294 ? firstCreatedState.referenceSurface()
1295 : lastCreatedMeasurement.referenceSurface();
1298 "Smoothing successful, updating stepping state to smoothed "
1299 "parameters at surface "
1300 <<
surface.geometryId() <<
". Prepared to reach the target surface.");
1305 navigator.resetState(
1306 state.navigation, state.geoContext, stepper.position(state.stepping),
1307 state.options.direction * stepper.direction(state.stepping), &
surface,
1337 template <
typename source_link_accessor_t,
typename parameters_t>
1343 template <
typename propagator_state_t,
typename stepper_t,
1344 typename navigator_t,
typename result_t>
1346 const navigator_t& ,
const result_t& result,
1348 if (result.finished) {
1378 template <
typename source_link_iterator_t,
typename start_parameters_t,
1379 typename track_container_t,
template <
typename>
class holder_t,
1382 const start_parameters_t& initialParameters,
1387 typename std::decay_t<decltype(trackContainer)>::TrackProxy>> {
1388 using TrackContainer =
typename std::decay_t<decltype(trackContainer)>;
1389 using SourceLinkAccessor =
1393 using CombinatorialKalmanFilterAborter =
1395 using CombinatorialKalmanFilterActor =
1397 using Actors = ActionList<CombinatorialKalmanFilterActor>;
1398 using Aborters = AbortList<CombinatorialKalmanFilterAborter>;
1402 tfOptions.magFieldContext);
1408 auto& combKalmanActor =
1409 propOptions.
actionList.template get<CombinatorialKalmanFilterActor>();
1410 combKalmanActor.filterTargetSurface = tfOptions.filterTargetSurface;
1411 combKalmanActor.smoothingTargetSurface = tfOptions.smoothingTargetSurface;
1412 combKalmanActor.smoothingTargetSurfaceStrategy =
1413 tfOptions.smoothingTargetSurfaceStrategy;
1414 combKalmanActor.multipleScattering = tfOptions.multipleScattering;
1415 combKalmanActor.energyLoss = tfOptions.energyLoss;
1416 combKalmanActor.smoothing = tfOptions.smoothing;
1420 combKalmanActor.calibrationContext = &tfOptions.calibrationContext.get();
1423 combKalmanActor.m_sourcelinkAccessor = tfOptions.sourcelinkAccessor;
1424 combKalmanActor.m_extensions = tfOptions.extensions;
1427 auto stateBuffer = std::make_shared<traj_t>();
1429 typename propagator_t::template action_list_t_result_t<
1434 inputResult.template get<CombinatorialKalmanFilterResult<traj_t>>();
1436 r.fittedStates = &trackContainer.trackStateContainer();
1437 r.stateBuffer = stateBuffer;
1438 r.stateBuffer->clear();
1441 initialParameters, propOptions,
false,
std::move(inputResult));
1444 ACTS_ERROR(
"Propagation failed: " << result.error() <<
" "
1445 << result.error().message()
1446 <<
" with the initial parameters: \n"
1447 << initialParameters.parameters());
1448 return result.error();
1451 auto& propRes = *result;
1464 if (combKalmanResult.lastError.ok() and not combKalmanResult.finished) {
1466 CombinatorialKalmanFilterError::PropagationReachesMaxSteps);
1469 if (!combKalmanResult.lastError.ok()) {
1470 ACTS_ERROR(
"CombinatorialKalmanFilter failed: "
1471 << combKalmanResult.lastError.error() <<
" "
1472 << combKalmanResult.lastError.error().message()
1473 <<
" with the initial parameters: \n"
1474 << initialParameters.parameters());
1477 std::vector<typename TrackContainer::TrackProxy>
tracks;
1479 for (
auto tip : combKalmanResult.lastMeasurementIndices) {
1480 auto it = combKalmanResult.fittedParameters.find(tip);
1481 if (
it == combKalmanResult.fittedParameters.end()) {
1485 auto track = trackContainer.getTrack(trackContainer.addTrack());
1486 track.tipIndex() = tip;
1489 track.parameters() = parameters.
parameters();
1490 track.covariance() = *parameters.
covariance();
1495 tracks.push_back(track);