EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CylinderVolumeHelper.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file CylinderVolumeHelper.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2016-2020 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 
26 
27 #include <cmath>
28 
30  const Acts::CylinderVolumeHelper::Config& cvhConfig,
31  std::unique_ptr<const Logger> logger)
32  : Acts::ITrackingVolumeHelper(), m_cfg(), m_logger(std::move(logger)) {
33  setConfiguration(cvhConfig);
34 }
35 
36 // configuration
38  const Acts::CylinderVolumeHelper::Config& cvhConfig) {
39  // @todo check consistency
40  // copy the configuration
41  m_cfg = cvhConfig;
42 }
43 
45  std::unique_ptr<const Logger> newLogger) {
46  m_logger = std::move(newLogger);
47 }
48 
49 std::shared_ptr<Acts::TrackingVolume>
51  const GeometryContext& gctx, const LayerVector& layers,
52  std::shared_ptr<const IVolumeMaterial> volumeMaterial,
53  std::shared_ptr<const VolumeBounds> volumeBounds,
55  const std::string& volumeName, BinningType bType) const {
56  // the final one to build / sensitive Volume / Bounds
57  MutableTrackingVolumePtr tVolume = nullptr;
58  // the layer array
59  std::unique_ptr<const LayerArray> layerArray = nullptr;
60 
61  // Cases are:
62  // (1) volumeBounds && transform : use both information
63  // (2) volumeBounds && transform==identity : centered around 0, but with
64  // given bounds
65  // (3) !volumeBounds && transform : estimate size from layers,
66  // use transform
67  // (4) !volumeBounds && transform==identity : estimate size &
68  // translation from layers
69  bool idTrf = transform.isApprox(s_idTransform);
70 
71  const CylinderVolumeBounds* cylinderBounds = nullptr;
72  // this is the implementation of CylinderVolumeHelper
73  if (volumeBounds) {
74  cylinderBounds =
75  dynamic_cast<const CylinderVolumeBounds*>(volumeBounds.get());
76  if (cylinderBounds == nullptr) {
78  "[!] Problem: given bounds are not cylindrical - return nullptr");
79  return tVolume;
80  }
81  }
82  // this is only needed if layers are provided
83  if (!layers.empty()) {
84  // the raw data
85  double rMinRaw = 0.;
86  double rMaxRaw = 0.;
87  double zMinRaw = 0.;
88  double zMaxRaw = 0.;
89 
90  BinningValue bValue = binR;
91 
92  // check the dimension and fill raw data
93  if (not estimateAndCheckDimension(gctx, layers, cylinderBounds, transform,
94  rMinRaw, rMaxRaw, zMinRaw, zMaxRaw,
95  bValue, bType)) {
97  "[!] Problem with given dimensions - return nullptr and "
98  "delete provided objects");
99  // delete if newly created bounds
100  if (volumeBounds == nullptr) {
101  delete cylinderBounds;
102  }
103  return tVolume;
104  }
105  // get the zMin/Max
106  double zMin =
107  (not idTrf ? transform.translation().z() : 0.) +
108  (cylinderBounds != nullptr
109  ? -cylinderBounds->get(CylinderVolumeBounds::eHalfLengthZ)
110  : 0.);
111  double zMax = (not idTrf ? transform.translation().z() : 0.) +
112  (cylinderBounds != nullptr
113  ? cylinderBounds->get(CylinderVolumeBounds::eHalfLengthZ)
114  : 0.);
115  // get the rMin/rmAx
116  double rMin = cylinderBounds != nullptr
117  ? cylinderBounds->get(CylinderVolumeBounds::eMinR)
118  : rMinRaw;
119  double rMax = cylinderBounds != nullptr
120  ? cylinderBounds->get(CylinderVolumeBounds::eMaxR)
121  : rMaxRaw;
122 
123  ACTS_VERBOSE(
124  "Filling the layers into an appropriate layer array - with "
125  "binningValue = "
126  << bValue);
127 
128  // create the Layer Array
129  layerArray = (bValue == binR)
130  ? m_cfg.layerArrayCreator->layerArray(gctx, layers, rMin,
131  rMax, bType, bValue)
132  : m_cfg.layerArrayCreator->layerArray(gctx, layers, zMin,
133  zMax, bType, bValue);
134 
135  } // layers are created and done
136  // make sure the ownership of the bounds is correct
137  std::shared_ptr<const VolumeBounds> volumeBoundsFinal =
138  volumeBounds.get() != nullptr
139  ? volumeBounds
140  : std::shared_ptr<const VolumeBounds>(cylinderBounds);
141  // finally create the TrackingVolume
142  tVolume = TrackingVolume::create(transform, volumeBoundsFinal, volumeMaterial,
143  std::move(layerArray), nullptr, mtvVector,
144  volumeName);
145  // screen output
146  ACTS_VERBOSE(
147  "Created cylindrical volume at z-position :" << tVolume->center().z());
148  ACTS_VERBOSE(" created bounds : " << tVolume->volumeBounds());
149  // return the constructed TrackingVolume
150  return tVolume;
151 }
152 
153 std::shared_ptr<Acts::TrackingVolume>
155  const GeometryContext& gctx, const LayerVector& layers,
156  MutableTrackingVolumeVector mtvVector,
157  std::shared_ptr<const IVolumeMaterial> volumeMaterial, double rMin,
158  double rMax, double zMin, double zMax, const std::string& volumeName,
159  BinningType bType) const {
160  // The Bounds to e created
161  CylinderVolumeBounds* cBounds = nullptr;
162 
163  // Screen output
164  ACTS_VERBOSE("Create cylindrical TrackingVolume '" << volumeName << "'.");
165  ACTS_VERBOSE(" -> with given dimensions of (rMin/rMax/zMin/Max) = "
166  << rMin << " / " << rMax << " / " << zMin << " / " << zMax);
167 
168  // check for consistency
169  if (zMin > zMax || rMin > rMax) {
170  ACTS_WARNING("Inconsistent dimensions given :"
171  << ((zMin > zMax) ? " zMin > zMax (" : " rMin > rMax (")
172  << ((zMin > zMax) ? zMin : rMin) << " > "
173  << ((zMin > zMax) ? zMax : rMax) << " ) - return 0");
174  return nullptr;
175  }
176 
177  // create a Transform3D and VolumeBounds out of the zMin/zMax
178  double halflengthZ = 0.5 * (zMax - zMin);
179  double zPosition = 0.5 * (zMin + zMax);
180  zPosition = std::abs(zPosition) < 0.1 ? 0. : zPosition;
181 
182  // now create the cylinder volume bounds
183  cBounds = new CylinderVolumeBounds(rMin, rMax, halflengthZ);
184 
185  // transform
186  const Transform3D transform = Transform3D(Translation3D(0., 0., zPosition));
187  // call to the creation method with Bounds & Translation3D
188  return createTrackingVolume(gctx, layers, volumeMaterial,
189  VolumeBoundsPtr(cBounds), mtvVector, transform,
190  volumeName, bType);
191 }
192 
193 std::shared_ptr<Acts::TrackingVolume>
195  const GeometryContext& gctx, MutableTrackingVolumeVector& mtvVector,
196  std::shared_ptr<const IVolumeMaterial> volumeMaterial, double rMin,
197  double rMax, double zMin, double zMax, unsigned int materialLayers,
198  bool cylinder, const std::string& volumeName) const {
199  // screen output
200  ACTS_VERBOSE("Create cylindrical gap TrackingVolume '"
201  << volumeName << "' with (rMin/rMax/zMin/Max) = ");
202  ACTS_VERBOSE('\t' << rMin << " / " << rMax << " / " << zMin << " / " << zMax);
203 
204  // assing min/max
205  double min = cylinder ? rMin : zMin;
206  double max = cylinder ? rMax : zMax;
207 
208  // create the layer r/z positions
209  std::vector<double> layerPositions;
210  if (materialLayers > 1) {
211  double step = cylinder ? (max - min) / (materialLayers - 1)
212  : (max - min) / (materialLayers - 1);
213  for (unsigned int il = 0; il < materialLayers; ++il) {
214  layerPositions.push_back(min + il * step);
215  }
216  } else {
217  layerPositions.push_back(0.5 * (min + max));
218  }
219 
220  // now call the main method
221  return createGapTrackingVolume(gctx, mtvVector, volumeMaterial, rMin, rMax,
222  zMin, zMax, layerPositions, cylinder,
223  volumeName, arbitrary);
224 }
225 
226 std::shared_ptr<Acts::TrackingVolume>
228  const GeometryContext& gctx, MutableTrackingVolumeVector& mtvVector,
229  std::shared_ptr<const IVolumeMaterial> volumeMaterial, double rMin,
230  double rMax, double zMin, double zMax,
231  const std::vector<double>& layerPositions, bool cylinder,
232  const std::string& volumeName, BinningType bType) const {
233  // screen output
234  ACTS_VERBOSE("Create cylindrical gap TrackingVolume '"
235  << volumeName << "' with (rMin/rMax/zMin/Max) = ");
236  ACTS_VERBOSE('\t' << rMin << " / " << rMax << " / " << zMin << " / " << zMax);
237 
238  // create the layers
239  LayerVector layers;
240  layers.reserve(layerPositions.size());
241 
242  std::vector<double>::const_iterator layerPropIter = layerPositions.begin();
243  std::vector<double>::const_iterator layerPropEnd = layerPositions.end();
244  for (; layerPropIter != layerPropEnd; ++layerPropIter) {
245  // create cylinder layers
246  if (cylinder) {
247  // take envelopes into account
248  double zMinLayer = zMin;
249  double zMaxLayer = zMax;
250  // create the layer
251  layers.push_back(createCylinderLayer(
252  0.5 * (zMinLayer + zMaxLayer), (*layerPropIter),
253  std::abs(0.5 * (zMaxLayer - zMinLayer)), m_cfg.passiveLayerThickness,
254  m_cfg.passiveLayerPhiBins, m_cfg.passiveLayerRzBins));
255 
256  } else {
257  // take the envelopes into account
258  double rMinLayer = rMin;
259  double rMaxLayer = rMax;
260  // create the layer
261  layers.push_back(createDiscLayer(
262  (*layerPropIter), rMinLayer, rMaxLayer, m_cfg.passiveLayerThickness,
263  m_cfg.passiveLayerPhiBins, m_cfg.passiveLayerRzBins));
264  }
265  }
266  // now call the createTrackingVolume() method
267  return createTrackingVolume(gctx, layers, mtvVector, volumeMaterial, rMin,
268  rMax, zMin, zMax, volumeName, bType);
269 }
270 
271 std::shared_ptr<Acts::TrackingVolume>
273  const GeometryContext& gctx, const TrackingVolumeVector& volumes) const {
274  // check if you have more than one volume
275  if (volumes.size() <= (size_t)1) {
276  ACTS_WARNING(
277  "None (only one) TrackingVolume given to create container "
278  "volume (min required: 2) - returning 0 ");
279  return nullptr;
280  }
281  // screen output
282  std::string volumeName = "{ ";
283  ACTS_VERBOSE("[start] Creating a container volume with " << volumes.size()
284  << " sub volumes:");
285  // volumes need to be sorted in either r or z - both increasing
286  // set the iterator to the volumes, the first and the end
287  auto firstVolume = volumes.begin();
288  auto lastVolume = volumes.end();
289 
290  for (size_t ivol = 0; firstVolume != lastVolume; ++firstVolume, ++ivol) {
291  ACTS_VERBOSE(" - volume (" << ivol
292  << ") is : " << (*firstVolume)->volumeName());
293  ACTS_VERBOSE(" at position : " << (*firstVolume)->center().x() << ", "
294  << (*firstVolume)->center().y() << ", "
295  << (*firstVolume)->center().z());
296 
297  ACTS_VERBOSE(" with bounds : " << (*firstVolume)->volumeBounds());
298  // put the name together
299  volumeName += (*firstVolume)->volumeName();
300  if (ivol + 1 < volumes.size()) {
301  volumeName += " | ";
302  }
303  }
304  // close the volume name
305  volumeName += " }";
306  // reset the iterator -----
307  firstVolume = volumes.begin();
308  --lastVolume; // set to the last volume
309 
310  if (firstVolume == lastVolume) {
311  ACTS_WARNING(
312  "Only one TrackingVolume given to create Top level volume "
313  "(min required: 2) - returning 0 ");
314  return nullptr;
315  }
316  // get the bounds
317  const CylinderVolumeBounds* firstVolumeBounds =
318  dynamic_cast<const CylinderVolumeBounds*>(
319  &((*firstVolume)->volumeBounds()));
320  const CylinderVolumeBounds* lastVolumeBounds =
321  dynamic_cast<const CylinderVolumeBounds*>(
322  &((*lastVolume)->volumeBounds()));
323  // check the dynamic cast
324  if ((firstVolumeBounds == nullptr) || (lastVolumeBounds == nullptr)) {
325  ACTS_WARNING(
326  "VolumeBounds given are not of type: CylinderVolumeBounds "
327  "(required) - returning 0 ");
328  return nullptr;
329  }
330  // Check whether it is a r-binned case or a z-binned case
331  bool rCase =
332  std::abs(firstVolumeBounds->get(CylinderVolumeBounds::eMinR) -
333  lastVolumeBounds->get(CylinderVolumeBounds::eMinR)) > 0.1;
334 
335  // Fill these ones depending on the rCase though assignment
336  double zMin = 0.;
337  double zMax = 0.;
338  double rMin = 0.;
339  double rGlueMin = 0.;
340  double rMax = 0.;
341  double zSep1 = 0.;
342  double zSep2 = 0.;
343  if (rCase) {
344  zMin = (*firstVolume)->center().z() -
345  firstVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ);
346  zMax = (*firstVolume)->center().z() +
347  firstVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ);
348  zSep1 = zMin;
349  zSep2 = zMax;
350  rMin = firstVolumeBounds->get(CylinderVolumeBounds::eMinR);
351  rGlueMin = firstVolumeBounds->get(CylinderVolumeBounds::eMaxR);
352  rMax = lastVolumeBounds->get(CylinderVolumeBounds::eMaxR);
353  } else {
354  zMin = (*firstVolume)->center().z() -
355  firstVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ);
356  zMax = (*lastVolume)->center().z() +
357  lastVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ);
358  zSep1 = (*firstVolume)->center().z() +
359  firstVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ);
360  zSep2 = zSep1;
361  rMin = firstVolumeBounds->get(CylinderVolumeBounds::eMinR);
362  rMax = firstVolumeBounds->get(CylinderVolumeBounds::eMaxR);
363  }
364  // Estimate the z - position
365  double zPos = 0.5 * (zMin + zMax);
366  // Create the transform from the stuff known so far
367  const Transform3D topVolumeTransform =
368  Transform3D(Translation3D(0., 0., zPos));
369  // Create the bounds from the information gathered so far
370  CylinderVolumeBounds* topVolumeBounds =
371  new CylinderVolumeBounds(rMin, rMax, 0.5 * std::abs(zMax - zMin));
372 
373  // some screen output
374  ACTS_VERBOSE("Container volume bounds are " << (*topVolumeBounds));
375 
376  // create the volume array with the ITrackingVolumeArrayCreator
377  std::shared_ptr<const TrackingVolumeArray> volumeArray =
378  (rCase) ? m_cfg.trackingVolumeArrayCreator->trackingVolumeArray(
379  gctx, volumes, binR)
380  : m_cfg.trackingVolumeArrayCreator->trackingVolumeArray(
381  gctx, volumes, binZ);
382  if (volumeArray == nullptr) {
383  ACTS_WARNING(
384  "Creation of TrackingVolume array did not succeed - returning 0 ");
385  delete topVolumeBounds;
386  return nullptr;
387  }
388  // we have the bounds and the volume array, create the volume
389  std::shared_ptr<TrackingVolume> topVolume = TrackingVolume::create(
390  topVolumeTransform, VolumeBoundsPtr(topVolumeBounds), volumeArray,
391  volumeName);
392  // glueing section
393  // --------------------------------------------------------------------------------------
394  if (not interGlueTrackingVolume(gctx, topVolume, rCase, rMin, rGlueMin, rMax,
395  zSep1, zSep2)) {
396  ACTS_WARNING(
397  "Problem with inter-glueing of TrackingVolumes (needed) - "
398  "returning 0 ");
399  return nullptr;
400  }
401 
402  ACTS_VERBOSE(
403  "[ end ] return newly created container : " << topVolume->volumeName());
404 
405  return topVolume;
406 }
407 
411  const GeometryContext& gctx, const LayerVector& layers,
412  const CylinderVolumeBounds*& cylinderVolumeBounds,
413  const Transform3D& transform, double& rMinClean, double& rMaxClean,
414  double& zMinClean, double& zMaxClean, BinningValue& bValue,
415  BinningType /*unused*/) const {
416  // some verbose output
417 
418  ACTS_VERBOSE("Parsing the " << layers.size()
419  << " layers to gather overall dimensions");
420  if (cylinderVolumeBounds != nullptr)
421  ACTS_DEBUG("Cylinder volume bounds are given: (rmin/rmax/dz) = "
422  << "(" << cylinderVolumeBounds->get(CylinderVolumeBounds::eMinR)
423  << "/" << cylinderVolumeBounds->get(CylinderVolumeBounds::eMaxR)
424  << "/"
425  << cylinderVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ)
426  << ")");
427 
428  // prepare for parsing the layers
429  double layerRmin = 10e10;
430  double layerRmax = 0.;
431  double layerZmin = 10e10;
432  double layerZmax = -10e10;
433  bool radial = false;
434 
435  rMinClean = 10e10;
436  rMaxClean = 0.;
437  zMinClean = 10e10;
438  zMaxClean = -10e10;
439 
440  // find out what is there
441  for (auto& layerIter : layers) {
442  // initialize
443  double currentRmin = 0.;
444  double currentRmax = 0.;
445  double currentZmin = 0.;
446  double currentZmax = 0.;
447  // dynamic cast the bounds either to CylinderBounds or DiscBounds
448  const CylinderBounds* cylBounds = dynamic_cast<const CylinderBounds*>(
449  &(layerIter->surfaceRepresentation()).bounds());
450  // cylinder bounds
451  if (cylBounds != nullptr) {
452  radial = true;
453  // get the raw data
454  double currentR = cylBounds->get(CylinderBounds::eR);
455  double centerZ = (layerIter->surfaceRepresentation()).center(gctx).z();
456  // check for min/max in the cylinder bounds case
457  currentRmin = currentR - (0.5 * (layerIter)->thickness());
458  currentRmax = currentR + (0.5 * (layerIter)->thickness());
459  currentZmin = centerZ - cylBounds->get(CylinderBounds::eHalfLengthZ);
460  currentZmax = centerZ + cylBounds->get(CylinderBounds::eHalfLengthZ);
461  }
462  // dynamic cast to the DiscBounds
463  const RadialBounds* discBounds = dynamic_cast<const RadialBounds*>(
464  &(layerIter->surfaceRepresentation()).bounds());
465  if (discBounds != nullptr) {
466  // check for min/max in the cylinder bounds case
467  double centerZ = (layerIter->surfaceRepresentation()).center(gctx).z();
468  currentRmin = discBounds->rMin();
469  currentRmax = discBounds->rMax();
470  currentZmin = centerZ - (0.5 * (layerIter)->thickness());
471  currentZmax = centerZ + (0.5 * (layerIter)->thickness());
472  }
473  // the raw data
474  rMinClean = std::min(rMinClean, currentRmin);
475  rMaxClean = std::max(rMaxClean, currentRmax);
476  zMinClean = std::min(zMinClean, currentZmin);
477  zMaxClean = std::max(zMaxClean, currentZmax);
478  // assign if they overrule the minima/maxima (with layers thicknesses)
479  layerRmin = std::min(layerRmin, currentRmin);
480  layerRmax = std::max(layerRmax, currentRmax);
481  layerZmin = std::min(layerZmin, currentZmin);
482  layerZmax = std::max(layerZmax, currentZmax);
483  }
484 
485  // set the binning value
486  bValue = radial ? binR : binZ;
487 
488  ACTS_VERBOSE(
489  "Estimate/check CylinderVolumeBounds from/w.r.t. enclosed "
490  "layers + envelope covers");
491  // the z from the layers w and w/o envelopes
492  double zEstFromLayerEnv = 0.5 * ((layerZmax) + (layerZmin));
493  double halflengthFromLayer = 0.5 * std::abs((layerZmax) - (layerZmin));
494 
495  bool concentric = (zEstFromLayerEnv * zEstFromLayerEnv < 0.001);
496 
497  bool idTrf = transform.isApprox(s_idTransform);
498 
499  Transform3D vtransform = s_idTransform;
500  // no CylinderBounds and Translation given - make it
501  if ((cylinderVolumeBounds == nullptr) && idTrf) {
502  // create the CylinderBounds from parsed layer inputs
503  cylinderVolumeBounds =
504  new CylinderVolumeBounds(layerRmin, layerRmax, halflengthFromLayer);
505  // and the transform
506  vtransform = concentric
507  ? Transform3D(Translation3D(0., 0., zEstFromLayerEnv))
508  : s_idTransform;
509  } else if ((cylinderVolumeBounds != nullptr) && idTrf && !concentric) {
510  vtransform = Transform3D(Translation3D(0., 0., zEstFromLayerEnv));
511  } else if (not idTrf && (cylinderVolumeBounds == nullptr)) {
512  // create the CylinderBounds from parsed layer inputs
513  cylinderVolumeBounds =
514  new CylinderVolumeBounds(layerRmin, layerRmax, halflengthFromLayer);
515  }
516 
517  ACTS_VERBOSE(" -> dimensions from layers (rMin/rMax/zMin/zMax) = "
518  << layerRmin << " / " << layerRmax << " / " << layerZmin << " / "
519  << layerZmax);
520 
521  double zFromTransform = not idTrf ? transform.translation().z() : 0.;
522  ACTS_VERBOSE(
523  " -> while created bounds are (rMin/rMax/zMin/zMax) = "
524  << cylinderVolumeBounds->get(CylinderVolumeBounds::eMinR) << " / "
525  << cylinderVolumeBounds->get(CylinderVolumeBounds::eMaxR) << " / "
526  << zFromTransform -
527  cylinderVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ)
528  << " / "
529  << zFromTransform +
530  cylinderVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ));
531 
532  // both is NOW given --- check it -----------------------------
533  if (cylinderVolumeBounds != nullptr) {
534  // only check
535  if (zFromTransform -
536  cylinderVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ) <=
537  layerZmin &&
538  zFromTransform +
539  cylinderVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ) >=
540  layerZmax &&
541  cylinderVolumeBounds->get(CylinderVolumeBounds::eMinR) <= layerRmin &&
542  cylinderVolumeBounds->get(CylinderVolumeBounds::eMaxR) >= layerRmax) {
543  return true;
544  } else {
545  ACTS_WARNING(
546  "Provided layers are not contained by volume ! Bailing out. ");
547  ACTS_WARNING("- zFromTransform: " << zFromTransform);
548  ACTS_WARNING("- volumeZmin:"
549  << zFromTransform - cylinderVolumeBounds->get(
551  << ", layerZmin: " << layerZmin);
552  ACTS_WARNING("- volumeZmax: "
553  << zFromTransform + cylinderVolumeBounds->get(
555  << ", layerZmax: " << layerZmax);
556  ACTS_WARNING("- volumeRmin: "
557  << cylinderVolumeBounds->get(CylinderVolumeBounds::eMinR)
558  << ", layerRmin: " << layerRmin);
559  ACTS_WARNING("- volumeRmax: "
560  << cylinderVolumeBounds->get(CylinderVolumeBounds::eMaxR)
561  << ", layerRmax: " << layerRmax);
562  return false;
563  }
564  }
565 
566  ACTS_VERBOSE("Created/Checked " << *cylinderVolumeBounds);
567  return true;
568 }
569 
571  const GeometryContext& gctx, const std::shared_ptr<TrackingVolume>& tVolume,
572  bool rBinned, double rMin, double rGlueMin, double rMax, double zMin,
573  double zMax) const {
574  ACTS_VERBOSE("Glue contained TrackingVolumes of container '"
575  << tVolume->volumeName() << "'.");
576 
577  // only go on if you have confinedVolumes
578  if (tVolume->confinedVolumes()) {
579  // get the glueVolumes descriptor of the top volume to register the outside
580  // volumes
581  GlueVolumesDescriptor& glueDescr = tVolume->glueVolumesDescriptor();
582 
583  // now retrieve the volumes
584  auto& volumes = tVolume->confinedVolumes()->arrayObjects();
585 
586  // list the volume names:
587  // and make the screen output readable
588  size_t ivol = 0;
589  for (auto& vol : volumes)
590  ACTS_VERBOSE("[" << ivol++ << "] - volume : " << vol->volumeName());
591 
592  // the needed iterators
593  auto tVolIter = volumes.begin();
594  auto tVolFirst = volumes.begin();
595  auto tVolLast = volumes.end();
596  --tVolLast;
597  auto tVolEnd = volumes.end();
598 
599  // the glue volumes for the description
600  TrackingVolumeVector glueVolumesInnerTube;
601  TrackingVolumeVector glueVolumesOuterTube;
602  TrackingVolumeVector glueVolumesNegativeFace;
603  TrackingVolumeVector glueVolumesPositiveFace;
604  // reset ivol counter
605  ivol = 0;
606  // volumes of increasing r
607  if (rBinned) {
608  // loop over the volumes -------------------------------
609  for (; tVolIter != tVolEnd;) {
610  // screen output
611  ACTS_VERBOSE("r-binning: Processing volume [" << ivol++ << "]");
612  // for the first one
613  std::shared_ptr<TrackingVolume> tVol =
615  if (tVolIter == tVolFirst) {
616  addFaceVolumes(tVol, tubeInnerCover, glueVolumesInnerTube);
617  }
618  // add this or the subvolumes to the negativeFace and positiveFace
619  addFaceVolumes(tVol, negativeFaceXY, glueVolumesNegativeFace);
620  addFaceVolumes(tVol, positiveFaceXY, glueVolumesPositiveFace);
621  if (tVolIter == tVolLast) {
622  addFaceVolumes(tVol, tubeOuterCover, glueVolumesOuterTube);
623  ++tVolIter;
624  } else {
625  std::shared_ptr<TrackingVolume> tVol1 =
627  std::shared_ptr<TrackingVolume> tVol2 =
628  std::const_pointer_cast<TrackingVolume>(*(++tVolIter));
629  glueTrackingVolumes(gctx, tVol1, tubeOuterCover, tVol2,
630  tubeInnerCover, rMin, rGlueMin, rMax, zMin, zMax);
631  }
632  }
633  } else {
634  // Volumes in increasing z
635  // Loop over the volumes
636  for (; tVolIter != tVolEnd;) {
637  // screen output
638  ACTS_VERBOSE("z-binning: Processing volume '"
639  << (*tVolIter)->volumeName() << "'.");
640  std::shared_ptr<TrackingVolume> tVol =
642  if (tVolIter == tVolFirst) {
643  addFaceVolumes(tVol, negativeFaceXY, glueVolumesNegativeFace);
644  }
645  addFaceVolumes(tVol, tubeInnerCover, glueVolumesInnerTube);
646  addFaceVolumes(tVol, tubeOuterCover, glueVolumesOuterTube);
647  if (tVolIter == tVolLast) {
648  addFaceVolumes(tVol, positiveFaceXY, glueVolumesPositiveFace);
649  ++tVolIter;
650  } else {
651  std::shared_ptr<TrackingVolume> tVol1 =
653  std::shared_ptr<TrackingVolume> tVol2 =
654  std::const_pointer_cast<TrackingVolume>(*(++tVolIter));
655  glueTrackingVolumes(gctx, tVol1, positiveFaceXY, tVol2,
656  negativeFaceXY, rMin, rGlueMin, rMax, zMin, zMax);
657  }
658  }
659  }
660  // create BinnedArraysand register then to the glue volume descriptor for
661  // upstream glueing
662  if (!glueVolumesNegativeFace.empty()) {
663  // create the outside volume array
664  std::shared_ptr<const TrackingVolumeArray> glueVolumesNegativeFaceArray =
665  m_cfg.trackingVolumeArrayCreator->trackingVolumeArray(
666  gctx, glueVolumesNegativeFace, binR);
667  // register the glue voluems
669  glueVolumesNegativeFaceArray);
670  }
671  if (!glueVolumesPositiveFace.empty()) {
672  // create the outside volume array
673  std::shared_ptr<const TrackingVolumeArray> glueVolumesPositiveFaceArray =
674  m_cfg.trackingVolumeArrayCreator->trackingVolumeArray(
675  gctx, glueVolumesPositiveFace, binR);
676  // register the glue voluems
678  glueVolumesPositiveFaceArray);
679  }
680  if (!glueVolumesInnerTube.empty()) {
681  // create the outside volume array
682  std::shared_ptr<const TrackingVolumeArray> glueVolumesInnerTubeArray =
683  m_cfg.trackingVolumeArrayCreator->trackingVolumeArray(
684  gctx, glueVolumesInnerTube, binZ);
685  // register the glue voluems
686  glueDescr.registerGlueVolumes(tubeInnerCover, glueVolumesInnerTubeArray);
687  }
688  if (!glueVolumesOuterTube.empty()) {
689  // create the outside volume array
690  std::shared_ptr<const TrackingVolumeArray> glueVolumesOuterTubeArray =
691  m_cfg.trackingVolumeArrayCreator->trackingVolumeArray(
692  gctx, glueVolumesOuterTube, binZ);
693  // register the glue voluems
694  glueDescr.registerGlueVolumes(tubeOuterCover, glueVolumesOuterTubeArray);
695  }
696 
697  ACTS_VERBOSE("[GV] Register " << glueVolumesNegativeFace.size()
698  << " volumes at face negativeFaceXY:");
699  for (tVolIter = glueVolumesNegativeFace.begin();
700  tVolIter != glueVolumesNegativeFace.end(); ++tVolIter)
701  ACTS_VERBOSE(" -> volume '" << (*tVolIter)->volumeName() << "'");
702  ACTS_VERBOSE("[GV] Register " << glueVolumesPositiveFace.size()
703  << " volumes at face positiveFaceXY: ");
704  for (tVolIter = glueVolumesPositiveFace.begin();
705  tVolIter != glueVolumesPositiveFace.end(); ++tVolIter)
706  ACTS_VERBOSE(" -> volume '" << (*tVolIter)->volumeName() << "'");
707  ACTS_VERBOSE("[GV] Register " << glueVolumesInnerTube.size()
708  << " volumes at face tubeInnerCover: ");
709  for (tVolIter = glueVolumesInnerTube.begin();
710  tVolIter != glueVolumesInnerTube.end(); ++tVolIter)
711  ACTS_VERBOSE(" -> volume '" << (*tVolIter)->volumeName() << "'");
712  ACTS_VERBOSE("[GV] Register " << glueVolumesOuterTube.size()
713  << " volumes at face tubeOuterCover:");
714  for (tVolIter = glueVolumesOuterTube.begin();
715  tVolIter != glueVolumesOuterTube.end(); ++tVolIter)
716  ACTS_VERBOSE(" -> volume '" << (*tVolIter)->volumeName());
717  }
718  // return success
719  return true;
720 }
721 
724  const GeometryContext& gctx, const std::shared_ptr<TrackingVolume>& tvolOne,
725  BoundarySurfaceFace faceOne, const std::shared_ptr<TrackingVolume>& tvolTwo,
726  BoundarySurfaceFace faceTwo, double rMin, double rGlueMin, double rMax,
727  double zMin, double zMax) const {
728  // get the two gluevolume descriptors
729  const GlueVolumesDescriptor& gvDescriptorOne =
730  tvolOne->glueVolumesDescriptor();
731  const GlueVolumesDescriptor& gvDescriptorTwo =
732  tvolTwo->glueVolumesDescriptor();
733 
734  size_t volOneGlueVols =
735  gvDescriptorOne.glueVolumes(faceOne)
736  ? gvDescriptorOne.glueVolumes(faceOne)->arrayObjects().size()
737  : 0;
738  ACTS_VERBOSE("GlueVolumeDescriptor of volume '"
739  << tvolOne->volumeName() << "' has " << volOneGlueVols << " @ "
740  << faceOne);
741  size_t volTwoGlueVols =
742  gvDescriptorTwo.glueVolumes(faceTwo)
743  ? gvDescriptorTwo.glueVolumes(faceTwo)->arrayObjects().size()
744  : 0;
745  ACTS_VERBOSE("GlueVolumeDescriptor of volume '"
746  << tvolTwo->volumeName() << "' has " << volTwoGlueVols << " @ "
747  << faceTwo);
748 
749  // they could still be a container though - should not happen usually
750  TrackingVolumePtr glueVolOne =
751  volOneGlueVols != 0u
752  ? gvDescriptorOne.glueVolumes(faceOne)->arrayObjects()[0]
753  : tvolOne;
754  TrackingVolumePtr glueVolTwo =
755  volTwoGlueVols != 0u
756  ? gvDescriptorTwo.glueVolumes(faceTwo)->arrayObjects()[0]
757  : tvolTwo;
758 
759  // We'll need to mutate those volumes in order to glue them together
760  auto mutableGlueVolOne = std::const_pointer_cast<TrackingVolume>(glueVolOne);
761  auto mutableGlueVolTwo = std::const_pointer_cast<TrackingVolume>(glueVolTwo);
762 
763  // check the cases
764  if (volOneGlueVols <= 1 && volTwoGlueVols <= 1) {
765  // (i) one -> one
766  ACTS_VERBOSE(" glue : one[ " << glueVolOne->volumeName() << " @ "
767  << faceOne << " ]-to-one[ "
768  << glueVolTwo->volumeName() << " @ "
769  << faceTwo << " ]");
770  // one to one is easy
771  mutableGlueVolOne->glueTrackingVolume(gctx, faceOne,
772  mutableGlueVolTwo.get(), faceTwo);
773 
774  } else if (volOneGlueVols <= 1) {
775  // (ii) one -> many
776  ACTS_VERBOSE(" glue : one[ "
777  << glueVolOne->volumeName() << " @ " << faceOne
778  << " ]-to-many[ " << tvolTwo->volumeName() << " @ " << faceTwo
779  << " ]");
780  auto mutableFaceTwoVolumes = std::const_pointer_cast<TrackingVolumeArray>(
781  gvDescriptorTwo.glueVolumes(faceTwo));
782  mutableGlueVolOne->glueTrackingVolumes(gctx, faceOne, mutableFaceTwoVolumes,
783  faceTwo);
784  } else if (volTwoGlueVols <= 1) {
785  // (iii) many -> one
786  ACTS_VERBOSE(" glue : many[ "
787  << tvolOne->volumeName() << " @ " << faceOne << " ]-to-one[ "
788  << glueVolTwo->volumeName() << " @ " << faceTwo << " ]");
789  auto mutableFaceOneVolumes = std::const_pointer_cast<TrackingVolumeArray>(
790  gvDescriptorOne.glueVolumes(faceOne));
791  mutableGlueVolTwo->glueTrackingVolumes(gctx, faceTwo, mutableFaceOneVolumes,
792  faceOne);
793  } else {
794  // (iv) glue array to array
795  ACTS_VERBOSE(" glue : many[ "
796  << tvolOne->volumeName() << " @ " << faceOne << " ]-to-many[ "
797  << tvolTwo->volumeName() << " @ " << faceTwo << " ]");
798 
799  // Create a new BoundarySurface as shared pointer
800  std::shared_ptr<const BoundarySurfaceT<TrackingVolume>> boundarySurface =
801  nullptr;
802 
803  // the transform of the new boundary surface
804  Transform3D transform = s_idTransform;
805  if (std::abs(zMin + zMax) > 0.1) {
806  // it's not a concentric cylinder, so create a transform
807  transform =
808  Transform3D(Translation3D(Vector3D(0., 0., 0.5 * (zMin + zMax))));
809  }
810  // 2 cases: r-Binning and zBinning
811  if (faceOne == cylinderCover || faceOne == tubeOuterCover) {
812  // (1) create the Boundary CylinderSurface
813  auto cBounds =
814  std::make_shared<CylinderBounds>(rGlueMin, 0.5 * (zMax - zMin));
815  std::shared_ptr<const Surface> cSurface =
816  Surface::makeShared<CylinderSurface>(transform, cBounds);
817  ACTS_VERBOSE(
818  " creating a new cylindrical boundary surface "
819  "with bounds = "
820  << cSurface->bounds());
821  ACTS_VERBOSE(" at " << cSurface->center(gctx).transpose());
822  boundarySurface =
823  std::make_shared<const BoundarySurfaceT<TrackingVolume>>(
824  std::move(cSurface), gvDescriptorOne.glueVolumes(faceOne),
825  gvDescriptorTwo.glueVolumes(faceTwo));
826  } else {
827  // Calculate correct position for disc surface
828 
829  // we assume it's cylinder bounds
830  auto cylVolBounds = dynamic_cast<const Acts::CylinderVolumeBounds*>(
831  &tvolOne->volumeBounds());
832  double zPos = tvolOne->center().z();
833  double zHL = cylVolBounds->get(CylinderVolumeBounds::eHalfLengthZ);
834  transform = Transform3D(Translation3D(0, 0, zPos + zHL));
835  // this puts the surface on the positive z side of the cyl vol bounds
836  // iteration is from neg to pos, so it should always be in between.
837 
838  // (2) create the BoundaryDiscSurface, in that case the zMin/zMax provided
839  // are both the position of the disk in question
840  std::shared_ptr<const Surface> dSurface =
841  Surface::makeShared<DiscSurface>(transform, rMin, rMax);
842  ACTS_VERBOSE(
843  " creating a new disc-like boundary surface "
844  "with bounds = "
845  << dSurface->bounds());
846  ACTS_VERBOSE(" at " << dSurface->center(gctx).transpose());
847  boundarySurface =
848  std::make_shared<const BoundarySurfaceT<TrackingVolume>>(
849  std::move(dSurface), gvDescriptorOne.glueVolumes(faceOne),
850  gvDescriptorTwo.glueVolumes(faceTwo));
851  }
852 
853  // Collect the material - might be ambiguous, first one wins
854  std::shared_ptr<const ISurfaceMaterial> boundaryMaterial = nullptr;
855 
856  ACTS_VERBOSE("New Boundary surface setting for countainers");
857  ACTS_VERBOSE(" - at first volume: " << tvolOne->volumeName());
858  // Update the volume with the boundary surface accordingly
859  // it's safe to access directly, they can not be nullptr
860  for (auto& oneVolume :
861  gvDescriptorOne.glueVolumes(faceOne)->arrayObjects()) {
862  auto mutableOneVolume =
864  // Look out for surface material
865  if (boundaryMaterial == nullptr) {
866  auto oneBSurface = mutableOneVolume->boundarySurfaces()[faceOne];
867  boundaryMaterial =
868  oneBSurface->surfaceRepresentation().surfaceMaterialSharedPtr();
869  }
870  mutableOneVolume->updateBoundarySurface(faceOne, boundarySurface);
871  ACTS_VERBOSE(" -> setting boundary surface to volume: "
872  << mutableOneVolume->volumeName());
873  }
874  ACTS_VERBOSE(" - at second volume: " << tvolTwo->volumeName());
875  for (auto& twoVolume :
876  gvDescriptorTwo.glueVolumes(faceTwo)->arrayObjects()) {
877  auto mutableTwoVolume =
879  // Look out for surface material
880  if (boundaryMaterial == nullptr) {
881  auto twoBSurface = mutableTwoVolume->boundarySurfaces()[faceTwo];
882  boundaryMaterial =
883  twoBSurface->surfaceRepresentation().surfaceMaterialSharedPtr();
884  }
885  mutableTwoVolume->updateBoundarySurface(faceTwo, boundarySurface);
886  ACTS_VERBOSE(" -> setting boundary surface to volume: "
887  << mutableTwoVolume->volumeName());
888  }
889 
890  // If we have boundary material, let's assign it
891  if (boundaryMaterial != nullptr) {
892  // Adapt the boundary material
893  ACTS_VERBOSE("- the new boundary surface has boundary material: ");
894  ACTS_VERBOSE(" " << *boundaryMaterial);
895  Surface* newSurface =
896  const_cast<Surface*>(&(boundarySurface->surfaceRepresentation()));
897  newSurface->assignSurfaceMaterial(boundaryMaterial);
898  }
899 
900  } // end of case (iv)
901 }
902 
905  const std::shared_ptr<TrackingVolume>& tvol, BoundarySurfaceFace glueFace,
906  TrackingVolumeVector& vols) const {
907  ACTS_VERBOSE("Adding face volumes of face " << glueFace << " for the volume '"
908  << tvol->volumeName() << "'.");
909  // retrieve the gluevolume descriptor
910  const GlueVolumesDescriptor& gvDescriptor = tvol->glueVolumesDescriptor();
911  // if volumes are registered: take them
912  if (gvDescriptor.glueVolumes(glueFace)) {
913  // get the navigation level subvolumes
914  auto volIter = gvDescriptor.glueVolumes(glueFace)->arrayObjects().begin();
915  auto volEnd = gvDescriptor.glueVolumes(glueFace)->arrayObjects().end();
916  for (; volIter != volEnd; ++volIter) {
917  ACTS_VERBOSE(" -> adding : " << (*volIter)->volumeName());
918  vols.push_back(*volIter);
919  }
920  // screen output
921  ACTS_VERBOSE(vols.size()
922  << " navigation volumes registered as glue volumes.");
923  } else {
924  // the volume itself is on navigation level
925  ACTS_VERBOSE(" -> adding only volume itself (at navigation level).");
926  vols.push_back(tvol);
927  }
928 }
929 
930 std::shared_ptr<const Acts::Layer>
932  double halflengthZ,
933  double thickness, int binsPhi,
934  int binsZ) const {
935  ACTS_VERBOSE("Creating a CylinderLayer at position " << z << " and radius "
936  << r);
937  // positioning
938  const Transform3D transform(Translation3D(0., 0., z));
939 
940  // z-binning
941  BinUtility layerBinUtility(binsZ, z - halflengthZ, z + halflengthZ, open,
942  binZ);
943  if (binsPhi == 1) {
944  // the BinUtility for the material
945  // ---------------------> create material for the layer surface
946  ACTS_VERBOSE(" -> Preparing the binned material with " << binsZ
947  << " bins in Z. ");
948 
949  } else { // break the phi symmetry
950  // update the BinUtility: local position on Cylinder is rPhi, z
951  BinUtility layerBinUtilityPhiZ(binsPhi, -r * M_PI, +r * M_PI, closed,
952  binPhi);
953  layerBinUtilityPhiZ += layerBinUtility;
954  // ---------------------> create material for the layer surface
955  ACTS_VERBOSE(" -> Preparing the binned material with "
956  << binsPhi << " / " << binsZ << " bins in phi / Z. ");
957  }
958  // @todo create the SurfaceMaterial
959  // bounds for cylinderical surface
960  CylinderBounds* cylinderBounds = new CylinderBounds(r, halflengthZ);
961  // create the cylinder
962  return CylinderLayer::create(
963  transform, std::shared_ptr<const CylinderBounds>(cylinderBounds), nullptr,
964  thickness);
965 }
966 
967 std::shared_ptr<const Acts::Layer> Acts::CylinderVolumeHelper::createDiscLayer(
968  double z, double rMin, double rMax, double thickness, int binsPhi,
969  int binsR) const {
970  ACTS_VERBOSE("Creating a DiscLayer at position " << z << " and rMin/rMax "
971  << rMin << " / " << rMax);
972 
973  // positioning
974  const Transform3D transform(Translation3D(0., 0., z));
975 
976  // R is the primary binning for the material
977  BinUtility materialBinUtility(binsR, rMin, rMax, open, binR);
978  if (binsPhi == 1) {
979  ACTS_VERBOSE(" -> Preparing the binned material with " << binsR
980  << " bins in R. ");
981  } else {
982  // also binning in phi chosen
983  materialBinUtility += BinUtility(binsPhi, -M_PI, M_PI, closed, binPhi);
984  ACTS_VERBOSE(" -> Preparing the binned material with "
985  << binsPhi << " / " << binsR << " bins in phi / R. ");
986  }
987 
988  // @todo create the SurfaceMaterial
989  // bounds for disk-like surface
990  RadialBounds* discBounds = new RadialBounds(rMin, rMax);
991  // create the disc
992  return DiscLayer::create(transform,
993  std::shared_ptr<const DiscBounds>(discBounds),
994  nullptr, thickness);
995 }