Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TrackTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file TrackTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2023 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 #include <boost/test/data/test_case.hpp>
10 #include <boost/test/unit_test.hpp>
11 
29 #include "Acts/Utilities/Zip.hpp"
30 
31 #include <cstddef>
32 #include <iterator>
33 #include <memory>
34 #include <numeric>
35 #include <random>
36 #include <stdexcept>
37 #include <tuple>
38 #include <type_traits>
39 #include <utility>
40 #include <vector>
41 
42 namespace {
43 
44 using namespace Acts::UnitLiterals;
45 
46 using namespace Acts;
47 using namespace Acts::HashedStringLiteral;
48 using namespace Acts::Test;
50 namespace bd = boost::unit_test::data;
51 
52 const GeometryContext gctx;
53 // fixed seed for reproducible tests
54 std::default_random_engine rng(31415);
55 
56 // template <template <typename> class holder_t>
57 // using track_container_t =
58 // TrackContainer<VectorTrackContainer, VectorMultiTrajectory, holder_t>;
59 
60 template <typename track_container_t, typename traj_t,
61  template <typename> class holder_t>
62 struct Factory {};
63 
64 template <typename track_container_t, typename traj_t>
65 struct Factory<track_container_t, traj_t, detail::RefHolder> {
66  using track_container_type =
68 
69  track_container_t vtc;
70  traj_t mtj;
71  track_container_type tc{vtc, mtj};
72 
73  auto& trackContainer() { return tc; }
74  auto& trackStateContainer() { return mtj; }
75  auto& backend() { return vtc; }
76 };
77 
78 template <typename track_container_t, typename traj_t>
79 struct Factory<track_container_t, traj_t, detail::ValueHolder> {
80  using track_container_type =
82 
83  track_container_type tc{track_container_t{}, traj_t{}};
84 
85  auto& trackContainer() { return tc; }
86  auto& trackStateContainer() { return tc.trackStateContainer(); }
87  auto& backend() { return tc.container(); }
88 };
89 
90 template <typename track_container_t, typename traj_t>
91 struct Factory<track_container_t, traj_t, std::shared_ptr> {
92  using track_container_type =
94 
95  std::shared_ptr<track_container_t> vtc{std::make_shared<track_container_t>()};
96  std::shared_ptr<traj_t> mtj{std::make_shared<traj_t>()};
97  track_container_type tc{vtc, mtj};
98 
99  auto& trackContainer() { return tc; }
100  auto& trackStateContainer() { return *mtj; }
101  auto& backend() { return *vtc; }
102 };
103 
104 template <typename track_container_t, typename traj_t,
105  template <typename> class... holders>
106 using holder_types_t =
107  std::tuple<Factory<track_container_t, traj_t, holders>...>;
108 
109 using holder_types = holder_types_t<VectorTrackContainer, VectorMultiTrajectory,
110  // detail_tc::ValueHolder,
111  // detail_tc::RefHolder,
112  std::shared_ptr>;
113 
114 using const_holder_types =
116  detail::ValueHolder, detail::RefHolder, std::shared_ptr>;
117 
118 } // namespace
119 
120 BOOST_AUTO_TEST_SUITE(EventDataTrack)
121 
122 BOOST_AUTO_TEST_CASE(BuildDefaultHolder) {
124  VectorTrackContainer vtc{};
125  TrackContainer tc{vtc, mtj};
126 
127  static_assert(
128  std::is_same_v<decltype(tc),
130  detail::RefHolder>>,
131  "Incorrect deduced type");
132  BOOST_CHECK_EQUAL(&mtj, &tc.trackStateContainer());
133  BOOST_CHECK_EQUAL(&vtc, &tc.container());
134  tc.addTrack();
135 
136  std::decay_t<decltype(tc)> copy = tc;
137  BOOST_CHECK_EQUAL(&mtj, &copy.trackStateContainer());
138  BOOST_CHECK_EQUAL(&vtc, &copy.container());
139 }
140 
141 BOOST_AUTO_TEST_CASE(BuildValueHolder) {
142  {
144  VectorTrackContainer vtc{};
146  static_assert(
147  std::is_same_v<decltype(tc), TrackContainer<VectorTrackContainer,
149  detail::ValueHolder>>,
150  "Incorrect deduced type");
151  std::decay_t<decltype(tc)> copy = tc;
152  BOOST_CHECK_NE(&tc.trackStateContainer(), &copy.trackStateContainer());
153  BOOST_CHECK_NE(&tc.container(), &copy.container());
154  }
155  {
157 
158  static_assert(
159  std::is_same_v<decltype(tc), TrackContainer<VectorTrackContainer,
161  detail::ValueHolder>>,
162  "Incorrect deduced type");
163  tc.addTrack();
164  std::decay_t<decltype(tc)> copy = tc;
165  BOOST_CHECK_NE(&tc.trackStateContainer(), &copy.trackStateContainer());
166  BOOST_CHECK_NE(&tc.container(), &copy.container());
167  }
168 }
169 
170 BOOST_AUTO_TEST_CASE(BuildRefHolder) {
172  VectorTrackContainer vtc{};
174  tc{vtc, mtj};
175 
176  static_assert(
177  std::is_same_v<decltype(tc),
179  detail::RefHolder>>,
180  "Incorrect deduced type");
181  BOOST_CHECK_EQUAL(&mtj, &tc.trackStateContainer());
182  BOOST_CHECK_EQUAL(&vtc, &tc.container());
183  tc.addTrack();
184  std::decay_t<decltype(tc)> copy = tc;
185  BOOST_CHECK_EQUAL(&mtj, &copy.trackStateContainer());
186  BOOST_CHECK_EQUAL(&vtc, &copy.container());
187 }
188 
189 BOOST_AUTO_TEST_CASE(BuildSharedPtr) {
190  auto mtj = std::make_shared<VectorMultiTrajectory>();
191  auto vtc = std::make_shared<VectorTrackContainer>();
193  tc{vtc, mtj};
194 
195  static_assert(
196  std::is_same_v<decltype(tc),
198  std::shared_ptr>>,
199  "Incorrect deduced type");
200  BOOST_CHECK_EQUAL(mtj.get(), &tc.trackStateContainer());
201  BOOST_CHECK_EQUAL(vtc.get(), &tc.container());
202  tc.addTrack();
203  std::decay_t<decltype(tc)> copy = tc;
204  BOOST_CHECK_EQUAL(mtj.get(), &copy.trackStateContainer());
205  BOOST_CHECK_EQUAL(vtc.get(), &copy.container());
206 }
207 
208 BOOST_AUTO_TEST_CASE_TEMPLATE(Build, factory_t, holder_types) {
209  factory_t factory;
210 
211  auto& tc = factory.trackContainer();
212 
213  static_assert(std::is_same_v<std::decay_t<decltype(tc)>,
214  typename factory_t::track_container_type>,
215  "Incorrect deduction");
216 
217  static_assert(!std::decay_t<decltype(tc)>::ReadOnly,
218  "Should not be read only");
219  BOOST_CHECK(!tc.ReadOnly);
220 
221  auto idx = tc.addTrack();
222  auto t = tc.getTrack(idx);
223  auto t2 = tc.getTrack(idx);
224  t.template component<IndexType, "tipIndex"_hash>() = 5;
225 
226  BOOST_CHECK_EQUAL((t.template component<IndexType, "tipIndex"_hash>()), 5);
227  BOOST_CHECK_EQUAL(t.tipIndex(), 5);
228  t.tipIndex() = 6;
229  BOOST_CHECK_EQUAL(t.tipIndex(), 6);
230 
232  pars.setRandom();
233  t.parameters() = pars;
234  BOOST_CHECK_EQUAL(t.parameters(), pars);
235 
237  cov.setRandom();
238  t.covariance() = cov;
239  BOOST_CHECK_EQUAL(t.covariance(), cov);
240 
241  auto surface = Acts::Surface::makeShared<Acts::PlaneSurface>(
242  Acts::Vector3{-3_m, 0., 0.}, Acts::Vector3{1., 0., 0});
243 
244  t.setReferenceSurface(surface);
245  BOOST_CHECK_EQUAL(surface.get(), &t.referenceSurface());
246 
247  TrackAccessor<unsigned int> accNMeasuements("nMeasurements");
249 
250  t.nMeasurements() = 42;
251  BOOST_CHECK_EQUAL(t2.nMeasurements(), 42);
252  BOOST_CHECK_EQUAL(accNMeasuements(t), 42);
253  accNMeasuements(t) = 89;
254  BOOST_CHECK_EQUAL(t2.nMeasurements(), 89);
255  BOOST_CHECK_EQUAL(caccNMeasuements(t), 89);
256 
257  // does not compile
258  // caccNMeasuements(t) = 66;
259 
260  t2.nHoles() = 67;
261  BOOST_CHECK_EQUAL(t.nHoles(), 67);
262 
263  t2.nOutliers() = 68;
264  BOOST_CHECK_EQUAL(t.nOutliers(), 68);
265 
266  t2.nSharedHits() = 69;
267  BOOST_CHECK_EQUAL(t.nSharedHits(), 69);
268 
269  t2.chi2() = 555.0;
270  BOOST_CHECK_EQUAL(t2.chi2(), 555.0);
271 
272  t2.nDoF() = 123;
273  BOOST_CHECK_EQUAL(t2.nDoF(), 123);
274 
275  // const checks: should not compile
276  // const auto& ctc = tc;
277  // ctc.getTrack(idx).covariance().setRandom();
278  // const auto& ctp = t;
279  // ctp.covariance().setRandom();
280 }
281 
282 BOOST_AUTO_TEST_CASE_TEMPLATE(TrackStateAccess, factory_t, holder_types) {
283  factory_t factory;
284  auto& tc = factory.trackContainer();
285 
286  VectorMultiTrajectory& traj = factory.trackStateContainer();
287 
288  auto mkts = [&](auto prev) {
289  if constexpr (std::is_same_v<decltype(prev), IndexType>) {
290  auto ts =
291  traj.getTrackState(traj.addTrackState(TrackStatePropMask::All, prev));
292  TestTrackState pc(rng, 2u);
293  fillTrackState<VectorMultiTrajectory>(pc, TrackStatePropMask::All, ts);
294  return ts;
295  } else {
296  auto ts = traj.getTrackState(
297  traj.addTrackState(TrackStatePropMask::All, prev.index()));
298  TestTrackState pc(rng, 2u);
299  fillTrackState<VectorMultiTrajectory>(pc, TrackStatePropMask::All, ts);
300  return ts;
301  }
302  };
303 
304  auto ts1 = mkts(MultiTrajectoryTraits::kInvalid);
305  auto ts2 = mkts(ts1);
306  auto ts3 = mkts(ts2);
307  auto ts4 = mkts(ts3);
308  auto ts5 = mkts(ts4);
309 
310  auto t = tc.getTrack(tc.addTrack());
311  t.tipIndex() = ts5.index();
312 
313  std::vector<IndexType> act;
314  for (const auto& ts : t.trackStatesReversed()) {
315  act.push_back(ts.index());
316  }
317 
318  std::vector<IndexType> exp;
319  exp.resize(5);
320  std::iota(exp.rbegin(), exp.rend(), 0);
321  BOOST_CHECK_EQUAL_COLLECTIONS(act.begin(), act.end(), exp.begin(), exp.end());
322 
323  const auto& ct = t;
324 
325  for (const auto& ts : ct.trackStatesReversed()) {
326  (void)ts;
327  }
328 
329  BOOST_CHECK_EQUAL(t.nTrackStates(), 5);
330 
331  auto tNone = tc.getTrack(tc.addTrack());
332  BOOST_CHECK_EQUAL(tNone.nTrackStates(), 0);
333 
334  auto tsRange = tNone.trackStatesReversed();
335  BOOST_CHECK(tsRange.begin() == tsRange.end());
336 
337  size_t i = 0;
338  for (const auto& state : tNone.trackStatesReversed()) {
339  (void)state;
340  i++;
341  }
342  BOOST_CHECK_EQUAL(i, 0);
343 }
344 
345 BOOST_AUTO_TEST_CASE_TEMPLATE(TrackIterator, factory_t, holder_types) {
346  factory_t factory;
347  auto& tc = factory.trackContainer();
348 
349  for (unsigned int i = 0; i < 10; i++) {
350  auto t = tc.getTrack(tc.addTrack());
351  t.tipIndex() = i;
352  }
353  BOOST_CHECK_EQUAL(tc.size(), 10);
354 
355  unsigned int i = 0;
356  for (auto track : tc) {
357  BOOST_CHECK_EQUAL(i, track.tipIndex());
358  track.parameters().setRandom();
359  i++;
360  }
361 
362  BOOST_CHECK_EQUAL(std::distance(tc.begin(), tc.end()), tc.size());
363 }
364 
365 BOOST_AUTO_TEST_CASE(IteratorConcept) {
368  TrackContainer tc{vtc, mtj};
369 
370  for (unsigned int i = 0; i < 10; i++) {
371  auto t = tc.getTrack(tc.addTrack());
372  t.tipIndex() = i;
373  }
374  BOOST_CHECK_EQUAL(tc.size(), 10);
375  BOOST_CHECK_EQUAL(std::distance(tc.begin(), tc.end()), tc.size());
376 
377  {
378  auto it = tc.begin();
379  BOOST_CHECK(*it == tc.getTrack(0));
380  ++it;
381  BOOST_CHECK(*it == tc.getTrack(1));
382  it += 1;
383  BOOST_CHECK(*it == tc.getTrack(2));
384  it -= 1;
385  BOOST_CHECK(*it == tc.getTrack(1));
386  ++it;
387  ++it;
388  --it;
389  BOOST_CHECK(*it == tc.getTrack(2));
390  }
391  {
392  auto it = tc.begin();
393  BOOST_CHECK(*it == tc.getTrack(0));
394  std::advance(it, 4);
395  BOOST_CHECK(*it == tc.getTrack(4));
396  BOOST_CHECK(*(it[-1]) == tc.getTrack(3));
397  BOOST_CHECK(*(it[0]) == tc.getTrack(4));
398  BOOST_CHECK(*(it[1]) == tc.getTrack(5));
399  BOOST_CHECK(*(it - 2) == tc.getTrack(2));
400  }
401 
402  {
403  auto it = tc.begin();
404  auto it4 = it + 4;
405  auto it5 = it + 5;
406  auto it6 = it + 6;
407 
408  BOOST_CHECK(it4 < it5);
409  BOOST_CHECK(it5 < it6);
410  BOOST_CHECK(it4 < it6);
411 
412  BOOST_CHECK(it6 > it5);
413  BOOST_CHECK(it5 > it4);
414  BOOST_CHECK(it6 > it4);
415 
416  BOOST_CHECK(it4 <= it4);
417  BOOST_CHECK(it4 <= it5);
418  BOOST_CHECK(it5 <= it5);
419  BOOST_CHECK(it5 <= it6);
420 
421  BOOST_CHECK(it6 >= it6);
422  BOOST_CHECK(it6 >= it5);
423  }
424 }
425 
426 BOOST_AUTO_TEST_CASE(ConstCorrectness) {
429  {
430  TrackContainer tc{vtc, mtj};
431 
432  for (unsigned int i = 0; i < 10; i++) {
433  auto t = tc.getTrack(tc.addTrack());
434  t.tipIndex() = i;
435  }
436 
437  unsigned int i = 0;
438  for (auto track : tc) {
439  BOOST_CHECK_EQUAL(i, track.tipIndex());
440  track.parameters().setRandom();
441  i++;
442  }
443 
444  for (const auto track : tc) {
445  (void)track;
446  // does not compile
447  // track.parameters().setRandom();
448  }
449  }
450 
453  {
455 
456  unsigned int i = 0;
457  for (auto track : tc) {
458  BOOST_CHECK_EQUAL(i, track.tipIndex());
459  i++;
460  // does not compile
461  // track.parameters().setRandom();
462  }
463  }
464 }
465 
466 BOOST_AUTO_TEST_CASE(BuildFromConstRef) {
467  VectorTrackContainer mutVtc;
468  VectorMultiTrajectory mutMtj;
469 
470  TrackContainer mutTc{mutVtc, mutMtj};
471  static_assert(!mutTc.ReadOnly, "Unexpectedly read only");
472 
473  auto t = mutTc.getTrack(mutTc.addTrack());
474  t.appendTrackState();
475  t.appendTrackState();
476  t.appendTrackState();
477  t = mutTc.getTrack(mutTc.addTrack());
478  t.appendTrackState();
479 
480  BOOST_CHECK_EQUAL(mutTc.size(), 2);
481  BOOST_CHECK_EQUAL(mutMtj.size(), 4);
482 
485 
486  // moved from
487  BOOST_CHECK_EQUAL(mutTc.size(), 0);
488  BOOST_CHECK_EQUAL(mutMtj.size(), 0);
489 
490  TrackContainer ctc{vtc, mtj};
491  static_assert(ctc.ReadOnly, "Unexpectedly not read only");
492 
493  // Does not compile:
494  // ctc.addTrack();
495 
496  BOOST_CHECK_EQUAL(ctc.size(), 2);
497  BOOST_CHECK_EQUAL(mtj.size(), 4);
498 
499  const auto& cvtc = vtc;
500  const auto& cmtj = mtj;
501 
502  TrackContainer crtc{cvtc, cmtj};
503 
504  BOOST_CHECK_EQUAL(crtc.size(), 2);
505  BOOST_CHECK_EQUAL(cmtj.size(), 4);
506 
507  // Does not compile: holder deduced to ConstRefHolder, but is not RO
508  // const auto& mrvtc = mutVtc;
509  // const auto& mrmtj = mutMtj;
510  // TrackContainer mrtc{mrvtc, mrmtj};
511  // static_assert(ctc.ReadOnly, "Unexpectedly not read only");
512  // mrtc.addTrack();
513 }
514 
515 BOOST_AUTO_TEST_CASE_TEMPLATE(BuildReadOnly, factory_t, const_holder_types) {
516  factory_t factory;
517  auto& tc = factory.trackContainer();
518 
519  static_assert(std::is_same_v<std::decay_t<decltype(tc)>,
520  typename factory_t::track_container_type>,
521  "Incorrect deduction");
522 
523  static_assert(std::decay_t<decltype(tc)>::ReadOnly, "Should be read only");
524  BOOST_CHECK(tc.ReadOnly);
525 }
526 
527 BOOST_AUTO_TEST_CASE_TEMPLATE(DynamicColumns, factory_t, holder_types) {
528  factory_t factory;
529  auto& tc = factory.trackContainer();
530 
531  BOOST_CHECK(!tc.hasColumn("col_a"_hash));
532  tc.template addColumn<float>("col_a");
533  BOOST_CHECK(tc.hasColumn("col_a"_hash));
534 
535  auto t = tc.getTrack(tc.addTrack());
536  t.template component<float>("col_a") = 5.6f;
537  BOOST_CHECK_EQUAL((t.template component<float, "col_a"_hash>()), 5.6f);
538 }
539 
540 BOOST_AUTO_TEST_CASE(EnsureDynamicColumns) {
542  tc.addColumn<size_t>("counter");
543  tc.addColumn<bool>("odd");
544 
545  BOOST_CHECK(tc.hasColumn("counter"));
546  BOOST_CHECK(tc.hasColumn("odd"));
547 
549 
550  BOOST_CHECK(!tc2.hasColumn("counter"));
551  BOOST_CHECK(!tc2.hasColumn("odd"));
552 
553  tc2.ensureDynamicColumns(tc);
554 
555  BOOST_CHECK(tc2.hasColumn("counter"));
556  BOOST_CHECK(tc2.hasColumn("odd"));
557 }
558 
559 BOOST_AUTO_TEST_CASE(AppendTrackState) {
561  auto t = tc.getTrack(tc.addTrack());
562 
563  std::vector<VectorMultiTrajectory::TrackStateProxy> trackStates;
564  trackStates.push_back(t.appendTrackState());
565  trackStates.push_back(t.appendTrackState());
566  trackStates.push_back(t.appendTrackState());
567  trackStates.push_back(t.appendTrackState());
568  trackStates.push_back(t.appendTrackState());
569  trackStates.push_back(t.appendTrackState());
570 
571  BOOST_CHECK_EQUAL(trackStates.size(), t.nTrackStates());
572 
573  for (size_t i = trackStates.size() - 1; i > 0; i--) {
574  BOOST_CHECK_EQUAL(trackStates.at(i).index(), i);
575  }
576 }
577 
578 BOOST_AUTO_TEST_CASE(ForwardIteration) {
580  {
581  // let's create an unrelated track first
582  auto t = tc.getTrack(tc.addTrack());
583  for (std::size_t i = 0; i < 10; i++) {
584  t.appendTrackState();
585  }
586  }
587 
588  auto t = tc.getTrack(tc.addTrack());
589 
590  auto stem = t.appendTrackState();
591  t.appendTrackState();
592  t.appendTrackState();
593  t.appendTrackState();
594  t.appendTrackState();
595 
596  BOOST_CHECK_THROW(t.trackStates(), std::invalid_argument);
597  BOOST_CHECK(!t.innermostTrackState().has_value());
598 
599  t.linkForward();
600 
601  BOOST_CHECK_EQUAL(t.stemIndex(), stem.index());
602  BOOST_CHECK_EQUAL(t.innermostTrackState().value().index(), stem.index());
603  t.innermostTrackState()->predicted().setRandom();
604 
605  std::vector<IndexType> indices;
606  for (const auto& ts : t.trackStatesReversed()) {
607  indices.push_back(ts.index());
608  }
609 
610  std::reverse(indices.begin(), indices.end());
611 
612  std::vector<IndexType> act;
613  for (auto ts : t.trackStates()) {
614  act.push_back(ts.index());
615  ts.predicted().setRandom();
616  }
617 
618  BOOST_CHECK_EQUAL_COLLECTIONS(indices.begin(), indices.end(), act.begin(),
619  act.end());
620 
621  t.reverseTrackStates();
622  BOOST_CHECK_EQUAL(t.innermostTrackState().value().index(), indices.back());
623  t.innermostTrackState()->predicted().setRandom();
624 
625  act.clear();
626  for (const auto& ts : t.trackStates()) {
627  act.push_back(ts.index());
628  }
629 
630  BOOST_CHECK_EQUAL_COLLECTIONS(indices.rbegin(), indices.rend(), act.begin(),
631  act.end());
632 }
633 
634 BOOST_AUTO_TEST_CASE(CalculateQuantities) {
636  auto t = tc.getTrack(tc.addTrack());
637 
638  auto ts = t.appendTrackState();
639  ts.typeFlags().set(MeasurementFlag);
640 
641  ts = t.appendTrackState();
642  ts.typeFlags().set(OutlierFlag);
643 
644  ts = t.appendTrackState();
645  ts.typeFlags().set(MeasurementFlag);
646  ts.typeFlags().set(SharedHitFlag);
647 
648  ts = t.appendTrackState();
649  ts.typeFlags().set(HoleFlag);
650 
651  ts = t.appendTrackState();
652  ts.typeFlags().set(OutlierFlag);
653 
654  ts = t.appendTrackState();
655  ts.typeFlags().set(HoleFlag);
656 
657  ts = t.appendTrackState();
658  ts.typeFlags().set(MeasurementFlag);
659  ts.typeFlags().set(SharedHitFlag);
660 
661  ts = t.appendTrackState();
662  ts.typeFlags().set(OutlierFlag);
663 
665 
666  BOOST_CHECK_EQUAL(t.nHoles(), 2);
667  BOOST_CHECK_EQUAL(t.nMeasurements(), 3);
668  BOOST_CHECK_EQUAL(t.nOutliers(), 3);
669  BOOST_CHECK_EQUAL(t.nSharedHits(), 2);
670 }
671 
672 BOOST_AUTO_TEST_SUITE_END()