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