ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DoubleHitSpacePointBuilder.ipp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file DoubleHitSpacePointBuilder.ipp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2018 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 <cmath>
10 #include <limits>
12 
13 namespace Acts {
14 namespace detail {
33  double qmag = 0.;
35  double m = 0.;
37  double n = 0.;
40  double limit = 1.;
43  double limitExtended = 0.;
44 };
45 
55 double differenceOfClustersChecked(const Vector3D& pos1, const Vector3D& pos2,
56  const Vector3D& posVertex,
57  const double maxDistance,
58  const double maxAngleTheta2,
59  const double maxAnglePhi2) {
60  // Check if measurements are close enough to each other
61  if ((pos1 - pos2).norm() > maxDistance) {
62  return -1.;
63  }
64 
65  // Calculate the angles of the vectors
66  double phi1, theta1, phi2, theta2;
67  phi1 = VectorHelpers::phi(pos1 - posVertex);
68  theta1 = VectorHelpers::theta(pos1 - posVertex);
69  phi2 = VectorHelpers::phi(pos2 - posVertex);
70  theta2 = VectorHelpers::theta(pos2 - posVertex);
71 
72  // Calculate the squared difference between the theta angles
73  double diffTheta2 = (theta1 - theta2) * (theta1 - theta2);
74  if (diffTheta2 > maxAngleTheta2) {
75  return -1.;
76  }
77 
78  // Calculate the squared difference between the phi angles
79  double diffPhi2 = (phi1 - phi2) * (phi1 - phi2);
80  if (diffPhi2 > maxAnglePhi2) {
81  return -1.;
82  }
83 
84  // Return the squared distance between both vector
85  return diffTheta2 + diffPhi2;
86 }
87 
95 std::pair<Vector2D, Vector2D> findLocalTopAndBottomEnd(
96  const Vector2D& local, const CartesianSegmentation* segment) {
97  auto& binData = segment->binUtility().binningData();
98  auto& boundariesX = binData[0].boundaries();
99  auto& boundariesY = binData[1].boundaries();
100 
101  // Search the x-/y-bin of the cluster
102  size_t binX = binData[0].searchLocal(local);
103  size_t binY = binData[1].searchLocal(local);
104 
105  // Storage of the local top (first) and bottom (second) end
106  std::pair<Vector2D, Vector2D> topBottomLocal;
107 
108  if (boundariesX[binX + 1] - boundariesX[binX] <
109  boundariesY[binY + 1] - boundariesY[binY]) {
110  // Set the top and bottom end of the strip in local coordinates
111  topBottomLocal.first = {(boundariesX[binX] + boundariesX[binX + 1]) / 2,
112  boundariesY[binY + 1]};
113  topBottomLocal.second = {(boundariesX[binX] + boundariesX[binX + 1]) / 2,
114  boundariesY[binY]};
115  } else {
116  // Set the top and bottom end of the strip in local coordinates
117  topBottomLocal.first = {boundariesX[binX],
118  (boundariesY[binY] + boundariesY[binY + 1]) / 2};
119  topBottomLocal.second = {boundariesX[binX + 1],
120  (boundariesY[binY] + boundariesY[binY + 1]) / 2};
121  }
122  return topBottomLocal;
123 }
124 
136  const Vector3D& q, const Vector3D& r) {
147  Vector3D ac = c - a;
148  double qr = q.dot(r);
149  double denom = q.dot(q) - qr * qr;
150 
151  // Check for numerical stability
152  if (fabs(denom) > 10e-7) {
153  // Return lambda0
154  return (ac.dot(r) * qr - ac.dot(q) * r.dot(r)) / denom;
155  }
156  // lambda0 is in the interval [-1,0]. This return serves as error check.
157  return 1.;
158 }
159 
171  double stripLengthGapTolerance) {
173  // Check if the limits are allowed to be increased
174  if (stripLengthGapTolerance <= 0.) {
175  return false;
176  }
177  spaPoPa.qmag = spaPoPa.q.norm();
178  // Increase the limits. This allows a check if the point is just slightly
179  // outside the SDE
180  spaPoPa.limitExtended =
181  spaPoPa.limit + stripLengthGapTolerance / spaPoPa.qmag;
182  // Check if m is just slightly outside
183  if (fabs(spaPoPa.m) > spaPoPa.limitExtended) {
184  return false;
185  }
186  // Calculate n if not performed previously
187  if (spaPoPa.n == 0.) {
188  spaPoPa.n = -spaPoPa.t.dot(spaPoPa.qs) / spaPoPa.r.dot(spaPoPa.qs);
189  }
190  // Check if n is just slightly outside
191  if (fabs(spaPoPa.n) > spaPoPa.limitExtended) {
192  return false;
193  }
194 
212 
213  // Calculate the scaling factor to project lengths of the second SDE on the
214  // first SDE
215  double secOnFirstScale =
216  spaPoPa.q.dot(spaPoPa.r) / (spaPoPa.qmag * spaPoPa.qmag);
217  // Check if both overshoots are in the same direction
218  if (spaPoPa.m > 1. && spaPoPa.n > 1.) {
219  // Calculate the overshoots
220  double mOvershoot = spaPoPa.m - 1.;
221  double nOvershoot =
222  (spaPoPa.n - 1.) * secOnFirstScale; // Perform projection
223  // Resolve worse overshoot
224  double biggerOvershoot = std::max(mOvershoot, nOvershoot);
225  // Move m and n towards 0
226  spaPoPa.m -= biggerOvershoot;
227  spaPoPa.n -= (biggerOvershoot / secOnFirstScale);
228  // Check if this recovered the space point
229  return fabs(spaPoPa.m) < spaPoPa.limit && fabs(spaPoPa.n) < spaPoPa.limit;
230  }
231  // Check if both overshoots are in the same direction
232  if (spaPoPa.m < -1. && spaPoPa.n < -1.) {
233  // Calculate the overshoots
234  double mOvershoot = -(spaPoPa.m + 1.);
235  double nOvershoot =
236  -(spaPoPa.n + 1.) * secOnFirstScale; // Perform projection
237  // Resolve worse overshoot
238  double biggerOvershoot = std::max(mOvershoot, nOvershoot);
239  // Move m and n towards 0
240  spaPoPa.m += biggerOvershoot;
241  spaPoPa.n += (biggerOvershoot / secOnFirstScale);
242  // Check if this recovered the space point
243  return fabs(spaPoPa.m) < spaPoPa.limit && fabs(spaPoPa.n) < spaPoPa.limit;
244  }
245  // No solution could be found
246  return false;
247 }
248 
262 bool calculateSpacePoint(const std::pair<Vector3D, Vector3D>& stripEnds1,
263  const std::pair<Vector3D, Vector3D>& stripEnds2,
264  const Vector3D& posVertex,
265  SpacePointParameters& spaPoPa,
266  const double stripLengthTolerance) {
287 
288  spaPoPa.s = stripEnds1.first + stripEnds1.second - 2 * posVertex;
289  spaPoPa.t = stripEnds2.first + stripEnds2.second - 2 * posVertex;
290  spaPoPa.qs = spaPoPa.q.cross(spaPoPa.s);
291  spaPoPa.rt = spaPoPa.r.cross(spaPoPa.t);
292  spaPoPa.m = -spaPoPa.s.dot(spaPoPa.rt) / spaPoPa.q.dot(spaPoPa.rt);
293 
294  // Set the limit for the parameter
295  if (spaPoPa.limit == 1. && stripLengthTolerance != 0.) {
296  spaPoPa.limit = 1. + stripLengthTolerance;
297  }
298 
299  // Check if m and n can be resolved in the interval (-1, 1)
300  return (fabs(spaPoPa.m) <= spaPoPa.limit &&
301  fabs(spaPoPa.n = -spaPoPa.t.dot(spaPoPa.qs) /
302  spaPoPa.r.dot(spaPoPa.qs)) <= spaPoPa.limit);
303 }
304 } // namespace detail
305 } // namespace Acts
306 
310 template <typename Cluster>
312  DoubleHitSpacePointConfig cfg)
313  : m_cfg(std::move(cfg)) {}
314 
315 template <typename Cluster>
317  const Cluster& cluster) const {
318  // Local position information
319  auto par = cluster.parameters();
321  return local;
322 }
323 
324 template <typename Cluster>
326  const GeometryContext& gctx, const Cluster& cluster) const {
327  // Receive corresponding surface
328  auto& clusterSurface = cluster.referenceSurface();
329 
330  // Transform local into global position information
332  clusterSurface.localToGlobal(gctx, localCoords(cluster), mom, pos);
333 
334  return pos;
335 }
336 
337 template <typename Cluster>
339  const GeometryContext& gctx,
340  const std::vector<const Cluster*>& clustersFront,
341  const std::vector<const Cluster*>& clustersBack,
342  std::vector<std::pair<const Cluster*, const Cluster*>>& clusterPairs)
343  const {
344  // Return if no clusters are given in a vector
345  if (clustersFront.empty() || clustersBack.empty()) {
346  return;
347  }
348 
349  // Declare helper variables
350  double currentDiff;
351  double diffMin;
352  unsigned int clusterMinDist;
353 
354  // Walk through all clusters on both surfaces
355  for (unsigned int iClustersFront = 0; iClustersFront < clustersFront.size();
356  iClustersFront++) {
357  // Set the closest distance to the maximum of double
359  // Set the corresponding index to an element not in the list of clusters
360  clusterMinDist = clustersBack.size();
361  for (unsigned int iClustersBack = 0; iClustersBack < clustersBack.size();
362  iClustersBack++) {
363  // Calculate the distances between the hits
365  globalCoords(gctx, *(clustersFront[iClustersFront])),
366  globalCoords(gctx, *(clustersBack[iClustersBack])), m_cfg.vertex,
367  m_cfg.diffDist, m_cfg.diffPhi2, m_cfg.diffTheta2);
368  // Store the closest clusters (distance and index) calculated so far
369  if (currentDiff < diffMin && currentDiff >= 0.) {
370  diffMin = currentDiff;
371  clusterMinDist = iClustersBack;
372  }
373  }
374 
375  // Store the best (=closest) result
376  if (clusterMinDist < clustersBack.size()) {
377  std::pair<const Cluster*, const Cluster*> clusterPair;
378  clusterPair = std::make_pair(clustersFront[iClustersFront],
379  clustersBack[clusterMinDist]);
380  clusterPairs.push_back(clusterPair);
381  }
382  }
383 }
384 
385 template <typename Cluster>
386 std::pair<Acts::Vector3D, Acts::Vector3D>
388  const GeometryContext& gctx, const Cluster& cluster) const {
389  // Calculate the local coordinates of the cluster
390  const Acts::Vector2D local = localCoords(cluster);
391 
392  // Receive the binning
393  auto segment = dynamic_cast<const Acts::CartesianSegmentation*>(
394  &(cluster.digitizationModule()->segmentation()));
395 
396  std::pair<Vector2D, Vector2D> topBottomLocal =
397  detail::findLocalTopAndBottomEnd(local, segment);
398 
399  // Calculate the global coordinates of the top and bottom end of the strip
400  Acts::Vector3D topGlobal, bottomGlobal, mom; // mom is a dummy variable
401  const auto* sur = &cluster.referenceSurface();
402  sur->localToGlobal(gctx, topBottomLocal.first, mom, topGlobal);
403  sur->localToGlobal(gctx, topBottomLocal.second, mom, bottomGlobal);
404 
405  // Return the top and bottom end of the strip in global coordinates
406  return std::make_pair(topGlobal, bottomGlobal);
407 }
408 
409 template <typename Cluster>
410 void Acts::SpacePointBuilder<Acts::SpacePoint<Cluster>>::calculateSpacePoints(
411  const GeometryContext& gctx,
412  const std::vector<std::pair<const Cluster*, const Cluster*>>& clusterPairs,
413  std::vector<Acts::SpacePoint<Cluster>>& spacePoints) const {
415 
416  detail::SpacePointParameters spaPoPa;
417 
418  // Walk over every found candidate pair
419  for (const auto& cp : clusterPairs) {
420  // Calculate the ends of the SDEs
421  const auto& ends1 = endsOfStrip(gctx, *(cp.first));
422  const auto& ends2 = endsOfStrip(gctx, *(cp.second));
423 
424  spaPoPa.q = ends1.first - ends1.second;
425  spaPoPa.r = ends2.first - ends2.second;
426 
427  // Fast skipping if a perpendicular projection should be used
428  double resultPerpProj;
429  if (m_cfg.usePerpProj) {
430  resultPerpProj = detail::calcPerpendicularProjection(
431  ends1.first, ends2.first, spaPoPa.q, spaPoPa.r);
432  if (resultPerpProj <= 0.) {
434  sp.clusterModule.push_back(cp.first);
435  sp.clusterModule.push_back(cp.second);
436  Vector3D pos = ends1.first + resultPerpProj * spaPoPa.q;
437  sp.vector = pos;
438  spacePoints.push_back(std::move(sp));
439  continue;
440  }
441  }
442 
443  if (calculateSpacePoint(ends1, ends2, m_cfg.vertex, spaPoPa,
444  m_cfg.stripLengthTolerance)) {
445  // Store the space point
447  sp.clusterModule.push_back(cp.first);
448  sp.clusterModule.push_back(cp.second);
449  Vector3D pos = 0.5 * (ends1.first + ends1.second + spaPoPa.m * spaPoPa.q);
450  // TODO: Clusters should deliver timestamp
451  sp.vector = pos;
452  spacePoints.push_back(std::move(sp));
453  } else {
460  // Check if a recovery the point(s) and store them if successful
461  if (detail::recoverSpacePoint(spaPoPa, m_cfg.stripLengthGapTolerance)) {
463  sp.clusterModule.push_back(cp.first);
464  sp.clusterModule.push_back(cp.second);
465  Vector3D pos =
466  0.5 * (ends1.first + ends1.second + spaPoPa.m * spaPoPa.q);
467  sp.vector = pos;
468  spacePoints.push_back(std::move(sp));
469  }
470  }
471  }
472 }