File indexing completed on 2026-10-05 08:14:44
0001
0002
0003
0004
0005
0006
0007
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
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
0059 GeometryContext geoContext = GeometryContext::dangerouslyDefaultConstruct();
0060 MagneticFieldContext magFieldContext = MagneticFieldContext();
0061
0062
0063 std::uniform_real_distribution<double> vXYDist(-0.1_mm, 0.1_mm);
0064
0065 std::uniform_real_distribution<double> vZDist(-20_mm, 20_mm);
0066
0067 std::uniform_real_distribution<double> d0Dist(-0.01_mm, 0.01_mm);
0068
0069 std::uniform_real_distribution<double> z0Dist(-0.2_mm, 0.2_mm);
0070
0071 std::uniform_real_distribution<double> pTDist(1._GeV, 30._GeV);
0072
0073 std::uniform_real_distribution<double> phiDist(-std::numbers::pi,
0074 std::numbers::pi);
0075
0076 std::uniform_real_distribution<double> thetaDist(1., std::numbers::pi - 1.);
0077
0078 std::uniform_real_distribution<double> qDist(-1, 1);
0079
0080
0081 std::uniform_real_distribution<double> relTDist(-4_ps, 4_ps);
0082
0083 std::uniform_real_distribution<double> resIPDist(0., 100._um);
0084
0085 std::uniform_real_distribution<double> resAngDist(0., 0.1);
0086
0087 std::uniform_real_distribution<double> resQoPDist(-0.1, 0.1);
0088
0089
0090 std::uniform_real_distribution<double> resTDist(0_ps, 8_ps);
0091
0092 BOOST_AUTO_TEST_SUITE(VertexingSuite)
0093
0094
0095
0096 BOOST_AUTO_TEST_CASE(adaptive_multi_vertex_fitter_test) {
0097
0098 int mySeed = 31415;
0099 std::mt19937 gen(mySeed);
0100
0101
0102 auto bField = std::make_shared<ConstantBField>(Vector3{0.0, 0.0, 1_T});
0103
0104
0105 EigenStepper<> stepper(bField);
0106
0107
0108 auto propagator = std::make_shared<Propagator>(stepper);
0109
0110 VertexingOptions vertexingOptions(geoContext, magFieldContext);
0111
0112
0113 ImpactPointEstimator::Config ip3dEstCfg(bField, propagator);
0114 ImpactPointEstimator ip3dEst(ip3dEstCfg);
0115
0116
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
0126 fitterCfg.doSmoothing = true;
0127 fitterCfg.extractParameters.connect<&InputTrack::extractParameters>();
0128
0129 AdaptiveMultiVertexFitter fitter(std::move(fitterCfg));
0130
0131
0132
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
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
0150 SquareMatrix4 posCovariance(SquareMatrix4::Identity());
0151 vtx.setFullCovariance(posCovariance);
0152
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
0169
0170 for (unsigned int iTrack = 0; iTrack < nTracksPerVtx * vtxPosVec.size();
0171 iTrack++) {
0172
0173 double q = std::copysign(1., qDist(gen));
0174
0175
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
0183 int vtxIdx = static_cast<int>(iTrack / nTracksPerVtx);
0184
0185
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
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
0220
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
0247
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
0282
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
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
0318
0319 BOOST_AUTO_TEST_CASE(time_fitting) {
0320
0321 int mySeed = 31415;
0322 std::mt19937 gen(mySeed);
0323
0324
0325 auto bField = std::make_shared<ConstantBField>(Vector3{0.0, 0.0, 1_T});
0326
0327
0328 EigenStepper<> stepper(bField);
0329
0330
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
0341 Linearizer::Config ltConfig;
0342 ltConfig.bField = bField;
0343 ltConfig.propagator = propagator;
0344 Linearizer linearizer(ltConfig);
0345
0346
0347 fitterCfg.doSmoothing = true;
0348
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
0356 double trueVtxTime = 40.0_ps;
0357 Vector3 trueVtxPos(-0.15_mm, -0.1_mm, -1.5_mm);
0358
0359
0360 Vector4 vtxSeedPos(0.0_mm, 0.0_mm, -1.4_mm, 0.0_ps);
0361
0362 Vertex vtx(vtxSeedPos);
0363
0364 SquareMatrix4 initialCovariance(SquareMatrix4::Identity() * 1e+8);
0365 vtx.setFullCovariance(initialCovariance);
0366
0367
0368 std::vector<BoundTrackParameters> trks;
0369
0370 unsigned int nTracks = 4;
0371 for (unsigned int _ = 0; _ < nTracks; _++) {
0372
0373 double q = std::copysign(1., qDist(gen));
0374
0375
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
0384 Covariance covMat;
0385
0386
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
0395
0396
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
0414 VertexFitProblem state;
0415 AdaptiveMultiVertexFitter::Cache cache(*bField, magFieldContext);
0416
0417 for (const auto& trk : trks) {
0418 ACTS_DEBUG("Track parameters:\n" << trk);
0419
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
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
0448 for (std::size_t i = 0; i <= 3; i++) {
0449 BOOST_CHECK_GT(vtxCov(i, i), 0.);
0450 }
0451
0452
0453
0454 CHECK_CLOSE_ABS(vtxCov - vtxCov.transpose(), SquareMatrix4::Zero(),
0455 1e-3 * vtxCov.cwiseAbs().maxCoeff());
0456
0457
0458
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
0468
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
0502
0503
0504 BOOST_AUTO_TEST_CASE(adaptive_multi_vertex_fitter_test_athena) {
0505
0506 auto bField = std::make_shared<ConstantBField>(Vector3{0.0, 0.0, 2_T});
0507
0508
0509
0510 EigenStepper<> stepper(bField);
0511
0512
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
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
0539
0540
0541 AdaptiveMultiVertexFitter fitter(std::move(fitterCfg));
0542
0543
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
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
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
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
0628 ACTS_PUSH_IGNORE_DEPRECATED()
0629 AdaptiveMultiVertexFitter::State state(*bField, magFieldContext);
0630
0631
0632 SquareMatrix4 covConstr(SquareMatrix4::Identity());
0633 covConstr = covConstr * 1e+8;
0634 covConstr(3, 3) = 0.;
0635
0636
0637 Vector3 vtxPos1(0.15_mm, 0.15_mm, 2.9_mm);
0638 Vertex vtx1(vtxPos1);
0639
0640
0641 state.vertexCollection.push_back(&vtx1);
0642
0643
0644 Vertex vtx1Constr(vtxPos1);
0645 vtx1Constr.setFullCovariance(covConstr);
0646 vtx1Constr.setFitQuality(0, -3);
0647
0648
0649 VertexInfo vtxInfo1;
0650
0651
0652
0653
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
0667 Vector3 vtxPos2(0.3_mm, -0.2_mm, -4.8_mm);
0668 Vertex vtx2(vtxPos2);
0669
0670
0671 state.vertexCollection.push_back(&vtx2);
0672
0673
0674 Vertex vtx2Constr(vtxPos2);
0675 vtx2Constr.setFullCovariance(covConstr);
0676 vtx2Constr.setFitQuality(0, -3);
0677
0678
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
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
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
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
0738
0739 const Vector3 expVtx1Pos(0.077_mm, -0.189_mm, 2.924_mm);
0740
0741
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
0751 const Vector3 expVtx2Pos(-0.443_mm, -0.044_mm, -4.829_mm);
0752
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
0761
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
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
0790
0791
0792
0793
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
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
0867
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
0907
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
0920
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
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 }