File indexing completed on 2026-01-09 09:26:55
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/TrackParametrization.hpp"
0013 #include "Acts/Definitions/Units.hpp"
0014 #include "Acts/EventData/MultiTrajectory.hpp"
0015 #include "Acts/EventData/ProxyAccessor.hpp"
0016 #include "Acts/EventData/TrackContainer.hpp"
0017 #include "Acts/EventData/TrackProxy.hpp"
0018 #include "Acts/EventData/TrackStatePropMask.hpp"
0019 #include "Acts/EventData/Types.hpp"
0020 #include "Acts/EventData/VectorMultiTrajectory.hpp"
0021 #include "Acts/EventData/VectorTrackContainer.hpp"
0022 #include "Acts/EventData/detail/GenerateParameters.hpp"
0023 #include "Acts/EventData/detail/TestTrackState.hpp"
0024 #include "Acts/Geometry/GeometryContext.hpp"
0025 #include "Acts/Surfaces/PerigeeSurface.hpp"
0026 #include "Acts/Utilities/HashedString.hpp"
0027 #include "Acts/Utilities/Holders.hpp"
0028
0029 #include <algorithm>
0030 #include <cstddef>
0031 #include <iterator>
0032 #include <memory>
0033 #include <numeric>
0034 #include <random>
0035 #include <stdexcept>
0036 #include <tuple>
0037 #include <type_traits>
0038 #include <utility>
0039 #include <vector>
0040
0041 namespace {
0042
0043 using namespace Acts::UnitLiterals;
0044
0045 using namespace Acts;
0046 using namespace Acts::HashedStringLiteral;
0047 using namespace Acts::detail::Test;
0048
0049 using IndexType = TrackIndexType;
0050
0051 const GeometryContext gctx;
0052
0053 std::default_random_engine rng(31415);
0054
0055
0056
0057
0058
0059 template <typename track_container_t, typename traj_t,
0060 template <typename> class holder_t>
0061 struct Factory {};
0062
0063 template <typename track_container_t, typename traj_t>
0064 struct Factory<track_container_t, traj_t, detail::RefHolder> {
0065 using track_container_type =
0066 TrackContainer<track_container_t, traj_t, detail::RefHolder>;
0067
0068 track_container_t vtc;
0069 traj_t mtj;
0070 track_container_type tc{vtc, mtj};
0071
0072 auto& trackContainer() { return tc; }
0073 auto& trackStateContainer() { return mtj; }
0074 auto& backend() { return vtc; }
0075 };
0076
0077 template <typename track_container_t, typename traj_t>
0078 struct Factory<track_container_t, traj_t, detail::ValueHolder> {
0079 using track_container_type =
0080 TrackContainer<track_container_t, traj_t, detail::ValueHolder>;
0081
0082 track_container_type tc{track_container_t{}, traj_t{}};
0083
0084 auto& trackContainer() { return tc; }
0085 auto& trackStateContainer() { return tc.trackStateContainer(); }
0086 auto& backend() { return tc.container(); }
0087 };
0088
0089 template <typename track_container_t, typename traj_t>
0090 struct Factory<track_container_t, traj_t, std::shared_ptr> {
0091 using track_container_type =
0092 TrackContainer<track_container_t, traj_t, std::shared_ptr>;
0093
0094 std::shared_ptr<track_container_t> vtc{std::make_shared<track_container_t>()};
0095 std::shared_ptr<traj_t> mtj{std::make_shared<traj_t>()};
0096 track_container_type tc{vtc, mtj};
0097
0098 auto& trackContainer() { return tc; }
0099 auto& trackStateContainer() { return *mtj; }
0100 auto& backend() { return *vtc; }
0101 };
0102
0103 template <typename track_container_t, typename traj_t,
0104 template <typename> class... holders>
0105 using holder_types_t =
0106 std::tuple<Factory<track_container_t, traj_t, holders>...>;
0107
0108 using holder_types = holder_types_t<VectorTrackContainer, VectorMultiTrajectory,
0109
0110
0111 std::shared_ptr>;
0112
0113 using const_holder_types =
0114 holder_types_t<ConstVectorTrackContainer, ConstVectorMultiTrajectory,
0115 detail::ValueHolder, detail::RefHolder, std::shared_ptr>;
0116
0117 }
0118
0119 namespace ActsTests {
0120
0121
0122
0123 static_assert(
0124 ConstTrackProxyConcept<TrackProxy<
0125 VectorTrackContainer, VectorMultiTrajectory, detail::RefHolder, true>>);
0126 static_assert(ConstTrackProxyConcept<
0127 TrackProxy<VectorTrackContainer, VectorMultiTrajectory,
0128 detail::RefHolder, false>>);
0129 static_assert(MutableTrackProxyConcept<
0130 TrackProxy<VectorTrackContainer, VectorMultiTrajectory,
0131 detail::RefHolder, false>>);
0132 static_assert(
0133 !MutableTrackProxyConcept<TrackProxy<
0134 VectorTrackContainer, VectorMultiTrajectory, detail::RefHolder, true>>);
0135
0136 static_assert(ConstTrackStateProxyConcept<
0137 TrackStateProxy<VectorMultiTrajectory, eBoundSize, true>>);
0138 static_assert(!ConstTrackStateProxyConcept<
0139 TrackStateProxy<VectorMultiTrajectory, eBoundSize, false>>);
0140 static_assert(MutableTrackStateProxyConcept<
0141 TrackStateProxy<VectorMultiTrajectory, eBoundSize, false>>);
0142 static_assert(!MutableTrackStateProxyConcept<
0143 TrackStateProxy<VectorMultiTrajectory, eBoundSize, true>>);
0144
0145 BOOST_AUTO_TEST_SUITE(EventDataSuite)
0146
0147 BOOST_AUTO_TEST_CASE_TEMPLATE(TrackStateAccess, factory_t, holder_types) {
0148 factory_t factory;
0149 auto& tc = factory.trackContainer();
0150
0151 VectorMultiTrajectory& traj = factory.trackStateContainer();
0152
0153 auto mkts = [&](auto prev) {
0154 if constexpr (std::is_same_v<decltype(prev), IndexType>) {
0155 auto ts = traj.makeTrackState(TrackStatePropMask::All, prev);
0156 TestTrackState pc(rng, 2u);
0157 fillTrackState<VectorMultiTrajectory>(pc, TrackStatePropMask::All, ts);
0158 return ts;
0159 } else {
0160 auto ts = traj.makeTrackState(TrackStatePropMask::All, prev.index());
0161 TestTrackState pc(rng, 2u);
0162 fillTrackState<VectorMultiTrajectory>(pc, TrackStatePropMask::All, ts);
0163 return ts;
0164 }
0165 };
0166
0167 auto ts1 = mkts(kTrackIndexInvalid);
0168 auto ts2 = mkts(ts1);
0169 auto ts3 = mkts(ts2);
0170 auto ts4 = mkts(ts3);
0171 auto ts5 = mkts(ts4);
0172
0173 auto t = tc.makeTrack();
0174 t.tipIndex() = ts5.index();
0175
0176 std::vector<IndexType> act;
0177 for (const auto& ts : t.trackStatesReversed()) {
0178 act.push_back(ts.index());
0179 }
0180
0181 std::vector<IndexType> exp;
0182 exp.resize(5);
0183 std::iota(exp.rbegin(), exp.rend(), 0);
0184 BOOST_CHECK_EQUAL_COLLECTIONS(act.begin(), act.end(), exp.begin(), exp.end());
0185
0186 const auto& ct = t;
0187
0188 for (const auto& ts : ct.trackStatesReversed()) {
0189 (void)ts;
0190 }
0191
0192 BOOST_CHECK_EQUAL(t.nTrackStates(), 5);
0193
0194 auto tNone = tc.makeTrack();
0195 BOOST_CHECK_EQUAL(tNone.nTrackStates(), 0);
0196
0197 auto tsRange = tNone.trackStatesReversed();
0198 BOOST_CHECK(tsRange.begin() == tsRange.end());
0199
0200 std::size_t i = 0;
0201 for (const auto& state : tNone.trackStatesReversed()) {
0202 (void)state;
0203 i++;
0204 }
0205 BOOST_CHECK_EQUAL(i, 0);
0206 }
0207
0208 BOOST_AUTO_TEST_CASE_TEMPLATE(TrackIterator, factory_t, holder_types) {
0209 factory_t factory;
0210 auto& tc = factory.trackContainer();
0211
0212 for (unsigned int i = 0; i < 10; i++) {
0213 auto t = tc.makeTrack();
0214 t.tipIndex() = i;
0215 }
0216 BOOST_CHECK_EQUAL(tc.size(), 10);
0217
0218 unsigned int i = 0;
0219 for (auto track : tc) {
0220 BOOST_CHECK_EQUAL(i, track.tipIndex());
0221 track.parameters().setRandom();
0222 i++;
0223 }
0224
0225 BOOST_CHECK_EQUAL(std::distance(tc.begin(), tc.end()), tc.size());
0226 }
0227
0228 BOOST_AUTO_TEST_CASE(IteratorConcept) {
0229 VectorTrackContainer vtc;
0230 VectorMultiTrajectory mtj;
0231 TrackContainer tc{vtc, mtj};
0232
0233 for (unsigned int i = 0; i < 10; i++) {
0234 auto t = tc.makeTrack();
0235 t.tipIndex() = i;
0236 }
0237 BOOST_CHECK_EQUAL(tc.size(), 10);
0238 BOOST_CHECK_EQUAL(std::distance(tc.begin(), tc.end()), tc.size());
0239
0240 {
0241 auto it = tc.begin();
0242 BOOST_CHECK(*it == tc.getTrack(0));
0243 ++it;
0244 BOOST_CHECK(*it == tc.getTrack(1));
0245 it += 1;
0246 BOOST_CHECK(*it == tc.getTrack(2));
0247 it -= 1;
0248 BOOST_CHECK(*it == tc.getTrack(1));
0249 ++it;
0250 ++it;
0251 --it;
0252 BOOST_CHECK(*it == tc.getTrack(2));
0253 }
0254 {
0255 auto it = tc.begin();
0256 BOOST_CHECK(*it == tc.getTrack(0));
0257 std::advance(it, 4);
0258 BOOST_CHECK(*it == tc.getTrack(4));
0259 BOOST_CHECK(*(it + (-1)) == tc.getTrack(3));
0260 BOOST_CHECK(*(it + 0) == tc.getTrack(4));
0261 BOOST_CHECK(*(it + 1) == tc.getTrack(5));
0262 BOOST_CHECK(*(it - 2) == tc.getTrack(2));
0263 }
0264
0265 {
0266 auto it = tc.begin();
0267 auto it4 = it + 4;
0268 auto it5 = it + 5;
0269 auto it6 = it + 6;
0270
0271 BOOST_CHECK(it4 < it5);
0272 BOOST_CHECK(it5 < it6);
0273 BOOST_CHECK(it4 < it6);
0274
0275 BOOST_CHECK(it6 > it5);
0276 BOOST_CHECK(it5 > it4);
0277 BOOST_CHECK(it6 > it4);
0278
0279 BOOST_CHECK(it4 <= it4);
0280 BOOST_CHECK(it4 <= it5);
0281 BOOST_CHECK(it5 <= it5);
0282 BOOST_CHECK(it5 <= it6);
0283
0284 BOOST_CHECK(it6 >= it6);
0285 BOOST_CHECK(it6 >= it5);
0286 }
0287 }
0288
0289 BOOST_AUTO_TEST_CASE(ConstCorrectness) {
0290 VectorTrackContainer vtc;
0291 VectorMultiTrajectory mtj;
0292 {
0293 TrackContainer tc{vtc, mtj};
0294
0295 for (unsigned int i = 0; i < 10; i++) {
0296 auto t = tc.makeTrack();
0297 t.tipIndex() = i;
0298 }
0299
0300 unsigned int i = 0;
0301 for (auto track : tc) {
0302 BOOST_CHECK_EQUAL(i, track.tipIndex());
0303 track.parameters().setRandom();
0304 i++;
0305 }
0306
0307 for (const auto track : tc) {
0308 (void)track;
0309
0310
0311 }
0312 }
0313
0314 ConstVectorTrackContainer cvtc{std::move(vtc)};
0315 ConstVectorMultiTrajectory cmtj{std::move(mtj)};
0316 {
0317 TrackContainer tc{cvtc, cmtj};
0318
0319 unsigned int i = 0;
0320 for (auto track : tc) {
0321 BOOST_CHECK_EQUAL(i, track.tipIndex());
0322 i++;
0323
0324
0325 }
0326 }
0327 }
0328
0329 BOOST_AUTO_TEST_CASE(BuildFromConstRef) {
0330 VectorTrackContainer mutVtc;
0331 VectorMultiTrajectory mutMtj;
0332
0333 TrackContainer mutTc{mutVtc, mutMtj};
0334 static_assert(!mutTc.ReadOnly, "Unexpectedly read only");
0335
0336 auto t = mutTc.makeTrack();
0337 t.appendTrackState();
0338 t.appendTrackState();
0339 t.appendTrackState();
0340 t = mutTc.makeTrack();
0341 t.appendTrackState();
0342 std::cout << "New track with l0: " << t.loc0() << ", l1: " << t.loc1()
0343 << ", phi: " << t.phi() << ", theta: " << t.theta()
0344 << ", q/p: " << t.qOverP() << ", q: " << t.charge()
0345 << ", P: " << t.absoluteMomentum()
0346 << ", pT: " << t.transverseMomentum()
0347 << ", direction: " << t.direction().transpose()
0348 << ", mom: " << t.momentum().transpose()
0349 << ", p4: " << t.fourMomentum() << ", nStates: " << t.nTrackStates()
0350 << ", nMeasurements: " << t.nMeasurements()
0351 << ", nHoles: " << t.nHoles() << ", nOutlier: " << t.nOutliers()
0352 << ", nShared: " << t.nSharedHits() << ", chi2: " << t.chi2()
0353 << ", nDoF: " << t.nDoF() << std::endl;
0354
0355 BOOST_CHECK_EQUAL(mutTc.size(), 2);
0356 BOOST_CHECK_EQUAL(mutMtj.size(), 4);
0357
0358 ConstVectorTrackContainer vtc{std::move(mutVtc)};
0359 ConstVectorMultiTrajectory mtj{std::move(mutMtj)};
0360
0361
0362 BOOST_CHECK_EQUAL(mutTc.size(), 0);
0363 BOOST_CHECK_EQUAL(mutMtj.size(), 0);
0364
0365 TrackContainer ctc{vtc, mtj};
0366 static_assert(ctc.ReadOnly, "Unexpectedly not read only");
0367
0368
0369
0370
0371 BOOST_CHECK_EQUAL(ctc.size(), 2);
0372 BOOST_CHECK_EQUAL(mtj.size(), 4);
0373
0374 const auto& cvtc = vtc;
0375 const auto& cmtj = mtj;
0376
0377 TrackContainer crtc{cvtc, cmtj};
0378
0379 BOOST_CHECK_EQUAL(crtc.size(), 2);
0380 BOOST_CHECK_EQUAL(cmtj.size(), 4);
0381
0382
0383
0384
0385
0386
0387
0388 }
0389
0390 BOOST_AUTO_TEST_CASE_TEMPLATE(BuildReadOnly, factory_t, const_holder_types) {
0391 factory_t factory;
0392 auto& tc = factory.trackContainer();
0393
0394 static_assert(std::is_same_v<std::decay_t<decltype(tc)>,
0395 typename factory_t::track_container_type>,
0396 "Incorrect deduction");
0397
0398 static_assert(std::decay_t<decltype(tc)>::ReadOnly, "Should be read only");
0399 BOOST_CHECK(tc.ReadOnly);
0400 }
0401
0402 BOOST_AUTO_TEST_CASE_TEMPLATE(DynamicColumns, factory_t, holder_types) {
0403 factory_t factory;
0404 auto& tc = factory.trackContainer();
0405
0406 BOOST_CHECK(!tc.hasColumn("col_a"_hash));
0407 tc.template addColumn<float>("col_a");
0408 BOOST_CHECK(tc.hasColumn("col_a"_hash));
0409
0410 auto t = tc.makeTrack();
0411 t.template component<float>("col_a") = 5.6f;
0412 BOOST_CHECK_EQUAL((t.template component<float, "col_a"_hash>()), 5.6f);
0413 }
0414
0415 BOOST_AUTO_TEST_CASE(EnsureDynamicColumns) {
0416 TrackContainer tc{VectorTrackContainer{}, VectorMultiTrajectory{}};
0417 tc.addColumn<std::size_t>("counter");
0418 tc.addColumn<bool>("odd");
0419
0420 BOOST_CHECK(tc.hasColumn("counter"));
0421 BOOST_CHECK(tc.hasColumn("odd"));
0422
0423 TrackContainer tc2{VectorTrackContainer{}, VectorMultiTrajectory{}};
0424
0425 BOOST_CHECK(!tc2.hasColumn("counter"));
0426 BOOST_CHECK(!tc2.hasColumn("odd"));
0427
0428 tc2.ensureDynamicColumns(tc);
0429
0430 BOOST_CHECK(tc2.hasColumn("counter"));
0431 BOOST_CHECK(tc2.hasColumn("odd"));
0432 }
0433
0434 BOOST_AUTO_TEST_CASE(AppendTrackState) {
0435 TrackContainer tc{VectorTrackContainer{}, VectorMultiTrajectory{}};
0436 auto t = tc.makeTrack();
0437
0438 std::vector<VectorMultiTrajectory::TrackStateProxy> trackStates;
0439 trackStates.push_back(t.appendTrackState());
0440 trackStates.push_back(t.appendTrackState());
0441 trackStates.push_back(t.appendTrackState());
0442 trackStates.push_back(t.appendTrackState());
0443 trackStates.push_back(t.appendTrackState());
0444 trackStates.push_back(t.appendTrackState());
0445
0446 BOOST_CHECK_EQUAL(trackStates.size(), t.nTrackStates());
0447
0448 for (std::size_t i = trackStates.size() - 1; i > 0; i--) {
0449 BOOST_CHECK_EQUAL(trackStates.at(i).index(), i);
0450 }
0451 }
0452
0453 BOOST_AUTO_TEST_CASE(ForwardIteration) {
0454 TrackContainer tc{VectorTrackContainer{}, VectorMultiTrajectory{}};
0455 {
0456
0457 auto t = tc.makeTrack();
0458 for (std::size_t i = 0; i < 10; i++) {
0459 t.appendTrackState();
0460 }
0461 }
0462
0463 auto t = tc.makeTrack();
0464
0465 auto stem = t.appendTrackState();
0466 t.appendTrackState();
0467 t.appendTrackState();
0468 t.appendTrackState();
0469 t.appendTrackState();
0470
0471 BOOST_CHECK_THROW(t.trackStates(), std::invalid_argument);
0472 BOOST_CHECK(!t.innermostTrackState().has_value());
0473
0474 t.linkForward();
0475
0476 BOOST_CHECK_EQUAL(t.stemIndex(), stem.index());
0477 BOOST_CHECK_EQUAL(t.innermostTrackState().value().index(), stem.index());
0478 t.innermostTrackState()->predicted().setRandom();
0479
0480 std::vector<IndexType> indices;
0481 for (const auto& ts : t.trackStatesReversed()) {
0482 indices.push_back(ts.index());
0483 }
0484
0485 std::ranges::reverse(indices);
0486
0487 std::vector<IndexType> act;
0488 for (auto ts : t.trackStates()) {
0489 act.push_back(ts.index());
0490 ts.predicted().setRandom();
0491 }
0492
0493 BOOST_CHECK_EQUAL_COLLECTIONS(indices.begin(), indices.end(), act.begin(),
0494 act.end());
0495
0496 t.reverseTrackStates();
0497 BOOST_CHECK_EQUAL(t.innermostTrackState().value().index(), indices.back());
0498 t.innermostTrackState()->predicted().setRandom();
0499
0500 act.clear();
0501 for (const auto& ts : t.trackStates()) {
0502 act.push_back(ts.index());
0503 }
0504
0505 BOOST_CHECK_EQUAL_COLLECTIONS(indices.rbegin(), indices.rend(), act.begin(),
0506 act.end());
0507 }
0508
0509 BOOST_AUTO_TEST_CASE(ShallowCopy) {
0510 TrackContainer tc{VectorTrackContainer{}, VectorMultiTrajectory{}};
0511 auto t = tc.makeTrack();
0512
0513 auto perigee =
0514 Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3::Zero());
0515
0516 t.parameters().setRandom();
0517 t.covariance().setRandom();
0518 t.particleHypothesis() = Acts::ParticleHypothesis::pion();
0519 t.setReferenceSurface(perigee);
0520
0521 auto ts1 = t.appendTrackState();
0522 ts1.predicted().setRandom();
0523 auto ts2 = t.appendTrackState();
0524 ts2.predicted().setRandom();
0525 auto ts3 = t.appendTrackState();
0526 ts3.predicted().setRandom();
0527
0528 auto t2 = tc.makeTrack();
0529 t2.copyFromShallow(t);
0530
0531 BOOST_CHECK_NE(t.index(), t2.index());
0532 BOOST_CHECK_EQUAL(t.nTrackStates(), t2.nTrackStates());
0533
0534 BOOST_CHECK_EQUAL(t.particleHypothesis(), t2.particleHypothesis());
0535 BOOST_CHECK_EQUAL(t.parameters(), t2.parameters());
0536 BOOST_CHECK_EQUAL(t.covariance(), t2.covariance());
0537
0538 BOOST_CHECK_EQUAL(t.referenceSurface().getSharedPtr(),
0539 t2.referenceSurface().getSharedPtr());
0540 BOOST_CHECK_EQUAL(t.tipIndex(), t2.tipIndex());
0541
0542 std::vector<decltype(tc)::TrackStateProxy> trackStates;
0543 for (const auto& ts : t.trackStatesReversed()) {
0544 trackStates.insert(trackStates.begin(), ts);
0545 }
0546
0547 auto t2_ts1 = trackStates.at(0);
0548 auto t2_ts2 = trackStates.at(1);
0549 auto t2_ts3 = trackStates.at(2);
0550
0551 BOOST_CHECK_EQUAL(t2_ts1.predicted(), ts1.predicted());
0552 BOOST_CHECK_EQUAL(t2_ts1.index(), ts1.index());
0553 BOOST_CHECK_EQUAL(t2_ts2.predicted(), ts2.predicted());
0554 BOOST_CHECK_EQUAL(t2_ts2.index(), ts2.index());
0555 BOOST_CHECK_EQUAL(t2_ts3.predicted(), ts3.predicted());
0556 BOOST_CHECK_EQUAL(t2_ts3.index(), ts3.index());
0557 }
0558
0559 BOOST_AUTO_TEST_SUITE_END()
0560
0561 }