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