Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Layer.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file Layer.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2016-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 
16 
17 #include <algorithm>
18 #include <functional>
19 #include <iterator>
20 #include <vector>
21 
22 Acts::Layer::Layer(std::unique_ptr<SurfaceArray> surfaceArray, double thickness,
23  std::unique_ptr<ApproachDescriptor> ades, LayerType laytyp)
24  : m_nextLayers(NextLayers(nullptr, nullptr)),
25  m_surfaceArray(surfaceArray.release()),
26  m_layerThickness(thickness),
27  m_approachDescriptor(nullptr),
28  m_representingVolume(nullptr),
29  m_layerType(laytyp),
30  m_ssRepresentingSurface(1) {
31  if (ades) {
32  ades->registerLayer(*this);
34  m_ssApproachSurfaces = 1; // indicates existence
35  }
36  // indicates existence of sensitive surfaces
37  if (m_surfaceArray) {
39  }
40 }
41 
43  return m_approachDescriptor.get();
44 }
45 
47  return const_cast<ApproachDescriptor*>(m_approachDescriptor.get());
48 }
49 
50 void Acts::Layer::closeGeometry(const IMaterialDecorator* materialDecorator,
51  const GeometryIdentifier& layerID,
52  const GeometryIdentifierHook& hook,
53  const Logger& logger) {
54  // set the volumeID of this
55  assignGeometryId(layerID);
56  // assign to the representing surface
57  Surface* rSurface = const_cast<Surface*>(&surfaceRepresentation());
58  if (materialDecorator != nullptr) {
59  materialDecorator->decorate(*rSurface);
60  }
61  ACTS_DEBUG("layerID: " << layerID);
62 
63  rSurface->assignGeometryId(layerID);
64 
65  // also find out how the sub structure is defined
66  if (surfaceRepresentation().surfaceMaterial() != nullptr) {
67  m_ssRepresentingSurface = 2;
68  }
69  // loop over the approach surfaces
70  if (m_approachDescriptor) {
71  // indicates the existence of approach surfaces
72  m_ssApproachSurfaces = 1;
73  // loop through the approachSurfaces and assign unique GeomeryID
74  GeometryIdentifier::Value iasurface = 0;
75  for (auto& aSurface : m_approachDescriptor->containedSurfaces()) {
76  auto asurfaceID = GeometryIdentifier(layerID).setApproach(++iasurface);
77  auto mutableASurface = const_cast<Surface*>(aSurface);
78  mutableASurface->assignGeometryId(asurfaceID);
79  if (materialDecorator != nullptr) {
80  materialDecorator->decorate(*mutableASurface);
81  }
82  // if any of the approach surfaces has material
83  if (aSurface->surfaceMaterial() != nullptr) {
84  m_ssApproachSurfaces = 2;
85  }
86  }
87  }
88  // check if you have sensitive surfaces
89  if (m_surfaceArray) {
90  // indicates the existence of sensitive surfaces
91  m_ssSensitiveSurfaces = 1;
92  // loop sensitive surfaces and assign unique GeometryIdentifier
93  GeometryIdentifier::Value issurface = 0;
94  for (auto& sSurface : m_surfaceArray->surfaces()) {
95  auto ssurfaceID = GeometryIdentifier(layerID).setSensitive(++issurface);
96  ssurfaceID = hook.decorateIdentifier(ssurfaceID, *sSurface);
97  auto mutableSSurface = const_cast<Surface*>(sSurface);
98  mutableSSurface->assignGeometryId(ssurfaceID);
99  if (materialDecorator != nullptr) {
100  materialDecorator->decorate(*mutableSSurface);
101  }
102  // if any of the sensitive surfaces has material
103  if (sSurface->surfaceMaterial() != nullptr) {
104  m_ssSensitiveSurfaces = 2;
105  }
106  }
107  }
108 }
109 
110 boost::container::small_vector<Acts::SurfaceIntersection, 10>
112  const GeometryContext& gctx, const Vector3& position,
113  const Vector3& direction, const NavigationOptions<Surface>& options) const {
114  // the list of valid intersection
115  boost::container::small_vector<SurfaceIntersection, 10> sIntersections;
116 
117  // fast exit - there is nothing to
118  if (!m_surfaceArray || !m_approachDescriptor) {
119  return sIntersections;
120  }
121 
122  // (0) End surface check
123  // @todo: - we might be able to skip this by use of options.pathLimit
124  // check if you have to stop at the endSurface
125  double pathLimit = options.pathLimit;
126  double overstepLimit = options.overstepLimit;
127  if (options.endObject != nullptr) {
128  // intersect the end surface
129  // - it is the final one don't use the boundary check at all
130  SurfaceIntersection endInter =
131  options.endObject
132  ->intersect(gctx, position, direction, BoundaryCheck(true))
133  .closest();
134  // non-valid intersection with the end surface provided at this layer
135  // indicates wrong direction or faulty setup
136  // -> do not return compatible surfaces since they may lead you on a wrong
137  // navigation path
138  if (endInter) {
139  pathLimit = endInter.pathLength();
140  } else {
141  return sIntersections;
142  }
143  } else {
144  // compatibleSurfaces() should only be called when on the layer,
145  // i.e. the maximum path limit is given by the layer thickness times
146  // path correction, we take a safety factor of 1.5
147  // -> this avoids punch through for cylinders
148  double pCorrection =
149  surfaceRepresentation().pathCorrection(gctx, position, direction);
150  pathLimit = 1.5 * thickness() * pCorrection;
151  }
152 
153  // lemma 0 : accept the surface
154  auto acceptSurface = [&options](const Surface& sf,
155  bool sensitive = false) -> bool {
156  // surface is sensitive and you're asked to resolve
157  if (sensitive && options.resolveSensitive) {
158  return true;
159  }
160  // next option: it's a material surface and you want to have it
161  if (options.resolveMaterial && sf.surfaceMaterial() != nullptr) {
162  return true;
163  }
164  // last option: resolve all
165  return options.resolvePassive;
166  };
167 
168  // lemma 1 : check and fill the surface
169  // [&sIntersections, &options, &parameters
170  auto processSurface = [&](const Surface& sf, bool sensitive = false) {
171  // veto if it's start or end surface
172  if (options.startObject == &sf || options.endObject == &sf) {
173  return;
174  }
175  // veto if it doesn't fit the prescription
176  if (!acceptSurface(sf, sensitive)) {
177  return;
178  }
179  bool boundaryCheck = options.boundaryCheck;
180  if (std::find(options.externalSurfaces.begin(),
181  options.externalSurfaces.end(),
182  sf.geometryId()) != options.externalSurfaces.end()) {
183  boundaryCheck = false;
184  }
185  // the surface intersection
187  sf.intersect(gctx, position, direction, boundaryCheck);
188  for (const auto& sfi : sfmi.split()) {
189  // check if intersection is valid and pathLimit has not been exceeded
190  if (sfi &&
191  detail::checkIntersection(sfi.intersection(), pathLimit,
192  overstepLimit, s_onSurfaceTolerance)) {
193  sIntersections.push_back(sfi);
194  }
195  }
196  };
197 
198  // (A) approach descriptor section
199  //
200  // the approach surfaces are in principle always testSurfaces
201  // - the surface on approach is excluded via the veto
202  // - the surfaces are only collected if needed
203  if (m_approachDescriptor &&
204  (options.resolveMaterial || options.resolvePassive)) {
205  // the approach surfaces
206  const std::vector<const Surface*>& approachSurfaces =
207  m_approachDescriptor->containedSurfaces();
208  // we loop through and veto
209  // - if the approach surface is the parameter surface
210  // - if the surface is not compatible with the collect
211  for (auto& aSurface : approachSurfaces) {
212  processSurface(*aSurface);
213  }
214  }
215 
216  // (B) sensitive surface section
217  //
218  // check the sensitive surfaces if you have some
219  if (m_surfaceArray && (options.resolveMaterial || options.resolvePassive ||
220  options.resolveSensitive)) {
221  // get the candidates
222  const std::vector<const Surface*>& sensitiveSurfaces =
223  m_surfaceArray->neighbors(position);
224  // loop through and veto
225  // - if the approach surface is the parameter surface
226  // - if the surface is not compatible with the type(s) that are collected
227  for (auto& sSurface : sensitiveSurfaces) {
228  processSurface(*sSurface, true);
229  }
230  }
231 
232  // (C) representing surface section
233  //
234  // the layer surface itself is a testSurface
235  const Surface* layerSurface = &surfaceRepresentation();
236  processSurface(*layerSurface);
237 
238  // Sort by object address
239  std::sort(
240  sIntersections.begin(), sIntersections.end(),
241  [](const auto& a, const auto& b) { return a.object() < b.object(); });
242  // Now look for duplicates. As we just sorted by path length, duplicates
243  // should be subsequent
244  auto it = std::unique(
245  sIntersections.begin(), sIntersections.end(),
246  [](const SurfaceIntersection& a, const SurfaceIntersection& b) -> bool {
247  return a.object() == b.object();
248  });
249 
250  // resize to remove all items that are past the unique range
251  sIntersections.resize(std::distance(sIntersections.begin(), it),
253 
254  // sort according to the path length
255  std::sort(sIntersections.begin(), sIntersections.end(),
257 
258  return sIntersections;
259 }
260 
262  const GeometryContext& gctx, const Vector3& position,
263  const Vector3& direction, const NavigationOptions<Layer>& options) const {
264  // resolve directive based by options
265  // - options.resolvePassive is on -> always
266  // - options.resolveSensitive is on -> always
267  // - options.resolveMaterial is on
268  // && either sensitive or approach surfaces have material
269  bool resolvePS = options.resolveSensitive || options.resolvePassive;
270  bool resolveMS = options.resolveMaterial &&
271  (m_ssSensitiveSurfaces > 1 || m_ssApproachSurfaces > 1 ||
272  (surfaceRepresentation().surfaceMaterial() != nullptr));
273 
274  // The Limits: current path & overstepping
275  double pLimit = options.pathLimit;
276  double oLimit = options.overstepLimit;
277  // TODO this should be configurable
279 
280  // Helper function to find valid intersection
281  auto findValidIntersection =
282  [&](const SurfaceMultiIntersection& sfmi) -> SurfaceIntersection {
283  for (const auto& sfi : sfmi.split()) {
284  if (sfi && detail::checkIntersection(sfi.intersection(), pLimit, oLimit,
285  tolerance)) {
286  return sfi;
287  }
288  }
289 
290  // Return an invalid one
292  };
293 
294  // Approach descriptor present and resolving is necessary
295  if (m_approachDescriptor && (resolvePS || resolveMS)) {
296  SurfaceIntersection aSurface = m_approachDescriptor->approachSurface(
297  gctx, position, direction, options.boundaryCheck, pLimit, oLimit,
298  tolerance);
299  return aSurface;
300  }
301 
302  // Intersect and check the representing surface
303  const Surface& rSurface = surfaceRepresentation();
304  auto sIntersection =
305  rSurface.intersect(gctx, position, direction, options.boundaryCheck);
306  return findValidIntersection(sIntersection);
307 }