ATLAS Offline Software
TrackFindingData.h
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 #ifndef ACTSTRACKRECONSTRUCTION_TRACKFINDINGDATA_H
5 #define ACTSTRACKRECONSTRUCTION_TRACKFINDINGDATA_H 1
6 
7 #include "src/TrackFindingAlg.h"
8 
9 // ACTS
10 #include "Acts/EventData/VectorTrackContainer.hpp"
11 #include "Acts/EventData/TrackContainer.hpp"
12 #include "Acts/EventData/TrackProxy.hpp"
13 #include "Acts/Definitions/Common.hpp"
14 #include "Acts/Definitions/Algebra.hpp"
15 #include "Acts/Propagator/EigenStepper.hpp"
16 #include "Acts/Propagator/Navigator.hpp"
17 #include "Acts/Propagator/Propagator.hpp"
18 #include "Acts/TrackFitting/GainMatrixSmoother.hpp"
19 #include "Acts/TrackFitting/GainMatrixUpdater.hpp"
20 #include "Acts/TrackFinding/MeasurementSelector.hpp"
21 #include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp"
22 #include "Acts/TrackFinding/TrackSelector.hpp"
23 #include "Acts/Surfaces/Surface.hpp"
24 
25 // Athena
31 
32 // ActsTrk
36 #include "src/TrackStatePrinter.h"
37 
38 // STL
39 #include <unordered_map>
40 #include <utility>
41 #include <vector>
42 #include <variant>
43 
45 
46 namespace
47 {
52 
53  // container used during the reconstruction
54  using RecoTrackStateContainer = ActsTrk::TrackFindingAlg::RecoTrackStateContainer;
55 
56 
58 
59  using Stepper = Acts::EigenStepper<>;
60  using Navigator = Acts::Navigator;
61  using Propagator = Acts::Propagator<Stepper, Navigator>;
62  using CKF = Acts::CombinatorialKalmanFilter<Propagator, RecoTrackStateContainer>;
63  using Extrapolator = Propagator;
64 
65  // Small holder class to keep CKF and related objects.
66  // Keep a unique_ptr<CKF_pimpl> in TrackFindingAlg, so we don't have to expose the
67  // Acts class definitions in TrackFindingAlg.h.
68  // ActsTrk::TrackFindingAlg::CKF_pimpl inherits from CKF_config to prevent -Wsubobject-linkage warning.
69  struct CKF_config
70  {
71  // Extrapolator
72  Extrapolator extrapolator;
73  // CKF algorithm
74  CKF ckf;
75  // CKF configuration
76  Acts::MeasurementSelector measurementSelector;
77  Acts::PropagatorPlainOptions pOptions;
78  Acts::PropagatorPlainOptions pSecondOptions;
79  Acts::CombinatorialKalmanFilterExtensions<RecoTrackStateContainer> ckfExtensions;
80  // Track selection
81  Acts::TrackSelector trackSelector;
82  };
83 
84  // === DuplicateSeedDetector ===============================================
85 
86  // Identify duplicate seeds: seeds where all measurements were already located in a previously followed trajectory.
87  class DuplicateSeedDetector
88  {
89  public:
90  DuplicateSeedDetector(size_t numSeeds, bool enabled)
91  : m_disabled(!enabled),
92  m_nUsedMeasurements(enabled ? numSeeds : 0u, 0u),
93  m_nSeedMeasurements(enabled ? numSeeds : 0u, 0u),
94  m_isDuplicateSeed(enabled ? numSeeds : 0u, false)
95  {
96  if (m_disabled)
97  return;
98  m_seedIndex.reserve(6 * numSeeds); // 6 hits/seed for strips (3 for pixels)
99  m_seedOffset.reserve(2);
100  }
101 
102  DuplicateSeedDetector() = delete;
103  DuplicateSeedDetector(const DuplicateSeedDetector &) = delete;
104  DuplicateSeedDetector &operator=(const DuplicateSeedDetector &) = delete;
105 
106  // add seeds from an associated measurements collection.
107  // measurementOffset non-zero is only needed if measurements holds more than one collection (eg. kept for TrackStatePrinter).
108  void addSeeds(size_t typeIndex, const ActsTrk::SeedContainer &seeds)
109  {
110  if (m_disabled)
111  return;
112  if (!(typeIndex < m_seedOffset.size()))
113  m_seedOffset.resize(typeIndex + 1);
114  m_seedOffset[typeIndex] = m_numSeed;
115 
116  for (const auto *seed : seeds)
117  {
118  if (!seed)
119  continue;
120  for (const auto *sp : seed->sp())
121  {
122  const auto &els = sp->measurements();
123  for (const xAOD::UncalibratedMeasurement *meas : els)
124  {
125  m_seedIndex.insert({meas, m_numSeed});
126  ++m_nSeedMeasurements[m_numSeed];
127  }
128  }
129  ++m_numSeed;
130  }
131  }
132 
133  void newTrajectory()
134  {
135  if (m_disabled || m_found == 0 || m_nextSeed == m_nUsedMeasurements.size())
136  return;
137  auto beg = m_nUsedMeasurements.begin();
138  if (m_nextSeed < m_nUsedMeasurements.size())
139  std::advance(beg, m_nextSeed);
140  std::fill(beg, m_nUsedMeasurements.end(), 0u);
141  }
142 
143  void addMeasurement(const ActsTrk::ATLASUncalibSourceLink &sl)
144  {
145  if (m_disabled || m_nextSeed == m_nUsedMeasurements.size())
146  return;
147  for (auto [iiseed, eiseed] = m_seedIndex.equal_range(&(ActsTrk::getUncalibratedMeasurement(sl))); iiseed != eiseed; ++iiseed)
148  {
149  size_t iseed = iiseed->second;
150  assert(iseed < m_nUsedMeasurements.size());
151  if (iseed < m_nextSeed || m_isDuplicateSeed[iseed])
152  continue;
153  if (++m_nUsedMeasurements[iseed] >= m_nSeedMeasurements[iseed])
154  {
155  assert(m_nUsedMeasurements[iseed] == m_nSeedMeasurements[iseed]); // shouldn't ever find more
156  m_isDuplicateSeed[iseed] = true;
157  }
158  ++m_found;
159  }
160  }
161 
162  // For complete removal of duplicate seeds, assumes isDuplicate(iseed) is called for monotonically increasing iseed.
163  bool isDuplicate(size_t typeIndex, size_t iseed)
164  {
165  if (m_disabled)
166  return false;
167  if (typeIndex < m_seedOffset.size())
168  iseed += m_seedOffset[typeIndex];
169  assert(iseed < m_isDuplicateSeed.size());
170  // If iseed not increasing, we will miss some duplicate seeds, but won't exclude needed seeds.
171  if (iseed >= m_nextSeed)
172  m_nextSeed = iseed + 1;
173  return m_isDuplicateSeed[iseed];
174  }
175 
176  private:
177  bool m_disabled = false;
178  std::unordered_multimap<const xAOD::UncalibratedMeasurement *, size_t> m_seedIndex;
179  std::vector<size_t> m_nUsedMeasurements;
180  std::vector<size_t> m_nSeedMeasurements;
181  std::vector<bool> m_isDuplicateSeed;
182  std::vector<size_t> m_seedOffset;
183  size_t m_numSeed = 0u; // count of number of seeds so-far added with addSeeds()
184  size_t m_nextSeed = 0u; // index of next seed expected with isDuplicate()
185  size_t m_found = 0u; // count of found seeds for this/last trajectory
186  };
187 
188  // === TrackFindingMeasurements ============================================
189 
190  // Helper class to convert xAOD::PixelClusterContainer or xAOD::StripClusterContainer to UncalibSourceLinkMultiset.
191  class TrackFindingMeasurements {
192  public:
193  TrackFindingMeasurements(std::size_t measTotal) {
194  m_orderedGeoIds.reserve(measTotal);
195  m_measurementOffsets.reserve(2); // pixels+strips
196  }
197 
198  TrackFindingMeasurements() = delete;
199  TrackFindingMeasurements(const TrackFindingMeasurements &) = delete;
200  TrackFindingMeasurements &operator=(const TrackFindingMeasurements &) = delete;
201 
202  void addDetectorElements(xAOD::UncalibMeasType measType,
203  const InDetDD::SiDetectorElementCollection &detElems,
204  const ToolHandle<ActsTrk::IActsToTrkConverterTool> &ATLASConverterTool) {
205  assert (m_sorted == false); // should not call this again after addMeasurements()
206 
207  if (!(static_cast<std::size_t>(measType) < TrackingSurfaceHelper::s_NMeasTypes)) {
208  std::stringstream msg;
209  msg << "Measurements of type " << static_cast<std::size_t>(measType) << " larger than " << TrackingSurfaceHelper::s_NMeasTypes - 1;
210  throw std::runtime_error(msg.str());
211  }
212 
213  if (measType != xAOD::UncalibMeasType::Other) {
214  m_trackingSurfaceHelper.setSiDetectorElements(measType, &detElems);
215  }
216 
217  auto &actsSurfaces = m_trackingSurfaceHelper.actsSurfaces(measType);
218  actsSurfaces.reserve(actsSurfaces.size() + detElems.size()); // may extend previous data, but usually starts from empty
219  for (const auto *det_el : detElems)
220  {
221  const Acts::Surface &surface = ATLASConverterTool->trkSurfaceToActsSurface(det_el->surface());
222  m_orderedGeoIds.push_back(surface.geometryId());
223  actsSurfaces.push_back(&surface);
224  }
225  m_sorted = false;
226  }
227 
228  // NB. all addDetectorElements() must have been done before calling first addMeasurements().
229  void addMeasurements(size_t typeIndex,
230  const xAOD::UncalibratedMeasurementContainer &clusterContainer,
231  const InDetDD::SiDetectorElementCollection &detElems,
232  const ToolHandle<ActsTrk::IActsToTrkConverterTool> &ATLASConverterTool) {
233  if (!m_sorted) {
234  std::sort(m_orderedGeoIds.begin(), m_orderedGeoIds.end());
235  m_sorted = true;
236  m_measurementRanges.resize(m_orderedGeoIds.size());
237  }
238 
239  // m_measurementOffsets only needed for TrackStatePrinter, but it is trivial overhead to save it for each event
240  if (!(typeIndex < m_measurementOffsets.size()))
241  m_measurementOffsets.resize(typeIndex + 1);
242  m_measurementOffsets[typeIndex] = m_measurementsTotal;
243 
244  m_measurementRanges.setContainer(typeIndex, &clusterContainer);
245 
246  xAOD::UncalibMeasType last_measurement_type = xAOD::UncalibMeasType::Other;
248  unsigned int range_idx = m_measurementRanges.size();
249  std::size_t sl_idx = 0;
250  for (auto *measurement : clusterContainer)
251  {
252  const InDetDD::SiDetectorElement *elem =
253  detElems.getDetectorElement(measurement->identifierHash());
254  if (!elem)
255  {
256  throw std::domain_error("No detector element for measurement");
257  }
258 
259  if (measurement->identifierHash() != last_id_hash || measurement->type() != last_measurement_type)
260  {
261  const Acts::Surface &surface = ATLASConverterTool->trkSurfaceToActsSurface(elem->surface());
262  std::vector<Acts::GeometryIdentifier>::const_iterator
263  geo_iter = std::lower_bound(m_orderedGeoIds.begin(), m_orderedGeoIds.end(), surface.geometryId());
264  if (geo_iter == m_orderedGeoIds.end() || *geo_iter != surface.geometryId())
265  {
266  std::stringstream msg;
267  msg << "Measurement with unexpected Acts geometryId: " << surface.geometryId()
268  << " type = " << static_cast<unsigned int>(measurement->type())
269  << " idHash=" << measurement->identifierHash();
270  throw std::runtime_error(msg.str());
271  }
272  range_idx = geo_iter - m_orderedGeoIds.begin();
273  if (m_measurementRanges[range_idx].first != std::numeric_limits<unsigned int>::max())
274  {
275  std::stringstream msg;
276  msg << "Measurement not clustered by identifierHash / geometryId. New measurement "
277  << sl_idx << " with geo Id " << surface.geometryId()
278  << " type = " << static_cast<unsigned int>(measurement->type())
279  << " idHash=" << measurement->identifierHash()
280  << " but already recorded for this geo ID the range : " << m_measurementRanges[range_idx].first
281  << " .. " << m_measurementRanges[range_idx].second;
282  throw std::runtime_error(msg.str());
283  }
284  m_measurementRanges[range_idx].setRangeBegin(typeIndex, sl_idx);
285  last_id_hash = measurement->identifierHash();
286  last_measurement_type = measurement->type();
287  }
288  m_measurementRanges[range_idx].setRangeEnd(typeIndex, sl_idx + 1);
289  ++sl_idx;
290  }
291  m_measurementsTotal += clusterContainer.size();
292  }
293 
294  std::vector<std::pair<const xAOD::UncalibratedMeasurementContainer *, size_t>> measurementContainerOffsets() const
295  {
296  std::vector<std::pair<const xAOD::UncalibratedMeasurementContainer *, size_t>> offsets;
297  if (m_measurementRanges.numContainers() == 0) return offsets;
298  offsets.reserve(m_measurementRanges.numContainers() - 1); // first one usually 0
299  for (std::size_t typeIndex = 0; typeIndex < m_measurementRanges.numContainers(); ++typeIndex)
300  {
301  const xAOD::UncalibratedMeasurementContainer *the_container
302  = std::visit( [] (const auto &a) -> const xAOD::UncalibratedMeasurementContainer * { return a.containerPtr();} ,
303  m_measurementRanges.container(typeIndex));
304  if (measurementOffset(typeIndex) > 0 && the_container != nullptr)
305  {
306  offsets.emplace_back(the_container, measurementOffset(typeIndex));
307  }
308  }
309  return offsets;
310  }
311 
312  size_t measurementOffset(size_t typeIndex) const { return typeIndex < m_measurementOffsets.size() ? m_measurementOffsets[typeIndex] : 0u; }
313  const std::vector<size_t>& measurementOffsets() const { return m_measurementOffsets; }
314  const std::vector<Acts::GeometryIdentifier> &orderedGeoIds() const { return m_orderedGeoIds; }
315  const ActsTrk::MeasurementRangeList &measurementRanges() const { return m_measurementRanges; }
316  const TrackingSurfaceHelper &trackingSurfaceHelper() const { return m_trackingSurfaceHelper; }
317 
318  private:
319 
320  std::vector<size_t> m_measurementOffsets;
321  std::vector<Acts::GeometryIdentifier> m_orderedGeoIds;
322  TrackingSurfaceHelper m_trackingSurfaceHelper;
323  ActsTrk::MeasurementRangeList m_measurementRanges;
324  std::size_t m_measurementsTotal = 0;
325  bool m_sorted = false;
326  };
327 
328 } // anonymous namespace
329 
330 #endif
TrackingSurfaceHelper
Simple helper class which allows to access the tracking surface associated to a certain (Si-)measurem...
Definition: TrackingSurfaceHelper.h:17
UncalibratedMeasurement.h
max
#define max(a, b)
Definition: cfImp.cxx:41
InDetDD::SiDetectorElementCollection
Definition: SiDetectorElementCollection.h:30
AtlasUncalibSourceLinkAccessor.h
InDetDD::SolidStateDetectorElementBase::surface
Trk::Surface & surface()
Element Surface.
TrackingSurfaceHelper.h
TrackStatePrinter.h
Trk::u
@ u
Enums for curvilinear frames.
Definition: ParamDefs.h:83
xAOD::UncalibratedMeasurement_v1
Definition: UncalibratedMeasurement_v1.h:13
Generate_dsid_ranseed.seed
seed
Definition: Generate_dsid_ranseed.py:10
TrackingSurfaceHelper::s_NMeasTypes
static constexpr unsigned int s_NMeasTypes
Definition: TrackingSurfaceHelper.h:19
PixelClusterContainer.h
xAOD::Other
@ Other
ActsTrk::GenMeasurementRangeList
Definition: AtlasUncalibSourceLinkAccessor.h:64
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
WriteBchToCool.beg
beg
Definition: WriteBchToCool.py:69
xAOD::DetectorIDHashType
unsigned int DetectorIDHashType
@ detector ID element hash
Definition: MeasurementDefs.h:42
ActsTrk::getUncalibratedMeasurement
const xAOD::UncalibratedMeasurement & getUncalibratedMeasurement(const ATLASUncalibSourceLink &source_link)
Definition: ATLASSourceLink.h:27
InDetDD::SiDetectorElement
Definition: SiDetectorElement.h:109
SiDetectorElementCollection.h
SiDetectorElement.h
a
TList * a
Definition: liststreamerinfos.cxx:10
TrackFindingAlg.h
lumiFormat.fill
fill
Definition: lumiFormat.py:111
std::sort
void sort(typename std::reverse_iterator< DataModel_detail::iterator< DVL > > beg, typename std::reverse_iterator< DataModel_detail::iterator< DVL > > end, const Compare &comp)
Specialization of sort for DataVector/List.
Definition: DVL_algorithms.h:623
StripClusterContainer.h
DeMoScan.first
bool first
Definition: DeMoScan.py:534
xAOD::UncalibMeasType
UncalibMeasType
Define the type of the uncalibrated measurement.
Definition: MeasurementDefs.h:24
ActsTrk::TrackFindingAlg::RecoTrackStateContainer
Acts::VectorMultiTrajectory RecoTrackStateContainer
Definition: TrackFindingAlg.h:72
IActsToTrkConverterTool.h
InDetDD::SiDetectorElementCollection::getDetectorElement
const SiDetectorElement * getDetectorElement(const IdentifierHash &hash) const
Definition: SiDetectorElementCollection.cxx:15
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7