File indexing completed on 2025-07-05 08:11:15
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/TrackParametrization.hpp"
0012 #include "Acts/EventData/MultiComponentTrackParameters.hpp"
0013 #include "Acts/EventData/MultiTrajectory.hpp"
0014 #include "Acts/EventData/MultiTrajectoryHelpers.hpp"
0015 #include "Acts/Propagator/detail/PointwiseMaterialInteraction.hpp"
0016 #include "Acts/Surfaces/Surface.hpp"
0017 #include "Acts/TrackFitting/GsfOptions.hpp"
0018 #include "Acts/TrackFitting/detail/GsfComponentMerging.hpp"
0019 #include "Acts/TrackFitting/detail/GsfUtils.hpp"
0020 #include "Acts/TrackFitting/detail/KalmanUpdateHelpers.hpp"
0021 #include "Acts/Utilities/Helpers.hpp"
0022 #include "Acts/Utilities/Zip.hpp"
0023
0024 #include <ios>
0025 #include <map>
0026
0027 namespace Acts::detail {
0028
0029 template <typename traj_t>
0030 struct GsfResult {
0031
0032 traj_t* fittedStates{nullptr};
0033
0034
0035 MultiTrajectoryTraits::IndexType currentTip = MultiTrajectoryTraits::kInvalid;
0036
0037
0038 MultiTrajectoryTraits::IndexType lastMeasurementTip =
0039 MultiTrajectoryTraits::kInvalid;
0040
0041
0042
0043 std::vector<std::tuple<double, BoundVector, BoundMatrix>>
0044 lastMeasurementComponents;
0045
0046
0047 const Acts::Surface* lastMeasurementSurface = nullptr;
0048
0049
0050 std::size_t measurementStates = 0;
0051 std::size_t measurementHoles = 0;
0052 std::size_t processedStates = 0;
0053
0054 std::vector<const Surface*> visitedSurfaces;
0055 std::vector<const Surface*> surfacesVisitedBwdAgain;
0056
0057
0058 Updatable<std::size_t> nInvalidBetheHeitler;
0059 Updatable<double> maxPathXOverX0;
0060 Updatable<double> sumPathXOverX0;
0061
0062
0063 Result<void> result{Result<void>::success()};
0064
0065
0066 std::vector<GsfComponent> componentCache;
0067 };
0068
0069
0070 template <typename bethe_heitler_approx_t, typename traj_t>
0071 struct GsfActor {
0072
0073 GsfActor() = default;
0074
0075 using ComponentCache = GsfComponent;
0076
0077
0078 using result_type = GsfResult<traj_t>;
0079
0080
0081 struct Config {
0082
0083 std::size_t maxComponents = 16;
0084
0085
0086 const std::map<GeometryIdentifier, SourceLink>* inputMeasurements = nullptr;
0087
0088
0089
0090 const bethe_heitler_approx_t* bethe_heitler_approx = nullptr;
0091
0092
0093 bool multipleScattering = true;
0094
0095
0096 double weightCutoff = 1.0e-4;
0097
0098
0099
0100
0101 bool disableAllMaterialHandling = false;
0102
0103
0104 bool abortOnError = false;
0105
0106
0107
0108 std::optional<std::size_t> numberMeasurements;
0109
0110
0111 GsfExtensions<traj_t> extensions;
0112
0113
0114
0115
0116 bool inReversePass = false;
0117
0118
0119 ComponentMergeMethod mergeMethod = ComponentMergeMethod::eMaxWeight;
0120
0121 const Logger* logger{nullptr};
0122
0123
0124 const CalibrationContext* calibrationContext{nullptr};
0125
0126 } m_cfg;
0127
0128 const Logger& logger() const { return *m_cfg.logger; }
0129
0130 struct TemporaryStates {
0131 traj_t traj;
0132 std::vector<MultiTrajectoryTraits::IndexType> tips;
0133 std::map<MultiTrajectoryTraits::IndexType, double> weights;
0134 };
0135
0136 using FiltProjector = MultiTrajectoryProjector<StatesType::eFiltered, traj_t>;
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147 template <typename propagator_state_t, typename stepper_t,
0148 typename navigator_t>
0149 void act(propagator_state_t& state, const stepper_t& stepper,
0150 const navigator_t& navigator, result_type& result,
0151 const Logger& ) const {
0152 assert(result.fittedStates && "No MultiTrajectory set");
0153
0154
0155 if (!result.result.ok()) {
0156 ACTS_WARNING("result.result not ok, return!");
0157 return;
0158 }
0159
0160
0161 auto setErrorOrAbort = [&](auto error) {
0162 if (m_cfg.abortOnError) {
0163 std::abort();
0164 } else {
0165 result.result = error;
0166 }
0167 };
0168
0169
0170
0171 const detail::ScopedGsfInfoPrinterAndChecker printer(state, stepper,
0172 navigator, logger());
0173
0174
0175 if (!navigator.currentSurface(state.navigation)) {
0176 return;
0177 }
0178
0179 const auto& surface = *navigator.currentSurface(state.navigation);
0180 ACTS_VERBOSE("Step is at surface " << surface.geometryId());
0181
0182
0183
0184 [[maybe_unused]] auto stepperComponents =
0185 stepper.constComponentIterable(state.stepping);
0186 assert(detail::weightsAreNormalized(
0187 stepperComponents, [](const auto& cmp) { return cmp.weight(); }));
0188
0189
0190
0191
0192 using Status [[maybe_unused]] = IntersectionStatus;
0193 assert(std::all_of(
0194 stepperComponents.begin(), stepperComponents.end(),
0195 [](const auto& cmp) { return cmp.status() == Status::onSurface; }));
0196
0197
0198
0199 const bool visited = rangeContainsValue(result.visitedSurfaces, &surface);
0200
0201 if (visited) {
0202 ACTS_VERBOSE("Already visited surface, return");
0203 return;
0204 }
0205
0206 result.visitedSurfaces.push_back(&surface);
0207
0208
0209 const auto foundSourceLink =
0210 m_cfg.inputMeasurements->find(surface.geometryId());
0211 const bool haveMaterial =
0212 navigator.currentSurface(state.navigation)->surfaceMaterial() &&
0213 !m_cfg.disableAllMaterialHandling;
0214 const bool haveMeasurement =
0215 foundSourceLink != m_cfg.inputMeasurements->end();
0216
0217 ACTS_VERBOSE(std::boolalpha << "haveMaterial " << haveMaterial
0218 << ", haveMeasurement: " << haveMeasurement);
0219
0220
0221
0222
0223
0224
0225 if (!haveMaterial && !haveMeasurement) {
0226
0227 if (result.processedStates > 0 && surface.associatedDetectorElement()) {
0228 TemporaryStates tmpStates;
0229 noMeasurementUpdate(state, stepper, navigator, result, tmpStates, true);
0230 }
0231 return;
0232 }
0233
0234
0235
0236
0237 if (haveMeasurement) {
0238 result.maxPathXOverX0.update();
0239 result.sumPathXOverX0.update();
0240 result.nInvalidBetheHeitler.update();
0241 }
0242
0243 for (auto cmp : stepper.componentIterable(state.stepping)) {
0244 cmp.singleStepper(stepper).transportCovarianceToBound(cmp.state(),
0245 surface);
0246 }
0247
0248 if (haveMaterial) {
0249 if (haveMeasurement) {
0250 applyMultipleScattering(state, stepper, navigator,
0251 MaterialUpdateStage::PreUpdate);
0252 } else {
0253 applyMultipleScattering(state, stepper, navigator,
0254 MaterialUpdateStage::FullUpdate);
0255 }
0256 }
0257
0258
0259
0260
0261 if (!haveMaterial) {
0262 TemporaryStates tmpStates;
0263
0264 auto res = kalmanUpdate(state, stepper, navigator, result, tmpStates,
0265 foundSourceLink->second);
0266
0267 if (!res.ok()) {
0268 setErrorOrAbort(res.error());
0269 return;
0270 }
0271
0272 updateStepper(state, stepper, tmpStates);
0273 }
0274
0275
0276
0277 else {
0278 TemporaryStates tmpStates;
0279 Result<void> res;
0280
0281 if (haveMeasurement) {
0282 res = kalmanUpdate(state, stepper, navigator, result, tmpStates,
0283 foundSourceLink->second);
0284 } else {
0285 res = noMeasurementUpdate(state, stepper, navigator, result, tmpStates,
0286 false);
0287 }
0288
0289 if (!res.ok()) {
0290 setErrorOrAbort(res.error());
0291 return;
0292 }
0293
0294
0295 std::vector<ComponentCache>& componentCache = result.componentCache;
0296 componentCache.clear();
0297
0298 convoluteComponents(state, stepper, navigator, tmpStates, componentCache,
0299 result);
0300
0301 if (componentCache.empty()) {
0302 ACTS_WARNING(
0303 "No components left after applying energy loss. "
0304 "Is the weight cutoff "
0305 << m_cfg.weightCutoff << " too high?");
0306 ACTS_WARNING("Return to propagator without applying energy loss");
0307 return;
0308 }
0309
0310
0311 const auto finalCmpNumber = std::min(
0312 static_cast<std::size_t>(stepper.maxComponents), m_cfg.maxComponents);
0313 m_cfg.extensions.mixtureReducer(componentCache, finalCmpNumber, surface);
0314
0315 removeLowWeightComponents(componentCache);
0316
0317 updateStepper(state, stepper, navigator, componentCache);
0318 }
0319
0320
0321 if (haveMaterial && haveMeasurement) {
0322 applyMultipleScattering(state, stepper, navigator,
0323 MaterialUpdateStage::PostUpdate);
0324 }
0325 }
0326
0327 template <typename propagator_state_t, typename stepper_t,
0328 typename navigator_t>
0329 bool checkAbort(propagator_state_t& , const stepper_t& ,
0330 const navigator_t& , const result_type& result,
0331 const Logger& ) const {
0332 if (m_cfg.numberMeasurements &&
0333 result.measurementStates == m_cfg.numberMeasurements) {
0334 ACTS_VERBOSE("Stop navigation because all measurements are found");
0335 return true;
0336 }
0337
0338 return false;
0339 }
0340
0341 template <typename propagator_state_t, typename stepper_t,
0342 typename navigator_t>
0343 void convoluteComponents(propagator_state_t& state, const stepper_t& stepper,
0344 const navigator_t& navigator,
0345 const TemporaryStates& tmpStates,
0346 std::vector<ComponentCache>& componentCache,
0347 result_type& result) const {
0348 auto cmps = stepper.componentIterable(state.stepping);
0349 double pathXOverX0 = 0.0;
0350 for (auto [idx, cmp] : zip(tmpStates.tips, cmps)) {
0351 auto proxy = tmpStates.traj.getTrackState(idx);
0352
0353 BoundTrackParameters bound(proxy.referenceSurface().getSharedPtr(),
0354 proxy.filtered(), proxy.filteredCovariance(),
0355 stepper.particleHypothesis(state.stepping));
0356
0357 pathXOverX0 +=
0358 applyBetheHeitler(state, navigator, bound, tmpStates.weights.at(idx),
0359 componentCache, result);
0360 }
0361
0362
0363
0364 result.sumPathXOverX0.tmp() += pathXOverX0 / tmpStates.tips.size();
0365 }
0366
0367 template <typename propagator_state_t, typename navigator_t>
0368 double applyBetheHeitler(const propagator_state_t& state,
0369 const navigator_t& navigator,
0370 const BoundTrackParameters& old_bound,
0371 const double old_weight,
0372 std::vector<ComponentCache>& componentCaches,
0373 result_type& result) const {
0374 const auto& surface = *navigator.currentSurface(state.navigation);
0375 const auto p_prev = old_bound.absoluteMomentum();
0376 const auto& particleHypothesis = old_bound.particleHypothesis();
0377
0378
0379 auto slab = surface.surfaceMaterial()->materialSlab(
0380 old_bound.position(state.geoContext), state.options.direction,
0381 MaterialUpdateStage::FullUpdate);
0382
0383 const auto pathCorrection = surface.pathCorrection(
0384 state.geoContext, old_bound.position(state.geoContext),
0385 old_bound.direction());
0386 slab.scaleThickness(pathCorrection);
0387
0388 const double pathXOverX0 = slab.thicknessInX0();
0389 result.maxPathXOverX0.tmp() =
0390 std::max(result.maxPathXOverX0.tmp(), pathXOverX0);
0391
0392
0393 if (!m_cfg.bethe_heitler_approx->validXOverX0(pathXOverX0)) {
0394 ++result.nInvalidBetheHeitler.tmp();
0395 ACTS_DEBUG(
0396 "Bethe-Heitler approximation encountered invalid value for x/x0="
0397 << pathXOverX0 << " at surface " << surface.geometryId());
0398 }
0399
0400
0401 const auto mixture = m_cfg.bethe_heitler_approx->mixture(pathXOverX0);
0402
0403
0404 for (const auto& gaussian : mixture) {
0405
0406
0407 const auto new_weight = gaussian.weight * old_weight;
0408
0409 if (new_weight < m_cfg.weightCutoff) {
0410 ACTS_VERBOSE("Skip component with weight " << new_weight);
0411 continue;
0412 }
0413
0414 if (gaussian.mean < 1.e-8) {
0415 ACTS_WARNING("Skip component with gaussian " << gaussian.mean << " +- "
0416 << gaussian.var);
0417 continue;
0418 }
0419
0420
0421 auto new_pars = old_bound.parameters();
0422
0423 const auto delta_p = [&]() {
0424 if (state.options.direction == Direction::Forward()) {
0425 return p_prev * (gaussian.mean - 1.);
0426 } else {
0427 return p_prev * (1. / gaussian.mean - 1.);
0428 }
0429 }();
0430
0431 assert(p_prev + delta_p > 0. && "new momentum must be > 0");
0432 new_pars[eBoundQOverP] =
0433 particleHypothesis.qOverP(p_prev + delta_p, old_bound.charge());
0434
0435
0436 auto new_cov = old_bound.covariance().value();
0437
0438 const auto varInvP = [&]() {
0439 if (state.options.direction == Direction::Forward()) {
0440 const auto f = 1. / (p_prev * gaussian.mean);
0441 return f * f * gaussian.var;
0442 } else {
0443 return gaussian.var / (p_prev * p_prev);
0444 }
0445 }();
0446
0447 new_cov(eBoundQOverP, eBoundQOverP) += varInvP;
0448 assert(std::isfinite(new_cov(eBoundQOverP, eBoundQOverP)) &&
0449 "new cov not finite");
0450
0451
0452 componentCaches.push_back({new_weight, new_pars, new_cov});
0453 }
0454
0455 return pathXOverX0;
0456 }
0457
0458
0459
0460
0461
0462 void removeLowWeightComponents(std::vector<ComponentCache>& cmps) const {
0463 auto proj = [](auto& cmp) -> double& { return cmp.weight; };
0464
0465 detail::normalizeWeights(cmps, proj);
0466
0467 auto new_end = std::remove_if(cmps.begin(), cmps.end(), [&](auto& cmp) {
0468 return proj(cmp) < m_cfg.weightCutoff;
0469 });
0470
0471
0472 if (std::distance(cmps.begin(), new_end) == 0) {
0473 cmps = {*std::max_element(
0474 cmps.begin(), cmps.end(),
0475 [&](auto& a, auto& b) { return proj(a) < proj(b); })};
0476 cmps.front().weight = 1.0;
0477 } else {
0478 cmps.erase(new_end, cmps.end());
0479 detail::normalizeWeights(cmps, proj);
0480 }
0481 }
0482
0483
0484 template <typename propagator_state_t, typename stepper_t>
0485 void updateStepper(propagator_state_t& state, const stepper_t& stepper,
0486 const TemporaryStates& tmpStates) const {
0487 auto cmps = stepper.componentIterable(state.stepping);
0488
0489 for (auto [idx, cmp] : zip(tmpStates.tips, cmps)) {
0490
0491
0492 if (tmpStates.weights.at(idx) < m_cfg.weightCutoff) {
0493 cmp.status() = IntersectionStatus::unreachable;
0494 continue;
0495 }
0496
0497 auto proxy = tmpStates.traj.getTrackState(idx);
0498
0499 cmp.pars() =
0500 MultiTrajectoryHelpers::freeFiltered(state.geoContext, proxy);
0501 cmp.cov() = proxy.filteredCovariance();
0502 cmp.weight() = tmpStates.weights.at(idx);
0503 }
0504
0505 stepper.removeMissedComponents(state.stepping);
0506
0507
0508
0509 detail::normalizeWeights(cmps,
0510 [&](auto cmp) -> double& { return cmp.weight(); });
0511 }
0512
0513
0514 template <typename propagator_state_t, typename stepper_t,
0515 typename navigator_t>
0516 void updateStepper(propagator_state_t& state, const stepper_t& stepper,
0517 const navigator_t& navigator,
0518 const std::vector<ComponentCache>& componentCache) const {
0519 const auto& surface = *navigator.currentSurface(state.navigation);
0520
0521
0522 stepper.clearComponents(state.stepping);
0523
0524
0525 for (const auto& [weight, pars, cov] : componentCache) {
0526
0527 BoundTrackParameters bound(surface.getSharedPtr(), pars, cov,
0528 stepper.particleHypothesis(state.stepping));
0529
0530 auto res = stepper.addComponent(state.stepping, std::move(bound), weight);
0531
0532 if (!res.ok()) {
0533 ACTS_ERROR("Error adding component to MultiStepper");
0534 continue;
0535 }
0536
0537 auto& cmp = *res;
0538 auto freeParams = cmp.pars();
0539 cmp.jacToGlobal() = surface.boundToFreeJacobian(
0540 state.geoContext, freeParams.template segment<3>(eFreePos0),
0541 freeParams.template segment<3>(eFreeDir0));
0542 cmp.pathAccumulated() = state.stepping.pathAccumulated;
0543 cmp.jacobian() = BoundMatrix::Identity();
0544 cmp.derivative() = FreeVector::Zero();
0545 cmp.jacTransport() = FreeMatrix::Identity();
0546 }
0547 }
0548
0549
0550
0551 template <typename propagator_state_t, typename stepper_t,
0552 typename navigator_t>
0553 Result<void> kalmanUpdate(propagator_state_t& state, const stepper_t& stepper,
0554 const navigator_t& navigator, result_type& result,
0555 TemporaryStates& tmpStates,
0556 const SourceLink& sourceLink) const {
0557 const auto& surface = *navigator.currentSurface(state.navigation);
0558
0559
0560
0561
0562
0563 bool is_valid_measurement = false;
0564
0565 auto cmps = stepper.componentIterable(state.stepping);
0566 for (auto cmp : cmps) {
0567 auto singleState = cmp.singleState(state);
0568 const auto& singleStepper = cmp.singleStepper(stepper);
0569
0570 auto trackStateProxyRes = detail::kalmanHandleMeasurement(
0571 *m_cfg.calibrationContext, singleState, singleStepper,
0572 m_cfg.extensions, surface, sourceLink, tmpStates.traj,
0573 MultiTrajectoryTraits::kInvalid, false, logger());
0574
0575 if (!trackStateProxyRes.ok()) {
0576 return trackStateProxyRes.error();
0577 }
0578
0579 const auto& trackStateProxy = *trackStateProxyRes;
0580
0581
0582
0583 if (trackStateProxy.typeFlags().test(TrackStateFlag::MeasurementFlag)) {
0584 is_valid_measurement = true;
0585 }
0586
0587 tmpStates.tips.push_back(trackStateProxy.index());
0588 tmpStates.weights[tmpStates.tips.back()] = cmp.weight();
0589 }
0590
0591 computePosteriorWeights(tmpStates.traj, tmpStates.tips, tmpStates.weights);
0592
0593 detail::normalizeWeights(tmpStates.tips, [&](auto idx) -> double& {
0594 return tmpStates.weights.at(idx);
0595 });
0596
0597
0598 ++result.processedStates;
0599
0600
0601 if (is_valid_measurement) {
0602 ++result.measurementStates;
0603 }
0604
0605 updateMultiTrajectory(result, tmpStates, surface);
0606
0607 result.lastMeasurementTip = result.currentTip;
0608 result.lastMeasurementSurface = &surface;
0609
0610
0611
0612 result.lastMeasurementComponents.clear();
0613
0614 FiltProjector proj{tmpStates.traj, tmpStates.weights};
0615 for (const auto& idx : tmpStates.tips) {
0616 const auto& [w, p, c] = proj(idx);
0617
0618 if (w > 0.0) {
0619 result.lastMeasurementComponents.push_back({w, p, c});
0620 }
0621 }
0622
0623
0624 return Result<void>::success();
0625 }
0626
0627 template <typename propagator_state_t, typename stepper_t,
0628 typename navigator_t>
0629 Result<void> noMeasurementUpdate(propagator_state_t& state,
0630 const stepper_t& stepper,
0631 const navigator_t& navigator,
0632 result_type& result,
0633 TemporaryStates& tmpStates,
0634 bool doCovTransport) const {
0635 const auto& surface = *navigator.currentSurface(state.navigation);
0636
0637 const bool precedingMeasurementExists = result.processedStates > 0;
0638
0639
0640
0641 bool isHole = true;
0642
0643 for (auto cmp : stepper.componentIterable(state.stepping)) {
0644 auto& singleState = cmp.state();
0645 const auto& singleStepper = cmp.singleStepper(stepper);
0646
0647
0648
0649 auto trackStateProxyRes = detail::kalmanHandleNoMeasurement(
0650 singleState, singleStepper, surface, tmpStates.traj,
0651 MultiTrajectoryTraits::kInvalid, doCovTransport, logger(),
0652 precedingMeasurementExists);
0653
0654 if (!trackStateProxyRes.ok()) {
0655 return trackStateProxyRes.error();
0656 }
0657
0658 const auto& trackStateProxy = *trackStateProxyRes;
0659
0660 if (!trackStateProxy.typeFlags().test(TrackStateFlag::HoleFlag)) {
0661 isHole = false;
0662 }
0663
0664 tmpStates.tips.push_back(trackStateProxy.index());
0665 tmpStates.weights[tmpStates.tips.back()] = cmp.weight();
0666 }
0667
0668
0669 if (isHole) {
0670 ++result.measurementHoles;
0671 }
0672
0673 ++result.processedStates;
0674
0675 updateMultiTrajectory(result, tmpStates, surface);
0676
0677 return Result<void>::success();
0678 }
0679
0680
0681 template <typename propagator_state_t, typename stepper_t,
0682 typename navigator_t>
0683 void applyMultipleScattering(propagator_state_t& state,
0684 const stepper_t& stepper,
0685 const navigator_t& navigator,
0686 const MaterialUpdateStage& updateStage =
0687 MaterialUpdateStage::FullUpdate) const {
0688 const auto& surface = *navigator.currentSurface(state.navigation);
0689
0690 for (auto cmp : stepper.componentIterable(state.stepping)) {
0691 auto singleState = cmp.singleState(state);
0692 const auto& singleStepper = cmp.singleStepper(stepper);
0693
0694 detail::PointwiseMaterialInteraction interaction(&surface, singleState,
0695 singleStepper);
0696 if (interaction.evaluateMaterialSlab(singleState, navigator,
0697 updateStage)) {
0698
0699 interaction.evaluatePointwiseMaterialInteraction(
0700 m_cfg.multipleScattering, false);
0701
0702
0703 ACTS_VERBOSE("Material effects on surface: "
0704 << surface.geometryId()
0705 << " at update stage: " << updateStage << " are :");
0706 ACTS_VERBOSE("eLoss = "
0707 << interaction.Eloss << ", "
0708 << "variancePhi = " << interaction.variancePhi << ", "
0709 << "varianceTheta = " << interaction.varianceTheta << ", "
0710 << "varianceQoverP = " << interaction.varianceQoverP);
0711
0712
0713 interaction.updateState(singleState, singleStepper, addNoise);
0714
0715 assert(singleState.stepping.cov.array().isFinite().all() &&
0716 "covariance not finite after multi scattering");
0717 }
0718 }
0719 }
0720
0721 void updateMultiTrajectory(result_type& result,
0722 const TemporaryStates& tmpStates,
0723 const Surface& surface) const {
0724 using PrtProjector =
0725 MultiTrajectoryProjector<StatesType::ePredicted, traj_t>;
0726 using FltProjector =
0727 MultiTrajectoryProjector<StatesType::eFiltered, traj_t>;
0728
0729 if (!m_cfg.inReversePass) {
0730 const auto firstCmpProxy =
0731 tmpStates.traj.getTrackState(tmpStates.tips.front());
0732 const auto isMeasurement =
0733 firstCmpProxy.typeFlags().test(MeasurementFlag);
0734
0735 const auto mask =
0736 isMeasurement
0737 ? TrackStatePropMask::Calibrated | TrackStatePropMask::Predicted |
0738 TrackStatePropMask::Filtered | TrackStatePropMask::Smoothed
0739 : TrackStatePropMask::Calibrated | TrackStatePropMask::Predicted;
0740
0741 auto proxy = result.fittedStates->makeTrackState(mask, result.currentTip);
0742 result.currentTip = proxy.index();
0743
0744 proxy.setReferenceSurface(surface.getSharedPtr());
0745 proxy.copyFrom(firstCmpProxy, mask);
0746
0747 auto [prtMean, prtCov] =
0748 mergeGaussianMixture(tmpStates.tips, surface, m_cfg.mergeMethod,
0749 PrtProjector{tmpStates.traj, tmpStates.weights});
0750 proxy.predicted() = prtMean;
0751 proxy.predictedCovariance() = prtCov;
0752
0753 if (isMeasurement) {
0754 auto [fltMean, fltCov] = mergeGaussianMixture(
0755 tmpStates.tips, surface, m_cfg.mergeMethod,
0756 FltProjector{tmpStates.traj, tmpStates.weights});
0757 proxy.filtered() = fltMean;
0758 proxy.filteredCovariance() = fltCov;
0759 proxy.smoothed() = BoundVector::Constant(-2);
0760 proxy.smoothedCovariance() = BoundSquareMatrix::Constant(-2);
0761 } else {
0762 proxy.shareFrom(TrackStatePropMask::Predicted,
0763 TrackStatePropMask::Filtered);
0764 }
0765
0766 } else {
0767 assert((result.currentTip != MultiTrajectoryTraits::kInvalid &&
0768 "tip not valid"));
0769
0770 result.fittedStates->applyBackwards(
0771 result.currentTip, [&](auto trackState) {
0772 auto fSurface = &trackState.referenceSurface();
0773 if (fSurface == &surface) {
0774 result.surfacesVisitedBwdAgain.push_back(&surface);
0775
0776 if (trackState.hasSmoothed()) {
0777 const auto [smtMean, smtCov] = mergeGaussianMixture(
0778 tmpStates.tips, surface, m_cfg.mergeMethod,
0779 FltProjector{tmpStates.traj, tmpStates.weights});
0780
0781 trackState.smoothed() = smtMean;
0782 trackState.smoothedCovariance() = smtCov;
0783 }
0784 return false;
0785 }
0786 return true;
0787 });
0788 }
0789 }
0790
0791
0792
0793 void setOptions(const GsfOptions<traj_t>& options) {
0794 m_cfg.maxComponents = options.maxComponents;
0795 m_cfg.extensions = options.extensions;
0796 m_cfg.abortOnError = options.abortOnError;
0797 m_cfg.disableAllMaterialHandling = options.disableAllMaterialHandling;
0798 m_cfg.weightCutoff = options.weightCutoff;
0799 m_cfg.mergeMethod = options.componentMergeMethod;
0800 m_cfg.calibrationContext = &options.calibrationContext.get();
0801 }
0802 };
0803
0804 }