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