Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:22:16

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