Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-13 07:37:53

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/MagneticField/ConstantBField.hpp"
0017 #include "Acts/MagneticField/MagneticFieldContext.hpp"
0018 #include "Acts/Propagator/EigenStepper.hpp"
0019 #include "Acts/Propagator/Propagator.hpp"
0020 #include "Acts/Utilities/AnnealingUtility.hpp"
0021 #include "Acts/Utilities/Result.hpp"
0022 #include "Acts/Vertexing/AdaptiveGridDensityVertexFinder.hpp"
0023 #include "Acts/Vertexing/AdaptiveMultiVertexFinder.hpp"
0024 #include "Acts/Vertexing/AdaptiveMultiVertexFitter.hpp"
0025 #include "Acts/Vertexing/GaussianTrackDensity.hpp"
0026 #include "Acts/Vertexing/GridDensityVertexFinder.hpp"
0027 #include "Acts/Vertexing/HelicalTrackLinearizer.hpp"
0028 #include "Acts/Vertexing/IVertexFinder.hpp"
0029 #include "Acts/Vertexing/ImpactPointEstimator.hpp"
0030 #include "Acts/Vertexing/TrackAtVertex.hpp"
0031 #include "Acts/Vertexing/TrackDensityVertexFinder.hpp"
0032 #include "Acts/Vertexing/Vertex.hpp"
0033 #include "Acts/Vertexing/VertexingOptions.hpp"
0034 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0035 
0036 #include <array>
0037 #include <chrono>
0038 #include <cmath>
0039 #include <iostream>
0040 #include <memory>
0041 #include <numbers>
0042 #include <string>
0043 #include <system_error>
0044 #include <tuple>
0045 #include <utility>
0046 #include <vector>
0047 
0048 #include "VertexingDataHelper.hpp"
0049 
0050 using namespace Acts;
0051 using namespace Acts::UnitLiterals;
0052 
0053 namespace ActsTests {
0054 
0055 using Covariance = BoundMatrix;
0056 using Propagator = Acts::Propagator<EigenStepper<>>;
0057 using Linearizer = HelicalTrackLinearizer;
0058 
0059 // Create a test context
0060 GeometryContext geoContext = GeometryContext::dangerouslyDefaultConstruct();
0061 MagneticFieldContext magFieldContext = MagneticFieldContext();
0062 
0063 const std::string toolString = "AMVF";
0064 
0065 class FixedVertexSeedFinder final : public IVertexFinder {
0066  public:
0067   struct State {};
0068 
0069   explicit FixedVertexSeedFinder(std::vector<Vertex> seeds)
0070       : m_seeds(std::move(seeds)) {}
0071 
0072   Result<std::vector<Vertex>> find(
0073       const std::vector<InputTrack>& /*trackVector*/,
0074       const VertexingOptions& /*vertexingOptions*/,
0075       IVertexFinder::State& /*state*/) const override {
0076     return m_seeds;
0077   }
0078 
0079   IVertexFinder::State makeState(
0080       const MagneticFieldContext& /*mctx*/) const override {
0081     return IVertexFinder::State{State{}};
0082   }
0083 
0084   void setTracksToRemove(
0085       IVertexFinder::State& /*state*/,
0086       const std::vector<InputTrack>& /*removedTracks*/) const override {}
0087 
0088  private:
0089   std::vector<Vertex> m_seeds;
0090 };
0091 
0092 BOOST_AUTO_TEST_SUITE(VertexingSuite)
0093 
0094 /// @brief AMVF test with Gaussian seed finder
0095 BOOST_AUTO_TEST_CASE(adaptive_multi_vertex_finder_test) {
0096   // Set debug mode
0097   bool debugMode = false;
0098   // Set up constant B-Field
0099   auto bField = std::make_shared<ConstantBField>(Vector3(0., 0., 2_T));
0100 
0101   // Set up EigenStepper
0102   // EigenStepper<> stepper(bField);
0103   EigenStepper<> stepper(bField);
0104 
0105   // Set up propagator with void navigator
0106   auto propagator = std::make_shared<Propagator>(stepper);
0107 
0108   // IP 3D Estimator
0109   ImpactPointEstimator::Config ipEstimatorCfg(bField, propagator);
0110   ImpactPointEstimator ipEstimator(ipEstimatorCfg);
0111 
0112   std::vector<double> temperatures{
0113       8., 4., 2., std::numbers::sqrt2, std::sqrt(3. / 2.), 1.};
0114   AnnealingUtility::Config annealingConfig;
0115   annealingConfig.setOfTemperatures = temperatures;
0116   AnnealingUtility annealingUtility(annealingConfig);
0117 
0118   using Fitter = AdaptiveMultiVertexFitter;
0119 
0120   Fitter::Config fitterCfg(ipEstimator);
0121 
0122   fitterCfg.annealingTool = annealingUtility;
0123 
0124   // Linearizer for BoundTrackParameters type test
0125   Linearizer::Config ltConfig;
0126   ltConfig.bField = bField;
0127   ltConfig.propagator = propagator;
0128   Linearizer linearizer(ltConfig);
0129 
0130   // Test smoothing
0131   fitterCfg.doSmoothing = true;
0132   fitterCfg.extractParameters.connect<&InputTrack::extractParameters>();
0133   fitterCfg.trackLinearizer.connect<&Linearizer::linearizeTrack>(&linearizer);
0134 
0135   Fitter fitter(fitterCfg);
0136 
0137   GaussianTrackDensity::Config densityCfg;
0138   densityCfg.extractParameters.connect<&InputTrack::extractParameters>();
0139   auto seedFinder = std::make_shared<TrackDensityVertexFinder>(
0140       TrackDensityVertexFinder::Config{Acts::GaussianTrackDensity(densityCfg)});
0141 
0142   AdaptiveMultiVertexFinder::Config finderConfig(std::move(fitter), seedFinder,
0143                                                  ipEstimator, bField);
0144   finderConfig.extractParameters.connect<&InputTrack::extractParameters>();
0145 
0146   AdaptiveMultiVertexFinder finder(std::move(finderConfig));
0147   IVertexFinder::State state = finder.makeState(magFieldContext);
0148 
0149   auto csvData = readTracksAndVertexCSV(toolString);
0150   std::vector<BoundTrackParameters> tracks = std::get<TracksData>(csvData);
0151 
0152   if (debugMode) {
0153     std::cout << "Number of tracks in event: " << tracks.size() << std::endl;
0154     int maxCout = 10;
0155     int count = 0;
0156     for (const auto& trk : tracks) {
0157       std::cout << count << ". track: " << std::endl;
0158       std::cout << "params: " << trk << std::endl;
0159       count++;
0160       if (count == maxCout) {
0161         break;
0162       }
0163     }
0164   }
0165 
0166   std::vector<InputTrack> inputTracks;
0167   for (const auto& trk : tracks) {
0168     inputTracks.emplace_back(&trk);
0169   }
0170 
0171   // TODO: test without using beam spot constraint
0172   Vertex bsConstr = std::get<BeamSpotData>(csvData);
0173   VertexingOptions vertexingOptions(geoContext, magFieldContext, bsConstr);
0174 
0175   auto t1 = std::chrono::system_clock::now();
0176   auto findResult = finder.find(inputTracks, vertexingOptions, state);
0177   auto t2 = std::chrono::system_clock::now();
0178 
0179   auto timediff =
0180       std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
0181 
0182   if (!findResult.ok()) {
0183     std::cout << findResult.error().message() << std::endl;
0184   }
0185 
0186   BOOST_CHECK(findResult.ok());
0187 
0188   std::vector<Vertex> allVertices = *findResult;
0189 
0190   if (debugMode) {
0191     std::cout << "Time needed: " << timediff << " ms." << std::endl;
0192     std::cout << "Number of vertices reconstructed: " << allVertices.size()
0193               << std::endl;
0194 
0195     int count = 0;
0196     for (const auto& vtx : allVertices) {
0197       count++;
0198       std::cout << count << ". Vertex at position: " << vtx.position()[0]
0199                 << ", " << vtx.position()[1] << ", " << vtx.position()[2]
0200                 << std::endl;
0201       std::cout << count << ". Vertex with cov: " << vtx.covariance()
0202                 << std::endl;
0203       std::cout << "\t with n tracks: " << vtx.tracks().size() << std::endl;
0204     }
0205   }
0206 
0207   // Test expected outcomes from athena implementation
0208   // Number of reconstructed vertices
0209   auto verticesInfo = std::get<VerticesData>(csvData);
0210   const int expNRecoVertices = verticesInfo.size();
0211 
0212   BOOST_CHECK_EQUAL(allVertices.size(), expNRecoVertices);
0213 
0214   double relTol = 1e-2;
0215   double small = 1e-3;
0216   for (int i = 0; i < expNRecoVertices; i++) {
0217     auto recoVtx = allVertices[i];
0218     auto expVtx = verticesInfo[i];
0219     CHECK_CLOSE_OR_SMALL(recoVtx.position(), expVtx.position, relTol, small);
0220     CHECK_CLOSE_OR_SMALL(recoVtx.covariance(), expVtx.covariance, relTol,
0221                          small);
0222     BOOST_CHECK_EQUAL(recoVtx.tracks().size(), expVtx.nTracks);
0223     CHECK_CLOSE_OR_SMALL(recoVtx.tracks()[0].trackWeight, expVtx.trk1Weight,
0224                          relTol, small);
0225     CHECK_CLOSE_OR_SMALL(recoVtx.tracks()[0].vertexCompatibility,
0226                          expVtx.trk1Comp, relTol, small);
0227   }
0228 }
0229 
0230 // Dummy user-defined InputTrackStub type
0231 struct InputTrackStub {
0232   InputTrackStub(const BoundTrackParameters& params, int id)
0233       : m_parameters(params), m_id(id) {}
0234 
0235   const BoundTrackParameters& parameters() const { return m_parameters; }
0236   // store e.g. link to original objects here
0237 
0238   int id() const { return m_id; }
0239 
0240  private:
0241   BoundTrackParameters m_parameters;
0242 
0243   // Some test track ID
0244   int m_id;
0245 };
0246 
0247 /// @brief AMVF test with user-defined input track type
0248 BOOST_AUTO_TEST_CASE(adaptive_multi_vertex_finder_usertype_test) {
0249   // Set debug mode
0250   bool debugMode = false;
0251   // Set up constant B-Field
0252   auto bField = std::make_shared<ConstantBField>(Vector3(0., 0., 2_T));
0253 
0254   // Set up EigenStepper
0255   // EigenStepper<> stepper(bField);
0256   EigenStepper<> stepper(bField);
0257 
0258   // Set up propagator with void navigator
0259   auto propagator = std::make_shared<Propagator>(stepper);
0260 
0261   // Create a custom std::function to extract BoundTrackParameters from
0262   // user-defined InputTrackStub
0263   auto extractParameters = [](const InputTrack& track) {
0264     return track.as<InputTrackStub>()->parameters();
0265   };
0266 
0267   // IP 3D Estimator
0268   ImpactPointEstimator::Config ipEstimatorCfg(bField, propagator);
0269   ImpactPointEstimator ipEstimator(ipEstimatorCfg);
0270 
0271   std::vector<double> temperatures{
0272       8., 4., 2., std::numbers::sqrt2, std::sqrt(3. / 2.), 1.};
0273   AnnealingUtility::Config annealingConfig;
0274   annealingConfig.setOfTemperatures = temperatures;
0275   AnnealingUtility annealingUtility(annealingConfig);
0276 
0277   using Fitter = AdaptiveMultiVertexFitter;
0278 
0279   Fitter::Config fitterCfg(ipEstimator);
0280 
0281   fitterCfg.annealingTool = annealingUtility;
0282 
0283   // Linearizer
0284   Linearizer::Config ltConfig;
0285   ltConfig.bField = bField;
0286   ltConfig.propagator = propagator;
0287   Linearizer linearizer(ltConfig);
0288 
0289   // Test smoothing
0290   fitterCfg.doSmoothing = true;
0291   fitterCfg.extractParameters.connect(extractParameters);
0292   fitterCfg.trackLinearizer.connect<&Linearizer::linearizeTrack>(&linearizer);
0293 
0294   Fitter fitter(fitterCfg);
0295 
0296   GaussianTrackDensity::Config densityCfg;
0297   densityCfg.extractParameters.connect(extractParameters);
0298   auto seedFinder = std::make_shared<TrackDensityVertexFinder>(
0299       TrackDensityVertexFinder::Config{Acts::GaussianTrackDensity(densityCfg)});
0300 
0301   AdaptiveMultiVertexFinder::Config finderConfig(
0302       std::move(fitter), std::move(seedFinder), ipEstimator, bField);
0303   finderConfig.extractParameters.connect(extractParameters);
0304 
0305   AdaptiveMultiVertexFinder finder(std::move(finderConfig));
0306   IVertexFinder::State state = finder.makeState(magFieldContext);
0307 
0308   auto csvData = readTracksAndVertexCSV(toolString);
0309   auto tracks = std::get<TracksData>(csvData);
0310 
0311   std::vector<InputTrackStub> userTracks;
0312   int idCount = 0;
0313   for (const auto& trk : tracks) {
0314     userTracks.push_back(InputTrackStub(trk, idCount));
0315     idCount++;
0316   }
0317 
0318   if (debugMode) {
0319     std::cout << "Number of tracks in event: " << tracks.size() << std::endl;
0320     int maxCout = 10;
0321     int count = 0;
0322     for (const auto& trk : tracks) {
0323       std::cout << count << ". track: " << std::endl;
0324       std::cout << "params: " << trk << std::endl;
0325       count++;
0326       if (count == maxCout) {
0327         break;
0328       }
0329     }
0330   }
0331 
0332   std::vector<InputTrack> userInputTracks;
0333   for (const auto& trk : userTracks) {
0334     userInputTracks.emplace_back(&trk);
0335   }
0336 
0337   Vertex constraintVtx;
0338   constraintVtx.setPosition(std::get<BeamSpotData>(csvData).position());
0339   constraintVtx.setCovariance(std::get<BeamSpotData>(csvData).covariance());
0340 
0341   VertexingOptions vertexingOptions(geoContext, magFieldContext, constraintVtx);
0342 
0343   auto findResult = finder.find(userInputTracks, vertexingOptions, state);
0344 
0345   if (!findResult.ok()) {
0346     std::cout << findResult.error().message() << std::endl;
0347   }
0348 
0349   BOOST_CHECK(findResult.ok());
0350 
0351   std::vector<Vertex> allVertices = *findResult;
0352 
0353   if (debugMode) {
0354     std::cout << "Number of vertices reconstructed: " << allVertices.size()
0355               << std::endl;
0356 
0357     int count = 0;
0358     for (const auto& vtx : allVertices) {
0359       count++;
0360       std::cout << count << ". Vertex at position: " << vtx.position()[0]
0361                 << ", " << vtx.position()[1] << ", " << vtx.position()[2]
0362                 << std::endl;
0363       std::cout << count << ". Vertex with cov: " << vtx.covariance()
0364                 << std::endl;
0365       std::cout << "\t with n tracks: " << vtx.tracks().size() << std::endl;
0366     }
0367     for (auto& trk : allVertices[0].tracks()) {
0368       std::cout << "Track ID at first vertex: "
0369                 << trk.originalParams.as<InputTrackStub>()->id() << std::endl;
0370     }
0371   }
0372 
0373   auto verticesInfo = std::get<VerticesData>(csvData);
0374   const int expNRecoVertices = verticesInfo.size();
0375 
0376   BOOST_CHECK_EQUAL(allVertices.size(), expNRecoVertices);
0377 
0378   double relTol = 1e-2;
0379   double small = 1e-3;
0380   for (int i = 0; i < expNRecoVertices; i++) {
0381     auto recoVtx = allVertices[i];
0382     auto expVtx = verticesInfo[i];
0383     CHECK_CLOSE_OR_SMALL(recoVtx.position(), expVtx.position, relTol, small);
0384     CHECK_CLOSE_OR_SMALL(recoVtx.covariance(), expVtx.covariance, relTol,
0385                          small);
0386     BOOST_CHECK_EQUAL(recoVtx.tracks().size(), expVtx.nTracks);
0387     CHECK_CLOSE_OR_SMALL(recoVtx.tracks()[0].trackWeight, expVtx.trk1Weight,
0388                          relTol, small);
0389     CHECK_CLOSE_OR_SMALL(recoVtx.tracks()[0].vertexCompatibility,
0390                          expVtx.trk1Comp, relTol, small);
0391   }
0392 }
0393 
0394 /// @brief AMVF test with grid seed finder
0395 BOOST_AUTO_TEST_CASE(adaptive_multi_vertex_finder_grid_seed_finder_test) {
0396   // Set debug mode
0397   bool debugMode = false;
0398   if (debugMode) {
0399     std::cout << "Starting AMVF test with grid seed finder..." << std::endl;
0400   }
0401   // Set up constant B-Field
0402   auto bField = std::make_shared<ConstantBField>(Vector3(0., 0., 2_T));
0403 
0404   // Set up EigenStepper
0405   // EigenStepper<> stepper(bField);
0406   EigenStepper<> stepper(bField);
0407 
0408   // Set up propagator with void navigator
0409   auto propagator = std::make_shared<Propagator>(stepper);
0410 
0411   // IP Estimator
0412   ImpactPointEstimator::Config ipEstCfg(bField, propagator);
0413   ImpactPointEstimator ipEst(ipEstCfg);
0414 
0415   std::vector<double> temperatures{
0416       8., 4., 2., std::numbers::sqrt2, std::sqrt(3. / 2.), 1.};
0417   AnnealingUtility::Config annealingConfig;
0418   annealingConfig.setOfTemperatures = temperatures;
0419   AnnealingUtility annealingUtility(annealingConfig);
0420 
0421   using Fitter = AdaptiveMultiVertexFitter;
0422 
0423   Fitter::Config fitterCfg(ipEst);
0424 
0425   fitterCfg.annealingTool = annealingUtility;
0426 
0427   // Linearizer for BoundTrackParameters type test
0428   Linearizer::Config ltConfig;
0429   ltConfig.bField = bField;
0430   ltConfig.propagator = propagator;
0431   Linearizer linearizer(ltConfig);
0432 
0433   // Test smoothing
0434   fitterCfg.doSmoothing = true;
0435   fitterCfg.extractParameters.connect<&InputTrack::extractParameters>();
0436   fitterCfg.trackLinearizer.connect<&Linearizer::linearizeTrack>(&linearizer);
0437 
0438   Fitter fitter(fitterCfg);
0439 
0440   using SeedFinder = GridDensityVertexFinder;
0441   GaussianGridTrackDensity::Config gDensityConfig(250, 4000, 55);
0442   GaussianGridTrackDensity gDensity(gDensityConfig);
0443   SeedFinder::Config seedFinderCfg(gDensity);
0444   seedFinderCfg.cacheGridStateForTrackRemoval = true;
0445   seedFinderCfg.extractParameters.connect<&InputTrack::extractParameters>();
0446 
0447   auto seedFinder = std::make_shared<SeedFinder>(seedFinderCfg);
0448 
0449   AdaptiveMultiVertexFinder::Config finderConfig(
0450       std::move(fitter), std::move(seedFinder), ipEst, bField);
0451   finderConfig.extractParameters.connect<&InputTrack::extractParameters>();
0452 
0453   AdaptiveMultiVertexFinder finder(std::move(finderConfig));
0454   IVertexFinder::State state = finder.makeState(magFieldContext);
0455 
0456   auto csvData = readTracksAndVertexCSV(toolString);
0457   auto tracks = std::get<TracksData>(csvData);
0458 
0459   if (debugMode) {
0460     std::cout << "Number of tracks in event: " << tracks.size() << std::endl;
0461     int maxCout = 10;
0462     int count = 0;
0463     for (const auto& trk : tracks) {
0464       std::cout << count << ". track: " << std::endl;
0465       std::cout << "params: " << trk << std::endl;
0466       count++;
0467       if (count == maxCout) {
0468         break;
0469       }
0470     }
0471   }
0472 
0473   std::vector<InputTrack> inputTracks;
0474   for (const auto& trk : tracks) {
0475     inputTracks.emplace_back(&trk);
0476   }
0477 
0478   // TODO: test using beam spot constraint
0479   Vertex bsConstr = std::get<BeamSpotData>(csvData);
0480   VertexingOptions vertexingOptions(geoContext, magFieldContext, bsConstr);
0481 
0482   auto t1 = std::chrono::system_clock::now();
0483   auto findResult = finder.find(inputTracks, vertexingOptions, state);
0484   auto t2 = std::chrono::system_clock::now();
0485 
0486   auto timediff =
0487       std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
0488 
0489   if (!findResult.ok()) {
0490     std::cout << findResult.error().message() << std::endl;
0491   }
0492 
0493   BOOST_CHECK(findResult.ok());
0494 
0495   std::vector<Vertex> allVertices = *findResult;
0496 
0497   if (debugMode) {
0498     std::cout << "Time needed: " << timediff << " ms." << std::endl;
0499     std::cout << "Number of vertices reconstructed: " << allVertices.size()
0500               << std::endl;
0501 
0502     int count = 0;
0503     for (const auto& vtx : allVertices) {
0504       count++;
0505       std::cout << count << ". Vertex at position: " << vtx.position()[0]
0506                 << ", " << vtx.position()[1] << ", " << vtx.position()[2]
0507                 << std::endl;
0508       std::cout << count << ". Vertex with cov: " << vtx.covariance()
0509                 << std::endl;
0510       std::cout << "\t with n tracks: " << vtx.tracks().size() << std::endl;
0511     }
0512   }
0513   // Test expected outcomes from athena implementation
0514   // Number of reconstructed vertices
0515   auto verticesInfo = std::get<VerticesData>(csvData);
0516   const int expNRecoVertices = verticesInfo.size();
0517 
0518   BOOST_CHECK_EQUAL(allVertices.size(), expNRecoVertices);
0519   std::vector<bool> vtxFound(expNRecoVertices, false);
0520 
0521   for (const auto& vtx : allVertices) {
0522     double vtxZ = vtx.position()[2];
0523     double diffZ = 1e5;
0524     int foundVtxIdx = -1;
0525     for (int i = 0; i < expNRecoVertices; i++) {
0526       if (!vtxFound[i]) {
0527         if (std::abs(vtxZ - verticesInfo[i].position[2]) < diffZ) {
0528           diffZ = std::abs(vtxZ - verticesInfo[i].position[2]);
0529           foundVtxIdx = i;
0530         }
0531       }
0532     }
0533     if (diffZ < 0.5_mm) {
0534       vtxFound[foundVtxIdx] = true;
0535       CHECK_CLOSE_ABS(vtx.tracks().size(), verticesInfo[foundVtxIdx].nTracks,
0536                       1);
0537     }
0538   }
0539   for (bool found : vtxFound) {
0540     BOOST_CHECK_EQUAL(found, true);
0541   }
0542 }
0543 
0544 /// @brief AMVF test with adaptive grid seed finder
0545 BOOST_AUTO_TEST_CASE(
0546     adaptive_multi_vertex_finder_adaptive_grid_seed_finder_test) {
0547   // Set debug mode
0548   bool debugMode = false;
0549   if (debugMode) {
0550     std::cout << "Starting AMVF test with adaptive grid seed finder..."
0551               << std::endl;
0552   }
0553   // Set up constant B-Field
0554   auto bField = std::make_shared<ConstantBField>(Vector3(0., 0., 2_T));
0555 
0556   // Set up EigenStepper
0557   // EigenStepper<> stepper(bField);
0558   EigenStepper<> stepper(bField);
0559 
0560   // Set up propagator with void navigator
0561   auto propagator = std::make_shared<Propagator>(stepper);
0562 
0563   // IP Estimator
0564   ImpactPointEstimator::Config ipEstCfg(bField, propagator);
0565   ImpactPointEstimator ipEst(ipEstCfg);
0566 
0567   std::vector<double> temperatures{
0568       8., 4., 2., std::numbers::sqrt2, std::sqrt(3. / 2.), 1.};
0569   AnnealingUtility::Config annealingConfig;
0570   annealingConfig.setOfTemperatures = temperatures;
0571   AnnealingUtility annealingUtility(annealingConfig);
0572 
0573   using Fitter = AdaptiveMultiVertexFitter;
0574 
0575   Fitter::Config fitterCfg(ipEst);
0576 
0577   fitterCfg.annealingTool = annealingUtility;
0578 
0579   // Linearizer for BoundTrackParameters type test
0580   Linearizer::Config ltConfig;
0581   ltConfig.bField = bField;
0582   ltConfig.propagator = propagator;
0583   Linearizer linearizer(ltConfig);
0584 
0585   // Test smoothing
0586   fitterCfg.doSmoothing = true;
0587   fitterCfg.extractParameters.connect<&InputTrack::extractParameters>();
0588   fitterCfg.trackLinearizer.connect<&Linearizer::linearizeTrack>(&linearizer);
0589 
0590   Fitter fitter(fitterCfg);
0591 
0592   // Grid density used during vertex seed finding
0593   AdaptiveGridTrackDensity::Config gridDensityCfg;
0594   // force track to have exactly spatialTrkGridSize spatial bins for testing
0595   // purposes
0596   gridDensityCfg.spatialTrkGridSizeRange = {55, 55};
0597   gridDensityCfg.spatialBinExtent = 0.05;
0598   AdaptiveGridTrackDensity gridDensity(gridDensityCfg);
0599 
0600   using SeedFinder = AdaptiveGridDensityVertexFinder;
0601   SeedFinder::Config seedFinderCfg(gridDensity);
0602   seedFinderCfg.cacheGridStateForTrackRemoval = true;
0603   seedFinderCfg.extractParameters.connect<&InputTrack::extractParameters>();
0604 
0605   auto seedFinder = std::make_shared<SeedFinder>(seedFinderCfg);
0606 
0607   AdaptiveMultiVertexFinder::Config finderConfig(
0608       std::move(fitter), std::move(seedFinder), ipEst, bField);
0609   finderConfig.extractParameters.connect<&InputTrack::extractParameters>();
0610 
0611   AdaptiveMultiVertexFinder finder(std::move(finderConfig));
0612   IVertexFinder::State state = finder.makeState(magFieldContext);
0613 
0614   auto csvData = readTracksAndVertexCSV(toolString);
0615   auto tracks = std::get<TracksData>(csvData);
0616 
0617   if (debugMode) {
0618     std::cout << "Number of tracks in event: " << tracks.size() << std::endl;
0619     int maxCout = 10;
0620     int count = 0;
0621     for (const auto& trk : tracks) {
0622       std::cout << count << ". track: " << std::endl;
0623       std::cout << "params: " << trk << std::endl;
0624       count++;
0625       if (count == maxCout) {
0626         break;
0627       }
0628     }
0629   }
0630 
0631   std::vector<InputTrack> inputTracks;
0632   for (const auto& trk : tracks) {
0633     inputTracks.emplace_back(&trk);
0634   }
0635 
0636   Vertex bsConstr = std::get<BeamSpotData>(csvData);
0637   VertexingOptions vertexingOptions(geoContext, magFieldContext, bsConstr);
0638 
0639   auto t1 = std::chrono::system_clock::now();
0640   auto findResult = finder.find(inputTracks, vertexingOptions, state);
0641   auto t2 = std::chrono::system_clock::now();
0642 
0643   auto timediff =
0644       std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
0645 
0646   if (!findResult.ok()) {
0647     std::cout << findResult.error().message() << std::endl;
0648   }
0649 
0650   BOOST_CHECK(findResult.ok());
0651 
0652   std::vector<Vertex> allVertices = *findResult;
0653 
0654   if (debugMode) {
0655     std::cout << "Time needed: " << timediff << " ms." << std::endl;
0656     std::cout << "Number of vertices reconstructed: " << allVertices.size()
0657               << std::endl;
0658 
0659     int count = 0;
0660     for (const auto& vtx : allVertices) {
0661       count++;
0662       std::cout << count << ". Vertex at position: " << vtx.position()[0]
0663                 << ", " << vtx.position()[1] << ", " << vtx.position()[2]
0664                 << std::endl;
0665       std::cout << count << ". Vertex with cov: " << vtx.covariance()
0666                 << std::endl;
0667       std::cout << "\t with n tracks: " << vtx.tracks().size() << std::endl;
0668     }
0669   }
0670   // Test expected outcomes from athena implementation
0671   // Number of reconstructed vertices
0672   auto verticesInfo = std::get<VerticesData>(csvData);
0673   const int expNRecoVertices = verticesInfo.size();
0674 
0675   BOOST_CHECK_EQUAL(allVertices.size(), expNRecoVertices);
0676   std::vector<bool> vtxFound(expNRecoVertices, false);
0677 
0678   for (const auto& vtx : allVertices) {
0679     double vtxZ = vtx.position()[2];
0680     double diffZ = 1e5;
0681     int foundVtxIdx = -1;
0682     for (int i = 0; i < expNRecoVertices; i++) {
0683       if (!vtxFound[i]) {
0684         if (std::abs(vtxZ - verticesInfo[i].position[2]) < diffZ) {
0685           diffZ = std::abs(vtxZ - verticesInfo[i].position[2]);
0686           foundVtxIdx = i;
0687         }
0688       }
0689     }
0690     if (diffZ < 0.5_mm) {
0691       vtxFound[foundVtxIdx] = true;
0692       CHECK_CLOSE_ABS(vtx.tracks().size(), verticesInfo[foundVtxIdx].nTracks,
0693                       2);
0694     }
0695   }
0696   for (bool found : vtxFound) {
0697     BOOST_CHECK_EQUAL(found, true);
0698   }
0699 }
0700 
0701 BOOST_AUTO_TEST_CASE(adaptive_multi_vertex_finder_removes_rejected_seed) {
0702   auto bField = std::make_shared<ConstantBField>(Vector3(0., 0., 2_T));
0703 
0704   EigenStepper<> stepper(bField);
0705   auto propagator = std::make_shared<Propagator>(stepper);
0706 
0707   ImpactPointEstimator::Config ipEstCfg(bField, propagator);
0708   ImpactPointEstimator ipEst(ipEstCfg);
0709 
0710   std::vector<double> temperatures{
0711       8., 4., 2., std::numbers::sqrt2, std::sqrt(3. / 2.), 1.};
0712   AnnealingUtility::Config annealingConfig;
0713   annealingConfig.setOfTemperatures = temperatures;
0714   AnnealingUtility annealingUtility(annealingConfig);
0715 
0716   using Fitter = AdaptiveMultiVertexFitter;
0717 
0718   Fitter::Config fitterCfg(ipEst);
0719   fitterCfg.annealingTool = annealingUtility;
0720 
0721   Linearizer::Config ltConfig;
0722   ltConfig.bField = bField;
0723   ltConfig.propagator = propagator;
0724   Linearizer linearizer(ltConfig);
0725 
0726   fitterCfg.doSmoothing = true;
0727   fitterCfg.extractParameters.connect<&InputTrack::extractParameters>();
0728   fitterCfg.trackLinearizer.connect<&Linearizer::linearizeTrack>(&linearizer);
0729 
0730   Fitter fitter(fitterCfg);
0731 
0732   auto csvData = readTracksAndVertexCSV(toolString);
0733   auto tracks = std::get<TracksData>(csvData);
0734   auto verticesInfo = std::get<VerticesData>(csvData);
0735   BOOST_REQUIRE_GE(verticesInfo.size(), 2u);
0736 
0737   std::vector<Vertex> seeds;
0738   seeds.emplace_back(verticesInfo[0].position);
0739   seeds.back().setCovariance(verticesInfo[0].covariance);
0740   seeds.emplace_back(verticesInfo[1].position);
0741   seeds.back().setCovariance(verticesInfo[1].covariance);
0742 
0743   auto seedFinder = std::make_shared<FixedVertexSeedFinder>(std::move(seeds));
0744 
0745   AdaptiveMultiVertexFinder::Config finderConfig(
0746       std::move(fitter), std::move(seedFinder), ipEst, bField);
0747   finderConfig.extractParameters.connect<&InputTrack::extractParameters>();
0748   finderConfig.maxMergeVertexSignificance = 1e9;
0749   finderConfig.maxIterations = 1;
0750 
0751   AdaptiveMultiVertexFinder finder(std::move(finderConfig));
0752   IVertexFinder::State state = finder.makeState(magFieldContext);
0753 
0754   std::vector<InputTrack> inputTracks;
0755   for (const auto& trk : tracks) {
0756     inputTracks.emplace_back(&trk);
0757   }
0758 
0759   VertexingOptions vertexingOptions(geoContext, magFieldContext,
0760                                     std::get<BeamSpotData>(csvData));
0761 
0762   auto findResult = finder.find(inputTracks, vertexingOptions, state);
0763 
0764   if (!findResult.ok()) {
0765     std::cout << findResult.error().message() << std::endl;
0766   }
0767 
0768   BOOST_REQUIRE(findResult.ok());
0769 
0770   std::vector<Vertex> allVertices = *findResult;
0771   BOOST_CHECK_EQUAL(allVertices.size(), 1u);
0772   BOOST_CHECK_GT(allVertices.front().tracks().size(), 1u);
0773 }
0774 
0775 BOOST_AUTO_TEST_SUITE_END()
0776 
0777 }  // namespace ActsTests