Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AdaptiveGridTrackDensityTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file AdaptiveGridTrackDensityTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2020-2023 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 
24 
25 #include <algorithm>
26 #include <iterator>
27 #include <memory>
28 #include <optional>
29 #include <utility>
30 #include <vector>
31 
32 namespace bdata = boost::unit_test::data;
33 using namespace Acts::UnitLiterals;
34 
35 namespace Acts {
36 namespace Test {
37 
39 
41  std::srand(seed);
42  Covariance randMat((Covariance::Random() + 1.5 * Covariance::Identity()) *
43  0.05);
44 
45  // symmetric covariance matrix
46  Covariance covMat = 0.5 * (randMat + randMat.transpose());
47 
48  return covMat;
49 }
50 
51 BOOST_AUTO_TEST_CASE(compare_to_analytical_solution_for_single_track) {
52  using Vector2 = Eigen::Matrix<float, 2, 1>;
53  using Matrix2 = Eigen::Matrix<float, 2, 2>;
54  // Using a large track grid so we can choose a small bin size
55  const int spatialTrkGridSize = 4001;
56  // Arbitrary (but small) bin size
57  const float binExtent = 3.1e-4;
58  // Arbitrary impact parameters
59  const float d0 = 0.4;
60  const float z0 = -0.2;
61  Vector2 impactParameters{d0, z0};
62 
64  Matrix2 subCovMat = covMat.block<2, 2>(0, 0).cast<float>();
65  BoundVector paramVec;
66  paramVec << d0, z0, 0, 0, 0, 0;
67 
68  // Create perigee surface
69  std::shared_ptr<PerigeeSurface> perigeeSurface =
70  Surface::makeShared<PerigeeSurface>(Vector3(0., 0., 0.));
71 
72  BoundTrackParameters params1(perigeeSurface, paramVec, covMat,
74 
77 
78  // Empty map
80 
81  // Add track
82  auto trackDensityMap = grid.addTrack(params1, mainDensityMap);
83 
84  float relTol = 1e-5;
85  float small = 1e-5;
86 
87  auto gaussian2D = [&](const Vector2& args, const Vector2& mus,
88  const Matrix2& sigmas) {
89  Vector2 diffs = args - mus;
90  float coef = 1 / std::sqrt(sigmas.determinant());
91  float expo = -0.5 * diffs.transpose().dot(sigmas.inverse() * diffs);
92  return coef * std::exp(expo);
93  };
94 
95  for (auto const& it : mainDensityMap) {
96  // Extract variables for better readability
97  int zBin = it.first.first;
98  float density = it.second;
99  // Argument for 2D gaussian
100  Vector2 dzVec{0., grid.getBinCenter(zBin, binExtent)};
101  // Compute correct density...
102  float correctDensity = gaussian2D(dzVec, impactParameters, subCovMat);
103  // ... and check if our result is equivalent
104  CHECK_CLOSE_OR_SMALL(density, correctDensity, relTol, small);
105  }
106 
107  // Analytical maximum of the Gaussian (can be obtained by expressing the
108  // exponent as (az - b)^2 + c and noting correctMaxZ = b/a)
109  float correctMaxZ =
110  -0.5 * (subCovMat(0, 1) + subCovMat(1, 0)) / subCovMat(0, 0) * d0 + z0;
111  // Analytical FWHM of the Gaussian (result similar to
112  // https://en.wikipedia.org/wiki/Full_width_at_half_maximum#Normal_distribution
113  // but the calculation needs to be slightly modified in our case)
114  float correctFWHM = 2. * std::sqrt(2 * std::log(2.) *
115  subCovMat.determinant() / subCovMat(0, 0));
116 
117  // Estimate maximum z position and seed width
118  auto res = grid.getMaxZTPositionAndWidth(mainDensityMap);
119  BOOST_CHECK(res.ok());
120 
121  // Extract variables for better readability...
122  float maxZ = res.value().first.first;
123  float fwhm = res.value().second * 2.355f;
124 
125  // ... and check if they are correct (note: the optimization is not as exact
126  // as the density values).
127  float relTolOptimization = 1e-3;
128  CHECK_CLOSE_REL(maxZ, correctMaxZ, relTolOptimization);
129  CHECK_CLOSE_REL(fwhm, correctFWHM, relTolOptimization);
130 }
131 
133  compare_to_analytical_solution_for_single_track_with_time) {
134  // Number of bins in z- and t-direction
135  const int spatialTrkGridSize = 401;
136  const int temporalTrkGridSize = 401;
137  // Bin extents
138  const float spatialBinExtent = 3.1e-3;
139  const float temporalBinExtent = 3.1e-3;
140  // Arbitrary impact parameters
141  const float d0 = -0.1;
142  const float z0 = -0.2;
143  const float t0 = 0.1;
144  Vector3 impactParameters{d0, z0, t0};
145 
146  // symmetric covariance matrix
147  Covariance covMat = makeRandomCovariance();
148 
149  BoundVector paramVec;
150  paramVec << d0, z0, 0, 0, 0, t0;
151  // Create perigee surface
152  std::shared_ptr<PerigeeSurface> perigeeSurface =
153  Surface::makeShared<PerigeeSurface>(Vector3(0., 0., 0.));
154 
155  BoundTrackParameters params(perigeeSurface, paramVec, covMat,
157 
158  ActsSquareMatrix<3> ipCov = params.impactParameterCovariance().value();
159 
161  spatialBinExtent, temporalBinExtent);
163 
164  // Empty map
166  mainDensityMap;
167 
168  // Add track
169  auto trackDensityMap = grid.addTrack(params, mainDensityMap);
170 
171  float relTol = 1e-5;
172  float small = 1e-5;
173 
174  auto gaussian3D = [&](const Vector3& args, const Vector3& mus,
175  const SquareMatrix3& sigmas) {
176  Vector3 diffs = args - mus;
177  float coef = 1 / std::sqrt(sigmas.determinant());
178  float expo = -0.5 * diffs.transpose().dot(sigmas.inverse() * diffs);
179  return coef * std::exp(expo);
180  };
181 
182  for (auto const& it : mainDensityMap) {
183  // Extract variables for better readability
184  float z = grid.getBinCenter(it.first.first, spatialBinExtent);
185  float t = grid.getBinCenter(it.first.second, temporalBinExtent);
186  float density = it.second;
187  // Argument for 3D gaussian
188  Vector3 dztVec{0., z, t};
189 
190  // Compute correct density...
191  float correctDensity = gaussian3D(dztVec, impactParameters, ipCov);
192 
193  // ... and check if our result is equivalent
194  CHECK_CLOSE_OR_SMALL(density, correctDensity, relTol, small);
195  }
196 
197  // The analytical calculations of the following can be found here:
198  // https://github.com/acts-project/acts/pull/2460.
199  // TODO: upload reference at a better place.
200  // Analytical maximum of the Gaussian
201  ActsSquareMatrix<3> ipWeights = ipCov.inverse();
202  ActsScalar denom =
203  ipWeights(1, 1) * ipWeights(2, 2) - ipWeights(1, 2) * ipWeights(1, 2);
204 
205  ActsScalar zNom =
206  ipWeights(0, 1) * ipWeights(2, 2) - ipWeights(0, 2) * ipWeights(1, 2);
207  ActsScalar correctMaxZ = zNom / denom * d0 + z0;
208 
209  ActsScalar tNom =
210  ipWeights(0, 2) * ipWeights(1, 1) - ipWeights(0, 1) * ipWeights(1, 2);
211  ActsScalar correctMaxT = tNom / denom * d0 + t0;
212 
213  // Analytical FWHM of the Gaussian
214  ActsScalar correctFWHM = 2. * std::sqrt(2 * std::log(2.) / ipWeights(1, 1));
215 
216  // Estimate maximum z position and seed width
217  auto res = grid.getMaxZTPositionAndWidth(mainDensityMap);
218  BOOST_CHECK(res.ok());
219 
220  // Extract variables for better readability...
221  float maxZ = res.value().first.first;
222  float maxT = res.value().first.second;
223  float fwhm = res.value().second * 2.355f;
224 
225  // ... and check if they are correct (note: the optimization is not as exact
226  // as the density values).
227  float relTolOptimization = 1e-1;
228  CHECK_CLOSE_REL(maxZ, correctMaxZ, relTolOptimization);
229  CHECK_CLOSE_REL(maxT, correctMaxT, relTolOptimization);
230  CHECK_CLOSE_REL(fwhm, correctFWHM, relTolOptimization);
231 }
232 
233 BOOST_AUTO_TEST_CASE(seed_width_estimation) {
234  // Dummy track grid size (not needed for this unit test)
235  const int spatialTrkGridSize = 1;
236  float binExtent = 2.;
239 
240  // Empty map
242 
243  // z-position of the maximum density
244  float correctMaxZ = -2.;
245 
246  // Fill map with a triangular track density.
247  // We use an isoscele triangle with a maximum density value of 1 and a width
248  // of 20 mm. The linear approximation we use during the seed width estimation
249  // should be exact in this case.
250  for (int i = -6; i <= 4; i++) {
251  mainDensityMap[std::make_pair(i, 0)] =
252  1.0 - 0.1 * std::abs(correctMaxZ - grid.getBinCenter(i, binExtent));
253  }
254 
255  // Get maximum z position and corresponding seed width
256  auto res = grid.getMaxZTPositionAndWidth(mainDensityMap);
257  BOOST_CHECK(res.ok());
258 
259  // Check if we found the correct maximum
260  float maxZ = res.value().first.first;
261  BOOST_CHECK_EQUAL(maxZ, correctMaxZ);
262 
263  // Calculate full width at half maximum from seed width and check if it's
264  // correct
265  float fwhm = res.value().second * 2.355f;
266  BOOST_CHECK_EQUAL(fwhm, 10.);
267 }
268 
269 BOOST_AUTO_TEST_CASE(track_adding) {
270  const int spatialTrkGridSize = 15;
271 
272  double binExtent = 0.1; // mm
273 
276 
277  // Create some test tracks in such a way that some tracks
278  // e.g. overlap and that certain tracks need to be inserted
279  // between two other tracks
280  Covariance covMat(Covariance::Identity());
281 
282  BoundVector paramVec0;
283  paramVec0 << 100.0, -0.4, 0, 0, 0, 0;
284  BoundVector paramVec1;
285  paramVec1 << 0.01, -0.4, 0, 0, 0, 0;
286  BoundVector paramVec2;
287  paramVec2 << 0.01, 10.9, 0, 0, 0, 0;
288  BoundVector paramVec3;
289  paramVec3 << 0.01, 0.9, 0, 0, 0, 0;
290 
291  // Create perigee surface
292  std::shared_ptr<PerigeeSurface> perigeeSurface =
293  Surface::makeShared<PerigeeSurface>(Vector3(0., 0., 0.));
294 
295  BoundTrackParameters params0(perigeeSurface, paramVec0, covMat,
297  BoundTrackParameters params1(perigeeSurface, paramVec1, covMat,
299  BoundTrackParameters params2(perigeeSurface, paramVec2, covMat,
301  BoundTrackParameters params3(perigeeSurface, paramVec3, covMat,
303 
304  // Empty map
306 
307  // Track is too far away from z axis and was not added
308  auto trackDensityMap = grid.addTrack(params0, mainDensityMap);
309  BOOST_CHECK(mainDensityMap.empty());
310 
311  // Track should have been entirely added to both grids
312  trackDensityMap = grid.addTrack(params1, mainDensityMap);
313  BOOST_CHECK_EQUAL(mainDensityMap.size(), spatialTrkGridSize);
314 
315  // Track should have been entirely added to both grids
316  trackDensityMap = grid.addTrack(params2, mainDensityMap);
317  BOOST_CHECK_EQUAL(mainDensityMap.size(), 2 * spatialTrkGridSize);
318 
319  // Track 3 has overlap of 2 bins with track 1
320  trackDensityMap = grid.addTrack(params3, mainDensityMap);
321  BOOST_CHECK_EQUAL(mainDensityMap.size(), 3 * spatialTrkGridSize - 2);
322 
323  // Add first track again, should *not* introduce new z entries
324  trackDensityMap = grid.addTrack(params1, mainDensityMap);
325  BOOST_CHECK_EQUAL(mainDensityMap.size(), 3 * spatialTrkGridSize - 2);
326 }
327 
328 BOOST_AUTO_TEST_CASE(max_z_t_and_width) {
329  const int spatialTrkGridSize = 29;
330  const int temporalTrkGridSize = 29;
331 
332  // spatial and temporal bin extent
333  double binExtent = 0.05;
334 
335  // 1D grid of z values
338 
339  // 2D grid of z and t values
341  cfg2D(binExtent, binExtent);
343  cfg2D);
344 
345  // Create some test tracks
346  Covariance covMat(Covariance::Identity() * 0.005);
347 
348  float z0Trk1 = 0.25;
349  float t0Trk1 = 0.05;
350  float z0Trk2 = -10.95;
351  float t0Trk2 = 0.1;
352  BoundVector paramVec1;
353  paramVec1 << 0.02, z0Trk1, 0, 0, 0, t0Trk1;
354  BoundVector paramVec2;
355  paramVec2 << 0.01, z0Trk2, 0, 0, 0, t0Trk2;
356 
357  // Create perigee surface
358  std::shared_ptr<PerigeeSurface> perigeeSurface =
359  Surface::makeShared<PerigeeSurface>(Vector3(0., 0., 0.));
360 
361  BoundTrackParameters params1(perigeeSurface, paramVec1, covMat,
363  BoundTrackParameters params2(perigeeSurface, paramVec2, covMat,
365 
366  // Empty maps
369  mainDensityMap2D;
370 
371  // Add first track to spatial grid
372  auto trackDensityMap = grid1D.addTrack(params1, mainDensityMap1D);
373  auto firstRes = grid1D.getMaxZTPosition(mainDensityMap1D);
374  BOOST_CHECK(firstRes.ok());
375  // Maximum should be at z0Trk1 position ...
376  BOOST_CHECK_EQUAL((*firstRes).first, z0Trk1);
377  // ... and the corresponding time should be set to 0
378  BOOST_CHECK_EQUAL((*firstRes).second, 0.);
379 
380  // Add first track to 2D grid
381  auto trackDensityMap2D = grid2D.addTrack(params1, mainDensityMap2D);
382  auto firstRes2D = grid2D.getMaxZTPosition(mainDensityMap2D);
383  BOOST_CHECK(firstRes2D.ok());
384  // Maximum should be at z0Trk1 position ...
385  BOOST_CHECK_EQUAL((*firstRes2D).first, z0Trk1);
386  // ... and the corresponding time should be at t0Trk1
387  BOOST_CHECK_EQUAL((*firstRes2D).second, t0Trk1);
388 
389  // Add second track to spatial grid
390  trackDensityMap = grid1D.addTrack(params2, mainDensityMap1D);
391  // Calculate maximum and the corresponding width
392  auto secondRes = grid1D.getMaxZTPositionAndWidth(mainDensityMap1D);
393  BOOST_CHECK(secondRes.ok());
394  // Trk 2 is closer to z-axis and should thus yield higher density values.
395  // Therefore, the new maximum is at z0Trk2 ...
396  BOOST_CHECK_EQUAL((*secondRes).first.first, z0Trk2);
397  // ... the corresponding time should be set to 0...
398  BOOST_CHECK_EQUAL((*secondRes).first.second, 0.);
399  // ... and it should have a positive width
400  BOOST_CHECK((*secondRes).second > 0);
401 
402  // Add second track to 2D grid
403  trackDensityMap = grid2D.addTrack(params2, mainDensityMap2D);
404  // Calculate maximum and the corresponding width
405  auto secondRes2D = grid2D.getMaxZTPositionAndWidth(mainDensityMap2D);
406  BOOST_CHECK(secondRes2D.ok());
407  // Trk 2 is closer to z-axis and should thus yield higher density values.
408  // Therefore, the new maximum is at z0Trk2 ...
409  BOOST_CHECK_EQUAL((*secondRes2D).first.first, z0Trk2);
410  // ... the corresponding time should be at t0Trk2 ...
411  BOOST_CHECK_EQUAL((*secondRes2D).first.second, t0Trk2);
412  // ... and it should have approximately the same width in z direction
413  CHECK_CLOSE_OR_SMALL((*secondRes2D).second, (*secondRes).second, 1e-5, 1e-5);
414 }
415 
416 BOOST_AUTO_TEST_CASE(highest_density_sum) {
417  const int spatialTrkGridSize = 29;
418 
419  double binExtent = 0.05; // mm
420 
422  cfg.useHighestSumZPosition = true;
423 
425 
426  // Create some test tracks
427  Covariance covMat(Covariance::Identity() * 0.005);
428 
429  float z0Trk1 = 0.25;
430  float z0Trk2 = -10.95;
431  BoundVector paramVec1;
432  paramVec1 << 0.01, z0Trk1, 0, 0, 0, 0;
433  BoundVector paramVec2;
434  paramVec2 << 0.0095, z0Trk2, 0, 0, 0, 0;
435 
436  // Create perigee surface
437  std::shared_ptr<PerigeeSurface> perigeeSurface =
438  Surface::makeShared<PerigeeSurface>(Vector3(0., 0., 0.));
439 
440  BoundTrackParameters params1(perigeeSurface, paramVec1, covMat,
442  BoundTrackParameters params2(perigeeSurface, paramVec2, covMat,
444 
445  // Empty map
447 
448  // Fill grid with track densities
449  auto trackDensityMap = grid.addTrack(params1, mainDensityMap);
450 
451  auto res1 = grid.getMaxZTPosition(mainDensityMap);
452  BOOST_CHECK(res1.ok());
453  // Maximum should be at z0Trk1 position
454  BOOST_CHECK_EQUAL((*res1).first, z0Trk1);
455 
456  // Add second track
457  trackDensityMap = grid.addTrack(params2, mainDensityMap);
458  auto res2 = grid.getMaxZTPosition(mainDensityMap);
459  BOOST_CHECK(res2.ok());
460  // Trk 2 is closer to z-axis and should yield higher density values
461  // New maximum is therefore at z0Trk2
462  BOOST_CHECK_EQUAL((*res2).first, z0Trk2);
463 
464  // Add small density values around the maximum of track 1
465  const float densityToAdd = 0.5;
466  mainDensityMap.at(std::make_pair(4, 0)) += densityToAdd;
467  mainDensityMap.at(std::make_pair(6, 0)) += densityToAdd;
468 
469  auto res3 = grid.getMaxZTPosition(mainDensityMap);
470  BOOST_CHECK(res3.ok());
471  // Trk 2 still has the highest peak density value, however, the small
472  // added densities for track 1 around its maximum should now lead to
473  // a prediction at z0Trk1 again
474  BOOST_CHECK_EQUAL((*res3).first, z0Trk1);
475 }
476 
477 BOOST_AUTO_TEST_CASE(track_removing) {
478  const int spatialTrkGridSize = 29;
479  const int temporalTrkGridSize = 29;
480 
481  int trkGridSize = spatialTrkGridSize * temporalTrkGridSize;
482 
483  // bin extent in z and t direction
484  double binExtent = 0.05;
485 
486  // 1D grid
489 
490  // 2D grid
492  cfg2D(binExtent, binExtent);
494  cfg2D);
495 
496  // Create some test tracks
497  Covariance covMat = makeRandomCovariance();
498 
499  // Define z0 values for test tracks
500  float z0Trk1 = -0.45;
501  float t0Trk1 = -0.15;
502  float z0Trk2 = -0.25;
503  float t0Trk2 = t0Trk1;
504 
505  BoundVector paramVec0;
506  paramVec0 << 0.1, z0Trk1, 0, 0, 0, t0Trk1;
507  BoundVector paramVec1;
508  paramVec1 << 0.1, z0Trk2, 0, 0, 0, t0Trk2;
509 
510  // Create perigee surface
511  std::shared_ptr<PerigeeSurface> perigeeSurface =
512  Surface::makeShared<PerigeeSurface>(Vector3(0., 0., 0.));
513 
514  BoundTrackParameters params0(perigeeSurface, paramVec0, covMat,
516  BoundTrackParameters params1(perigeeSurface, paramVec1, covMat,
518 
519  // Empty maps
522  mainDensityMap2D;
523 
524  // Lambda for calculating total density
525  auto densitySum = [](const auto& densityMap) {
526  float sum = 0.;
527  for (auto it = densityMap.begin(); it != densityMap.end(); it++) {
528  sum += it->second;
529  }
530  return sum;
531  };
532 
533  // Add track 0 to 1D grid
534  auto firstTrackDensityMap1D = grid1D.addTrack(params0, mainDensityMap1D);
535  BOOST_CHECK(not mainDensityMap1D.empty());
536  // Grid size should match spatialTrkGridSize
537  BOOST_CHECK_EQUAL(mainDensityMap1D.size(), spatialTrkGridSize);
538  float firstDensitySum1D = densitySum(mainDensityMap1D);
539 
540  // Add track 0 to 2D grid
541  auto firstTrackDensityMap2D = grid2D.addTrack(params0, mainDensityMap2D);
542  BOOST_CHECK(not mainDensityMap2D.empty());
543  // Grid size should match spatialTrkGridSize
544  BOOST_CHECK_EQUAL(mainDensityMap2D.size(), trkGridSize);
545  float firstDensitySum2D = densitySum(mainDensityMap2D);
546 
547  // Add track 0 again to 1D grid
548  firstTrackDensityMap1D = grid1D.addTrack(params0, mainDensityMap1D);
549  BOOST_CHECK(not mainDensityMap1D.empty());
550  // Grid size should still match spatialTrkGridSize
551  BOOST_CHECK_EQUAL(mainDensityMap1D.size(), spatialTrkGridSize);
552  // Calculate new total density ...
553  float secondDensitySum1D = densitySum(mainDensityMap1D);
554  // ... and check that it's twice as large as before
555  BOOST_CHECK(2 * firstDensitySum1D == secondDensitySum1D);
556 
557  // Add track 0 again to 2D grid
558  firstTrackDensityMap2D = grid2D.addTrack(params0, mainDensityMap2D);
559  BOOST_CHECK(not mainDensityMap2D.empty());
560  // Grid size should still match trkGridSize
561  BOOST_CHECK_EQUAL(mainDensityMap2D.size(), trkGridSize);
562  // Calculate new total density ...
563  float secondDensitySum2D = densitySum(mainDensityMap2D);
564  // ... and check that it's twice as large as before
565  BOOST_CHECK(2 * firstDensitySum2D == secondDensitySum2D);
566 
567  // Remove track 0 from 1D grid
568  grid1D.subtractTrack(firstTrackDensityMap1D, mainDensityMap1D);
569  // Calculate new total density
570  float thirdDensitySum1D = densitySum(mainDensityMap1D);
571  // Density should be old one again
572  BOOST_CHECK(firstDensitySum1D == thirdDensitySum1D);
573  // Grid size should still match spatialTrkGridSize (removal does not change
574  // grid size)
575  BOOST_CHECK_EQUAL(mainDensityMap1D.size(), spatialTrkGridSize);
576 
577  // Remove track 0 from 2D grid
578  grid2D.subtractTrack(firstTrackDensityMap2D, mainDensityMap2D);
579  // Calculate new total density
580  float thirdDensitySum2D = densitySum(mainDensityMap2D);
581  // Density should be old one again
582  BOOST_CHECK(firstDensitySum2D == thirdDensitySum2D);
583  // Grid size should still match trkGridSize (removal does not change grid
584  // size)
585  BOOST_CHECK_EQUAL(mainDensityMap2D.size(), trkGridSize);
586 
587  // Add track 1 to 1D grid (overlaps with track 0!)
588  auto secondTrackDensityMap1D = grid1D.addTrack(params1, mainDensityMap1D);
589  int nNonOverlappingBins1D = int(std::abs(z0Trk1 - z0Trk2) / binExtent + 1);
590  BOOST_CHECK_EQUAL(mainDensityMap1D.size(),
591  spatialTrkGridSize + nNonOverlappingBins1D);
592  float fourthDensitySum1D = densitySum(mainDensityMap1D);
593 
594  // Add track 1 to 2D grid (overlaps with track 0!)
595  auto secondTrackDensityMap2D = grid2D.addTrack(params1, mainDensityMap2D);
596  int nNonOverlappingBins2D = nNonOverlappingBins1D * temporalTrkGridSize;
597  BOOST_CHECK_EQUAL(mainDensityMap2D.size(),
598  trkGridSize + nNonOverlappingBins2D);
599  float fourthDensitySum2D = densitySum(mainDensityMap2D);
600 
601  // Remove second track 0 from 1D grid
602  grid1D.subtractTrack(firstTrackDensityMap1D, mainDensityMap1D);
603  float fifthDensitySum1D = densitySum(mainDensityMap1D);
604  // Density should match differences of removed tracks
605  CHECK_CLOSE_REL(fifthDensitySum1D, fourthDensitySum1D - firstDensitySum1D,
606  1e-5);
607 
608  // Remove second track 0 from 2D grid
609  grid2D.subtractTrack(firstTrackDensityMap2D, mainDensityMap2D);
610  float fifthDensitySum2D = densitySum(mainDensityMap2D);
611  // Density should match differences of removed tracks
612  CHECK_CLOSE_REL(fifthDensitySum2D, fourthDensitySum2D - firstDensitySum2D,
613  1e-5);
614 
615  // Remove track 1 from 1D grid
616  grid1D.subtractTrack(secondTrackDensityMap1D, mainDensityMap1D);
617  // Size should not have changed
618  BOOST_CHECK_EQUAL(mainDensityMap1D.size(),
619  spatialTrkGridSize + nNonOverlappingBins1D);
620  float sixthDensitySum1D = densitySum(mainDensityMap1D);
621  // 1D grid is now empty after all tracks were removed
622  CHECK_CLOSE_ABS(sixthDensitySum1D, 0., 1e-4);
623 
624  // Remove track 1 from 2D grid
625  grid2D.subtractTrack(secondTrackDensityMap2D, mainDensityMap2D);
626  // Size should not have changed
627  BOOST_CHECK_EQUAL(mainDensityMap2D.size(),
628  trkGridSize + nNonOverlappingBins2D);
629  float sixthDensitySum2D = densitySum(mainDensityMap2D);
630  // 2D grid is now empty after all tracks were removed
631  CHECK_CLOSE_ABS(sixthDensitySum2D, 0., 1e-4);
632 }
633 
634 } // namespace Test
635 } // namespace Acts