Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-07 08:10:00

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