Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-12 07:50:06

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 #pragma once
0010 
0011 #include <boost/test/unit_test.hpp>
0012 
0013 #include "Acts/Definitions/Algebra.hpp"
0014 #include "Acts/Definitions/TrackParametrization.hpp"
0015 #include "Acts/EventData/TrackStatePropMask.hpp"
0016 #include "Acts/EventData/VectorMultiTrajectory.hpp"
0017 #include "Acts/EventData/detail/TestSourceLink.hpp"
0018 #include "Acts/EventData/detail/TestTrackState.hpp"
0019 #include "Acts/Geometry/GeometryContext.hpp"
0020 #include "Acts/Utilities/CalibrationContext.hpp"
0021 #include "Acts/Utilities/HashedString.hpp"
0022 
0023 #include <random>
0024 #include <stdexcept>
0025 
0026 namespace Acts::detail::Test {
0027 
0028 constexpr auto kInvalid = kTrackIndexInvalid;
0029 
0030 template <typename factory_t>
0031 class MultiTrajectoryTestsCommon {
0032   using ParametersVector = BoundTrackParameters::ParametersVector;
0033   using CovarianceMatrix = BoundTrackParameters::CovarianceMatrix;
0034   using Jacobian = BoundMatrix;
0035 
0036   using trajectory_t = typename factory_t::trajectory_t;
0037   using const_trajectory_t = typename factory_t::const_trajectory_t;
0038 
0039  private:
0040   factory_t m_factory;
0041 
0042  public:
0043   void testBuild() {
0044     constexpr TrackStatePropMask kMask = TrackStatePropMask::Predicted;
0045 
0046     // construct trajectory w/ multiple components
0047     trajectory_t t = m_factory.create();
0048 
0049     auto i0 = t.addTrackState(kMask);
0050     // trajectory bifurcates here into multiple hypotheses
0051     auto i1a = t.addTrackState(kMask, i0);
0052     auto i1b = t.addTrackState(kMask, i0);
0053     auto i2a = t.addTrackState(kMask, i1a);
0054     auto i2b = t.addTrackState(kMask, i1b);
0055 
0056     // print each trajectory component
0057     std::vector<std::size_t> act;
0058     auto collect = [&](auto p) {
0059       act.push_back(p.index());
0060       BOOST_CHECK(!p.hasCalibrated());
0061       BOOST_CHECK(!p.hasFiltered());
0062       BOOST_CHECK(!p.hasSmoothed());
0063       BOOST_CHECK(!p.hasJacobian());
0064       BOOST_CHECK(!p.hasProjector());
0065     };
0066 
0067     std::vector<std::size_t> exp = {i2a, i1a, i0};
0068     t.visitBackwards(i2a, collect);
0069     BOOST_CHECK_EQUAL_COLLECTIONS(act.begin(), act.end(), exp.begin(),
0070                                   exp.end());
0071 
0072     act.clear();
0073     for (const auto& p : t.reverseTrackStateRange(i2a)) {
0074       act.push_back(p.index());
0075     }
0076     BOOST_CHECK_EQUAL_COLLECTIONS(act.begin(), act.end(), exp.begin(),
0077                                   exp.end());
0078 
0079     act.clear();
0080     exp = {i2b, i1b, i0};
0081     t.visitBackwards(i2b, collect);
0082     BOOST_CHECK_EQUAL_COLLECTIONS(act.begin(), act.end(), exp.begin(),
0083                                   exp.end());
0084 
0085     act.clear();
0086     for (const auto& p : t.reverseTrackStateRange(i2b)) {
0087       act.push_back(p.index());
0088     }
0089     BOOST_CHECK_EQUAL_COLLECTIONS(act.begin(), act.end(), exp.begin(),
0090                                   exp.end());
0091 
0092     act.clear();
0093     t.applyBackwards(i2b, collect);
0094     BOOST_CHECK_EQUAL_COLLECTIONS(act.begin(), act.end(), exp.begin(),
0095                                   exp.end());
0096 
0097     auto r = t.reverseTrackStateRange(i2b);
0098     BOOST_CHECK_EQUAL(std::distance(r.begin(), r.end()), 3);
0099 
0100     // check const-correctness
0101     const auto& ct = t;
0102     std::vector<BoundVector> predicteds;
0103     // mutation in this loop works!
0104     for (auto p : t.reverseTrackStateRange(i2b)) {
0105       predicteds.push_back(BoundVector::Random());
0106       p.predicted() = predicteds.back();
0107     }
0108     std::vector<BoundVector> predictedsAct;
0109     for (const auto& p : ct.reverseTrackStateRange(i2b)) {
0110       predictedsAct.push_back(p.predicted());
0111       // mutation in this loop doesn't work: does not compile
0112       // p.predicted() = BoundVector::Random();
0113     }
0114     BOOST_CHECK_EQUAL_COLLECTIONS(predictedsAct.begin(), predictedsAct.end(),
0115                                   predicteds.begin(), predicteds.end());
0116 
0117     {
0118       trajectory_t t2 = m_factory.create();
0119       auto ts = t2.makeTrackState(kMask);
0120       BOOST_CHECK_EQUAL(t2.size(), 1);
0121       auto ts2 = t2.makeTrackState(kMask, ts.index());
0122       BOOST_CHECK_EQUAL(t2.size(), 2);
0123       BOOST_CHECK_EQUAL(ts.previous(), kInvalid);
0124       BOOST_CHECK_EQUAL(ts2.previous(), ts.index());
0125     }
0126   }
0127 
0128   void testClear() {
0129     constexpr TrackStatePropMask kMask = TrackStatePropMask::Predicted;
0130     trajectory_t t = m_factory.create();
0131     BOOST_CHECK_EQUAL(t.size(), 0);
0132 
0133     auto i0 = t.addTrackState(kMask);
0134     // trajectory bifurcates here into multiple hypotheses
0135     auto i1a = t.addTrackState(kMask, i0);
0136     auto i1b = t.addTrackState(kMask, i0);
0137     t.addTrackState(kMask, i1a);
0138     t.addTrackState(kMask, i1b);
0139 
0140     BOOST_CHECK_EQUAL(t.size(), 5);
0141     t.clear();
0142     BOOST_CHECK_EQUAL(t.size(), 0);
0143   }
0144 
0145   void testApplyWithAbort() {
0146     constexpr TrackStatePropMask kMask = TrackStatePropMask::Predicted;
0147 
0148     // construct trajectory with three components
0149     trajectory_t t = m_factory.create();
0150     auto i0 = t.addTrackState(kMask);
0151     auto i1 = t.addTrackState(kMask, i0);
0152     auto i2 = t.addTrackState(kMask, i1);
0153 
0154     std::size_t n = 0;
0155     t.applyBackwards(i2, [&](const auto&) {
0156       n++;
0157       return false;
0158     });
0159     BOOST_CHECK_EQUAL(n, 1u);
0160 
0161     n = 0;
0162     t.applyBackwards(i2, [&](const auto& ts) {
0163       n++;
0164       if (ts.index() == i1) {
0165         return false;
0166       }
0167       return true;
0168     });
0169     BOOST_CHECK_EQUAL(n, 2u);
0170 
0171     n = 0;
0172     t.applyBackwards(i2, [&](const auto&) {
0173       n++;
0174       return true;
0175     });
0176     BOOST_CHECK_EQUAL(n, 3u);
0177   }
0178 
0179   void testAddTrackStateWithBitMask() {
0180     using PM = TrackStatePropMask;
0181     using namespace Acts::HashedStringLiteral;
0182 
0183     trajectory_t t = m_factory.create();
0184 
0185     auto alwaysPresent = [](auto& ts) {
0186       BOOST_CHECK(ts.template has<"referenceSurface"_hash>());
0187       BOOST_CHECK(ts.template has<"measdim"_hash>());
0188       BOOST_CHECK(ts.template has<"chi2"_hash>());
0189       BOOST_CHECK(ts.template has<"pathLength"_hash>());
0190       BOOST_CHECK(ts.template has<"typeFlags"_hash>());
0191     };
0192 
0193     auto ts = t.getTrackState(t.addTrackState(PM::All));
0194     BOOST_CHECK(ts.hasPredicted());
0195     BOOST_CHECK(ts.hasFiltered());
0196     BOOST_CHECK(ts.hasSmoothed());
0197     BOOST_CHECK(!ts.hasCalibrated());
0198     BOOST_CHECK(ts.hasProjector());
0199     BOOST_CHECK(ts.hasJacobian());
0200     alwaysPresent(ts);
0201     ts.allocateCalibrated(5);
0202     BOOST_CHECK(ts.hasCalibrated());
0203     BOOST_CHECK_EQUAL(ts.template calibrated<5>(), Vector<5>::Zero());
0204     BOOST_CHECK_EQUAL(ts.template calibratedCovariance<5>(),
0205                       SquareMatrix<5>::Zero());
0206 
0207     ts = t.getTrackState(t.addTrackState(PM::None));
0208     BOOST_CHECK(!ts.hasPredicted());
0209     BOOST_CHECK(!ts.hasFiltered());
0210     BOOST_CHECK(!ts.hasSmoothed());
0211     BOOST_CHECK(!ts.hasCalibrated());
0212     BOOST_CHECK(!ts.hasProjector());
0213     BOOST_CHECK(!ts.hasJacobian());
0214     alwaysPresent(ts);
0215 
0216     ts = t.getTrackState(t.addTrackState(PM::Predicted));
0217     BOOST_CHECK(ts.hasPredicted());
0218     BOOST_CHECK(!ts.hasFiltered());
0219     BOOST_CHECK(!ts.hasSmoothed());
0220     BOOST_CHECK(!ts.hasCalibrated());
0221     BOOST_CHECK(!ts.hasProjector());
0222     BOOST_CHECK(!ts.hasJacobian());
0223     alwaysPresent(ts);
0224 
0225     ts = t.getTrackState(t.addTrackState(PM::Filtered));
0226     BOOST_CHECK(!ts.hasPredicted());
0227     BOOST_CHECK(ts.hasFiltered());
0228     BOOST_CHECK(!ts.hasSmoothed());
0229     BOOST_CHECK(!ts.hasCalibrated());
0230     BOOST_CHECK(!ts.hasProjector());
0231     BOOST_CHECK(!ts.hasJacobian());
0232     alwaysPresent(ts);
0233 
0234     ts = t.getTrackState(t.addTrackState(PM::Smoothed));
0235     BOOST_CHECK(!ts.hasPredicted());
0236     BOOST_CHECK(!ts.hasFiltered());
0237     BOOST_CHECK(ts.hasSmoothed());
0238     BOOST_CHECK(!ts.hasCalibrated());
0239     BOOST_CHECK(!ts.hasProjector());
0240     BOOST_CHECK(!ts.hasJacobian());
0241     alwaysPresent(ts);
0242 
0243     ts = t.getTrackState(t.addTrackState(PM::Calibrated));
0244     BOOST_CHECK(!ts.hasPredicted());
0245     BOOST_CHECK(!ts.hasFiltered());
0246     BOOST_CHECK(!ts.hasSmoothed());
0247     BOOST_CHECK(!ts.hasCalibrated());
0248     BOOST_CHECK(ts.hasProjector());
0249     BOOST_CHECK(!ts.hasJacobian());
0250     ts.allocateCalibrated(5);
0251     BOOST_CHECK(ts.hasCalibrated());
0252     BOOST_CHECK_EQUAL(ts.template calibrated<5>(), Vector<5>::Zero());
0253     BOOST_CHECK_EQUAL(ts.template calibratedCovariance<5>(),
0254                       SquareMatrix<5>::Zero());
0255 
0256     ts = t.getTrackState(t.addTrackState(PM::Jacobian));
0257     BOOST_CHECK(!ts.hasPredicted());
0258     BOOST_CHECK(!ts.hasFiltered());
0259     BOOST_CHECK(!ts.hasSmoothed());
0260     BOOST_CHECK(!ts.hasCalibrated());
0261     BOOST_CHECK(!ts.hasProjector());
0262     BOOST_CHECK(ts.hasJacobian());
0263     alwaysPresent(ts);
0264   }
0265 
0266   void testAddTrackStateComponents() {
0267     using PM = TrackStatePropMask;
0268 
0269     trajectory_t t = m_factory.create();
0270 
0271     auto ts = t.makeTrackState(PM::None);
0272     BOOST_CHECK(!ts.hasPredicted());
0273     BOOST_CHECK(!ts.hasFiltered());
0274     BOOST_CHECK(!ts.hasSmoothed());
0275     BOOST_CHECK(!ts.hasCalibrated());
0276     BOOST_CHECK(!ts.hasJacobian());
0277 
0278     ts.addComponents(PM::None);
0279     BOOST_CHECK(!ts.hasPredicted());
0280     BOOST_CHECK(!ts.hasFiltered());
0281     BOOST_CHECK(!ts.hasSmoothed());
0282     BOOST_CHECK(!ts.hasCalibrated());
0283     BOOST_CHECK(!ts.hasJacobian());
0284 
0285     ts.addComponents(PM::Predicted);
0286     BOOST_CHECK(ts.hasPredicted());
0287     BOOST_CHECK(!ts.hasFiltered());
0288     BOOST_CHECK(!ts.hasSmoothed());
0289     BOOST_CHECK(!ts.hasCalibrated());
0290     BOOST_CHECK(!ts.hasJacobian());
0291 
0292     ts.addComponents(PM::Filtered);
0293     BOOST_CHECK(ts.hasPredicted());
0294     BOOST_CHECK(ts.hasFiltered());
0295     BOOST_CHECK(!ts.hasSmoothed());
0296     BOOST_CHECK(!ts.hasCalibrated());
0297     BOOST_CHECK(!ts.hasJacobian());
0298 
0299     ts.addComponents(PM::Smoothed);
0300     BOOST_CHECK(ts.hasPredicted());
0301     BOOST_CHECK(ts.hasFiltered());
0302     BOOST_CHECK(ts.hasSmoothed());
0303     BOOST_CHECK(!ts.hasCalibrated());
0304     BOOST_CHECK(!ts.hasJacobian());
0305 
0306     ts.addComponents(PM::Calibrated);
0307     ts.allocateCalibrated(5);
0308     BOOST_CHECK(ts.hasPredicted());
0309     BOOST_CHECK(ts.hasFiltered());
0310     BOOST_CHECK(ts.hasSmoothed());
0311     BOOST_CHECK(ts.hasCalibrated());
0312     BOOST_CHECK(!ts.hasJacobian());
0313     BOOST_CHECK_EQUAL(ts.template calibrated<5>(), Vector<5>::Zero());
0314     BOOST_CHECK_EQUAL(ts.template calibratedCovariance<5>(),
0315                       SquareMatrix<5>::Zero());
0316 
0317     ts.addComponents(PM::Jacobian);
0318     BOOST_CHECK(ts.hasPredicted());
0319     BOOST_CHECK(ts.hasFiltered());
0320     BOOST_CHECK(ts.hasSmoothed());
0321     BOOST_CHECK(ts.hasCalibrated());
0322     BOOST_CHECK(ts.hasJacobian());
0323 
0324     ts.addComponents(PM::All);
0325     BOOST_CHECK(ts.hasPredicted());
0326     BOOST_CHECK(ts.hasFiltered());
0327     BOOST_CHECK(ts.hasSmoothed());
0328     BOOST_CHECK(ts.hasCalibrated());
0329     BOOST_CHECK(ts.hasJacobian());
0330   }
0331 
0332   void testTrackStateProxyCrossTalk(std::default_random_engine& rng) {
0333     TestTrackState pc(rng, 2u);
0334 
0335     // multi trajectory w/ a single, fully set, track state
0336     trajectory_t traj = m_factory.create();
0337     std::size_t index = traj.addTrackState();
0338     {
0339       auto ts = traj.getTrackState(index);
0340       fillTrackState<trajectory_t>(pc, TrackStatePropMask::All, ts);
0341     }
0342     // get two TrackStateProxies that reference the same data
0343     auto tsa = traj.getTrackState(index);
0344     auto tsb = traj.getTrackState(index);
0345     // then modify one and check that the other was modified as well
0346     {
0347       auto [par, cov] = generateBoundParametersCovariance(rng, {});
0348       tsb.predicted() = par;
0349       tsb.predictedCovariance() = cov;
0350       BOOST_CHECK_EQUAL(tsa.predicted(), par);
0351       BOOST_CHECK_EQUAL(tsa.predictedCovariance(), cov);
0352       BOOST_CHECK_EQUAL(tsb.predicted(), par);
0353       BOOST_CHECK_EQUAL(tsb.predictedCovariance(), cov);
0354     }
0355     {
0356       auto [par, cov] = generateBoundParametersCovariance(rng, {});
0357       tsb.filtered() = par;
0358       tsb.filteredCovariance() = cov;
0359       BOOST_CHECK_EQUAL(tsa.filtered(), par);
0360       BOOST_CHECK_EQUAL(tsa.filteredCovariance(), cov);
0361       BOOST_CHECK_EQUAL(tsb.filtered(), par);
0362       BOOST_CHECK_EQUAL(tsb.filteredCovariance(), cov);
0363     }
0364     {
0365       auto [par, cov] = generateBoundParametersCovariance(rng, {});
0366       tsb.smoothed() = par;
0367       tsb.smoothedCovariance() = cov;
0368       BOOST_CHECK_EQUAL(tsa.smoothed(), par);
0369       BOOST_CHECK_EQUAL(tsa.smoothedCovariance(), cov);
0370       BOOST_CHECK_EQUAL(tsb.smoothed(), par);
0371       BOOST_CHECK_EQUAL(tsb.smoothedCovariance(), cov);
0372     }
0373     {
0374       // create a new (invalid) source link
0375       TestSourceLink invalid;
0376       invalid.sourceId = -1;
0377       BOOST_CHECK_NE(
0378           tsa.getUncalibratedSourceLink().template get<TestSourceLink>(),
0379           invalid);
0380       BOOST_CHECK_NE(
0381           tsb.getUncalibratedSourceLink().template get<TestSourceLink>(),
0382           invalid);
0383       tsb.setUncalibratedSourceLink(SourceLink{invalid});
0384       BOOST_CHECK_EQUAL(
0385           tsa.getUncalibratedSourceLink().template get<TestSourceLink>(),
0386           invalid);
0387       BOOST_CHECK_EQUAL(
0388           tsb.getUncalibratedSourceLink().template get<TestSourceLink>(),
0389           invalid);
0390     }
0391     {
0392       // reset measurements w/ full parameters
0393       auto [measPar, measCov] = generateBoundParametersCovariance(rng, {});
0394       // Explicitly unset to avoid error below
0395       tsb.unset(TrackStatePropMask::Calibrated);
0396       tsb.allocateCalibrated(eBoundSize);
0397       BOOST_CHECK_EQUAL(tsb.template calibrated<eBoundSize>(),
0398                         BoundVector::Zero());
0399       BOOST_CHECK_EQUAL(tsb.template calibratedCovariance<eBoundSize>(),
0400                         BoundMatrix::Zero());
0401       tsb.template calibrated<eBoundSize>() = measPar;
0402       tsb.template calibratedCovariance<eBoundSize>() = measCov;
0403       BOOST_CHECK_EQUAL(tsa.template calibrated<eBoundSize>(), measPar);
0404       BOOST_CHECK_EQUAL(tsa.template calibratedCovariance<eBoundSize>(),
0405                         measCov);
0406       BOOST_CHECK_EQUAL(tsb.template calibrated<eBoundSize>(), measPar);
0407       BOOST_CHECK_EQUAL(tsb.template calibratedCovariance<eBoundSize>(),
0408                         measCov);
0409     }
0410     {
0411       // reset only the effective measurements
0412       auto [measPar, measCov] = generateBoundParametersCovariance(rng, {});
0413       std::size_t nMeasurements = tsb.effectiveCalibrated().rows();
0414       auto effPar = measPar.head(nMeasurements);
0415       auto effCov = measCov.topLeftCorner(nMeasurements, nMeasurements);
0416       tsb.allocateCalibrated(
0417           eBoundSize);  // no allocation, but we expect it to be reset to zero
0418                         // with this overload
0419       BOOST_CHECK_EQUAL(tsa.effectiveCalibrated(), BoundVector::Zero());
0420       BOOST_CHECK_EQUAL(tsa.effectiveCalibratedCovariance(),
0421                         BoundMatrix::Zero());
0422       BOOST_CHECK_EQUAL(tsa.effectiveCalibrated(), BoundVector::Zero());
0423       BOOST_CHECK_EQUAL(tsa.effectiveCalibratedCovariance(),
0424                         BoundMatrix::Zero());
0425       tsb.effectiveCalibrated() = effPar;
0426       tsb.effectiveCalibratedCovariance() = effCov;
0427       BOOST_CHECK_EQUAL(tsa.effectiveCalibrated(), effPar);
0428       BOOST_CHECK_EQUAL(tsa.effectiveCalibratedCovariance(), effCov);
0429       BOOST_CHECK_EQUAL(tsb.effectiveCalibrated(), effPar);
0430       BOOST_CHECK_EQUAL(tsb.effectiveCalibratedCovariance(), effCov);
0431     }
0432     {
0433       Jacobian jac = Jacobian::Identity();
0434       BOOST_CHECK_NE(tsa.jacobian(), jac);
0435       BOOST_CHECK_NE(tsb.jacobian(), jac);
0436       tsb.jacobian() = jac;
0437       BOOST_CHECK_EQUAL(tsa.jacobian(), jac);
0438       BOOST_CHECK_EQUAL(tsb.jacobian(), jac);
0439     }
0440     {
0441       tsb.chi2() = 98.0;
0442       BOOST_CHECK_EQUAL(tsa.chi2(), 98.0);
0443       BOOST_CHECK_EQUAL(tsb.chi2(), 98.0);
0444     }
0445     {
0446       tsb.pathLength() = 66.0;
0447       BOOST_CHECK_EQUAL(tsa.pathLength(), 66.0);
0448       BOOST_CHECK_EQUAL(tsb.pathLength(), 66.0);
0449     }
0450   }
0451 
0452   void testTrackStateReassignment(std::default_random_engine& rng) {
0453     TestTrackState pc(rng, 1u);
0454 
0455     trajectory_t t = m_factory.create();
0456     std::size_t index = t.addTrackState();
0457     auto ts = t.getTrackState(index);
0458     fillTrackState<trajectory_t>(pc, TrackStatePropMask::All, ts);
0459 
0460     // assert contents of original measurement (just to be safe)
0461     BOOST_CHECK_EQUAL(ts.calibratedSize(), 1u);
0462     BOOST_CHECK_EQUAL(ts.effectiveCalibrated(),
0463                       (pc.sourceLink.parameters.head<1>()));
0464     BOOST_CHECK_EQUAL(ts.effectiveCalibratedCovariance(),
0465                       (pc.sourceLink.covariance.topLeftCorner<1, 1>()));
0466 
0467     // use temporary measurement to reset calibrated data
0468     TestTrackState ttsb(rng, 2u);
0469     const auto gctx = Acts::GeometryContext::dangerouslyDefaultConstruct();
0470     Acts::CalibrationContext cctx;
0471     BOOST_CHECK_EQUAL(
0472         ts.getUncalibratedSourceLink().template get<TestSourceLink>().sourceId,
0473         pc.sourceLink.sourceId);
0474     // Explicitly unset to avoid error below
0475     ts.unset(TrackStatePropMask::Calibrated);
0476     testSourceLinkCalibrator<trajectory_t>(gctx, cctx,
0477                                            SourceLink{ttsb.sourceLink}, ts);
0478     BOOST_CHECK_EQUAL(
0479         ts.getUncalibratedSourceLink().template get<TestSourceLink>().sourceId,
0480         ttsb.sourceLink.sourceId);
0481 
0482     BOOST_CHECK_EQUAL(ts.calibratedSize(), 2);
0483     BOOST_CHECK_EQUAL(ts.effectiveCalibrated(), ttsb.sourceLink.parameters);
0484     BOOST_CHECK_EQUAL(ts.effectiveCalibratedCovariance(),
0485                       ttsb.sourceLink.covariance);
0486   }
0487 
0488   void testTrackStateProxyStorage(std::default_random_engine& rng,
0489                                   std::size_t nMeasurements) {
0490     TestTrackState pc(rng, nMeasurements);
0491 
0492     // create trajectory with a single fully-filled random track state
0493     trajectory_t t = m_factory.create();
0494     std::size_t index = t.addTrackState();
0495     auto ts = t.getTrackState(index);
0496     fillTrackState<trajectory_t>(pc, TrackStatePropMask::All, ts);
0497 
0498     // check that the surface is correctly set
0499     BOOST_CHECK_EQUAL(&ts.referenceSurface(), pc.surface.get());
0500     BOOST_CHECK_EQUAL(ts.referenceSurface().geometryId(),
0501                       pc.sourceLink.m_geometryId);
0502 
0503     // check that the track parameters are set
0504     BOOST_CHECK(ts.hasPredicted());
0505     BOOST_CHECK_EQUAL(ts.predicted(), pc.predicted.parameters());
0506     BOOST_CHECK(pc.predicted.covariance().has_value());
0507     BOOST_CHECK_EQUAL(ts.predictedCovariance(), *pc.predicted.covariance());
0508     BOOST_CHECK(ts.hasFiltered());
0509     BOOST_CHECK_EQUAL(ts.filtered(), pc.filtered.parameters());
0510     BOOST_CHECK(pc.filtered.covariance().has_value());
0511     BOOST_CHECK_EQUAL(ts.filteredCovariance(), *pc.filtered.covariance());
0512     BOOST_CHECK(ts.hasSmoothed());
0513     BOOST_CHECK_EQUAL(ts.smoothed(), pc.smoothed.parameters());
0514     BOOST_CHECK(pc.smoothed.covariance().has_value());
0515     BOOST_CHECK_EQUAL(ts.smoothedCovariance(), *pc.smoothed.covariance());
0516 
0517     // check that the jacobian is set
0518     BOOST_CHECK(ts.hasJacobian());
0519     BOOST_CHECK_EQUAL(ts.jacobian(), pc.jacobian);
0520     BOOST_CHECK_EQUAL(ts.pathLength(), pc.pathLength);
0521     // check that chi2 is set
0522     BOOST_CHECK_EQUAL(ts.chi2(), static_cast<float>(pc.chi2));
0523 
0524     // check that the uncalibratedSourceLink source link is set
0525     BOOST_CHECK_EQUAL(
0526         ts.getUncalibratedSourceLink().template get<TestSourceLink>(),
0527         pc.sourceLink);
0528 
0529     // check that the calibrated measurement is set
0530     BOOST_CHECK(ts.hasCalibrated());
0531     BOOST_CHECK_EQUAL(ts.effectiveCalibrated(),
0532                       pc.sourceLink.parameters.head(nMeasurements));
0533     BOOST_CHECK_EQUAL(
0534         ts.effectiveCalibratedCovariance(),
0535         pc.sourceLink.covariance.topLeftCorner(nMeasurements, nMeasurements));
0536     {
0537       ParametersVector mParFull = ParametersVector::Zero();
0538       CovarianceMatrix mCovFull = CovarianceMatrix::Zero();
0539       mParFull.head(nMeasurements) =
0540           pc.sourceLink.parameters.head(nMeasurements);
0541       mCovFull.topLeftCorner(nMeasurements, nMeasurements) =
0542           pc.sourceLink.covariance.topLeftCorner(nMeasurements, nMeasurements);
0543 
0544       auto expMeas = pc.sourceLink.parameters.head(nMeasurements);
0545       auto expCov =
0546           pc.sourceLink.covariance.topLeftCorner(nMeasurements, nMeasurements);
0547 
0548       visit_measurement(ts.calibratedSize(), [&](auto N) {
0549         constexpr std::size_t measdim = decltype(N)::value;
0550         BOOST_CHECK_EQUAL(ts.template calibrated<measdim>(), expMeas);
0551         BOOST_CHECK_EQUAL(ts.template calibratedCovariance<measdim>(), expCov);
0552       });
0553     }
0554   }
0555 
0556   void testTrackStateProxyAllocations(std::default_random_engine& rng) {
0557     using namespace Acts::HashedStringLiteral;
0558 
0559     TestTrackState pc(rng, 2u);
0560 
0561     // this should allocate for all components in the trackstate, plus filtered
0562     trajectory_t t = m_factory.create();
0563     std::size_t i = t.addTrackState(TrackStatePropMask::Predicted |
0564                                     TrackStatePropMask::Filtered |
0565                                     TrackStatePropMask::Jacobian);
0566     auto tso = t.getTrackState(i);
0567     fillTrackState<trajectory_t>(pc, TrackStatePropMask::Predicted, tso);
0568     fillTrackState<trajectory_t>(pc, TrackStatePropMask::Filtered, tso);
0569     fillTrackState<trajectory_t>(pc, TrackStatePropMask::Jacobian, tso);
0570 
0571     BOOST_CHECK(tso.hasPredicted());
0572     BOOST_CHECK(tso.hasFiltered());
0573     BOOST_CHECK(!tso.hasSmoothed());
0574     BOOST_CHECK(!tso.hasCalibrated());
0575     BOOST_CHECK(tso.hasJacobian());
0576 
0577     auto tsnone = t.getTrackState(t.addTrackState(TrackStatePropMask::None));
0578     BOOST_CHECK(!tsnone.template has<"predicted"_hash>());
0579     BOOST_CHECK(!tsnone.template has<"filtered"_hash>());
0580     BOOST_CHECK(!tsnone.template has<"smoothed"_hash>());
0581     BOOST_CHECK(!tsnone.template has<"jacobian"_hash>());
0582     BOOST_CHECK(!tsnone.template has<"calibrated"_hash>());
0583     BOOST_CHECK(!tsnone.template has<"projector"_hash>());
0584     BOOST_CHECK(
0585         !tsnone.template has<"uncalibratedSourceLink"_hash>());  // separate
0586                                                                  // optional
0587                                                                  // mechanism
0588     BOOST_CHECK(tsnone.template has<"referenceSurface"_hash>());
0589     BOOST_CHECK(tsnone.template has<"measdim"_hash>());
0590     BOOST_CHECK(tsnone.template has<"chi2"_hash>());
0591     BOOST_CHECK(tsnone.template has<"pathLength"_hash>());
0592     BOOST_CHECK(tsnone.template has<"typeFlags"_hash>());
0593 
0594     auto tsall = t.getTrackState(t.addTrackState(TrackStatePropMask::All));
0595     BOOST_CHECK(tsall.template has<"predicted"_hash>());
0596     BOOST_CHECK(tsall.template has<"filtered"_hash>());
0597     BOOST_CHECK(tsall.template has<"smoothed"_hash>());
0598     BOOST_CHECK(tsall.template has<"jacobian"_hash>());
0599     BOOST_CHECK(!tsall.template has<"calibrated"_hash>());
0600     tsall.allocateCalibrated(5);
0601     BOOST_CHECK(tsall.template has<"calibrated"_hash>());
0602     BOOST_CHECK(tsall.template has<"projector"_hash>());
0603     BOOST_CHECK(!tsall.template has<
0604                  "uncalibratedSourceLink"_hash>());  // separate optional
0605                                                      // mechanism: nullptr
0606     BOOST_CHECK(tsall.template has<"referenceSurface"_hash>());
0607     BOOST_CHECK(tsall.template has<"measdim"_hash>());
0608     BOOST_CHECK(tsall.template has<"chi2"_hash>());
0609     BOOST_CHECK(tsall.template has<"pathLength"_hash>());
0610     BOOST_CHECK(tsall.template has<"typeFlags"_hash>());
0611 
0612     tsall.unset(TrackStatePropMask::Predicted);
0613     BOOST_CHECK(!tsall.template has<"predicted"_hash>());
0614     tsall.unset(TrackStatePropMask::Filtered);
0615     BOOST_CHECK(!tsall.template has<"filtered"_hash>());
0616     tsall.unset(TrackStatePropMask::Smoothed);
0617     BOOST_CHECK(!tsall.template has<"smoothed"_hash>());
0618     tsall.unset(TrackStatePropMask::Jacobian);
0619     BOOST_CHECK(!tsall.template has<"jacobian"_hash>());
0620     tsall.unset(TrackStatePropMask::Calibrated);
0621     BOOST_CHECK(!tsall.template has<"calibrated"_hash>());
0622   }
0623 
0624   void testTrackStateProxyGetMask() {
0625     using PM = TrackStatePropMask;
0626 
0627     std::array<PM, 5> values{PM::Predicted, PM::Filtered, PM::Smoothed,
0628                              PM::Jacobian, PM::Calibrated};
0629     PM all = std::accumulate(values.begin(), values.end(), PM::None,
0630                              [](auto a, auto b) { return a | b; });
0631 
0632     trajectory_t mj = m_factory.create();
0633     {
0634       auto ts = mj.getTrackState(mj.addTrackState(PM::All));
0635       // Calibrated is ignored because we haven't allocated yet
0636       BOOST_CHECK_EQUAL(ts.getMask(), (all & ~PM::Calibrated));
0637       ts.allocateCalibrated(4);
0638       BOOST_CHECK_EQUAL(ts.getMask(), all);
0639     }
0640     {
0641       auto ts =
0642           mj.getTrackState(mj.addTrackState(PM::Filtered | PM::Calibrated));
0643       // Calibrated is ignored because we haven't allocated yet
0644       BOOST_CHECK_EQUAL(ts.getMask(), PM::Filtered);
0645       ts.allocateCalibrated(4);
0646       BOOST_CHECK_EQUAL(ts.getMask(), (PM::Filtered | PM::Calibrated));
0647     }
0648     {
0649       auto ts = mj.getTrackState(
0650           mj.addTrackState(PM::Filtered | PM::Smoothed | PM::Predicted));
0651       BOOST_CHECK_EQUAL(ts.getMask(),
0652                         (PM::Filtered | PM::Smoothed | PM::Predicted));
0653     }
0654     {
0655       for (PM mask : values) {
0656         auto ts = mj.getTrackState(mj.addTrackState(mask));
0657         // Calibrated is ignored because we haven't allocated yet
0658         BOOST_CHECK_EQUAL(ts.getMask(), (mask & ~PM::Calibrated));
0659       }
0660     }
0661   }
0662 
0663   void testTrackStateProxyCopy(std::default_random_engine& rng) {
0664     using PM = TrackStatePropMask;
0665 
0666     std::array<PM, 4> values{PM::Predicted, PM::Filtered, PM::Smoothed,
0667                              PM::Jacobian};
0668 
0669     trajectory_t mj = m_factory.create();
0670     auto mkts = [&](PM mask) {
0671       auto r = mj.getTrackState(mj.addTrackState(mask));
0672       return r;
0673     };
0674 
0675     // orthogonal ones
0676     for (PM a : values) {
0677       for (PM b : values) {
0678         auto tsa = mkts(a);
0679         auto tsb = mkts(b);
0680         // doesn't work
0681         if (a != b) {
0682           BOOST_CHECK_THROW(tsa.copyFrom(tsb), std::runtime_error);
0683           BOOST_CHECK_THROW(tsb.copyFrom(tsa), std::runtime_error);
0684         } else {
0685           tsa.copyFrom(tsb);
0686           tsb.copyFrom(tsa);
0687         }
0688       }
0689     }
0690 
0691     {
0692       BOOST_TEST_CHECKPOINT("Calib auto alloc");
0693       auto tsa = mkts(PM::All);
0694       auto tsb = mkts(PM::All);
0695       tsb.allocateCalibrated(5);
0696       tsb.template calibrated<5>().setRandom();
0697       tsb.template calibratedCovariance<5>().setRandom();
0698       tsa.copyFrom(tsb, PM::All);
0699       BOOST_CHECK_EQUAL(tsa.template calibrated<5>(),
0700                         tsb.template calibrated<5>());
0701       BOOST_CHECK_EQUAL(tsa.template calibratedCovariance<5>(),
0702                         tsb.template calibratedCovariance<5>());
0703     }
0704 
0705     {
0706       BOOST_TEST_CHECKPOINT("Copy none");
0707       auto tsa = mkts(PM::All);
0708       auto tsb = mkts(PM::All);
0709       tsa.copyFrom(tsb, PM::None);
0710     }
0711 
0712     auto ts1 = mkts(PM::Filtered | PM::Predicted);  // this has both
0713     ts1.filtered().setRandom();
0714     ts1.filteredCovariance().setRandom();
0715     ts1.predicted().setRandom();
0716     ts1.predictedCovariance().setRandom();
0717 
0718     // ((src XOR dst) & src) == 0
0719     auto ts2 = mkts(PM::Predicted);
0720     ts2.predicted().setRandom();
0721     ts2.predictedCovariance().setRandom();
0722 
0723     // they are different before
0724     BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
0725     BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
0726 
0727     // ts1 -> ts2 fails
0728     BOOST_CHECK_THROW(ts2.copyFrom(ts1), std::runtime_error);
0729     BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
0730     BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
0731 
0732     // ts2 -> ts1 is ok
0733     ts1.copyFrom(ts2);
0734     BOOST_CHECK_EQUAL(ts1.predicted(), ts2.predicted());
0735     BOOST_CHECK_EQUAL(ts1.predictedCovariance(), ts2.predictedCovariance());
0736 
0737     std::size_t i0 = mj.addTrackState();
0738     std::size_t i1 = mj.addTrackState();
0739     ts1 = mj.getTrackState(i0);
0740     ts2 = mj.getTrackState(i1);
0741     TestTrackState rts1(rng, 1u);
0742     TestTrackState rts2(rng, 2u);
0743     fillTrackState<trajectory_t>(rts1, TrackStatePropMask::All, ts1);
0744     fillTrackState<trajectory_t>(rts2, TrackStatePropMask::All, ts2);
0745 
0746     auto ots1 = mkts(PM::All);
0747     auto ots2 = mkts(PM::All);
0748     // make full copy for later. We prove full copy works right below
0749     ots1.copyFrom(ts1);
0750     ots2.copyFrom(ts2);
0751 
0752     BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
0753     BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
0754     BOOST_CHECK_NE(ts1.filtered(), ts2.filtered());
0755     BOOST_CHECK_NE(ts1.filteredCovariance(), ts2.filteredCovariance());
0756     BOOST_CHECK_NE(ts1.smoothed(), ts2.smoothed());
0757     BOOST_CHECK_NE(ts1.smoothedCovariance(), ts2.smoothedCovariance());
0758 
0759     BOOST_CHECK_NE(
0760         ts1.getUncalibratedSourceLink().template get<TestSourceLink>(),
0761         ts2.getUncalibratedSourceLink().template get<TestSourceLink>());
0762 
0763     BOOST_CHECK_NE(ts1.calibratedSize(), ts2.calibratedSize());
0764     BOOST_CHECK(ts1.projectorSubspaceIndices() !=
0765                 ts2.projectorSubspaceIndices());
0766 
0767     BOOST_CHECK_NE(ts1.jacobian(), ts2.jacobian());
0768     BOOST_CHECK_NE(ts1.chi2(), ts2.chi2());
0769     BOOST_CHECK_NE(ts1.pathLength(), ts2.pathLength());
0770     BOOST_CHECK_NE(&ts1.referenceSurface(), &ts2.referenceSurface());
0771 
0772     // Explicitly unset to avoid error below
0773     ts1.unset(TrackStatePropMask::Calibrated);
0774     ts1.copyFrom(ts2);
0775 
0776     BOOST_CHECK_EQUAL(ts1.predicted(), ts2.predicted());
0777     BOOST_CHECK_EQUAL(ts1.predictedCovariance(), ts2.predictedCovariance());
0778     BOOST_CHECK_EQUAL(ts1.filtered(), ts2.filtered());
0779     BOOST_CHECK_EQUAL(ts1.filteredCovariance(), ts2.filteredCovariance());
0780     BOOST_CHECK_EQUAL(ts1.smoothed(), ts2.smoothed());
0781     BOOST_CHECK_EQUAL(ts1.smoothedCovariance(), ts2.smoothedCovariance());
0782 
0783     BOOST_CHECK_EQUAL(
0784         ts1.getUncalibratedSourceLink().template get<TestSourceLink>(),
0785         ts2.getUncalibratedSourceLink().template get<TestSourceLink>());
0786 
0787     visit_measurement(ts1.calibratedSize(), [&](auto N) {
0788       constexpr std::size_t measdim = decltype(N)::value;
0789       BOOST_CHECK_EQUAL(ts1.template calibrated<measdim>(),
0790                         ts2.template calibrated<measdim>());
0791       BOOST_CHECK_EQUAL(ts1.template calibratedCovariance<measdim>(),
0792                         ts2.template calibratedCovariance<measdim>());
0793       BOOST_CHECK(ts1.template projectorSubspaceIndices<measdim>() ==
0794                   ts2.template projectorSubspaceIndices<measdim>());
0795     });
0796 
0797     BOOST_CHECK_EQUAL(ts1.calibratedSize(), ts2.calibratedSize());
0798     BOOST_CHECK(ts1.projectorSubspaceIndices() ==
0799                 ts2.projectorSubspaceIndices());
0800 
0801     BOOST_CHECK_EQUAL(ts1.jacobian(), ts2.jacobian());
0802     BOOST_CHECK_EQUAL(ts1.chi2(), ts2.chi2());
0803     BOOST_CHECK_EQUAL(ts1.pathLength(), ts2.pathLength());
0804     BOOST_CHECK_EQUAL(&ts1.referenceSurface(), &ts2.referenceSurface());
0805 
0806     // full copy proven to work. now let's do partial copy
0807     ts2 = mkts(PM::Predicted | PM::Jacobian | PM::Calibrated);
0808     ts2.copyFrom(ots2, PM::Predicted | PM::Jacobian | PM::Calibrated);
0809     // copy into empty ts, only copy some
0810     // explicitly unset to avoid error below
0811     ts1.unset(TrackStatePropMask::Calibrated);
0812     ts1.copyFrom(ots1);  // reset to original
0813     // is different again
0814     BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
0815     BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
0816 
0817     BOOST_CHECK_NE(ts1.calibratedSize(), ts2.calibratedSize());
0818     BOOST_CHECK(ts1.projectorSubspaceIndices() !=
0819                 ts2.projectorSubspaceIndices());
0820 
0821     BOOST_CHECK_NE(ts1.jacobian(), ts2.jacobian());
0822     BOOST_CHECK_NE(ts1.chi2(), ts2.chi2());
0823     BOOST_CHECK_NE(ts1.pathLength(), ts2.pathLength());
0824     BOOST_CHECK_NE(&ts1.referenceSurface(), &ts2.referenceSurface());
0825 
0826     // Explicitly unset to avoid error below
0827     ts1.unset(TrackStatePropMask::Calibrated);
0828     ts1.copyFrom(ts2);
0829 
0830     // some components are same now
0831     BOOST_CHECK_EQUAL(ts1.predicted(), ts2.predicted());
0832     BOOST_CHECK_EQUAL(ts1.predictedCovariance(), ts2.predictedCovariance());
0833 
0834     visit_measurement(ts1.calibratedSize(), [&](auto N) {
0835       constexpr std::size_t measdim = decltype(N)::value;
0836       BOOST_CHECK_EQUAL(ts1.template calibrated<measdim>(),
0837                         ts2.template calibrated<measdim>());
0838       BOOST_CHECK_EQUAL(ts1.template calibratedCovariance<measdim>(),
0839                         ts2.template calibratedCovariance<measdim>());
0840       BOOST_CHECK(ts1.template projectorSubspaceIndices<measdim>() ==
0841                   ts2.template projectorSubspaceIndices<measdim>());
0842     });
0843 
0844     BOOST_CHECK_EQUAL(ts1.calibratedSize(), ts2.calibratedSize());
0845     BOOST_CHECK(ts1.projectorSubspaceIndices() ==
0846                 ts2.projectorSubspaceIndices());
0847 
0848     BOOST_CHECK_EQUAL(ts1.jacobian(), ts2.jacobian());
0849     BOOST_CHECK_EQUAL(ts1.chi2(), ts2.chi2());              // always copied
0850     BOOST_CHECK_EQUAL(ts1.pathLength(), ts2.pathLength());  // always copied
0851     BOOST_CHECK_EQUAL(&ts1.referenceSurface(),
0852                       &ts2.referenceSurface());  // always copied
0853   }
0854 
0855   void testTrackStateCopyDynamicColumns() {
0856     // mutable source
0857     trajectory_t mtj = m_factory.create();
0858     mtj.template addColumn<std::uint64_t>("counter");
0859     mtj.template addColumn<std::uint8_t>("odd");
0860 
0861     trajectory_t mtj2 = m_factory.create();
0862     // doesn't have the dynamic column
0863 
0864     trajectory_t mtj3 = m_factory.create();
0865     mtj3.template addColumn<std::uint64_t>("counter");
0866     mtj3.template addColumn<std::uint8_t>("odd");
0867 
0868     for (TrackIndexType i = 0; i < 10; i++) {
0869       auto ts =
0870           mtj.getTrackState(mtj.addTrackState(TrackStatePropMask::All, i));
0871       ts.template component<std::uint64_t>("counter") = i;
0872       ts.template component<std::uint8_t>("odd") = i % 2 == 0;
0873 
0874       auto ts2 =
0875           mtj2.getTrackState(mtj2.addTrackState(TrackStatePropMask::All, i));
0876       BOOST_CHECK_THROW(ts2.copyFrom(ts),
0877                         std::invalid_argument);  // this should fail
0878 
0879       auto ts3 =
0880           mtj3.getTrackState(mtj3.addTrackState(TrackStatePropMask::All, i));
0881       ts3.copyFrom(ts);  // this should work
0882 
0883       BOOST_CHECK_NE(ts3.index(), kInvalid);
0884 
0885       BOOST_CHECK_EQUAL(ts.template component<std::uint64_t>("counter"),
0886                         ts3.template component<std::uint64_t>("counter"));
0887       BOOST_CHECK_EQUAL(ts.template component<std::uint8_t>("odd"),
0888                         ts3.template component<std::uint8_t>("odd"));
0889     }
0890 
0891     std::size_t before = mtj.size();
0892     const_trajectory_t cmtj{mtj};
0893 
0894     BOOST_REQUIRE_EQUAL(cmtj.size(), before);
0895 
0896     VectorMultiTrajectory mtj5;
0897     mtj5.addColumn<std::uint64_t>("counter");
0898     mtj5.addColumn<std::uint8_t>("odd");
0899 
0900     for (std::size_t i = 0; i < 10; i++) {
0901       auto ts4 = cmtj.getTrackState(i);  // const source!
0902 
0903       auto ts5 =
0904           mtj5.getTrackState(mtj5.addTrackState(TrackStatePropMask::All, 0));
0905       ts5.copyFrom(ts4);  // this should work
0906 
0907       BOOST_CHECK_NE(ts5.index(), kInvalid);
0908 
0909       BOOST_CHECK_EQUAL(ts4.template component<std::uint64_t>("counter"),
0910                         ts5.template component<std::uint64_t>("counter"));
0911       BOOST_CHECK_EQUAL(ts4.template component<std::uint8_t>("odd"),
0912                         ts5.template component<std::uint8_t>("odd"));
0913     }
0914   }
0915 
0916   void testTrackStateProxyCopyDiffMTJ() {
0917     using PM = TrackStatePropMask;
0918 
0919     std::array<PM, 4> values{PM::Predicted, PM::Filtered, PM::Smoothed,
0920                              PM::Jacobian};
0921 
0922     trajectory_t mj = m_factory.create();
0923     trajectory_t mj2 = m_factory.create();
0924     auto mkts = [&](PM mask) {
0925       auto r = mj.getTrackState(mj.addTrackState(mask));
0926       return r;
0927     };
0928     auto mkts2 = [&](PM mask) {
0929       auto r = mj2.getTrackState(mj2.addTrackState(mask));
0930       return r;
0931     };
0932 
0933     // orthogonal ones
0934     for (PM a : values) {
0935       for (PM b : values) {
0936         auto tsa = mkts(a);
0937         auto tsb = mkts2(b);
0938         // doesn't work
0939         if (a != b) {
0940           BOOST_CHECK_THROW(tsa.copyFrom(tsb), std::runtime_error);
0941           BOOST_CHECK_THROW(tsb.copyFrom(tsa), std::runtime_error);
0942         } else {
0943           tsa.copyFrom(tsb);
0944           tsb.copyFrom(tsa);
0945         }
0946       }
0947     }
0948 
0949     // make sure they are actually on different MultiTrajectories
0950     BOOST_CHECK_EQUAL(mj.size(), values.size() * values.size());
0951     BOOST_CHECK_EQUAL(mj2.size(), values.size() * values.size());
0952 
0953     auto ts1 = mkts(PM::Filtered | PM::Predicted);  // this has both
0954     ts1.filtered().setRandom();
0955     ts1.filteredCovariance().setRandom();
0956     ts1.predicted().setRandom();
0957     ts1.predictedCovariance().setRandom();
0958 
0959     // ((src XOR dst) & src) == 0
0960     auto ts2 = mkts2(PM::Predicted);
0961     ts2.predicted().setRandom();
0962     ts2.predictedCovariance().setRandom();
0963 
0964     // they are different before
0965     BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
0966     BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
0967 
0968     // ts1 -> ts2 fails
0969     BOOST_CHECK_THROW(ts2.copyFrom(ts1), std::runtime_error);
0970     BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
0971     BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
0972 
0973     // ts2 -> ts1 is ok
0974     ts1.copyFrom(ts2);
0975     BOOST_CHECK_EQUAL(ts1.predicted(), ts2.predicted());
0976     BOOST_CHECK_EQUAL(ts1.predictedCovariance(), ts2.predictedCovariance());
0977 
0978     {
0979       BOOST_TEST_CHECKPOINT("Calib auto alloc");
0980       auto tsa = mkts(PM::All);
0981       auto tsb = mkts(PM::All);
0982       tsb.allocateCalibrated(5);
0983       tsb.template calibrated<5>().setRandom();
0984       tsb.template calibratedCovariance<5>().setRandom();
0985       tsa.copyFrom(tsb, PM::All);
0986       BOOST_CHECK_EQUAL(tsa.template calibrated<5>(),
0987                         tsb.template calibrated<5>());
0988       BOOST_CHECK_EQUAL(tsa.template calibratedCovariance<5>(),
0989                         tsb.template calibratedCovariance<5>());
0990     }
0991 
0992     {
0993       BOOST_TEST_CHECKPOINT("Copy none");
0994       auto tsa = mkts(PM::All);
0995       auto tsb = mkts(PM::All);
0996       tsa.copyFrom(tsb, PM::None);
0997     }
0998   }
0999 
1000   void testProxyAssignment() {
1001     constexpr TrackStatePropMask kMask = TrackStatePropMask::Predicted;
1002     trajectory_t t = m_factory.create();
1003     auto i0 = t.addTrackState(kMask);
1004 
1005     typename trajectory_t::TrackStateProxy tp = t.getTrackState(i0);  // mutable
1006     typename trajectory_t::TrackStateProxy tp2{tp};  // mutable to mutable
1007     static_cast<void>(tp2);
1008     typename trajectory_t::ConstTrackStateProxy tp3{tp};  // mutable to const
1009     static_cast<void>(tp3);
1010     // const to mutable: this won't compile
1011     // MultiTrajectory::TrackStateProxy tp4{tp3};
1012   }
1013 
1014   void testCopyFromConst() {
1015     // Check if the copy from const does compile, assume the copy is done
1016     // correctly
1017 
1018     using PM = TrackStatePropMask;
1019     trajectory_t mj = m_factory.create();
1020 
1021     const auto idx_a = mj.addTrackState(PM::All);
1022     const auto idx_b = mj.addTrackState(PM::All);
1023 
1024     typename trajectory_t::TrackStateProxy mutableProxy =
1025         mj.getTrackState(idx_a);
1026 
1027     const trajectory_t& cmj = mj;
1028     typename trajectory_t::ConstTrackStateProxy constProxy =
1029         cmj.getTrackState(idx_b);
1030 
1031     mutableProxy.copyFrom(constProxy);
1032 
1033     // copy mutable to const: this won't compile
1034     // constProxy.copyFrom(mutableProxy);
1035   }
1036 
1037   void testTrackStateProxyShare(std::default_random_engine& rng) {
1038     TestTrackState pc(rng, 2u);
1039 
1040     {
1041       trajectory_t traj = m_factory.create();
1042       std::size_t ia = traj.addTrackState(TrackStatePropMask::All);
1043       std::size_t ib = traj.addTrackState(TrackStatePropMask::None);
1044 
1045       auto tsa = traj.getTrackState(ia);
1046       auto tsb = traj.getTrackState(ib);
1047 
1048       fillTrackState<trajectory_t>(pc, TrackStatePropMask::All, tsa);
1049 
1050       BOOST_CHECK(tsa.hasPredicted());
1051       BOOST_CHECK(!tsb.hasPredicted());
1052       tsb.shareFrom(tsa, TrackStatePropMask::Predicted);
1053       BOOST_CHECK(tsa.hasPredicted());
1054       BOOST_CHECK(tsb.hasPredicted());
1055       BOOST_CHECK_EQUAL(tsa.predicted(), tsb.predicted());
1056       BOOST_CHECK_EQUAL(tsa.predictedCovariance(), tsb.predictedCovariance());
1057 
1058       BOOST_CHECK(tsa.hasFiltered());
1059       BOOST_CHECK(!tsb.hasFiltered());
1060       tsb.shareFrom(tsa, TrackStatePropMask::Filtered);
1061       BOOST_CHECK(tsa.hasFiltered());
1062       BOOST_CHECK(tsb.hasFiltered());
1063       BOOST_CHECK_EQUAL(tsa.filtered(), tsb.filtered());
1064       BOOST_CHECK_EQUAL(tsa.filteredCovariance(), tsb.filteredCovariance());
1065 
1066       BOOST_CHECK(tsa.hasSmoothed());
1067       BOOST_CHECK(!tsb.hasSmoothed());
1068       tsb.shareFrom(tsa, TrackStatePropMask::Smoothed);
1069       BOOST_CHECK(tsa.hasSmoothed());
1070       BOOST_CHECK(tsb.hasSmoothed());
1071       BOOST_CHECK_EQUAL(tsa.smoothed(), tsb.smoothed());
1072       BOOST_CHECK_EQUAL(tsa.smoothedCovariance(), tsb.smoothedCovariance());
1073 
1074       BOOST_CHECK(tsa.hasJacobian());
1075       BOOST_CHECK(!tsb.hasJacobian());
1076       tsb.shareFrom(tsa, TrackStatePropMask::Jacobian);
1077       BOOST_CHECK(tsa.hasJacobian());
1078       BOOST_CHECK(tsb.hasJacobian());
1079       BOOST_CHECK_EQUAL(tsa.jacobian(), tsb.jacobian());
1080     }
1081 
1082     {
1083       trajectory_t traj = m_factory.create();
1084       std::size_t i = traj.addTrackState(TrackStatePropMask::All &
1085                                          ~TrackStatePropMask::Filtered &
1086                                          ~TrackStatePropMask::Smoothed);
1087 
1088       auto ts = traj.getTrackState(i);
1089 
1090       BOOST_CHECK(ts.hasPredicted());
1091       BOOST_CHECK(!ts.hasFiltered());
1092       BOOST_CHECK(!ts.hasSmoothed());
1093       ts.predicted().setRandom();
1094       ts.predictedCovariance().setRandom();
1095 
1096       ts.shareFrom(TrackStatePropMask::Predicted, TrackStatePropMask::Filtered);
1097       BOOST_CHECK(ts.hasPredicted());
1098       BOOST_CHECK(ts.hasFiltered());
1099       BOOST_CHECK(!ts.hasSmoothed());
1100       BOOST_CHECK_EQUAL(ts.predicted(), ts.filtered());
1101       BOOST_CHECK_EQUAL(ts.predictedCovariance(), ts.filteredCovariance());
1102 
1103       ts.shareFrom(TrackStatePropMask::Predicted, TrackStatePropMask::Smoothed);
1104       BOOST_CHECK(ts.hasPredicted());
1105       BOOST_CHECK(ts.hasFiltered());
1106       BOOST_CHECK(ts.hasSmoothed());
1107       BOOST_CHECK_EQUAL(ts.predicted(), ts.filtered());
1108       BOOST_CHECK_EQUAL(ts.predicted(), ts.smoothed());
1109       BOOST_CHECK_EQUAL(ts.predictedCovariance(), ts.filteredCovariance());
1110       BOOST_CHECK_EQUAL(ts.predictedCovariance(), ts.smoothedCovariance());
1111     }
1112   }
1113 
1114   void testMultiTrajectoryExtraColumns() {
1115     using namespace HashedStringLiteral;
1116 
1117     auto test = [&](const std::string& col, auto value) {
1118       using T = decltype(value);
1119       std::string col2 = col + "_2";
1120       HashedString h{hashStringDynamic(col)};
1121       HashedString h2{hashStringDynamic(col2)};
1122 
1123       trajectory_t traj = m_factory.create();
1124       BOOST_CHECK(!traj.hasColumn(h));
1125       traj.template addColumn<T>(col);
1126       BOOST_CHECK(traj.hasColumn(h));
1127 
1128       BOOST_CHECK(!traj.hasColumn(h2));
1129       traj.template addColumn<T>(col2);
1130       BOOST_CHECK(traj.hasColumn(h2));
1131 
1132       auto ts1 = traj.getTrackState(traj.addTrackState());
1133       auto ts2 = traj.getTrackState(
1134           traj.addTrackState(TrackStatePropMask::All, ts1.index()));
1135       auto ts3 = traj.getTrackState(
1136           traj.addTrackState(TrackStatePropMask::All, ts2.index()));
1137 
1138       BOOST_CHECK(ts1.has(h));
1139       BOOST_CHECK(ts2.has(h));
1140       BOOST_CHECK(ts3.has(h));
1141 
1142       BOOST_CHECK(ts1.has(h2));
1143       BOOST_CHECK(ts2.has(h2));
1144       BOOST_CHECK(ts3.has(h2));
1145 
1146       ts1.template component<T>(col) = value;
1147       BOOST_CHECK_EQUAL(ts1.template component<T>(col), value);
1148     };
1149 
1150     test("std_uint32_t", std::uint32_t{1});
1151     test("std_uint64_t", std::uint64_t{2});
1152     test("std_int32_t", std::int32_t{-3});
1153     test("std_int64_t", std::int64_t{-4});
1154     test("float", float{8.9});
1155     test("double", double{656.2});
1156 
1157     trajectory_t traj = m_factory.create();
1158     traj.template addColumn<int>("extra_column");
1159     traj.template addColumn<float>("another_column");
1160 
1161     auto ts1 = traj.getTrackState(traj.addTrackState());
1162     auto ts2 = traj.getTrackState(
1163         traj.addTrackState(TrackStatePropMask::All, ts1.index()));
1164     auto ts3 = traj.getTrackState(
1165         traj.addTrackState(TrackStatePropMask::All, ts2.index()));
1166 
1167     BOOST_CHECK(ts1.template has<"extra_column"_hash>());
1168     BOOST_CHECK(ts2.template has<"extra_column"_hash>());
1169     BOOST_CHECK(ts3.template has<"extra_column"_hash>());
1170 
1171     BOOST_CHECK(ts1.template has<"another_column"_hash>());
1172     BOOST_CHECK(ts2.template has<"another_column"_hash>());
1173     BOOST_CHECK(ts3.template has<"another_column"_hash>());
1174 
1175     ts2.template component<int, "extra_column"_hash>() = 6;
1176 
1177     BOOST_CHECK_EQUAL((ts2.template component<int, "extra_column"_hash>()), 6);
1178 
1179     ts3.template component<float, "another_column"_hash>() = 7.2f;
1180     BOOST_CHECK_EQUAL((ts3.template component<float, "another_column"_hash>()),
1181                       7.2f);
1182   }
1183 
1184   void testMultiTrajectoryExtraColumnsRuntime() {
1185     auto runTest = [&](auto&& fn) {
1186       trajectory_t mt = m_factory.create();
1187       std::vector<std::string> columns = {"one", "two", "three", "four"};
1188       for (const auto& c : columns) {
1189         BOOST_CHECK(!mt.hasColumn(fn(c)));
1190         mt.template addColumn<int>(c);
1191         BOOST_CHECK(mt.hasColumn(fn(c)));
1192       }
1193       for (const auto& c : columns) {
1194         auto ts1 = mt.getTrackState(mt.addTrackState());
1195         auto ts2 = mt.getTrackState(mt.addTrackState());
1196         BOOST_CHECK(ts1.has(fn(c)));
1197         BOOST_CHECK(ts2.has(fn(c)));
1198         ts1.template component<int>(fn(c)) = 674;
1199         ts2.template component<int>(fn(c)) = 421;
1200         BOOST_CHECK_EQUAL(ts1.template component<int>(fn(c)), 674);
1201         BOOST_CHECK_EQUAL(ts2.template component<int>(fn(c)), 421);
1202       }
1203     };
1204 
1205     runTest([](const std::string& c) { return hashStringDynamic(c.c_str()); });
1206     // runTest([](const std::string& c) { return c.c_str(); });
1207     // runTest([](const std::string& c) { return c; });
1208     // runTest([](std::string_view c) { return c; });
1209   }
1210 
1211   void testMultiTrajectoryAllocateCalibratedInit(
1212       std::default_random_engine& rng) {
1213     trajectory_t traj = m_factory.create();
1214     auto ts = traj.makeTrackState(TrackStatePropMask::All);
1215 
1216     BOOST_CHECK_EQUAL(ts.calibratedSize(), kInvalid);
1217 
1218     auto [par, cov] = generateBoundParametersCovariance(rng, {});
1219 
1220     ts.allocateCalibrated(par.head<3>(), cov.topLeftCorner<3, 3>());
1221 
1222     BOOST_CHECK_EQUAL(ts.calibratedSize(), 3);
1223     BOOST_CHECK_EQUAL(ts.template calibrated<3>(), par.head<3>());
1224     BOOST_CHECK_EQUAL(ts.template calibratedCovariance<3>(),
1225                       (cov.topLeftCorner<3, 3>()));
1226 
1227     auto [par2, cov2] = generateBoundParametersCovariance(rng, {});
1228 
1229     ts.allocateCalibrated(3);
1230     BOOST_CHECK_EQUAL(ts.template calibrated<3>(), Vector3::Zero());
1231     BOOST_CHECK_EQUAL(ts.template calibratedCovariance<3>(),
1232                       SquareMatrix<3>::Zero());
1233 
1234     ts.allocateCalibrated(par2.head<3>(), cov2.topLeftCorner<3, 3>());
1235     BOOST_CHECK_EQUAL(ts.calibratedSize(), 3);
1236     // The values are re-assigned
1237     BOOST_CHECK_EQUAL(ts.template calibrated<3>(), par2.head<3>());
1238     BOOST_CHECK_EQUAL(ts.template calibratedCovariance<3>(),
1239                       (cov2.topLeftCorner<3, 3>()));
1240 
1241     // Re-allocation with a different measurement dimension is an error
1242     BOOST_CHECK_THROW(
1243         ts.allocateCalibrated(par2.head<4>(), cov2.topLeftCorner<4, 4>()),
1244         std::invalid_argument);
1245   }
1246 };
1247 }  // namespace Acts::detail::Test