Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-19 07:58:54

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Definitions/Units.hpp"
0012 #include "Acts/EventData/ProxyAccessor.hpp"
0013 #include "Acts/EventData/VectorMultiTrajectory.hpp"
0014 #include "Acts/EventData/VectorTrackContainer.hpp"
0015 #include "Acts/Surfaces/CurvilinearSurface.hpp"
0016 #include "Acts/Surfaces/PlaneSurface.hpp"
0017 #include "Acts/Utilities/Diagnostics.hpp"
0018 #include "Acts/Utilities/Zip.hpp"
0019 
0020 #include <algorithm>
0021 #include <numeric>
0022 
0023 using namespace Acts;
0024 using namespace Acts::HashedStringLiteral;
0025 using MultiTrajectoryTraits::IndexType;
0026 using namespace Acts::UnitLiterals;
0027 
0028 template <typename track_container_t, typename traj_t,
0029           template <typename> class holder_t>
0030 struct Factory {};
0031 
0032 template <typename track_container_t, typename traj_t>
0033 struct Factory<track_container_t, traj_t, detail::RefHolder> {
0034   using track_container_type =
0035       TrackContainer<track_container_t, traj_t, detail::RefHolder>;
0036 
0037   track_container_t vtc;
0038   traj_t mtj;
0039   track_container_type tc{vtc, mtj};
0040 
0041   auto& trackContainer() { return tc; }
0042   auto& trackStateContainer() { return mtj; }
0043   auto& backend() { return vtc; }
0044 };
0045 
0046 template <typename track_container_t, typename traj_t>
0047 struct Factory<track_container_t, traj_t, detail::ValueHolder> {
0048   using track_container_type =
0049       TrackContainer<track_container_t, traj_t, detail::ValueHolder>;
0050 
0051   track_container_type tc{track_container_t{}, traj_t{}};
0052 
0053   auto& trackContainer() { return tc; }
0054   auto& trackStateContainer() { return tc.trackStateContainer(); }
0055   auto& backend() { return tc.container(); }
0056 };
0057 
0058 template <typename track_container_t, typename traj_t>
0059 struct Factory<track_container_t, traj_t, std::shared_ptr> {
0060   using track_container_type =
0061       TrackContainer<track_container_t, traj_t, std::shared_ptr>;
0062 
0063   std::shared_ptr<track_container_t> vtc{std::make_shared<track_container_t>()};
0064   std::shared_ptr<traj_t> mtj{std::make_shared<traj_t>()};
0065   track_container_type tc{vtc, mtj};
0066 
0067   auto& trackContainer() { return tc; }
0068   auto& trackStateContainer() { return *mtj; }
0069   auto& backend() { return *vtc; }
0070 };
0071 
0072 template <typename track_container_t, typename traj_t,
0073           template <typename> class... holders>
0074 using holder_types_t =
0075     std::tuple<Factory<track_container_t, traj_t, holders>...>;
0076 
0077 using holder_types = holder_types_t<VectorTrackContainer, VectorMultiTrajectory,
0078                                     // detail_tc::ValueHolder,
0079                                     // detail_tc::RefHolder,
0080                                     std::shared_ptr>;
0081 
0082 using const_holder_types =
0083     holder_types_t<ConstVectorTrackContainer, ConstVectorMultiTrajectory,
0084                    detail::ValueHolder, detail::RefHolder, std::shared_ptr>;
0085 
0086 namespace ActsTests {
0087 
0088 BOOST_AUTO_TEST_SUITE(EventDataSuite)
0089 
0090 BOOST_AUTO_TEST_CASE(BuildDefaultHolder) {
0091   VectorMultiTrajectory mtj{};
0092   VectorTrackContainer vtc{};
0093   TrackContainer tc{vtc, mtj};
0094 
0095   static_assert(
0096       std::is_same_v<decltype(tc),
0097                      TrackContainer<VectorTrackContainer, VectorMultiTrajectory,
0098                                     detail::RefHolder>>,
0099       "Incorrect deduced type");
0100   BOOST_CHECK_EQUAL(&mtj, &tc.trackStateContainer());
0101   BOOST_CHECK_EQUAL(&vtc, &tc.container());
0102   tc.addTrack();
0103 
0104   std::decay_t<decltype(tc)> copy = tc;
0105   BOOST_CHECK_EQUAL(&mtj, &copy.trackStateContainer());
0106   BOOST_CHECK_EQUAL(&vtc, &copy.container());
0107 }
0108 
0109 BOOST_AUTO_TEST_CASE(BuildValueHolder) {
0110   {
0111     VectorMultiTrajectory mtj{};
0112     VectorTrackContainer vtc{};
0113     TrackContainer tc{std::move(vtc), std::move(mtj)};
0114     static_assert(
0115         std::is_same_v<decltype(tc), TrackContainer<VectorTrackContainer,
0116                                                     VectorMultiTrajectory,
0117                                                     detail::ValueHolder>>,
0118         "Incorrect deduced type");
0119     std::decay_t<decltype(tc)> copy = tc;
0120     BOOST_CHECK_NE(&tc.trackStateContainer(), &copy.trackStateContainer());
0121     BOOST_CHECK_NE(&tc.container(), &copy.container());
0122   }
0123   {
0124     TrackContainer tc{VectorTrackContainer{}, VectorMultiTrajectory{}};
0125 
0126     static_assert(
0127         std::is_same_v<decltype(tc), TrackContainer<VectorTrackContainer,
0128                                                     VectorMultiTrajectory,
0129                                                     detail::ValueHolder>>,
0130         "Incorrect deduced type");
0131     tc.addTrack();
0132     std::decay_t<decltype(tc)> copy = tc;
0133     BOOST_CHECK_NE(&tc.trackStateContainer(), &copy.trackStateContainer());
0134     BOOST_CHECK_NE(&tc.container(), &copy.container());
0135   }
0136 }
0137 
0138 BOOST_AUTO_TEST_CASE(BuildRefHolder) {
0139   VectorMultiTrajectory mtj{};
0140   VectorTrackContainer vtc{};
0141   TrackContainer<VectorTrackContainer, VectorMultiTrajectory, detail::RefHolder>
0142       tc{vtc, mtj};
0143 
0144   static_assert(
0145       std::is_same_v<decltype(tc),
0146                      TrackContainer<VectorTrackContainer, VectorMultiTrajectory,
0147                                     detail::RefHolder>>,
0148       "Incorrect deduced type");
0149   BOOST_CHECK_EQUAL(&mtj, &tc.trackStateContainer());
0150   BOOST_CHECK_EQUAL(&vtc, &tc.container());
0151   tc.addTrack();
0152   std::decay_t<decltype(tc)> copy = tc;
0153   BOOST_CHECK_EQUAL(&mtj, &copy.trackStateContainer());
0154   BOOST_CHECK_EQUAL(&vtc, &copy.container());
0155 }
0156 
0157 BOOST_AUTO_TEST_CASE(BuildSharedPtr) {
0158   auto mtj = std::make_shared<VectorMultiTrajectory>();
0159   auto vtc = std::make_shared<VectorTrackContainer>();
0160   TrackContainer<VectorTrackContainer, VectorMultiTrajectory, std::shared_ptr>
0161       tc{vtc, mtj};
0162 
0163   static_assert(
0164       std::is_same_v<decltype(tc),
0165                      TrackContainer<VectorTrackContainer, VectorMultiTrajectory,
0166                                     std::shared_ptr>>,
0167       "Incorrect deduced type");
0168   BOOST_CHECK_EQUAL(mtj.get(), &tc.trackStateContainer());
0169   BOOST_CHECK_EQUAL(vtc.get(), &tc.container());
0170   tc.addTrack();
0171   std::decay_t<decltype(tc)> copy = tc;
0172   BOOST_CHECK_EQUAL(mtj.get(), &copy.trackStateContainer());
0173   BOOST_CHECK_EQUAL(vtc.get(), &copy.container());
0174 }
0175 
0176 BOOST_AUTO_TEST_CASE(BuildConvenience) {
0177   VectorMultiTrajectory mtj{};
0178   VectorTrackContainer vtc{};
0179   TrackContainer tc{vtc, mtj};
0180 
0181   BOOST_CHECK_EQUAL(tc.size(), 0);
0182   auto track1 = tc.makeTrack();
0183   BOOST_CHECK_EQUAL(tc.size(), 1);
0184   auto track2 = tc.makeTrack();
0185   BOOST_CHECK_EQUAL(tc.size(), 2);
0186 
0187   BOOST_CHECK_EQUAL(track1.index(), 0);
0188   BOOST_CHECK_EQUAL(track2.index(), 1);
0189 }
0190 
0191 BOOST_AUTO_TEST_CASE_TEMPLATE(Build, factory_t, holder_types) {
0192   factory_t factory;
0193 
0194   auto& tc = factory.trackContainer();
0195 
0196   static_assert(std::is_same_v<std::decay_t<decltype(tc)>,
0197                                typename factory_t::track_container_type>,
0198                 "Incorrect deduction");
0199 
0200   static_assert(!std::decay_t<decltype(tc)>::ReadOnly,
0201                 "Should not be read only");
0202   BOOST_CHECK(!tc.ReadOnly);
0203 
0204   auto idx = tc.addTrack();
0205   auto t = tc.getTrack(idx);
0206   auto t2 = tc.getTrack(idx);
0207   t.template component<IndexType, "tipIndex"_hash>() = 5;
0208 
0209   BOOST_CHECK_EQUAL((t.template component<IndexType, "tipIndex"_hash>()), 5);
0210   BOOST_CHECK_EQUAL(t.tipIndex(), 5);
0211   t.tipIndex() = 6;
0212   BOOST_CHECK_EQUAL(t.tipIndex(), 6);
0213 
0214   BoundVector pars;
0215   pars.setRandom();
0216   t.parameters() = pars;
0217   BOOST_CHECK_EQUAL(t.parameters(), pars);
0218 
0219   BoundMatrix cov;
0220   cov.setRandom();
0221   t.covariance() = cov;
0222   BOOST_CHECK_EQUAL(t.covariance(), cov);
0223 
0224   std::shared_ptr<PlaneSurface> surface =
0225       CurvilinearSurface(Vector3{-3_m, 0., 0.}, Vector3{1., 0., 0})
0226           .planeSurface();
0227 
0228   t.setReferenceSurface(surface);
0229   BOOST_CHECK_EQUAL(surface.get(), &t.referenceSurface());
0230 
0231   ProxyAccessor<unsigned int> accNMeasuements("nMeasurements");
0232   ConstProxyAccessor<unsigned int> caccNMeasuements("nMeasurements");
0233 
0234   t.nMeasurements() = 42;
0235   BOOST_CHECK_EQUAL(t2.nMeasurements(), 42);
0236   BOOST_CHECK_EQUAL(accNMeasuements(t), 42);
0237   accNMeasuements(t) = 89;
0238   BOOST_CHECK_EQUAL(t2.nMeasurements(), 89);
0239   BOOST_CHECK_EQUAL(caccNMeasuements(t), 89);
0240 
0241   // Test hasColumn functionality
0242   BOOST_CHECK(accNMeasuements.hasColumn(t));
0243   BOOST_CHECK(caccNMeasuements.hasColumn(t));
0244 
0245   ProxyAccessor<std::string> accNonExistent("nonExistentColumn");
0246   ConstProxyAccessor<std::string> caccNonExistent("nonExistentColumn");
0247   BOOST_CHECK(!accNonExistent.hasColumn(t));
0248   BOOST_CHECK(!caccNonExistent.hasColumn(t));
0249 
0250   // does not compile
0251   // caccNMeasuements(t) = 66;
0252 
0253   t2.nHoles() = 67;
0254   BOOST_CHECK_EQUAL(t.nHoles(), 67);
0255 
0256   t2.nOutliers() = 68;
0257   BOOST_CHECK_EQUAL(t.nOutliers(), 68);
0258 
0259   t2.nSharedHits() = 69;
0260   BOOST_CHECK_EQUAL(t.nSharedHits(), 69);
0261 
0262   t2.chi2() = 555.0;
0263   BOOST_CHECK_EQUAL(t2.chi2(), 555.0);
0264 
0265   t2.nDoF() = 123;
0266   BOOST_CHECK_EQUAL(t2.nDoF(), 123);
0267 
0268   // const checks: should not compile
0269   // const auto& ctc = tc;
0270   // ctc.getTrack(idx).covariance().setRandom();
0271   // const auto& ctp = t;
0272   // ctp.covariance().setRandom();
0273 }
0274 
0275 BOOST_AUTO_TEST_CASE(CopyTracksIncludingDynamicColumns) {
0276   // mutable source
0277   VectorTrackContainer vtc{};
0278   VectorMultiTrajectory mtj{};
0279   TrackContainer tc{vtc, mtj};
0280   tc.addColumn<std::size_t>("counter");
0281   tc.addColumn<bool>("odd");
0282   mtj.addColumn<std::size_t>("ts_counter");
0283   mtj.addColumn<bool>("ts_odd");
0284 
0285   TrackContainer tc2{VectorTrackContainer{}, VectorMultiTrajectory{}};
0286   // doesn't have the dynamic column
0287 
0288   VectorTrackContainer vtc3{};
0289   VectorMultiTrajectory mtj3{};
0290   mtj3.addColumn<std::size_t>("ts_counter");
0291   mtj3.addColumn<bool>("ts_odd");
0292 
0293   TrackContainer tc3{vtc3, mtj3};
0294 
0295   tc3.addColumn<std::size_t>("counter");
0296   tc3.addColumn<bool>("odd");
0297 
0298   for (std::size_t i = 0; i < 10; i++) {
0299     auto t = tc.makeTrack();
0300     auto ts = t.appendTrackState();
0301     ts.predicted() = BoundVector::Ones();
0302     ts.component<std::size_t, "ts_counter"_hash>() = i;
0303 
0304     ts = t.appendTrackState();
0305     ts.predicted().setOnes();
0306     ts.predicted() *= 2;
0307     ts.component<std::size_t, "ts_counter"_hash>() = i + 1;
0308 
0309     ts = t.appendTrackState();
0310     ts.predicted().setOnes();
0311     ts.predicted() *= 3;
0312     ts.component<std::size_t, "ts_counter"_hash>() = i + 2;
0313 
0314     t.template component<std::size_t>("counter") = i;
0315     t.template component<bool>("odd") = i % 2 == 0;
0316 
0317     auto t2 = tc2.makeTrack();
0318     BOOST_CHECK_THROW(t2.copyFrom(t),
0319                       std::invalid_argument);  // this should fail
0320 
0321     auto t3 = tc3.makeTrack();
0322     t3.copyFrom(t);  // this should work
0323 
0324     BOOST_CHECK_NE(t3.tipIndex(), MultiTrajectoryTraits::kInvalid);
0325     BOOST_CHECK_GT(t3.nTrackStates(), 0);
0326     BOOST_REQUIRE_EQUAL(t.nTrackStates(), t3.nTrackStates());
0327 
0328     for (auto [tsa, tsb] :
0329          zip(t.trackStatesReversed(), t3.trackStatesReversed())) {
0330       BOOST_CHECK_EQUAL(tsa.predicted(), tsb.predicted());
0331 
0332       BOOST_CHECK_EQUAL(
0333           (tsa.template component<std::size_t, "ts_counter"_hash>()),
0334           (tsb.template component<std::size_t, "ts_counter"_hash>()));
0335 
0336       BOOST_CHECK_EQUAL((tsa.template component<bool, "ts_odd"_hash>()),
0337                         (tsb.template component<bool, "ts_odd"_hash>()));
0338     }
0339 
0340     BOOST_CHECK_EQUAL(t.template component<std::size_t>("counter"),
0341                       t3.template component<std::size_t>("counter"));
0342     BOOST_CHECK_EQUAL(t.template component<bool>("odd"),
0343                       t3.template component<bool>("odd"));
0344   }
0345 
0346   std::size_t before = mtj.size();
0347   TrackContainer tc4{ConstVectorTrackContainer{vtc},
0348                      ConstVectorMultiTrajectory{mtj}};
0349 
0350   BOOST_REQUIRE_EQUAL(tc4.trackStateContainer().size(), before);
0351 
0352   VectorTrackContainer vtc5{};
0353   VectorMultiTrajectory mtj5{};
0354   mtj5.addColumn<std::size_t>("ts_counter");
0355   mtj5.addColumn<bool>("ts_odd");
0356 
0357   TrackContainer tc5{vtc5, mtj5};
0358   tc5.addColumn<std::size_t>("counter");
0359   tc5.addColumn<bool>("odd");
0360 
0361   for (std::size_t i = 0; i < 10; i++) {
0362     auto t4 = tc4.getTrack(i);  // const source!
0363     BOOST_CHECK_NE(t4.nTrackStates(), 0);
0364 
0365     auto t5 = tc5.makeTrack();
0366     t5.copyFrom(t4);  // this should work
0367 
0368     BOOST_CHECK_NE(t5.tipIndex(), MultiTrajectoryTraits::kInvalid);
0369     BOOST_CHECK_GT(t5.nTrackStates(), 0);
0370     BOOST_REQUIRE_EQUAL(t4.nTrackStates(), t5.nTrackStates());
0371 
0372     for (auto [tsa, tsb] :
0373          zip(t4.trackStatesReversed(), t5.trackStatesReversed())) {
0374       BOOST_CHECK_EQUAL(tsa.predicted(), tsb.predicted());
0375     }
0376 
0377     BOOST_CHECK_EQUAL(t4.template component<std::size_t>("counter"),
0378                       t5.template component<std::size_t>("counter"));
0379     BOOST_CHECK_EQUAL(t4.template component<bool>("odd"),
0380                       t5.template component<bool>("odd"));
0381   }
0382 }
0383 
0384 BOOST_AUTO_TEST_CASE(ReverseTrackStates) {
0385   VectorTrackContainer vtc{};
0386   VectorMultiTrajectory mtj{};
0387   TrackContainer tc{vtc, mtj};
0388 
0389   auto t = tc.makeTrack();
0390 
0391   for (std::size_t i = 0; i < 4; i++) {
0392     auto ts = t.appendTrackState();
0393     ts.jacobian() = BoundMatrix::Identity() * i;
0394   }
0395 
0396   std::vector<IndexType> exp;
0397   exp.resize(t.nTrackStates());
0398   std::iota(exp.rbegin(), exp.rend(), 0);
0399   std::vector<IndexType> act;
0400   std::transform(t.trackStatesReversed().begin(), t.trackStatesReversed().end(),
0401                  std::back_inserter(act),
0402                  [](const auto& ts) { return ts.index(); });
0403 
0404   // jacobians count up
0405   for (const auto [e, ts] : zip(exp, t.trackStatesReversed())) {
0406     BOOST_CHECK_EQUAL(ts.jacobian(), BoundMatrix::Identity() * e);
0407   }
0408 
0409   BOOST_CHECK_EQUAL_COLLECTIONS(exp.begin(), exp.end(), act.begin(), act.end());
0410 
0411   // reverse!
0412   t.reverseTrackStates();
0413 
0414   std::iota(exp.begin(), exp.end(), 0);
0415   act.clear();
0416   std::transform(t.trackStatesReversed().begin(), t.trackStatesReversed().end(),
0417                  std::back_inserter(act),
0418                  [](const auto& ts) { return ts.index(); });
0419   BOOST_CHECK_EQUAL_COLLECTIONS(exp.begin(), exp.end(), act.begin(), act.end());
0420 
0421   // jacobians stay with their track states
0422   for (const auto [e, ts] : zip(exp, t.trackStatesReversed())) {
0423     BOOST_CHECK_EQUAL(ts.jacobian(), BoundMatrix::Identity() * e);
0424   }
0425 
0426   // back to original!
0427   t.reverseTrackStates();
0428 
0429   // jacobians stay with their track states
0430   for (const auto [e, ts] : zip(exp, t.trackStates())) {
0431     BOOST_CHECK_EQUAL(ts.jacobian(), BoundMatrix::Identity() * e);
0432   }
0433 
0434   // reverse with jacobians
0435   t.reverseTrackStates(true);
0436 
0437   std::ranges::reverse(exp);
0438   std::rotate(exp.rbegin(), std::next(exp.rbegin()), exp.rend());
0439 
0440   for (const auto [e, ts] : zip(exp, t.trackStates())) {
0441     Acts::BoundMatrix expJac;
0442     if (e == 0) {
0443       expJac = BoundMatrix::Zero();
0444     } else {
0445       expJac = (BoundMatrix::Identity() * e).inverse();
0446     }
0447 
0448     BOOST_CHECK_EQUAL(ts.jacobian(), expJac);
0449   }
0450 
0451   // now back to original order, revert jacobians again
0452   t.reverseTrackStates(true);
0453 
0454   // reset exp to range(0, N)
0455   std::iota(exp.begin(), exp.end(), 0);
0456 
0457   for (const auto [e, ts] : zip(exp, t.trackStates())) {
0458     BOOST_CHECK_EQUAL(ts.jacobian(), BoundMatrix::Identity() * e);
0459   }
0460 }
0461 
0462 BOOST_AUTO_TEST_CASE(CopyTrackProxyCalibrated) {
0463   VectorTrackContainer vtc{};
0464   VectorMultiTrajectory mtj{};
0465   TrackContainer tc{vtc, mtj};
0466 
0467   constexpr static std::size_t kMeasurementSize = 3;
0468 
0469   auto track1 = tc.makeTrack();
0470   auto ts = track1.appendTrackState(TrackStatePropMask::Calibrated);
0471   ts.allocateCalibrated(kMeasurementSize);
0472   ts.setProjectorSubspaceIndices(BoundSubspaceIndices{});
0473 
0474   auto tsCopy = track1.appendTrackState(TrackStatePropMask::Calibrated);
0475   tsCopy.copyFrom(ts, TrackStatePropMask::Calibrated, false);
0476 
0477   BOOST_CHECK_EQUAL(ts.calibratedSize(), tsCopy.calibratedSize());
0478 }
0479 
0480 BOOST_AUTO_TEST_CASE(ProxyAccessorHasColumn) {
0481   VectorTrackContainer vtc{};
0482   VectorMultiTrajectory mtj{};
0483   TrackContainer tc{vtc, mtj};
0484 
0485   // Add a custom column to the track state container
0486   mtj.addColumn<float>("customFloat");
0487   // Add a custom column to the track container
0488   tc.addColumn<std::string>("customString");
0489 
0490   auto track = tc.makeTrack();
0491   auto ts = track.appendTrackState(TrackStatePropMask::Predicted);
0492   ts.predicted() = BoundVector::Zero();
0493 
0494   // Set values in the custom columns
0495   ts.component<float>("customFloat") = 42.5f;
0496   track.component<std::string>("customString") = "test";
0497 
0498   // Test ALL known track container columns
0499   // From VectorTrackContainer.hpp hasColumn_impl
0500   BOOST_CHECK(ConstProxyAccessor<IndexType>("tipIndex").hasColumn(track));
0501   BOOST_CHECK(ConstProxyAccessor<IndexType>("stemIndex").hasColumn(track));
0502   BOOST_CHECK(ConstProxyAccessor<BoundVector>("params").hasColumn(track));
0503   BOOST_CHECK(ConstProxyAccessor<BoundMatrix>("cov").hasColumn(track));
0504   BOOST_CHECK(
0505       ConstProxyAccessor<unsigned int>("nMeasurements").hasColumn(track));
0506   BOOST_CHECK(ConstProxyAccessor<unsigned int>("nHoles").hasColumn(track));
0507   BOOST_CHECK(ConstProxyAccessor<float>("chi2").hasColumn(track));
0508   BOOST_CHECK(ConstProxyAccessor<unsigned int>("ndf").hasColumn(track));
0509   BOOST_CHECK(ConstProxyAccessor<unsigned int>("nOutliers").hasColumn(track));
0510   BOOST_CHECK(ConstProxyAccessor<unsigned int>("nSharedHits").hasColumn(track));
0511 
0512   // Test custom track container column
0513   BOOST_CHECK(ConstProxyAccessor<std::string>("customString").hasColumn(track));
0514 
0515   // Test ALL known track state columns
0516   // From VectorMultiTrajectory.hpp hasColumn_impl
0517   BOOST_CHECK(ConstProxyAccessor<IndexType>("previous").hasColumn(ts));
0518   BOOST_CHECK(ConstProxyAccessor<IndexType>("next").hasColumn(ts));
0519   BOOST_CHECK(ConstProxyAccessor<IndexType>("predicted").hasColumn(ts));
0520   BOOST_CHECK(ConstProxyAccessor<IndexType>("filtered").hasColumn(ts));
0521   BOOST_CHECK(ConstProxyAccessor<IndexType>("smoothed").hasColumn(ts));
0522   BOOST_CHECK(ConstProxyAccessor<IndexType>("calibrated").hasColumn(ts));
0523   BOOST_CHECK(ConstProxyAccessor<IndexType>("calibratedCov").hasColumn(ts));
0524   BOOST_CHECK(ConstProxyAccessor<IndexType>("jacobian").hasColumn(ts));
0525   BOOST_CHECK(ConstProxyAccessor<IndexType>("projector").hasColumn(ts));
0526   BOOST_CHECK(
0527       ConstProxyAccessor<std::optional<SourceLink>>("uncalibratedSourceLink")
0528           .hasColumn(ts));
0529   BOOST_CHECK(
0530       ConstProxyAccessor<std::shared_ptr<const Surface>>("referenceSurface")
0531           .hasColumn(ts));
0532   BOOST_CHECK(ConstProxyAccessor<std::uint8_t>("measdim").hasColumn(ts));
0533   BOOST_CHECK(ConstProxyAccessor<float>("chi2").hasColumn(ts));
0534   BOOST_CHECK(ConstProxyAccessor<double>("pathLength").hasColumn(ts));
0535   BOOST_CHECK(
0536       ConstProxyAccessor<TrackStateType::raw_type>("typeFlags").hasColumn(ts));
0537 
0538   // Test custom track state column
0539   BOOST_CHECK(ConstProxyAccessor<float>("customFloat").hasColumn(ts));
0540 
0541   // Test with non-existent columns
0542   BOOST_CHECK(!ConstProxyAccessor<int>("nonExistentColumn").hasColumn(ts));
0543   BOOST_CHECK(!ConstProxyAccessor<std::string>("nonExistentTrackColumn")
0544                    .hasColumn(track));
0545 
0546   // Test that we can actually access the custom columns
0547   ProxyAccessor<float> accCustomFloat("customFloat");
0548   ConstProxyAccessor<float> caccCustomFloat("customFloat");
0549   BOOST_CHECK_EQUAL(accCustomFloat(ts), 42.5f);
0550   BOOST_CHECK_EQUAL(caccCustomFloat(ts), 42.5f);
0551 
0552   ProxyAccessor<std::string> accCustomString("customString");
0553   ConstProxyAccessor<std::string> caccCustomString("customString");
0554   BOOST_CHECK_EQUAL(accCustomString(track), "test");
0555   BOOST_CHECK_EQUAL(caccCustomString(track), "test");
0556 }
0557 
0558 consteval ProxyAccessor<int> makeProxyAccessor() {
0559   return ProxyAccessor<int>("test_consteval");
0560 }
0561 
0562 BOOST_AUTO_TEST_CASE(ProxyAccessorConstexprConstruction) {
0563   static_assert(ProxyAccessor<int>("test").key == "test"_hash,
0564                 "ProxyAccessor should be constructible with a string key");
0565 
0566   constexpr auto acc = makeProxyAccessor();
0567 
0568   static_assert(acc.key == "test_consteval"_hash,
0569                 "ProxyAccessor should be constructible at compile time");
0570 }
0571 
0572 BOOST_AUTO_TEST_CASE(CopyFromWithoutStatesInvalidatesIndices) {
0573   VectorTrackContainer vtc{};
0574   VectorMultiTrajectory mtj{};
0575   TrackContainer tc{vtc, mtj};
0576 
0577   // Create source track with track states
0578   auto sourceTrack = tc.makeTrack();
0579   sourceTrack.appendTrackState();
0580   sourceTrack.appendTrackState();
0581   sourceTrack.appendTrackState();
0582   sourceTrack.linkForward();
0583 
0584   // Verify source track has valid indices
0585   BOOST_CHECK_NE(sourceTrack.tipIndex(), MultiTrajectoryTraits::kInvalid);
0586   BOOST_CHECK_NE(sourceTrack.stemIndex(), MultiTrajectoryTraits::kInvalid);
0587   BOOST_CHECK_EQUAL(sourceTrack.nTrackStates(), 3);
0588 
0589   // Set some track properties
0590   sourceTrack.nMeasurements() = 42;
0591   sourceTrack.nHoles() = 5;
0592   sourceTrack.chi2() = 123.45f;
0593 
0594   // Create destination track that also has track states initially
0595   auto destTrack = tc.makeTrack();
0596   destTrack.appendTrackState();
0597   destTrack.appendTrackState();
0598   destTrack.linkForward();
0599 
0600   // Verify destination has valid indices before copy
0601   BOOST_CHECK_NE(destTrack.tipIndex(), MultiTrajectoryTraits::kInvalid);
0602   BOOST_CHECK_NE(destTrack.stemIndex(), MultiTrajectoryTraits::kInvalid);
0603   BOOST_CHECK_EQUAL(destTrack.nTrackStates(), 2);
0604 
0605   // Copy without states
0606   destTrack.copyFromWithoutStates(sourceTrack);
0607 
0608   // Verify that tip and stem indices are now invalid
0609   BOOST_CHECK_EQUAL(destTrack.tipIndex(), MultiTrajectoryTraits::kInvalid);
0610   BOOST_CHECK_EQUAL(destTrack.stemIndex(), MultiTrajectoryTraits::kInvalid);
0611 
0612   // Verify that track properties were copied
0613   BOOST_CHECK_EQUAL(destTrack.nMeasurements(), 42);
0614   BOOST_CHECK_EQUAL(destTrack.nHoles(), 5);
0615   BOOST_CHECK_EQUAL(destTrack.chi2(), 123.45f);
0616 
0617   // Verify that nTrackStates returns 0 since indices are invalid
0618   BOOST_CHECK_EQUAL(destTrack.nTrackStates(), 0);
0619 
0620   // Verify that the original track states are still in the container
0621   // but not accessible through the destination track
0622   BOOST_CHECK_EQUAL(sourceTrack.nTrackStates(), 3);
0623   BOOST_CHECK_NE(sourceTrack.tipIndex(), MultiTrajectoryTraits::kInvalid);
0624 }
0625 
0626 BOOST_AUTO_TEST_CASE(CopyFromDeepCopyFunctionality) {
0627   VectorTrackContainer vtc{};
0628   VectorMultiTrajectory mtj{};
0629   TrackContainer tc{vtc, mtj};
0630 
0631   // Create source track with track states and set unique data
0632   auto sourceTrack = tc.makeTrack();
0633 
0634   // Set track-level properties
0635   sourceTrack.nMeasurements() = 15;
0636   sourceTrack.nHoles() = 3;
0637   sourceTrack.nOutliers() = 2;
0638   sourceTrack.chi2() = 42.5f;
0639   sourceTrack.nDoF() = 10;
0640 
0641   // Create track states with distinctive predicted parameters
0642   auto ts1 = sourceTrack.appendTrackState();
0643   ts1.predicted() = BoundVector::Ones() * 1.0;
0644 
0645   auto ts2 = sourceTrack.appendTrackState();
0646   ts2.predicted() = BoundVector::Ones() * 2.0;
0647 
0648   auto ts3 = sourceTrack.appendTrackState();
0649   ts3.predicted() = BoundVector::Ones() * 3.0;
0650 
0651   // Verify source track setup
0652   BOOST_CHECK_EQUAL(sourceTrack.nTrackStates(), 3);
0653 
0654   // Create destination track and perform deep copy
0655   auto destTrack = tc.makeTrack();
0656   destTrack.copyFrom(sourceTrack);
0657 
0658   // Verify track-level properties were copied
0659   BOOST_CHECK_EQUAL(destTrack.nMeasurements(), 15);
0660   BOOST_CHECK_EQUAL(destTrack.nHoles(), 3);
0661   BOOST_CHECK_EQUAL(destTrack.nOutliers(), 2);
0662   BOOST_CHECK_EQUAL(destTrack.chi2(), 42.5f);
0663   BOOST_CHECK_EQUAL(destTrack.nDoF(), 10);
0664 
0665   // Verify track state structure
0666   BOOST_CHECK_EQUAL(destTrack.nTrackStates(), 3);
0667   BOOST_CHECK_NE(destTrack.tipIndex(), MultiTrajectoryTraits::kInvalid);
0668   BOOST_CHECK_NE(destTrack.stemIndex(), MultiTrajectoryTraits::kInvalid);
0669 
0670   // Verify track is forward-linked (can iterate forward)
0671   BOOST_CHECK(destTrack.innermostTrackState().has_value());
0672 
0673   // Verify track state data was copied correctly (order preserved)
0674   std::vector<BoundVector> sourceParams;
0675   for (const auto& ts : sourceTrack.trackStatesReversed()) {
0676     sourceParams.insert(sourceParams.begin(), ts.predicted());
0677   }
0678 
0679   std::vector<BoundVector> destParams;
0680   for (const auto& ts : destTrack.trackStatesReversed()) {
0681     destParams.insert(destParams.begin(), ts.predicted());
0682   }
0683 
0684   BOOST_REQUIRE_EQUAL(sourceParams.size(), destParams.size());
0685   for (std::size_t i = 0; i < sourceParams.size(); ++i) {
0686     BOOST_CHECK_EQUAL(sourceParams[i], destParams[i]);
0687   }
0688 
0689   // Verify track states have different indices (new track states were created)
0690   std::vector<IndexType> sourceIndices;
0691   for (const auto& ts : sourceTrack.trackStatesReversed()) {
0692     sourceIndices.push_back(ts.index());
0693   }
0694 
0695   std::vector<IndexType> destIndices;
0696   for (const auto& ts : destTrack.trackStatesReversed()) {
0697     destIndices.push_back(ts.index());
0698   }
0699 
0700   BOOST_REQUIRE_EQUAL(sourceIndices.size(), destIndices.size());
0701   for (std::size_t i = 0; i < sourceIndices.size(); ++i) {
0702     BOOST_CHECK_NE(sourceIndices[i], destIndices[i]);
0703   }
0704 
0705   // Verify forward iteration works (result of forward-linking)
0706   std::vector<BoundVector> forwardParams;
0707   for (const auto& ts : destTrack.trackStates()) {
0708     forwardParams.push_back(ts.predicted());
0709   }
0710 
0711   // Forward iteration should give same parameters in same order
0712   BOOST_REQUIRE_EQUAL(destParams.size(), forwardParams.size());
0713   for (std::size_t i = 0; i < destParams.size(); ++i) {
0714     BOOST_CHECK_EQUAL(destParams[i], forwardParams[i]);
0715   }
0716 
0717   // Verify tracks are independent (modifying dest doesn't affect source)
0718   destTrack.nMeasurements() = 99;
0719   BOOST_CHECK_EQUAL(sourceTrack.nMeasurements(), 15);
0720   BOOST_CHECK_EQUAL(destTrack.nMeasurements(), 99);
0721 }
0722 
0723 BOOST_AUTO_TEST_CASE(DeprecatedCopyFromWithBooleanStillWorks) {
0724   VectorTrackContainer vtc{};
0725   VectorMultiTrajectory mtj{};
0726   TrackContainer tc{vtc, mtj};
0727 
0728   // Create source track with track states and properties
0729   auto sourceTrack = tc.makeTrack();
0730   sourceTrack.nMeasurements() = 25;
0731   sourceTrack.chi2() = 78.9f;
0732 
0733   auto ts1 = sourceTrack.appendTrackState();
0734   ts1.predicted() = BoundVector::Ones() * 5.0;
0735   auto ts2 = sourceTrack.appendTrackState();
0736   ts2.predicted() = BoundVector::Ones() * 10.0;
0737 
0738   BOOST_CHECK_EQUAL(sourceTrack.nTrackStates(), 2);
0739 
0740   // Test deprecated copyFrom with copyTrackStates = true
0741   auto destTrack1 = tc.makeTrack();
0742 
0743   ACTS_DIAGNOSTIC_PUSH()
0744   ACTS_DIAGNOSTIC_IGNORE("-Wdeprecated-declarations")
0745 
0746   destTrack1.copyFrom(sourceTrack, true);  // Should do full deep copy
0747 
0748   ACTS_DIAGNOSTIC_POP()
0749 
0750   // Verify it worked like the non-boolean copyFrom
0751   BOOST_CHECK_EQUAL(destTrack1.nMeasurements(), 25);
0752   BOOST_CHECK_EQUAL(destTrack1.chi2(), 78.9f);
0753   BOOST_CHECK_EQUAL(destTrack1.nTrackStates(), 2);
0754   BOOST_CHECK_NE(destTrack1.tipIndex(), MultiTrajectoryTraits::kInvalid);
0755   BOOST_CHECK_NE(destTrack1.stemIndex(), MultiTrajectoryTraits::kInvalid);
0756 
0757   // Verify track states were copied (different indices, same data)
0758   std::vector<BoundVector> sourceParams, destParams;
0759   for (const auto& ts : sourceTrack.trackStatesReversed()) {
0760     sourceParams.insert(sourceParams.begin(), ts.predicted());
0761   }
0762   for (const auto& ts : destTrack1.trackStatesReversed()) {
0763     destParams.insert(destParams.begin(), ts.predicted());
0764   }
0765 
0766   BOOST_REQUIRE_EQUAL(sourceParams.size(), destParams.size());
0767   for (std::size_t i = 0; i < sourceParams.size(); ++i) {
0768     BOOST_CHECK_EQUAL(sourceParams[i], destParams[i]);
0769   }
0770 
0771   // Test deprecated copyFrom with copyTrackStates = false
0772   auto destTrack2 = tc.makeTrack();
0773   destTrack2.appendTrackState();  // Add some initial track states
0774   destTrack2.appendTrackState();
0775   destTrack2.linkForward();
0776 
0777   ACTS_DIAGNOSTIC_PUSH()
0778   ACTS_DIAGNOSTIC_IGNORE("-Wdeprecated-declarations")
0779 
0780   destTrack2.copyFrom(sourceTrack,
0781                       false);  // Should behave like copyFromWithoutStates
0782 
0783   ACTS_DIAGNOSTIC_POP()
0784 
0785   // The deprecated method with false should behave like copyFromWithoutStates:
0786   // - Copy track properties
0787   // - Invalidate tip and stem indices
0788   // - Leave existing track states in container but inaccessible
0789 
0790   // Track properties should be copied
0791   BOOST_CHECK_EQUAL(destTrack2.nMeasurements(), 25);
0792   BOOST_CHECK_EQUAL(destTrack2.chi2(), 78.9f);
0793 
0794   // Tip and stem indices should be invalidated
0795   BOOST_CHECK_EQUAL(destTrack2.tipIndex(), 5);
0796   BOOST_CHECK_EQUAL(destTrack2.stemIndex(), 4);
0797 
0798   // nTrackStates should return 0 due to invalid indices
0799   BOOST_CHECK_EQUAL(destTrack2.nTrackStates(), 2);
0800 }
0801 
0802 BOOST_AUTO_TEST_SUITE_END()
0803 
0804 }  // namespace ActsTests