Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CylinderVolumeBuilder.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file CylinderVolumeBuilder.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"
29 
30 #include <algorithm>
31 #include <iterator>
32 #include <vector>
33 
34 #include <boost/algorithm/string.hpp>
35 #include <math.h>
36 
38  const Acts::CylinderVolumeBuilder::Config& cvbConfig,
39  std::unique_ptr<const Logger> logger)
40  : Acts::ITrackingVolumeBuilder(), m_cfg(), m_logger(std::move(logger)) {
41  setConfiguration(cvbConfig);
42 }
43 
45 
47  const Acts::CylinderVolumeBuilder::Config& cvbConfig) {
48  // @todo check consistency
49  // copy the configuration
50  m_cfg = cvbConfig;
51 }
52 
54  std::unique_ptr<const Logger> newLogger) {
55  m_logger = std::move(newLogger);
56 }
57 
58 std::shared_ptr<Acts::TrackingVolume>
60  const GeometryContext& gctx, TrackingVolumePtr existingVolume,
61  VolumeBoundsPtr externalBounds) const {
62  ACTS_DEBUG("Configured to build volume : " << m_cfg.volumeName);
63  if (existingVolume) {
64  ACTS_DEBUG("- will wrap/enclose : " << existingVolume->volumeName());
65  }
66 
67  // the return volume
68  // -----------------------------------------------------------------------------
69  MutableTrackingVolumePtr volume = nullptr;
70 
71  // now analyize the layers that are provided
72  // -----------------------------------------------------
73  ACTS_DEBUG("-> Building layers");
74  LayerVector negativeLayers;
75  LayerVector centralLayers;
76  LayerVector positiveLayers;
77 
78  // the wrapping configuration
79  WrappingConfig wConfig;
80 
81  // the layers are built by the layer builder
82  if (m_cfg.layerBuilder) {
83  // the negative Layers
84  negativeLayers = m_cfg.layerBuilder->negativeLayers(gctx);
85  // the central Layers
86  centralLayers = m_cfg.layerBuilder->centralLayers(gctx);
87  // the positive Layer
88  positiveLayers = m_cfg.layerBuilder->positiveLayers(gctx);
89  }
90  ACTS_DEBUG("-> Building layers complete");
91 
92  // Build the confined volumes
93  MutableTrackingVolumeVector centralVolumes;
94  if (m_cfg.ctVolumeBuilder) {
95  centralVolumes = m_cfg.ctVolumeBuilder->centralVolumes();
96  }
97 
98  // (0) PREP WORK ------------------------------------------------
99  //
100  // a) volume config of the existing volume
101  if (existingVolume) {
102  // volume and existing volume
103  auto existingBounds = dynamic_cast<const CylinderVolumeBounds*>(
104  &existingVolume->volumeBounds());
105  // set the inside values
106  wConfig.existingVolumeConfig.present = true;
107  wConfig.existingVolumeConfig.rMin =
108  existingBounds->get(CylinderVolumeBounds::eMinR);
109  wConfig.existingVolumeConfig.rMax =
110  existingBounds->get(CylinderVolumeBounds::eMaxR);
111  wConfig.existingVolumeConfig.zMin =
112  existingVolume->center().z() -
113  existingBounds->get(CylinderVolumeBounds::eHalfLengthZ);
114  wConfig.existingVolumeConfig.zMax =
115  existingVolume->center().z() +
116  existingBounds->get(CylinderVolumeBounds::eHalfLengthZ);
117  }
118  //
119  // b) outside config
120  // the volume config for the Outside
121  VolumeConfig externalBoundConfig;
122  if (externalBounds) {
123  const CylinderVolumeBounds* ocvBounds =
124  dynamic_cast<const CylinderVolumeBounds*>(externalBounds.get());
125  // the cast to CylinderVolumeBounds needs to be successful
126  if (ocvBounds != nullptr) {
127  // get values from the out bounds
128  wConfig.externalVolumeConfig.present = true;
129  wConfig.externalVolumeConfig.rMin =
130  ocvBounds->get(CylinderVolumeBounds::eMinR);
131  wConfig.externalVolumeConfig.rMax =
132  ocvBounds->get(CylinderVolumeBounds::eMaxR);
133  wConfig.externalVolumeConfig.zMin =
135  wConfig.externalVolumeConfig.zMax =
137  }
138  }
139 
140  // ---------------------------------------------
141  // The Volume Config of the SubVolumes
142  // ---------------------------------------------
143  // sub volume / layer configuration (subVolumes only build of layers are
144  // present)
145  // --------------------------------------------------------------------------
146  //
147  // possible configurations are (so far only synchronised):
148  //
149  // | Negative Endcap | Barrel | Positive Endcap | - all layers present
150  // | Barrel | - barrel present
151  // | Negative Endcap | | Positive Endcap | - only endcaps present
152  // - no layer present
153  // Check if already given through configuration
154  //
155  // (A) volume configuration
156  //
157 
158  // Find out with Layer analysis
159  // analyze the layers
160  wConfig.nVolumeConfig = analyzeContent(gctx, negativeLayers, {}); // TODO
161  wConfig.cVolumeConfig = analyzeContent(gctx, centralLayers, centralVolumes);
162  wConfig.pVolumeConfig = analyzeContent(gctx, positiveLayers, {}); // TODO
163 
164  bool hasLayers = wConfig.nVolumeConfig.present ||
165  wConfig.cVolumeConfig.present ||
166  wConfig.pVolumeConfig.present;
167 
168  if (!hasLayers) {
169  ACTS_INFO("No layers present, returning nullptr");
170  return nullptr;
171  }
172 
173  std::string layerConfiguration = "|";
174  if (wConfig.nVolumeConfig) {
175  // negative layers are present
176  ACTS_VERBOSE("Negative layers are present: rmin, rmax | zmin, zmax = "
177  << wConfig.nVolumeConfig.toString());
178  std::vector<std::string> centers;
179  std::transform(negativeLayers.begin(), negativeLayers.end(),
180  std::back_inserter(centers), [&](const auto& layer) {
181  return std::to_string(
182  layer->surfaceRepresentation().center(gctx)[eZ]);
183  });
184  ACTS_VERBOSE("-> z locations: " << boost::algorithm::join(centers, ", "));
185  // add to the string output
186  layerConfiguration += " Negative Endcap |";
187  }
188  if (wConfig.cVolumeConfig) {
189  // central layers are present
190  ACTS_VERBOSE("Central layers are present: rmin, rmax | zmin, zmax = "
191  << wConfig.cVolumeConfig.toString());
192  std::vector<std::string> centers;
193  std::transform(centralLayers.begin(), centralLayers.end(),
194  std::back_inserter(centers), [&](const auto& layer) {
196  layer->surfaceRepresentation().center(gctx)));
197  });
198  ACTS_VERBOSE("-> radii: " << boost::algorithm::join(centers, ", "));
199  // add to the string output
200  layerConfiguration += " Barrel |";
201  }
202  if (wConfig.pVolumeConfig) {
203  // positive layers are present
204  ACTS_VERBOSE("Positive layers are present: rmin, rmax | zmin, zmax = "
205  << wConfig.pVolumeConfig.toString());
206  std::vector<std::string> centers;
207  std::transform(positiveLayers.begin(), positiveLayers.end(),
208  std::back_inserter(centers), [&](const auto& layer) {
209  return std::to_string(
210  layer->surfaceRepresentation().center(gctx)[eZ]);
211  });
212  ACTS_VERBOSE("-> z locations: " << boost::algorithm::join(centers, ", "));
213  // add to the string output
214  layerConfiguration += " Positive Endcap |";
215  }
216  // screen output
217  ACTS_DEBUG("Layer configuration is : " << layerConfiguration);
218 
219  // (B) LAYER Config SYNCHRONISATION ----------------------------------
220  // synchronise the layer config
221  ACTS_VERBOSE("Configurations after layer parsing " << '\n'
222  << wConfig.toString());
223  // first let us arrange the new container volume
224  wConfig.configureContainerVolume();
225  ACTS_VERBOSE("Configuration after container synchronisation "
226  << '\n'
227  << wConfig.toString());
228  // now let's understand the wrapping if needed
229  if (wConfig.existingVolumeConfig) {
230  wConfig.wrapInsertAttach();
231  ACTS_VERBOSE("Configuration after wrapping, insertion, attachment "
232  << '\n'
233  << wConfig.toString());
234  } else {
235  // no wrapping around inner volume needed
236  // however there could be central, positive & negative volume which will
237  // need to be put into a container volume
238  wConfig.wCondition = NoWrapping;
239  }
240 
241  // (C) VOLUME CREATION ----------------------------------
242  auto tvHelper = m_cfg.trackingVolumeHelper;
243  // the barrel is always created
244  auto barrel =
245  wConfig.cVolumeConfig
246  ? tvHelper->createTrackingVolume(
247  gctx, wConfig.cVolumeConfig.layers,
248  wConfig.cVolumeConfig.volumes, m_cfg.volumeMaterial,
249  wConfig.cVolumeConfig.rMin, wConfig.cVolumeConfig.rMax,
250  wConfig.cVolumeConfig.zMin, wConfig.cVolumeConfig.zMax,
251  m_cfg.volumeName + "::Barrel")
252  : nullptr;
253 
254  // Helper method to check for
255 
256  // Helper method to create endcap volume
257  auto createEndcap =
258  [&](VolumeConfig& centralConfig, VolumeConfig& endcapConfig,
259  const std::string& endcapName) -> MutableTrackingVolumePtr {
260  // No config - no volume
261  if (not endcapConfig) {
262  return nullptr;
263  }
264  // Check for ring layout
265  if (m_cfg.checkRingLayout) {
266  ACTS_DEBUG("Configured to check for ring layout - parsing layers.");
267  // Parsing loop for ring layout
268  std::vector<double> innerRadii = {};
269  std::vector<double> outerRadii = {};
270  for (const auto& elay : endcapConfig.layers) {
271  auto discBounds = dynamic_cast<const RadialBounds*>(
272  &(elay->surfaceRepresentation().bounds()));
273  if (discBounds != nullptr) {
274  double tolerance = m_cfg.ringTolerance;
275  // Search for the rmin value - and insert if necessary
276  double rMin = discBounds->rMin();
277  auto innerSearch = std::find_if(
278  innerRadii.begin(), innerRadii.end(), [&](double reference) {
279  return std::abs(rMin - reference) < tolerance;
280  });
281  if (innerSearch == innerRadii.end()) {
282  innerRadii.push_back(rMin);
283  }
284  // Search for the rmax value - and insert if necessary
285  double rMax = discBounds->rMax();
286  auto outerSearch = std::find_if(
287  outerRadii.begin(), outerRadii.end(), [&](double reference) {
288  return std::abs(rMax - reference) < tolerance;
289  });
290  if (outerSearch == outerRadii.end()) {
291  outerRadii.push_back(rMax);
292  }
293  }
294  }
295 
296  // we check radii for consistency from the inside outwards, so need to
297  // sort
298  std::sort(innerRadii.begin(), innerRadii.end());
299  std::sort(outerRadii.begin(), outerRadii.end());
300 
301  ACTS_DEBUG("Inner radii:" << [&]() {
302  std::stringstream ss;
303  for (double f : innerRadii) {
304  ss << " " << f;
305  }
306  return ss.str();
307  }());
308 
309  ACTS_DEBUG("Outer radii:" << [&]() {
310  std::stringstream ss;
311  for (double f : outerRadii) {
312  ss << " " << f;
313  }
314  return ss.str();
315  }());
316  // Result of the parsing loop
317  if (innerRadii.size() == outerRadii.size() and not innerRadii.empty()) {
318  bool consistent = true;
319  // The inter volume radii
320  ACTS_VERBOSE("Checking ring radius consistency");
321  std::vector<double> interRadii = {};
322  for (int ir = 1; ir < int(innerRadii.size()); ++ir) {
323  // Check whether inner/outer radii are consistent
324  ACTS_VERBOSE(
325  "or #" << ir - 1 << " < ir #" << ir << ": " << outerRadii[ir - 1]
326  << " < " << innerRadii[ir] << ", ok: "
327  << (outerRadii[ir - 1] < innerRadii[ir] ? "yes" : "no"));
328  if (outerRadii[ir - 1] < innerRadii[ir]) {
329  interRadii.push_back(0.5 * (outerRadii[ir - 1] + innerRadii[ir]));
330  } else {
331  consistent = false;
332  break;
333  }
334  }
335  // Continue if the ring layout is consistent
336  if (consistent) {
337  ACTS_DEBUG("Ring layout detection: " << innerRadii.size()
338  << " volumes.");
339  // Separate the Layers into volumes
340  std::vector<std::pair<double, double>> volumeRminRmax = {};
341  for (unsigned int ii = 0; ii < interRadii.size(); ++ii) {
342  if (ii == 0) {
343  volumeRminRmax.push_back({endcapConfig.rMin, interRadii[ii]});
344  }
345  if (ii + 1 < interRadii.size()) {
346  volumeRminRmax.push_back({interRadii[ii], interRadii[ii + 1]});
347  } else {
348  volumeRminRmax.push_back({interRadii[ii], endcapConfig.rMax});
349  }
350  }
351  auto ringLayers =
352  std::vector<LayerVector>(innerRadii.size(), LayerVector());
353  // Filling loop
354  for (const auto& elay : endcapConfig.layers) {
355  // Getting the reference radius
356  double test =
357  elay->surfaceRepresentation().binningPositionValue(gctx, binR);
358  // Find the right bin
359  auto ringVolume = std::find_if(
360  volumeRminRmax.begin(), volumeRminRmax.end(),
361  [&](const auto& reference) {
362  return (test > reference.first and test < reference.second);
363  });
364  if (ringVolume != volumeRminRmax.end()) {
365  unsigned int ringBin =
366  std::distance(volumeRminRmax.begin(), ringVolume);
367  ringLayers[ringBin].push_back(elay);
368  }
369  }
370  // Subvolume construction
371  ACTS_DEBUG("Ring layout configuration: ");
372  // Endcap container
373  std::vector<TrackingVolumePtr> endcapContainer;
374  unsigned int ir = 0;
375  for (auto& rLayers : ringLayers) {
376  ACTS_DEBUG(" - ring volume " << ir << " with " << rLayers.size()
377  << " layers, and rmin/rmax = "
378  << volumeRminRmax[ir].first << "/"
379  << volumeRminRmax[ir].second);
380  endcapContainer.push_back(tvHelper->createTrackingVolume(
381  gctx, rLayers, centralConfig.volumes, m_cfg.volumeMaterial,
382  volumeRminRmax[ir].first, volumeRminRmax[ir].second,
383  endcapConfig.zMin, endcapConfig.zMax,
384  m_cfg.volumeName + endcapName + std::string("::Ring") +
385  std::to_string(ir)));
386  ++ir;
387  }
388  // Return a container of ring volumes
389  return tvHelper->createContainerTrackingVolume(gctx, endcapContainer);
390  } else {
391  ACTS_DEBUG("Ring radii found to be inconsistent");
392  }
393  } else {
394  ACTS_DEBUG("Have " << innerRadii.size() << " inner radii and "
395  << outerRadii.size() << " outer radii");
396  }
397  }
398 
399  // No ring layout - return single volume
400  return tvHelper->createTrackingVolume(
401  gctx, endcapConfig.layers, centralConfig.volumes, m_cfg.volumeMaterial,
402  endcapConfig.rMin, endcapConfig.rMax, endcapConfig.zMin,
403  endcapConfig.zMax, m_cfg.volumeName + endcapName);
404  };
405 
406  // The negative endcap is created if present
407  auto nEndcap = createEndcap(wConfig.cVolumeConfig, wConfig.nVolumeConfig,
408  "::NegativeEndcap");
409 
410  // The positive endcap is created if present
411  auto pEndcap = createEndcap(wConfig.cVolumeConfig, wConfig.pVolumeConfig,
412  "::PositiveEndcap");
413 
414  ACTS_DEBUG("Newly created volume(s) will be " << wConfig.wConditionScreen);
415  // Standalone container, full wrapping, full insertion & if no existing volume
416  // is present needs a bare triple
417  if (wConfig.wCondition == Wrapping || wConfig.wCondition == Inserting ||
418  wConfig.wCondition == NoWrapping) {
419  ACTS_VERBOSE("Combined new container is being built.");
420  // Stuff into the container what you have
421  std::vector<TrackingVolumePtr> volumesContainer;
422  if (nEndcap) {
423  volumesContainer.push_back(nEndcap);
424  volume = nEndcap;
425  // Set the inner or outer material
426  if (not m_cfg.buildToRadiusZero) {
427  volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[0],
429  }
430  volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[1],
432  volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[2],
434  volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[3],
436  }
437  if (barrel) {
438  // Assign boundary material if existing
439  volumesContainer.push_back(barrel);
440  volume = barrel;
441  // Set the inner or outer material
442  if (not m_cfg.buildToRadiusZero) {
443  volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[0],
445  }
446  volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[1],
448  volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[3],
450  volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[4],
452  }
453  if (pEndcap) {
454  volumesContainer.push_back(pEndcap);
455  volume = pEndcap;
456  // Set the inner or outer material
457  if (not m_cfg.buildToRadiusZero) {
458  volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[0],
460  }
461  volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[1],
463  volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[4],
465  volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[5],
467  }
468  // and low lets create the new volume
469  volume =
470  volumesContainer.size() > 1
471  ? tvHelper->createContainerTrackingVolume(gctx, volumesContainer)
472  : volume;
473  } else if (wConfig.wCondition != Attaching) {
474  // the new volume is the only one present
475  volume = nEndcap ? nEndcap : (barrel ? barrel : pEndcap);
476  }
477 
478  // Prepare the gap volumes first
479  TrackingVolumePtr existingVolumeCp = existingVolume;
480  // Check if further action is needed on existing volumes and gap volumes
481  if (existingVolumeCp) {
482  // Check if gaps are needed
483  std::vector<TrackingVolumePtr> existingContainer;
484  if (wConfig.fGapVolumeConfig) {
485  // create the gap volume
486  auto fGap = tvHelper->createGapTrackingVolume(
487  gctx, wConfig.cVolumeConfig.volumes, m_cfg.volumeMaterial,
488  wConfig.fGapVolumeConfig.rMin, wConfig.fGapVolumeConfig.rMax,
489  wConfig.fGapVolumeConfig.zMin, wConfig.fGapVolumeConfig.zMax, 1,
490  false, m_cfg.volumeName + "::fGap");
491  // push it back into the list
492  existingContainer.push_back(fGap);
493  }
494  existingContainer.push_back(existingVolumeCp);
495  if (wConfig.sGapVolumeConfig) {
496  // create the gap volume
497  auto sGap = tvHelper->createGapTrackingVolume(
498  gctx, wConfig.cVolumeConfig.volumes, m_cfg.volumeMaterial,
499  wConfig.sGapVolumeConfig.rMin, wConfig.sGapVolumeConfig.rMax,
500  wConfig.sGapVolumeConfig.zMin, wConfig.sGapVolumeConfig.zMax, 1,
501  false, m_cfg.volumeName + "::sGap");
502  // push it back into the list
503  existingContainer.push_back(sGap);
504  }
505 
506  // And low lets create the new existing volume with gaps
507  existingVolumeCp =
508  existingContainer.size() > 1
509  ? tvHelper->createContainerTrackingVolume(gctx, existingContainer)
510  : existingVolumeCp;
511 
512  // for central wrapping or inserting, we need to update once more
513  // clear the container
514  existingContainer.clear();
515  if (wConfig.wCondition == CentralWrapping) {
516  existingContainer.push_back(existingVolumeCp);
517  existingContainer.push_back(barrel);
518  } else if (wConfig.wCondition == CentralInserting) {
519  existingContainer.push_back(barrel);
520  existingContainer.push_back(existingVolumeCp);
521  }
522  // update
523  existingVolumeCp =
524  !existingContainer.empty()
525  ? tvHelper->createContainerTrackingVolume(gctx, existingContainer)
526  : existingVolumeCp;
527 
528  std::vector<TrackingVolumePtr> totalContainer;
529  // check what to do with the existing
530  if (wConfig.wCondition == Attaching ||
531  wConfig.wCondition == CentralWrapping ||
532  wConfig.wCondition == CentralInserting) {
533  if (nEndcap) {
534  totalContainer.push_back(nEndcap);
535  }
536  totalContainer.push_back(existingVolumeCp);
537  if (pEndcap) {
538  totalContainer.push_back(pEndcap);
539  }
540  } else if (wConfig.wCondition == Inserting && volume) {
541  totalContainer.push_back(volume);
542  totalContainer.push_back(existingVolumeCp);
543  } else if (wConfig.wCondition == Wrapping && volume) {
544  totalContainer.push_back(existingVolumeCp);
545  totalContainer.push_back(volume);
546  } else {
547  ACTS_ERROR("Misconfiguration in volume building detected.");
548  return nullptr;
549  }
550  // now create the new container volume
551  volume = tvHelper->createContainerTrackingVolume(gctx, totalContainer);
552  }
553 
554  return volume;
555 }
556 
557 // -----------------------------
559  const GeometryContext& gctx, const LayerVector& lVector,
560  const MutableTrackingVolumeVector& mtvVector) const {
561  // @TODO add envelope tolerance
562  //
563  // return object
564  VolumeConfig lConfig;
565  // only if the vector is present it can actually be analyzed
566  if (!lVector.empty() || !mtvVector.empty()) {
567  // we have layers
568  lConfig.present = true;
569  // loop over the layer
570  for (auto& layer : lVector) {
571  // the thickness of the layer needs to be taken into account
572  double thickness = layer->thickness();
573  // get the center of the layer
574  const Vector3& center = layer->surfaceRepresentation().center(gctx);
575  // check if it is a cylinder layer
576  const CylinderLayer* cLayer =
577  dynamic_cast<const CylinderLayer*>(layer.get());
578  if (cLayer != nullptr) {
579  // now we have access to all the information
580  double rMinC =
582  0.5 * thickness;
583  double rMaxC =
585  0.5 * thickness;
586 
587  double hZ = cLayer->surfaceRepresentation().bounds().get(
589  lConfig.rMin =
590  std::min(lConfig.rMin, rMinC - m_cfg.layerEnvelopeR.first);
591  lConfig.rMax =
592  std::max(lConfig.rMax, rMaxC + m_cfg.layerEnvelopeR.second);
593  lConfig.zMin =
594  std::min(lConfig.zMin, center.z() - hZ - m_cfg.layerEnvelopeZ);
595  lConfig.zMax =
596  std::max(lConfig.zMax, center.z() + hZ + m_cfg.layerEnvelopeZ);
597  }
598  // proceed further if it is a Disc layer
599  const RadialBounds* dBounds = dynamic_cast<const RadialBounds*>(
600  &(layer->surfaceRepresentation().bounds()));
601  if (dBounds != nullptr) {
602  // now we have access to all the information
603  double rMinD = dBounds->rMin();
604  double rMaxD = dBounds->rMax();
605  double zMinD = center.z() - 0.5 * thickness;
606  double zMaxD = center.z() + 0.5 * thickness;
607  lConfig.rMin =
608  std::min(lConfig.rMin, rMinD - m_cfg.layerEnvelopeR.first);
609  lConfig.rMax =
610  std::max(lConfig.rMax, rMaxD + m_cfg.layerEnvelopeR.second);
611  lConfig.rMin = std::max(0.0, lConfig.rMin);
612  lConfig.zMin = std::min(lConfig.zMin, zMinD - m_cfg.layerEnvelopeZ);
613  lConfig.zMax = std::max(lConfig.zMax, zMaxD + m_cfg.layerEnvelopeZ);
614  }
615  }
616  for (auto& volume : mtvVector) {
617  const CylinderVolumeBounds* cvBounds =
618  dynamic_cast<const CylinderVolumeBounds*>(&volume->volumeBounds());
619  if (cvBounds != nullptr) {
620  lConfig.rMin =
621  std::min(lConfig.rMin, cvBounds->get(CylinderVolumeBounds::eMinR));
622  lConfig.rMax =
623  std::max(lConfig.rMax, cvBounds->get(CylinderVolumeBounds::eMaxR));
624  lConfig.zMin = std::min(
625  lConfig.zMin, -cvBounds->get(CylinderVolumeBounds::eHalfLengthZ));
626  lConfig.zMax = std::max(
627  lConfig.zMax, cvBounds->get(CylinderVolumeBounds::eHalfLengthZ));
628  }
629  }
630  }
631 
632  // Set the layers to the layer vector
633  lConfig.layers = lVector;
634  // set the layers to the layer vector
635  lConfig.volumes = mtvVector;
636  // overwrite to radius 0 if needed
637  if (m_cfg.buildToRadiusZero) {
638  ACTS_VERBOSE("This layer builder is configured to build to the beamline.");
639  lConfig.rMin = 0.;
640  }
641 
642  // and return what you have
643  return lConfig;
644 }