File indexing completed on 2025-01-18 09:13:01
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 Finder1::Config cfg1{{{100, mainGridSize, trkGridSize}}};
0100 cfg1.cacheGridStateForTrackRemoval = false;
0101 cfg1.extractParameters.connect<&InputTrack::extractParameters>();
0102 Finder1 finder1(cfg1);
0103 IVertexFinder::State state1 = finder1.makeState(magFieldContext);
0104
0105
0106 AdaptiveGridTrackDensity::Config adaptiveDensityConfig;
0107 adaptiveDensityConfig.spatialTrkGridSizeRange = {trkGridSize, trkGridSize};
0108 adaptiveDensityConfig.spatialBinExtent = 2. / 30.01 * 1_mm;
0109 AdaptiveGridTrackDensity adaptiveDensity(adaptiveDensityConfig);
0110
0111 using Finder2 = AdaptiveGridDensityVertexFinder;
0112 Finder2::Config cfg2(adaptiveDensity);
0113 cfg2.cacheGridStateForTrackRemoval = false;
0114 cfg2.extractParameters.connect<&InputTrack::extractParameters>();
0115 Finder2 finder2(cfg2);
0116 IVertexFinder::State state2 = finder2.makeState(magFieldContext);
0117
0118 int mySeed = 31415;
0119 std::mt19937 gen(mySeed);
0120 unsigned int nTracks = 200;
0121
0122 std::vector<BoundTrackParameters> trackVec;
0123 trackVec.reserve(nTracks);
0124
0125
0126 for (unsigned int i = 0; i < nTracks; i++) {
0127
0128 Vector3 pos(xdist(gen), ydist(gen), 0);
0129
0130
0131 double pt = pTDist(gen);
0132 double phi = phiDist(gen);
0133 double eta = etaDist(gen);
0134 double charge = etaDist(gen) > 0 ? 1 : -1;
0135
0136
0137 Vector3 direction = makeDirectionFromPhiEta(phi, eta);
0138 auto intersection =
0139 perigeeSurface->intersect(geoContext, pos, direction).closest();
0140 pos = intersection.position();
0141
0142
0143
0144 pos[eZ] = ((i % 4) == 0) ? z2dist(gen) : z1dist(gen);
0145
0146 trackVec.push_back(BoundTrackParameters::create(
0147 perigeeSurface, geoContext, makeVector4(pos, 0),
0148 direction, charge / pt, covMat,
0149 ParticleHypothesis::pion())
0150 .value());
0151 }
0152
0153 std::vector<InputTrack> inputTracks;
0154 for (const auto& trk : trackVec) {
0155 inputTracks.emplace_back(&trk);
0156 }
0157
0158 auto res1 = finder1.find(inputTracks, vertexingOptions, state1);
0159 if (!res1.ok()) {
0160 std::cout << res1.error().message() << std::endl;
0161 }
0162
0163 auto res2 = finder2.find(inputTracks, vertexingOptions, state2);
0164 if (!res2.ok()) {
0165 std::cout << res2.error().message() << std::endl;
0166 }
0167
0168 double zResult1 = 0;
0169 if (res1.ok()) {
0170 BOOST_CHECK(!(*res1).empty());
0171 Vector3 result1 = (*res1).back().position();
0172 if (debugMode) {
0173 std::cout << "Vertex position result 1: " << result1.transpose()
0174 << std::endl;
0175 }
0176 CHECK_CLOSE_ABS(result1[eZ], zVertexPos1, 1_mm);
0177 zResult1 = result1[eZ];
0178 }
0179
0180 double zResult2 = 0;
0181 if (res2.ok()) {
0182 BOOST_CHECK(!(*res2).empty());
0183 Vector3 result2 = (*res2).back().position();
0184 if (debugMode) {
0185 std::cout << "Vertex position result 2: " << result2.transpose()
0186 << std::endl;
0187 }
0188 CHECK_CLOSE_ABS(result2[eZ], zVertexPos1, 1_mm);
0189 zResult2 = result2[eZ];
0190 }
0191
0192
0193 CHECK_CLOSE_REL(zResult1, zResult2, 1e-5);
0194 }
0195
0196 BOOST_AUTO_TEST_CASE(grid_density_vertex_finder_track_caching_test) {
0197 bool debugMode = false;
0198
0199 const int mainGridSize = 3001;
0200 const int trkGridSize = 35;
0201
0202 Covariance covMat = Covariance::Identity();
0203
0204
0205 Vector3 pos0{0, 0, 0};
0206 std::shared_ptr<PerigeeSurface> perigeeSurface =
0207 Surface::makeShared<PerigeeSurface>(pos0);
0208
0209 VertexingOptions vertexingOptions(geoContext, magFieldContext);
0210
0211 using Finder1 = GridDensityVertexFinder;
0212 using GridDensity = GaussianGridTrackDensity;
0213
0214
0215 GridDensity::Config densityConfig(100_mm, mainGridSize, trkGridSize);
0216 densityConfig.useHighestSumZPosition = true;
0217 GridDensity density(densityConfig);
0218
0219 Finder1::Config cfg(density);
0220 cfg.cacheGridStateForTrackRemoval = true;
0221 cfg.extractParameters.connect<&InputTrack::extractParameters>();
0222 Finder1 finder1(cfg);
0223
0224
0225 AdaptiveGridTrackDensity::Config adaptiveDensityConfig;
0226 adaptiveDensityConfig.spatialTrkGridSizeRange = {trkGridSize, trkGridSize};
0227 adaptiveDensityConfig.spatialBinExtent = 2. / 30.01 * 1_mm;
0228 adaptiveDensityConfig.useHighestSumZPosition = true;
0229 AdaptiveGridTrackDensity adaptiveDensity(adaptiveDensityConfig);
0230
0231 using Finder2 = AdaptiveGridDensityVertexFinder;
0232 Finder2::Config cfg2(adaptiveDensity);
0233 cfg2.cacheGridStateForTrackRemoval = true;
0234 cfg2.extractParameters.connect<&InputTrack::extractParameters>();
0235 Finder2 finder2(cfg2);
0236
0237 int mySeed = 31415;
0238 std::mt19937 gen(mySeed);
0239 unsigned int nTracks = 200;
0240
0241 std::vector<BoundTrackParameters> trackVec;
0242 trackVec.reserve(nTracks);
0243
0244
0245 for (unsigned int i = 0; i < nTracks; i++) {
0246
0247 Vector3 pos(xdist(gen), ydist(gen), 0);
0248
0249
0250 double pt = pTDist(gen);
0251 double phi = phiDist(gen);
0252 double eta = etaDist(gen);
0253 double charge = etaDist(gen) > 0 ? 1 : -1;
0254
0255
0256 Vector3 direction = makeDirectionFromPhiEta(phi, eta);
0257 auto intersection =
0258 perigeeSurface->intersect(geoContext, pos, direction).closest();
0259 pos = intersection.position();
0260
0261
0262
0263 pos[eZ] = ((i % 4) == 0) ? z2dist(gen) : z1dist(gen);
0264
0265 trackVec.push_back(BoundTrackParameters::create(
0266 perigeeSurface, geoContext, makeVector4(pos, 0),
0267 direction, charge / pt, covMat,
0268 ParticleHypothesis::pion())
0269 .value());
0270 }
0271
0272 std::vector<InputTrack> inputTracks;
0273 for (const auto& trk : trackVec) {
0274 inputTracks.emplace_back(&trk);
0275 }
0276
0277 IVertexFinder::State state1 = finder1.makeState(magFieldContext);
0278 IVertexFinder::State state2 = finder2.makeState(magFieldContext);
0279
0280 double zResult1 = 0;
0281 double zResult2 = 0;
0282
0283 auto res1 = finder1.find(inputTracks, vertexingOptions, state1);
0284 if (!res1.ok()) {
0285 std::cout << res1.error().message() << std::endl;
0286 }
0287 if (res1.ok()) {
0288 BOOST_CHECK(!(*res1).empty());
0289 Vector3 result = (*res1).back().position();
0290 if (debugMode) {
0291 std::cout << "Vertex position after first fill 1: " << result.transpose()
0292 << std::endl;
0293 }
0294 CHECK_CLOSE_ABS(result[eZ], zVertexPos1, 1_mm);
0295 zResult1 = result[eZ];
0296 }
0297
0298 auto res2 = finder2.find(inputTracks, vertexingOptions, state2);
0299 if (!res2.ok()) {
0300 std::cout << res2.error().message() << std::endl;
0301 }
0302 if (res2.ok()) {
0303 BOOST_CHECK(!(*res2).empty());
0304 Vector3 result = (*res2).back().position();
0305 if (debugMode) {
0306 std::cout << "Vertex position after first fill 2: " << result.transpose()
0307 << std::endl;
0308 }
0309 CHECK_CLOSE_ABS(result[eZ], zVertexPos1, 1_mm);
0310 zResult2 = result[eZ];
0311 }
0312
0313 CHECK_CLOSE_REL(zResult1, zResult2, 1e-5);
0314
0315 int trkCount = 0;
0316 std::vector<InputTrack> removedTracks;
0317 for (const auto& trk : trackVec) {
0318 if ((trkCount % 4) != 0) {
0319 removedTracks.emplace_back(&trk);
0320 }
0321 trkCount++;
0322 }
0323
0324 state1.as<Finder1::State>().tracksToRemove = removedTracks;
0325 state2.as<Finder2::State>().tracksToRemove = removedTracks;
0326
0327 auto res3 = finder1.find(inputTracks, vertexingOptions, state1);
0328 if (!res3.ok()) {
0329 std::cout << res3.error().message() << std::endl;
0330 }
0331 if (res3.ok()) {
0332 BOOST_CHECK(!(*res3).empty());
0333 Vector3 result = (*res3).back().position();
0334 if (debugMode) {
0335 std::cout
0336 << "Vertex position after removing tracks near first density peak 1: "
0337 << result << std::endl;
0338 }
0339 CHECK_CLOSE_ABS(result[eZ], zVertexPos2, 1_mm);
0340 zResult1 = result[eZ];
0341 }
0342
0343 auto res4 = finder2.find(inputTracks, vertexingOptions, state2);
0344 if (!res4.ok()) {
0345 std::cout << res4.error().message() << std::endl;
0346 }
0347 if (res4.ok()) {
0348 BOOST_CHECK(!(*res4).empty());
0349 Vector3 result = (*res4).back().position();
0350 if (debugMode) {
0351 std::cout
0352 << "Vertex position after removing tracks near first density peak 2: "
0353 << result << std::endl;
0354 }
0355 CHECK_CLOSE_ABS(result[eZ], zVertexPos2, 1_mm);
0356 zResult2 = result[eZ];
0357 }
0358
0359 CHECK_CLOSE_REL(zResult1, zResult2, 1e-5);
0360 }
0361
0362
0363
0364
0365 BOOST_AUTO_TEST_CASE(grid_density_vertex_finder_seed_width_test) {
0366 bool debugMode = false;
0367
0368 const int mainGridSize = 3001;
0369 const int trkGridSize = 35;
0370
0371 Covariance covMat = Covariance::Identity();
0372
0373
0374 Vector3 pos0{0, 0, 0};
0375 std::shared_ptr<PerigeeSurface> perigeeSurface =
0376 Surface::makeShared<PerigeeSurface>(pos0);
0377
0378 VertexingOptions vertexingOptions(geoContext, magFieldContext);
0379 Vertex constraintVtx;
0380 constraintVtx.setCovariance(SquareMatrix3::Identity());
0381 vertexingOptions.constraint = constraintVtx;
0382
0383 using Finder1 = GridDensityVertexFinder;
0384 Finder1::Config cfg1{{{100, mainGridSize, trkGridSize}}};
0385 cfg1.cacheGridStateForTrackRemoval = false;
0386 cfg1.estimateSeedWidth = true;
0387 cfg1.extractParameters.connect<&InputTrack::extractParameters>();
0388 Finder1 finder1(cfg1);
0389 IVertexFinder::State state1 = finder1.makeState(magFieldContext);
0390
0391
0392 AdaptiveGridTrackDensity::Config adaptiveDensityConfig;
0393 adaptiveDensityConfig.spatialTrkGridSizeRange = {trkGridSize, trkGridSize};
0394 adaptiveDensityConfig.spatialBinExtent = 2. / 30.01 * 1_mm;
0395 AdaptiveGridTrackDensity adaptiveDensity(adaptiveDensityConfig);
0396
0397 using Finder2 = AdaptiveGridDensityVertexFinder;
0398 Finder2::Config cfg2(adaptiveDensity);
0399 cfg2.cacheGridStateForTrackRemoval = false;
0400 cfg2.estimateSeedWidth = true;
0401 cfg2.extractParameters.connect<&InputTrack::extractParameters>();
0402 Finder2 finder2(cfg2);
0403 IVertexFinder::State state2 = finder2.makeState(magFieldContext);
0404
0405 int mySeed = 31415;
0406 std::mt19937 gen(mySeed);
0407 unsigned int nTracks = 20;
0408
0409 std::vector<BoundTrackParameters> trackVec;
0410 trackVec.reserve(nTracks);
0411
0412
0413 for (unsigned int i = 0; i < nTracks; i++) {
0414
0415 Vector3 pos(xdist(gen), ydist(gen), 0);
0416
0417
0418 double pt = pTDist(gen);
0419 double phi = phiDist(gen);
0420 double eta = etaDist(gen);
0421 double charge = etaDist(gen) > 0 ? 1 : -1;
0422
0423
0424 Vector3 direction = makeDirectionFromPhiEta(phi, eta);
0425 auto intersection =
0426 perigeeSurface->intersect(geoContext, pos, direction).closest();
0427 pos = intersection.position();
0428
0429 pos[eZ] = z1dist(gen);
0430
0431 trackVec.push_back(BoundTrackParameters::create(
0432 perigeeSurface, geoContext, makeVector4(pos, 0),
0433 direction, charge / pt, covMat,
0434 ParticleHypothesis::pion())
0435 .value());
0436 }
0437
0438 std::vector<InputTrack> inputTracks;
0439 for (const auto& trk : trackVec) {
0440 inputTracks.emplace_back(&trk);
0441 }
0442
0443
0444 auto res1 = finder1.find(inputTracks, vertexingOptions, state1);
0445 if (!res1.ok()) {
0446 std::cout << res1.error().message() << std::endl;
0447 }
0448
0449 double covZZ1 = 0;
0450 if (res1.ok()) {
0451 BOOST_CHECK(!(*res1).empty());
0452 SquareMatrix3 cov = (*res1).back().covariance();
0453 BOOST_CHECK_NE(constraintVtx.covariance(), cov);
0454 BOOST_CHECK_NE(cov(eZ, eZ), 0.);
0455 covZZ1 = cov(eZ, eZ);
0456 if (debugMode) {
0457 std::cout << "Estimated z-seed width 1: " << cov(eZ, eZ) << std::endl;
0458 }
0459 }
0460
0461
0462 auto res2 = finder2.find(inputTracks, vertexingOptions, state2);
0463 if (!res2.ok()) {
0464 std::cout << res2.error().message() << std::endl;
0465 }
0466
0467 double covZZ2 = 0;
0468 if (res2.ok()) {
0469 BOOST_CHECK(!(*res2).empty());
0470 SquareMatrix3 cov = (*res2).back().covariance();
0471 BOOST_CHECK_NE(constraintVtx.covariance(), cov);
0472 BOOST_CHECK_NE(cov(eZ, eZ), 0.);
0473 covZZ2 = cov(eZ, eZ);
0474 if (debugMode) {
0475 std::cout << "Estimated z-seed width 2: " << cov(eZ, eZ) << std::endl;
0476 }
0477 }
0478
0479
0480 CHECK_CLOSE_ABS(covZZ1, covZZ2, 1e-4);
0481 }
0482
0483 }