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