diff --git a/Core/include/Acts/EventData/MultiTrajectory.hpp b/Core/include/Acts/EventData/MultiTrajectory.hpp index babe672e2be..17107013b36 100644 --- a/Core/include/Acts/EventData/MultiTrajectory.hpp +++ b/Core/include/Acts/EventData/MultiTrajectory.hpp @@ -148,29 +148,34 @@ struct IsReadOnlyMultiTrajectory; /// iterating over specific sub-components. template class MultiTrajectory { - public: using Derived = derived_t; static constexpr bool ReadOnly = IsReadOnlyMultiTrajectory::value; // Pull out type alias and re-expose them for ease of use. - // static constexpr unsigned int MeasurementSizeMax = MultiTrajectoryTraits::MeasurementSizeMax; - private: friend class TrackStateProxy; friend class TrackStateProxy; template friend class MultiTrajectory; public: + /// Alias for the const version of a track state proxy, with the same + /// backends as this container using ConstTrackStateProxy = Acts::TrackStateProxy; + + /// Alias for the mutable version of a track state proxy, with the same + /// backends as this container using TrackStateProxy = Acts::TrackStateProxy; + /// The index type of the track state container using IndexType = typename TrackStateProxy::IndexType; + + /// Sentinel value that indicates an invalid index static constexpr IndexType kInvalid = TrackStateProxy::kInvalid; protected: @@ -202,7 +207,16 @@ class MultiTrajectory { } public: + /// @anchor track_state_container_track_access + /// @name MultiTrajectory track state (proxy) access and manipulation + /// + /// These methods allow accessing track states, i.e. adding or retrieving a + /// track state proxy that points at a specific track state in the container. + /// + /// @{ + /// Access a read-only point on the trajectory by index. + /// @note Only available if the MultiTrajectory is not read-only /// @param istate The index to access /// @return Read only proxy to the stored track state ConstTrackStateProxy getTrackState(IndexType istate) const { @@ -210,6 +224,7 @@ class MultiTrajectory { } /// Access a writable point on the trajectory by index. + /// @note Only available if the MultiTrajectory is not read-only /// @param istate The index to access /// @return Read-write proxy to the stored track state template > @@ -217,6 +232,20 @@ class MultiTrajectory { return {*this, istate}; } + /// Add a track state without providing explicit information. Which components + /// of the track state are initialized/allocated can be controlled via @p mask + /// @note Only available if the MultiTrajectory is not read-only + /// @param mask The bitmask that instructs which components to allocate and + /// which to leave invalid + /// @param iprevious index of the previous state, kInvalid if first + /// @return Index of the newly added track state + template > + constexpr IndexType addTrackState( + TrackStatePropMask mask = TrackStatePropMask::All, + IndexType iprevious = kInvalid) { + return self().addTrackState_impl(mask, iprevious); + } + /// Add a track state to the container and return a track state proxy to it /// This effectively calls @c addTrackState and @c getTrackState /// @note Only available if the track state container is not read-only @@ -228,6 +257,12 @@ class MultiTrajectory { return getTrackState(addTrackState(mask, iprevious)); } + /// @} + + /// @anchor track_state_container_iteration + /// @name MultiTrajectory track state iteration + /// @{ + /// Visit all previous states starting at a given endpoint. /// /// @param iendpoint index of the last state @@ -235,6 +270,45 @@ class MultiTrajectory { template void visitBackwards(IndexType iendpoint, F&& callable) const; + /// Apply a function to all previous states starting at a given endpoint. + /// + /// @param iendpoint index of the last state + /// @param callable modifying functor to be called with each point + /// + /// @warning If the trajectory contains multiple components with common + /// points, this can have an impact on the other components. + /// @note Only available if the MultiTrajectory is not read-only + template > + void applyBackwards(IndexType iendpoint, F&& callable) { + static_assert(detail_lt::VisitorConcept, + "Callable needs to satisfy VisitorConcept"); + + if (iendpoint == MultiTrajectoryTraits::kInvalid) { + throw std::runtime_error( + "Cannot apply backwards with kInvalid as endpoint"); + } + + while (true) { + auto ts = getTrackState(iendpoint); + if constexpr (std::is_same_v, + bool>) { + bool proceed = callable(ts); + // this point has no parent and ends the trajectory, or a break was + // requested + if (!proceed || !ts.hasPrevious()) { + break; + } + } else { + callable(ts); + // this point has no parent and ends the trajectory + if (!ts.hasPrevious()) { + break; + } + } + iendpoint = ts.previous(); + } + } + /// Range for the track states from @p iendpoint to the trajectory start /// @param iendpoint Trajectory entry point to start from /// @return Iterator pair to iterate over @@ -251,6 +325,7 @@ class MultiTrajectory { /// Range for the track states from @p iendpoint to the trajectory start, /// i.e from the outside in. + /// @note Only available if the MultiTrajectory is not read-only /// @param iendpoint Trajectory entry point to start from /// @return Iterator pair to iterate over /// @note Mutable version @@ -283,6 +358,7 @@ class MultiTrajectory { /// Range for the track states from @p istartpoint to the trajectory end, /// i.e from inside out + /// @note Only available if the MultiTrajectory is not read-only /// @param istartpoint Trajectory state index for the innermost track /// state to start from /// @return Iterator pair to iterate over @@ -297,79 +373,20 @@ class MultiTrajectory { return range_t{getTrackState(istartpoint)}; } - /// Apply a function to all previous states starting at a given endpoint. - /// - /// @param iendpoint index of the last state - /// @param callable modifying functor to be called with each point - /// - /// @warning If the trajectory contains multiple components with common - /// points, this can have an impact on the other components. - template > - void applyBackwards(IndexType iendpoint, F&& callable) { - static_assert(detail_lt::VisitorConcept, - "Callable needs to satisfy VisitorConcept"); - - if (iendpoint == MultiTrajectoryTraits::kInvalid) { - throw std::runtime_error( - "Cannot apply backwards with kInvalid as endpoint"); - } - - while (true) { - auto ts = getTrackState(iendpoint); - if constexpr (std::is_same_v, - bool>) { - bool proceed = callable(ts); - // this point has no parent and ends the trajectory, or a break was - // requested - if (!proceed || !ts.hasPrevious()) { - break; - } - } else { - callable(ts); - // this point has no parent and ends the trajectory - if (!ts.hasPrevious()) { - break; - } - } - iendpoint = ts.previous(); - } - } - - auto&& convertToReadOnly() const { - auto&& cv = self().convertToReadOnly_impl(); - static_assert( - IsReadOnlyMultiTrajectory::value, - "convertToReadOnly_impl does not return something that reports " - "being ReadOnly."); - return cv; - } - - /// Clear the @c MultiTrajectory. Leaves the underlying storage untouched - template > - constexpr void clear() { - self().clear_impl(); - } - - /// Returns the number of track states contained - constexpr IndexType size() const { return self().size_impl(); } + /// @} - /// Add a track state without providing explicit information. Which components - /// of the track state are initialized/allocated can be controlled via @p mask - /// @param mask The bitmask that instructs which components to allocate and - /// which to leave invalid - /// @param iprevious index of the previous state, kInvalid if first - /// @return Index of the newly added track state - template > - constexpr IndexType addTrackState( - TrackStatePropMask mask = TrackStatePropMask::All, - IndexType iprevious = kInvalid) { - return self().addTrackState_impl(mask, iprevious); - } + /// @anchor track_state_container_columns + /// @name MultiTrajectory column management + /// MultiTrajectory can manage a set of common static columns, and dynamic + /// columns that can be added at runtime. This set of methods allows you to + /// manage the dynamic columns. + /// @{ /// Add a column to the @c MultiTrajectory /// @tparam T Type of the column values to add /// @note This takes a string argument rather than a hashed string to maintain /// compatibility with backends. + /// @note Only available if the MultiTrajectory is not read-only template > constexpr void addColumn(const std::string& key) { self().template addColumn_impl(key); @@ -382,6 +399,19 @@ class MultiTrajectory { return self().hasColumn_impl(key); } + /// @} + + /// Clear the @c MultiTrajectory. Leaves the underlying storage untouched + /// @note Only available if the MultiTrajectory is not read-only + template > + constexpr void clear() { + self().clear_impl(); + } + + /// Returns the number of track states contained + /// @return The number of track states + constexpr IndexType size() const { return self().size_impl(); } + protected: // These are internal helper functions which the @c TrackStateProxy class talks to diff --git a/Core/include/Acts/EventData/TrackContainer.hpp b/Core/include/Acts/EventData/TrackContainer.hpp index 82d5e3a3ff5..17dae45f637 100644 --- a/Core/include/Acts/EventData/TrackContainer.hpp +++ b/Core/include/Acts/EventData/TrackContainer.hpp @@ -40,8 +40,12 @@ template class holder_t = detail::RefHolder> class TrackContainer { public: + /// Indicates if this track container is read-only, or if it can be modified static constexpr bool ReadOnly = IsReadOnlyTrackContainer::value; + + /// Indicates if the track state container is read-only, or if it can be + /// modified static constexpr bool TrackStateReadOnly = IsReadOnlyMultiTrajectory::value; @@ -49,11 +53,19 @@ class TrackContainer { "Either both track container and track state container need to " "be readonly or both have to be readwrite"); + /// The index type of the track container, taken from the container backend using IndexType = TrackIndexType; + + /// Sentinel value that indicates an invalid index static constexpr IndexType kInvalid = kTrackIndexInvalid; + /// Alias for the mutable version of a track proxy, with the same backends as + /// this container using TrackProxy = Acts::TrackProxy; + + /// Alias for the const version of a track proxy, with the same backends as + /// this container using ConstTrackProxy = Acts::TrackProxy; @@ -62,6 +74,17 @@ class TrackContainer { friend ConstTrackProxy; #endif + /// @anchor track_container_construction + /// @name TrackContainer construction + /// + /// Constructors for the track container by using a set of backends + /// (track + track state). The container can either take ownership of the + /// backends or just hold references to them. This is driven by the @c + /// holder_t template parameter, where you can also supply a custom holder + /// type. Template deduction is used to try to guess the correct holder type. + /// + /// @{ + /// Constructor from a track container backend and a track state container /// backend /// @param container the track container backend @@ -96,6 +119,16 @@ class TrackContainer { TrackContainer(const track_container_t& container, const traj_t& traj) : m_container{&container}, m_traj{&traj} {} + /// @} + + /// @anchor track_container_track_access + /// @name TrackContainer track (proxy) access and manipulation + /// + /// These methods allow accessing tracks, i.e. adding or retrieving a track + /// proxy that points at a specific track in the container. + /// + /// @{ + /// Get a const track proxy for a track index /// @param itrack the track index in the container /// @return A const track proxy for the index @@ -104,6 +137,7 @@ class TrackContainer { } /// Get a mutable track proxy for a track index + /// @note Only available if the track container is not read-only /// @param itrack the track index in the container /// @return A mutable track proxy for the index template > @@ -111,14 +145,9 @@ class TrackContainer { return {*this, itrack}; } - /// Get the size of the track container - /// @return the sixe - constexpr IndexType size() const { - return m_container->size_impl(); - } - /// Add a track to the container. Note this only creates the logical track and /// allocates memory. You can combine this with @c getTrack to obtain a track proxy + /// @note Only available if the track container is not read-only /// @return the index to the newly added track template > IndexType addTrack() { @@ -137,14 +166,58 @@ class TrackContainer { } /// Remove a track at index @p itrack from the container - /// @note This invalidates all track proxies! + /// @note Only available if the track container is not read-only + /// @note This invalidates track proxies that point to tracks with larger + /// indices than @p itrack! /// @param itrack The index of the track to remove template > void removeTrack(IndexType itrack) { m_container->removeTrack_impl(itrack); } + /// Get a mutable iterator to the first track in the container + /// @note Only available if the track container is not read-only + /// @return a mutable iterator to the first track + template > + auto begin() { + return detail_tc::TrackProxyIterator, + TrackProxy, false>{*this, 0}; + } + + /// Get a past-the-end iterator for this container + /// @note Only available if the track container is not read-only + /// @return a past-the-end iterator + template > + auto end() { + return detail_tc::TrackProxyIterator, + TrackProxy, false>{*this, size()}; + } + + /// Get an const iterator to the first track in the container + /// @return a const iterator to the first track + auto begin() const { + return detail_tc::TrackProxyIterator, + ConstTrackProxy, true>{*this, 0}; + } + + /// Get a past-the-end iterator for this container + /// @return a past-the-end iterator + auto end() const { + return detail_tc::TrackProxyIterator, + ConstTrackProxy, true>{*this, size()}; + } + + /// @} + + /// @anchor track_container_columns + /// @name TrackContainer column management + /// TrackContainer can manage a set of common static columns, and dynamic + /// columns that can be added at runtime. This set of methods allows you to + /// manage the dynamic columns. + /// @{ + /// Add a dymanic column to the track container + /// @note Only available if the track container is not read-only /// @param key the name of the column to be added template > constexpr void addColumn(const std::string& key) { @@ -163,7 +236,29 @@ class TrackContainer { return m_container->hasColumn_impl(key); } + /// Helper function to make this track container match the dynamic columns of + /// another one. This will only work if the track container supports this + /// source, and depends on the implementation details of the dynamic columns + /// of the container + /// @note Only available if the track container is not read-only + /// @tparam other_track_container_t Type of the other track container + /// @param other The other track container + template > + void ensureDynamicColumns(const other_track_container_t& other) { + container().ensureDynamicColumns_impl(other.container()); + } + + /// @} + + /// @anchor track_congtainer_backend_access + /// @name TrackContainer backend access + /// These methods allow accessing the backend of the track container. In most + /// cases, this is not necessary for interacting with the container. + /// @{ + /// Get a mutable reference to the track container backend + /// @note Only available if the track container is not read-only /// @return a mutable reference to the backend template > auto& container() { @@ -177,6 +272,7 @@ class TrackContainer { } /// Get a mutable reference to the track state container backend + /// @note Only available if the track container is not read-only /// @return a mutable reference to the backend template > auto& trackStateContainer() { @@ -185,6 +281,7 @@ class TrackContainer { /// Retrieve the holder of the track state container /// @return The track state container including it's holder + /// @note Only available if the track container is not read-only template > auto& trackStateContainerHolder() { return m_traj; @@ -202,49 +299,16 @@ class TrackContainer { return m_traj; } - /// Get a mutable iterator to the first track in the container - /// @return a mutable iterator to the first track - template > - auto begin() { - return detail_tc::TrackProxyIterator, - TrackProxy, false>{*this, 0}; - } - - /// Get a past-the-end iterator for this container - /// @return a past-the-end iterator - template > - auto end() { - return detail_tc::TrackProxyIterator, - TrackProxy, false>{*this, size()}; - } + /// @} - /// Get an const iterator to the first track in the container - /// @return a const iterator to the first track - auto begin() const { - return detail_tc::TrackProxyIterator, - ConstTrackProxy, true>{*this, 0}; - } - - /// Get a past-the-end iterator for this container - /// @return a past-the-end iterator - auto end() const { - return detail_tc::TrackProxyIterator, - ConstTrackProxy, true>{*this, size()}; - } - - /// Helper function to make this track container match the dynamic columns of - /// another one. This will only work if the track container supports this - /// source, and depends on the implementation details of the dynamic columns - /// of the container - /// @tparam other_track_container_t Type of the other track container - /// @param other The other track container - template > - void ensureDynamicColumns(const other_track_container_t& other) { - container().ensureDynamicColumns_impl(other.container()); + /// Get the size (number of tracks) of the track container + /// @return the sixe + constexpr IndexType size() const { + return m_container->size_impl(); } /// Clear the content of the track container + /// @note Only available if the track container is not read-only template > void clear() { m_container->clear(); diff --git a/Core/include/Acts/EventData/TrackProxy.hpp b/Core/include/Acts/EventData/TrackProxy.hpp index 5a36a38afee..d52211dd2a3 100644 --- a/Core/include/Acts/EventData/TrackProxy.hpp +++ b/Core/include/Acts/EventData/TrackProxy.hpp @@ -143,7 +143,12 @@ class TrackProxyIterator { } // namespace detail_tc -/// Proxy class representing a single track +/// Proxy class representing a single track. +/// This class provides a **view** into an associated @ref TrackContainer, and +/// has **reference semantics**. You can think of it as a pointer to a vector +/// of tracks, which exposes an object-oriented interface for accessing the +/// track properties. +/// /// @tparam track_container_t the container backend /// @tparam trajectory_t the track state container backend /// @tparam holder_t ownership management class for the backend @@ -152,37 +157,71 @@ template class holder_t, bool read_only = true> class TrackProxy { public: + /// Indicates whether this track proxy is read-only or if it can be modified static constexpr bool ReadOnly = read_only; + + /// The track container backend given as a template parameter using Container = track_container_t; + + /// The track state container backend given as a template parameter using Trajectory = trajectory_t; + /// The index type of the track container + using IndexType = typename Container::IndexType; + + /// Sentinel value that indicates an invalid index + static constexpr IndexType kInvalid = Container::kInvalid; + + /// Alias for the mutable version of this track proxy, with the same backends using MutableTrackProxy = TrackProxy; + + /// Alias for the const version of this track proxy, with the same backends using ConstTrackProxy = TrackProxy; + /// Alias for an associated mutable track state proxy, with the same backends using TrackStateProxy = typename Trajectory::TrackStateProxy; + + /// Alias for an associated const track state proxy, with the same backends using ConstTrackStateProxy = typename Trajectory::ConstTrackStateProxy; + /// Map-type for a bound parameter vector. This has reference semantics, i.e. + /// points at a matrix by an internal pointer. using Parameters = typename detail_lt::Types::CoefficientsMap; + + /// Same as @ref Parameters, but with const semantics using ConstParameters = typename detail_lt::Types::CoefficientsMap; + /// Map-type for a bound covariance. This has reference semantics, i.e. + /// points at a matrix by an internal pointer. using Covariance = typename detail_lt::Types::CovarianceMap; + + /// Same as @ref Covariance, but with const semantics using ConstCovariance = typename detail_lt::Types::CovarianceMap; - using IndexType = typename Container::IndexType; - static constexpr IndexType kInvalid = Container::kInvalid; - #ifndef DOXYGEN friend TrackContainer; friend MutableTrackProxy; friend ConstTrackProxy; + // Track proxies are friends, not food! + template class H, bool R> + friend class TrackProxy; #endif + /// @anchor track_proxy_construct + /// @name Constructors and assignment operator + /// + /// Public constructors and assignment operators for @c TrackProxy only + /// allow construction from another @c TrackProxy. You should generally + /// not have to construct @c TrackProxy manually. + /// + /// @{ + /// Copy constructor from a mutable track proxy. This is always valid, either /// mutable to mutable or mutable to const /// @param other the other track state proxy @@ -198,62 +237,26 @@ class TrackProxy { return *this; } - /// Retrieve a mutable reference to a component - /// @tparam T The type of the component to access - /// @tparam key String key for the component to access - /// @return Mutable reference to the component given by @p key - template > - constexpr T& component() { - return m_container->template component(m_index); - } - - /// Retrieve a mutable reference to a component - /// @tparam T The type of the component to access - /// @param key String key for the component to access - /// @return Mutable reference to the component given by @p key - template > - constexpr T& component(HashedString key) { - return m_container->template component(key, m_index); - } - - /// Retrieve a mutable reference to a component - /// @tparam T The type of the component to access - /// @param key String key for the component to access - /// @note This might hash the @p key at runtime instead of compile-time - /// @return Mutable reference to the component given by @p key - template > - constexpr T& component(std::string_view key) { - return m_container->template component(hashString(key), m_index); - } - - /// Retrieve a const reference to a component - /// @tparam T The type of the component to access - /// @tparam key String key for the component to access - /// @return Const reference to the component given by @p key - template - constexpr const T& component() const { - return m_container->template component(m_index); - } + /// @} - /// Retrieve a const reference to a component - /// @tparam T The type of the component to access - /// @param key String key for the component to access - /// @return Const reference to the component given by @p key - template - constexpr const T& component(HashedString key) const { - return m_container->template component(key, m_index); + /// Equality operator with another track proxy + /// Checks the container identity and the track index + /// @return True if the track proxies refer to the same track + bool operator==(const TrackProxy& other) const { + return &(*m_container) == &(*other.m_container) && m_index == other.m_index; } - /// Retrieve a const reference to a component - /// @tparam T The type of the component to access - /// @param key String key for the component to access - /// @note This might hash the @p key at runtime instead of compile-time - /// @return Const reference to the component given by @p key - template - constexpr const T& component(std::string_view key) const { - return m_container->template component(hashString(key), m_index); - } + /// @anchor track_proxy_props + /// @name TrackProxy properties + /// Methods that give access to the properties of a track represented by + /// @c TrackProxy. + /// + /// Many of these methods come in a @c const and a non-@c const version. The + /// non-@c const version is only available if you have an instance of + /// @c TrackProxy that does not have the @c read_only template parameter set to + /// @c true, even if you hold it as an lvalue. + /// + /// @{ /// Get the tip index, i.e. the entry point into the track state container /// @return the tip index by value @@ -271,6 +274,7 @@ class TrackProxy { /// Get a mutable reference to the tip index, i.e. the entry point into the /// track container + /// @note Only available if the track proxy is not read-only /// @return mutable reference to the tip index template > IndexType& tipIndex() { @@ -280,45 +284,13 @@ class TrackProxy { /// Index of the stem, i.e. the innermost track state of the track. /// This might be invalid, signifying that the track state is not /// forward-linked. + /// @note Only available if the track proxy is not read-only /// @return mutable reference to the stem index template > IndexType& stemIndex() { return component(hashString("stemIndex")); } - /// Return a const track state proxy to the innermost track state - /// @note This is only available, if the track is forward linked - /// @return The innermost track state proxy - auto innermostTrackState() const { - using proxy_t = decltype(m_container->trackStateContainer().getTrackState( - std::declval())); - - IndexType stem = component(hashString("stemIndex")); - if (stem == kInvalid) { - return std::optional{}; - } else { - return std::optional{ - m_container->trackStateContainer().getTrackState(stem)}; - } - } - - /// Return a mutable track state proxy to the innermost track state - /// @note This is only available, if the track is forward linked - /// @return The innermost track state proxy - template > - auto innermostTrackState() { - using proxy_t = decltype(m_container->trackStateContainer().getTrackState( - std::declval())); - - IndexType stem = component(hashString("stemIndex")); - if (stem == kInvalid) { - return std::optional{}; - } else { - return std::optional{ - m_container->trackStateContainer().getTrackState(stem)}; - } - } - /// Get the reference surface of the track (e.g. the perigee) /// @return the reference surface const Surface& referenceSurface() const { @@ -335,7 +307,7 @@ class TrackProxy { } // NOLINTEND(performance-unnecessary-value-param) - /// Return whether a reference surface is associated to this track + /// Returns whether the track has a reference surface or not /// @return whether a surface exists or not bool hasReferenceSurface() const { // @TODO: This could be more efficient @@ -358,6 +330,7 @@ class TrackProxy { /// Get the parameters of the track at the reference surface (e.g. perigee). /// Mutable version + /// @note Only available if the track proxy is not read-only /// @return Proxy vector for the parameters template > Parameters parameters() { @@ -366,6 +339,7 @@ class TrackProxy { /// Get the covariance of the track at the reference surface (e.g. perigee). /// Mutable version + /// @note Only available if the track proxy is not read-only /// @return Proxy matrix for the covariance template > Covariance covariance() { @@ -415,6 +389,7 @@ class TrackProxy { } /// Set a new particle hypothesis for this track + /// @note Only available if the track proxy is not read-only /// @param particleHypothesis The particle hypothesis to set template > void setParticleHypothesis(const ParticleHypothesis& particleHypothesis) { @@ -453,65 +428,6 @@ class TrackProxy { return absoluteMomentum() * direction(); } - /// Get a range over the track states of this track. Return value is - /// compatible with range based for loop. Const version - /// @note This range is from the outside inwards! - /// @return Track state range to iterate over - auto trackStatesReversed() const { - return m_container->reverseTrackStateRange(m_index); - } - - /// Get a range over the track states of this track. Return value is - /// compatible with range based for loop. Mutable version - /// @note This range is from the outside inwards! - /// @return Track state range to iterate over - template > - auto trackStatesReversed() { - return m_container->reverseTrackStateRange(m_index); - } - - /// Get a range over the track states of this track. Return value is - /// compatible with range based for loop. Const version - /// @note This range is from the inside out! - /// @return Track state range to iterate over - auto trackStates() const { - return m_container->forwardTrackStateRange(m_index); - } - - /// Get a range over the track states of this track. Return value is - /// compatible with range based for loop. Mutable version - /// @note This range is from the inside out! - /// @return Track state range to iterate over - template > - auto trackStates() { - return m_container->forwardTrackStateRange(m_index); - } - - /// Forward connect a track, i.e. set indices from the inside out - /// on all track states. - template > - void linkForward() { - IndexType last = kInvalid; - for (auto ts : trackStatesReversed()) { - ts.template component(hashString("next")) = last; - last = ts.index(); - } - stemIndex() = last; - } - - /// Append a track state to this track. This will modify the tip index to - /// point at the newly created track state, which will be directly after the - /// previous track state at tip index. - /// @param mask The allocation prop mask for the new track state - /// @return The newly added track state - template > - auto appendTrackState(TrackStatePropMask mask = TrackStatePropMask::All) { - auto& tsc = m_container->trackStateContainer(); - auto ts = tsc.getTrackState(tsc.addTrackState(mask, tipIndex())); - tipIndex() = ts.index(); - return ts; - } - /// Return the number of track states associated to this track /// @note This is calculated by iterating over the track states which is /// somewhat expensive. Consider caching this value if you need It @@ -529,6 +445,7 @@ class TrackProxy { } /// Return the number of measurements for the track. Const version + /// @note Only available if the track proxy is not read-only /// @return The number of measurements template > unsigned int& nMeasurements() { @@ -544,6 +461,7 @@ class TrackProxy { /// Return a mutable reference to the number of holes for the track. /// Mutable version + /// @note Only available if the track proxy is not read-only /// @return The number of holes template > unsigned int& nHoles() { @@ -558,6 +476,7 @@ class TrackProxy { /// Return a mutable reference to the number of outliers for the track. /// Mutable version + /// @note Only available if the track proxy is not read-only /// @return The number of outliers template > unsigned int& nOutliers() { @@ -572,6 +491,7 @@ class TrackProxy { /// Return a mutable reference to the number of shared hits for the track. /// Mutable version + /// @note Only available if the track proxy is not read-only /// @return The number of shared hits template > unsigned int& nSharedHits() { @@ -586,6 +506,7 @@ class TrackProxy { /// Return a mutable reference to the chi squared /// Mutable version + /// @note Only available if the track proxy is not read-only /// @return The chi squared template > float& chi2() { @@ -600,6 +521,7 @@ class TrackProxy { /// Return a mutable reference to the number of degrees of freedom for the /// track. Mutable version + /// @note Only available if the track proxy is not read-only /// @return The number of degrees of freedom template > unsigned int& nDoF() { @@ -619,22 +541,127 @@ class TrackProxy { return m_index; } - /// Return the track parameters at the reference surface - /// @note The parameters are created on the fly - /// @return the track parameters - BoundTrackParameters createParametersAtReference() const { - return BoundTrackParameters(referenceSurface().getSharedPtr(), parameters(), - covariance(), particleHypothesis()); + /// @} + + /// @anchor track_proxy_track_states + /// @name TrackProxy track state access + /// Methods that give access to the track states of a track represented by @c TrackProxy. + /// @{ + + /// Return a const track state proxy to the innermost track state + /// @note This is only available, if the track is forward linked + /// @return The innermost track state proxy + auto innermostTrackState() const { + using proxy_t = decltype(m_container->trackStateContainer().getTrackState( + std::declval())); + + IndexType stem = component(hashString("stemIndex")); + if (stem == kInvalid) { + return std::optional{}; + } else { + return std::optional{ + m_container->trackStateContainer().getTrackState(stem)}; + } } - /// Return a reference to the track container backend, mutable version. - /// @return reference to the track container backend + /// Return a mutable track state proxy to the innermost track state + /// @note This is only available, if the track is forward linked + /// @note Only available if the track proxy is not read-only + /// @return The innermost track state proxy template > - auto& container() { - return *m_container; + auto innermostTrackState() { + using proxy_t = decltype(m_container->trackStateContainer().getTrackState( + std::declval())); + + IndexType stem = component(hashString("stemIndex")); + if (stem == kInvalid) { + return std::optional{}; + } else { + return std::optional{ + m_container->trackStateContainer().getTrackState(stem)}; + } + } + + /// Get a range over the track states of this track. Return value is + /// compatible with range based for loop. Const version + /// @note This range is from the outside inwards! + /// @return Track state range to iterate over + auto trackStatesReversed() const { + return m_container->reverseTrackStateRange(m_index); + } + + /// Get a range over the track states of this track. Return value is + /// compatible with range based for loop. Mutable version + /// @note Only available if the track proxy is not read-only + /// @note This range is from the outside inwards! + /// @return Track state range to iterate over + template > + auto trackStatesReversed() { + return m_container->reverseTrackStateRange(m_index); + } + + /// Get a range over the track states of this track. Return value is + /// compatible with range based for loop. This overload returns a const-only + /// track state range, which means you cannot modify the track states obtained + /// in the iteration. + /// @note This range is from the inside out! + /// @warning This access direction is only possible if the track states are + /// **forward-linked**. + /// @return Track state range to iterate over + auto trackStates() const { + return m_container->forwardTrackStateRange(m_index); + } + + /// Get a range over the track states of this track. + /// Return value is compatible with range based for loop. + /// This overload returns a mutable track state range, which means you + /// can modify the track states obtained in the iteration. + /// @note Only available if the track proxy is not read-only + /// @note This range is from the inside out! + /// @warning This access direction is only possible if the track states are + /// **forward-linked**. + /// @return Track state range to iterate over + template > + auto trackStates() { + return m_container->forwardTrackStateRange(m_index); + } + + /// @} + + /// @anchor track_proxy_track_state_manipulation + /// @name TrackProxy track state manipulation + /// Methods that manipulate the track states of a track represented by @c TrackProxy. + /// @{ + + /// Forward connect a track. + /// This means setting indices from the inside out on all track states. + /// @note Only available if the track proxy is not read-only + template > + void linkForward() { + IndexType last = kInvalid; + for (auto ts : trackStatesReversed()) { + ts.template component(hashString("next")) = last; + last = ts.index(); + } + stemIndex() = last; + } + + /// Append a track state to this track. + /// This will modify the tip index to point at the newly created track state, + /// which will be directly after the previous track state at tip index. + /// @note Only available if the track proxy is not read-only + /// @param mask The allocation prop mask for the new track state + /// @return The newly added track state + template > + auto appendTrackState(TrackStatePropMask mask = TrackStatePropMask::All) { + auto& tsc = m_container->trackStateContainer(); + auto ts = tsc.getTrackState(tsc.addTrackState(mask, tipIndex())); + tipIndex() = ts.index(); + return ts; } /// Copy the content of another track proxy into this one + /// @note Only available if the track proxy is not read-only /// @tparam track_proxy_t the other track proxy's type /// @param other The track proxy /// @param copyTrackStates Copy the track state sequence from @p other @@ -679,6 +706,7 @@ class TrackProxy { /// Reverse the ordering of track states for this track /// Afterwards, the previous endpoint of the track state sequence will be the /// "innermost" track state + /// @note Only available if the track proxy is not read-only /// @note This is dangerous with branching track state sequences, as it will break them /// @note This also automatically forward-links the track! /// @param invertJacobians Whether to invert the Jacobians of the track states @@ -714,23 +742,104 @@ class TrackProxy { } } - /// Return a reference to the track container backend, const version. + /// @} + + /// @anchor track_proxy_generic_component + /// @name TrackProxy generic component access + /// Methods that give access to generic components of a track represented by + /// @c TrackProxy. Internally, a compile-time hash of the component name is + /// used to identify which component is being requested. Most of the named + /// methods in @ref track_proxy_props "TrackProxy properties" use these + /// methods to retrieve the actual data. + /// + /// A number of overloads exist, where you can either supply the + /// @ref HashedString @c key as a template parameter or a runtime argument. The + /// former has the advantage of being guaranteed to be evaluated at + /// compile-time. + /// + /// @{ + + /// Retrieve a mutable reference to a component + /// @tparam T The type of the component to access + /// @tparam key String key for the component to access + /// @return Mutable reference to the component given by @p key + template > + constexpr T& component() { + return m_container->template component(m_index); + } + + /// Retrieve a mutable reference to a component + /// @tparam T The type of the component to access + /// @param key String key for the component to access + /// @return Mutable reference to the component given by @p key + template > + constexpr T& component(HashedString key) { + return m_container->template component(key, m_index); + } + + /// Retrieve a mutable reference to a component + /// @tparam T The type of the component to access + /// @param key String key for the component to access + /// @note This might hash the @p key at runtime instead of compile-time + /// @return Mutable reference to the component given by @p key + template > + constexpr T& component(std::string_view key) { + return m_container->template component(hashString(key), m_index); + } + + /// Retrieve a const reference to a component + /// @tparam T The type of the component to access + /// @tparam key String key for the component to access + /// @return Const reference to the component given by @p key + template + constexpr const T& component() const { + return m_container->template component(m_index); + } + + /// Retrieve a const reference to a component + /// @tparam T The type of the component to access + /// @param key String key for the component to access + /// @return Const reference to the component given by @p key + template + constexpr const T& component(HashedString key) const { + return m_container->template component(key, m_index); + } + + /// Retrieve a const reference to a component + /// @tparam T The type of the component to access + /// @param key String key for the component to access + /// @note This might hash the @p key at runtime instead of compile-time + /// @return Const reference to the component given by @p key + template + constexpr const T& component(std::string_view key) const { + return m_container->template component(hashString(key), m_index); + } + + /// @} + + /// Return the track parameters at the reference surface + /// @note The parameters are created on the fly + /// @return the track parameters + BoundTrackParameters createParametersAtReference() const { + return BoundTrackParameters(referenceSurface().getSharedPtr(), parameters(), + covariance(), particleHypothesis()); + } + + /// Return a reference to the track container backend, mutable version. + /// @note Only available if the track proxy is not read-only /// @return reference to the track container backend - const auto& container() const { + template > + auto& container() { return *m_container; } - /// Equality operator with another track proxy - /// Checks the container identity and the track index - /// @return True if the track proxies refer to the same track - bool operator==(const TrackProxy& other) const { - return &(*m_container) == &(*other.m_container) && m_index == other.m_index; + /// Return a reference to the track container backend, const version. + /// @return reference to the track container backend + const auto& container() const { + return *m_container; } - // Track proxies are friends, not food! - template class H, bool R> - friend class TrackProxy; - private: TrackProxy(detail_tc::ConstIf, ReadOnly>& container, diff --git a/Core/include/Acts/EventData/TrackStateProxy.hpp b/Core/include/Acts/EventData/TrackStateProxy.hpp index b82ad298a15..654468d1179 100644 --- a/Core/include/Acts/EventData/TrackStateProxy.hpp +++ b/Core/include/Acts/EventData/TrackStateProxy.hpp @@ -124,42 +124,80 @@ struct TrackStateTraits { template class TrackStateProxy { public: + /// Map-type for a bound parameter vector. This has reference semantics, i.e. + /// points at a matrix by an internal pointer. using Parameters = typename TrackStateTraits::Parameters; - using Covariance = typename TrackStateTraits::Covariance; + + /// Same as @ref Parameters, but with const semantics using ConstParameters = typename TrackStateTraits::Parameters; + + /// Map-type for a bound covariance. This has reference semantics, i.e. + /// points at a matrix by an internal pointer. + using Covariance = typename TrackStateTraits::Covariance; + + /// Same as @ref Covariance, but with const semantics using ConstCovariance = typename TrackStateTraits::Covariance; + /// Map-type for a measurement vector, where the local measurement dimension + /// is variable. template using Measurement = typename TrackStateTraits::Measurement; + + /// Same as @c Measurement, but with const semantics + template + using ConstMeasurement = typename TrackStateTraits::Measurement; + + /// Map-type for a measurement covariance matrix, where the local measurement + /// dimension is variable. template using MeasurementCovariance = typename TrackStateTraits::MeasurementCovariance; - template - using ConstMeasurement = typename TrackStateTraits::Measurement; + + /// Same as @ref MeasurementCovariance, but with const semantics template using ConstMeasurementCovariance = typename TrackStateTraits::MeasurementCovariance; + /// The index type of the track state container using IndexType = TrackIndexType; + + /// Sentinel value that indicates an invalid index static constexpr IndexType kInvalid = kTrackIndexInvalid; - // as opposed to the types above, this is an actual Matrix (rather than a - // map) - // @TODO: Does not copy flags, because this fails: can't have col major row - // vector, but that's required for 1xN projection matrices below. + /// Matrix representing the projector (measurement mapping function) for a + /// measurement. This is not a map type, but an actual matrix. This matrix + /// is always \f$M \times M\f$, even if the local measurement dimension is lower. + /// The actual \f$N\times M\f$ projector is given by the top \f$N\f$ rows. using Projector = typename TrackStateTraits::Projector; + + /// Dynamic variant of the projector matrix + /// @warning Using this type is discouraged, as it has a runtime overhead using EffectiveProjector = Eigen::Matrix::ProjectorFlags, M, eBoundSize>; + /// The track state container backend given as a template parameter using Trajectory = trajectory_t; - // Constructor and assignment operator to construct ReadOnly TrackStateProxy - // from ReadWrite (mutable -> const) + /// @anchor track_state_proxy_construct + /// @name Constructors and assignment operator + /// + /// Public constructors and assignment operators for @c TrackStateProxy only + /// allow construction from another @c TrackStateProxy. You should generally + /// not have to construct @c TrackStateProxy manually. + /// + /// @{ + + /// Constructor and assignment operator to construct TrackStateProxy + /// from mutable + /// @param other The other TrackStateProxy to construct from TrackStateProxy(const TrackStateProxy& other) : m_traj{other.m_traj}, m_istate{other.m_istate} {} + /// Assignment operator to from mutable @c TrackStateProxy + /// @param other The other TrackStateProxy to construct from + /// @return Reference to this TrackStateProxy TrackStateProxy& operator=( const TrackStateProxy& other) { m_traj = other.m_traj; @@ -168,11 +206,58 @@ class TrackStateProxy { return *this; } + /// @} + + /// @anchor track_state_proxy_props + /// @name Track state properties + /// + /// Properties of the track state represented by @c TrackStateProxy. + /// + /// Many of these methods come in a @c const and a non-@c const version. The + /// non-@c const version is only available if you have an instance of + /// @c TrackStateProxy that does not have the @c read_only template parameter set to + /// @c true, even if you hold it as an lvalue. + /// + /// The track states each have an index in the track state container. The + /// sequence of track states is implemented as a one or two-way linked list, + /// which uses indices into the same container. + /// + /// Each track state has a @c previous index, which points at the track state + /// immediately preceding. A track state with a @c previous index of @c + /// kInvalid is the first (innermost) track state in a track or track + /// candidate. This is also referred to as a *stem* at the track level. + /// + /// During track finding and fitting, track states are usually appended to the + /// sequence, populating the @c previous index of the new track state. Combinatorial + /// track finding can produce track states which fork in this way, by having + /// more than one track state with the same @c previous index. + /// + /// The track states have static, optional and dynamic properties. Static + /// properties are always present, and can always be retrieved. Optional + /// components use an extra indirection mechanism that coordinates with the + /// backend to allow both not having the component set, or sharing it with + /// other track states. An example is a branching trajectory from track + /// finding which shares the same predicted parameter vector and associated + /// covariance. + /// + /// Optional components are + /// - predicted parameters and covariance + /// - filtered parameters and covariance + /// - smoothed parameters and covariance + /// - jacobian + /// - calibrated measurement info including projector + /// + /// They can be unset via @ref unset, @ref getMask can be used to check which + /// components are present. The first four are shareable between track + /// states via @ref shareFrom. + /// + /// @{ + /// Index within the trajectory. /// @return the index IndexType index() const { return m_istate; } - /// Return the index of the track state 'previous' in the track sequence + /// Return the index of the track state `previous` in the track sequence /// @return The index of the previous track state. IndexType previous() const { return component(); @@ -180,6 +265,7 @@ class TrackStateProxy { /// Return a mutable reference to the index of the track state 'previous' in /// the track sequence + /// @note Only available if the track state proxy is not read-only /// @return The index of the previous track state. template > IndexType& previous() { @@ -197,191 +283,8 @@ class TrackStateProxy { /// @return The generated mask TrackStatePropMask getMask() const; - /// Share a shareable component within this track state - /// @param shareSource Which component to share from - /// @param shareTarget Which component to share as. This should be different from - /// as @p shareSource, e.g. predicted can be shared as filtered. - /// @note Shareable components are predicted, filtered, smoothed, calibrated, jacobian, - /// or projector. See @c TrackStatePropMask. - template > - void shareFrom(TrackStatePropMask shareSource, - TrackStatePropMask shareTarget) { - shareFrom(*this, shareSource, shareTarget); - } - - /// Share a shareable component from another track state. - /// @param other Track state proxy to share component from - /// @param component Which component to share. - /// @note Shareable components are predicted, filtered, smoothed, calibrated, jacobian, - /// or projector. See @c TrackStatePropMask. - /// @note The track states both need to be stored in the - /// same @c MultiTrajectory instance - template > - void shareFrom(const TrackStateProxy& other, - TrackStatePropMask component) { - shareFrom(other, component, component); - } - - /// Share a shareable component from another track state - /// @param shareSource Which component to share from - /// @param shareTarget Which component to share as. This can be be different from - /// as @p shareSource, e.g. predicted can be shared as filtered. - /// @note Shareable components are predicted, filtered, smoothed, calibrated, jacobian, - /// or projector. See @c TrackStatePropMask. - template > - void shareFrom(const TrackStateProxy& other, - TrackStatePropMask shareSource, - TrackStatePropMask shareTarget) { - assert(m_traj == other.m_traj && - "Cannot share components across MultiTrajectories"); - - assert(ACTS_CHECK_BIT(other.getMask(), shareSource) && - "Source has incompatible allocation"); - - m_traj->self().shareFrom(m_istate, other.m_istate, shareSource, - shareTarget); - } - - /// Copy the contents of another track state proxy into this one - /// @param other The other track state to copy from - /// @param mask An optional mask to determine what to copy from - /// @param onlyAllocated Whether to only copy allocated components - /// @note If the this track state proxy does not have compatible allocations - /// with the source track state proxy, and @p onlyAllocated is false, - /// an exception is thrown. - /// @note The mask parameter will not cause a copy of components that are - /// not allocated in the source track state proxy. - template > - void copyFrom(const track_state_proxy_t& other, - TrackStatePropMask mask = TrackStatePropMask::All, - bool onlyAllocated = true) { - using PM = TrackStatePropMask; - - // @TODO: How to support arbitrary columns here? - - if (onlyAllocated) { - auto dest = getMask(); - auto src = other.getMask() & - mask; // combine what we have with what we want to copy - - if (ACTS_CHECK_BIT(src, PM::Calibrated)) { - // on-demand allocate calibrated - dest |= PM::Calibrated; - } - - if ((static_cast>( - (src ^ dest) & src) != 0 || - dest == TrackStatePropMask::None || - src == TrackStatePropMask::None) && - mask != TrackStatePropMask::None) { - throw std::runtime_error( - "Attempt track state copy with incompatible allocations"); - } - - // we're sure now this has correct allocations, so just copy - if (ACTS_CHECK_BIT(src, PM::Predicted)) { - predicted() = other.predicted(); - predictedCovariance() = other.predictedCovariance(); - } - - if (ACTS_CHECK_BIT(src, PM::Filtered)) { - filtered() = other.filtered(); - filteredCovariance() = other.filteredCovariance(); - } - - if (ACTS_CHECK_BIT(src, PM::Smoothed)) { - smoothed() = other.smoothed(); - smoothedCovariance() = other.smoothedCovariance(); - } - - if (other.hasUncalibratedSourceLink()) { - setUncalibratedSourceLink(other.getUncalibratedSourceLink()); - } - - if (ACTS_CHECK_BIT(src, PM::Jacobian)) { - jacobian() = other.jacobian(); - } - - if (ACTS_CHECK_BIT(src, PM::Calibrated)) { - allocateCalibrated(other.calibratedSize()); - - // workaround for gcc8 bug: - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86594 - auto* self = this; - visit_measurement(other.calibratedSize(), [&](auto N) { - constexpr int measdim = decltype(N)::value; - self->template calibrated() = - other.template calibrated(); - self->template calibratedCovariance() = - other.template calibratedCovariance(); - }); - - setProjectorBitset(other.projectorBitset()); - } - } else { - if (ACTS_CHECK_BIT(mask, PM::Predicted) && - has() && - other.template has()) { - predicted() = other.predicted(); - predictedCovariance() = other.predictedCovariance(); - } - - if (ACTS_CHECK_BIT(mask, PM::Filtered) && has() && - other.template has()) { - filtered() = other.filtered(); - filteredCovariance() = other.filteredCovariance(); - } - - if (ACTS_CHECK_BIT(mask, PM::Smoothed) && has() && - other.template has()) { - smoothed() = other.smoothed(); - smoothedCovariance() = other.smoothedCovariance(); - } - - if (other.hasUncalibratedSourceLink()) { - setUncalibratedSourceLink(other.getUncalibratedSourceLink()); - } - - if (ACTS_CHECK_BIT(mask, PM::Jacobian) && has() && - other.template has()) { - jacobian() = other.jacobian(); - } - - if (ACTS_CHECK_BIT(mask, PM::Calibrated) && - has() && - other.template has()) { - allocateCalibrated(other.calibratedSize()); - - // workaround for gcc8 bug: - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86594 - auto* self = this; - visit_measurement(other.calibratedSize(), [&](auto N) { - constexpr int measdim = decltype(N)::value; - self->template calibrated() = - other.template calibrated(); - self->template calibratedCovariance() = - other.template calibratedCovariance(); - }); - - setProjectorBitset(other.projectorBitset()); - } - } - - chi2() = other.chi2(); - pathLength() = other.pathLength(); - typeFlags() = other.typeFlags(); - - if (other.hasReferenceSurface()) { - setReferenceSurface(other.referenceSurface().getSharedPtr()); - } - - m_traj->copyDynamicFrom(m_istate, other.container(), other.index()); - } - /// Unset an optional track state component + /// @note Only available if the track state proxy is not read-only /// @param target The component to unset template > void unset(TrackStatePropMask target) { @@ -414,85 +317,59 @@ class TrackStateProxy { } // NOLINTEND(performance-unnecessary-value-param) - /// Check if a component is set - /// @tparam key Hashed string key to check for - /// @return true if the component exists, false if not - template - constexpr bool has() const { - return m_traj->template has(m_istate); + /// Getter/setter for chi2 value associated with the track state + /// This overload returns a mutable reference, which allows setting a new + /// value directly into the backing store. + /// @note this overload is only enabled in case the proxy is not read-only + /// @return Mutable reference to the chi2 value + template > + float& chi2() { + return component(); } - /// Check if a component is set - /// @param key Hashed string key to check for - /// @return true if the component exists, false if not - constexpr bool has(HashedString key) const { - return m_traj->has(key, m_istate); + /// Getter for the chi2 value associated with the track state. + /// This overload returns a copy of the chi2 value, and thus does not allow + /// modification of the value in the backing storage. + /// @return the chi2 value of the track state + float chi2() const { return component(); } + + /// Getter for the path length associated with the track state. + /// This overloaded is only enabled if not read-only, and returns a mutable + /// reference. + /// @return Mutable reference to the pathlength. + template > + double& pathLength() { + return component(); } - /// Check if a component is set - /// @param key String key to check for - /// @note This might hash the @p key at runtime instead of compile-time - /// @return true if the component exists, false if not - constexpr bool has(std::string_view key) const { - return has(hashString(key)); + /// Getter for the path length. Returns a copy of the path length value. + /// @return The path length of this track state + double pathLength() const { + return component(); } - /// Retrieve a mutable reference to a component - /// @tparam T The type of the component to access - /// @tparam key String key for the component to access - /// @return Mutable reference to the component given by @p key - template > - constexpr T& component() { - return m_traj->template component(m_istate); + /// Getter for the type flags associated with the track state. + /// This overloaded is only enabled if not read-only, and returns a mutable + /// reference. + /// @return reference to the type flags. + template > + TrackStateType typeFlags() { + return TrackStateType{ + component()}; } - /// Retrieve a mutable reference to a component - /// @tparam T The type of the component to access - /// @param key String key for the component to access - /// @return Mutable reference to the component given by @p key - template > - constexpr T& component(HashedString key) { - return m_traj->template component(key, m_istate); + /// Getter for the type flags. Returns a copy of the type flags value. + /// @return The type flags of this track state + ConstTrackStateType typeFlags() const { + return ConstTrackStateType{ + component()}; } - /// Retrieve a mutable reference to a component - /// @tparam T The type of the component to access - /// @param key String key for the component to access - /// @note This might hash the @p key at runtime instead of compile-time - /// @return Mutable reference to the component given by @p key - template > - constexpr T& component(std::string_view key) { - return m_traj->template component(hashString(key), m_istate); - } + /// @} - /// Retrieve a const reference to a component - /// @tparam T The type of the component to access - /// @tparam key String key for the component to access - /// @return Const reference to the component given by @p key - template - constexpr const T& component() const { - return m_traj->template component(m_istate); - } - - /// Retrieve a const reference to a component - /// @tparam T The type of the component to access - /// @param key String key for the component to access - /// @return Const reference to the component given by @p key - template - constexpr const T& component(HashedString key) const { - return m_traj->template component(key, m_istate); - } - - /// Retrieve a const reference to a component - /// @tparam T The type of the component to access - /// @param key String key for the component to access - /// @note This might hash the @p key at runtime instead of compile-time - /// @return Const reference to the component given by @p key - template - constexpr const T& component(std::string_view key) const { - return m_traj->template component(hashString(key), m_istate); - } + /// @anchor track_state_proxy_params + /// @name Track state parameters + /// @{ /// Track parameters vector. This tries to be somewhat smart and return the /// first parameters that are set in this order: predicted -> filtered -> @@ -646,6 +523,38 @@ class TrackStateProxy { /// @return Whether it is set bool hasJacobian() const { return has(); } + /// @} + + /// @anchor track_state_proxy_meas + /// @name Track state measurement properties + /// + /// Properties of the measurement associated with the track state represented. + /// This consists of a vector and an associated square matrix of a measurement + /// dimension which is between one and the size of the track parametrization. + /// The measurement coordinate frame is required to be a strict subset of the + /// bound track parametrization on the local geometry coordinate frame, i.e. + /// using a pure projector matrix to convert from the bound parametrization to + /// the measurement frame is possible. + /// + /// The track state stores the parameter vector and covariance, and the + /// backend is given the possibility to do so in a jagged way, i.e. only + /// storing the number of values needed. This requires calling + /// @ref allocateCalibrated before storing the measurements + /// (even if it might be a no-op). + /// + /// The projector matrix is packed as a bitset, which is converted to a matrix + /// on-demand (and therefore returned by value). + /// + /// A convenience function to assign this from the @ref Measurement class + /// is provided, although it's use is discouraged. + /// + /// The track state also includes a @ref SourceLink which acts as a proxy + /// to the original uncalibrated measurement that the calibrated measurement + /// was derived from. It is set and returned by value, to allow unpacking / + /// repacking by the backend, if needed. + /// + /// @{ + /// Returns the projector (measurement mapping function) for this track /// state. It is derived from the uncalibrated measurement /// @note This function returns the overallocated projector. This means it @@ -661,8 +570,8 @@ class TrackStateProxy { /// Returns the projector (measurement mapping function) for this track /// state. It is derived from the uncalibrated measurement - /// @note This function returns the effective projector. This means it - /// is of dimension NxM, where N is the actual dimension of the + /// @warning This function returns the effective projector. This means it + /// is of dimension \f$N\times M\f$, where \f$N\f$ is the actual dimension of the /// measurement. /// @return The effective projector EffectiveProjector effectiveProjector() const { @@ -702,10 +611,11 @@ class TrackStateProxy { projectorBitset.to_ullong(); } - /// Get the projector bitset, a compressed form of a projection matrix + /// Directly get the projector bitset, a compressed form of a projection + /// matrix /// @note This is mainly to copy explicitly a projector from one state - /// to another. Use the `projector` or `effectiveProjector` method if - /// you want to access the matrix. + /// to another. Use the `projector` or `effectiveProjector` method if + /// you want to access the matrix. /// @return The projector bitset ProjectorBitset projectorBitset() const { assert(has()); @@ -716,7 +626,8 @@ class TrackStateProxy { /// @param proj The projector bitset /// /// @note This is mainly to copy explicitly a projector from one state - /// to another. If you have a projection matrix, set it with `setProjector`. + /// to another. If you have a projection matrix, set it with + /// `setProjector`. template > void setProjectorBitset(ProjectorBitset proj) { assert(has()); @@ -765,20 +676,18 @@ class TrackStateProxy { return m_traj->self().template measurement(m_istate); } - /// Full calibrated measurement covariance matrix. The effective covariance - /// is located in the top left corner, everything else is zeroed. + /// Const full calibrated measurement covariance matrix. The effective + /// covariance is located in the top left corner, everything else is zeroed. /// @return The measurement covariance matrix - /// @note Const version template ConstMeasurementCovariance calibratedCovariance() const { assert(has()); return m_traj->self().template measurementCovariance(m_istate); } - /// Full calibrated measurement covariance matrix. The effective covariance - /// is located in the top left corner, everything else is zeroed. + /// Mutable full calibrated measurement covariance matrix. The effective + /// covariance is located in the top left corner, everything else is zeroed. /// @return The measurement covariance matrix - /// @note Mutable version template > MeasurementCovariance calibratedCovariance() { @@ -786,9 +695,9 @@ class TrackStateProxy { return m_traj->self().template measurementCovariance(m_istate); } - /// Dynamic measurement vector with only the valid dimensions. + /// Mutable dynamic measurement vector with only the valid dimensions. + /// @warning The dynamic vector has a runtime overhead! /// @return The effective calibrated measurement vector - /// @note Mutable version template > auto effectiveCalibrated() { // repackage the data pointer to a dynamic map type @@ -803,9 +712,9 @@ class TrackStateProxy { }); } - /// Dynamic measurement vector with only the valid dimensions. + /// Const dynamic measurement vector with only the valid dimensions. + /// @warning The dynamic matrix has a runtime overhead! /// @return The effective calibrated measurement vector - /// @note Const version auto effectiveCalibrated() const { // repackage the data pointer to a dynamic map type // workaround for gcc8 bug: @@ -819,9 +728,10 @@ class TrackStateProxy { }); } - /// Dynamic measurement covariance matrix with only the valid dimensions. + /// Mutable dynamic measurement covariance matrix with only the valid + /// dimensions. + /// @warning The dynamic matrix has a runtime overhead! /// @return The effective calibrated covariance matrix - /// @note Mutable version template > auto effectiveCalibratedCovariance() { // repackage the data pointer to a dynamic map type @@ -836,9 +746,10 @@ class TrackStateProxy { }); } - /// Dynamic measurement covariance matrix with only the valid dimensions. + /// Const dynamic measurement covariance matrix with only the valid + /// dimensions. + /// @warning The dynamic matrix has a runtime overhead! /// @return The effective calibrated covariance matrix - /// @note Const version auto effectiveCalibratedCovariance() const { // repackage the data pointer to a dynamic map type // workaround for gcc8 bug: @@ -853,20 +764,24 @@ class TrackStateProxy { } /// Return the (dynamic) number of dimensions stored for this measurement. - /// @note The underlying storage is overallocated to MeasurementSizeMax - /// regardless of this value + /// @note Depending on the backend, this size is used to determine the + /// memory range of the measurement vector and covariance. /// @return The number of dimensions IndexType calibratedSize() const { return m_traj->calibratedSize(m_istate); } - /// Overwrite existing measurement data. + /// Set the calibrated measurement of this track state from a measurement + /// object. This is a convenience function to set the calibrated measurement + /// from the @c Acts::Measurement object. In general, you should implement this + /// functionality specifically for an (experiment-specific) uncalibrated + /// measurement EDM. /// /// @tparam kMeasurementSize Size of the calibrated measurement /// @param meas The measurement object to set /// - /// @note This assumes this TrackState stores it's own calibrated - /// measurement. **If storage is shared with another TrackState, both will - /// be overwritten!**. Also assumes none of the calibrated components is - /// *invalid* (i.e. unset) for this TrackState. + /// @warning This assumes this TrackState stores it's own calibrated + /// measurement. **If storage is shared with another TrackState, both + /// will be overwritten!**. Also assumes none of the calibrated + /// components is *invalid* (i.e. unset) for this TrackState. /// @note This does not set the reference surface. template > @@ -888,67 +803,306 @@ class TrackStateProxy { setProjector(meas.projector()); } + /// Allocate storage to be able to store a measurement of size @p measdim. + /// This must be called **before** setting the measurement content. void allocateCalibrated(std::size_t measdim) { m_traj->allocateCalibrated(m_istate, measdim); } - /// Getter/setter for chi2 value associated with the track state - /// This overload returns a mutable reference, which allows setting a new - /// value directly into the backing store. - /// @note this overload is only enabled in case the proxy is not read-only - /// @return Mutable reference to the chi2 value + /// @} + + /// @anchor track_state_share_copy + /// @name Sharing and copying + /// + /// Methods to share and copy track state components. Sharing means setting up + /// more than one track state to point to the same component. + /// + /// Shareable components are + /// - predicted parameters and covariance + /// - filtered parameters and covariance + /// - smoothed parameters and covariance + /// - jacobian + /// + /// See @ref TrackStatePropMask. + /// + /// @{ + + /// Share a shareable component **within** this track state + /// @param shareSource Which component to share from + /// @param shareTarget Which component to share as. This should be different from + /// as @p shareSource, e.g. predicted can be shared as filtered. template > - float& chi2() { - return component(); + void shareFrom(TrackStatePropMask shareSource, + TrackStatePropMask shareTarget) { + shareFrom(*this, shareSource, shareTarget); } - /// Getter for the chi2 value associated with the track state. - /// This overload returns a copy of the chi2 value, and thus does not allow - /// modification of the value in the backing storage. - /// @return the chi2 value of the track state - float chi2() const { return component(); } + /// Share a shareable component from another track state. + /// @param other Track state proxy to share component from + /// @param component Which component to share. + /// @note The track states both need to be stored in the + /// same @c MultiTrajectory instance + template > + void shareFrom(const TrackStateProxy& other, + TrackStatePropMask component) { + shareFrom(other, component, component); + } - /// Getter for the path length associated with the track state. - /// This overloaded is only enabled if not read-only, and returns a mutable - /// reference. - /// @return Mutable reference to the pathlength. - template > - double& pathLength() { - return component(); + /// Share a shareable component from another track state + /// @param other Track state proxy to share component(s) from + /// @param shareSource Which component to share from + /// @param shareTarget Which component to share as. This can be be different from + /// as @p shareSource, e.g. predicted can be shared as filtered. + /// @note Shareable components are predicted, filtered, smoothed, calibrated, jacobian, + /// or projector. See @c TrackStatePropMask. + template > + void shareFrom(const TrackStateProxy& other, + TrackStatePropMask shareSource, + TrackStatePropMask shareTarget) { + assert(m_traj == other.m_traj && + "Cannot share components across MultiTrajectories"); + + assert(ACTS_CHECK_BIT(other.getMask(), shareSource) && + "Source has incompatible allocation"); + + m_traj->self().shareFrom(m_istate, other.m_istate, shareSource, + shareTarget); } - /// Getter for the path length. Returns a copy of the path length value. - /// @return The path length of this track state - double pathLength() const { - return component(); + /// Copy the contents of another track state proxy into this one + /// @param other The other track state to copy from + /// @param mask An optional mask to determine what to copy from + /// @param onlyAllocated Whether to only copy allocated components + /// @note If the this track state proxy does not have compatible allocations + /// with the source track state proxy, and @p onlyAllocated is false, + /// an exception is thrown. + /// @note The mask parameter will not cause a copy of components that are + /// not allocated in the source track state proxy. + template > + void copyFrom(const track_state_proxy_t& other, + TrackStatePropMask mask = TrackStatePropMask::All, + bool onlyAllocated = true) { + using PM = TrackStatePropMask; + + if (onlyAllocated) { + auto dest = getMask(); + auto src = other.getMask() & + mask; // combine what we have with what we want to copy + + if (ACTS_CHECK_BIT(src, PM::Calibrated)) { + // on-demand allocate calibrated + dest |= PM::Calibrated; + } + + if ((static_cast>( + (src ^ dest) & src) != 0 || + dest == TrackStatePropMask::None || + src == TrackStatePropMask::None) && + mask != TrackStatePropMask::None) { + throw std::runtime_error( + "Attempt track state copy with incompatible allocations"); + } + + // we're sure now this has correct allocations, so just copy + if (ACTS_CHECK_BIT(src, PM::Predicted)) { + predicted() = other.predicted(); + predictedCovariance() = other.predictedCovariance(); + } + + if (ACTS_CHECK_BIT(src, PM::Filtered)) { + filtered() = other.filtered(); + filteredCovariance() = other.filteredCovariance(); + } + + if (ACTS_CHECK_BIT(src, PM::Smoothed)) { + smoothed() = other.smoothed(); + smoothedCovariance() = other.smoothedCovariance(); + } + + if (other.hasUncalibratedSourceLink()) { + setUncalibratedSourceLink(other.getUncalibratedSourceLink()); + } + + if (ACTS_CHECK_BIT(src, PM::Jacobian)) { + jacobian() = other.jacobian(); + } + + if (ACTS_CHECK_BIT(src, PM::Calibrated)) { + allocateCalibrated(other.calibratedSize()); + + // workaround for gcc8 bug: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86594 + auto* self = this; + visit_measurement(other.calibratedSize(), [&](auto N) { + constexpr int measdim = decltype(N)::value; + self->template calibrated() = + other.template calibrated(); + self->template calibratedCovariance() = + other.template calibratedCovariance(); + }); + + setProjectorBitset(other.projectorBitset()); + } + } else { + if (ACTS_CHECK_BIT(mask, PM::Predicted) && + has() && + other.template has()) { + predicted() = other.predicted(); + predictedCovariance() = other.predictedCovariance(); + } + + if (ACTS_CHECK_BIT(mask, PM::Filtered) && has() && + other.template has()) { + filtered() = other.filtered(); + filteredCovariance() = other.filteredCovariance(); + } + + if (ACTS_CHECK_BIT(mask, PM::Smoothed) && has() && + other.template has()) { + smoothed() = other.smoothed(); + smoothedCovariance() = other.smoothedCovariance(); + } + + if (other.hasUncalibratedSourceLink()) { + setUncalibratedSourceLink(other.getUncalibratedSourceLink()); + } + + if (ACTS_CHECK_BIT(mask, PM::Jacobian) && has() && + other.template has()) { + jacobian() = other.jacobian(); + } + + if (ACTS_CHECK_BIT(mask, PM::Calibrated) && + has() && + other.template has()) { + allocateCalibrated(other.calibratedSize()); + + // workaround for gcc8 bug: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86594 + auto* self = this; + visit_measurement(other.calibratedSize(), [&](auto N) { + constexpr int measdim = decltype(N)::value; + self->template calibrated() = + other.template calibrated(); + self->template calibratedCovariance() = + other.template calibratedCovariance(); + }); + + setProjectorBitset(other.projectorBitset()); + } + } + + chi2() = other.chi2(); + pathLength() = other.pathLength(); + typeFlags() = other.typeFlags(); + + if (other.hasReferenceSurface()) { + setReferenceSurface(other.referenceSurface().getSharedPtr()); + } + + m_traj->copyDynamicFrom(m_istate, other.container(), other.index()); } - /// Getter for the type flags associated with the track state. - /// This overloaded is only enabled if not read-only, and returns a mutable - /// reference. - /// @return reference to the type flags. - template > - TrackStateType typeFlags() { - return TrackStateType{ - component()}; + /// @} + + /// @anchor track_state_proxy_generic_component + /// @name Track state proxy Generic component access + /// @{ + + /// Check if a component is set + /// @tparam key Hashed string key to check for + /// @return true if the component exists, false if not + template + constexpr bool has() const { + return m_traj->template has(m_istate); } - /// Getter for the type flags. Returns a copy of the type flags value. - /// @return The type flags of this track state - ConstTrackStateType typeFlags() const { - return ConstTrackStateType{ - component()}; + /// Check if a component is set + /// @param key Hashed string key to check for + /// @return true if the component exists, false if not + constexpr bool has(HashedString key) const { + return m_traj->has(key, m_istate); } - /// Get a mutable reference to the track state container backend - /// @return a mutable reference to the backend + /// Check if a component is set + /// @param key String key to check for + /// @note This might hash the @p key at runtime instead of compile-time + /// @return true if the component exists, false if not + constexpr bool has(std::string_view key) const { + return has(hashString(key)); + } + + /// Retrieve a mutable reference to a component + /// @tparam T The type of the component to access + /// @tparam key String key for the component to access + /// @return Mutable reference to the component given by @p key + template > + constexpr T& component() { + return m_traj->template component(m_istate); + } + + /// Retrieve a mutable reference to a component + /// @tparam T The type of the component to access + /// @param key String key for the component to access + /// @return Mutable reference to the component given by @p key + template > + constexpr T& component(HashedString key) { + return m_traj->template component(key, m_istate); + } + + /// Retrieve a mutable reference to a component + /// @tparam T The type of the component to access + /// @param key String key for the component to access + /// @note This might hash the @p key at runtime instead of compile-time + /// @return Mutable reference to the component given by @p key + template > + constexpr T& component(std::string_view key) { + return m_traj->template component(hashString(key), m_istate); + } + + /// Retrieve a const reference to a component + /// @tparam T The type of the component to access + /// @tparam key String key for the component to access + /// @return Const reference to the component given by @p key + template + constexpr const T& component() const { + return m_traj->template component(m_istate); + } + + /// Retrieve a const reference to a component + /// @tparam T The type of the component to access + /// @param key String key for the component to access + /// @return Const reference to the component given by @p key + template + constexpr const T& component(HashedString key) const { + return m_traj->template component(key, m_istate); + } + + /// Retrieve a const reference to a component + /// @tparam T The type of the component to access + /// @param key String key for the component to access + /// @note This might hash the @p key at runtime instead of compile-time + /// @return Const reference to the component given by @p key + template + constexpr const T& component(std::string_view key) const { + return m_traj->template component(hashString(key), m_istate); + } + + /// @} + + /// Return a mutable reference to the underlying backend container + /// @return A reference to the backend container template > MultiTrajectory& trajectory() { return *m_traj; } - /// Get a const reference to the track state container backend - /// @return a const reference to the backend + /// Return a const reference to the underlying backend container + /// @return A const reference to the backend container const MultiTrajectory& trajectory() const { return *m_traj; } /// Get a mutable reference to the track state container backend diff --git a/Core/include/Acts/EventData/VectorMultiTrajectory.hpp b/Core/include/Acts/EventData/VectorMultiTrajectory.hpp index d73e6d9d223..5a6aa87e62e 100644 --- a/Core/include/Acts/EventData/VectorMultiTrajectory.hpp +++ b/Core/include/Acts/EventData/VectorMultiTrajectory.hpp @@ -182,6 +182,7 @@ class VectorMultiTrajectoryBase { for (const auto& [key, value] : other.m_dynamic) { m_dynamic.insert({key, value->clone()}); } + m_dynamicKeys = other.m_dynamicKeys; }; VectorMultiTrajectoryBase(VectorMultiTrajectoryBase&& other) = default; @@ -333,6 +334,7 @@ class VectorMultiTrajectoryBase { // be handled in a smart way by moving but not sure. std::vector> m_referenceSurfaces; + std::vector m_dynamicKeys; std::unordered_map> m_dynamic; }; diff --git a/Core/include/Acts/EventData/VectorTrackContainer.hpp b/Core/include/Acts/EventData/VectorTrackContainer.hpp index 0183ce8d801..50bdbc2cd88 100644 --- a/Core/include/Acts/EventData/VectorTrackContainer.hpp +++ b/Core/include/Acts/EventData/VectorTrackContainer.hpp @@ -188,6 +188,7 @@ class VectorTrackContainerBase { std::unordered_map> m_dynamic; + std::vector m_dynamicKeys; }; } // namespace detail_vtc diff --git a/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp b/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp index 8b97da0f8b7..8693a396104 100644 --- a/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp +++ b/Core/include/Acts/EventData/detail/MultiTrajectoryTestsCommon.hpp @@ -463,7 +463,7 @@ class MultiTrajectoryTestsCommon { } BOOST_CHECK(ts.hasProjector()); - ActsMatrix fullProj; + ActsMatrix fullProj; fullProj.setZero(); { Acts::GeometryContext gctx; diff --git a/Core/src/EventData/VectorTrackContainer.cpp b/Core/src/EventData/VectorTrackContainer.cpp index 1b75a5eb987..27f7425182a 100644 --- a/Core/src/EventData/VectorTrackContainer.cpp +++ b/Core/src/EventData/VectorTrackContainer.cpp @@ -34,6 +34,7 @@ VectorTrackContainerBase::VectorTrackContainerBase( for (const auto& [key, value] : other.m_dynamic) { m_dynamic.insert({key, value->clone()}); } + m_dynamicKeys = other.m_dynamicKeys; assert(checkConsistency()); } } // namespace detail_vtc diff --git a/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackContainer.hpp b/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackContainer.hpp index 4ae77b59051..89cc7c06f46 100644 --- a/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackContainer.hpp +++ b/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackContainer.hpp @@ -294,6 +294,7 @@ class MutablePodioTrackContainer : public PodioTrackContainerBase { friend PodioTrackContainerBase; std::unique_ptr m_collection; + std::vector m_dynamicKeys; std::unordered_map> m_dynamic; @@ -383,6 +384,7 @@ class ConstPodioTrackContainer : public PodioTrackContainerBase { std::unordered_map> m_dynamic; + std::vector m_dynamicKeys; }; ACTS_STATIC_CHECK_CONCEPT(ConstTrackContainerBackend, ConstPodioTrackContainer); diff --git a/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackStateContainer.hpp b/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackStateContainer.hpp index 0ba4a0540eb..442b6d21590 100644 --- a/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackStateContainer.hpp +++ b/Plugins/Podio/include/Acts/Plugins/Podio/PodioTrackStateContainer.hpp @@ -339,6 +339,7 @@ class ConstPodioTrackStateContainer final std::unordered_map> m_dynamic; + std::vector m_dynamicKeys; }; static_assert(IsReadOnlyMultiTrajectory::value, @@ -655,15 +656,13 @@ class MutablePodioTrackStateContainer final std::unordered_map> m_dynamic; + std::vector m_dynamicKeys; }; static_assert( !IsReadOnlyMultiTrajectory::value, "MutablePodioTrackStateContainer should not be read-only"); -static_assert(!MutablePodioTrackStateContainer::ReadOnly, - "MutablePodioTrackStateContainer should not be read-only"); - ACTS_STATIC_CHECK_CONCEPT(MutableMultiTrajectoryBackend, MutablePodioTrackStateContainer); diff --git a/Tests/UnitTests/Core/EventData/MultiTrajectoryTests.cpp b/Tests/UnitTests/Core/EventData/MultiTrajectoryTests.cpp index 422d31c3879..1efdf714164 100644 --- a/Tests/UnitTests/Core/EventData/MultiTrajectoryTests.cpp +++ b/Tests/UnitTests/Core/EventData/MultiTrajectoryTests.cpp @@ -75,7 +75,7 @@ BOOST_AUTO_TEST_CASE(ConstCorrectness) { VectorMultiTrajectory t; auto i0 = t.addTrackState(); - BOOST_CHECK(!t.ReadOnly); + BOOST_CHECK(!IsReadOnlyMultiTrajectory::value); { VectorMultiTrajectory::TrackStateProxy tsp = t.getTrackState(i0);