File indexing completed on 2025-08-06 08:11:36
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/data/test_case.hpp>
0010 #include <boost/test/tools/output_test_stream.hpp>
0011 #include <boost/test/unit_test.hpp>
0012
0013 #include "Acts/Definitions/Algebra.hpp"
0014 #include "Acts/Definitions/Common.hpp"
0015 #include "Acts/Definitions/TrackParametrization.hpp"
0016 #include "Acts/Definitions/Units.hpp"
0017 #include "Acts/EventData/GenericBoundTrackParameters.hpp"
0018 #include "Acts/EventData/TrackParameters.hpp"
0019 #include "Acts/Geometry/GeometryContext.hpp"
0020 #include "Acts/MagneticField/MagneticFieldContext.hpp"
0021 #include "Acts/Surfaces/PerigeeSurface.hpp"
0022 #include "Acts/Surfaces/Surface.hpp"
0023 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0024 #include "Acts/Utilities/Intersection.hpp"
0025 #include "Acts/Utilities/Result.hpp"
0026 #include "Acts/Utilities/UnitVectors.hpp"
0027 #include "Acts/Vertexing/AdaptiveGridDensityVertexFinder.hpp"
0028 #include "Acts/Vertexing/AdaptiveGridTrackDensity.hpp"
0029 #include "Acts/Vertexing/GaussianGridTrackDensity.hpp"
0030 #include "Acts/Vertexing/GridDensityVertexFinder.hpp"
0031 #include "Acts/Vertexing/IVertexFinder.hpp"
0032 #include "Acts/Vertexing/Vertex.hpp"
0033 #include "Acts/Vertexing/VertexingOptions.hpp"
0034
0035 #include <iostream>
0036 #include <memory>
0037 #include <random>
0038 #include <system_error>
0039 #include <vector>
0040
0041 namespace bdata = boost::unit_test::data;
0042 using namespace Acts::UnitLiterals;
0043 using Acts::VectorHelpers::makeVector4;
0044
0045 namespace Acts::Test {
0046
0047 using Covariance = BoundSquareMatrix;
0048
0049
0050 GeometryContext geoContext = GeometryContext();
0051 MagneticFieldContext magFieldContext = MagneticFieldContext();
0052
0053 const double zVertexPos1 = 12.;
0054 const double zVertexPos2 = -3.;
0055
0056 std::normal_distribution<double> xdist(1_mm, 0.1_mm);
0057
0058 std::normal_distribution<double> ydist(-0.7_mm, 0.1_mm);
0059
0060 std::normal_distribution<double> z1dist(zVertexPos1 * 1_mm, 1_mm);
0061
0062 std::normal_distribution<double> z2dist(zVertexPos2 * 1_mm, 0.5_mm);
0063
0064 std::uniform_real_distribution<double> pTDist(0.1_GeV, 100_GeV);
0065
0066 std::uniform_real_distribution<double> phiDist(-M_PI, M_PI);
0067
0068 std::uniform_real_distribution<double> etaDist(-4., 4.);
0069
0070
0071
0072
0073
0074 BOOST_AUTO_TEST_CASE(grid_density_vertex_finder_test) {
0075 bool debugMode = false;
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087 const int mainGridSize = 3001;
0088 const int trkGridSize = 35;
0089
0090 Covariance covMat = Covariance::Identity();
0091
0092
0093 Vector3 pos0{0, 0, 0};
0094 std::shared_ptr<PerigeeSurface> perigeeSurface =
0095 Surface::makeShared<PerigeeSurface>(pos0);
0096
0097 VertexingOptions vertexingOptions(geoContext, magFieldContext);
0098
0099 using Finder1 = GridDensityVertexFinder;
0100 Finder1::Config cfg1{{{100, mainGridSize, trkGridSize}}};
0101 cfg1.cacheGridStateForTrackRemoval = false;
0102 cfg1.extractParameters.connect<&InputTrack::extractParameters>();
0103 Finder1 finder1(cfg1);
0104 IVertexFinder::State state1 = finder1.makeState(magFieldContext);
0105
0106
0107 AdaptiveGridTrackDensity::Config adaptiveDensityConfig;
0108 adaptiveDensityConfig.spatialTrkGridSizeRange = {trkGridSize, trkGridSize};
0109 adaptiveDensityConfig.spatialBinExtent = 2. / 30.01 * 1_mm;
0110 AdaptiveGridTrackDensity adaptiveDensity(adaptiveDensityConfig);
0111
0112 using Finder2 = AdaptiveGridDensityVertexFinder;
0113 Finder2::Config cfg2(adaptiveDensity);
0114 cfg2.cacheGridStateForTrackRemoval = false;
0115 cfg2.extractParameters.connect<&InputTrack::extractParameters>();
0116 Finder2 finder2(cfg2);
0117 IVertexFinder::State state2 = finder2.makeState(magFieldContext);
0118
0119 int mySeed = 31415;
0120 std::mt19937 gen(mySeed);
0121 unsigned int nTracks = 200;
0122
0123 std::vector<BoundTrackParameters> trackVec;
0124 trackVec.reserve(nTracks);
0125
0126
0127 for (unsigned int i = 0; i < nTracks; i++) {
0128
0129 Vector3 pos(xdist(gen), ydist(gen), 0);
0130
0131
0132 double pt = pTDist(gen);
0133 double phi = phiDist(gen);
0134 double eta = etaDist(gen);
0135 double charge = etaDist(gen) > 0 ? 1 : -1;
0136
0137
0138 Vector3 direction = makeDirectionFromPhiEta(phi, eta);
0139 auto intersection =
0140 perigeeSurface->intersect(geoContext, pos, direction).closest();
0141 pos = intersection.position();
0142
0143
0144
0145 pos[eZ] = ((i % 4) == 0) ? z2dist(gen) : z1dist(gen);
0146
0147 trackVec.push_back(BoundTrackParameters::create(
0148 perigeeSurface, geoContext, makeVector4(pos, 0),
0149 direction, charge / pt, covMat,
0150 ParticleHypothesis::pion())
0151 .value());
0152 }
0153
0154 std::vector<InputTrack> inputTracks;
0155 for (const auto& trk : trackVec) {
0156 inputTracks.emplace_back(&trk);
0157 }
0158
0159 auto res1 = finder1.find(inputTracks, vertexingOptions, state1);
0160 if (!res1.ok()) {
0161 std::cout << res1.error().message() << std::endl;
0162 }
0163
0164 auto res2 = finder2.find(inputTracks, vertexingOptions, state2);
0165 if (!res2.ok()) {
0166 std::cout << res2.error().message() << std::endl;
0167 }
0168
0169 double zResult1 = 0;
0170 if (res1.ok()) {
0171 BOOST_CHECK(!(*res1).empty());
0172 Vector3 result1 = (*res1).back().position();
0173 if (debugMode) {
0174 std::cout << "Vertex position result 1: " << result1.transpose()
0175 << std::endl;
0176 }
0177 CHECK_CLOSE_ABS(result1[eZ], zVertexPos1, 1_mm);
0178 zResult1 = result1[eZ];
0179 }
0180
0181 double zResult2 = 0;
0182 if (res2.ok()) {
0183 BOOST_CHECK(!(*res2).empty());
0184 Vector3 result2 = (*res2).back().position();
0185 if (debugMode) {
0186 std::cout << "Vertex position result 2: " << result2.transpose()
0187 << std::endl;
0188 }
0189 CHECK_CLOSE_ABS(result2[eZ], zVertexPos1, 1_mm);
0190 zResult2 = result2[eZ];
0191 }
0192
0193
0194 CHECK_CLOSE_REL(zResult1, zResult2, 1e-5);
0195 }
0196
0197 BOOST_AUTO_TEST_CASE(grid_density_vertex_finder_track_caching_test) {
0198 bool debugMode = false;
0199
0200 const int mainGridSize = 3001;
0201 const int trkGridSize = 35;
0202
0203 Covariance covMat = Covariance::Identity();
0204
0205
0206 Vector3 pos0{0, 0, 0};
0207 std::shared_ptr<PerigeeSurface> perigeeSurface =
0208 Surface::makeShared<PerigeeSurface>(pos0);
0209
0210 VertexingOptions vertexingOptions(geoContext, magFieldContext);
0211
0212 using Finder1 = GridDensityVertexFinder;
0213 using GridDensity = GaussianGridTrackDensity;
0214
0215
0216 GridDensity::Config densityConfig(100_mm, mainGridSize, trkGridSize);
0217 densityConfig.useHighestSumZPosition = true;
0218 GridDensity density(densityConfig);
0219
0220 Finder1::Config cfg(density);
0221 cfg.cacheGridStateForTrackRemoval = true;
0222 cfg.extractParameters.connect<&InputTrack::extractParameters>();
0223 Finder1 finder1(cfg);
0224
0225
0226 AdaptiveGridTrackDensity::Config adaptiveDensityConfig;
0227 adaptiveDensityConfig.spatialTrkGridSizeRange = {trkGridSize, trkGridSize};
0228 adaptiveDensityConfig.spatialBinExtent = 2. / 30.01 * 1_mm;
0229 adaptiveDensityConfig.useHighestSumZPosition = true;
0230 AdaptiveGridTrackDensity adaptiveDensity(adaptiveDensityConfig);
0231
0232 using Finder2 = AdaptiveGridDensityVertexFinder;
0233 Finder2::Config cfg2(adaptiveDensity);
0234 cfg2.cacheGridStateForTrackRemoval = true;
0235 cfg2.extractParameters.connect<&InputTrack::extractParameters>();
0236 Finder2 finder2(cfg2);
0237
0238 int mySeed = 31415;
0239 std::mt19937 gen(mySeed);
0240 unsigned int nTracks = 200;
0241
0242 std::vector<BoundTrackParameters> trackVec;
0243 trackVec.reserve(nTracks);
0244
0245
0246 for (unsigned int i = 0; i < nTracks; i++) {
0247
0248 Vector3 pos(xdist(gen), ydist(gen), 0);
0249
0250
0251 double pt = pTDist(gen);
0252 double phi = phiDist(gen);
0253 double eta = etaDist(gen);
0254 double charge = etaDist(gen) > 0 ? 1 : -1;
0255
0256
0257 Vector3 direction = makeDirectionFromPhiEta(phi, eta);
0258 auto intersection =
0259 perigeeSurface->intersect(geoContext, pos, direction).closest();
0260 pos = intersection.position();
0261
0262
0263
0264 pos[eZ] = ((i % 4) == 0) ? z2dist(gen) : z1dist(gen);
0265
0266 trackVec.push_back(BoundTrackParameters::create(
0267 perigeeSurface, geoContext, makeVector4(pos, 0),
0268 direction, charge / pt, covMat,
0269 ParticleHypothesis::pion())
0270 .value());
0271 }
0272
0273 std::vector<InputTrack> inputTracks;
0274 for (const auto& trk : trackVec) {
0275 inputTracks.emplace_back(&trk);
0276 }
0277
0278 IVertexFinder::State state1 = finder1.makeState(magFieldContext);
0279 IVertexFinder::State state2 = finder2.makeState(magFieldContext);
0280
0281 double zResult1 = 0;
0282 double zResult2 = 0;
0283
0284 auto res1 = finder1.find(inputTracks, vertexingOptions, state1);
0285 if (!res1.ok()) {
0286 std::cout << res1.error().message() << std::endl;
0287 }
0288 if (res1.ok()) {
0289 BOOST_CHECK(!(*res1).empty());
0290 Vector3 result = (*res1).back().position();
0291 if (debugMode) {
0292 std::cout << "Vertex position after first fill 1: " << result.transpose()
0293 << std::endl;
0294 }
0295 CHECK_CLOSE_ABS(result[eZ], zVertexPos1, 1_mm);
0296 zResult1 = result[eZ];
0297 }
0298
0299 auto res2 = finder2.find(inputTracks, vertexingOptions, state2);
0300 if (!res2.ok()) {
0301 std::cout << res2.error().message() << std::endl;
0302 }
0303 if (res2.ok()) {
0304 BOOST_CHECK(!(*res2).empty());
0305 Vector3 result = (*res2).back().position();
0306 if (debugMode) {
0307 std::cout << "Vertex position after first fill 2: " << result.transpose()
0308 << std::endl;
0309 }
0310 CHECK_CLOSE_ABS(result[eZ], zVertexPos1, 1_mm);
0311 zResult2 = result[eZ];
0312 }
0313
0314 CHECK_CLOSE_REL(zResult1, zResult2, 1e-5);
0315
0316 int trkCount = 0;
0317 std::vector<InputTrack> removedTracks;
0318 for (const auto& trk : trackVec) {
0319 if ((trkCount % 4) != 0) {
0320 removedTracks.emplace_back(&trk);
0321 }
0322 trkCount++;
0323 }
0324
0325 state1.as<Finder1::State>().tracksToRemove = removedTracks;
0326 state2.as<Finder2::State>().tracksToRemove = removedTracks;
0327
0328 auto res3 = finder1.find(inputTracks, vertexingOptions, state1);
0329 if (!res3.ok()) {
0330 std::cout << res3.error().message() << std::endl;
0331 }
0332 if (res3.ok()) {
0333 BOOST_CHECK(!(*res3).empty());
0334 Vector3 result = (*res3).back().position();
0335 if (debugMode) {
0336 std::cout
0337 << "Vertex position after removing tracks near first density peak 1: "
0338 << result << std::endl;
0339 }
0340 CHECK_CLOSE_ABS(result[eZ], zVertexPos2, 1_mm);
0341 zResult1 = result[eZ];
0342 }
0343
0344 auto res4 = finder2.find(inputTracks, vertexingOptions, state2);
0345 if (!res4.ok()) {
0346 std::cout << res4.error().message() << std::endl;
0347 }
0348 if (res4.ok()) {
0349 BOOST_CHECK(!(*res4).empty());
0350 Vector3 result = (*res4).back().position();
0351 if (debugMode) {
0352 std::cout
0353 << "Vertex position after removing tracks near first density peak 2: "
0354 << result << std::endl;
0355 }
0356 CHECK_CLOSE_ABS(result[eZ], zVertexPos2, 1_mm);
0357 zResult2 = result[eZ];
0358 }
0359
0360 CHECK_CLOSE_REL(zResult1, zResult2, 1e-5);
0361 }
0362
0363
0364
0365
0366 BOOST_AUTO_TEST_CASE(grid_density_vertex_finder_seed_width_test) {
0367 bool debugMode = false;
0368
0369 const int mainGridSize = 3001;
0370 const int trkGridSize = 35;
0371
0372 Covariance covMat = Covariance::Identity();
0373
0374
0375 Vector3 pos0{0, 0, 0};
0376 std::shared_ptr<PerigeeSurface> perigeeSurface =
0377 Surface::makeShared<PerigeeSurface>(pos0);
0378
0379 VertexingOptions vertexingOptions(geoContext, magFieldContext);
0380 Vertex constraintVtx;
0381 constraintVtx.setCovariance(SquareMatrix3::Identity());
0382 vertexingOptions.constraint = constraintVtx;
0383
0384 using Finder1 = GridDensityVertexFinder;
0385 Finder1::Config cfg1{{{100, mainGridSize, trkGridSize}}};
0386 cfg1.cacheGridStateForTrackRemoval = false;
0387 cfg1.estimateSeedWidth = true;
0388 cfg1.extractParameters.connect<&InputTrack::extractParameters>();
0389 Finder1 finder1(cfg1);
0390 IVertexFinder::State state1 = finder1.makeState(magFieldContext);
0391
0392
0393 AdaptiveGridTrackDensity::Config adaptiveDensityConfig;
0394 adaptiveDensityConfig.spatialTrkGridSizeRange = {trkGridSize, trkGridSize};
0395 adaptiveDensityConfig.spatialBinExtent = 2. / 30.01 * 1_mm;
0396 AdaptiveGridTrackDensity adaptiveDensity(adaptiveDensityConfig);
0397
0398 using Finder2 = AdaptiveGridDensityVertexFinder;
0399 Finder2::Config cfg2(adaptiveDensity);
0400 cfg2.cacheGridStateForTrackRemoval = false;
0401 cfg2.estimateSeedWidth = true;
0402 cfg2.extractParameters.connect<&InputTrack::extractParameters>();
0403 Finder2 finder2(cfg2);
0404 IVertexFinder::State state2 = finder2.makeState(magFieldContext);
0405
0406 int mySeed = 31415;
0407 std::mt19937 gen(mySeed);
0408 unsigned int nTracks = 20;
0409
0410 std::vector<BoundTrackParameters> trackVec;
0411 trackVec.reserve(nTracks);
0412
0413
0414 for (unsigned int i = 0; i < nTracks; i++) {
0415
0416 Vector3 pos(xdist(gen), ydist(gen), 0);
0417
0418
0419 double pt = pTDist(gen);
0420 double phi = phiDist(gen);
0421 double eta = etaDist(gen);
0422 double charge = etaDist(gen) > 0 ? 1 : -1;
0423
0424
0425 Vector3 direction = makeDirectionFromPhiEta(phi, eta);
0426 auto intersection =
0427 perigeeSurface->intersect(geoContext, pos, direction).closest();
0428 pos = intersection.position();
0429
0430 pos[eZ] = z1dist(gen);
0431
0432 trackVec.push_back(BoundTrackParameters::create(
0433 perigeeSurface, geoContext, makeVector4(pos, 0),
0434 direction, charge / pt, covMat,
0435 ParticleHypothesis::pion())
0436 .value());
0437 }
0438
0439 std::vector<InputTrack> inputTracks;
0440 for (const auto& trk : trackVec) {
0441 inputTracks.emplace_back(&trk);
0442 }
0443
0444
0445 auto res1 = finder1.find(inputTracks, vertexingOptions, state1);
0446 if (!res1.ok()) {
0447 std::cout << res1.error().message() << std::endl;
0448 }
0449
0450 double covZZ1 = 0;
0451 if (res1.ok()) {
0452 BOOST_CHECK(!(*res1).empty());
0453 SquareMatrix3 cov = (*res1).back().covariance();
0454 BOOST_CHECK_NE(constraintVtx.covariance(), cov);
0455 BOOST_CHECK_NE(cov(eZ, eZ), 0.);
0456 covZZ1 = cov(eZ, eZ);
0457 if (debugMode) {
0458 std::cout << "Estimated z-seed width 1: " << cov(eZ, eZ) << std::endl;
0459 }
0460 }
0461
0462
0463 auto res2 = finder2.find(inputTracks, vertexingOptions, state2);
0464 if (!res2.ok()) {
0465 std::cout << res2.error().message() << std::endl;
0466 }
0467
0468 double covZZ2 = 0;
0469 if (res2.ok()) {
0470 BOOST_CHECK(!(*res2).empty());
0471 SquareMatrix3 cov = (*res2).back().covariance();
0472 BOOST_CHECK_NE(constraintVtx.covariance(), cov);
0473 BOOST_CHECK_NE(cov(eZ, eZ), 0.);
0474 covZZ2 = cov(eZ, eZ);
0475 if (debugMode) {
0476 std::cout << "Estimated z-seed width 2: " << cov(eZ, eZ) << std::endl;
0477 }
0478 }
0479
0480
0481 CHECK_CLOSE_ABS(covZZ1, covZZ2, 1e-4);
0482 }
0483
0484 }