Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-09 08:18:06

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