Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /acts/Core/include/Acts/TrackFitting/detail/TrackletJoining.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/TrackParametrization.hpp"
0013 #include "Acts/EventData/AnyTrackStateProxy.hpp"
0014 #include "Acts/EventData/TrackProxyCommon.hpp"
0015 #include "Acts/EventData/TrackProxyConcept.hpp"
0016 #include "Acts/EventData/TrackStatePropMask.hpp"
0017 #include "Acts/EventData/TrackStateProxyConcept.hpp"
0018 #include "Acts/EventData/Types.hpp"
0019 #include "Acts/TrackFitting/GainMatrixSmoother.hpp"
0020 #include "Acts/TrackFitting/KalmanFitterError.hpp"
0021 #include "Acts/Utilities/Logger.hpp"
0022 #include "Acts/Utilities/Result.hpp"
0023 
0024 #include <cstddef>
0025 #include <optional>
0026 #include <ranges>
0027 #include <utility>
0028 #include <vector>
0029 
0030 namespace Acts::detail {
0031 
0032 /// Write a smoothed estimate without changing aliased filter history.
0033 /// @param ts The state to update
0034 /// @param mean The smoothed parameters
0035 /// @param cov The smoothed covariance
0036 void setSmoothedWithoutSharing(AnyMutableTrackStateProxy ts, BoundVector mean,
0037                                BoundMatrix cov);
0038 
0039 /// One smoothing step from the first state of a smoothed segment onto the
0040 /// prior node it was predicted from, in the Rauch-Tung-Striebel gain form of
0041 /// the @ref Acts::GainMatrixSmoother: `G = P F^T Pp^-1`,
0042 /// `x' = x + G (xs - xp)`, `P' = P + G (Ps - Pp) G^T`. The gain form needs
0043 /// one factorization of `Pp` per segment. The modified Bryson-Frazier form
0044 /// would need the adjoint of the first state, which the smoother does not
0045 /// store and which costs the same factorization to recover.
0046 /// @param first The first state of the segment, smoothed
0047 /// @param priorMean The estimate at the prior node
0048 /// @param priorCov Its covariance
0049 /// @param logger The logger
0050 /// @return The estimate at the prior node with the segment included, or
0051 ///         `KalmanFitterError::SmoothFailed` if the predicted covariance
0052 ///         is not positive definite or the result is not finite
0053 Result<std::pair<BoundVector, BoundMatrix>> smoothPriorNode(
0054     const AnyConstTrackStateProxy& first, const BoundVector& priorMean,
0055     const BoundMatrix& priorCov, const Logger& logger);
0056 
0057 /// Per-track terms of the conditioning on a shared state: the change of the
0058 /// shared state mapped by `Z = Pp_s Ps_s^-1`
0059 struct SharedStateCondition {
0060   /// `Z (x_s' - x_s)`
0061   BoundVector u = BoundVector::Zero();
0062   /// `Z (P_s' - P_s) Z^T`
0063   BoundMatrix w = BoundMatrix::Zero();
0064 };
0065 
0066 /// Build the conditioning terms from the shared state and its new estimate
0067 /// @param shared The shared state, smoothed
0068 /// @param newMean The new estimate of the shared state
0069 /// @param newCov Its covariance
0070 /// @param logger The logger
0071 /// @return The terms, or `KalmanFitterError::SmoothFailed` if the shared
0072 ///         covariance is not positive definite or the terms are not finite
0073 Result<SharedStateCondition> makeSharedStateCondition(
0074     const AnyConstTrackStateProxy& shared, const BoundVector& newMean,
0075     const BoundMatrix& newCov, const Logger& logger);
0076 
0077 /// Sensitivity of the filtered state to the prior mean, `Df = (I - K H) Dp`.
0078 /// This and @ref conditionTrackState are the recursions of the modified
0079 /// Bryson-Frazier smoother (@ref Acts::MbfSmoother) applied to the
0080 /// sensitivity to the prior mean instead of to the innovations.
0081 /// @param ts The state
0082 /// @param dp The sensitivity of its predicted state
0083 /// @return The sensitivity of its filtered state
0084 BoundMatrix filteredSensitivity(const AnyConstTrackStateProxy& ts,
0085                                 const BoundMatrix& dp);
0086 
0087 /// Condition one smoothed state and transport the adjoint sensitivity to the
0088 /// previous state, as the modified Bryson-Frazier smoother transports its
0089 /// adjoint: `T = Df - Pf Psi^`, `x += T u`, `P += T w T^T`,
0090 /// `Psi^ <- F^T (H^T S^-1 H Dp + (I - K H)^T Psi^)`
0091 /// @param ts The state
0092 /// @param dp The sensitivity of its predicted state
0093 /// @param df The sensitivity of its filtered state
0094 /// @param psiHat The adjoint sensitivity, in and out
0095 /// @param condition The per-track terms
0096 /// @param logger The logger
0097 /// @return Success, or `KalmanFitterError::SmoothFailed` if the result is
0098 ///         not finite
0099 Result<void> conditionTrackState(AnyMutableTrackStateProxy ts,
0100                                  const BoundMatrix& dp, const BoundMatrix& df,
0101                                  BoundMatrix& psiHat,
0102                                  const SharedStateCondition& condition,
0103                                  const Logger& logger);
0104 
0105 /// Condition the smoothed states of a segment on a new estimate of one of
0106 /// its states.
0107 ///
0108 /// The segment runs from @p sharedIndex to @p tipIndex in filter order and is
0109 /// smoothed. Each state is updated by its regression on the shared state,
0110 /// `x_k += L_k (x_s' - x_s)`, `P_k += L_k (P_s' - P_s) L_k^T`, which is the
0111 /// exact linear-Gaussian update for information that enters through the
0112 /// shared state. `L_k = T_k Pp_s Ps_s^-1`, where `T_k` is the sensitivity of
0113 /// the smoothed state to the prior mean of the segment, computed in the
0114 /// modified Bryson-Frazier form with a forward sweep over
0115 /// @ref filteredSensitivity and a backward sweep over
0116 /// @ref conditionTrackState.
0117 ///
0118 /// States before the shared state get a plain smoothing step from the new
0119 /// estimate. States after the last smoothed state stay as they are.
0120 ///
0121 /// @tparam traj_t The MultiTrajectory type
0122 /// @param trajectory The trajectory that holds the segment
0123 /// @param sharedIndex The index of the shared state
0124 /// @param tipIndex The index of the last state of the segment in filter order
0125 /// @param newMean The new estimate of the shared state
0126 /// @param newCov Its covariance
0127 /// @param logger The logger
0128 /// @return Success, or `KalmanFitterError::SmoothFailed` if the shared
0129 ///         state is not on the chain, a state lacks components, or a result
0130 ///         is not finite
0131 template <typename traj_t>
0132 Result<void> conditionSmoothedStatesOnSharedState(traj_t& trajectory,
0133                                                   std::size_t sharedIndex,
0134                                                   std::size_t tipIndex,
0135                                                   const BoundVector& newMean,
0136                                                   const BoundMatrix& newCov,
0137                                                   const Logger& logger) {
0138   using TrackStateProxy = typename traj_t::TrackStateProxy;
0139 
0140   // collect the segment from the tip down to the shared state
0141   std::vector<std::size_t> indices;
0142   bool found = false;
0143   trajectory.applyBackwards(tipIndex, [&](TrackStateProxy ts) {
0144     indices.push_back(ts.index());
0145     found = (ts.index() == sharedIndex);
0146     return !found;
0147   });
0148   if (!found) {
0149     ACTS_DEBUG("Shared state " << sharedIndex << " is not on the chain of "
0150                                << tipIndex);
0151     return KalmanFitterError::SmoothFailed;
0152   }
0153 
0154   // states after the last smoothed state, e.g. holes after the last
0155   // measurement, stay as they are
0156   std::size_t skip = 0;
0157   while (skip + 1 < indices.size() &&
0158          !trajectory.getTrackState(indices[skip]).hasSmoothed()) {
0159     ++skip;
0160   }
0161   indices.erase(indices.begin(), indices.begin() + skip);
0162 
0163   auto shared = trajectory.getTrackState(sharedIndex);
0164   if (!shared.hasSmoothed()) {
0165     ACTS_DEBUG("Shared state " << sharedIndex << " has no smoothed parameters");
0166     return KalmanFitterError::SmoothFailed;
0167   }
0168   auto condition = makeSharedStateCondition(AnyConstTrackStateProxy{shared},
0169                                             newMean, newCov, logger);
0170   if (!condition.ok()) {
0171     return condition.error();
0172   }
0173 
0174   // forward sweep: sensitivities (Dp, Df) of the predicted and filtered
0175   // states to the prior mean of the segment
0176   std::vector<std::pair<BoundMatrix, BoundMatrix>> sensitivities(
0177       indices.size());
0178   BoundMatrix df = BoundMatrix::Identity();
0179   for (std::size_t k :
0180        std::views::iota(std::size_t{0}, indices.size()) | std::views::reverse) {
0181     auto ts = trajectory.getTrackState(indices[k]);
0182     if (!ts.hasSmoothed() || !ts.hasPredicted() || !ts.hasJacobian()) {
0183       ACTS_DEBUG("State " << ts.index()
0184                           << " lacks smoothed, predicted or jacobian");
0185       return KalmanFitterError::SmoothFailed;
0186     }
0187     const bool isShared = (k + 1 == indices.size());
0188     const BoundMatrix dp =
0189         isShared ? BoundMatrix::Identity() : BoundMatrix(ts.jacobian() * df);
0190     df = filteredSensitivity(AnyConstTrackStateProxy{ts}, dp);
0191     sensitivities[k] = {dp, df};
0192   }
0193 
0194   // backward sweep: condition the states from the tip down to the shared one
0195   BoundMatrix psiHat = BoundMatrix::Zero();
0196   for (std::size_t k = 0; k + 1 < indices.size(); ++k) {
0197     auto ts = trajectory.getTrackState(indices[k]);
0198     const auto& [dp, dfk] = sensitivities[k];
0199     auto res = conditionTrackState(AnyMutableTrackStateProxy{ts}, dp, dfk,
0200                                    psiHat, *condition, logger);
0201     if (!res.ok()) {
0202       return res.error();
0203     }
0204   }
0205 
0206   setSmoothedWithoutSharing(AnyMutableTrackStateProxy{shared}, newMean, newCov);
0207 
0208   if (shared.hasPrevious()) {
0209     GainMatrixSmoother smoother;
0210     Result<void> result = Result<void>::success();
0211     auto later = shared;
0212     trajectory.applyBackwards(shared.previous(), [&](TrackStateProxy ts) {
0213       ts.addComponents(TrackStatePropMask::Smoothed);
0214       auto res = smoother.calculate(AnyMutableTrackStateProxy{ts},
0215                                     AnyConstTrackStateProxy{later}, logger);
0216       if (!res.ok()) {
0217         result = res;
0218         return false;
0219       }
0220       later = ts;
0221       return true;
0222     });
0223     return result;
0224   }
0225 
0226   return Result<void>::success();
0227 }
0228 
0229 /// Link a second tracklet, filtered from a state of a first tracklet, behind
0230 /// that state.
0231 ///
0232 /// The states of the second tracklet are reversed and linked behind the shared
0233 /// state. With @p invertJacobians the jacobians are inverted and shifted, and
0234 /// the transport onto the shared state is stored on the shared state.
0235 ///
0236 /// @tparam track_state_proxy_t The track state proxy type
0237 /// @tparam track_proxy_t The track proxy type
0238 /// @param sharedState The shared state of the first tracklet
0239 /// @param second The second tracklet
0240 /// @param invertJacobians Whether to invert and shift the jacobians
0241 /// @return The transport onto the shared state, if any
0242 template <TrackStateProxyConcept track_state_proxy_t,
0243           TrackProxyConcept track_proxy_t>
0244 std::optional<BoundMatrix> linkTrackletBehind(track_state_proxy_t sharedState,
0245                                               track_proxy_t& second,
0246                                               bool invertJacobians) {
0247   std::optional<BoundMatrix> stitch =
0248       second.reverseTrackStates(invertJacobians);
0249   if (second.tipIndex() == kTrackIndexInvalid) {
0250     return stitch;
0251   }
0252 
0253   auto secondTip = second.outermostTrackState();
0254   sharedState.previous() = secondTip.index();
0255   secondTip.template component<TrackIndexType>(detail_tp::kNextKey) =
0256       sharedState.index();
0257 
0258   if (stitch.has_value()) {
0259     sharedState.jacobian() = *stitch;
0260   }
0261 
0262   return stitch;
0263 }
0264 
0265 }  // namespace Acts::detail