Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-01 08:07:44

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