ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TrackingVolume.ipp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file TrackingVolume.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 
10 // TrackingVolume.ipp, Acts project
12 
13 inline const Acts::Layer* TrackingVolume::associatedLayer(
14  const GeometryContext& /*gctx*/, const Vector3D& position) const {
15  // confined static layers - highest hierarchy
16  if (m_confinedLayers != nullptr) {
17  return (m_confinedLayers->object(position).get());
18  }
19 
20  // return the null pointer
21  return nullptr;
22 }
23 
24 template <typename options_t>
25 std::vector<LayerIntersection> TrackingVolume::compatibleLayers(
26  const GeometryContext& gctx, const Vector3D& position,
27  const Vector3D& direction, const options_t& options) const {
28  // the layer intersections which are valid
29  std::vector<LayerIntersection> lIntersections;
30 
31  // the confinedLayers
32  if (m_confinedLayers != nullptr) {
33  // start layer given or not - test layer
34  const Layer* tLayer = options.startObject != nullptr
35  ? options.startObject
36  : associatedLayer(gctx, position);
37  while (tLayer != nullptr) {
38  // check if the layer needs resolving
39  // - resolveSensitive -> always take layer if it has a surface array
40  // - resolveMaterial -> always take layer if it has material
41  // - resolvePassive -> always take, unless it's a navigation layer
42  // skip the start object
43  if (tLayer != options.startObject && tLayer->resolve(options)) {
44  // if it's a resolveable start layer, you are by definition on it
45  // layer on approach intersection
46  auto atIntersection =
47  tLayer->surfaceOnApproach(gctx, position, direction, options);
48  auto path = atIntersection.intersection.pathLength;
49  bool withinLimit =
50  (path * path <= options.pathLimit * options.pathLimit);
51  // Intersection is ok - take it (move to surface on appraoch)
52  if (atIntersection &&
53  (atIntersection.object != options.targetSurface) && withinLimit) {
54  // create a layer intersection
55  lIntersections.push_back(LayerIntersection(
56  atIntersection.intersection, tLayer, atIntersection.object));
57  }
58  }
59  // move to next one or break because you reached the end layer
60  tLayer =
61  (tLayer == options.endObject)
62  ? nullptr
63  : tLayer->nextLayer(gctx, position, options.navDir * direction);
64  }
65  // sort them accordingly to the navigation direction
66  if (options.navDir == forward) {
67  std::sort(lIntersections.begin(), lIntersections.end());
68  } else {
69  std::sort(lIntersections.begin(), lIntersections.end(), std::greater<>());
70  }
71  }
72  // and return
73  return lIntersections;
74 }
75 
76 // Returns the boundary surfaces ordered in probability to hit them based on
77 template <typename options_t>
78 std::vector<BoundaryIntersection> TrackingVolume::compatibleBoundaries(
79  const GeometryContext& gctx, const Vector3D& position,
80  const Vector3D& direction, const options_t& options) const {
81  // Loop over boundarySurfaces and calculate the intersection
82  auto excludeObject = options.startObject;
83  std::vector<BoundaryIntersection> bIntersections;
84 
85  // The signed direction: solution (except overstepping) is positive
86  auto sDirection = options.navDir * direction;
87 
88  // The Limits: current, path & overstepping
89  double pLimit = options.pathLimit;
90  double oLimit = options.overstepLimit;
91 
92  // Helper function to test intersection
93  auto checkIntersection =
94  [&](SurfaceIntersection& sIntersection,
95  const BoundarySurface* bSurface) -> BoundaryIntersection {
96  // Avoid doing anything if that's a rotten apple already
97  if (!sIntersection) {
98  return BoundaryIntersection();
99  }
100 
101  double cLimit = sIntersection.intersection.pathLength;
102  // Check if the surface is within limit
103  bool withinLimit =
104  (cLimit > oLimit and
105  cLimit * cLimit <= pLimit * pLimit + s_onSurfaceTolerance);
106  if (withinLimit) {
107  sIntersection.intersection.pathLength *=
108  std::copysign(1., options.navDir);
109  return BoundaryIntersection(sIntersection.intersection, bSurface,
110  sIntersection.object);
111  }
112  // Check the alternative
113  if (sIntersection.alternative) {
114  // Test the alternative
115  cLimit = sIntersection.alternative.pathLength;
116  withinLimit = (cLimit > oLimit and
117  cLimit * cLimit <= pLimit * pLimit + s_onSurfaceTolerance);
118  if (sIntersection.alternative and withinLimit) {
119  sIntersection.alternative.pathLength *=
120  std::copysign(1., options.navDir);
121  return BoundaryIntersection(sIntersection.alternative, bSurface,
122  sIntersection.object);
123  }
124  }
125  // Return an invalid one
126  return BoundaryIntersection();
127  };
128 
130  auto processBoundaries =
131  [&](const TrackingVolumeBoundaries& bSurfaces) -> void {
132  // Loop over the boundary surfaces
133  for (auto& bsIter : bSurfaces) {
134  // Get the boundary surface pointer
135  const auto& bSurfaceRep = bsIter->surfaceRepresentation();
136  // Exclude the boundary where you are on
137  if (excludeObject != &bSurfaceRep) {
138  auto bCandidate = bSurfaceRep.intersect(gctx, position, sDirection,
139  options.boundaryCheck);
140  // Intersect and continue
141  auto bIntersection = checkIntersection(bCandidate, bsIter.get());
142  if (bIntersection) {
143  bIntersections.push_back(bIntersection);
144  }
145  }
146  }
147  };
148 
149  // Process the boundaries of the current volume
150  auto& bSurfaces = boundarySurfaces();
151  processBoundaries(bSurfaces);
152 
153  // Process potential boundaries of contained volumes
154  auto confinedDenseVolumes = denseVolumes();
155  for (const auto& dv : confinedDenseVolumes) {
156  auto& bSurfacesConfined = dv->boundarySurfaces();
157  processBoundaries(bSurfacesConfined);
158  }
159 
160  // Sort them accordingly to the navigation direction
161  if (options.navDir == forward) {
162  std::sort(bIntersections.begin(), bIntersections.end());
163  } else {
164  std::sort(bIntersections.begin(), bIntersections.end(), std::greater<>());
165  }
166  return bIntersections;
167 }
168 
169 template <typename options_t>
170 std::vector<SurfaceIntersection>
171 TrackingVolume::compatibleSurfacesFromHierarchy(
172  const GeometryContext& gctx, const Vector3D& position,
173  const Vector3D& direction, double angle, const options_t& options) const {
174  std::vector<SurfaceIntersection> sIntersections;
175  sIntersections.reserve(20); // arbitrary
176 
177  // The limits for this navigation step
178  double pLimit = options.pathLimit;
179  double oLimit = options.overstepLimit;
180 
181  if (m_bvhTop == nullptr || !options.navDir) {
182  return sIntersections;
183  }
184 
185  // The signed direction
186  Vector3D sdir = options.navDir * direction;
187 
188  std::vector<const Volume*> hits;
189  if (angle == 0) {
190  // use ray
191  Ray3D obj(position, sdir);
192  hits = intersectSearchHierarchy(std::move(obj), m_bvhTop);
193  } else {
194  Acts::Frustum<double, 3, 4> obj(position, sdir, angle);
195  hits = intersectSearchHierarchy(std::move(obj), m_bvhTop);
196  }
197 
198  // have cells, decompose to surfaces
199  for (const Volume* vol : hits) {
200  const AbstractVolume* avol = dynamic_cast<const AbstractVolume*>(vol);
201  const std::vector<std::shared_ptr<const BoundarySurfaceT<AbstractVolume>>>&
202  boundarySurfaces = avol->boundarySurfaces();
203  for (const auto& bs : boundarySurfaces) {
204  const Surface& srf = bs->surfaceRepresentation();
206  srf.intersectionEstimate(gctx, position, sdir, false), &srf);
207 
208  if (sfi and sfi.intersection.pathLength > oLimit and
209  sfi.intersection.pathLength <= pLimit) {
210  sIntersections.push_back(std::move(sfi));
211  }
212  }
213  }
214 
215  // Sort according to the path length
216  if (options.navDir == forward) {
217  std::sort(sIntersections.begin(), sIntersections.end());
218  } else {
219  std::sort(sIntersections.begin(), sIntersections.end(), std::greater<>());
220  }
221 
222  return sIntersections;
223 }
224 
225 template <typename T>
226 std::vector<const Volume*> TrackingVolume::intersectSearchHierarchy(
227  const T obj, const Volume::BoundingBox* lnode) {
228  std::vector<const Volume*> hits;
229  hits.reserve(20); // arbitrary
230  do {
231  if (lnode->intersect(obj)) {
232  if (lnode->hasEntity()) {
233  // found primitive
234  // check obb to limit false positivies
235  const Volume* vol = lnode->entity();
236  const auto& obb = vol->orientedBoundingBox();
237  if (obb.intersect(obj.transformed(vol->itransform()))) {
238  hits.push_back(vol);
239  }
240  // we skip in any case, whether we actually hit the OBB or not
241  lnode = lnode->getSkip();
242  } else {
243  // go over children
244  lnode = lnode->getLeftChild();
245  }
246  } else {
247  lnode = lnode->getSkip();
248  }
249  } while (lnode != nullptr);
250 
251  return hits;
252 }