Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:10:47

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     visit_measurement(ts1.calibratedSize(), [&](auto N) {
0762       constexpr std::size_t measdim = decltype(N)::value;
0763       BOOST_CHECK_NE(ts1.template calibrated<measdim>(),
0764                      ts2.template calibrated<measdim>());
0765       BOOST_CHECK_NE(ts1.template calibratedCovariance<measdim>(),
0766                      ts2.template calibratedCovariance<measdim>());
0767     });
0768 
0769     BOOST_CHECK_NE(ts1.calibratedSize(), ts2.calibratedSize());
0770     BOOST_CHECK(ts1.projectorSubspaceIndices() !=
0771                 ts2.projectorSubspaceIndices());
0772 
0773     BOOST_CHECK_NE(ts1.jacobian(), ts2.jacobian());
0774     BOOST_CHECK_NE(ts1.chi2(), ts2.chi2());
0775     BOOST_CHECK_NE(ts1.pathLength(), ts2.pathLength());
0776     BOOST_CHECK_NE(&ts1.referenceSurface(), &ts2.referenceSurface());
0777 
0778     // Explicitly unset to avoid error below
0779     ts1.unset(TrackStatePropMask::Calibrated);
0780     ts1.copyFrom(ts2);
0781 
0782     BOOST_CHECK_EQUAL(ts1.predicted(), ts2.predicted());
0783     BOOST_CHECK_EQUAL(ts1.predictedCovariance(), ts2.predictedCovariance());
0784     BOOST_CHECK_EQUAL(ts1.filtered(), ts2.filtered());
0785     BOOST_CHECK_EQUAL(ts1.filteredCovariance(), ts2.filteredCovariance());
0786     BOOST_CHECK_EQUAL(ts1.smoothed(), ts2.smoothed());
0787     BOOST_CHECK_EQUAL(ts1.smoothedCovariance(), ts2.smoothedCovariance());
0788 
0789     BOOST_CHECK_EQUAL(
0790         ts1.getUncalibratedSourceLink().template get<TestSourceLink>(),
0791         ts2.getUncalibratedSourceLink().template get<TestSourceLink>());
0792 
0793     visit_measurement(ts1.calibratedSize(), [&](auto N) {
0794       constexpr std::size_t measdim = decltype(N)::value;
0795       BOOST_CHECK_EQUAL(ts1.template calibrated<measdim>(),
0796                         ts2.template calibrated<measdim>());
0797       BOOST_CHECK_EQUAL(ts1.template calibratedCovariance<measdim>(),
0798                         ts2.template calibratedCovariance<measdim>());
0799     });
0800 
0801     BOOST_CHECK_EQUAL(ts1.calibratedSize(), ts2.calibratedSize());
0802     BOOST_CHECK(ts1.projectorSubspaceIndices() ==
0803                 ts2.projectorSubspaceIndices());
0804 
0805     BOOST_CHECK_EQUAL(ts1.jacobian(), ts2.jacobian());
0806     BOOST_CHECK_EQUAL(ts1.chi2(), ts2.chi2());
0807     BOOST_CHECK_EQUAL(ts1.pathLength(), ts2.pathLength());
0808     BOOST_CHECK_EQUAL(&ts1.referenceSurface(), &ts2.referenceSurface());
0809 
0810     // full copy proven to work. now let's do partial copy
0811     ts2 = mkts(PM::Predicted | PM::Jacobian | PM::Calibrated);
0812     ts2.copyFrom(ots2, PM::Predicted | PM::Jacobian | PM::Calibrated);
0813     // copy into empty ts, only copy some
0814     // explicitly unset to avoid error below
0815     ts1.unset(TrackStatePropMask::Calibrated);
0816     ts1.copyFrom(ots1);  // reset to original
0817     // is different again
0818     BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
0819     BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
0820 
0821     visit_measurement(ts1.calibratedSize(), [&](auto N) {
0822       constexpr std::size_t measdim = decltype(N)::value;
0823       BOOST_CHECK_NE(ts1.template calibrated<measdim>(),
0824                      ts2.template calibrated<measdim>());
0825       BOOST_CHECK_NE(ts1.template calibratedCovariance<measdim>(),
0826                      ts2.template calibratedCovariance<measdim>());
0827     });
0828 
0829     BOOST_CHECK_NE(ts1.calibratedSize(), ts2.calibratedSize());
0830     BOOST_CHECK(ts1.projectorSubspaceIndices() !=
0831                 ts2.projectorSubspaceIndices());
0832 
0833     BOOST_CHECK_NE(ts1.jacobian(), ts2.jacobian());
0834     BOOST_CHECK_NE(ts1.chi2(), ts2.chi2());
0835     BOOST_CHECK_NE(ts1.pathLength(), ts2.pathLength());
0836     BOOST_CHECK_NE(&ts1.referenceSurface(), &ts2.referenceSurface());
0837 
0838     // Explicitly unset to avoid error below
0839     ts1.unset(TrackStatePropMask::Calibrated);
0840     ts1.copyFrom(ts2);
0841 
0842     // some components are same now
0843     BOOST_CHECK_EQUAL(ts1.predicted(), ts2.predicted());
0844     BOOST_CHECK_EQUAL(ts1.predictedCovariance(), ts2.predictedCovariance());
0845 
0846     visit_measurement(ts1.calibratedSize(), [&](auto N) {
0847       constexpr std::size_t measdim = decltype(N)::value;
0848       BOOST_CHECK_EQUAL(ts1.template calibrated<measdim>(),
0849                         ts2.template calibrated<measdim>());
0850       BOOST_CHECK_EQUAL(ts1.template calibratedCovariance<measdim>(),
0851                         ts2.template calibratedCovariance<measdim>());
0852     });
0853 
0854     BOOST_CHECK_EQUAL(ts1.calibratedSize(), ts2.calibratedSize());
0855     BOOST_CHECK(ts1.projectorSubspaceIndices() ==
0856                 ts2.projectorSubspaceIndices());
0857 
0858     BOOST_CHECK_EQUAL(ts1.jacobian(), ts2.jacobian());
0859     BOOST_CHECK_EQUAL(ts1.chi2(), ts2.chi2());              // always copied
0860     BOOST_CHECK_EQUAL(ts1.pathLength(), ts2.pathLength());  // always copied
0861     BOOST_CHECK_EQUAL(&ts1.referenceSurface(),
0862                       &ts2.referenceSurface());  // always copied
0863   }
0864 
0865   void testTrackStateCopyDynamicColumns() {
0866     // mutable source
0867     trajectory_t mtj = m_factory.create();
0868     mtj.template addColumn<std::uint64_t>("counter");
0869     mtj.template addColumn<std::uint8_t>("odd");
0870 
0871     trajectory_t mtj2 = m_factory.create();
0872     // doesn't have the dynamic column
0873 
0874     trajectory_t mtj3 = m_factory.create();
0875     mtj3.template addColumn<std::uint64_t>("counter");
0876     mtj3.template addColumn<std::uint8_t>("odd");
0877 
0878     for (MultiTrajectoryTraits::IndexType i = 0; i < 10; i++) {
0879       auto ts =
0880           mtj.getTrackState(mtj.addTrackState(TrackStatePropMask::All, i));
0881       ts.template component<std::uint64_t>("counter") = i;
0882       ts.template component<std::uint8_t>("odd") = i % 2 == 0;
0883 
0884       auto ts2 =
0885           mtj2.getTrackState(mtj2.addTrackState(TrackStatePropMask::All, i));
0886       BOOST_CHECK_THROW(ts2.copyFrom(ts),
0887                         std::invalid_argument);  // this should fail
0888 
0889       auto ts3 =
0890           mtj3.getTrackState(mtj3.addTrackState(TrackStatePropMask::All, i));
0891       ts3.copyFrom(ts);  // this should work
0892 
0893       BOOST_CHECK_NE(ts3.index(), MultiTrajectoryTraits::kInvalid);
0894 
0895       BOOST_CHECK_EQUAL(ts.template component<std::uint64_t>("counter"),
0896                         ts3.template component<std::uint64_t>("counter"));
0897       BOOST_CHECK_EQUAL(ts.template component<std::uint8_t>("odd"),
0898                         ts3.template component<std::uint8_t>("odd"));
0899     }
0900 
0901     std::size_t before = mtj.size();
0902     const_trajectory_t cmtj{mtj};
0903 
0904     BOOST_REQUIRE_EQUAL(cmtj.size(), before);
0905 
0906     VectorMultiTrajectory mtj5;
0907     mtj5.addColumn<std::uint64_t>("counter");
0908     mtj5.addColumn<std::uint8_t>("odd");
0909 
0910     for (std::size_t i = 0; i < 10; i++) {
0911       auto ts4 = cmtj.getTrackState(i);  // const source!
0912 
0913       auto ts5 =
0914           mtj5.getTrackState(mtj5.addTrackState(TrackStatePropMask::All, 0));
0915       ts5.copyFrom(ts4);  // this should work
0916 
0917       BOOST_CHECK_NE(ts5.index(), MultiTrajectoryTraits::kInvalid);
0918 
0919       BOOST_CHECK_EQUAL(ts4.template component<std::uint64_t>("counter"),
0920                         ts5.template component<std::uint64_t>("counter"));
0921       BOOST_CHECK_EQUAL(ts4.template component<std::uint8_t>("odd"),
0922                         ts5.template component<std::uint8_t>("odd"));
0923     }
0924   }
0925 
0926   void testTrackStateProxyCopyDiffMTJ() {
0927     using PM = TrackStatePropMask;
0928 
0929     std::array<PM, 4> values{PM::Predicted, PM::Filtered, PM::Smoothed,
0930                              PM::Jacobian};
0931 
0932     trajectory_t mj = m_factory.create();
0933     trajectory_t mj2 = m_factory.create();
0934     auto mkts = [&](PM mask) {
0935       auto r = mj.getTrackState(mj.addTrackState(mask));
0936       return r;
0937     };
0938     auto mkts2 = [&](PM mask) {
0939       auto r = mj2.getTrackState(mj2.addTrackState(mask));
0940       return r;
0941     };
0942 
0943     // orthogonal ones
0944     for (PM a : values) {
0945       for (PM b : values) {
0946         auto tsa = mkts(a);
0947         auto tsb = mkts2(b);
0948         // doesn't work
0949         if (a != b) {
0950           BOOST_CHECK_THROW(tsa.copyFrom(tsb), std::runtime_error);
0951           BOOST_CHECK_THROW(tsb.copyFrom(tsa), std::runtime_error);
0952         } else {
0953           tsa.copyFrom(tsb);
0954           tsb.copyFrom(tsa);
0955         }
0956       }
0957     }
0958 
0959     // make sure they are actually on different MultiTrajectories
0960     BOOST_CHECK_EQUAL(mj.size(), values.size() * values.size());
0961     BOOST_CHECK_EQUAL(mj2.size(), values.size() * values.size());
0962 
0963     auto ts1 = mkts(PM::Filtered | PM::Predicted);  // this has both
0964     ts1.filtered().setRandom();
0965     ts1.filteredCovariance().setRandom();
0966     ts1.predicted().setRandom();
0967     ts1.predictedCovariance().setRandom();
0968 
0969     // ((src XOR dst) & src) == 0
0970     auto ts2 = mkts2(PM::Predicted);
0971     ts2.predicted().setRandom();
0972     ts2.predictedCovariance().setRandom();
0973 
0974     // they are different before
0975     BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
0976     BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
0977 
0978     // ts1 -> ts2 fails
0979     BOOST_CHECK_THROW(ts2.copyFrom(ts1), std::runtime_error);
0980     BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
0981     BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
0982 
0983     // ts2 -> ts1 is ok
0984     ts1.copyFrom(ts2);
0985     BOOST_CHECK_EQUAL(ts1.predicted(), ts2.predicted());
0986     BOOST_CHECK_EQUAL(ts1.predictedCovariance(), ts2.predictedCovariance());
0987 
0988     {
0989       BOOST_TEST_CHECKPOINT("Calib auto alloc");
0990       auto tsa = mkts(PM::All);
0991       auto tsb = mkts(PM::All);
0992       tsb.allocateCalibrated(5);
0993       tsb.template calibrated<5>().setRandom();
0994       tsb.template calibratedCovariance<5>().setRandom();
0995       tsa.copyFrom(tsb, PM::All);
0996       BOOST_CHECK_EQUAL(tsa.template calibrated<5>(),
0997                         tsb.template calibrated<5>());
0998       BOOST_CHECK_EQUAL(tsa.template calibratedCovariance<5>(),
0999                         tsb.template calibratedCovariance<5>());
1000     }
1001 
1002     {
1003       BOOST_TEST_CHECKPOINT("Copy none");
1004       auto tsa = mkts(PM::All);
1005       auto tsb = mkts(PM::All);
1006       tsa.copyFrom(tsb, PM::None);
1007     }
1008   }
1009 
1010   void testProxyAssignment() {
1011     constexpr TrackStatePropMask kMask = TrackStatePropMask::Predicted;
1012     trajectory_t t = m_factory.create();
1013     auto i0 = t.addTrackState(kMask);
1014 
1015     typename trajectory_t::TrackStateProxy tp = t.getTrackState(i0);  // mutable
1016     typename trajectory_t::TrackStateProxy tp2{tp};       // mutable to mutable
1017     typename trajectory_t::ConstTrackStateProxy tp3{tp};  // mutable to const
1018     // const to mutable: this won't compile
1019     // MultiTrajectory::TrackStateProxy tp4{tp3};
1020   }
1021 
1022   void testCopyFromConst() {
1023     // Check if the copy from const does compile, assume the copy is done
1024     // correctly
1025 
1026     using PM = TrackStatePropMask;
1027     trajectory_t mj = m_factory.create();
1028 
1029     const auto idx_a = mj.addTrackState(PM::All);
1030     const auto idx_b = mj.addTrackState(PM::All);
1031 
1032     typename trajectory_t::TrackStateProxy mutableProxy =
1033         mj.getTrackState(idx_a);
1034 
1035     const trajectory_t& cmj = mj;
1036     typename trajectory_t::ConstTrackStateProxy constProxy =
1037         cmj.getTrackState(idx_b);
1038 
1039     mutableProxy.copyFrom(constProxy);
1040 
1041     // copy mutable to const: this won't compile
1042     // constProxy.copyFrom(mutableProxy);
1043   }
1044 
1045   void testTrackStateProxyShare(std::default_random_engine& rng) {
1046     TestTrackState pc(rng, 2u);
1047 
1048     {
1049       trajectory_t traj = m_factory.create();
1050       std::size_t ia = traj.addTrackState(TrackStatePropMask::All);
1051       std::size_t ib = traj.addTrackState(TrackStatePropMask::None);
1052 
1053       auto tsa = traj.getTrackState(ia);
1054       auto tsb = traj.getTrackState(ib);
1055 
1056       fillTrackState<trajectory_t>(pc, TrackStatePropMask::All, tsa);
1057 
1058       BOOST_CHECK(tsa.hasPredicted());
1059       BOOST_CHECK(!tsb.hasPredicted());
1060       tsb.shareFrom(tsa, TrackStatePropMask::Predicted);
1061       BOOST_CHECK(tsa.hasPredicted());
1062       BOOST_CHECK(tsb.hasPredicted());
1063       BOOST_CHECK_EQUAL(tsa.predicted(), tsb.predicted());
1064       BOOST_CHECK_EQUAL(tsa.predictedCovariance(), tsb.predictedCovariance());
1065 
1066       BOOST_CHECK(tsa.hasFiltered());
1067       BOOST_CHECK(!tsb.hasFiltered());
1068       tsb.shareFrom(tsa, TrackStatePropMask::Filtered);
1069       BOOST_CHECK(tsa.hasFiltered());
1070       BOOST_CHECK(tsb.hasFiltered());
1071       BOOST_CHECK_EQUAL(tsa.filtered(), tsb.filtered());
1072       BOOST_CHECK_EQUAL(tsa.filteredCovariance(), tsb.filteredCovariance());
1073 
1074       BOOST_CHECK(tsa.hasSmoothed());
1075       BOOST_CHECK(!tsb.hasSmoothed());
1076       tsb.shareFrom(tsa, TrackStatePropMask::Smoothed);
1077       BOOST_CHECK(tsa.hasSmoothed());
1078       BOOST_CHECK(tsb.hasSmoothed());
1079       BOOST_CHECK_EQUAL(tsa.smoothed(), tsb.smoothed());
1080       BOOST_CHECK_EQUAL(tsa.smoothedCovariance(), tsb.smoothedCovariance());
1081 
1082       BOOST_CHECK(tsa.hasJacobian());
1083       BOOST_CHECK(!tsb.hasJacobian());
1084       tsb.shareFrom(tsa, TrackStatePropMask::Jacobian);
1085       BOOST_CHECK(tsa.hasJacobian());
1086       BOOST_CHECK(tsb.hasJacobian());
1087       BOOST_CHECK_EQUAL(tsa.jacobian(), tsb.jacobian());
1088     }
1089 
1090     {
1091       trajectory_t traj = m_factory.create();
1092       std::size_t i = traj.addTrackState(TrackStatePropMask::All &
1093                                          ~TrackStatePropMask::Filtered &
1094                                          ~TrackStatePropMask::Smoothed);
1095 
1096       auto ts = traj.getTrackState(i);
1097 
1098       BOOST_CHECK(ts.hasPredicted());
1099       BOOST_CHECK(!ts.hasFiltered());
1100       BOOST_CHECK(!ts.hasSmoothed());
1101       ts.predicted().setRandom();
1102       ts.predictedCovariance().setRandom();
1103 
1104       ts.shareFrom(TrackStatePropMask::Predicted, TrackStatePropMask::Filtered);
1105       BOOST_CHECK(ts.hasPredicted());
1106       BOOST_CHECK(ts.hasFiltered());
1107       BOOST_CHECK(!ts.hasSmoothed());
1108       BOOST_CHECK_EQUAL(ts.predicted(), ts.filtered());
1109       BOOST_CHECK_EQUAL(ts.predictedCovariance(), ts.filteredCovariance());
1110 
1111       ts.shareFrom(TrackStatePropMask::Predicted, TrackStatePropMask::Smoothed);
1112       BOOST_CHECK(ts.hasPredicted());
1113       BOOST_CHECK(ts.hasFiltered());
1114       BOOST_CHECK(ts.hasSmoothed());
1115       BOOST_CHECK_EQUAL(ts.predicted(), ts.filtered());
1116       BOOST_CHECK_EQUAL(ts.predicted(), ts.smoothed());
1117       BOOST_CHECK_EQUAL(ts.predictedCovariance(), ts.filteredCovariance());
1118       BOOST_CHECK_EQUAL(ts.predictedCovariance(), ts.smoothedCovariance());
1119     }
1120   }
1121 
1122   void testMultiTrajectoryExtraColumns() {
1123     using namespace HashedStringLiteral;
1124 
1125     auto test = [&](const std::string& col, auto value) {
1126       using T = decltype(value);
1127       std::string col2 = col + "_2";
1128       HashedString h{hashStringDynamic(col)};
1129       HashedString h2{hashStringDynamic(col2)};
1130 
1131       trajectory_t traj = m_factory.create();
1132       BOOST_CHECK(!traj.hasColumn(h));
1133       traj.template addColumn<T>(col);
1134       BOOST_CHECK(traj.hasColumn(h));
1135 
1136       BOOST_CHECK(!traj.hasColumn(h2));
1137       traj.template addColumn<T>(col2);
1138       BOOST_CHECK(traj.hasColumn(h2));
1139 
1140       auto ts1 = traj.getTrackState(traj.addTrackState());
1141       auto ts2 = traj.getTrackState(
1142           traj.addTrackState(TrackStatePropMask::All, ts1.index()));
1143       auto ts3 = traj.getTrackState(
1144           traj.addTrackState(TrackStatePropMask::All, ts2.index()));
1145 
1146       BOOST_CHECK(ts1.has(h));
1147       BOOST_CHECK(ts2.has(h));
1148       BOOST_CHECK(ts3.has(h));
1149 
1150       BOOST_CHECK(ts1.has(h2));
1151       BOOST_CHECK(ts2.has(h2));
1152       BOOST_CHECK(ts3.has(h2));
1153 
1154       ts1.template component<T>(col) = value;
1155       BOOST_CHECK_EQUAL(ts1.template component<T>(col), value);
1156     };
1157 
1158     test("std_uint32_t", std::uint32_t{1});
1159     test("std_uint64_t", std::uint64_t{2});
1160     test("std_int32_t", std::int32_t{-3});
1161     test("std_int64_t", std::int64_t{-4});
1162     test("float", float{8.9});
1163     test("double", double{656.2});
1164 
1165     trajectory_t traj = m_factory.create();
1166     traj.template addColumn<int>("extra_column");
1167     traj.template addColumn<float>("another_column");
1168 
1169     auto ts1 = traj.getTrackState(traj.addTrackState());
1170     auto ts2 = traj.getTrackState(
1171         traj.addTrackState(TrackStatePropMask::All, ts1.index()));
1172     auto ts3 = traj.getTrackState(
1173         traj.addTrackState(TrackStatePropMask::All, ts2.index()));
1174 
1175     BOOST_CHECK(ts1.template has<"extra_column"_hash>());
1176     BOOST_CHECK(ts2.template has<"extra_column"_hash>());
1177     BOOST_CHECK(ts3.template has<"extra_column"_hash>());
1178 
1179     BOOST_CHECK(ts1.template has<"another_column"_hash>());
1180     BOOST_CHECK(ts2.template has<"another_column"_hash>());
1181     BOOST_CHECK(ts3.template has<"another_column"_hash>());
1182 
1183     ts2.template component<int, "extra_column"_hash>() = 6;
1184 
1185     BOOST_CHECK_EQUAL((ts2.template component<int, "extra_column"_hash>()), 6);
1186 
1187     ts3.template component<float, "another_column"_hash>() = 7.2f;
1188     BOOST_CHECK_EQUAL((ts3.template component<float, "another_column"_hash>()),
1189                       7.2f);
1190   }
1191 
1192   void testMultiTrajectoryExtraColumnsRuntime() {
1193     auto runTest = [&](auto&& fn) {
1194       trajectory_t mt = m_factory.create();
1195       std::vector<std::string> columns = {"one", "two", "three", "four"};
1196       for (const auto& c : columns) {
1197         BOOST_CHECK(!mt.hasColumn(fn(c)));
1198         mt.template addColumn<int>(c);
1199         BOOST_CHECK(mt.hasColumn(fn(c)));
1200       }
1201       for (const auto& c : columns) {
1202         auto ts1 = mt.getTrackState(mt.addTrackState());
1203         auto ts2 = mt.getTrackState(mt.addTrackState());
1204         BOOST_CHECK(ts1.has(fn(c)));
1205         BOOST_CHECK(ts2.has(fn(c)));
1206         ts1.template component<int>(fn(c)) = 674;
1207         ts2.template component<int>(fn(c)) = 421;
1208         BOOST_CHECK_EQUAL(ts1.template component<int>(fn(c)), 674);
1209         BOOST_CHECK_EQUAL(ts2.template component<int>(fn(c)), 421);
1210       }
1211     };
1212 
1213     runTest([](const std::string& c) { return hashStringDynamic(c.c_str()); });
1214     // runTest([](const std::string& c) { return c.c_str(); });
1215     // runTest([](const std::string& c) { return c; });
1216     // runTest([](std::string_view c) { return c; });
1217   }
1218 
1219   void testMultiTrajectoryAllocateCalibratedInit(
1220       std::default_random_engine& rng) {
1221     trajectory_t traj = m_factory.create();
1222     auto ts = traj.makeTrackState(TrackStatePropMask::All);
1223 
1224     BOOST_CHECK_EQUAL(ts.calibratedSize(), MultiTrajectoryTraits::kInvalid);
1225 
1226     auto [par, cov] = generateBoundParametersCovariance(rng, {});
1227 
1228     ts.allocateCalibrated(par.head<3>(), cov.topLeftCorner<3, 3>());
1229 
1230     BOOST_CHECK_EQUAL(ts.calibratedSize(), 3);
1231     BOOST_CHECK_EQUAL(ts.template calibrated<3>(), par.head<3>());
1232     BOOST_CHECK_EQUAL(ts.template calibratedCovariance<3>(),
1233                       (cov.topLeftCorner<3, 3>()));
1234 
1235     auto [par2, cov2] = generateBoundParametersCovariance(rng, {});
1236 
1237     ts.allocateCalibrated(3);
1238     BOOST_CHECK_EQUAL(ts.template calibrated<3>(), Vector3::Zero());
1239     BOOST_CHECK_EQUAL(ts.template calibratedCovariance<3>(),
1240                       ActsSquareMatrix<3>::Zero());
1241 
1242     ts.allocateCalibrated(par2.head<3>(), cov2.topLeftCorner<3, 3>());
1243     BOOST_CHECK_EQUAL(ts.calibratedSize(), 3);
1244     // The values are re-assigned
1245     BOOST_CHECK_EQUAL(ts.template calibrated<3>(), par2.head<3>());
1246     BOOST_CHECK_EQUAL(ts.template calibratedCovariance<3>(),
1247                       (cov2.topLeftCorner<3, 3>()));
1248 
1249     // Re-allocation with a different measurement dimension is an error
1250     BOOST_CHECK_THROW(
1251         ts.allocateCalibrated(par2.head<4>(), cov2.topLeftCorner<4, 4>()),
1252         std::invalid_argument);
1253   }
1254 };
1255 }  // namespace Acts::detail::Test