Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-05 08:14:44

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 #include <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/TrackParametrization.hpp"
0013 #include "Acts/Definitions/Units.hpp"
0014 #include "Acts/EventData/BoundTrackParameters.hpp"
0015 #include "Acts/Geometry/GeometryContext.hpp"
0016 #include "Acts/Geometry/GeometryIdentifier.hpp"
0017 #include "Acts/MagneticField/ConstantBField.hpp"
0018 #include "Acts/MagneticField/MagneticFieldContext.hpp"
0019 #include "Acts/Propagator/EigenStepper.hpp"
0020 #include "Acts/Propagator/Propagator.hpp"
0021 #include "Acts/Surfaces/PerigeeSurface.hpp"
0022 #include "Acts/Surfaces/Surface.hpp"
0023 #include "Acts/Utilities/AnnealingUtility.hpp"
0024 #include "Acts/Utilities/Diagnostics.hpp"
0025 #include "Acts/Utilities/Logger.hpp"
0026 #include "Acts/Utilities/Result.hpp"
0027 #include "Acts/Vertexing/AMVFInfo.hpp"
0028 #include "Acts/Vertexing/AdaptiveMultiVertexFitter.hpp"
0029 #include "Acts/Vertexing/HelicalTrackLinearizer.hpp"
0030 #include "Acts/Vertexing/ImpactPointEstimator.hpp"
0031 #include "Acts/Vertexing/TrackAtVertex.hpp"
0032 #include "Acts/Vertexing/Vertex.hpp"
0033 #include "Acts/Vertexing/VertexingOptions.hpp"
0034 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0035 
0036 #include <iostream>
0037 #include <map>
0038 #include <memory>
0039 #include <numbers>
0040 #include <random>
0041 #include <utility>
0042 #include <vector>
0043 
0044 using namespace Acts;
0045 using namespace Acts::UnitLiterals;
0046 
0047 namespace ActsTests {
0048 
0049 using Acts::VectorHelpers::makeVector4;
0050 
0051 // Set up logger
0052 ACTS_LOCAL_LOGGER(getDefaultLogger("AMVFitterTests", Logging::INFO))
0053 
0054 using Covariance = BoundMatrix;
0055 using Propagator = Acts::Propagator<EigenStepper<>>;
0056 using Linearizer = HelicalTrackLinearizer;
0057 
0058 // Create a test context
0059 GeometryContext geoContext = GeometryContext::dangerouslyDefaultConstruct();
0060 MagneticFieldContext magFieldContext = MagneticFieldContext();
0061 
0062 // Vertex x/y position distribution
0063 std::uniform_real_distribution<double> vXYDist(-0.1_mm, 0.1_mm);
0064 // Vertex z position distribution
0065 std::uniform_real_distribution<double> vZDist(-20_mm, 20_mm);
0066 // Track d0 distribution
0067 std::uniform_real_distribution<double> d0Dist(-0.01_mm, 0.01_mm);
0068 // Track z0 distribution
0069 std::uniform_real_distribution<double> z0Dist(-0.2_mm, 0.2_mm);
0070 // Track pT distribution
0071 std::uniform_real_distribution<double> pTDist(1._GeV, 30._GeV);
0072 // Track phi distribution
0073 std::uniform_real_distribution<double> phiDist(-std::numbers::pi,
0074                                                std::numbers::pi);
0075 // Track theta distribution
0076 std::uniform_real_distribution<double> thetaDist(1., std::numbers::pi - 1.);
0077 // Track charge helper distribution
0078 std::uniform_real_distribution<double> qDist(-1, 1);
0079 // Distribution of track time (relative to vertex time). Values are unrealistic
0080 // and only used for testing purposes.
0081 std::uniform_real_distribution<double> relTDist(-4_ps, 4_ps);
0082 // Track IP resolution distribution
0083 std::uniform_real_distribution<double> resIPDist(0., 100._um);
0084 // Track angular distribution
0085 std::uniform_real_distribution<double> resAngDist(0., 0.1);
0086 // Track q/p resolution distribution
0087 std::uniform_real_distribution<double> resQoPDist(-0.1, 0.1);
0088 // Track time resolution distribution. Values are unrealistic and only used for
0089 // testing purposes.
0090 std::uniform_real_distribution<double> resTDist(0_ps, 8_ps);
0091 
0092 BOOST_AUTO_TEST_SUITE(VertexingSuite)
0093 
0094 /// @brief Unit test for AdaptiveMultiVertexFitter
0095 ///
0096 BOOST_AUTO_TEST_CASE(adaptive_multi_vertex_fitter_test) {
0097   // Set up RNG
0098   int mySeed = 31415;
0099   std::mt19937 gen(mySeed);
0100 
0101   // Set up constant B-Field
0102   auto bField = std::make_shared<ConstantBField>(Vector3{0.0, 0.0, 1_T});
0103 
0104   // Set up EigenStepper
0105   EigenStepper<> stepper(bField);
0106 
0107   // Set up propagator with void navigator
0108   auto propagator = std::make_shared<Propagator>(stepper);
0109 
0110   VertexingOptions vertexingOptions(geoContext, magFieldContext);
0111 
0112   // IP 3D Estimator
0113   ImpactPointEstimator::Config ip3dEstCfg(bField, propagator);
0114   ImpactPointEstimator ip3dEst(ip3dEstCfg);
0115 
0116   // Linearizer for BoundTrackParameters type test
0117   Linearizer::Config ltConfig;
0118   ltConfig.bField = bField;
0119   ltConfig.propagator = propagator;
0120   Linearizer linearizer(ltConfig);
0121 
0122   AdaptiveMultiVertexFitter::Config fitterCfg(ip3dEst);
0123   fitterCfg.trackLinearizer.connect<&Linearizer::linearizeTrack>(&linearizer);
0124 
0125   // Test smoothing
0126   fitterCfg.doSmoothing = true;
0127   fitterCfg.extractParameters.connect<&InputTrack::extractParameters>();
0128 
0129   AdaptiveMultiVertexFitter fitter(std::move(fitterCfg));
0130 
0131   // Create positions of three vertices, two of which (1 and 2) are
0132   // close to one another and will share a common track later
0133   Vector3 vtxPos1(-0.15_mm, -0.1_mm, -1.5_mm);
0134   Vector3 vtxPos2(-0.1_mm, -0.15_mm, -3._mm);
0135   Vector3 vtxPos3(0.2_mm, 0.2_mm, 10._mm);
0136 
0137   std::vector<Vector3> vtxPosVec{vtxPos1, vtxPos2, vtxPos3};
0138 
0139   // Resolutions, use the same for all tracks
0140   double resD0 = resIPDist(gen);
0141   double resZ0 = resIPDist(gen);
0142   double resPh = resAngDist(gen);
0143   double resTh = resAngDist(gen);
0144   double resQp = resQoPDist(gen);
0145 
0146   std::vector<Vertex> vtxList;
0147   for (auto& vtxPos : vtxPosVec) {
0148     Vertex vtx(vtxPos);
0149     // Set some vertex covariance
0150     SquareMatrix4 posCovariance(SquareMatrix4::Identity());
0151     vtx.setFullCovariance(posCovariance);
0152     // Add to vertex list
0153     vtxList.push_back(vtx);
0154   }
0155 
0156   std::vector<Vertex*> vtxPtrList;
0157   ACTS_DEBUG("All vertices in test case:");
0158   int cv = 0;
0159   for (auto& vtx : vtxList) {
0160     cv++;
0161     ACTS_DEBUG("\t" << cv << ". vertex ptr: " << &vtx);
0162     vtxPtrList.push_back(&vtx);
0163   }
0164 
0165   std::vector<BoundTrackParameters> allTracks;
0166 
0167   unsigned int nTracksPerVtx = 4;
0168   // Construct nTracksPerVtx * 3 (3 vertices) random track emerging
0169   // from vicinity of vertex positions
0170   for (unsigned int iTrack = 0; iTrack < nTracksPerVtx * vtxPosVec.size();
0171        iTrack++) {
0172     // Construct positive or negative charge randomly
0173     double q = std::copysign(1., qDist(gen));
0174 
0175     // Fill vector of track objects with simple covariance matrix
0176     Covariance covMat;
0177 
0178     covMat << resD0 * resD0, 0., 0., 0., 0., 0., 0., resZ0 * resZ0, 0., 0., 0.,
0179         0., 0., 0., resPh * resPh, 0., 0., 0., 0., 0., 0., resTh * resTh, 0.,
0180         0., 0., 0., 0., 0., resQp * resQp, 0., 0., 0., 0., 0., 0., 1.;
0181 
0182     // Index of current vertex
0183     int vtxIdx = static_cast<int>(iTrack / nTracksPerVtx);
0184 
0185     // Construct random track parameters
0186     BoundVector paramVec;
0187     paramVec << d0Dist(gen), z0Dist(gen), phiDist(gen), thetaDist(gen),
0188         q / pTDist(gen), 0.;
0189 
0190     std::shared_ptr<PerigeeSurface> perigeeSurface =
0191         Surface::makeShared<PerigeeSurface>(vtxPosVec[vtxIdx]);
0192 
0193     allTracks.emplace_back(perigeeSurface, paramVec, std::move(covMat),
0194                            ParticleHypothesis::pion());
0195   }
0196 
0197   int ct = 0;
0198   ACTS_DEBUG("All tracks in test case:");
0199   for (auto& trk : allTracks) {
0200     ct++;
0201     ACTS_DEBUG("\t" << ct << ". track ptr: " << &trk);
0202   }
0203 
0204   VertexFitProblem state;
0205   AdaptiveMultiVertexFitter::Cache cache(*bField, magFieldContext);
0206 
0207   for (unsigned int iTrack = 0; iTrack < nTracksPerVtx * vtxPosVec.size();
0208        iTrack++) {
0209     // Index of current vertex
0210     int vtxIdx = static_cast<int>(iTrack / nTracksPerVtx);
0211 
0212     InputTrack inputTrack{&allTracks[iTrack]};
0213 
0214     state.candidates[&(vtxList[vtxIdx])].trackLinks.push_back(inputTrack);
0215     state.tracksAtVertices.insert(
0216         std::make_pair(std::make_pair(inputTrack, &(vtxList[vtxIdx])),
0217                        TrackAtVertex(1., allTracks[iTrack], inputTrack)));
0218 
0219     // Use first track also for second vertex to let vtx1 and vtx2
0220     // share this track
0221     if (iTrack == 0) {
0222       state.candidates[&(vtxList.at(1))].trackLinks.push_back(inputTrack);
0223       state.tracksAtVertices.insert(
0224           std::make_pair(std::make_pair(inputTrack, &(vtxList.at(1))),
0225                          TrackAtVertex(1., allTracks[iTrack], inputTrack)));
0226     }
0227   }
0228 
0229   for (auto& vtx : vtxPtrList) {
0230     state.addVertexToMultiMap(*vtx);
0231     ACTS_DEBUG("Vertex, with ptr: " << vtx);
0232     for (auto& trk : state.candidates[vtx].trackLinks) {
0233       ACTS_DEBUG("\t track ptr: " << trk);
0234     }
0235   }
0236 
0237   ACTS_DEBUG("Checking all vertices linked to a single track:");
0238   for (auto& trk : allTracks) {
0239     ACTS_DEBUG("Track with ptr: " << &trk);
0240     auto range = state.trackToVertices.equal_range(InputTrack{&trk});
0241     for (auto vtxIter = range.first; vtxIter != range.second; ++vtxIter) {
0242       ACTS_DEBUG("\t used by vertex: " << vtxIter->second);
0243     }
0244   }
0245 
0246   // Copy vertex seeds from state.vertices to new
0247   // list in order to be able to compare later
0248   std::vector<Vertex> seedListCopy = vtxList;
0249 
0250   std::vector<Vertex*> vtxFitPtr = {&vtxList.at(0)};
0251   auto res1 = fitter.addVtxToFit(state, vtxFitPtr, vertexingOptions, cache);
0252   ACTS_DEBUG("Tracks linked to each vertex AFTER fit:");
0253   int c = 0;
0254   for (auto& vtx : vtxPtrList) {
0255     c++;
0256     ACTS_DEBUG(c << ". vertex, with ptr: " << vtx);
0257     for (const auto& trk : state.candidates[vtx].trackLinks) {
0258       ACTS_DEBUG("\t track ptr: " << trk);
0259     }
0260   }
0261 
0262   ACTS_DEBUG("Checking all vertices linked to a single track AFTER fit:");
0263   for (auto& trk : allTracks) {
0264     ACTS_DEBUG("Track with ptr: " << &trk);
0265     auto range = state.trackToVertices.equal_range(InputTrack{&trk});
0266     for (auto vtxIter = range.first; vtxIter != range.second; ++vtxIter) {
0267       ACTS_DEBUG("\t used by vertex: " << vtxIter->second);
0268     }
0269   }
0270 
0271   BOOST_CHECK(res1.ok());
0272 
0273   ACTS_DEBUG("Vertex positions after fit of vertex 1 and 2:");
0274   for (std::size_t vtxIter = 0; vtxIter < 3; vtxIter++) {
0275     ACTS_DEBUG("Vtx " << vtxIter + 1 << ", seed position:\n "
0276                       << seedListCopy.at(vtxIter).fullPosition()
0277                       << "\nFitted position:\n "
0278                       << vtxList.at(vtxIter).fullPosition());
0279   }
0280 
0281   // After fit of first vertex, only first and second vertex seed
0282   // should have been modified while third vertex should remain untouched
0283   BOOST_CHECK_NE(vtxList.at(0).fullPosition(),
0284                  seedListCopy.at(0).fullPosition());
0285   BOOST_CHECK_NE(vtxList.at(1).fullPosition(),
0286                  seedListCopy.at(1).fullPosition());
0287   BOOST_CHECK_EQUAL(vtxList.at(2).fullPosition(),
0288                     seedListCopy.at(2).fullPosition());
0289 
0290   CHECK_CLOSE_ABS(vtxList.at(0).fullPosition(),
0291                   seedListCopy.at(0).fullPosition(), 1_mm);
0292   CHECK_CLOSE_ABS(vtxList.at(1).fullPosition(),
0293                   seedListCopy.at(1).fullPosition(), 1_mm);
0294 
0295   vtxFitPtr = {&vtxList.at(2)};
0296   auto res2 = fitter.addVtxToFit(state, vtxFitPtr, vertexingOptions, cache);
0297   BOOST_CHECK(res2.ok());
0298 
0299   // Now also the third vertex should have been modified and fitted
0300   BOOST_CHECK_NE(vtxList.at(2).fullPosition(),
0301                  seedListCopy.at(2).fullPosition());
0302   CHECK_CLOSE_ABS(vtxList.at(2).fullPosition(),
0303                   seedListCopy.at(2).fullPosition(), 1_mm);
0304 
0305   ACTS_DEBUG("Vertex positions after fit of vertex 3:");
0306   ACTS_DEBUG("Vtx 1, seed position:\n " << seedListCopy.at(0).fullPosition()
0307                                         << "\nFitted position:\n "
0308                                         << vtxList.at(0).fullPosition());
0309   ACTS_DEBUG("Vtx 2, seed position:\n " << seedListCopy.at(1).fullPosition()
0310                                         << "\nFitted position:\n "
0311                                         << vtxList.at(1).fullPosition());
0312   ACTS_DEBUG("Vtx 3, seed position:\n " << seedListCopy.at(2).fullPosition()
0313                                         << "\nFitted position:\n "
0314                                         << vtxList.at(2).fullPosition());
0315 }
0316 
0317 /// @brief Unit test for fitting a 4D vertex position
0318 ///
0319 BOOST_AUTO_TEST_CASE(time_fitting) {
0320   // Set up RNG
0321   int mySeed = 31415;
0322   std::mt19937 gen(mySeed);
0323 
0324   // Set up constant B-Field
0325   auto bField = std::make_shared<ConstantBField>(Vector3{0.0, 0.0, 1_T});
0326 
0327   // Set up EigenStepper
0328   EigenStepper<> stepper(bField);
0329 
0330   // Set up propagator with void navigator
0331   auto propagator = std::make_shared<Propagator>(stepper);
0332 
0333   VertexingOptions vertexingOptions(geoContext, magFieldContext);
0334 
0335   ImpactPointEstimator::Config ip3dEstCfg(bField, propagator);
0336   ImpactPointEstimator ip3dEst(ip3dEstCfg);
0337 
0338   AdaptiveMultiVertexFitter::Config fitterCfg(ip3dEst);
0339 
0340   // Linearizer for BoundTrackParameters type test
0341   Linearizer::Config ltConfig;
0342   ltConfig.bField = bField;
0343   ltConfig.propagator = propagator;
0344   Linearizer linearizer(ltConfig);
0345 
0346   // Test smoothing
0347   fitterCfg.doSmoothing = true;
0348   // Do time fit
0349   fitterCfg.useTime = true;
0350   fitterCfg.extractParameters.connect<&InputTrack::extractParameters>();
0351   fitterCfg.trackLinearizer.connect<&Linearizer::linearizeTrack>(&linearizer);
0352 
0353   AdaptiveMultiVertexFitter fitter(std::move(fitterCfg));
0354 
0355   // Vertex position
0356   double trueVtxTime = 40.0_ps;
0357   Vector3 trueVtxPos(-0.15_mm, -0.1_mm, -1.5_mm);
0358 
0359   // Seed position of the vertex
0360   Vector4 vtxSeedPos(0.0_mm, 0.0_mm, -1.4_mm, 0.0_ps);
0361 
0362   Vertex vtx(vtxSeedPos);
0363   // Set initial covariance matrix to a large value
0364   SquareMatrix4 initialCovariance(SquareMatrix4::Identity() * 1e+8);
0365   vtx.setFullCovariance(initialCovariance);
0366 
0367   // Vector of all tracks
0368   std::vector<BoundTrackParameters> trks;
0369 
0370   unsigned int nTracks = 4;
0371   for (unsigned int _ = 0; _ < nTracks; _++) {
0372     // Construct positive or negative charge randomly
0373     double q = std::copysign(1., qDist(gen));
0374 
0375     // Track resolution
0376     double resD0 = resIPDist(gen);
0377     double resZ0 = resIPDist(gen);
0378     double resPh = resAngDist(gen);
0379     double resTh = resAngDist(gen);
0380     double resQp = resQoPDist(gen);
0381     double resT = resTDist(gen);
0382 
0383     // Random diagonal covariance matrix
0384     Covariance covMat;
0385 
0386     // clang-format off
0387     covMat <<
0388       resD0 * resD0, 0., 0., 0., 0., 0.,
0389       0., resZ0 * resZ0, 0., 0., 0., 0.,
0390       0., 0., resPh * resPh, 0., 0., 0.,
0391       0., 0., 0., resTh * resTh, 0., 0.,
0392       0., 0., 0., 0., resQp * resQp, 0.,
0393       0., 0., 0., 0., 0., resT * resT;
0394     // clang-format on
0395 
0396     // Random track parameters
0397     BoundVector paramVec;
0398     paramVec << d0Dist(gen), z0Dist(gen), phiDist(gen), thetaDist(gen),
0399         q / pTDist(gen), trueVtxTime + relTDist(gen);
0400 
0401     std::shared_ptr<PerigeeSurface> perigeeSurface =
0402         Surface::makeShared<PerigeeSurface>(trueVtxPos);
0403 
0404     trks.emplace_back(perigeeSurface, paramVec, std::move(covMat),
0405                       ParticleHypothesis::pion());
0406   }
0407 
0408   std::vector<const BoundTrackParameters*> trksPtr;
0409   for (const auto& trk : trks) {
0410     trksPtr.push_back(&trk);
0411   }
0412 
0413   // Prepare fitter state
0414   VertexFitProblem state;
0415   AdaptiveMultiVertexFitter::Cache cache(*bField, magFieldContext);
0416 
0417   for (const auto& trk : trks) {
0418     ACTS_DEBUG("Track parameters:\n" << trk);
0419     // Index of current vertex
0420     state.candidates[&vtx].trackLinks.push_back(InputTrack{&trk});
0421     state.tracksAtVertices.insert(
0422         std::make_pair(std::make_pair(InputTrack{&trk}, &vtx),
0423                        TrackAtVertex(1., trk, InputTrack{&trk})));
0424   }
0425 
0426   state.addVertexToMultiMap(vtx);
0427 
0428   std::vector<Vertex*> vtxFitPtr = {&vtx};
0429   auto res = fitter.addVtxToFit(state, vtxFitPtr, vertexingOptions, cache);
0430 
0431   BOOST_CHECK(res.ok());
0432 
0433   ACTS_DEBUG("Truth vertex position:  " << trueVtxPos.transpose());
0434   ACTS_DEBUG("Fitted vertex position: " << vtx.position().transpose());
0435 
0436   ACTS_DEBUG("Truth vertex time:  " << trueVtxTime);
0437   ACTS_DEBUG("Fitted vertex time: " << vtx.time());
0438 
0439   // Check that true vertex position and time approximately recovered
0440   CHECK_CLOSE_ABS(trueVtxPos, vtx.position(), 60_um);
0441   CHECK_CLOSE_ABS(trueVtxTime, vtx.time(), 2_ps);
0442 
0443   const SquareMatrix4& vtxCov = vtx.fullCovariance();
0444 
0445   ACTS_DEBUG("Vertex 4D covariance after the fit:\n" << vtxCov);
0446 
0447   // Check that variances of the vertex position/time are positive
0448   for (std::size_t i = 0; i <= 3; i++) {
0449     BOOST_CHECK_GT(vtxCov(i, i), 0.);
0450   }
0451 
0452   // Check that the covariance matrix is approximately symmetric. Its entries
0453   // span several orders of magnitude, hence the relative tolerance.
0454   CHECK_CLOSE_ABS(vtxCov - vtxCov.transpose(), SquareMatrix4::Zero(),
0455                   1e-3 * vtxCov.cwiseAbs().maxCoeff());
0456 
0457   // Every track must contribute exactly once: ndf is the sum of the track
0458   // weights, 2 degrees of freedom each.
0459   double sumTrackWeights = 0.;
0460   for (const auto& trk : trks) {
0461     sumTrackWeights +=
0462         state.tracksAtVertices.at(std::make_pair(InputTrack{&trk}, &vtx))
0463             .trackWeight;
0464   }
0465   CHECK_CLOSE_ABS(vtx.fitQuality().second, 2 * sumTrackWeights, 1e-9);
0466 
0467   // An unconstrained fit must equal a fit constrained to the initial vertex
0468   // state
0469   Vertex constrainedVtx(vtxSeedPos);
0470   constrainedVtx.setFullCovariance(initialCovariance);
0471 
0472   Vertex constraint(vtxSeedPos);
0473   constraint.setFullCovariance(initialCovariance);
0474 
0475   VertexFitProblem constrainedState;
0476   AdaptiveMultiVertexFitter::Cache constrainedCache(*bField, magFieldContext);
0477   VertexFitCandidate& constrainedCandidate =
0478       constrainedState.candidates[&constrainedVtx];
0479   constrainedCandidate.constraint = constraint;
0480 
0481   for (const auto& trk : trks) {
0482     constrainedCandidate.trackLinks.push_back(InputTrack{&trk});
0483     constrainedState.tracksAtVertices.insert(
0484         std::make_pair(std::make_pair(InputTrack{&trk}, &constrainedVtx),
0485                        TrackAtVertex(1., trk, InputTrack{&trk})));
0486   }
0487 
0488   constrainedState.addVertexToMultiMap(constrainedVtx);
0489 
0490   std::vector<Vertex*> constrainedVtxFitPtr = {&constrainedVtx};
0491   auto constrainedRes =
0492       fitter.addVtxToFit(constrainedState, constrainedVtxFitPtr,
0493                          vertexingOptions, constrainedCache);
0494 
0495   BOOST_CHECK(constrainedRes.ok());
0496 
0497   CHECK_CLOSE_ABS(constrainedVtx.fullPosition(), vtx.fullPosition(), 1e-9);
0498   CHECK_CLOSE_ABS(constrainedVtx.fullCovariance(), vtx.fullCovariance(), 1e-9);
0499 }
0500 
0501 /// @brief Unit test for AdaptiveMultiVertexFitter
0502 /// based on Athena unit test, i.e. same setting and
0503 /// test values are used here
0504 BOOST_AUTO_TEST_CASE(adaptive_multi_vertex_fitter_test_athena) {
0505   // Set up constant B-Field
0506   auto bField = std::make_shared<ConstantBField>(Vector3{0.0, 0.0, 2_T});
0507 
0508   // Set up EigenStepper
0509   // EigenStepper<> stepper(bField);
0510   EigenStepper<> stepper(bField);
0511 
0512   // Set up propagator with void navigator
0513   auto propagator = std::make_shared<Propagator>(stepper);
0514 
0515   VertexingOptions vertexingOptions(geoContext, magFieldContext);
0516 
0517   ImpactPointEstimator::Config ip3dEstCfg(bField, propagator);
0518   ImpactPointEstimator ip3dEst(ip3dEstCfg);
0519 
0520   std::vector<double> temperatures(1, 3.);
0521   AnnealingUtility::Config annealingConfig;
0522   annealingConfig.setOfTemperatures = temperatures;
0523   AnnealingUtility annealingUtility(annealingConfig);
0524 
0525   AdaptiveMultiVertexFitter::Config fitterCfg(ip3dEst);
0526 
0527   fitterCfg.annealingTool = annealingUtility;
0528   fitterCfg.extractParameters.connect<&InputTrack::extractParameters>();
0529 
0530   // Linearizer for BoundTrackParameters type test
0531   Linearizer::Config ltConfig;
0532   ltConfig.bField = bField;
0533   ltConfig.propagator = propagator;
0534   Linearizer linearizer(ltConfig);
0535 
0536   fitterCfg.trackLinearizer.connect<&Linearizer::linearizeTrack>(&linearizer);
0537 
0538   // Test smoothing
0539   // fitterCfg.doSmoothing = true;
0540 
0541   AdaptiveMultiVertexFitter fitter(std::move(fitterCfg));
0542 
0543   // Create first vector of tracks
0544   Vector3 pos1a(0.5_mm, -0.5_mm, 2.4_mm);
0545   Vector3 mom1a(1000_MeV, 0_MeV, -500_MeV);
0546   Vector3 pos1b(0.5_mm, -0.5_mm, 3.5_mm);
0547   Vector3 mom1b(0_MeV, 1000_MeV, 500_MeV);
0548   Vector3 pos1c(-0.2_mm, 0.1_mm, 3.4_mm);
0549   Vector3 mom1c(-50_MeV, 180_MeV, 300_MeV);
0550 
0551   Vector3 pos1d(-0.1_mm, 0.3_mm, 3.0_mm);
0552   Vector3 mom1d(-80_MeV, 480_MeV, -100_MeV);
0553   Vector3 pos1e(-0.01_mm, 0.01_mm, 2.9_mm);
0554   Vector3 mom1e(-600_MeV, 10_MeV, 210_MeV);
0555 
0556   Vector3 pos1f(-0.07_mm, 0.03_mm, 2.5_mm);
0557   Vector3 mom1f(240_MeV, 110_MeV, 150_MeV);
0558 
0559   // Start creating some track parameters
0560   Covariance covMat1;
0561   covMat1 << 1_mm * 1_mm, 0, 0., 0, 0., 0, 0, 1_mm * 1_mm, 0, 0., 0, 0, 0., 0,
0562       0.1, 0, 0, 0, 0, 0., 0, 0.1, 0, 0, 0., 0, 0, 0, 1. / (10_GeV * 10_GeV), 0,
0563       0, 0, 0, 0, 0, 1_ns;
0564 
0565   std::vector<BoundTrackParameters> params1 = {
0566       BoundTrackParameters::create(
0567           geoContext, Surface::makeShared<PerigeeSurface>(pos1a),
0568           makeVector4(pos1a, 0), mom1a.normalized(), 1_e / mom1a.norm(),
0569           covMat1, ParticleHypothesis::pion())
0570           .value(),
0571       BoundTrackParameters::create(
0572           geoContext, Surface::makeShared<PerigeeSurface>(pos1b),
0573           makeVector4(pos1b, 0), mom1b.normalized(), -1_e / mom1b.norm(),
0574           covMat1, ParticleHypothesis::pion())
0575           .value(),
0576       BoundTrackParameters::create(
0577           geoContext, Surface::makeShared<PerigeeSurface>(pos1c),
0578           makeVector4(pos1c, 0), mom1c.normalized(), 1_e / mom1c.norm(),
0579           covMat1, ParticleHypothesis::pion())
0580           .value(),
0581       BoundTrackParameters::create(
0582           geoContext, Surface::makeShared<PerigeeSurface>(pos1d),
0583           makeVector4(pos1d, 0), mom1d.normalized(), -1_e / mom1d.norm(),
0584           covMat1, ParticleHypothesis::pion())
0585           .value(),
0586       BoundTrackParameters::create(
0587           geoContext, Surface::makeShared<PerigeeSurface>(pos1e),
0588           makeVector4(pos1e, 0), mom1e.normalized(), 1_e / mom1e.norm(),
0589           covMat1, ParticleHypothesis::pion())
0590           .value(),
0591       BoundTrackParameters::create(
0592           geoContext, Surface::makeShared<PerigeeSurface>(pos1f),
0593           makeVector4(pos1f, 0), mom1f.normalized(), -1_e / mom1f.norm(),
0594           covMat1, ParticleHypothesis::pion())
0595           .value(),
0596   };
0597 
0598   // Create second vector of tracks
0599   Vector3 pos2a(0.2_mm, 0_mm, -4.9_mm);
0600   Vector3 mom2a(5000_MeV, 30_MeV, 200_MeV);
0601   Vector3 pos2b(-0.5_mm, 0.1_mm, -5.1_mm);
0602   Vector3 mom2b(800_MeV, 1200_MeV, 200_MeV);
0603   Vector3 pos2c(0.05_mm, -0.5_mm, -4.7_mm);
0604   Vector3 mom2c(400_MeV, -300_MeV, -200_MeV);
0605 
0606   // Define covariance as used in athena unit test
0607   Covariance covMat2 = covMat1;
0608 
0609   std::vector<BoundTrackParameters> params2 = {
0610       BoundTrackParameters::create(
0611           geoContext, Surface::makeShared<PerigeeSurface>(pos2a),
0612           makeVector4(pos2a, 0), mom2a.normalized(), 1_e / mom2a.norm(),
0613           covMat2, ParticleHypothesis::pion())
0614           .value(),
0615       BoundTrackParameters::create(
0616           geoContext, Surface::makeShared<PerigeeSurface>(pos2b),
0617           makeVector4(pos2b, 0), mom2b.normalized(), -1_e / mom2b.norm(),
0618           covMat2, ParticleHypothesis::pion())
0619           .value(),
0620       BoundTrackParameters::create(
0621           geoContext, Surface::makeShared<PerigeeSurface>(pos2c),
0622           makeVector4(pos2c, 0), mom2c.normalized(), -1_e / mom2c.norm(),
0623           covMat2, ParticleHypothesis::pion())
0624           .value(),
0625   };
0626 
0627   // Preserve the historical scratch initialization through the legacy adapter.
0628   ACTS_PUSH_IGNORE_DEPRECATED()
0629   AdaptiveMultiVertexFitter::State state(*bField, magFieldContext);
0630 
0631   // The constraint vertex position covariance
0632   SquareMatrix4 covConstr(SquareMatrix4::Identity());
0633   covConstr = covConstr * 1e+8;
0634   covConstr(3, 3) = 0.;
0635 
0636   // Prepare first vertex
0637   Vector3 vtxPos1(0.15_mm, 0.15_mm, 2.9_mm);
0638   Vertex vtx1(vtxPos1);
0639 
0640   // Add to vertex list
0641   state.vertexCollection.push_back(&vtx1);
0642 
0643   // The constraint vtx for vtx1
0644   Vertex vtx1Constr(vtxPos1);
0645   vtx1Constr.setFullCovariance(covConstr);
0646   vtx1Constr.setFitQuality(0, -3);
0647 
0648   // Prepare vertex information for the legacy fitter interface
0649   VertexInfo vtxInfo1;
0650   // Note: the seed position is deliberately left at zero here, reproducing the
0651   // original ordering of this test, where seedPosition was read off linPoint
0652   // before linPoint had been assigned. It is unused in this test because
0653   // oldPosition == linPoint, so no relinearization is triggered.
0654   vtxInfo1.linPoint.setZero();
0655   vtxInfo1.linPoint.head<3>() = vtxPos1;
0656   vtxInfo1.constraint = std::move(vtx1Constr);
0657   vtxInfo1.oldPosition = vtxInfo1.linPoint;
0658 
0659   for (const auto& trk : params1) {
0660     vtxInfo1.trackLinks.push_back(InputTrack{&trk});
0661     state.tracksAtVerticesMap.insert(
0662         std::make_pair(std::make_pair(InputTrack{&trk}, &vtx1),
0663                        TrackAtVertex(1.5, trk, InputTrack{&trk})));
0664   }
0665 
0666   // Prepare second vertex
0667   Vector3 vtxPos2(0.3_mm, -0.2_mm, -4.8_mm);
0668   Vertex vtx2(vtxPos2);
0669 
0670   // Add to vertex list
0671   state.vertexCollection.push_back(&vtx2);
0672 
0673   // The constraint vtx for vtx2
0674   Vertex vtx2Constr(vtxPos2);
0675   vtx2Constr.setFullCovariance(covConstr);
0676   vtx2Constr.setFitQuality(0, -3);
0677 
0678   // Prepare vertex information for the legacy fitter interface
0679   VertexInfo vtxInfo2;
0680   vtxInfo2.linPoint.setZero();
0681   vtxInfo2.linPoint.head<3>() = vtxPos2;
0682   vtxInfo2.constraint = std::move(vtx2Constr);
0683   vtxInfo2.oldPosition = vtxInfo2.linPoint;
0684   vtxInfo2.seedPosition = vtxInfo2.linPoint;
0685 
0686   for (const auto& trk : params2) {
0687     vtxInfo2.trackLinks.push_back(InputTrack{&trk});
0688     state.tracksAtVerticesMap.insert(
0689         std::make_pair(std::make_pair(InputTrack{&trk}, &vtx2),
0690                        TrackAtVertex(1.5, trk, InputTrack{&trk})));
0691   }
0692 
0693   state.vtxInfoMap[&vtx1] = std::move(vtxInfo1);
0694   state.vtxInfoMap[&vtx2] = std::move(vtxInfo2);
0695 
0696   state.addVertexToMultiMap(vtx1);
0697   state.addVertexToMultiMap(vtx2);
0698 
0699   // Fit vertices
0700   auto fitRes = fitter.fit(state, vertexingOptions);
0701   BOOST_CHECK(fitRes.ok());
0702 
0703   auto vtx1Fitted = state.vertexCollection.at(0);
0704   auto vtx1PosFitted = vtx1Fitted->position();
0705   auto vtx1CovFitted = vtx1Fitted->covariance();
0706   auto trks1 = state.vtxInfoMap.at(vtx1Fitted).trackLinks;
0707   auto vtx1FQ = vtx1Fitted->fitQuality();
0708 
0709   auto vtx2Fitted = state.vertexCollection.at(1);
0710   auto vtx2PosFitted = vtx2Fitted->position();
0711   auto vtx2CovFitted = vtx2Fitted->covariance();
0712   auto trks2 = state.vtxInfoMap.at(vtx2Fitted).trackLinks;
0713   auto vtx2FQ = vtx2Fitted->fitQuality();
0714 
0715   // Vertex 1
0716   ACTS_DEBUG("Vertex 1, position: " << vtx1PosFitted);
0717   ACTS_DEBUG("Vertex 1, covariance: " << vtx1CovFitted);
0718   for (const auto& trk : trks1) {
0719     auto& trkAtVtx =
0720         state.tracksAtVerticesMap.at(std::make_pair(trk, vtx1Fitted));
0721     ACTS_DEBUG("\tTrack weight:" << trkAtVtx.trackWeight);
0722   }
0723   ACTS_DEBUG("Vertex 1, chi2: " << vtx1FQ.first);
0724   ACTS_DEBUG("Vertex 1, ndf: " << vtx1FQ.second);
0725 
0726   // Vertex 2
0727   ACTS_DEBUG("Vertex 2, position: " << vtx2PosFitted);
0728   ACTS_DEBUG("Vertex 2, covariance: " << vtx2CovFitted);
0729   for (const auto& trk : trks2) {
0730     auto& trkAtVtx =
0731         state.tracksAtVerticesMap.at(std::make_pair(trk, vtx2Fitted));
0732     ACTS_DEBUG("\tTrack weight:" << trkAtVtx.trackWeight);
0733   }
0734   ACTS_DEBUG("Vertex 2, chi2: " << vtx2FQ.first);
0735   ACTS_DEBUG("Vertex 2, ndf: " << vtx2FQ.second);
0736 
0737   // Expected values from Athena implementation
0738   // Vertex 1
0739   const Vector3 expVtx1Pos(0.077_mm, -0.189_mm, 2.924_mm);
0740 
0741   // Helper matrix to create const expVtx1Cov below
0742   SquareMatrix3 expVtx1Cov;
0743   expVtx1Cov << 0.329, 0.016, -0.035, 0.016, 0.250, 0.085, -0.035, 0.085, 0.242;
0744 
0745   Vector<6> expVtx1TrkWeights;
0746   expVtx1TrkWeights << 0.8128, 0.7994, 0.8164, 0.8165, 0.8165, 0.8119;
0747   const double expVtx1chi2 = 0.9812;
0748   const double expVtx1ndf = 6.7474;
0749 
0750   // Vertex 2
0751   const Vector3 expVtx2Pos(-0.443_mm, -0.044_mm, -4.829_mm);
0752   // Helper matrix to create const expVtx2Cov below
0753   SquareMatrix3 expVtx2Cov;
0754   expVtx2Cov << 1.088, 0.028, -0.066, 0.028, 0.643, 0.073, -0.066, 0.073, 0.435;
0755 
0756   const Vector3 expVtx2TrkWeights(0.8172, 0.8150, 0.8137);
0757   const double expVtx2chi2 = 0.2114;
0758   const double expVtx2ndf = 1.8920;
0759 
0760   // Compare the results
0761   // Vertex 1
0762   CHECK_CLOSE_ABS(vtx1PosFitted, expVtx1Pos, 0.001_mm);
0763   CHECK_CLOSE_ABS(vtx1CovFitted, expVtx1Cov, 0.001_mm);
0764   int trkCount = 0;
0765   for (const auto& trk : trks1) {
0766     auto& trkAtVtx =
0767         state.tracksAtVerticesMap.at(std::make_pair(trk, vtx1Fitted));
0768     CHECK_CLOSE_ABS(trkAtVtx.trackWeight, expVtx1TrkWeights[trkCount], 0.001);
0769     trkCount++;
0770   }
0771   CHECK_CLOSE_ABS(vtx1FQ.first, expVtx1chi2, 0.001);
0772   CHECK_CLOSE_ABS(vtx1FQ.second, expVtx1ndf, 0.001);
0773 
0774   // Vertex 2
0775   CHECK_CLOSE_ABS(vtx2PosFitted, expVtx2Pos, 0.001_mm);
0776   CHECK_CLOSE_ABS(vtx2CovFitted, expVtx2Cov, 0.001_mm);
0777   trkCount = 0;
0778   for (const auto& trk : trks2) {
0779     auto& trkAtVtx =
0780         state.tracksAtVerticesMap.at(std::make_pair(trk, vtx2Fitted));
0781     CHECK_CLOSE_ABS(trkAtVtx.trackWeight, expVtx2TrkWeights[trkCount], 0.001);
0782     trkCount++;
0783   }
0784   CHECK_CLOSE_ABS(vtx2FQ.first, expVtx2chi2, 0.001);
0785   CHECK_CLOSE_ABS(vtx2FQ.second, expVtx2ndf, 0.001);
0786   ACTS_POP_IGNORE_DEPRECATED()
0787 }
0788 
0789 /// @brief Unit test comparing the deprecated State based interface against the
0790 /// VertexFitProblem/Cache interface it forwards to
0791 ///
0792 /// Fits the same three vertices twice, once through each interface, and
0793 /// requires the fitted vertices and the fit bookkeeping to agree exactly.
0794 BOOST_AUTO_TEST_CASE(deprecated_state_interface) {
0795   int mySeed = 31415;
0796   std::mt19937 gen(mySeed);
0797 
0798   auto bField = std::make_shared<ConstantBField>(Vector3{0.0, 0.0, 1_T});
0799   EigenStepper<> stepper(bField);
0800   auto propagator = std::make_shared<Propagator>(stepper);
0801 
0802   VertexingOptions vertexingOptions(geoContext, magFieldContext);
0803 
0804   ImpactPointEstimator::Config ip3dEstCfg(bField, propagator);
0805   ImpactPointEstimator ip3dEst(ip3dEstCfg);
0806 
0807   Linearizer::Config ltConfig;
0808   ltConfig.bField = bField;
0809   ltConfig.propagator = propagator;
0810   Linearizer linearizer(ltConfig);
0811 
0812   AdaptiveMultiVertexFitter::Config fitterCfg(ip3dEst);
0813   fitterCfg.trackLinearizer.connect<&Linearizer::linearizeTrack>(&linearizer);
0814   fitterCfg.doSmoothing = true;
0815   fitterCfg.extractParameters.connect<&InputTrack::extractParameters>();
0816 
0817   AdaptiveMultiVertexFitter fitter(std::move(fitterCfg));
0818 
0819   std::vector<Vector3> vtxPosVec{Vector3(-0.15_mm, -0.1_mm, -1.5_mm),
0820                                  Vector3(-0.1_mm, -0.15_mm, -3._mm),
0821                                  Vector3(0.2_mm, 0.2_mm, 10._mm)};
0822 
0823   double resD0 = resIPDist(gen);
0824   double resZ0 = resIPDist(gen);
0825   double resPh = resAngDist(gen);
0826   double resTh = resAngDist(gen);
0827   double resQp = resQoPDist(gen);
0828 
0829   const unsigned int nTracksPerVtx = 4;
0830   std::vector<BoundTrackParameters> allTracks;
0831   for (unsigned int iTrack = 0; iTrack < nTracksPerVtx * vtxPosVec.size();
0832        iTrack++) {
0833     double q = std::copysign(1., qDist(gen));
0834 
0835     Covariance covMat;
0836     covMat << resD0 * resD0, 0., 0., 0., 0., 0., 0., resZ0 * resZ0, 0., 0., 0.,
0837         0., 0., 0., resPh * resPh, 0., 0., 0., 0., 0., 0., resTh * resTh, 0.,
0838         0., 0., 0., 0., 0., resQp * resQp, 0., 0., 0., 0., 0., 0., 1.;
0839 
0840     BoundVector paramVec;
0841     paramVec << d0Dist(gen), z0Dist(gen), phiDist(gen), thetaDist(gen),
0842         q / pTDist(gen), 0.;
0843 
0844     std::shared_ptr<PerigeeSurface> perigeeSurface =
0845         Surface::makeShared<PerigeeSurface>(
0846             vtxPosVec[static_cast<int>(iTrack / nTracksPerVtx)]);
0847 
0848     allTracks.emplace_back(perigeeSurface, paramVec, std::move(covMat),
0849                            ParticleHypothesis::pion());
0850   }
0851 
0852   // Seed vertices, one independent set per interface under test
0853   auto makeSeeds = [&]() {
0854     std::vector<Vertex> vtxList;
0855     for (const auto& vtxPos : vtxPosVec) {
0856       Vertex vtx(vtxPos);
0857       vtx.setFullCovariance(SquareMatrix4::Identity());
0858       vtxList.push_back(vtx);
0859     }
0860     return vtxList;
0861   };
0862 
0863   std::vector<Vertex> vtxListNew = makeSeeds();
0864   std::vector<Vertex> vtxListOld = makeSeeds();
0865 
0866   // Track-to-vertex assignment, identical for both interfaces: track 0 is
0867   // shared between the first two vertices
0868   auto vertexOfTrack = [&](unsigned int iTrack) {
0869     return static_cast<std::size_t>(iTrack / nTracksPerVtx);
0870   };
0871 
0872   VertexFitProblem problem;
0873   AdaptiveMultiVertexFitter::Cache cache(*bField, magFieldContext);
0874 
0875   ACTS_PUSH_IGNORE_DEPRECATED()
0876   AdaptiveMultiVertexFitter::State state(*bField, magFieldContext);
0877 
0878   for (unsigned int iTrack = 0; iTrack < allTracks.size(); iTrack++) {
0879     InputTrack inputTrack{&allTracks[iTrack]};
0880 
0881     std::vector<std::size_t> vtxIndices{vertexOfTrack(iTrack)};
0882     if (iTrack == 0) {
0883       vtxIndices.push_back(1);
0884     }
0885 
0886     for (std::size_t vtxIdx : vtxIndices) {
0887       Vertex* vtxNew = &vtxListNew.at(vtxIdx);
0888       problem.candidates[vtxNew].trackLinks.push_back(inputTrack);
0889       problem.tracksAtVertices.emplace(
0890           std::make_pair(inputTrack, vtxNew),
0891           TrackAtVertex(1., allTracks[iTrack], inputTrack));
0892 
0893       Vertex* vtxOld = &vtxListOld.at(vtxIdx);
0894       state.vtxInfoMap[vtxOld].trackLinks.push_back(inputTrack);
0895       state.tracksAtVerticesMap.emplace(
0896           std::make_pair(inputTrack, vtxOld),
0897           TrackAtVertex(1., allTracks[iTrack], inputTrack));
0898     }
0899   }
0900 
0901   for (std::size_t vtxIdx = 0; vtxIdx < vtxPosVec.size(); vtxIdx++) {
0902     problem.addVertexToMultiMap(vtxListNew.at(vtxIdx));
0903     state.addVertexToMultiMap(vtxListOld.at(vtxIdx));
0904   }
0905 
0906   // Fit the first vertex, which drags in the second one via the shared track,
0907   // then the third one on its own
0908   for (std::size_t vtxIdx : {0u, 2u}) {
0909     std::vector<Vertex*> newVerticesNew = {&vtxListNew.at(vtxIdx)};
0910     BOOST_CHECK(
0911         fitter.addVtxToFit(problem, newVerticesNew, vertexingOptions, cache)
0912             .ok());
0913 
0914     std::vector<Vertex*> newVerticesOld = {&vtxListOld.at(vtxIdx)};
0915     BOOST_CHECK(
0916         fitter.addVtxToFit(state, newVerticesOld, vertexingOptions).ok());
0917   }
0918 
0919   // The fitted vertices have to agree, and so has the fit bookkeeping the
0920   // caller reads back off the state
0921   for (std::size_t vtxIdx = 0; vtxIdx < vtxPosVec.size(); vtxIdx++) {
0922     const Vertex& vtxNew = vtxListNew.at(vtxIdx);
0923     const Vertex& vtxOld = vtxListOld.at(vtxIdx);
0924 
0925     BOOST_CHECK_EQUAL(vtxNew.fullPosition(), vtxOld.fullPosition());
0926     BOOST_CHECK_EQUAL(vtxNew.fullCovariance(), vtxOld.fullCovariance());
0927     BOOST_CHECK_EQUAL(vtxNew.fitQuality().first, vtxOld.fitQuality().first);
0928     BOOST_CHECK_EQUAL(vtxNew.fitQuality().second, vtxOld.fitQuality().second);
0929     BOOST_CHECK_EQUAL(vtxNew.tracks().size(), vtxOld.tracks().size());
0930 
0931     const VertexFitCandidate& candidate =
0932         problem.candidates.at(&vtxListNew.at(vtxIdx));
0933     const VertexInfo& info = state.vtxInfoMap.at(&vtxListOld.at(vtxIdx));
0934 
0935     BOOST_CHECK_EQUAL(candidate.seedPosition, info.seedPosition);
0936     BOOST_CHECK_EQUAL(candidate.trackLinks.size(), info.trackLinks.size());
0937     BOOST_CHECK_EQUAL(candidate.constraint.fullPosition(),
0938                       info.constraint.fullPosition());
0939 
0940     for (const auto& trk : candidate.trackLinks) {
0941       const TrackAtVertex& trkAtVtxNew = problem.tracksAtVertices.at(
0942           std::make_pair(trk, &vtxListNew.at(vtxIdx)));
0943       const TrackAtVertex& trkAtVtxOld = state.tracksAtVerticesMap.at(
0944           std::make_pair(trk, &vtxListOld.at(vtxIdx)));
0945       BOOST_CHECK_EQUAL(trkAtVtxNew.trackWeight, trkAtVtxOld.trackWeight);
0946       BOOST_CHECK_EQUAL(trkAtVtxNew.vertexCompatibility,
0947                         trkAtVtxOld.vertexCompatibility);
0948       BOOST_CHECK_EQUAL(trkAtVtxNew.chi2Track, trkAtVtxOld.chi2Track);
0949     }
0950   }
0951 
0952   // The vertex collection is handed back as well
0953   BOOST_CHECK_EQUAL(problem.vertices.size(), state.vertexCollection.size());
0954   BOOST_CHECK_EQUAL(problem.trackToVertices.size(),
0955                     state.trackToVerticesMultiMap.size());
0956   ACTS_POP_IGNORE_DEPRECATED()
0957 }
0958 
0959 BOOST_AUTO_TEST_SUITE_END()
0960 
0961 }  // namespace ActsTests