Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:09:36

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2016-2020 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 http://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) {
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) {
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) {
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) {
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
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) {
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::find_if(
0278               innerRadii.begin(), innerRadii.end(), [&](double reference) {
0279                 return std::abs(rMin - reference) < tolerance;
0280               });
0281           if (innerSearch == innerRadii.end()) {
0282             innerRadii.push_back(rMin);
0283           }
0284           // Search for the rmax value - and insert if necessary
0285           double rMax = discBounds->rMax();
0286           auto outerSearch = std::find_if(
0287               outerRadii.begin(), outerRadii.end(), [&](double reference) {
0288                 return std::abs(rMax - reference) < tolerance;
0289               });
0290           if (outerSearch == outerRadii.end()) {
0291             outerRadii.push_back(rMax);
0292           }
0293         }
0294       }
0295 
0296       // we check radii for consistency from the inside outwards, so need to
0297       // sort
0298       std::sort(innerRadii.begin(), innerRadii.end());
0299       std::sort(outerRadii.begin(), outerRadii.end());
0300 
0301       ACTS_DEBUG("Inner radii:" << [&]() {
0302         std::stringstream ss;
0303         for (double f : innerRadii) {
0304           ss << " " << f;
0305         }
0306         return ss.str();
0307       }());
0308 
0309       ACTS_DEBUG("Outer radii:" << [&]() {
0310         std::stringstream ss;
0311         for (double f : outerRadii) {
0312           ss << " " << f;
0313         }
0314         return ss.str();
0315       }());
0316       // Result of the parsing loop
0317       if (innerRadii.size() == outerRadii.size() && !innerRadii.empty()) {
0318         bool consistent = true;
0319         // The inter volume radii
0320         ACTS_VERBOSE("Checking ring radius consistency");
0321         std::vector<double> interRadii = {};
0322         for (int ir = 1; ir < int(innerRadii.size()); ++ir) {
0323           // Check whether inner/outer radii are consistent
0324           ACTS_VERBOSE(
0325               "or #" << ir - 1 << " < ir #" << ir << ": " << outerRadii[ir - 1]
0326                      << " < " << innerRadii[ir] << ", ok: "
0327                      << (outerRadii[ir - 1] < innerRadii[ir] ? "yes" : "no"));
0328           if (outerRadii[ir - 1] < innerRadii[ir]) {
0329             interRadii.push_back(0.5 * (outerRadii[ir - 1] + innerRadii[ir]));
0330           } else {
0331             consistent = false;
0332             break;
0333           }
0334         }
0335         // Continue if the ring layout is consistent
0336         if (consistent) {
0337           ACTS_DEBUG("Ring layout detection: " << innerRadii.size()
0338                                                << " volumes.");
0339           // Separate the Layers into volumes
0340           std::vector<std::pair<double, double>> volumeRminRmax = {};
0341           for (unsigned int ii = 0; ii < interRadii.size(); ++ii) {
0342             if (ii == 0) {
0343               volumeRminRmax.push_back({endcapConfig.rMin, interRadii[ii]});
0344             }
0345             if (ii + 1 < interRadii.size()) {
0346               volumeRminRmax.push_back({interRadii[ii], interRadii[ii + 1]});
0347             } else {
0348               volumeRminRmax.push_back({interRadii[ii], endcapConfig.rMax});
0349             }
0350           }
0351           auto ringLayers =
0352               std::vector<LayerVector>(innerRadii.size(), LayerVector());
0353           // Filling loop
0354           for (const auto& elay : endcapConfig.layers) {
0355             // Getting the reference radius
0356             double test =
0357                 elay->surfaceRepresentation().binningPositionValue(gctx, binR);
0358             // Find the right bin
0359             auto ringVolume = std::find_if(
0360                 volumeRminRmax.begin(), volumeRminRmax.end(),
0361                 [&](const auto& reference) {
0362                   return (test > reference.first && test < reference.second);
0363                 });
0364             if (ringVolume != volumeRminRmax.end()) {
0365               unsigned int ringBin =
0366                   std::distance(volumeRminRmax.begin(), ringVolume);
0367               ringLayers[ringBin].push_back(elay);
0368             }
0369           }
0370           // Subvolume construction
0371           ACTS_DEBUG("Ring layout configuration: ");
0372           // Endcap container
0373           std::vector<TrackingVolumePtr> endcapContainer;
0374           unsigned int ir = 0;
0375           for (auto& rLayers : ringLayers) {
0376             ACTS_DEBUG(" - ring volume " << ir << " with " << rLayers.size()
0377                                          << " layers, and rmin/rmax = "
0378                                          << volumeRminRmax[ir].first << "/"
0379                                          << volumeRminRmax[ir].second);
0380             endcapContainer.push_back(tvHelper->createTrackingVolume(
0381                 gctx, rLayers, centralConfig.volumes, m_cfg.volumeMaterial,
0382                 volumeRminRmax[ir].first, volumeRminRmax[ir].second,
0383                 endcapConfig.zMin, endcapConfig.zMax,
0384                 m_cfg.volumeName + endcapName + std::string("::Ring") +
0385                     std::to_string(ir)));
0386             ++ir;
0387           }
0388           // Return a container of ring volumes
0389           return tvHelper->createContainerTrackingVolume(gctx, endcapContainer);
0390         } else {
0391           ACTS_DEBUG("Ring radii found to be inconsistent");
0392         }
0393       } else {
0394         ACTS_DEBUG("Have " << innerRadii.size() << " inner radii and "
0395                            << outerRadii.size() << " outer radii");
0396       }
0397     }
0398 
0399     // No ring layout - return single volume
0400     return tvHelper->createTrackingVolume(
0401         gctx, endcapConfig.layers, centralConfig.volumes, m_cfg.volumeMaterial,
0402         endcapConfig.rMin, endcapConfig.rMax, endcapConfig.zMin,
0403         endcapConfig.zMax, m_cfg.volumeName + endcapName);
0404   };
0405 
0406   // The negative endcap is created if present
0407   auto nEndcap = createEndcap(wConfig.cVolumeConfig, wConfig.nVolumeConfig,
0408                               "::NegativeEndcap");
0409 
0410   // The positive endcap is created if present
0411   auto pEndcap = createEndcap(wConfig.cVolumeConfig, wConfig.pVolumeConfig,
0412                               "::PositiveEndcap");
0413 
0414   ACTS_DEBUG("Newly created volume(s) will be " << wConfig.wConditionScreen);
0415   // Standalone container, full wrapping, full insertion & if no existing volume
0416   // is present needs a bare triple
0417   if (wConfig.wCondition == Wrapping || wConfig.wCondition == Inserting ||
0418       wConfig.wCondition == NoWrapping) {
0419     ACTS_VERBOSE("Combined new container is being built.");
0420     // Stuff into the container what you have
0421     std::vector<TrackingVolumePtr> volumesContainer;
0422     if (nEndcap) {
0423       volumesContainer.push_back(nEndcap);
0424       volume = nEndcap;
0425       // Set the inner or outer material
0426       if (!m_cfg.buildToRadiusZero) {
0427         volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[0],
0428                                        Acts::tubeInnerCover);
0429       }
0430       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[1],
0431                                      Acts::tubeOuterCover);
0432       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[2],
0433                                      Acts::negativeFaceXY);
0434       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[3],
0435                                      Acts::positiveFaceXY);
0436     }
0437     if (barrel) {
0438       // Assign boundary material if existing
0439       volumesContainer.push_back(barrel);
0440       volume = barrel;
0441       // Set the inner or outer material
0442       if (!m_cfg.buildToRadiusZero) {
0443         volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[0],
0444                                        Acts::tubeInnerCover);
0445       }
0446       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[1],
0447                                      Acts::tubeOuterCover);
0448       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[3],
0449                                      Acts::negativeFaceXY);
0450       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[4],
0451                                      Acts::positiveFaceXY);
0452     }
0453     if (pEndcap) {
0454       volumesContainer.push_back(pEndcap);
0455       volume = pEndcap;
0456       // Set the inner or outer material
0457       if (!m_cfg.buildToRadiusZero) {
0458         volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[0],
0459                                        Acts::tubeInnerCover);
0460       }
0461       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[1],
0462                                      Acts::tubeOuterCover);
0463       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[4],
0464                                      Acts::negativeFaceXY);
0465       volume->assignBoundaryMaterial(m_cfg.boundaryMaterial[5],
0466                                      Acts::positiveFaceXY);
0467     }
0468     // and low lets create the new volume
0469     volume =
0470         volumesContainer.size() > 1
0471             ? tvHelper->createContainerTrackingVolume(gctx, volumesContainer)
0472             : volume;
0473   } else if (wConfig.wCondition != Attaching) {
0474     // the new volume is the only one present
0475     volume = nEndcap ? nEndcap : (barrel ? barrel : pEndcap);
0476   }
0477 
0478   // Prepare the gap volumes first
0479   TrackingVolumePtr existingVolumeCp = existingVolume;
0480   // Check if further action is needed on existing volumes and gap volumes
0481   if (existingVolumeCp) {
0482     // Check if gaps are needed
0483     std::vector<TrackingVolumePtr> existingContainer;
0484     if (wConfig.fGapVolumeConfig) {
0485       // create the gap volume
0486       auto fGap = tvHelper->createGapTrackingVolume(
0487           gctx, wConfig.cVolumeConfig.volumes, m_cfg.volumeMaterial,
0488           wConfig.fGapVolumeConfig.rMin, wConfig.fGapVolumeConfig.rMax,
0489           wConfig.fGapVolumeConfig.zMin, wConfig.fGapVolumeConfig.zMax, 1,
0490           false, m_cfg.volumeName + "::fGap");
0491       // push it back into the list
0492       existingContainer.push_back(fGap);
0493     }
0494     existingContainer.push_back(existingVolumeCp);
0495     if (wConfig.sGapVolumeConfig) {
0496       // create the gap volume
0497       auto sGap = tvHelper->createGapTrackingVolume(
0498           gctx, wConfig.cVolumeConfig.volumes, m_cfg.volumeMaterial,
0499           wConfig.sGapVolumeConfig.rMin, wConfig.sGapVolumeConfig.rMax,
0500           wConfig.sGapVolumeConfig.zMin, wConfig.sGapVolumeConfig.zMax, 1,
0501           false, m_cfg.volumeName + "::sGap");
0502       // push it back into the list
0503       existingContainer.push_back(sGap);
0504     }
0505 
0506     // And low lets create the new existing volume with gaps
0507     existingVolumeCp =
0508         existingContainer.size() > 1
0509             ? tvHelper->createContainerTrackingVolume(gctx, existingContainer)
0510             : existingVolumeCp;
0511 
0512     // for central wrapping or inserting, we need to update once more
0513     // clear the container
0514     existingContainer.clear();
0515     if (wConfig.wCondition == CentralWrapping) {
0516       existingContainer.push_back(existingVolumeCp);
0517       existingContainer.push_back(barrel);
0518     } else if (wConfig.wCondition == CentralInserting) {
0519       existingContainer.push_back(barrel);
0520       existingContainer.push_back(existingVolumeCp);
0521     }
0522     // update
0523     existingVolumeCp =
0524         !existingContainer.empty()
0525             ? tvHelper->createContainerTrackingVolume(gctx, existingContainer)
0526             : existingVolumeCp;
0527 
0528     std::vector<TrackingVolumePtr> totalContainer;
0529     // check what to do with the existing
0530     if (wConfig.wCondition == Attaching ||
0531         wConfig.wCondition == CentralWrapping ||
0532         wConfig.wCondition == CentralInserting) {
0533       if (nEndcap) {
0534         totalContainer.push_back(nEndcap);
0535       }
0536       totalContainer.push_back(existingVolumeCp);
0537       if (pEndcap) {
0538         totalContainer.push_back(pEndcap);
0539       }
0540     } else if (wConfig.wCondition == Inserting && volume) {
0541       totalContainer.push_back(volume);
0542       totalContainer.push_back(existingVolumeCp);
0543     } else if (wConfig.wCondition == Wrapping && volume) {
0544       totalContainer.push_back(existingVolumeCp);
0545       totalContainer.push_back(volume);
0546     } else {
0547       ACTS_ERROR("Misconfiguration in volume building detected.");
0548       return nullptr;
0549     }
0550     // now create the new container volume
0551     volume = tvHelper->createContainerTrackingVolume(gctx, totalContainer);
0552   }
0553 
0554   return volume;
0555 }
0556 
0557 // -----------------------------
0558 Acts::VolumeConfig Acts::CylinderVolumeBuilder::analyzeContent(
0559     const GeometryContext& gctx, const LayerVector& lVector,
0560     const MutableTrackingVolumeVector& mtvVector) const {
0561   // @TODO add envelope tolerance
0562   //
0563   // return object
0564   VolumeConfig lConfig;
0565   // only if the vector is present it can actually be analyzed
0566   if (!lVector.empty() || !mtvVector.empty()) {
0567     // we have layers
0568     lConfig.present = true;
0569     // loop over the layer
0570     for (auto& layer : lVector) {
0571       // the thickness of the layer needs to be taken into account
0572       double thickness = layer->thickness();
0573       // get the center of the layer
0574       const Vector3& center = layer->surfaceRepresentation().center(gctx);
0575       // check if it is a cylinder layer
0576       const CylinderLayer* cLayer =
0577           dynamic_cast<const CylinderLayer*>(layer.get());
0578       if (cLayer != nullptr) {
0579         // now we have access to all the information
0580         double rMinC =
0581             cLayer->surfaceRepresentation().bounds().get(CylinderBounds::eR) -
0582             0.5 * thickness;
0583         double rMaxC =
0584             cLayer->surfaceRepresentation().bounds().get(CylinderBounds::eR) +
0585             0.5 * thickness;
0586 
0587         double hZ = cLayer->surfaceRepresentation().bounds().get(
0588             CylinderBounds::eHalfLengthZ);
0589         lConfig.rMin =
0590             std::min(lConfig.rMin, rMinC - m_cfg.layerEnvelopeR.first);
0591         lConfig.rMax =
0592             std::max(lConfig.rMax, rMaxC + m_cfg.layerEnvelopeR.second);
0593         lConfig.zMin =
0594             std::min(lConfig.zMin, center.z() - hZ - m_cfg.layerEnvelopeZ);
0595         lConfig.zMax =
0596             std::max(lConfig.zMax, center.z() + hZ + m_cfg.layerEnvelopeZ);
0597       }
0598       // proceed further if it is a Disc layer
0599       const RadialBounds* dBounds = dynamic_cast<const RadialBounds*>(
0600           &(layer->surfaceRepresentation().bounds()));
0601       if (dBounds != nullptr) {
0602         // now we have access to all the information
0603         double rMinD = dBounds->rMin();
0604         double rMaxD = dBounds->rMax();
0605         double zMinD = center.z() - 0.5 * thickness;
0606         double zMaxD = center.z() + 0.5 * thickness;
0607         lConfig.rMin =
0608             std::min(lConfig.rMin, rMinD - m_cfg.layerEnvelopeR.first);
0609         lConfig.rMax =
0610             std::max(lConfig.rMax, rMaxD + m_cfg.layerEnvelopeR.second);
0611         lConfig.rMin = std::max(0.0, lConfig.rMin);
0612         lConfig.zMin = std::min(lConfig.zMin, zMinD - m_cfg.layerEnvelopeZ);
0613         lConfig.zMax = std::max(lConfig.zMax, zMaxD + m_cfg.layerEnvelopeZ);
0614       }
0615     }
0616     for (auto& volume : mtvVector) {
0617       const CylinderVolumeBounds* cvBounds =
0618           dynamic_cast<const CylinderVolumeBounds*>(&volume->volumeBounds());
0619       if (cvBounds != nullptr) {
0620         lConfig.rMin =
0621             std::min(lConfig.rMin, cvBounds->get(CylinderVolumeBounds::eMinR));
0622         lConfig.rMax =
0623             std::max(lConfig.rMax, cvBounds->get(CylinderVolumeBounds::eMaxR));
0624         lConfig.zMin = std::min(
0625             lConfig.zMin, -cvBounds->get(CylinderVolumeBounds::eHalfLengthZ));
0626         lConfig.zMax = std::max(
0627             lConfig.zMax, cvBounds->get(CylinderVolumeBounds::eHalfLengthZ));
0628       }
0629     }
0630   }
0631 
0632   // Set the layers to the layer vector
0633   lConfig.layers = lVector;
0634   // set the layers to the layer vector
0635   lConfig.volumes = mtvVector;
0636   // overwrite to radius 0 if needed
0637   if (m_cfg.buildToRadiusZero) {
0638     ACTS_VERBOSE("This layer builder is configured to build to the beamline.");
0639     lConfig.rMin = 0.;
0640   }
0641 
0642   // and return what you have
0643   return lConfig;
0644 }