Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /acts/Core/include/Acts/TrackFitting/TrackletJoiner.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/EventData/TrackContainerFrontendConcept.hpp"
0013 #include "Acts/EventData/TrackProxyConcept.hpp"
0014 #include "Acts/EventData/TrackStateProxyConcept.hpp"
0015 #include "Acts/EventData/Types.hpp"
0016 #include "Acts/Geometry/GeometryContext.hpp"
0017 #include "Acts/TrackFitting/KalmanFitterError.hpp"
0018 #include "Acts/TrackFitting/MbfSmoother.hpp"
0019 #include "Acts/TrackFitting/detail/TrackletJoining.hpp"
0020 #include "Acts/Utilities/Logger.hpp"
0021 #include "Acts/Utilities/Result.hpp"
0022 
0023 #include <algorithm>
0024 #include <iterator>
0025 #include <memory>
0026 #include <tuple>
0027 #include <utility>
0028 
0029 namespace Acts {
0030 
0031 /// @addtogroup track_fitting
0032 /// @{
0033 
0034 /// Join a second tracklet, filtered from a state of a smoothed first tracklet
0035 /// as prior, behind that shared state, and combine their smoothed estimates
0036 /// without a new propagation. This is the two-way track finding.
0037 ///
0038 /// A smoother over the stitched chain would count the first tracklet twice.
0039 /// Instead the second tracklet is smoothed alone and one smoothing step
0040 /// carries its information onto the shared state; the change of the shared
0041 /// state is transported to the first tracklet by conditioning
0042 /// (`detail::conditionSmoothedStatesOnSharedState`); then the chains are linked
0043 /// (`detail::linkTrackletBehind`).
0044 ///
0045 /// With smoothing and conditioning enabled, the smoothed states hold both
0046 /// tracklets. Unsmoothed trailing states of the first tracklet stay unchanged.
0047 /// States of the first tracklet before the shared state leave the chain.
0048 /// The predicted and filtered history stays in two filter orders, so a
0049 /// later smoother over the joined chain is invalid. The track-level data is
0050 /// taken from the second tracklet.
0051 /// If the second tracklet has no states, only its track-level data is copied;
0052 /// this covers propagation to the target without another detector surface.
0053 class TrackletJoiner {
0054  public:
0055   /// Configuration
0056   struct Config {
0057     /// Smooth the second tracklet and update the shared state
0058     bool smoothSecond = true;
0059     /// Condition the first tracklet on the updated shared state
0060     bool conditionFirst = true;
0061     /// Invert and shift the jacobians of the second tracklet in the link
0062     bool invertJacobians = true;
0063   };
0064 
0065   /// Default constructor
0066   TrackletJoiner() : TrackletJoiner(Config{}) {}
0067 
0068   /// Constructor
0069   /// @param cfg The configuration
0070   /// @param logger The logger
0071   explicit TrackletJoiner(const Config& cfg,
0072                           std::unique_ptr<const Logger> logger =
0073                               getDefaultLogger("TrackletJoiner", Logging::INFO))
0074       : m_cfg(cfg), m_logger(std::move(logger)) {}
0075 
0076   /// Get the configuration
0077   /// @return The configuration
0078   const Config& config() const { return m_cfg; }
0079 
0080   /// Join in place: the first tracklet becomes the joined track. It must own
0081   /// its states; with several second tracklets use @ref joinCopy.
0082   /// Both tracklets must use the same trajectory and own disjoint states.
0083   /// If the first tracklet is not linked forward, this links it forward.
0084   /// On failure, smoothed states may already have been modified.
0085   ///
0086   /// @tparam smoother_t The smoother for the second tracklet
0087   /// @tparam track_proxy_t The track proxy type
0088   /// @param gctx The geometry context
0089   /// @param first The first tracklet, smoothed
0090   /// @param sharedState The state the second tracklet started from
0091   /// @param second The second tracklet
0092   /// @param smoother The smoother
0093   /// @return Success or the first error
0094   template <typename smoother_t = MbfSmoother, TrackProxyConcept track_proxy_t>
0095   Result<void> joinInPlace(const GeometryContext& gctx, track_proxy_t& first,
0096                            typename track_proxy_t::TrackStateProxy sharedState,
0097                            track_proxy_t& second,
0098                            const smoother_t& smoother = smoother_t{}) const {
0099     auto& trajectory = first.container().trackStateContainer();
0100 
0101     if (first.stemIndex() == kTrackIndexInvalid) {
0102       first.linkForward();
0103     }
0104 
0105     if (second.tipIndex() == kTrackIndexInvalid) {
0106       // An empty second pass can still carry the estimate at the target.
0107       const auto tipIndex = first.tipIndex();
0108       const auto stemIndex = first.stemIndex();
0109       first.copyFromWithoutStates(second);
0110       first.tipIndex() = tipIndex;
0111       first.stemIndex() = stemIndex;
0112       return Result<void>::success();
0113     }
0114     if (!sharedState.hasSmoothed()) {
0115       ACTS_DEBUG("Shared state " << sharedState.index()
0116                                  << " has no smoothed parameters");
0117       return KalmanFitterError::SmoothFailed;
0118     }
0119 
0120     BoundVector sharedMean = sharedState.smoothed();
0121     BoundMatrix sharedCov = sharedState.smoothedCovariance();
0122 
0123     if (m_cfg.smoothSecond) {
0124       auto res = smoother(gctx, trajectory, second.tipIndex(), logger());
0125       if (!res.ok()) {
0126         ACTS_DEBUG("Smoothing of the second tracklet failed: "
0127                    << res.error().message());
0128         return res.error();
0129       }
0130       // the first state of the second tracklet was predicted from the shared
0131       // state
0132       auto secondStart = second.outermostTrackState();
0133       for (auto ts : second.trackStatesReversed()) {
0134         secondStart = ts;
0135       }
0136       auto prior = detail::smoothPriorNode(AnyConstTrackStateProxy{secondStart},
0137                                            sharedMean, sharedCov, logger());
0138       if (!prior.ok()) {
0139         return prior.error();
0140       }
0141       std::tie(sharedMean, sharedCov) = *prior;
0142     }
0143 
0144     if (m_cfg.conditionFirst) {
0145       auto res = detail::conditionSmoothedStatesOnSharedState(
0146           trajectory, sharedState.index(), first.tipIndex(), sharedMean,
0147           sharedCov, logger());
0148       if (!res.ok()) {
0149         ACTS_DEBUG("Conditioning of the first tracklet failed: "
0150                    << res.error().message());
0151         return res.error();
0152       }
0153     } else {
0154       detail::setSmoothedWithoutSharing(AnyMutableTrackStateProxy{sharedState},
0155                                         sharedMean, sharedCov);
0156     }
0157 
0158     const auto tipIndex = first.tipIndex();
0159     detail::linkTrackletBehind(sharedState, second, m_cfg.invertJacobians);
0160     first.copyFromWithoutStates(second);
0161     first.tipIndex() = tipIndex;
0162     first.stemIndex() = second.stemIndex();
0163 
0164     return Result<void>::success();
0165   }
0166 
0167   /// Join copies of both tracklets in @p out and return the joined copy. The
0168   /// inputs stay unchanged.
0169   ///
0170   /// @tparam smoother_t The smoother for the second tracklet
0171   /// @tparam track_container_t The output track container type
0172   /// @tparam track_proxy_t The input track proxy type
0173   /// @tparam track_state_proxy_t The input track state proxy type
0174   /// @param gctx The geometry context
0175   /// @param out The container that receives the copies
0176   /// @param first The first tracklet, smoothed
0177   /// @param sharedState The state the second tracklet started from
0178   /// @param second The second tracklet
0179   /// @param smoother The smoother
0180   /// @return The joined track in @p out, or the first error
0181   template <typename smoother_t = MbfSmoother,
0182             TrackContainerFrontend track_container_t,
0183             TrackProxyConcept track_proxy_t,
0184             TrackStateProxyConcept track_state_proxy_t>
0185   Result<typename track_container_t::TrackProxy> joinCopy(
0186       const GeometryContext& gctx, track_container_t& out,
0187       const track_proxy_t& first, const track_state_proxy_t& sharedState,
0188       const track_proxy_t& second,
0189       const smoother_t& smoother = smoother_t{}) const {
0190     using TrackProxy = typename track_container_t::TrackProxy;
0191     using TrackStateProxy = typename track_container_t::TrackStateProxy;
0192 
0193     // position of the shared state, counted from the tip
0194     auto firstStates = first.trackStatesReversed();
0195     auto sharedIt = std::ranges::find_if(firstStates, [&](const auto& ts) {
0196       return ts.index() == sharedState.index();
0197     });
0198     if (sharedIt == firstStates.end()) {
0199       ACTS_DEBUG("Shared state " << sharedState.index()
0200                                  << " is not on the first tracklet");
0201       return Result<TrackProxy>::failure(KalmanFitterError::SmoothFailed);
0202     }
0203 
0204     TrackProxy firstCopy = out.makeTrack();
0205     firstCopy.copyFrom(first);
0206     TrackProxy secondCopy = out.makeTrack();
0207     secondCopy.copyFrom(second);
0208 
0209     auto copyStates = firstCopy.trackStatesReversed();
0210     TrackStateProxy sharedCopy = *std::ranges::next(
0211         copyStates.begin(),
0212         std::ranges::distance(firstStates.begin(), sharedIt));
0213 
0214     auto res = joinInPlace(gctx, firstCopy, sharedCopy, secondCopy, smoother);
0215     // the second copy is a shell now, its states are in the joined chain
0216     out.removeTrack(secondCopy.index());
0217     if (!res.ok()) {
0218       out.removeTrack(firstCopy.index());
0219       return Result<TrackProxy>::failure(res.error());
0220     }
0221     return firstCopy;
0222   }
0223 
0224  private:
0225   const Logger& logger() const { return *m_logger; }
0226 
0227   Config m_cfg;
0228   std::unique_ptr<const Logger> m_logger;
0229 };
0230 
0231 /// @}
0232 
0233 }  // namespace Acts