ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TrackingVolume.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file TrackingVolume.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2016-2019 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.cpp, Acts project
12 
13 #include <functional>
14 #include <utility>
15 
22 
24  : Volume(),
25  m_volumeMaterial(nullptr),
26  m_boundarySurfaces(),
27  m_confinedLayers(nullptr),
28  m_confinedVolumes(nullptr),
29  m_name("undefined") {}
30 
32  std::shared_ptr<const Transform3D> htrans, VolumeBoundsPtr volbounds,
33  const std::shared_ptr<const TrackingVolumeArray>& containedVolumeArray,
34  const std::string& volumeName)
35  : Volume(std::move(htrans), std::move(volbounds)),
36  m_volumeMaterial(nullptr),
37  m_boundarySurfaces(),
38  m_confinedLayers(nullptr),
39  m_confinedVolumes(containedVolumeArray),
40  m_name(volumeName) {
43 }
44 
45 // constructor for arguments
47  std::shared_ptr<const Transform3D> htrans, VolumeBoundsPtr volumeBounds,
48  std::shared_ptr<const IVolumeMaterial> volumeMaterial,
49  std::unique_ptr<const LayerArray> staticLayerArray,
50  std::shared_ptr<const TrackingVolumeArray> containedVolumeArray,
51  MutableTrackingVolumeVector denseVolumeVector,
52  const std::string& volumeName)
53  : Volume(std::move(htrans), std::move(volumeBounds)),
54  m_volumeMaterial(std::move(volumeMaterial)),
55  m_confinedLayers(std::move(staticLayerArray)),
56  m_confinedVolumes(std::move(containedVolumeArray)),
57  m_confinedDenseVolumes({}),
58  m_name(volumeName) {
59  createBoundarySurfaces();
60  interlinkLayers();
61  connectDenseBoundarySurfaces(denseVolumeVector);
62 }
63 
64 // constructor for arguments
66  std::shared_ptr<const Transform3D> htrans, VolumeBoundsPtr volbounds,
67  std::vector<std::unique_ptr<Volume::BoundingBox>> boxStore,
68  std::vector<std::unique_ptr<const Volume>> descendants,
69  const Volume::BoundingBox* top,
70  std::shared_ptr<const IVolumeMaterial> volumeMaterial,
71  const std::string& volumeName)
72  : Volume(std::move(htrans), std::move(volbounds)),
73  m_volumeMaterial(std::move(volumeMaterial)),
74  m_name(volumeName),
75  m_descendantVolumes(std::move(descendants)),
76  m_bvhTop(top) {
78  // we take a copy of the unique box pointers, but we want to
79  // store them as consts.
80  for (auto& uptr : boxStore) {
81  m_boundingBoxes.push_back(
82  std::unique_ptr<Volume::BoundingBox>(uptr.release()));
83  }
84 }
85 
87  delete m_glueVolumeDescriptor;
88 }
89 
91  const GeometryContext& /*gctx*/, const Vector3D& position,
92  const double tol) const {
93  // confined static volumes - highest hierarchy
94  if (m_confinedVolumes) {
95  return (m_confinedVolumes->object(position).get());
96  }
97 
98  // search for dense volumes
99  if (!m_confinedDenseVolumes.empty())
100  for (auto& denseVolume : m_confinedDenseVolumes)
101  if (denseVolume->inside(position, tol))
102  return denseVolume.get();
103 
104  // there is no lower sub structure
105  return this;
106 }
107 
109  const {
110  return (m_boundarySurfaces);
111 }
112 
114  MutableTrackingVolumeVector& confinedDenseVolumes) {
115  if (!confinedDenseVolumes.empty()) {
117  // Walk over each dense volume
118  for (auto& confDenseVol : confinedDenseVolumes) {
119  // Walk over each boundary surface of the volume
120  auto& boundSur = confDenseVol->boundarySurfaces();
121  for (unsigned int i = 0; i < boundSur.size(); i++) {
122  // Skip empty entries since we do not know the shape of the dense volume
123  // and therewith the used indices
124  if (boundSur.at(i) == nullptr) {
125  continue;
126  }
127 
128  // Use mother volume as the opposite direction of the already used
129  // direction
130  auto mutableBs =
132  boundSur.at(i));
133  if (mutableBs->m_insideVolume != nullptr &&
134  mutableBs->m_outsideVolume == nullptr) {
136  mutableBs->attachVolume(this, bo);
137  } else {
138  if (mutableBs->m_insideVolume == nullptr &&
139  mutableBs->m_outsideVolume != nullptr) {
141  mutableBs->attachVolume(this, bo);
142  }
143  }
144 
145  // Update the boundary
146  confDenseVol->updateBoundarySurface((BoundarySurfaceFace)i, mutableBs);
147  }
148  // Store the volume
149  m_confinedDenseVolumes.push_back(std::move(confDenseVol));
150  }
151  }
152 }
153 
155  // transform Surfaces To BoundarySurfaces
156  std::vector<std::shared_ptr<const Surface>> surfaces =
157  Volume::volumeBounds().decomposeToSurfaces(m_transform.get());
158 
159  // counter to flip the inner/outer position for Cylinders
160  int sfCounter = 0;
161  size_t sfNumber = surfaces.size();
162 
163  for (auto& sf : surfaces) {
164  // flip inner/outer for cylinders
165  TrackingVolume* inner =
166  (sf->type() == Surface::Cylinder && sfCounter == 3 && sfNumber > 3)
167  ? nullptr
168  : this;
169  TrackingVolume* outer = (inner) != nullptr ? nullptr : this;
170  // create the boundary surface
171  m_boundarySurfaces.push_back(
172  std::make_shared<const BoundarySurfaceT<TrackingVolume>>(std::move(sf),
173  inner, outer));
174  // increase the counter
175  ++sfCounter;
176  }
177 }
178 
180  BoundarySurfaceFace bsfMine,
181  TrackingVolume* neighbor,
182  BoundarySurfaceFace bsfNeighbor) {
183  // Find the connection of the two tracking volumes: binR returns the center
184  // except for cylindrical volumes
185  Vector3D bPosition(binningPosition(gctx, binR));
186  Vector3D distance =
187  Vector3D(neighbor->binningPosition(gctx, binR) - bPosition);
188  // glue to the face
189  std::shared_ptr<const BoundarySurfaceT<TrackingVolume>> bSurfaceMine =
190  boundarySurfaces().at(bsfMine);
191  // @todo - complex glueing could be possible with actual intersection for the
192  // normal vector
193  Vector3D nvector =
194  bSurfaceMine->surfaceRepresentation().normal(gctx, bPosition);
195  // estimate the orientation
196  BoundaryOrientation bOrientation =
197  (nvector.dot(distance) > 0.) ? outsideVolume : insideVolume;
198  // The easy case :
199  // - no glue volume descriptors on either side
200  if ((m_glueVolumeDescriptor == nullptr) ||
201  m_glueVolumeDescriptor->glueVolumes(bsfMine) == nullptr) {
202  // the boundary orientation
203  auto mutableBSurfaceMine =
205  mutableBSurfaceMine->attachVolume(neighbor, bOrientation);
206  // Make sure you keep the boundary material if there
207  const Surface& neighborSurface =
208  neighbor->m_boundarySurfaces.at(bsfNeighbor)->surfaceRepresentation();
209  auto neighborMaterial = neighborSurface.surfaceMaterialSharedPtr();
210  const Surface& mySurface = bSurfaceMine->surfaceRepresentation();
211  auto myMaterial = mySurface.surfaceMaterialSharedPtr();
212  // Keep the neighbor material
213  if (myMaterial == nullptr and neighborMaterial != nullptr) {
214  Surface* myMutbableSurface = const_cast<Surface*>(&mySurface);
215  myMutbableSurface->assignSurfaceMaterial(neighborMaterial);
216  }
217  // Now set it to the neighbor volume
218  (neighbor->m_boundarySurfaces).at(bsfNeighbor) = bSurfaceMine;
219  }
220 }
221 
223  const GeometryContext& gctx, BoundarySurfaceFace bsfMine,
224  const std::shared_ptr<TrackingVolumeArray>& neighbors,
225  BoundarySurfaceFace bsfNeighbor) {
226  // find the connection of the two tracking volumes : binR returns the center
227  // except for cylindrical volumes
228  std::shared_ptr<const TrackingVolume> nRefVolume =
229  neighbors->arrayObjects().at(0);
230  // get the distance
231  Vector3D bPosition(binningPosition(gctx, binR));
232  Vector3D distance =
233  Vector3D(nRefVolume->binningPosition(gctx, binR) - bPosition);
234  // take the normal at the binning positio
235  std::shared_ptr<const BoundarySurfaceT<TrackingVolume>> bSurfaceMine =
236  boundarySurfaces().at(bsfMine);
237  // @todo - complex glueing could be possible with actual intersection for the
238  // normal vector
239  Vector3D nvector =
240  bSurfaceMine->surfaceRepresentation().normal(gctx, bPosition);
241  // estimate the orientation
242  BoundaryOrientation bOrientation =
243  (nvector.dot(distance) > 0.) ? outsideVolume : insideVolume;
244  // the easy case :
245  // - no glue volume descriptors on either side
246  if ((m_glueVolumeDescriptor == nullptr) ||
247  !m_glueVolumeDescriptor->glueVolumes(bsfMine)) {
248  // the boundary orientation
249  auto mutableBSurfaceMine =
251  mutableBSurfaceMine->attachVolumeArray(neighbors, bOrientation);
252  // now set it to the neighbor volumes - the optised way
253  for (auto& nVolume : neighbors->arrayObjects()) {
254  auto mutableNVolume = std::const_pointer_cast<TrackingVolume>(nVolume);
255  (mutableNVolume->m_boundarySurfaces).at(bsfNeighbor) = bSurfaceMine;
256  }
257  }
258 }
259 
261  std::shared_ptr<const ISurfaceMaterial> surfaceMaterial,
262  BoundarySurfaceFace bsFace) {
263  auto bSurface = m_boundarySurfaces.at(bsFace);
264  Surface* surface = const_cast<Surface*>(&bSurface->surfaceRepresentation());
265  surface->assignSurfaceMaterial(std::move(surfaceMaterial));
266 }
267 
271  bool checkmaterial) {
272  if (checkmaterial) {
273  auto cMaterialPtr = m_boundarySurfaces.at(bsf)
274  ->surfaceRepresentation()
275  .surfaceMaterialSharedPtr();
276  auto bsMaterial = bs->surfaceRepresentation().surfaceMaterial();
277  if (cMaterialPtr != nullptr && bsMaterial == nullptr) {
278  Surface* surface = const_cast<Surface*>(&bs->surfaceRepresentation());
279  surface->assignSurfaceMaterial(cMaterialPtr);
280  }
281  }
282  m_boundarySurfaces.at(bsf) = std::move(bs);
283 }
284 
286  GlueVolumesDescriptor* gvd) {
287  delete m_glueVolumeDescriptor;
288  m_glueVolumeDescriptor = gvd;
289 }
290 
292  if (m_glueVolumeDescriptor == nullptr) {
293  m_glueVolumeDescriptor = new GlueVolumesDescriptor;
294  }
295  return (*m_glueVolumeDescriptor);
296 }
297 
298 void Acts::TrackingVolume::synchronizeLayers(double envelope) const {
299  // case a : Layers exist
300  // msgstream << MSG::VERBOSE << " -> synchronizing Layer dimensions of
301  // TrackingVolume '" << volumeName() << "'." << endreq;
302 
303  if (m_confinedLayers) {
304  // msgstream << MSG::VERBOSE << " ---> working on " <<
305  // m_confinedLayers->arrayObjects().size() << " (material+navigation)
306  // layers." << endreq;
307  for (auto& clayIter : m_confinedLayers->arrayObjects()) {
308  if (clayIter) {
309  // @todo implement syncrhonize layer
310  // if (clayIter->surfaceRepresentation().type() == Surface::Cylinder &&
311  // !(center().isApprox(clayIter->surfaceRepresentation().center())) )
312  // clayIter->resizeAndRepositionLayer(volumeBounds(),center(),envelope);
313  // else
314  // clayIter->resizeLayer(volumeBounds(),envelope);
315  } // else
316  // msgstream << MSG::WARNING << " ---> found 0 pointer to layer,
317  // indicates problem." << endreq;
318  }
319  }
320 
321  // case b : container volume -> step down
322  if (m_confinedVolumes) {
323  // msgstream << MSG::VERBOSE << " ---> no confined layers, working on " <<
324  // m_confinedVolumes->arrayObjects().size() << " confined volumes." <<
325  // endreq;
326  for (auto& cVolumesIter : m_confinedVolumes->arrayObjects()) {
327  cVolumesIter->synchronizeLayers(envelope);
328  }
329  }
330 }
331 
333  if (m_confinedLayers) {
334  auto& layers = m_confinedLayers->arrayObjects();
335 
336  // forward register the last one as the previous one
337  // first <- | -> second, first <- | -> second, first <- | -> second
338  const Layer* lastLayer = nullptr;
339  for (auto& layerPtr : layers) {
340  // we'll need to mutate our confined layers to perform this operation
341  Layer& mutableLayer = *(std::const_pointer_cast<Layer>(layerPtr));
342  // register the layers
343  mutableLayer.m_nextLayerUtility = m_confinedLayers->binUtility();
344  mutableLayer.m_nextLayers.first = lastLayer;
345  // register the volume
346  mutableLayer.encloseTrackingVolume(*this);
347  // remember the last layer
348  lastLayer = &mutableLayer;
349  }
350  // backward loop
351  lastLayer = nullptr;
352  for (auto layerIter = layers.rbegin(); layerIter != layers.rend();
353  ++layerIter) {
354  // set the other next volume
355  Layer& mutableLayer = *(std::const_pointer_cast<Layer>(*layerIter));
356  mutableLayer.m_nextLayers.second = lastLayer;
357  lastLayer = &mutableLayer;
358  }
359  }
360 }
361 
363  const IMaterialDecorator* materialDecorator,
364  std::map<std::string, const TrackingVolume*>& volumeMap, size_t& vol) {
365  // insert the volume into the map
366  volumeMap[volumeName()] = this;
367 
368  // we can construct the volume ID from this
369  auto volumeID = GeometryID().setVolume(++vol);
370  // assign the Volume ID to the volume itself
371  auto thisVolume = const_cast<TrackingVolume*>(this);
372  thisVolume->assignGeoID(volumeID);
373 
374  // assign the material if you have a decorator
375  if (materialDecorator != nullptr) {
376  materialDecorator->decorate(*thisVolume);
377  }
378  if (thisVolume->volumeMaterial() == nullptr && thisVolume->motherVolume() &&
379  thisVolume->motherVolume()->volumeMaterial() != nullptr) {
380  auto protoMaterial = dynamic_cast<const Acts::ProtoVolumeMaterial*>(
381  thisVolume->motherVolume()->volumeMaterial());
382  if (protoMaterial == nullptr) {
383  thisVolume->assignVolumeMaterial(
384  thisVolume->motherVolume()->volumeMaterialSharedPtr());
385  }
386  }
387 
388  this->assignGeoID(volumeID);
389  // loop over the boundary surfaces
390  GeometryID::Value iboundary = 0;
391  // loop over the boundary surfaces
392  for (auto& bSurfIter : boundarySurfaces()) {
393  // get the intersection soltuion
394  auto& bSurface = bSurfIter->surfaceRepresentation();
395  // create the boundary surface id
396  auto boundaryID = GeometryID(volumeID).setBoundary(++iboundary);
397  // now assign to the boundary surface
398  auto& mutableBSurface = *(const_cast<Surface*>(&bSurface));
399  mutableBSurface.assignGeoID(boundaryID);
400  // assign the material if you have a decorator
401  if (materialDecorator != nullptr) {
402  materialDecorator->decorate(mutableBSurface);
403  }
404  }
405 
406  // A) this is NOT a container volume, volumeID is already incremented
407  if (!m_confinedVolumes) {
408  // loop over the confined layers
409  if (m_confinedLayers) {
410  GeometryID::Value ilayer = 0;
411  // loop over the layers
412  for (auto& layerPtr : m_confinedLayers->arrayObjects()) {
413  // create the layer identification
414  auto layerID = GeometryID(volumeID).setLayer(++ilayer);
415  // now close the geometry
416  auto mutableLayerPtr = std::const_pointer_cast<Layer>(layerPtr);
417  mutableLayerPtr->closeGeometry(materialDecorator, layerID);
418  }
419  } else if (m_bvhTop != nullptr) {
420  GeometryID::Value isurface = 0;
421  for (const auto& descVol : m_descendantVolumes) {
422  // Attempt to cast to AbstractVolume: only one we'll handle
423  const AbstractVolume* avol =
424  dynamic_cast<const AbstractVolume*>(descVol.get());
425  if (avol != nullptr) {
426  const auto& bndSrf = avol->boundarySurfaces();
427  for (const auto& bnd : bndSrf) {
428  const auto& srf = bnd->surfaceRepresentation();
429  Surface* mutableSurfcePtr = const_cast<Surface*>(&srf);
430  auto geoID = GeometryID(volumeID).setSensitive(++isurface);
431  mutableSurfcePtr->assignGeoID(geoID);
432  }
433  }
434  }
435  }
436  } else {
437  // B) this is a container volume, go through sub volume
438  // do the loop
439  for (auto& volumesIter : m_confinedVolumes->arrayObjects()) {
440  auto mutableVolumesIter =
442  mutableVolumesIter->setMotherVolume(this);
443  mutableVolumesIter->closeGeometry(materialDecorator, volumeMap, vol);
444  }
445  }
446 
447  if (!m_confinedDenseVolumes.empty()) {
448  for (auto& volumesIter : m_confinedDenseVolumes) {
449  auto mutableVolumesIter =
451  mutableVolumesIter->setMotherVolume(this);
452  mutableVolumesIter->closeGeometry(materialDecorator, volumeMap, vol);
453  }
454  }
455 }
456 
458  const std::function<void(const Acts::Surface*)>& visitor) const {
459  if (!m_confinedVolumes) {
460  // no sub volumes => loop over the confined layers
461  if (m_confinedLayers) {
462  for (const auto& layer : m_confinedLayers->arrayObjects()) {
463  if (layer->surfaceArray() == nullptr) {
464  // no surface array (?)
465  continue;
466  }
467  for (const auto& srf : layer->surfaceArray()->surfaces()) {
468  visitor(srf);
469  }
470  }
471  }
472  } else {
473  // contains sub volumes
474  for (const auto& volume : m_confinedVolumes->arrayObjects()) {
475  volume->visitSurfaces(visitor);
476  }
477  }
478 }