Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MultiTrajectory.hpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file MultiTrajectory.hpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019-2020 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #pragma once
10 
18 #include "Acts/EventData/Types.hpp"
26 
27 #include <bitset>
28 #include <cstddef>
29 #include <cstdint>
30 #include <iterator>
31 #include <memory>
32 #include <optional>
33 #include <type_traits>
34 #include <vector>
35 
36 #include <Eigen/Core>
37 
38 namespace Acts {
39 
40 // forward declarations
41 template <typename derived_t>
43 class Surface;
44 
45 namespace detail_lt {
47 template <typename T, bool select>
48 using ConstIf = std::conditional_t<select, const T, T>;
49 
51 template <typename T>
53  public:
54  TransitiveConstPointer() = default;
56 
57  template <typename U>
58  TransitiveConstPointer(const TransitiveConstPointer<U>& other)
59  : m_ptr{other.ptr()} {}
60 
61  template <typename U>
62  TransitiveConstPointer& operator=(const TransitiveConstPointer<U>& other) {
63  m_ptr = other.m_ptr;
64  return *this;
65  }
66 
67  template <typename U>
68  bool operator==(const TransitiveConstPointer<U>& other) const {
69  return m_ptr == other.m_ptr;
70  }
71 
72  const T* operator->() const { return m_ptr; }
73 
74  T* operator->() { return m_ptr; }
75 
76  template <typename U>
77  friend class TransitiveConstPointer;
78 
79  const T& operator*() const { return *m_ptr; }
80 
81  T& operator*() { return *m_ptr; }
82 
83  private:
84  T* ptr() const { return m_ptr; }
85 
86  T* m_ptr;
87 };
88 
90 template <size_t Size, bool ReadOnlyMaps = true>
91 struct Types {
92  enum {
93  Flags = Eigen::ColMajor | Eigen::AutoAlign,
94  };
95 
96  using Scalar = ActsScalar;
97  // single items
98  using Coefficients = Eigen::Matrix<Scalar, Size, 1, Flags>;
99  using Covariance = Eigen::Matrix<Scalar, Size, Size, Flags>;
100  using CoefficientsMap = Eigen::Map<ConstIf<Coefficients, ReadOnlyMaps>>;
101  using CovarianceMap = Eigen::Map<ConstIf<Covariance, ReadOnlyMaps>>;
102 
103  using DynamicCoefficients = Eigen::Matrix<Scalar, Eigen::Dynamic, 1, Flags>;
104  using DynamicCovariance =
105  Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Flags>;
106  using DynamicCoefficientsMap =
107  Eigen::Map<ConstIf<DynamicCoefficients, ReadOnlyMaps>>;
108  using DynamicCovarianceMap =
109  Eigen::Map<ConstIf<DynamicCovariance, ReadOnlyMaps>>;
110 };
111 } // namespace detail_lt
112 
113 // This is public
114 template <size_t M, bool ReadOnly = true>
116  using Parameters =
118  using Covariance =
121  using MeasurementCovariance =
123 
124  constexpr static auto ProjectorFlags = Eigen::RowMajor | Eigen::AutoAlign;
125  using Projector =
126  Eigen::Matrix<typename Covariance::Scalar, M, eBoundSize, ProjectorFlags>;
127 };
128 
129 namespace detail_lt {
130 
136 template <typename trajectory_t, size_t M, bool ReadOnly = true>
138  public:
143 
144  template <size_t N>
146  template <size_t N>
147  using MeasurementCovariance =
149  template <size_t N>
151  template <size_t N>
154 
157 
158  // as opposed to the types above, this is an actual Matrix (rather than a
159  // map)
160  // @TODO: Does not copy flags, because this fails: can't have col major row
161  // vector, but that's required for 1xN projection matrices below.
163  using EffectiveProjector =
164  Eigen::Matrix<typename Projector::Scalar, Eigen::Dynamic, Eigen::Dynamic,
167 
168  using Trajectory = trajectory_t;
169 
170  // Constructor and assignment operator to construct ReadOnly TrackStateProxy
171  // from ReadWrite (mutable -> const)
173  : m_traj{other.m_traj}, m_istate{other.m_istate} {}
174 
177  m_traj = other.m_traj;
178  m_istate = other.m_istate;
179 
180  return *this;
181  }
182 
185  IndexType index() const { return m_istate; }
186 
189  IndexType previous() const {
190  return component<IndexType, hashString("previous")>();
191  }
192 
196  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
197  IndexType& previous() {
198  return component<IndexType, hashString("previous")>();
199  }
200 
203  bool hasPrevious() const {
204  return component<IndexType, hashString("previous")>() != kInvalid;
205  }
206 
210  TrackStatePropMask getMask() const;
211 
218  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
219  void shareFrom(TrackStatePropMask shareSource,
220  TrackStatePropMask shareTarget) {
221  shareFrom(*this, shareSource, shareTarget);
222  }
223 
231  template <bool RO = ReadOnly, bool ReadOnlyOther,
232  typename = std::enable_if_t<!RO>>
235  shareFrom(other, component, component);
236  }
237 
244  template <bool RO = ReadOnly, bool ReadOnlyOther,
245  typename = std::enable_if_t<!RO>>
247  TrackStatePropMask shareSource,
248  TrackStatePropMask shareTarget) {
249  assert(m_traj == other.m_traj &&
250  "Cannot share components across MultiTrajectories");
251 
252  assert(ACTS_CHECK_BIT(other.getMask(), shareSource) &&
253  "Source has incompatible allocation");
254 
255  m_traj->self().shareFrom(m_istate, other.m_istate, shareSource,
256  shareTarget);
257  }
258 
268  template <ACTS_CONCEPT(TrackStateProxyConcept) track_state_proxy_t,
269  bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
270  void copyFrom(const track_state_proxy_t& other,
272  bool onlyAllocated = true) {
273  using PM = TrackStatePropMask;
274 
275  // @TODO: How to support arbitrary columns here?
276 
277  if (onlyAllocated) {
278  auto dest = getMask();
279  auto src = other.getMask() &
280  mask; // combine what we have with what we want to copy
281 
282  if (ACTS_CHECK_BIT(src, PM::Calibrated)) {
283  // on-demand allocate calibrated
284  dest |= PM::Calibrated;
285  }
286 
287  if ((static_cast<std::underlying_type_t<TrackStatePropMask>>(
288  (src ^ dest) & src) != 0 ||
289  dest == TrackStatePropMask::None ||
290  src == TrackStatePropMask::None) &&
291  mask != TrackStatePropMask::None) {
292  throw std::runtime_error(
293  "Attempt track state copy with incompatible allocations");
294  }
295 
296  // we're sure now this has correct allocations, so just copy
297  if (ACTS_CHECK_BIT(src, PM::Predicted)) {
298  predicted() = other.predicted();
299  predictedCovariance() = other.predictedCovariance();
300  }
301 
302  if (ACTS_CHECK_BIT(src, PM::Filtered)) {
303  filtered() = other.filtered();
304  filteredCovariance() = other.filteredCovariance();
305  }
306 
307  if (ACTS_CHECK_BIT(src, PM::Smoothed)) {
308  smoothed() = other.smoothed();
309  smoothedCovariance() = other.smoothedCovariance();
310  }
311 
312  if (other.hasUncalibratedSourceLink()) {
313  setUncalibratedSourceLink(other.getUncalibratedSourceLink());
314  }
315 
316  if (ACTS_CHECK_BIT(src, PM::Jacobian)) {
317  jacobian() = other.jacobian();
318  }
319 
320  if (ACTS_CHECK_BIT(src, PM::Calibrated)) {
321  allocateCalibrated(other.calibratedSize());
322 
323  // workaround for gcc8 bug:
324  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86594
325  auto* self = this;
326  visit_measurement(other.calibratedSize(), [&](auto N) {
327  constexpr int measdim = decltype(N)::value;
328  self->template calibrated<measdim>() =
329  other.template calibrated<measdim>();
330  self->template calibratedCovariance<measdim>() =
331  other.template calibratedCovariance<measdim>();
332  });
333 
334  setProjectorBitset(other.projectorBitset());
335  }
336  } else {
337  if (ACTS_CHECK_BIT(mask, PM::Predicted) &&
338  has<hashString("predicted")>() &&
339  other.template has<hashString("predicted")>()) {
340  predicted() = other.predicted();
341  predictedCovariance() = other.predictedCovariance();
342  }
343 
344  if (ACTS_CHECK_BIT(mask, PM::Filtered) && has<hashString("filtered")>() &&
345  other.template has<hashString("filtered")>()) {
346  filtered() = other.filtered();
347  filteredCovariance() = other.filteredCovariance();
348  }
349 
350  if (ACTS_CHECK_BIT(mask, PM::Smoothed) && has<hashString("smoothed")>() &&
351  other.template has<hashString("smoothed")>()) {
352  smoothed() = other.smoothed();
353  smoothedCovariance() = other.smoothedCovariance();
354  }
355 
356  if (other.hasUncalibratedSourceLink()) {
357  setUncalibratedSourceLink(other.getUncalibratedSourceLink());
358  }
359 
360  if (ACTS_CHECK_BIT(mask, PM::Jacobian) && has<hashString("jacobian")>() &&
361  other.template has<hashString("jacobian")>()) {
362  jacobian() = other.jacobian();
363  }
364 
365  if (ACTS_CHECK_BIT(mask, PM::Calibrated) &&
366  has<hashString("calibrated")>() &&
367  other.template has<hashString("calibrated")>()) {
368  allocateCalibrated(other.calibratedSize());
369 
370  // workaround for gcc8 bug:
371  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86594
372  auto* self = this;
373  visit_measurement(other.calibratedSize(), [&](auto N) {
374  constexpr int measdim = decltype(N)::value;
375  self->template calibrated<measdim>() =
376  other.template calibrated<measdim>();
377  self->template calibratedCovariance<measdim>() =
378  other.template calibratedCovariance<measdim>();
379  });
380 
381  setProjectorBitset(other.projectorBitset());
382  }
383  }
384 
385  chi2() = other.chi2();
386  pathLength() = other.pathLength();
387  typeFlags() = other.typeFlags();
388 
389  if (other.hasReferenceSurface()) {
390  setReferenceSurface(other.referenceSurface().getSharedPtr());
391  }
392  }
393 
396  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
398  m_traj->self().unset(target, m_istate);
399  }
400 
403  const Surface& referenceSurface() const {
405  "TrackState does not have reference surface");
406  return *m_traj->referenceSurface(m_istate);
407  }
408 
411  bool hasReferenceSurface() const {
412  return m_traj->referenceSurface(m_istate) != nullptr;
413  }
414 
415  // NOLINTBEGIN(performance-unnecessary-value-param)
416  // looks like a false-positive. clang-tidy believes `srf` is not movable.
417 
421  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
422  void setReferenceSurface(std::shared_ptr<const Surface> srf) {
423  m_traj->setReferenceSurface(m_istate, std::move(srf));
424  }
425  // NOLINTEND(performance-unnecessary-value-param)
426 
430  template <HashedString key>
431  constexpr bool has() const {
432  return m_traj->template has<key>(m_istate);
433  }
434 
438  constexpr bool has(HashedString key) const {
439  return m_traj->has(key, m_istate);
440  }
441 
446  constexpr bool has(std::string_view key) const {
447  return has(hashString(key));
448  }
449 
454  template <typename T, HashedString key, bool RO = ReadOnly,
455  typename = std::enable_if_t<!RO>>
456  constexpr T& component() {
457  return m_traj->template component<T, key>(m_istate);
458  }
459 
464  template <typename T, bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
465  constexpr T& component(HashedString key) {
466  return m_traj->template component<T>(key, m_istate);
467  }
468 
474  template <typename T, bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
475  constexpr T& component(std::string_view key) {
476  return m_traj->template component<T>(hashString(key), m_istate);
477  }
478 
483  template <typename T, HashedString key>
484  constexpr const T& component() const {
485  return m_traj->template component<T, key>(m_istate);
486  }
487 
492  template <typename T>
493  constexpr const T& component(HashedString key) const {
494  return m_traj->template component<T>(key, m_istate);
495  }
496 
502  template <typename T>
503  constexpr const T& component(std::string_view key) const {
504  return m_traj->template component<T>(hashString(key), m_istate);
505  }
506 
511  ConstParameters parameters() const;
512 
518  ConstCovariance covariance() const;
519 
523  assert(has<hashString("predicted")>());
524  return m_traj->self().parameters(
525  component<IndexType, hashString("predicted")>());
526  }
527 
528  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
530  assert(has<hashString("predicted")>());
531  return m_traj->self().parameters(
532  component<IndexType, hashString("predicted")>());
533  }
534 
538  assert(has<hashString("predicted")>());
539  return m_traj->self().covariance(
540  component<IndexType, hashString("predicted")>());
541  }
542 
543  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
545  assert(has<hashString("predicted")>());
546  return m_traj->self().covariance(
547  component<IndexType, hashString("predicted")>());
548  }
549 
552  bool hasPredicted() const { return has<hashString("predicted")>(); }
553 
558  assert(has<hashString("filtered")>());
559  return m_traj->self().parameters(
560  component<IndexType, hashString("filtered")>());
561  }
562 
566  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
568  assert(has<hashString("filtered")>());
569  return m_traj->self().parameters(
570  component<IndexType, hashString("filtered")>());
571  }
572 
577  assert(has<hashString("filtered")>());
578  return m_traj->self().covariance(
579  component<IndexType, hashString("filtered")>());
580  }
581 
585  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
587  assert(has<hashString("filtered")>());
588  return m_traj->self().covariance(
589  component<IndexType, hashString("filtered")>());
590  }
591 
594  bool hasFiltered() const { return has<hashString("filtered")>(); }
595 
600  assert(has<hashString("smoothed")>());
601  return m_traj->self().parameters(
602  component<IndexType, hashString("smoothed")>());
603  }
604 
608  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
610  assert(has<hashString("smoothed")>());
611  return m_traj->self().parameters(
612  component<IndexType, hashString("smoothed")>());
613  }
614 
619  assert(has<hashString("smoothed")>());
620  return m_traj->self().covariance(
621  component<IndexType, hashString("smoothed")>());
622  }
623 
627  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
629  assert(has<hashString("smoothed")>());
630  return m_traj->self().covariance(
631  component<IndexType, hashString("smoothed")>());
632  }
633 
636  bool hasSmoothed() const { return has<hashString("smoothed")>(); }
637 
642  assert(has<hashString("jacobian")>());
643  return m_traj->self().jacobian(m_istate);
644  }
645 
649  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
651  assert(has<hashString("jacobian")>());
652  return m_traj->self().jacobian(m_istate);
653  }
654 
657  bool hasJacobian() const { return has<hashString("jacobian")>(); }
658 
666  Projector projector() const;
667 
670  bool hasProjector() const { return has<hashString("projector")>(); }
671 
679  return projector().topLeftCorner(calibratedSize(), M);
680  }
681 
687  template <typename Derived, bool RO = ReadOnly,
688  typename = std::enable_if_t<!RO>>
689  void setProjector(const Eigen::MatrixBase<Derived>& projector) {
690  constexpr int rows = Eigen::MatrixBase<Derived>::RowsAtCompileTime;
691  constexpr int cols = Eigen::MatrixBase<Derived>::ColsAtCompileTime;
692 
693  static_assert(rows != -1 && cols != -1,
694  "Assignment of dynamic matrices is currently not supported.");
695 
696  assert(has<hashString("projector")>());
697 
698  static_assert(rows <= M, "Given projector has too many rows");
699  static_assert(cols <= eBoundSize, "Given projector has too many columns");
700 
701  // set up full size projector with only zeros
702  typename TrackStateProxy::Projector fullProjector =
703  decltype(fullProjector)::Zero();
704 
705  // assign (potentially) smaller actual projector to matrix, preserving
706  // zeroes outside of smaller matrix block.
707  fullProjector.template topLeftCorner<rows, cols>() = projector;
708 
709  // convert to bitset before storing
710  auto projectorBitset = matrixToBitset(fullProjector);
711  component<ProjectorBitset, hashString("projector")>() =
712  projectorBitset.to_ullong();
713  }
714 
721  assert(has<hashString("projector")>());
722  return component<ProjectorBitset, hashString("projector")>();
723  }
724 
730  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
732  assert(has<hashString("projector")>());
733  component<ProjectorBitset, hashString("projector")>() = proj;
734  }
735 
739 
742  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
744  m_traj->setUncalibratedSourceLink(m_istate, std::move(sourceLink));
745  }
746 
750  return has<hashString("uncalibratedSourceLink")>();
751  }
752 
755  bool hasCalibrated() const { return has<hashString("calibrated")>(); }
756 
761  template <size_t measdim>
763  assert(has<hashString("calibrated")>());
764  return m_traj->self().template measurement<measdim>(m_istate);
765  }
766 
771  template <size_t measdim, bool RO = ReadOnly,
772  typename = std::enable_if_t<!RO>>
774  assert(has<hashString("calibrated")>());
775  return m_traj->self().template measurement<measdim>(m_istate);
776  }
777 
782  template <size_t measdim>
784  assert(has<hashString("calibratedCov")>());
785  return m_traj->self().template measurementCovariance<measdim>(m_istate);
786  }
787 
792  template <size_t measdim, bool RO = ReadOnly,
793  typename = std::enable_if_t<!RO>>
795  assert(has<hashString("calibratedCov")>());
796  return m_traj->self().template measurementCovariance<measdim>(m_istate);
797  }
798 
802  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
804  // repackage the data pointer to a dynamic map type
805  // workaround for gcc8 bug:
806  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86594
807  auto* self = this;
808  return visit_measurement(calibratedSize(), [&](auto N) {
809  constexpr int kMeasurementSize = decltype(N)::value;
811  self->template calibrated<kMeasurementSize>().data(),
812  kMeasurementSize};
813  });
814  }
815 
819  auto effectiveCalibrated() const {
820  // repackage the data pointer to a dynamic map type
821  // workaround for gcc8 bug:
822  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86594
823  auto* self = this;
824  return visit_measurement(calibratedSize(), [&](auto N) {
825  constexpr int kMeasurementSize = decltype(N)::value;
827  self->template calibrated<kMeasurementSize>().data(),
828  kMeasurementSize};
829  });
830  }
831 
835  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
837  // repackage the data pointer to a dynamic map type
838  // workaround for gcc8 bug:
839  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86594
840  auto* self = this;
841  return visit_measurement(calibratedSize(), [&](auto N) {
842  constexpr int kMeasurementSize = decltype(N)::value;
844  self->template calibratedCovariance<kMeasurementSize>().data(),
845  kMeasurementSize, kMeasurementSize};
846  });
847  }
848 
853  // repackage the data pointer to a dynamic map type
854  // workaround for gcc8 bug:
855  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86594
856  auto* self = this;
857  return visit_measurement(calibratedSize(), [&](auto N) {
858  constexpr int kMeasurementSize = decltype(N)::value;
859  return typename Types<M, true>::DynamicCovarianceMap{
860  self->template calibratedCovariance<kMeasurementSize>().data(),
861  kMeasurementSize, kMeasurementSize};
862  });
863  }
864 
869  IndexType calibratedSize() const { return m_traj->calibratedSize(m_istate); }
870 
881  template <size_t kMeasurementSize, bool RO = ReadOnly,
882  typename = std::enable_if_t<!RO>>
885  static_assert(kMeasurementSize <= M,
886  "Input measurement must be within the allowed size");
887 
888  allocateCalibrated(kMeasurementSize);
890 
891  calibrated<kMeasurementSize>().setZero();
892  calibrated<kMeasurementSize>().template head<kMeasurementSize>() =
893  meas.parameters();
894  calibratedCovariance<kMeasurementSize>().setZero();
895  calibratedCovariance<kMeasurementSize>()
896  .template topLeftCorner<kMeasurementSize, kMeasurementSize>() =
897  meas.covariance();
898  setProjector(meas.projector());
899  }
900 
901  void allocateCalibrated(size_t measdim) {
902  m_traj->allocateCalibrated(m_istate, measdim);
903  }
904 
910  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
911  double& chi2() {
912  return component<double, hashString("chi2")>();
913  }
914 
919  double chi2() const { return component<double, hashString("chi2")>(); }
920 
925  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
926  double& pathLength() {
927  return component<double, hashString("pathLength")>();
928  }
929 
932  double pathLength() const {
933  return component<double, hashString("pathLength")>();
934  }
935 
940  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
942  return TrackStateType{
944  }
945 
949  return ConstTrackStateType{
951  }
952 
953  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
955  return *m_traj;
956  }
957 
958  const MultiTrajectory<Trajectory>& trajectory() const { return *m_traj; }
959 
960  private:
961  // Private since it can only be created by the trajectory.
963  IndexType istate);
964 
967 
969  friend class TrackStateProxy<Trajectory, M, true>;
970  friend class TrackStateProxy<Trajectory, M, false>;
971 };
972 
974 template <bool reverse, typename trajectory_t, size_t M, bool ReadOnly>
977  using IndexType = typename ProxyType::IndexType;
979 
980  public:
983  struct Iterator {
984  std::optional<ProxyType> proxy;
985 
986  using iterator_category = std::forward_iterator_tag;
988  using difference_type = std::ptrdiff_t;
989  using pointer = void;
990  using reference = void;
991 
993  if (!proxy) {
994  return *this;
995  }
996  if constexpr (reverse) {
997  if (proxy->hasPrevious()) {
998  proxy = proxy->trajectory().getTrackState(proxy->previous());
999  return *this;
1000  } else {
1001  proxy = std::nullopt;
1002  return *this;
1003  }
1004  } else {
1005  IndexType next =
1006  proxy->template component<IndexType, hashString("next")>();
1007  if (next != kInvalid) {
1008  proxy = proxy->trajectory().getTrackState(next);
1009  return *this;
1010  } else {
1011  proxy = std::nullopt;
1012  return *this;
1013  }
1014  }
1015  }
1016 
1017  bool operator==(const Iterator& other) const {
1018  if (!proxy && !other.proxy) {
1019  return true;
1020  }
1021  if (proxy && other.proxy) {
1022  return proxy->index() == other.proxy->index();
1023  }
1024  return false;
1025  }
1026 
1027  bool operator!=(const Iterator& other) const { return !(*this == other); }
1028 
1029  ProxyType operator*() const { return *proxy; }
1030  ProxyType operator*() { return *proxy; }
1031  };
1032 
1033  TrackStateRange(ProxyType _begin) : m_begin{_begin} {}
1034  TrackStateRange() : m_begin{std::nullopt} {}
1035 
1036  Iterator begin() { return m_begin; }
1037  Iterator end() { return Iterator{std::nullopt}; }
1038 
1039  private:
1040  Iterator m_begin;
1041 };
1042 
1043 // implement track state visitor concept
1044 template <typename T, typename TS>
1045 using call_operator_t = decltype(std::declval<T>()(std::declval<TS>()));
1046 
1047 template <typename T, typename TS>
1049  Concepts ::either<Concepts ::identical_to<bool, call_operator_t, T, TS>,
1050  Concepts ::identical_to<void, call_operator_t, T, TS>>>;
1051 
1052 } // namespace detail_lt
1053 
1057 namespace MultiTrajectoryTraits {
1058 constexpr unsigned int MeasurementSizeMax = eBoundSize;
1061 } // namespace MultiTrajectoryTraits
1062 
1063 template <typename T>
1065 
1074 template <typename derived_t>
1076  public:
1077  using Derived = derived_t;
1078 
1079  static constexpr bool ReadOnly = IsReadOnlyMultiTrajectory<Derived>::value;
1080 
1081  // Pull out type alias and re-expose them for ease of use.
1082  //
1083  static constexpr unsigned int MeasurementSizeMax =
1085 
1086  using ConstTrackStateProxy =
1088  using TrackStateProxy =
1090 
1093 
1094  protected:
1095  MultiTrajectory() = default; // pseudo abstract base class
1096 
1097  private:
1099  constexpr Derived& self() { return static_cast<Derived&>(*this); }
1101  constexpr const Derived& self() const {
1102  return static_cast<const Derived&>(*this);
1103  }
1104 
1107  constexpr bool checkOptional(HashedString key, IndexType istate) const {
1108  using namespace Acts::HashedStringLiteral;
1109  switch (key) {
1110  case "predicted"_hash:
1111  case "filtered"_hash:
1112  case "smoothed"_hash:
1113  case "calibrated"_hash:
1114  case "jacobian"_hash:
1115  case "projector"_hash:
1116  return self().has_impl(key, istate);
1117  default:
1118  return true;
1119  }
1120  }
1121 
1122  public:
1127  return {*this, istate};
1128  }
1129 
1133  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
1135  return {*this, istate};
1136  }
1137 
1142  template <typename F>
1143  void visitBackwards(IndexType iendpoint, F&& callable) const;
1144 
1149  auto reverseTrackStateRange(IndexType iendpoint) const {
1150  using range_t =
1152  if (iendpoint == kInvalid) {
1153  return range_t{};
1154  }
1155 
1156  return range_t{getTrackState(iendpoint)};
1157  }
1158 
1164  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
1166  using range_t =
1168  if (iendpoint == kInvalid) {
1169  return range_t{};
1170  }
1171 
1172  return range_t{getTrackState(iendpoint)};
1173  }
1174 
1181  auto forwardTrackStateRange(IndexType istartpoint) const {
1182  using range_t =
1184  if (istartpoint == kInvalid) {
1185  return range_t{};
1186  }
1187 
1188  return range_t{getTrackState(istartpoint)};
1189  }
1190 
1196  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
1197  auto forwardTrackStateRange(IndexType istartpoint) {
1198  using range_t =
1200  if (istartpoint == kInvalid) {
1201  return range_t{};
1202  }
1203 
1204  return range_t{getTrackState(istartpoint)};
1205  }
1206 
1214  template <typename F, bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
1215  void applyBackwards(IndexType iendpoint, F&& callable) {
1216  static_assert(detail_lt::VisitorConcept<F, TrackStateProxy>,
1217  "Callable needs to satisfy VisitorConcept");
1218 
1219  if (iendpoint == MultiTrajectoryTraits::kInvalid) {
1220  throw std::runtime_error(
1221  "Cannot apply backwards with kInvalid as endpoint");
1222  }
1223 
1224  while (true) {
1225  auto ts = getTrackState(iendpoint);
1226  if constexpr (std::is_same_v<std::invoke_result_t<F, TrackStateProxy>,
1227  bool>) {
1228  bool proceed = callable(ts);
1229  // this point has no parent and ends the trajectory, or a break was
1230  // requested
1231  if (!proceed || !ts.hasPrevious()) {
1232  break;
1233  }
1234  } else {
1235  callable(ts);
1236  // this point has no parent and ends the trajectory
1237  if (!ts.hasPrevious()) {
1238  break;
1239  }
1240  }
1241  iendpoint = ts.previous();
1242  }
1243  }
1244 
1245  auto&& convertToReadOnly() const {
1246  auto&& cv = self().convertToReadOnly_impl();
1247  static_assert(
1248  IsReadOnlyMultiTrajectory<decltype(cv)>::value,
1249  "convertToReadOnly_impl does not return something that reports "
1250  "being ReadOnly.");
1251  return cv;
1252  }
1253 
1255  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
1256  constexpr void clear() {
1257  self().clear_impl();
1258  }
1259 
1261  constexpr IndexType size() const { return self().size_impl(); }
1262 
1269  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
1270  constexpr IndexType addTrackState(
1271  TrackStatePropMask mask = TrackStatePropMask::All,
1272  IndexType iprevious = kInvalid) {
1273  return self().addTrackState_impl(mask, iprevious);
1274  }
1275 
1280  template <typename T, bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
1281  constexpr void addColumn(const std::string& key) {
1282  self().template addColumn_impl<T>(key);
1283  }
1284 
1288  constexpr bool hasColumn(HashedString key) const {
1289  return self().hasColumn_impl(key);
1290  }
1291 
1292  protected:
1293  // These are internal helper functions which the @c TrackStateProxy class talks to
1294 
1299  constexpr bool has(HashedString key, IndexType istate) const {
1300  return self().has_impl(key, istate);
1301  }
1302 
1307  template <HashedString key>
1308  constexpr bool has(IndexType istate) const {
1309  return self().has_impl(key, istate);
1310  }
1311 
1315  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
1316  constexpr typename TrackStateProxy::Parameters parameters(IndexType parIdx) {
1317  return self().parameters_impl(parIdx);
1318  }
1319 
1324  IndexType parIdx) const {
1325  return self().parameters_impl(parIdx);
1326  }
1327 
1331  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
1332  constexpr typename TrackStateProxy::Covariance covariance(IndexType covIdx) {
1333  return self().covariance_impl(covIdx);
1334  }
1335 
1340  IndexType covIdx) const {
1341  return self().covariance_impl(covIdx);
1342  }
1343 
1347  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
1348  constexpr typename TrackStateProxy::Covariance jacobian(IndexType jacIdx) {
1349  return self().jacobian_impl(jacIdx);
1350  }
1351 
1356  IndexType jacIdx) const {
1357  return self().jacobian_impl(jacIdx);
1358  }
1359 
1364  template <size_t measdim, bool RO = ReadOnly,
1365  typename = std::enable_if_t<!RO>>
1366  constexpr typename TrackStateProxy::template Measurement<measdim> measurement(
1367  IndexType measIdx) {
1368  return self().template measurement_impl<measdim>(measIdx);
1369  }
1370 
1375  template <size_t measdim>
1376  constexpr typename ConstTrackStateProxy::template Measurement<measdim>
1377  measurement(IndexType measIdx) const {
1378  return self().template measurement_impl<measdim>(measIdx);
1379  }
1380 
1386  template <size_t measdim, bool RO = ReadOnly,
1387  typename = std::enable_if_t<!RO>>
1388  constexpr typename TrackStateProxy::template MeasurementCovariance<measdim>
1390  return self().template measurementCovariance_impl<measdim>(covIdx);
1391  }
1392 
1397  template <size_t measdim>
1398  constexpr
1399  typename ConstTrackStateProxy::template MeasurementCovariance<measdim>
1401  return self().template measurementCovariance_impl<measdim>(covIdx);
1402  }
1403 
1408  return self().calibratedSize_impl(istate);
1409  }
1410 
1421  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
1422  constexpr void shareFrom(IndexType iself, IndexType iother,
1423  TrackStatePropMask shareSource,
1424  TrackStatePropMask shareTarget) {
1425  self().shareFrom_impl(iself, iother, shareSource, shareTarget);
1426  }
1427 
1431  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
1432  constexpr void unset(TrackStatePropMask target, IndexType istate) {
1433  self().unset_impl(target, istate);
1434  }
1435 
1441  template <typename T, HashedString key, bool RO = ReadOnly,
1442  typename = std::enable_if_t<!RO>>
1443  constexpr T& component(IndexType istate) {
1444  assert(checkOptional(key, istate));
1445  return *std::any_cast<T*>(self().component_impl(key, istate));
1446  }
1447 
1453  template <typename T, bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
1454  constexpr T& component(HashedString key, IndexType istate) {
1455  assert(checkOptional(key, istate));
1456  return *std::any_cast<T*>(self().component_impl(key, istate));
1457  }
1458 
1464  template <typename T, HashedString key>
1465  constexpr const T& component(IndexType istate) const {
1466  assert(checkOptional(key, istate));
1467  return *std::any_cast<const T*>(self().component_impl(key, istate));
1468  }
1469 
1475  template <typename T>
1476  constexpr const T& component(HashedString key, IndexType istate) const {
1477  assert(checkOptional(key, istate));
1478  return *std::any_cast<const T*>(self().component_impl(key, istate));
1479  }
1480 
1486  void allocateCalibrated(IndexType istate, size_t measdim) {
1487  throw_assert(measdim > 0 && measdim <= eBoundSize,
1488  "Invalid measurement dimension detected");
1489 
1490  self().allocateCalibrated_impl(istate, measdim);
1491  }
1492 
1493  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
1495  self().setUncalibratedSourceLink_impl(istate, std::move(sourceLink));
1496  }
1497 
1499  return self().getUncalibratedSourceLink_impl(istate);
1500  }
1501 
1502  const Surface* referenceSurface(IndexType istate) const {
1503  return self().referenceSurface_impl(istate);
1504  }
1505 
1506  template <bool RO = ReadOnly, typename = std::enable_if_t<!RO>>
1508  std::shared_ptr<const Surface> surface) {
1509  self().setReferenceSurface_impl(istate, std::move(surface));
1510  }
1511 
1512  private:
1515 };
1516 
1517 } // namespace Acts
1518