Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:11:21

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include "Acts/Geometry/CylinderVolumeBuilder.hpp"
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/Common.hpp"
0013 #include "Acts/Geometry/BoundarySurfaceFace.hpp"
0014 #include "Acts/Geometry/CylinderLayer.hpp"
0015 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0016 #include "Acts/Geometry/IConfinedTrackingVolumeBuilder.hpp"
0017 #include "Acts/Geometry/ILayerBuilder.hpp"
0018 #include "Acts/Geometry/ITrackingVolumeHelper.hpp"
0019 #include "Acts/Geometry/Layer.hpp"
0020 #include "Acts/Geometry/TrackingVolume.hpp"
0021 #include "Acts/Geometry/VolumeBounds.hpp"
0022 #include "Acts/Surfaces/CylinderBounds.hpp"
0023 #include "Acts/Surfaces/CylinderSurface.hpp"
0024 #include "Acts/Surfaces/RadialBounds.hpp"
0025 #include "Acts/Surfaces/Surface.hpp"
0026 #include "Acts/Surfaces/SurfaceBounds.hpp"
0027 #include "Acts/Utilities/BinningType.hpp"
0028 #include "Acts/Utilities/Helpers.hpp"
0029 
0030 #include <algorithm>
0031 #include <iterator>
0032 #include <vector>
0033 
0034 #include <boost/algorithm/string.hpp>
0035 #include <math.h>
0036 
0037 Acts::CylinderVolumeBuilder::CylinderVolumeBuilder(
0038     const Acts::CylinderVolumeBuilder::Config& cvbConfig,
0039     std::unique_ptr<const Logger> logger)
0040     : Acts::ITrackingVolumeBuilder(), m_cfg(), m_logger(std::move(logger)) {
0041   setConfiguration(cvbConfig);
0042 }
0043 
0044 Acts::CylinderVolumeBuilder::~CylinderVolumeBuilder() = default;
0045 
0046 void Acts::CylinderVolumeBuilder::setConfiguration(
0047     const Acts::CylinderVolumeBuilder::Config& cvbConfig) {
0048   // @todo check consistency
0049   // copy the configuration
0050   m_cfg = cvbConfig;
0051 }
0052 
0053 void Acts::CylinderVolumeBuilder::setLogger(
0054     std::unique_ptr<const Logger> newLogger) {
0055   m_logger = std::move(newLogger);
0056 }
0057 
0058 std::shared_ptr<Acts::TrackingVolume>
0059 Acts::CylinderVolumeBuilder::trackingVolume(
0060     const GeometryContext& gctx, TrackingVolumePtr existingVolume,
0061     std::shared_ptr<const VolumeBounds> externalBounds) const {
0062   ACTS_DEBUG("Configured to build volume : " << m_cfg.volumeName);
0063   if (existingVolume) {
0064     ACTS_DEBUG("- will wrap/enclose : " << existingVolume->volumeName());
0065   }
0066 
0067   // the return volume
0068   // -----------------------------------------------------------------------------
0069   MutableTrackingVolumePtr volume = nullptr;
0070 
0071   // now analyize the layers that are provided
0072   // -----------------------------------------------------
0073   ACTS_DEBUG("-> Building layers");
0074   LayerVector negativeLayers;
0075   LayerVector centralLayers;
0076   LayerVector positiveLayers;
0077 
0078   // the wrapping configuration
0079   WrappingConfig wConfig;
0080 
0081   // the layers are built by the layer builder
0082   if (m_cfg.layerBuilder) {
0083     // the negative Layers
0084     negativeLayers = m_cfg.layerBuilder->negativeLayers(gctx);
0085     // the central Layers
0086     centralLayers = m_cfg.layerBuilder->centralLayers(gctx);
0087     // the positive Layer
0088     positiveLayers = m_cfg.layerBuilder->positiveLayers(gctx);
0089   }
0090   ACTS_DEBUG("-> Building layers complete");
0091 
0092   // Build the confined volumes
0093   MutableTrackingVolumeVector centralVolumes;
0094   if (m_cfg.ctVolumeBuilder) {
0095     centralVolumes = m_cfg.ctVolumeBuilder->centralVolumes();
0096   }
0097 
0098   // (0) PREP WORK ------------------------------------------------
0099   //
0100   // a) volume config of the existing volume
0101   if (existingVolume) {
0102     // volume and existing volume
0103     auto existingBounds = dynamic_cast<const CylinderVolumeBounds*>(
0104         &existingVolume->volumeBounds());
0105     // set the inside values
0106     wConfig.existingVolumeConfig.present = true;
0107     wConfig.existingVolumeConfig.rMin =
0108         existingBounds->get(CylinderVolumeBounds::eMinR);
0109     wConfig.existingVolumeConfig.rMax =
0110         existingBounds->get(CylinderVolumeBounds::eMaxR);
0111     wConfig.existingVolumeConfig.zMin =
0112         existingVolume->center().z() -
0113         existingBounds->get(CylinderVolumeBounds::eHalfLengthZ);
0114     wConfig.existingVolumeConfig.zMax =
0115         existingVolume->center().z() +
0116         existingBounds->get(CylinderVolumeBounds::eHalfLengthZ);
0117   }
0118   //
0119   // b) outside config
0120   // the volume config for the Outside
0121   VolumeConfig externalBoundConfig;
0122   if (externalBounds) {
0123     const CylinderVolumeBounds* ocvBounds =
0124         dynamic_cast<const CylinderVolumeBounds*>(externalBounds.get());
0125     // the cast to CylinderVolumeBounds needs to be successful
0126     if (ocvBounds != nullptr) {
0127       // get values from the out bounds
0128       wConfig.externalVolumeConfig.present = true;
0129       wConfig.externalVolumeConfig.rMin =
0130           ocvBounds->get(CylinderVolumeBounds::eMinR);
0131       wConfig.externalVolumeConfig.rMax =
0132           ocvBounds->get(CylinderVolumeBounds::eMaxR);
0133       wConfig.externalVolumeConfig.zMin =
0134           -ocvBounds->get(CylinderVolumeBounds::eHalfLengthZ);
0135       wConfig.externalVolumeConfig.zMax =
0136           ocvBounds->get(CylinderVolumeBounds::eHalfLengthZ);
0137     }
0138   }
0139 
0140   // ---------------------------------------------
0141   // The Volume Config of the SubVolumes
0142   // ---------------------------------------------
0143   // sub volume / layer configuration (subVolumes only build of layers are
0144   // present)
0145   // --------------------------------------------------------------------------
0146   //
0147   // possible configurations are (so far only synchronised):
0148   //
0149   // | Negative Endcap | Barrel | Positive Endcap | -  all layers present
0150   //                   | Barrel |                   -  barrel present
0151   // | Negative Endcap |        | Positive Endcap | - only endcaps present
0152   //                                                -  no layer present
0153   // Check if already given through configuration
0154   //
0155   // (A) volume configuration
0156   //
0157 
0158   // Find out with Layer analysis
0159   // analyze the layers
0160   wConfig.nVolumeConfig = analyzeContent(gctx, negativeLayers, {});  // TODO
0161   wConfig.cVolumeConfig = analyzeContent(gctx, centralLayers, centralVolumes);
0162   wConfig.pVolumeConfig = analyzeContent(gctx, positiveLayers, {});  // TODO
0163 
0164   bool hasLayers = wConfig.nVolumeConfig.present ||
0165                    wConfig.cVolumeConfig.present ||
0166                    wConfig.pVolumeConfig.present;
0167 
0168   if (!hasLayers) {
0169     ACTS_INFO("No layers present, returning nullptr");
0170     return nullptr;
0171   }
0172 
0173   std::string layerConfiguration = "|";
0174   if (wConfig.nVolumeConfig.present) {
0175     // negative layers are present
0176     ACTS_VERBOSE("Negative layers are present: rmin, rmax | zmin, zmax = "
0177                  << wConfig.nVolumeConfig.toString());
0178     std::vector<std::string> centers;
0179     std::transform(negativeLayers.begin(), negativeLayers.end(),
0180                    std::back_inserter(centers), [&](const auto& layer) {
0181                      return std::to_string(
0182                          layer->surfaceRepresentation().center(gctx)[eZ]);
0183                    });
0184     ACTS_VERBOSE("-> z locations: " << boost::algorithm::join(centers, ", "));
0185     // add to the string output
0186     layerConfiguration += " Negative Endcap |";
0187   }
0188   if (wConfig.cVolumeConfig.present) {
0189     // central layers are present
0190     ACTS_VERBOSE("Central layers are present:  rmin, rmax | zmin, zmax = "
0191                  << wConfig.cVolumeConfig.toString());
0192     std::vector<std::string> centers;
0193     std::transform(centralLayers.begin(), centralLayers.end(),
0194                    std::back_inserter(centers), [&](const auto& layer) {
0195                      return std::to_string(VectorHelpers::perp(
0196                          layer->surfaceRepresentation().center(gctx)));
0197                    });
0198     ACTS_VERBOSE("-> radii: " << boost::algorithm::join(centers, ", "));
0199     // add to the string output
0200     layerConfiguration += " Barrel |";
0201   }
0202   if (wConfig.pVolumeConfig.present) {
0203     // positive layers are present
0204     ACTS_VERBOSE("Positive layers are present: rmin, rmax | zmin, zmax = "
0205                  << wConfig.pVolumeConfig.toString());
0206     std::vector<std::string> centers;
0207     std::transform(positiveLayers.begin(), positiveLayers.end(),
0208                    std::back_inserter(centers), [&](const auto& layer) {
0209                      return std::to_string(
0210                          layer->surfaceRepresentation().center(gctx)[eZ]);
0211                    });
0212     ACTS_VERBOSE("-> z locations: " << boost::algorithm::join(centers, ", "));
0213     // add to the string output
0214     layerConfiguration += " Positive Endcap |";
0215   }
0216   // screen output
0217   ACTS_DEBUG("Layer configuration is : " << layerConfiguration);
0218 
0219   // (B) LAYER Config SYNCHRONISATION ----------------------------------
0220   // synchronise the layer config
0221   ACTS_VERBOSE("Configurations after layer parsing " << '\n'
0222                                                      << wConfig.toString());
0223   // first let us arrange the new container volume
0224   wConfig.configureContainerVolume();
0225   ACTS_VERBOSE("Configuration after container synchronisation "
0226                << '\n'
0227                << wConfig.toString());
0228   // now let's understand the wrapping if needed
0229   if (wConfig.existingVolumeConfig.present) {
0230     wConfig.wrapInsertAttach();
0231     ACTS_VERBOSE("Configuration after wrapping, insertion, attachment "
0232                  << '\n'
0233                  << wConfig.toString());
0234   } else {
0235     // no wrapping around inner volume needed
0236     // however there could be central, positive & negative volume which will
0237     // need to be put into a container volume
0238     wConfig.wCondition = NoWrapping;
0239   }
0240 
0241   // (C) VOLUME CREATION ----------------------------------
0242   auto tvHelper = m_cfg.trackingVolumeHelper;
0243   // the barrel is always created
0244   auto barrel =
0245       wConfig.cVolumeConfig.present
0246           ? tvHelper->createTrackingVolume(
0247                 gctx, wConfig.cVolumeConfig.layers,
0248                 wConfig.cVolumeConfig.volumes, m_cfg.volumeMaterial,
0249                 wConfig.cVolumeConfig.rMin, wConfig.cVolumeConfig.rMax,
0250                 wConfig.cVolumeConfig.zMin, wConfig.cVolumeConfig.zMax,
0251                 m_cfg.volumeName + "::Barrel")
0252           : nullptr;
0253 
0254   // Helper method to check for
0255 
0256   // Helper method to create endcap volume
0257   auto createEndcap =
0258       [&](VolumeConfig& centralConfig, VolumeConfig& endcapConfig,
0259           const std::string& endcapName) -> MutableTrackingVolumePtr {
0260     // No config - no volume
0261     if (!endcapConfig.present) {
0262       return nullptr;
0263     }
0264     // Check for ring layout
0265     if (m_cfg.checkRingLayout) {
0266       ACTS_DEBUG("Configured to check for ring layout - parsing layers.");
0267       // Parsing loop for ring layout
0268       std::vector<double> innerRadii = {};
0269       std::vector<double> outerRadii = {};
0270       for (const auto& elay : endcapConfig.layers) {
0271         auto discBounds = dynamic_cast<const RadialBounds*>(
0272             &(elay->surfaceRepresentation().bounds()));
0273         if (discBounds != nullptr) {
0274           double tolerance = m_cfg.ringTolerance;
0275           // Search for the rmin value  - and insert if necessary
0276           double rMin = discBounds->rMin();
0277           auto innerSearch = std::ranges::find_if(innerRadii, [&](double r) {
0278             return std::abs(rMin - r) < tolerance;
0279           });
0280           if (innerSearch == innerRadii.end()) {
0281             innerRadii.push_back(rMin);
0282           }
0283           // Search for the rmax value - and insert if necessary
0284           double rMax = discBounds->rMax();
0285           auto outerSearch = std::ranges::find_if(outerRadii, [&](double r) {
0286             return std::abs(rMax - r) < tolerance;
0287           });
0288           if (outerSearch == outerRadii.end()) {
0289             outerRadii.push_back(rMax);
0290           }
0291         }
0292       }
0293 
0294       // we check radii for consistency from the inside outwards, so need to
0295       // sort
0296       std::ranges::sort(innerRadii);
0297       std::ranges::sort(outerRadii);
0298 
0299       ACTS_DEBUG("Inner radii:" << [&]() {
0300         std::stringstream ss;
0301         for (double f : innerRadii) {
0302           ss << " " << f;
0303         }
0304         return ss.str();
0305       }());
0306 
0307       ACTS_DEBUG("Outer radii:" << [&]() {
0308         std::stringstream ss;
0309         for (double f : outerRadii) {
0310           ss << " " << f;
0311         }
0312         return ss.str();
0313       }());
0314       // Result of the parsing loop
0315       if (innerRadii.size() == outerRadii.size() && !innerRadii.empty()) {
0316         bool consistent = true;
0317         // The inter volume radii
0318         ACTS_VERBOSE("Checking ring radius consistency");
0319         std::vector<double> interRadii = {};
0320         for (std::size_t ir = 1; ir < innerRadii.size(); ++ir) {
0321           // Check whether inner/outer radii are consistent
0322           ACTS_VERBOSE(
0323               "or #" << ir - 1 << " < ir #" << ir << ": " << outerRadii[ir - 1]
0324                      << " < " << innerRadii[ir] << ", ok: "
0325                      << (outerRadii[ir - 1] < innerRadii[ir] ? "yes" : "no"));
0326           if (outerRadii[ir - 1] < innerRadii[ir]) {
0327             interRadii.push_back(0.5 * (outerRadii[ir - 1] + innerRadii[ir]));
0328           } else {
0329             consistent = false;
0330             break;
0331           }
0332         }
0333         // Continue if the ring layout is consistent
0334         if (consistent) {
0335           ACTS_DEBUG("Ring layout detection: " << innerRadii.size()
0336                                                << " volumes.");
0337           // Separate the Layers into volumes
0338           std::vector<std::pair<double, double>> volumeRminRmax = {};
0339           for (unsigned int ii = 0; ii < interRadii.size(); ++ii) {
0340             if (ii == 0) {
0341               volumeRminRmax.push_back({endcapConfig.rMin, interRadii[ii]});
0342             }
0343             if (ii + 1 < interRadii.size()) {
0344               volumeRminRmax.push_back({interRadii[ii], interRadii[ii + 1]});
0345             } else {
0346               volumeRminRmax.push_back({interRadii[ii], endcapConfig.rMax});
0347             }
0348           }
0349           auto ringLayers =
0350               std::vector<LayerVector>(innerRadii.size(), LayerVector());
0351           // Filling loop
0352           for (const auto& elay : endcapConfig.layers) {
0353             // Getting the reference radius
0354             double test = elay->surfaceRepresentation().referencePositionValue(
0355                 gctx, AxisDirection::AxisR);
0356             // Find the right bin
0357             auto ringVolume =
0358                 std::ranges::find_if(volumeRminRmax, [&](const auto& vrr) {
0359                   return (test > vrr.first && test < vrr.second);
0360                 });
0361             if (ringVolume != volumeRminRmax.end()) {
0362               unsigned int ringBin =
0363                   std::distance(volumeRminRmax.begin(), ringVolume);
0364               ringLayers[ringBin].push_back(elay);
0365             }
0366           }
0367           // Subvolume construction
0368           ACTS_DEBUG("Ring layout configuration: ");
0369           // Endcap container
0370           std::vector<TrackingVolumePtr> endcapContainer;
0371           unsigned int ir = 0;
0372           for (auto& rLayers : ringLayers) {
0373             ACTS_DEBUG(" - ring volume " << ir << " with " << rLayers.size()
0374                                          << " layers, and rmin/rmax = "
0375                                          << volumeRminRmax[ir].first << "/"
0376                                          << volumeRminRmax[ir].second);
0377             endcapContainer.push_back(tvHelper->createTrackingVolume(
0378                 gctx, rLayers, centralConfig.volumes, m_cfg.volumeMaterial,
0379                 volumeRminRmax[ir].first, volumeRminRmax[ir].second,
0380                 endcapConfig.zMin, endcapConfig.zMax,
0381                 m_cfg.volumeName + endcapName + std::string("::Ring") +
0382                     std::to_string(ir)));
0383             ++ir;
0384           }
0385           // Return a container of ring volumes
0386           return tvHelper->createContainerTrackingVolume(gctx, endcapContainer);
0387         } else {
0388           ACTS_DEBUG("Ring radii found to be inconsistent");
0389         }
0390       } else {
0391         ACTS_DEBUG("Have " << innerRadii.size() << " inner radii and "
0392                            << outerRadii.size() << " outer radii");
0393       }
0394     }
0395 
0396     // No ring layout - return single volume
0397     return tvHelper->createTrackingVolume(
0398         gctx, endcapConfig.layers, centralConfig.volumes, m_cfg.volumeMaterial,
0399         endcapConfig.rMin, endcapConfig.rMax, endcapConfig.zMin,
0400         endcapConfig.zMax, m_cfg.volumeName + endcapName);
0401   };
0402 
0403   // The negative endcap is created if present
0404   auto nEndcap = createEndcap(wConfig.cVolumeConfig, wConfig.nVolumeConfig,
0405                               "::NegativeEndcap");
0406 
0407   // The positive endcap is created if present
0408   auto pEndcap = createEndcap(wConfig.cVolumeConfig, wConfig.pVolumeConfig,
0409                               "::PositiveEndcap");
0410 
0411   ACTS_DEBUG("Newly created volume(s) will be " << wConfig.wConditionScreen);
0412   // Standalone container, full wrapping, full insertion & if no existing volume
0413   // is present needs a bare triple
0414   if (wConfig.wCondition == Wrapping || wConfig.wCondition == Inserting ||
0415       wConfig.wCondition == NoWrapping) {
0416     ACTS_VERBOSE("Combined new container is being built.");
0417     // Stuff into the container what you have
0418     std::vector<TrackingVolumePtr> volumesContainer;
0419     if (nEndcap) {
0420       volumesContainer.push_back(nEndcap);
0421       volume = nEndcap;
0422       // Set the inner or outer material
0423       if (!m_cfg.buildToRadiusZero) {
0424         volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[0],
0425                                        Acts::tubeInnerCover);
0426       }
0427       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[1],
0428                                      Acts::tubeOuterCover);
0429       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[2],
0430                                      Acts::negativeFaceXY);
0431       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[3],
0432                                      Acts::positiveFaceXY);
0433     }
0434     if (barrel) {
0435       // Assign boundary material if existing
0436       volumesContainer.push_back(barrel);
0437       volume = barrel;
0438       // Set the inner or outer material
0439       if (!m_cfg.buildToRadiusZero) {
0440         volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[0],
0441                                        Acts::tubeInnerCover);
0442       }
0443       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[1],
0444                                      Acts::tubeOuterCover);
0445       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[3],
0446                                      Acts::negativeFaceXY);
0447       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[4],
0448                                      Acts::positiveFaceXY);
0449     }
0450     if (pEndcap) {
0451       volumesContainer.push_back(pEndcap);
0452       volume = pEndcap;
0453       // Set the inner or outer material
0454       if (!m_cfg.buildToRadiusZero) {
0455         volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[0],
0456                                        Acts::tubeInnerCover);
0457       }
0458       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[1],
0459                                      Acts::tubeOuterCover);
0460       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[4],
0461                                      Acts::negativeFaceXY);
0462       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[5],
0463                                      Acts::positiveFaceXY);
0464     }
0465     // and low lets create the new volume
0466     volume =
0467         volumesContainer.size() > 1
0468             ? tvHelper->createContainerTrackingVolume(gctx, volumesContainer)
0469             : volume;
0470   } else if (wConfig.wCondition != Attaching) {
0471     // the new volume is the only one present
0472     volume = nEndcap ? nEndcap : (barrel ? barrel : pEndcap);
0473   }
0474 
0475   // Prepare the gap volumes first
0476   TrackingVolumePtr existingVolumeCp = existingVolume;
0477   // Check if further action is needed on existing volumes and gap volumes
0478   if (existingVolumeCp) {
0479     // Check if gaps are needed
0480     std::vector<TrackingVolumePtr> existingContainer;
0481     if (wConfig.fGapVolumeConfig.present) {
0482       // create the gap volume
0483       auto fGap = tvHelper->createGapTrackingVolume(
0484           gctx, wConfig.cVolumeConfig.volumes, m_cfg.volumeMaterial,
0485           wConfig.fGapVolumeConfig.rMin, wConfig.fGapVolumeConfig.rMax,
0486           wConfig.fGapVolumeConfig.zMin, wConfig.fGapVolumeConfig.zMax, 1,
0487           false, m_cfg.volumeName + "::fGap");
0488       // push it back into the list
0489       existingContainer.push_back(fGap);
0490     }
0491     existingContainer.push_back(existingVolumeCp);
0492     if (wConfig.sGapVolumeConfig.present) {
0493       // create the gap volume
0494       auto sGap = tvHelper->createGapTrackingVolume(
0495           gctx, wConfig.cVolumeConfig.volumes, m_cfg.volumeMaterial,
0496           wConfig.sGapVolumeConfig.rMin, wConfig.sGapVolumeConfig.rMax,
0497           wConfig.sGapVolumeConfig.zMin, wConfig.sGapVolumeConfig.zMax, 1,
0498           false, m_cfg.volumeName + "::sGap");
0499       // push it back into the list
0500       existingContainer.push_back(sGap);
0501     }
0502 
0503     // And low lets create the new existing volume with gaps
0504     existingVolumeCp =
0505         existingContainer.size() > 1
0506             ? tvHelper->createContainerTrackingVolume(gctx, existingContainer)
0507             : existingVolumeCp;
0508 
0509     // for central wrapping or inserting, we need to update once more
0510     // clear the container
0511     existingContainer.clear();
0512     if (wConfig.wCondition == CentralWrapping) {
0513       existingContainer.push_back(existingVolumeCp);
0514       existingContainer.push_back(barrel);
0515     } else if (wConfig.wCondition == CentralInserting) {
0516       existingContainer.push_back(barrel);
0517       existingContainer.push_back(existingVolumeCp);
0518     }
0519     // update
0520     existingVolumeCp =
0521         !existingContainer.empty()
0522             ? tvHelper->createContainerTrackingVolume(gctx, existingContainer)
0523             : existingVolumeCp;
0524 
0525     std::vector<TrackingVolumePtr> totalContainer;
0526     // check what to do with the existing
0527     if (wConfig.wCondition == Attaching ||
0528         wConfig.wCondition == CentralWrapping ||
0529         wConfig.wCondition == CentralInserting) {
0530       if (nEndcap) {
0531         totalContainer.push_back(nEndcap);
0532       }
0533       totalContainer.push_back(existingVolumeCp);
0534       if (pEndcap) {
0535         totalContainer.push_back(pEndcap);
0536       }
0537     } else if (wConfig.wCondition == Inserting && volume) {
0538       totalContainer.push_back(volume);
0539       totalContainer.push_back(existingVolumeCp);
0540     } else if (wConfig.wCondition == Wrapping && volume) {
0541       totalContainer.push_back(existingVolumeCp);
0542       totalContainer.push_back(volume);
0543     } else {
0544       ACTS_ERROR("Misconfiguration in volume building detected.");
0545       return nullptr;
0546     }
0547     // now create the new container volume
0548     volume = tvHelper->createContainerTrackingVolume(gctx, totalContainer);
0549   }
0550 
0551   return volume;
0552 }
0553 
0554 // -----------------------------
0555 Acts::VolumeConfig Acts::CylinderVolumeBuilder::analyzeContent(
0556     const GeometryContext& gctx, const LayerVector& lVector,
0557     const MutableTrackingVolumeVector& mtvVector) const {
0558   // @TODO add envelope tolerance
0559   //
0560   // return object
0561   VolumeConfig lConfig;
0562   // only if the vector is present it can actually be analyzed
0563   if (!lVector.empty() || !mtvVector.empty()) {
0564     // we have layers
0565     lConfig.present = true;
0566     // loop over the layer
0567     for (auto& layer : lVector) {
0568       // the thickness of the layer needs to be taken into account
0569       double thickness = layer->thickness();
0570       // get the center of the layer
0571       const Vector3& center = layer->surfaceRepresentation().center(gctx);
0572       // check if it is a cylinder layer
0573       const CylinderLayer* cLayer =
0574           dynamic_cast<const CylinderLayer*>(layer.get());
0575       if (cLayer != nullptr) {
0576         // now we have access to all the information
0577         double rMinC =
0578             cLayer->surfaceRepresentation().bounds().get(CylinderBounds::eR) -
0579             0.5 * thickness;
0580         double rMaxC =
0581             cLayer->surfaceRepresentation().bounds().get(CylinderBounds::eR) +
0582             0.5 * thickness;
0583 
0584         double hZ = cLayer->surfaceRepresentation().bounds().get(
0585             CylinderBounds::eHalfLengthZ);
0586         lConfig.rMin =
0587             std::min(lConfig.rMin, rMinC - m_cfg.layerEnvelopeR.first);
0588         lConfig.rMax =
0589             std::max(lConfig.rMax, rMaxC + m_cfg.layerEnvelopeR.second);
0590         lConfig.zMin =
0591             std::min(lConfig.zMin, center.z() - hZ - m_cfg.layerEnvelopeZ);
0592         lConfig.zMax =
0593             std::max(lConfig.zMax, center.z() + hZ + m_cfg.layerEnvelopeZ);
0594       }
0595       // proceed further if it is a Disc layer
0596       const RadialBounds* dBounds = dynamic_cast<const RadialBounds*>(
0597           &(layer->surfaceRepresentation().bounds()));
0598       if (dBounds != nullptr) {
0599         // now we have access to all the information
0600         double rMinD = dBounds->rMin();
0601         double rMaxD = dBounds->rMax();
0602         double zMinD = center.z() - 0.5 * thickness;
0603         double zMaxD = center.z() + 0.5 * thickness;
0604         lConfig.rMin =
0605             std::min(lConfig.rMin, rMinD - m_cfg.layerEnvelopeR.first);
0606         lConfig.rMax =
0607             std::max(lConfig.rMax, rMaxD + m_cfg.layerEnvelopeR.second);
0608         lConfig.rMin = std::max(0.0, lConfig.rMin);
0609         lConfig.zMin = std::min(lConfig.zMin, zMinD - m_cfg.layerEnvelopeZ);
0610         lConfig.zMax = std::max(lConfig.zMax, zMaxD + m_cfg.layerEnvelopeZ);
0611       }
0612     }
0613     for (auto& volume : mtvVector) {
0614       const CylinderVolumeBounds* cvBounds =
0615           dynamic_cast<const CylinderVolumeBounds*>(&volume->volumeBounds());
0616       if (cvBounds != nullptr) {
0617         lConfig.rMin =
0618             std::min(lConfig.rMin, cvBounds->get(CylinderVolumeBounds::eMinR));
0619         lConfig.rMax =
0620             std::max(lConfig.rMax, cvBounds->get(CylinderVolumeBounds::eMaxR));
0621         lConfig.zMin = std::min(
0622             lConfig.zMin, -cvBounds->get(CylinderVolumeBounds::eHalfLengthZ));
0623         lConfig.zMax = std::max(
0624             lConfig.zMax, cvBounds->get(CylinderVolumeBounds::eHalfLengthZ));
0625       }
0626     }
0627   }
0628 
0629   // Set the layers to the layer vector
0630   lConfig.layers = lVector;
0631   // set the layers to the layer vector
0632   lConfig.volumes = mtvVector;
0633   // overwrite to radius 0 if needed
0634   if (m_cfg.buildToRadiusZero) {
0635     ACTS_VERBOSE("This layer builder is configured to build to the beamline.");
0636     lConfig.rMin = 0.;
0637   }
0638 
0639   // and return what you have
0640   return lConfig;
0641 }