Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-19 09:23:19

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     auto meas = 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     auto m2 = std::get<Acts::Measurement<BoundIndices, 2u>>(meas);
0453 
0454     BOOST_CHECK_EQUAL(ts.calibratedSize(), 2);
0455     BOOST_CHECK_EQUAL(ts.effectiveCalibrated(), m2.parameters());
0456     BOOST_CHECK_EQUAL(ts.effectiveCalibratedCovariance(), m2.covariance());
0457     BOOST_CHECK_EQUAL(ts.effectiveProjector(), m2.projector());
0458   }
0459 
0460   void testTrackStateProxyStorage(std::default_random_engine& rng,
0461                                   std::size_t nMeasurements) {
0462     TestTrackState pc(rng, nMeasurements);
0463 
0464     // create trajectory with a single fully-filled random track state
0465     trajectory_t t = m_factory.create();
0466     std::size_t index = t.addTrackState();
0467     auto ts = t.getTrackState(index);
0468     fillTrackState<trajectory_t>(pc, TrackStatePropMask::All, ts);
0469 
0470     // check that the surface is correctly set
0471     BOOST_CHECK_EQUAL(&ts.referenceSurface(), pc.surface.get());
0472     BOOST_CHECK_EQUAL(ts.referenceSurface().geometryId(),
0473                       pc.sourceLink.m_geometryId);
0474 
0475     // check that the track parameters are set
0476     BOOST_CHECK(ts.hasPredicted());
0477     BOOST_CHECK_EQUAL(ts.predicted(), pc.predicted.parameters());
0478     BOOST_CHECK(pc.predicted.covariance().has_value());
0479     BOOST_CHECK_EQUAL(ts.predictedCovariance(), *pc.predicted.covariance());
0480     BOOST_CHECK(ts.hasFiltered());
0481     BOOST_CHECK_EQUAL(ts.filtered(), pc.filtered.parameters());
0482     BOOST_CHECK(pc.filtered.covariance().has_value());
0483     BOOST_CHECK_EQUAL(ts.filteredCovariance(), *pc.filtered.covariance());
0484     BOOST_CHECK(ts.hasSmoothed());
0485     BOOST_CHECK_EQUAL(ts.smoothed(), pc.smoothed.parameters());
0486     BOOST_CHECK(pc.smoothed.covariance().has_value());
0487     BOOST_CHECK_EQUAL(ts.smoothedCovariance(), *pc.smoothed.covariance());
0488 
0489     // check that the jacobian is set
0490     BOOST_CHECK(ts.hasJacobian());
0491     BOOST_CHECK_EQUAL(ts.jacobian(), pc.jacobian);
0492     BOOST_CHECK_EQUAL(ts.pathLength(), pc.pathLength);
0493     // check that chi2 is set
0494     BOOST_CHECK_EQUAL(ts.chi2(), static_cast<float>(pc.chi2));
0495 
0496     // check that the uncalibratedSourceLink source link is set
0497     BOOST_CHECK_EQUAL(
0498         ts.getUncalibratedSourceLink().template get<TestSourceLink>(),
0499         pc.sourceLink);
0500 
0501     // check that the calibrated measurement is set
0502     BOOST_CHECK(ts.hasCalibrated());
0503     BOOST_CHECK_EQUAL(ts.effectiveCalibrated(),
0504                       pc.sourceLink.parameters.head(nMeasurements));
0505     BOOST_CHECK_EQUAL(
0506         ts.effectiveCalibratedCovariance(),
0507         pc.sourceLink.covariance.topLeftCorner(nMeasurements, nMeasurements));
0508     {
0509       ParametersVector mParFull = ParametersVector::Zero();
0510       CovarianceMatrix mCovFull = CovarianceMatrix::Zero();
0511       mParFull.head(nMeasurements) =
0512           pc.sourceLink.parameters.head(nMeasurements);
0513       mCovFull.topLeftCorner(nMeasurements, nMeasurements) =
0514           pc.sourceLink.covariance.topLeftCorner(nMeasurements, nMeasurements);
0515 
0516       auto expMeas = pc.sourceLink.parameters.head(nMeasurements);
0517       auto expCov =
0518           pc.sourceLink.covariance.topLeftCorner(nMeasurements, nMeasurements);
0519 
0520       visit_measurement(ts.calibratedSize(), [&](auto N) {
0521         constexpr std::size_t measdim = decltype(N)::value;
0522         BOOST_CHECK_EQUAL(ts.template calibrated<measdim>(), expMeas);
0523         BOOST_CHECK_EQUAL(ts.template calibratedCovariance<measdim>(), expCov);
0524       });
0525     }
0526 
0527     BOOST_CHECK(ts.hasProjector());
0528     ActsMatrix<MultiTrajectoryTraits::MeasurementSizeMax, eBoundSize> fullProj;
0529     fullProj.setZero();
0530     {
0531       Acts::GeometryContext gctx;
0532       Acts::CalibrationContext cctx;
0533       // create a temporary measurement to extract the projector matrix
0534       auto meas = testSourceLinkCalibratorReturn<trajectory_t>(
0535           gctx, cctx, SourceLink{pc.sourceLink}, ts);
0536       std::visit(
0537           [&](const auto& m) {
0538             fullProj.topLeftCorner(nMeasurements, eBoundSize) = m.projector();
0539           },
0540           meas);
0541     }
0542     BOOST_CHECK_EQUAL(ts.effectiveProjector(),
0543                       fullProj.topLeftCorner(nMeasurements, eBoundSize));
0544     BOOST_CHECK_EQUAL(ts.projector(), fullProj);
0545   }
0546 
0547   void testTrackStateProxyAllocations(std::default_random_engine& rng) {
0548     using namespace Acts::HashedStringLiteral;
0549 
0550     TestTrackState pc(rng, 2u);
0551 
0552     // this should allocate for all components in the trackstate, plus filtered
0553     trajectory_t t = m_factory.create();
0554     std::size_t i = t.addTrackState(TrackStatePropMask::Predicted |
0555                                     TrackStatePropMask::Filtered |
0556                                     TrackStatePropMask::Jacobian);
0557     auto tso = t.getTrackState(i);
0558     fillTrackState<trajectory_t>(pc, TrackStatePropMask::Predicted, tso);
0559     fillTrackState<trajectory_t>(pc, TrackStatePropMask::Filtered, tso);
0560     fillTrackState<trajectory_t>(pc, TrackStatePropMask::Jacobian, tso);
0561 
0562     BOOST_CHECK(tso.hasPredicted());
0563     BOOST_CHECK(tso.hasFiltered());
0564     BOOST_CHECK(!tso.hasSmoothed());
0565     BOOST_CHECK(!tso.hasCalibrated());
0566     BOOST_CHECK(tso.hasJacobian());
0567 
0568     auto tsnone = t.getTrackState(t.addTrackState(TrackStatePropMask::None));
0569     BOOST_CHECK(!tsnone.template has<"predicted"_hash>());
0570     BOOST_CHECK(!tsnone.template has<"filtered"_hash>());
0571     BOOST_CHECK(!tsnone.template has<"smoothed"_hash>());
0572     BOOST_CHECK(!tsnone.template has<"jacobian"_hash>());
0573     BOOST_CHECK(!tsnone.template has<"calibrated"_hash>());
0574     BOOST_CHECK(!tsnone.template has<"projector"_hash>());
0575     BOOST_CHECK(
0576         !tsnone.template has<"uncalibratedSourceLink"_hash>());  // separate
0577                                                                  // optional
0578                                                                  // mechanism
0579     BOOST_CHECK(tsnone.template has<"referenceSurface"_hash>());
0580     BOOST_CHECK(tsnone.template has<"measdim"_hash>());
0581     BOOST_CHECK(tsnone.template has<"chi2"_hash>());
0582     BOOST_CHECK(tsnone.template has<"pathLength"_hash>());
0583     BOOST_CHECK(tsnone.template has<"typeFlags"_hash>());
0584 
0585     auto tsall = t.getTrackState(t.addTrackState(TrackStatePropMask::All));
0586     BOOST_CHECK(tsall.template has<"predicted"_hash>());
0587     BOOST_CHECK(tsall.template has<"filtered"_hash>());
0588     BOOST_CHECK(tsall.template has<"smoothed"_hash>());
0589     BOOST_CHECK(tsall.template has<"jacobian"_hash>());
0590     BOOST_CHECK(!tsall.template has<"calibrated"_hash>());
0591     tsall.allocateCalibrated(5);
0592     BOOST_CHECK(tsall.template has<"calibrated"_hash>());
0593     BOOST_CHECK(tsall.template has<"projector"_hash>());
0594     BOOST_CHECK(!tsall.template has<
0595                  "uncalibratedSourceLink"_hash>());  // separate optional
0596                                                      // mechanism: nullptr
0597     BOOST_CHECK(tsall.template has<"referenceSurface"_hash>());
0598     BOOST_CHECK(tsall.template has<"measdim"_hash>());
0599     BOOST_CHECK(tsall.template has<"chi2"_hash>());
0600     BOOST_CHECK(tsall.template has<"pathLength"_hash>());
0601     BOOST_CHECK(tsall.template has<"typeFlags"_hash>());
0602 
0603     tsall.unset(TrackStatePropMask::Predicted);
0604     BOOST_CHECK(!tsall.template has<"predicted"_hash>());
0605     tsall.unset(TrackStatePropMask::Filtered);
0606     BOOST_CHECK(!tsall.template has<"filtered"_hash>());
0607     tsall.unset(TrackStatePropMask::Smoothed);
0608     BOOST_CHECK(!tsall.template has<"smoothed"_hash>());
0609     tsall.unset(TrackStatePropMask::Jacobian);
0610     BOOST_CHECK(!tsall.template has<"jacobian"_hash>());
0611     tsall.unset(TrackStatePropMask::Calibrated);
0612     BOOST_CHECK(!tsall.template has<"calibrated"_hash>());
0613   }
0614 
0615   void testTrackStateProxyGetMask() {
0616     using PM = TrackStatePropMask;
0617 
0618     std::array<PM, 5> values{PM::Predicted, PM::Filtered, PM::Smoothed,
0619                              PM::Jacobian, PM::Calibrated};
0620     PM all = std::accumulate(values.begin(), values.end(), PM::None,
0621                              [](auto a, auto b) { return a | b; });
0622 
0623     trajectory_t mj = m_factory.create();
0624     {
0625       auto ts = mj.getTrackState(mj.addTrackState(PM::All));
0626       // Calibrated is ignored because we haven't allocated yet
0627       BOOST_CHECK_EQUAL(ts.getMask(), (all & ~PM::Calibrated));
0628       ts.allocateCalibrated(4);
0629       BOOST_CHECK_EQUAL(ts.getMask(), all);
0630     }
0631     {
0632       auto ts =
0633           mj.getTrackState(mj.addTrackState(PM::Filtered | PM::Calibrated));
0634       // Calibrated is ignored because we haven't allocated yet
0635       BOOST_CHECK_EQUAL(ts.getMask(), PM::Filtered);
0636       ts.allocateCalibrated(4);
0637       BOOST_CHECK_EQUAL(ts.getMask(), (PM::Filtered | PM::Calibrated));
0638     }
0639     {
0640       auto ts = mj.getTrackState(
0641           mj.addTrackState(PM::Filtered | PM::Smoothed | PM::Predicted));
0642       BOOST_CHECK_EQUAL(ts.getMask(),
0643                         (PM::Filtered | PM::Smoothed | PM::Predicted));
0644     }
0645     {
0646       for (PM mask : values) {
0647         auto ts = mj.getTrackState(mj.addTrackState(mask));
0648         // Calibrated is ignored because we haven't allocated yet
0649         BOOST_CHECK_EQUAL(ts.getMask(), (mask & ~PM::Calibrated));
0650       }
0651     }
0652   }
0653 
0654   void testTrackStateProxyCopy(std::default_random_engine& rng) {
0655     using PM = TrackStatePropMask;
0656 
0657     std::array<PM, 4> values{PM::Predicted, PM::Filtered, PM::Smoothed,
0658                              PM::Jacobian};
0659 
0660     trajectory_t mj = m_factory.create();
0661     auto mkts = [&](PM mask) {
0662       auto r = mj.getTrackState(mj.addTrackState(mask));
0663       return r;
0664     };
0665 
0666     // orthogonal ones
0667     for (PM a : values) {
0668       for (PM b : values) {
0669         auto tsa = mkts(a);
0670         auto tsb = mkts(b);
0671         // doesn't work
0672         if (a != b) {
0673           BOOST_CHECK_THROW(tsa.copyFrom(tsb), std::runtime_error);
0674           BOOST_CHECK_THROW(tsb.copyFrom(tsa), std::runtime_error);
0675         } else {
0676           tsa.copyFrom(tsb);
0677           tsb.copyFrom(tsa);
0678         }
0679       }
0680     }
0681 
0682     {
0683       BOOST_TEST_CHECKPOINT("Calib auto alloc");
0684       auto tsa = mkts(PM::All);
0685       auto tsb = mkts(PM::All);
0686       tsb.allocateCalibrated(5);
0687       tsb.template calibrated<5>().setRandom();
0688       tsb.template calibratedCovariance<5>().setRandom();
0689       tsa.copyFrom(tsb, PM::All);
0690       BOOST_CHECK_EQUAL(tsa.template calibrated<5>(),
0691                         tsb.template calibrated<5>());
0692       BOOST_CHECK_EQUAL(tsa.template calibratedCovariance<5>(),
0693                         tsb.template calibratedCovariance<5>());
0694     }
0695 
0696     {
0697       BOOST_TEST_CHECKPOINT("Copy none");
0698       auto tsa = mkts(PM::All);
0699       auto tsb = mkts(PM::All);
0700       tsa.copyFrom(tsb, PM::None);
0701     }
0702 
0703     auto ts1 = mkts(PM::Filtered | PM::Predicted);  // this has both
0704     ts1.filtered().setRandom();
0705     ts1.filteredCovariance().setRandom();
0706     ts1.predicted().setRandom();
0707     ts1.predictedCovariance().setRandom();
0708 
0709     // ((src XOR dst) & src) == 0
0710     auto ts2 = mkts(PM::Predicted);
0711     ts2.predicted().setRandom();
0712     ts2.predictedCovariance().setRandom();
0713 
0714     // they are different before
0715     BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
0716     BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
0717 
0718     // ts1 -> ts2 fails
0719     BOOST_CHECK_THROW(ts2.copyFrom(ts1), std::runtime_error);
0720     BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
0721     BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
0722 
0723     // ts2 -> ts1 is ok
0724     ts1.copyFrom(ts2);
0725     BOOST_CHECK_EQUAL(ts1.predicted(), ts2.predicted());
0726     BOOST_CHECK_EQUAL(ts1.predictedCovariance(), ts2.predictedCovariance());
0727 
0728     std::size_t i0 = mj.addTrackState();
0729     std::size_t i1 = mj.addTrackState();
0730     ts1 = mj.getTrackState(i0);
0731     ts2 = mj.getTrackState(i1);
0732     TestTrackState rts1(rng, 1u);
0733     TestTrackState rts2(rng, 2u);
0734     fillTrackState<trajectory_t>(rts1, TrackStatePropMask::All, ts1);
0735     fillTrackState<trajectory_t>(rts2, TrackStatePropMask::All, ts2);
0736 
0737     auto ots1 = mkts(PM::All);
0738     auto ots2 = mkts(PM::All);
0739     // make full copy for later. We prove full copy works right below
0740     ots1.copyFrom(ts1);
0741     ots2.copyFrom(ts2);
0742 
0743     BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
0744     BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
0745     BOOST_CHECK_NE(ts1.filtered(), ts2.filtered());
0746     BOOST_CHECK_NE(ts1.filteredCovariance(), ts2.filteredCovariance());
0747     BOOST_CHECK_NE(ts1.smoothed(), ts2.smoothed());
0748     BOOST_CHECK_NE(ts1.smoothedCovariance(), ts2.smoothedCovariance());
0749 
0750     BOOST_CHECK_NE(
0751         ts1.getUncalibratedSourceLink().template get<TestSourceLink>(),
0752         ts2.getUncalibratedSourceLink().template get<TestSourceLink>());
0753 
0754     visit_measurement(ts1.calibratedSize(), [&](auto N) {
0755       constexpr std::size_t measdim = decltype(N)::value;
0756       BOOST_CHECK_NE(ts1.template calibrated<measdim>(),
0757                      ts2.template calibrated<measdim>());
0758       BOOST_CHECK_NE(ts1.template calibratedCovariance<measdim>(),
0759                      ts2.template calibratedCovariance<measdim>());
0760     });
0761 
0762     BOOST_CHECK_NE(ts1.calibratedSize(), ts2.calibratedSize());
0763     BOOST_CHECK_NE(ts1.projector(), ts2.projector());
0764 
0765     BOOST_CHECK_NE(ts1.jacobian(), ts2.jacobian());
0766     BOOST_CHECK_NE(ts1.chi2(), ts2.chi2());
0767     BOOST_CHECK_NE(ts1.pathLength(), ts2.pathLength());
0768     BOOST_CHECK_NE(&ts1.referenceSurface(), &ts2.referenceSurface());
0769 
0770     ts1.copyFrom(ts2);
0771 
0772     BOOST_CHECK_EQUAL(ts1.predicted(), ts2.predicted());
0773     BOOST_CHECK_EQUAL(ts1.predictedCovariance(), ts2.predictedCovariance());
0774     BOOST_CHECK_EQUAL(ts1.filtered(), ts2.filtered());
0775     BOOST_CHECK_EQUAL(ts1.filteredCovariance(), ts2.filteredCovariance());
0776     BOOST_CHECK_EQUAL(ts1.smoothed(), ts2.smoothed());
0777     BOOST_CHECK_EQUAL(ts1.smoothedCovariance(), ts2.smoothedCovariance());
0778 
0779     BOOST_CHECK_EQUAL(
0780         ts1.getUncalibratedSourceLink().template get<TestSourceLink>(),
0781         ts2.getUncalibratedSourceLink().template get<TestSourceLink>());
0782 
0783     visit_measurement(ts1.calibratedSize(), [&](auto N) {
0784       constexpr std::size_t measdim = decltype(N)::value;
0785       BOOST_CHECK_EQUAL(ts1.template calibrated<measdim>(),
0786                         ts2.template calibrated<measdim>());
0787       BOOST_CHECK_EQUAL(ts1.template calibratedCovariance<measdim>(),
0788                         ts2.template calibratedCovariance<measdim>());
0789     });
0790 
0791     BOOST_CHECK_EQUAL(ts1.calibratedSize(), ts2.calibratedSize());
0792     BOOST_CHECK_EQUAL(ts1.projector(), ts2.projector());
0793 
0794     BOOST_CHECK_EQUAL(ts1.jacobian(), ts2.jacobian());
0795     BOOST_CHECK_EQUAL(ts1.chi2(), ts2.chi2());
0796     BOOST_CHECK_EQUAL(ts1.pathLength(), ts2.pathLength());
0797     BOOST_CHECK_EQUAL(&ts1.referenceSurface(), &ts2.referenceSurface());
0798 
0799     // full copy proven to work. now let's do partial copy
0800     ts2 = mkts(PM::Predicted | PM::Jacobian | PM::Calibrated);
0801     ts2.copyFrom(ots2, PM::Predicted | PM::Jacobian | PM::Calibrated);
0802     // copy into empty ts, only copy some
0803     ts1.copyFrom(ots1);  // reset to original
0804     // is different again
0805     BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
0806     BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
0807 
0808     visit_measurement(ts1.calibratedSize(), [&](auto N) {
0809       constexpr std::size_t measdim = decltype(N)::value;
0810       BOOST_CHECK_NE(ts1.template calibrated<measdim>(),
0811                      ts2.template calibrated<measdim>());
0812       BOOST_CHECK_NE(ts1.template calibratedCovariance<measdim>(),
0813                      ts2.template calibratedCovariance<measdim>());
0814     });
0815 
0816     BOOST_CHECK_NE(ts1.calibratedSize(), ts2.calibratedSize());
0817     BOOST_CHECK_NE(ts1.projector(), ts2.projector());
0818 
0819     BOOST_CHECK_NE(ts1.jacobian(), ts2.jacobian());
0820     BOOST_CHECK_NE(ts1.chi2(), ts2.chi2());
0821     BOOST_CHECK_NE(ts1.pathLength(), ts2.pathLength());
0822     BOOST_CHECK_NE(&ts1.referenceSurface(), &ts2.referenceSurface());
0823 
0824     ts1.copyFrom(ts2);
0825 
0826     // some components are same now
0827     BOOST_CHECK_EQUAL(ts1.predicted(), ts2.predicted());
0828     BOOST_CHECK_EQUAL(ts1.predictedCovariance(), ts2.predictedCovariance());
0829 
0830     visit_measurement(ts1.calibratedSize(), [&](auto N) {
0831       constexpr std::size_t measdim = decltype(N)::value;
0832       BOOST_CHECK_EQUAL(ts1.template calibrated<measdim>(),
0833                         ts2.template calibrated<measdim>());
0834       BOOST_CHECK_EQUAL(ts1.template calibratedCovariance<measdim>(),
0835                         ts2.template calibratedCovariance<measdim>());
0836     });
0837 
0838     BOOST_CHECK_EQUAL(ts1.calibratedSize(), ts2.calibratedSize());
0839     BOOST_CHECK_EQUAL(ts1.projector(), ts2.projector());
0840 
0841     BOOST_CHECK_EQUAL(ts1.jacobian(), ts2.jacobian());
0842     BOOST_CHECK_EQUAL(ts1.chi2(), ts2.chi2());              // always copied
0843     BOOST_CHECK_EQUAL(ts1.pathLength(), ts2.pathLength());  // always copied
0844     BOOST_CHECK_EQUAL(&ts1.referenceSurface(),
0845                       &ts2.referenceSurface());  // always copied
0846   }
0847 
0848   void testTrackStateCopyDynamicColumns() {
0849     // mutable source
0850     trajectory_t mtj = m_factory.create();
0851     mtj.template addColumn<uint64_t>("counter");
0852     mtj.template addColumn<uint8_t>("odd");
0853 
0854     trajectory_t mtj2 = m_factory.create();
0855     // doesn't have the dynamic column
0856 
0857     trajectory_t mtj3 = m_factory.create();
0858     mtj3.template addColumn<uint64_t>("counter");
0859     mtj3.template addColumn<uint8_t>("odd");
0860 
0861     for (MultiTrajectoryTraits::IndexType i = 0; i < 10; i++) {
0862       auto ts =
0863           mtj.getTrackState(mtj.addTrackState(TrackStatePropMask::All, i));
0864       ts.template component<uint64_t>("counter") = i;
0865       ts.template component<uint8_t>("odd") = i % 2 == 0;
0866 
0867       auto ts2 =
0868           mtj2.getTrackState(mtj2.addTrackState(TrackStatePropMask::All, i));
0869       BOOST_CHECK_THROW(ts2.copyFrom(ts),
0870                         std::invalid_argument);  // this should fail
0871 
0872       auto ts3 =
0873           mtj3.getTrackState(mtj3.addTrackState(TrackStatePropMask::All, i));
0874       ts3.copyFrom(ts);  // this should work
0875 
0876       BOOST_CHECK_NE(ts3.index(), MultiTrajectoryTraits::kInvalid);
0877 
0878       BOOST_CHECK_EQUAL(ts.template component<uint64_t>("counter"),
0879                         ts3.template component<uint64_t>("counter"));
0880       BOOST_CHECK_EQUAL(ts.template component<uint8_t>("odd"),
0881                         ts3.template component<uint8_t>("odd"));
0882     }
0883 
0884     std::size_t before = mtj.size();
0885     const_trajectory_t cmtj{mtj};
0886 
0887     BOOST_REQUIRE_EQUAL(cmtj.size(), before);
0888 
0889     VectorMultiTrajectory mtj5;
0890     mtj5.addColumn<uint64_t>("counter");
0891     mtj5.addColumn<uint8_t>("odd");
0892 
0893     for (std::size_t i = 0; i < 10; i++) {
0894       auto ts4 = cmtj.getTrackState(i);  // const source!
0895 
0896       auto ts5 =
0897           mtj5.getTrackState(mtj5.addTrackState(TrackStatePropMask::All, 0));
0898       ts5.copyFrom(ts4);  // this should work
0899 
0900       BOOST_CHECK_NE(ts5.index(), MultiTrajectoryTraits::kInvalid);
0901 
0902       BOOST_CHECK_EQUAL(ts4.template component<uint64_t>("counter"),
0903                         ts5.template component<uint64_t>("counter"));
0904       BOOST_CHECK_EQUAL(ts4.template component<uint8_t>("odd"),
0905                         ts5.template component<uint8_t>("odd"));
0906     }
0907   }
0908 
0909   void testTrackStateProxyCopyDiffMTJ() {
0910     using PM = TrackStatePropMask;
0911 
0912     std::array<PM, 4> values{PM::Predicted, PM::Filtered, PM::Smoothed,
0913                              PM::Jacobian};
0914 
0915     trajectory_t mj = m_factory.create();
0916     trajectory_t mj2 = m_factory.create();
0917     auto mkts = [&](PM mask) {
0918       auto r = mj.getTrackState(mj.addTrackState(mask));
0919       return r;
0920     };
0921     auto mkts2 = [&](PM mask) {
0922       auto r = mj2.getTrackState(mj2.addTrackState(mask));
0923       return r;
0924     };
0925 
0926     // orthogonal ones
0927     for (PM a : values) {
0928       for (PM b : values) {
0929         auto tsa = mkts(a);
0930         auto tsb = mkts2(b);
0931         // doesn't work
0932         if (a != b) {
0933           BOOST_CHECK_THROW(tsa.copyFrom(tsb), std::runtime_error);
0934           BOOST_CHECK_THROW(tsb.copyFrom(tsa), std::runtime_error);
0935         } else {
0936           tsa.copyFrom(tsb);
0937           tsb.copyFrom(tsa);
0938         }
0939       }
0940     }
0941 
0942     // make sure they are actually on different MultiTrajectories
0943     BOOST_CHECK_EQUAL(mj.size(), values.size() * values.size());
0944     BOOST_CHECK_EQUAL(mj2.size(), values.size() * values.size());
0945 
0946     auto ts1 = mkts(PM::Filtered | PM::Predicted);  // this has both
0947     ts1.filtered().setRandom();
0948     ts1.filteredCovariance().setRandom();
0949     ts1.predicted().setRandom();
0950     ts1.predictedCovariance().setRandom();
0951 
0952     // ((src XOR dst) & src) == 0
0953     auto ts2 = mkts2(PM::Predicted);
0954     ts2.predicted().setRandom();
0955     ts2.predictedCovariance().setRandom();
0956 
0957     // they are different before
0958     BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
0959     BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
0960 
0961     // ts1 -> ts2 fails
0962     BOOST_CHECK_THROW(ts2.copyFrom(ts1), std::runtime_error);
0963     BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
0964     BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
0965 
0966     // ts2 -> ts1 is ok
0967     ts1.copyFrom(ts2);
0968     BOOST_CHECK_EQUAL(ts1.predicted(), ts2.predicted());
0969     BOOST_CHECK_EQUAL(ts1.predictedCovariance(), ts2.predictedCovariance());
0970 
0971     {
0972       BOOST_TEST_CHECKPOINT("Calib auto alloc");
0973       auto tsa = mkts(PM::All);
0974       auto tsb = mkts(PM::All);
0975       tsb.allocateCalibrated(5);
0976       tsb.template calibrated<5>().setRandom();
0977       tsb.template calibratedCovariance<5>().setRandom();
0978       tsa.copyFrom(tsb, PM::All);
0979       BOOST_CHECK_EQUAL(tsa.template calibrated<5>(),
0980                         tsb.template calibrated<5>());
0981       BOOST_CHECK_EQUAL(tsa.template calibratedCovariance<5>(),
0982                         tsb.template calibratedCovariance<5>());
0983     }
0984 
0985     {
0986       BOOST_TEST_CHECKPOINT("Copy none");
0987       auto tsa = mkts(PM::All);
0988       auto tsb = mkts(PM::All);
0989       tsa.copyFrom(tsb, PM::None);
0990     }
0991   }
0992 
0993   void testProxyAssignment() {
0994     constexpr TrackStatePropMask kMask = TrackStatePropMask::Predicted;
0995     trajectory_t t = m_factory.create();
0996     auto i0 = t.addTrackState(kMask);
0997 
0998     typename trajectory_t::TrackStateProxy tp = t.getTrackState(i0);  // mutable
0999     typename trajectory_t::TrackStateProxy tp2{tp};       // mutable to mutable
1000     typename trajectory_t::ConstTrackStateProxy tp3{tp};  // mutable to const
1001     // const to mutable: this won't compile
1002     // MultiTrajectory::TrackStateProxy tp4{tp3};
1003   }
1004 
1005   void testCopyFromConst() {
1006     // Check if the copy from const does compile, assume the copy is done
1007     // correctly
1008 
1009     using PM = TrackStatePropMask;
1010     trajectory_t mj = m_factory.create();
1011 
1012     const auto idx_a = mj.addTrackState(PM::All);
1013     const auto idx_b = mj.addTrackState(PM::All);
1014 
1015     typename trajectory_t::TrackStateProxy mutableProxy =
1016         mj.getTrackState(idx_a);
1017 
1018     const trajectory_t& cmj = mj;
1019     typename trajectory_t::ConstTrackStateProxy constProxy =
1020         cmj.getTrackState(idx_b);
1021 
1022     mutableProxy.copyFrom(constProxy);
1023 
1024     // copy mutable to const: this won't compile
1025     // constProxy.copyFrom(mutableProxy);
1026   }
1027 
1028   void testTrackStateProxyShare(std::default_random_engine& rng) {
1029     TestTrackState pc(rng, 2u);
1030 
1031     {
1032       trajectory_t traj = m_factory.create();
1033       std::size_t ia = traj.addTrackState(TrackStatePropMask::All);
1034       std::size_t ib = traj.addTrackState(TrackStatePropMask::None);
1035 
1036       auto tsa = traj.getTrackState(ia);
1037       auto tsb = traj.getTrackState(ib);
1038 
1039       fillTrackState<trajectory_t>(pc, TrackStatePropMask::All, tsa);
1040 
1041       BOOST_CHECK(tsa.hasPredicted());
1042       BOOST_CHECK(!tsb.hasPredicted());
1043       tsb.shareFrom(tsa, TrackStatePropMask::Predicted);
1044       BOOST_CHECK(tsa.hasPredicted());
1045       BOOST_CHECK(tsb.hasPredicted());
1046       BOOST_CHECK_EQUAL(tsa.predicted(), tsb.predicted());
1047       BOOST_CHECK_EQUAL(tsa.predictedCovariance(), tsb.predictedCovariance());
1048 
1049       BOOST_CHECK(tsa.hasFiltered());
1050       BOOST_CHECK(!tsb.hasFiltered());
1051       tsb.shareFrom(tsa, TrackStatePropMask::Filtered);
1052       BOOST_CHECK(tsa.hasFiltered());
1053       BOOST_CHECK(tsb.hasFiltered());
1054       BOOST_CHECK_EQUAL(tsa.filtered(), tsb.filtered());
1055       BOOST_CHECK_EQUAL(tsa.filteredCovariance(), tsb.filteredCovariance());
1056 
1057       BOOST_CHECK(tsa.hasSmoothed());
1058       BOOST_CHECK(!tsb.hasSmoothed());
1059       tsb.shareFrom(tsa, TrackStatePropMask::Smoothed);
1060       BOOST_CHECK(tsa.hasSmoothed());
1061       BOOST_CHECK(tsb.hasSmoothed());
1062       BOOST_CHECK_EQUAL(tsa.smoothed(), tsb.smoothed());
1063       BOOST_CHECK_EQUAL(tsa.smoothedCovariance(), tsb.smoothedCovariance());
1064 
1065       BOOST_CHECK(tsa.hasJacobian());
1066       BOOST_CHECK(!tsb.hasJacobian());
1067       tsb.shareFrom(tsa, TrackStatePropMask::Jacobian);
1068       BOOST_CHECK(tsa.hasJacobian());
1069       BOOST_CHECK(tsb.hasJacobian());
1070       BOOST_CHECK_EQUAL(tsa.jacobian(), tsb.jacobian());
1071     }
1072 
1073     {
1074       trajectory_t traj = m_factory.create();
1075       std::size_t i = traj.addTrackState(TrackStatePropMask::All &
1076                                          ~TrackStatePropMask::Filtered &
1077                                          ~TrackStatePropMask::Smoothed);
1078 
1079       auto ts = traj.getTrackState(i);
1080 
1081       BOOST_CHECK(ts.hasPredicted());
1082       BOOST_CHECK(!ts.hasFiltered());
1083       BOOST_CHECK(!ts.hasSmoothed());
1084       ts.predicted().setRandom();
1085       ts.predictedCovariance().setRandom();
1086 
1087       ts.shareFrom(TrackStatePropMask::Predicted, TrackStatePropMask::Filtered);
1088       BOOST_CHECK(ts.hasPredicted());
1089       BOOST_CHECK(ts.hasFiltered());
1090       BOOST_CHECK(!ts.hasSmoothed());
1091       BOOST_CHECK_EQUAL(ts.predicted(), ts.filtered());
1092       BOOST_CHECK_EQUAL(ts.predictedCovariance(), ts.filteredCovariance());
1093 
1094       ts.shareFrom(TrackStatePropMask::Predicted, TrackStatePropMask::Smoothed);
1095       BOOST_CHECK(ts.hasPredicted());
1096       BOOST_CHECK(ts.hasFiltered());
1097       BOOST_CHECK(ts.hasSmoothed());
1098       BOOST_CHECK_EQUAL(ts.predicted(), ts.filtered());
1099       BOOST_CHECK_EQUAL(ts.predicted(), ts.smoothed());
1100       BOOST_CHECK_EQUAL(ts.predictedCovariance(), ts.filteredCovariance());
1101       BOOST_CHECK_EQUAL(ts.predictedCovariance(), ts.smoothedCovariance());
1102     }
1103   }
1104 
1105   void testMultiTrajectoryExtraColumns() {
1106     using namespace HashedStringLiteral;
1107 
1108     auto test = [&](const std::string& col, auto value) {
1109       using T = decltype(value);
1110       std::string col2 = col + "_2";
1111       HashedString h{hashString(col)};
1112       HashedString h2{hashString(col2)};
1113 
1114       trajectory_t traj = m_factory.create();
1115       BOOST_CHECK(!traj.hasColumn(h));
1116       traj.template addColumn<T>(col);
1117       BOOST_CHECK(traj.hasColumn(h));
1118 
1119       BOOST_CHECK(!traj.hasColumn(h2));
1120       traj.template addColumn<T>(col2);
1121       BOOST_CHECK(traj.hasColumn(h2));
1122 
1123       auto ts1 = traj.getTrackState(traj.addTrackState());
1124       auto ts2 = traj.getTrackState(
1125           traj.addTrackState(TrackStatePropMask::All, ts1.index()));
1126       auto ts3 = traj.getTrackState(
1127           traj.addTrackState(TrackStatePropMask::All, ts2.index()));
1128 
1129       BOOST_CHECK(ts1.has(h));
1130       BOOST_CHECK(ts2.has(h));
1131       BOOST_CHECK(ts3.has(h));
1132 
1133       BOOST_CHECK(ts1.has(h2));
1134       BOOST_CHECK(ts2.has(h2));
1135       BOOST_CHECK(ts3.has(h2));
1136 
1137       ts1.template component<T>(col) = value;
1138       BOOST_CHECK_EQUAL(ts1.template component<T>(col), value);
1139     };
1140 
1141     test("uint32_t", std::uint32_t{1});
1142     test("uint64_t", std::uint64_t{2});
1143     test("int32_t", std::int32_t{-3});
1144     test("int64_t", std::int64_t{-4});
1145     test("float", float{8.9});
1146     test("double", double{656.2});
1147 
1148     trajectory_t traj = m_factory.create();
1149     traj.template addColumn<int>("extra_column");
1150     traj.template addColumn<float>("another_column");
1151 
1152     auto ts1 = traj.getTrackState(traj.addTrackState());
1153     auto ts2 = traj.getTrackState(
1154         traj.addTrackState(TrackStatePropMask::All, ts1.index()));
1155     auto ts3 = traj.getTrackState(
1156         traj.addTrackState(TrackStatePropMask::All, ts2.index()));
1157 
1158     BOOST_CHECK(ts1.template has<"extra_column"_hash>());
1159     BOOST_CHECK(ts2.template has<"extra_column"_hash>());
1160     BOOST_CHECK(ts3.template has<"extra_column"_hash>());
1161 
1162     BOOST_CHECK(ts1.template has<"another_column"_hash>());
1163     BOOST_CHECK(ts2.template has<"another_column"_hash>());
1164     BOOST_CHECK(ts3.template has<"another_column"_hash>());
1165 
1166     ts2.template component<int, "extra_column"_hash>() = 6;
1167 
1168     BOOST_CHECK_EQUAL((ts2.template component<int, "extra_column"_hash>()), 6);
1169 
1170     ts3.template component<float, "another_column"_hash>() = 7.2f;
1171     BOOST_CHECK_EQUAL((ts3.template component<float, "another_column"_hash>()),
1172                       7.2f);
1173   }
1174 
1175   void testMultiTrajectoryExtraColumnsRuntime() {
1176     auto runTest = [&](auto&& fn) {
1177       trajectory_t mt = m_factory.create();
1178       std::vector<std::string> columns = {"one", "two", "three", "four"};
1179       for (const auto& c : columns) {
1180         BOOST_CHECK(!mt.hasColumn(fn(c)));
1181         mt.template addColumn<int>(c);
1182         BOOST_CHECK(mt.hasColumn(fn(c)));
1183       }
1184       for (const auto& c : columns) {
1185         auto ts1 = mt.getTrackState(mt.addTrackState());
1186         auto ts2 = mt.getTrackState(mt.addTrackState());
1187         BOOST_CHECK(ts1.has(fn(c)));
1188         BOOST_CHECK(ts2.has(fn(c)));
1189         ts1.template component<int>(fn(c)) = 674;
1190         ts2.template component<int>(fn(c)) = 421;
1191         BOOST_CHECK_EQUAL(ts1.template component<int>(fn(c)), 674);
1192         BOOST_CHECK_EQUAL(ts2.template component<int>(fn(c)), 421);
1193       }
1194     };
1195 
1196     runTest([](const std::string& c) { return hashString(c.c_str()); });
1197     // runTest([](const std::string& c) { return c.c_str(); });
1198     // runTest([](const std::string& c) { return c; });
1199     // runTest([](std::string_view c) { return c; });
1200   }
1201 };
1202 }  // namespace Acts::detail::Test