Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AdaptiveGridTrackDensity.ipp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file AdaptiveGridTrackDensity.ipp
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/.
10 
11 #include <algorithm>
12 
13 template <int spatialTrkGridSize, int temporalTrkGridSize>
15  spatialTrkGridSize, temporalTrkGridSize>::getBinCenter(int bin,
16  float binExtent) {
17  return bin * binExtent;
18 }
19 
20 template <int spatialTrkGridSize, int temporalTrkGridSize>
22  spatialTrkGridSize, temporalTrkGridSize>::getBin(float value,
23  float binExtent) {
24  return static_cast<int>(std::floor(value / binExtent - 0.5) + 1);
25 }
26 
27 template <int spatialTrkGridSize, int temporalTrkGridSize>
29  spatialTrkGridSize, temporalTrkGridSize>::DensityMap::const_iterator
31  highestDensityEntry(const DensityMap& densityMap) const {
32  auto maxEntry = std::max_element(
33  std::begin(densityMap), std::end(densityMap),
34  [](const auto& densityEntry1, const auto& densityEntry2) {
35  return densityEntry1.second < densityEntry2.second;
36  });
37  return maxEntry;
38 }
39 
40 template <int spatialTrkGridSize, int temporalTrkGridSize>
42  spatialTrkGridSize, temporalTrkGridSize>::ZTPosition>
44  getMaxZTPosition(DensityMap& densityMap) const {
45  if (densityMap.empty()) {
46  return VertexingError::EmptyInput;
47  }
48 
49  Bin bin;
50  if (!m_cfg.useHighestSumZPosition) {
51  bin = highestDensityEntry(densityMap)->first;
52  } else {
53  // Get z position with highest density sum
54  // of surrounding bins
55  bin = highestDensitySumBin(densityMap);
56  }
57 
58  // Derive corresponding z value
59  float maxZ = getBinCenter(bin.first, m_cfg.spatialBinExtent);
60 
61  ZTPosition maxValues = std::make_pair(maxZ, 0.);
62 
63  // Get t value of the maximum if we do time vertex seeding
64  if constexpr (temporalTrkGridSize > 1) {
65  float maxT = getBinCenter(bin.second, m_cfg.temporalBinExtent);
66  maxValues.second = maxT;
67  }
68 
69  return maxValues;
70 }
71 
72 template <int spatialTrkGridSize, int temporalTrkGridSize>
74  spatialTrkGridSize, temporalTrkGridSize>::ZTPositionAndWidth>
77  // Get z value where the density is the highest
78  auto maxZTRes = getMaxZTPosition(densityMap);
79  if (not maxZTRes.ok()) {
80  return maxZTRes.error();
81  }
82  ZTPosition maxZT = *maxZTRes;
83 
84  // Get seed width estimate
85  auto widthRes = estimateSeedWidth(densityMap, maxZT);
86  if (not widthRes.ok()) {
87  return widthRes.error();
88  }
89  float width = *widthRes;
90  ZTPositionAndWidth maxZTAndWidth{maxZT, width};
91  return maxZTAndWidth;
92 }
93 
94 template <int spatialTrkGridSize, int temporalTrkGridSize>
95 typename Acts::AdaptiveGridTrackDensity<spatialTrkGridSize,
96  temporalTrkGridSize>::DensityMap
99  DensityMap& mainDensityMap) const {
100  ActsVector<3> impactParams = trk.impactParameters();
102 
103  // Calculate bin in d direction
104  int centralDBin = getBin(impactParams(0), m_cfg.spatialBinExtent);
105  // Check if current track affects grid density
106  if (std::abs(centralDBin) > (spatialTrkGridSize - 1) / 2.) {
107  DensityMap emptyTrackDensityMap;
108  return emptyTrackDensityMap;
109  }
110  // Calculate bin in z direction
111  int centralZBin = getBin(impactParams(1), m_cfg.spatialBinExtent);
112 
113  // If we don't do time vertex seeding, the time index is set to 0
114  Bin centralBin = std::make_pair(centralZBin, 0.);
115 
116  // Calculate bin in t direction if we do time vertex seeding
117  if constexpr (temporalTrkGridSize > 1) {
118  int centralTBin = getBin(impactParams(2), m_cfg.temporalBinExtent);
119  centralBin.second = centralTBin;
120  }
121 
122  DensityMap trackDensityMap = createTrackGrid(impactParams, centralBin, cov);
123 
124  for (const auto& densityEntry : trackDensityMap) {
125  Bin bin = densityEntry.first;
126  float trackDensity = densityEntry.second;
127  // Check if z bin is already part of the main grid
128  if (mainDensityMap.count(bin) == 1) {
129  mainDensityMap.at(bin) += trackDensity;
130  } else {
131  mainDensityMap[bin] = trackDensity;
132  }
133  }
134 
135  return trackDensityMap;
136 }
137 
138 template <int spatialTrkGridSize, int temporalTrkGridSize>
140  subtractTrack(const DensityMap& trackDensityMap,
141  DensityMap& mainDensityMap) const {
142  for (auto it = trackDensityMap.begin(); it != trackDensityMap.end(); it++) {
143  mainDensityMap.at(it->first) -= it->second;
144  }
145 }
146 
147 template <int spatialTrkGridSize, int temporalTrkGridSize>
148 typename Acts::AdaptiveGridTrackDensity<spatialTrkGridSize,
149  temporalTrkGridSize>::DensityMap
151  createTrackGrid(const Acts::Vector3& impactParams, const Bin& centralBin,
152  const Acts::SquareMatrix3& cov) const {
153  DensityMap trackDensityMap;
154 
155  int halfSpatialTrkGridSize = (spatialTrkGridSize - 1) / 2;
156  int firstZBin = centralBin.first - halfSpatialTrkGridSize;
157 
158  // If we don't do time vertex seeding, firstTBin will be 0.
159  int halfTemporalTrkGridSize = (temporalTrkGridSize - 1) / 2;
160  int firstTBin = centralBin.second - halfTemporalTrkGridSize;
161 
162  // Loop over bins
163  for (int i = 0; i < temporalTrkGridSize; i++) {
164  int tBin = firstTBin + i;
165  // If we don't do vertex time seeding, we set the time to 0 since it will be
166  // discarded in the for loop below anyways
167  float t = 0;
168  if constexpr (temporalTrkGridSize > 1) {
169  t = getBinCenter(tBin, m_cfg.temporalBinExtent);
170  }
171  for (int j = 0; j < spatialTrkGridSize; j++) {
172  int zBin = firstZBin + j;
173  float z = getBinCenter(zBin, m_cfg.spatialBinExtent);
174  // Bin coordinates in the d-z-t plane
175  Acts::Vector3 binCoords(0., z, t);
176  // Transformation to coordinate system with origin at the track center
177  binCoords -= impactParams;
178  Bin bin = std::make_pair(zBin, tBin);
179  if constexpr (temporalTrkGridSize == 1) {
180  trackDensityMap[bin] = multivariateGaussian<2>(
181  binCoords.head<2>(), cov.topLeftCorner<2, 2>());
182  } else {
183  trackDensityMap[bin] = multivariateGaussian<3>(binCoords, cov);
184  }
185  }
186  }
187  return trackDensityMap;
188 }
189 
190 template <int spatialTrkGridSize, int temporalTrkGridSize>
192  spatialTrkGridSize,
193  temporalTrkGridSize>::estimateSeedWidth(const DensityMap& densityMap,
194  const ZTPosition& maxZT) const {
195  if (densityMap.empty()) {
196  return VertexingError::EmptyInput;
197  }
198 
199  // Get z bin of max density
200  int zMaxBin = getBin(maxZT.first, m_cfg.spatialBinExtent);
201  int tMaxBin = 0;
202  // Fill the time bin with a non-zero value if we do time vertex seeding
203  if constexpr (temporalTrkGridSize > 1) {
204  tMaxBin = getBin(maxZT.second, m_cfg.temporalBinExtent);
205  }
206  const float maxValue = densityMap.at(std::make_pair(zMaxBin, tMaxBin));
207 
208  int rhmBin = zMaxBin;
209  float gridValue = maxValue;
210  // Boolean indicating whether we find a filled bin that has a densityValue <=
211  // maxValue/2
212  bool binFilled = true;
213  while (gridValue > maxValue / 2) {
214  // Check if we are still operating on continuous z values
215  if (densityMap.count(std::make_pair(rhmBin + 1, tMaxBin)) == 0) {
216  binFilled = false;
217  break;
218  }
219  rhmBin += 1;
220  gridValue = densityMap.at(std::make_pair(rhmBin, tMaxBin));
221  }
222 
223  // Use linear approximation to find better z value for FWHM between bins
224  float rightDensity = 0;
225  if (binFilled) {
226  rightDensity = densityMap.at(std::make_pair(rhmBin, tMaxBin));
227  }
228  float leftDensity = densityMap.at(std::make_pair(rhmBin - 1, tMaxBin));
229  float deltaZ1 = m_cfg.spatialBinExtent * (maxValue / 2 - leftDensity) /
230  (rightDensity - leftDensity);
231 
232  int lhmBin = zMaxBin;
233  gridValue = maxValue;
234  binFilled = true;
235  while (gridValue > maxValue / 2) {
236  // Check if we are still operating on continuous z values
237  if (densityMap.count(std::make_pair(lhmBin - 1, tMaxBin)) == 0) {
238  binFilled = false;
239  break;
240  }
241  lhmBin -= 1;
242  gridValue = densityMap.at(std::make_pair(lhmBin, tMaxBin));
243  }
244 
245  // Use linear approximation to find better z value for FWHM between bins
246  rightDensity = densityMap.at(std::make_pair(lhmBin + 1, tMaxBin));
247  if (binFilled) {
248  leftDensity = densityMap.at(std::make_pair(lhmBin, tMaxBin));
249  } else {
250  leftDensity = 0;
251  }
252  float deltaZ2 = m_cfg.spatialBinExtent * (rightDensity - maxValue / 2) /
253  (rightDensity - leftDensity);
254 
255  float fwhm = (rhmBin - lhmBin) * m_cfg.spatialBinExtent - deltaZ1 - deltaZ2;
256 
257  // FWHM = 2.355 * sigma
258  float width = fwhm / 2.355f;
259 
260  return std::isnormal(width) ? width : 0.0f;
261 }
262 
263 template <int spatialTrkGridSize, int temporalTrkGridSize>
264 template <unsigned int nDim>
268  float expo = -0.5 * args.transpose().dot(cov.inverse() * args);
269  float gaussianDensity = safeExp(expo) / std::sqrt(cov.determinant());
270  return gaussianDensity;
271 }
272 
273 template <int spatialTrkGridSize, int temporalTrkGridSize>
274 typename Acts::AdaptiveGridTrackDensity<spatialTrkGridSize,
275  temporalTrkGridSize>::Bin
277  highestDensitySumBin(DensityMap& densityMap) const {
278  // The global maximum
279  auto firstMax = highestDensityEntry(densityMap);
280  Bin binFirstMax = firstMax->first;
281  float valueFirstMax = firstMax->second;
282  float firstSum = getDensitySum(densityMap, binFirstMax);
283  // Smaller maxima must have a density of at least:
284  // valueFirstMax - densityDeviation
285  float densityDeviation = valueFirstMax * m_cfg.maxRelativeDensityDev;
286 
287  // Get the second highest maximum
288  densityMap.at(binFirstMax) = 0;
289  auto secondMax = highestDensityEntry(densityMap);
290  Bin binSecondMax = secondMax->first;
291  float valueSecondMax = secondMax->second;
292  float secondSum = 0;
293  if (valueFirstMax - valueSecondMax < densityDeviation) {
294  secondSum = getDensitySum(densityMap, binSecondMax);
295  } else {
296  // If the second maximum is not sufficiently large the third maximum won't
297  // be either
298  densityMap.at(binFirstMax) = valueFirstMax;
299  return binFirstMax;
300  }
301 
302  // Get the third highest maximum
303  densityMap.at(binSecondMax) = 0;
304  auto thirdMax = highestDensityEntry(densityMap);
305  Bin binThirdMax = thirdMax->first;
306  float valueThirdMax = thirdMax->second;
307  float thirdSum = 0;
308  if (valueFirstMax - valueThirdMax < densityDeviation) {
309  thirdSum = getDensitySum(densityMap, binThirdMax);
310  }
311 
312  // Revert back to original values
313  densityMap.at(binFirstMax) = valueFirstMax;
314  densityMap.at(binSecondMax) = valueSecondMax;
315 
316  // Return the z bin position of the highest density sum
317  if (secondSum > firstSum && secondSum > thirdSum) {
318  return binSecondMax;
319  }
320  if (thirdSum > secondSum && thirdSum > firstSum) {
321  return binThirdMax;
322  }
323  return binFirstMax;
324 }
325 
326 template <int spatialTrkGridSize, int temporalTrkGridSize>
328  getDensitySum(const DensityMap& densityMap, const Bin& bin) const {
329  // Add density from the bin.
330  float sum = densityMap.at(bin);
331  // Check if neighboring bins are part of the densityMap and add them (if they
332  // are not part of the map, we assume them to be 0).
333  // Note that each key in a map is unique; the .count() function therefore
334  // returns either 0 or 1.
335  Bin binShifted = bin;
336  // Add density from the neighboring bin in -z direction.
337  binShifted.first -= 1;
338  if (densityMap.count(binShifted) == 1) {
339  sum += densityMap.at(binShifted);
340  }
341 
342  // Add density from the neighboring bin in +z direction.
343  binShifted.first += 2;
344  if (densityMap.count(binShifted) == 1) {
345  sum += densityMap.at(binShifted);
346  }
347  return sum;
348 }