EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
IterativeVertexFinderTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file IterativeVertexFinderTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #include <boost/test/data/test_case.hpp>
10 #include <boost/test/tools/output_test_stream.hpp>
11 #include <boost/test/unit_test.hpp>
12 
21 #include "Acts/Utilities/Units.hpp"
29 
30 #include "VertexingDataHelper.hpp"
31 
32 namespace bdata = boost::unit_test::data;
33 using namespace Acts::UnitLiterals;
34 
35 namespace Acts {
36 namespace Test {
37 
39 using Propagator = Propagator<EigenStepper<ConstantBField>>;
40 using Linearizer = HelicalTrackLinearizer<Propagator>;
41 
42 // Create a test context
45 
46 const std::string toolString = "IVF";
47 
48 // Vertex x/y position distribution
49 std::uniform_real_distribution<> vXYDist(-0.1_mm, 0.1_mm);
50 // Vertex z position distribution
51 std::uniform_real_distribution<> vZDist(-20_mm, 20_mm);
52 // Track d0 distribution
53 std::uniform_real_distribution<> d0Dist(-0.01_mm, 0.01_mm);
54 // Track z0 distribution
55 std::uniform_real_distribution<> z0Dist(-0.2_mm, 0.2_mm);
56 // Track pT distribution
57 std::uniform_real_distribution<> pTDist(0.4_GeV, 10_GeV);
58 // Track phi distribution
59 std::uniform_real_distribution<> phiDist(-M_PI, M_PI);
60 // Track theta distribution
61 std::uniform_real_distribution<> thetaDist(1.0, M_PI - 1.0);
62 // Track charge helper distribution
63 std::uniform_real_distribution<> qDist(-1, 1);
64 // Track IP resolution distribution
65 std::uniform_real_distribution<> resIPDist(0., 100_um);
66 // Track angular distribution
67 std::uniform_real_distribution<> resAngDist(0., 0.1);
68 // Track q/p resolution distribution
69 std::uniform_real_distribution<> resQoPDist(-0.01, 0.01);
70 // Number of vertices per test event distribution
71 std::uniform_int_distribution<> nVertexDist(1, 6);
72 // Number of tracks per vertex distribution
73 std::uniform_int_distribution<> nTracksDist(5, 15);
74 
75 // Dummy user-defined InputTrack type
76 struct InputTrack {
77  InputTrack(const BoundTrackParameters& params) : m_parameters(params) {}
78 
79  const BoundTrackParameters& parameters() const { return m_parameters; }
80 
81  // store e.g. link to original objects here
82 
83  private:
84  BoundTrackParameters m_parameters;
85 };
86 
90 BOOST_AUTO_TEST_CASE(iterative_finder_test) {
91  bool debug = false;
92 
93  // Set up RNG
94  int mySeed = 31415;
95  std::mt19937 gen(mySeed);
96 
97  // Number of test events
98  unsigned int nEvents = 5; // = nTest
99 
100  for (unsigned int iEvent = 0; iEvent < nEvents; ++iEvent) {
101  // Set up constant B-Field
102  ConstantBField bField(0.0, 0.0, 1_T);
103 
104  // Set up Eigenstepper
106 
107  // Set up propagator with void navigator
108  auto propagator = std::make_shared<Propagator>(stepper);
109 
110  // Linearizer for BoundTrackParameters type test
111  Linearizer::Config ltConfig(bField, propagator);
112  Linearizer linearizer(ltConfig);
113 
114  using BilloirFitter =
116 
117  // Set up Billoir Vertex Fitter
118  BilloirFitter::Config vertexFitterCfg;
119 
120  BilloirFitter bFitter(vertexFitterCfg);
121 
122  // Impact point estimator
124 
125  IPEstimator::Config ipEstimatorCfg(bField, propagator);
126  IPEstimator ipEstimator(ipEstimatorCfg);
127 
128  using ZScanSeedFinder = ZScanVertexFinder<BilloirFitter>;
129 
130  static_assert(VertexFinderConcept<ZScanSeedFinder>,
131  "Vertex finder does not fulfill vertex finder concept.");
132 
133  ZScanSeedFinder::Config seedFinderCfg(ipEstimator);
134 
135  ZScanSeedFinder sFinder(seedFinderCfg);
136 
137  // Vertex Finder
139 
140  static_assert(VertexFinderConcept<VertexFinder>,
141  "Vertex finder does not fulfill vertex finder concept.");
142 
143  VertexFinder::Config cfg(bFitter, linearizer, std::move(sFinder),
144  ipEstimator);
145 
146  cfg.reassignTracksAfterFirstFit = true;
147 
148  VertexFinder finder(cfg);
149  VertexFinder::State state(magFieldContext);
150 
151  // Vector to be filled with all tracks in current event
152  std::vector<std::unique_ptr<const BoundTrackParameters>> tracks;
153 
154  std::vector<const BoundTrackParameters*> tracksPtr;
155 
156  // Vector to be filled with truth vertices for later comparison
157  std::vector<Vertex<BoundTrackParameters>> trueVertices;
158 
159  // start creating event with nVertices vertices
160  unsigned int nVertices = nVertexDist(gen);
161  for (unsigned int iVertex = 0; iVertex < nVertices; ++iVertex) {
162  // Number of tracks
163  unsigned int nTracks = nTracksDist(gen);
164 
165  if (debug) {
166  std::cout << "Event " << iEvent << ", Vertex " << iVertex << "/"
167  << nVertices << " with " << nTracks << " tracks."
168  << std::endl;
169  }
170  // Create perigee surface
171  std::shared_ptr<PerigeeSurface> perigeeSurface =
172  Surface::makeShared<PerigeeSurface>(Vector3D(0., 0., 0.));
173 
174  // Create position of vertex and perigee surface
175  double x = vXYDist(gen);
176  double y = vXYDist(gen);
177  double z = vZDist(gen);
178 
179  // True vertex
180  Vertex<BoundTrackParameters> trueV(Vector3D(x, y, z));
181  std::vector<TrackAtVertex<BoundTrackParameters>> tracksAtTrueVtx;
182 
183  // Calculate d0 and z0 corresponding to vertex position
184  double d0_v = sqrt(x * x + y * y);
185  double z0_v = z;
186 
187  // Construct random track emerging from vicinity of vertex position
188  // Vector to store track objects used for vertex fit
189  for (unsigned int iTrack = 0; iTrack < nTracks; iTrack++) {
190  // Construct positive or negative charge randomly
191  double q = qDist(gen) < 0 ? -1. : 1.;
192 
193  // Construct random track parameters
194  BoundVector paramVec;
195  double z0track = z0_v + z0Dist(gen);
196  paramVec << d0_v + d0Dist(gen), z0track, phiDist(gen), thetaDist(gen),
197  q / pTDist(gen), 0.;
198 
199  // Resolutions
200  double res_d0 = resIPDist(gen);
201  double res_z0 = resIPDist(gen);
202  double res_ph = resAngDist(gen);
203  double res_th = resAngDist(gen);
204  double res_qp = resQoPDist(gen);
205 
206  // Fill vector of track objects with simple covariance matrix
207  Covariance covMat;
208  covMat << res_d0 * res_d0, 0., 0., 0., 0., 0., 0., res_z0 * res_z0, 0.,
209  0., 0., 0., 0., 0., res_ph * res_ph, 0., 0., 0., 0., 0., 0.,
210  res_th * res_th, 0., 0., 0., 0., 0., 0., res_qp * res_qp, 0., 0.,
211  0., 0., 0., 0., 1.;
212  auto params =
213  BoundTrackParameters(perigeeSurface, paramVec, std::move(covMat));
214 
215  tracks.push_back(std::make_unique<BoundTrackParameters>(params));
216 
217  TrackAtVertex<BoundTrackParameters> trAtVt(0., params,
218  tracks.back().get());
219  tracksAtTrueVtx.push_back(trAtVt);
220  }
221 
222  trueV.setTracksAtVertex(tracksAtTrueVtx);
223  trueVertices.push_back(trueV);
224 
225  } // end loop over vertices
226 
227  // shuffle list of tracks
228  std::shuffle(std::begin(tracks), std::end(tracks), gen);
229 
230  for (const auto& trk : tracks) {
231  tracksPtr.push_back(trk.get());
232  }
233 
236 
237  // find vertices
238  auto res = finder.find(tracksPtr, vertexingOptions, state);
239 
240  BOOST_CHECK(res.ok());
241 
242  if (!res.ok()) {
243  std::cout << res.error().message() << std::endl;
244  }
245 
246  // Retrieve vertices found by vertex finder
247  auto vertexCollection = *res;
248 
249  // check if same amount of vertices has been found with tolerance of 2
250  CHECK_CLOSE_ABS(vertexCollection.size(), nVertices, 2);
251 
252  if (debug) {
253  std::cout << "########## RESULT: ########## Event " << iEvent
254  << std::endl;
255  std::cout << "Number of true vertices: " << nVertices << std::endl;
256  std::cout << "Number of reco vertices: " << vertexCollection.size()
257  << std::endl;
258 
259  int count = 1;
260  std::cout << "----- True vertices -----" << std::endl;
261  for (const auto& vertex : trueVertices) {
262  Vector3D pos = vertex.position();
263  std::cout << count << ". True Vertex:\t Position:"
264  << "(" << pos[eX] << "," << pos[eY] << "," << pos[eZ] << ")"
265  << std::endl;
266  std::cout << "Number of tracks: " << vertex.tracks().size() << std::endl
267  << std::endl;
268  count++;
269  }
270  std::cout << "----- Reco vertices -----" << std::endl;
271  count = 1;
272  for (const auto& vertex : vertexCollection) {
273  Vector3D pos = vertex.position();
274  std::cout << count << ". Reco Vertex:\t Position:"
275  << "(" << pos[eX] << "," << pos[eY] << "," << pos[eZ] << ")"
276  << std::endl;
277  std::cout << "Number of tracks: " << vertex.tracks().size() << std::endl
278  << std::endl;
279  count++;
280  }
281  }
282 
283  // Check if all vertices have been found with close z-values
284  bool allVerticesFound = true;
285  for (const auto& trueVertex : trueVertices) {
286  Vector4D truePos = trueVertex.fullPosition();
287  bool currentVertexFound = false;
288  for (const auto& recoVertex : vertexCollection) {
289  Vector4D recoPos = recoVertex.fullPosition();
290  // check only for close z distance
291  double zDistance = std::abs(truePos[eZ] - recoPos[eZ]);
292  if (zDistance < 2_mm) {
293  currentVertexFound = true;
294  }
295  }
296  if (!currentVertexFound) {
297  allVerticesFound = false;
298  }
299  }
300 
301  // check if found vertices have compatible z values
302  BOOST_CHECK(allVerticesFound);
303  }
304 }
305 
310 BOOST_AUTO_TEST_CASE(iterative_finder_test_user_track_type) {
311  bool debug = false;
312 
313  // Set up RNG
314  int mySeed = 31415;
315  std::mt19937 gen(mySeed);
316 
317  // Number of test events
318  unsigned int nEvents = 5; // = nTest
319 
320  for (unsigned int iEvent = 0; iEvent < nEvents; ++iEvent) {
321  // Set up constant B-Field
322  ConstantBField bField(0.0, 0.0, 1_T);
323 
324  // Set up Eigenstepper
326 
327  // Set up propagator with void navigator
328  auto propagator = std::make_shared<Propagator>(stepper);
329 
330  // Linearizer for user defined InputTrack type test
331  Linearizer::Config ltConfigUT(bField, propagator);
332  Linearizer linearizer(ltConfigUT);
333 
334  // Set up vertex fitter for user track type
336 
337  // Create a custom std::function to extract BoundTrackParameters from
338  // user-defined InputTrack
339  std::function<BoundTrackParameters(InputTrack)> extractParameters =
340  [](InputTrack params) { return params.parameters(); };
341 
342  // Set up Billoir Vertex Fitter
343  BilloirFitter::Config vertexFitterCfg;
344 
345  BilloirFitter bFitter(vertexFitterCfg, extractParameters);
346 
347  // IP Estimator
349 
350  IPEstimator::Config ipEstimatorCfg(bField, propagator);
351  IPEstimator ipEstimator(ipEstimatorCfg);
352 
353  using ZScanSeedFinder = ZScanVertexFinder<BilloirFitter>;
354  ZScanSeedFinder::Config seedFinderCfg(ipEstimator);
355 
356  ZScanSeedFinder sFinder(seedFinderCfg, extractParameters);
357 
358  // Vertex Finder
360  VertexFinder::Config cfg(bFitter, linearizer, std::move(sFinder),
361  ipEstimator);
362  cfg.reassignTracksAfterFirstFit = true;
363 
364  VertexFinder finder(cfg, extractParameters);
365  VertexFinder::State state(magFieldContext);
366 
367  // Same for user track type tracks
368  std::vector<std::unique_ptr<const InputTrack>> tracks;
369 
370  std::vector<const InputTrack*> tracksPtr;
371 
372  // Vector to be filled with truth vertices for later comparison
373  std::vector<Vertex<InputTrack>> trueVertices;
374 
375  // start creating event with nVertices vertices
376  unsigned int nVertices = nVertexDist(gen);
377  for (unsigned int iVertex = 0; iVertex < nVertices; ++iVertex) {
378  // Number of tracks
379  unsigned int nTracks = nTracksDist(gen);
380 
381  if (debug) {
382  std::cout << "Event " << iEvent << ", Vertex " << iVertex << "/"
383  << nVertices << " with " << nTracks << " tracks."
384  << std::endl;
385  }
386  // Create perigee surface
387  std::shared_ptr<PerigeeSurface> perigeeSurface =
388  Surface::makeShared<PerigeeSurface>(Vector3D(0., 0., 0.));
389 
390  // Create position of vertex and perigee surface
391  double x = vXYDist(gen);
392  double y = vXYDist(gen);
393  double z = vZDist(gen);
394 
395  // True vertex
396  Vertex<InputTrack> trueV(Vector3D(x, y, z));
397  std::vector<TrackAtVertex<InputTrack>> tracksAtTrueVtx;
398 
399  // Calculate d0 and z0 corresponding to vertex position
400  double d0_v = sqrt(x * x + y * y);
401  double z0_v = z;
402 
403  // Construct random track emerging from vicinity of vertex position
404  // Vector to store track objects used for vertex fit
405  for (unsigned int iTrack = 0; iTrack < nTracks; iTrack++) {
406  // Construct positive or negative charge randomly
407  double q = qDist(gen) < 0 ? -1. : 1.;
408 
409  // Construct random track parameters
410  BoundVector paramVec;
411  double z0track = z0_v + z0Dist(gen);
412  paramVec << d0_v + d0Dist(gen), z0track, phiDist(gen), thetaDist(gen),
413  q / pTDist(gen), 0.;
414 
415  // Resolutions
416  double res_d0 = resIPDist(gen);
417  double res_z0 = resIPDist(gen);
418  double res_ph = resAngDist(gen);
419  double res_th = resAngDist(gen);
420  double res_qp = resQoPDist(gen);
421 
422  // Fill vector of track objects now for user track type
423  Covariance covMat;
424 
425  covMat << res_d0 * res_d0, 0., 0., 0., 0., 0., 0., res_z0 * res_z0, 0.,
426  0., 0., 0., 0., 0., res_ph * res_ph, 0., 0., 0., 0., 0., 0.,
427  res_th * res_th, 0., 0., 0., 0., 0., 0., res_qp * res_qp, 0., 0.,
428  0., 0., 0., 0., 1.;
429  auto paramsUT = InputTrack(
430  BoundTrackParameters(perigeeSurface, paramVec, std::move(covMat)));
431 
432  tracks.push_back(std::make_unique<InputTrack>(paramsUT));
433 
434  auto params = extractParameters(paramsUT);
435 
436  TrackAtVertex<InputTrack> trAtVt(0., params, tracks.back().get());
437  tracksAtTrueVtx.push_back(trAtVt);
438  }
439 
440  trueV.setTracksAtVertex(tracksAtTrueVtx);
441  trueVertices.push_back(trueV);
442 
443  } // end loop over vertices
444 
445  // shuffle list of tracks
446  std::shuffle(std::begin(tracks), std::end(tracks), gen);
447 
448  for (const auto& trk : tracks) {
449  tracksPtr.push_back(trk.get());
450  }
451 
452  VertexingOptions<InputTrack> vertexingOptionsUT(geoContext,
454 
455  // find vertices
456  auto res = finder.find(tracksPtr, vertexingOptionsUT, state);
457 
458  BOOST_CHECK(res.ok());
459 
460  if (!res.ok()) {
461  std::cout << res.error().message() << std::endl;
462  }
463 
464  // Retrieve vertices found by vertex finder
465  auto vertexCollectionUT = *res;
466 
467  // check if same amount of vertices has been found with tolerance of 2
468  CHECK_CLOSE_ABS(vertexCollectionUT.size(), nVertices, 2);
469 
470  if (debug) {
471  std::cout << "########## RESULT: ########## Event " << iEvent
472  << std::endl;
473  std::cout << "Number of true vertices: " << nVertices << std::endl;
474  std::cout << "Number of reco vertices: " << vertexCollectionUT.size()
475  << std::endl;
476 
477  int count = 1;
478  std::cout << "----- True vertices -----" << std::endl;
479  for (const auto& vertex : trueVertices) {
480  Vector3D pos = vertex.position();
481  std::cout << count << ". True Vertex:\t Position:"
482  << "(" << pos[eX] << "," << pos[eY] << "," << pos[eZ] << ")"
483  << std::endl;
484  std::cout << "Number of tracks: " << vertex.tracks().size() << std::endl
485  << std::endl;
486  count++;
487  }
488  std::cout << "----- Reco vertices -----" << std::endl;
489  count = 1;
490  for (const auto& vertex : vertexCollectionUT) {
491  Vector3D pos = vertex.position();
492  std::cout << count << ". Reco Vertex:\t Position:"
493  << "(" << pos[eX] << "," << pos[eY] << "," << pos[eZ] << ")"
494  << std::endl;
495  std::cout << "Number of tracks: " << vertex.tracks().size() << std::endl
496  << std::endl;
497  count++;
498  }
499  }
500 
501  // Check if all vertices have been found with close z-values
502  bool allVerticesFound = true;
503  for (const auto& trueVertex : trueVertices) {
504  Vector4D truePos = trueVertex.fullPosition();
505  bool currentVertexFound = false;
506  for (const auto& recoVertex : vertexCollectionUT) {
507  Vector4D recoPos = recoVertex.fullPosition();
508  // check only for close z distance
509  double zDistance = std::abs(truePos[eZ] - recoPos[eZ]);
510  if (zDistance < 2_mm) {
511  currentVertexFound = true;
512  }
513  }
514  if (!currentVertexFound) {
515  allVerticesFound = false;
516  }
517  }
518 
519  // check if found vertices have compatible z values
520  BOOST_CHECK(allVerticesFound);
521  }
522 }
523 
527 BOOST_AUTO_TEST_CASE(iterative_finder_test_athena_reference) {
528  // Set up constant B-Field
529  ConstantBField bField(0.0, 0.0, 2_T);
530 
531  // Set up Eigenstepper
533 
534  // Set up propagator with void navigator
535  auto propagator = std::make_shared<Propagator>(stepper);
536 
537  // Linearizer for BoundTrackParameters type test
538  Linearizer::Config ltConfig(bField, propagator);
539  Linearizer linearizer(ltConfig);
540 
541  using BilloirFitter =
543 
544  // Set up Billoir Vertex Fitter
545  BilloirFitter::Config vertexFitterCfg;
546 
547  BilloirFitter bFitter(vertexFitterCfg);
548 
549  // Impact point estimator
551 
552  IPEstimator::Config ipEstimatorCfg(bField, propagator);
553  IPEstimator ipEstimator(ipEstimatorCfg);
554 
555  using ZScanSeedFinder = ZScanVertexFinder<BilloirFitter>;
556 
557  static_assert(VertexFinderConcept<ZScanSeedFinder>,
558  "Vertex finder does not fulfill vertex finder concept.");
559 
560  ZScanSeedFinder::Config seedFinderCfg(ipEstimator);
561 
562  ZScanSeedFinder sFinder(seedFinderCfg);
563 
564  // Vertex Finder
566 
567  static_assert(VertexFinderConcept<VertexFinder>,
568  "Vertex finder does not fulfill vertex finder concept.");
569 
570  VertexFinder::Config cfg(bFitter, linearizer, std::move(sFinder),
571  ipEstimator);
572 
573  cfg.useBeamConstraint = true;
574  cfg.maxVertices = 200;
575  cfg.maximumChi2cutForSeeding = 49;
576  cfg.significanceCutSeeding = 12;
577 
578  VertexFinder finder(cfg);
579  VertexFinder::State state(magFieldContext);
580 
581  auto csvData = readTracksAndVertexCSV(toolString);
582  auto tracks = std::get<TracksData>(csvData);
583 
584  std::vector<const BoundTrackParameters*> tracksPtr;
585  for (const auto& trk : tracks) {
586  tracksPtr.push_back(&trk);
587  }
588 
591 
592  vertexingOptions.vertexConstraint = std::get<BeamSpotData>(csvData);
593 
594  // find vertices
595  auto findResult = finder.find(tracksPtr, vertexingOptions, state);
596 
597  // BOOST_CHECK(findResult.ok());
598 
599  if (!findResult.ok()) {
600  std::cout << findResult.error().message() << std::endl;
601  }
602 
603  // Retrieve vertices found by vertex finder
604  // std::vector<Vertex<BoundTrackParameters>> allVertices = *findResult;
605 
606  // Test expected outcomes from athena implementation
607  // Number of reconstructed vertices
608  // auto verticesInfo = std::get<VerticesData>(csvData);
609  // const int expNRecoVertices = verticesInfo.size();
610 
611  // BOOST_CHECK_EQUAL(allVertices.size(), expNRecoVertices);
612  // for (int i = 0; i < expNRecoVertices; i++) {
613  // auto recoVtx = allVertices[i];
614  // auto expVtx = verticesInfo[i];
615  // CHECK_CLOSE_ABS(recoVtx.position(), expVtx.position, 0.001_mm);
616  // CHECK_CLOSE_ABS(recoVtx.covariance(), expVtx.covariance, 0.001_mm);
617  // BOOST_CHECK_EQUAL(recoVtx.tracks().size(), expVtx.nTracks);
618  // CHECK_CLOSE_ABS(recoVtx.tracks()[0].trackWeight, expVtx.trk1Weight,
619  // 0.003); CHECK_CLOSE_ABS(recoVtx.tracks()[0].vertexCompatibility,
620  // expVtx.trk1Comp,
621  // 0.003);
622  // }
623 }
624 
625 } // namespace Test
626 } // namespace Acts