Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-10 07:46:29

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/CylinderVolumeHelper.hpp"
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Geometry/BoundarySurfaceT.hpp"
0013 #include "Acts/Geometry/CylinderLayer.hpp"
0014 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0015 #include "Acts/Geometry/DiscLayer.hpp"
0016 #include "Acts/Geometry/GlueVolumesDescriptor.hpp"
0017 #include "Acts/Geometry/ILayerArrayCreator.hpp"
0018 #include "Acts/Geometry/ITrackingVolumeArrayCreator.hpp"
0019 #include "Acts/Geometry/Layer.hpp"
0020 #include "Acts/Geometry/TrackingVolume.hpp"
0021 #include "Acts/Geometry/VolumeBounds.hpp"
0022 #include "Acts/Material/ISurfaceMaterial.hpp"
0023 #include "Acts/Surfaces/CylinderBounds.hpp"
0024 #include "Acts/Surfaces/CylinderSurface.hpp"
0025 #include "Acts/Surfaces/DiscSurface.hpp"
0026 #include "Acts/Surfaces/RadialBounds.hpp"
0027 #include "Acts/Surfaces/RegularSurface.hpp"
0028 #include "Acts/Surfaces/Surface.hpp"
0029 #include "Acts/Surfaces/SurfaceArray.hpp"
0030 #include "Acts/Surfaces/SurfaceBounds.hpp"
0031 #include "Acts/Utilities/BinUtility.hpp"
0032 
0033 #include <algorithm>
0034 #include <cmath>
0035 #include <cstddef>
0036 #include <iosfwd>
0037 #include <memory>
0038 #include <numbers>
0039 #include <ostream>
0040 #include <utility>
0041 
0042 namespace Acts {
0043 
0044 CylinderVolumeHelper::CylinderVolumeHelper(
0045     const CylinderVolumeHelper::Config& cvhConfig,
0046     std::unique_ptr<const Logger> logger)
0047     : ITrackingVolumeHelper(), m_cfg(), m_logger(std::move(logger)) {
0048   setConfiguration(cvhConfig);
0049 }
0050 
0051 // configuration
0052 void CylinderVolumeHelper::setConfiguration(
0053     const CylinderVolumeHelper::Config& cvhConfig) {
0054   // @todo check consistency
0055   // copy the configuration
0056   m_cfg = cvhConfig;
0057 }
0058 
0059 void CylinderVolumeHelper::setLogger(std::unique_ptr<const Logger> newLogger) {
0060   m_logger = std::move(newLogger);
0061 }
0062 
0063 std::shared_ptr<TrackingVolume> CylinderVolumeHelper::createTrackingVolume(
0064     const GeometryContext& gctx, const LayerVector& layers,
0065     std::shared_ptr<const IVolumeMaterial> volumeMaterial,
0066     std::shared_ptr<VolumeBounds> volumeBounds,
0067     MutableTrackingVolumeVector mtvVector, const Transform3& transform,
0068     const std::string& volumeName, BinningType bType) const {
0069   // the final one to build / sensitive Volume / Bounds
0070   MutableTrackingVolumePtr tVolume = nullptr;
0071   // the layer array
0072   std::unique_ptr<const LayerArray> layerArray = nullptr;
0073 
0074   // Cases are:
0075   // (1) volumeBounds && transform : use both information
0076   // (2) volumeBounds && transform==identity : centered around 0, but with
0077   //     given bounds
0078   // (3) !volumeBounds && transform : estimate size from layers,
0079   //     use transform
0080   // (4) !volumeBounds && transform==identity : estimate size &
0081   //     translation from layers
0082   bool idTrf = transform.isApprox(Transform3::Identity());
0083 
0084   auto cylinderBounds =
0085       std::dynamic_pointer_cast<CylinderVolumeBounds>(volumeBounds);
0086   // this is the implementation of CylinderVolumeHelper
0087   if (volumeBounds != nullptr && cylinderBounds == nullptr) {
0088     ACTS_WARNING(
0089         "[!] Problem: given bounds are not cylindrical - return nullptr");
0090     return tVolume;
0091   }
0092   // this is only needed if layers are provided
0093   if (!layers.empty()) {
0094     // the raw data
0095     double rMinRaw = 0.;
0096     double rMaxRaw = 0.;
0097     double zMinRaw = 0.;
0098     double zMaxRaw = 0.;
0099 
0100     AxisDirection bValue = AxisDirection::AxisR;
0101 
0102     // check the dimension and fill raw data
0103     if (!estimateAndCheckDimension(gctx, layers, cylinderBounds, transform,
0104                                    rMinRaw, rMaxRaw, zMinRaw, zMaxRaw, bValue,
0105                                    bType)) {
0106       ACTS_WARNING(
0107           "[!] Problem with given dimensions - return nullptr and "
0108           "delete provided objects");
0109       return tVolume;
0110     }
0111     // we might have overwritten the bounds in estimateAndCheckDimension
0112     volumeBounds = cylinderBounds;
0113     // get the zMin/Max
0114     double zMin =
0115         (!idTrf ? transform.translation().z() : 0.) +
0116         (cylinderBounds != nullptr
0117              ? -cylinderBounds->get(CylinderVolumeBounds::eHalfLengthZ)
0118              : 0.);
0119     double zMax = (!idTrf ? transform.translation().z() : 0.) +
0120                   (cylinderBounds != nullptr
0121                        ? cylinderBounds->get(CylinderVolumeBounds::eHalfLengthZ)
0122                        : 0.);
0123     // get the rMin/rmAx
0124     double rMin = cylinderBounds != nullptr
0125                       ? cylinderBounds->get(CylinderVolumeBounds::eMinR)
0126                       : rMinRaw;
0127     double rMax = cylinderBounds != nullptr
0128                       ? cylinderBounds->get(CylinderVolumeBounds::eMaxR)
0129                       : rMaxRaw;
0130 
0131     ACTS_VERBOSE(
0132         "Filling the layers into an appropriate layer array - with "
0133         "binningValue = "
0134         << bValue);
0135 
0136     // create the Layer Array
0137     layerArray = (bValue == AxisDirection::AxisR)
0138                      ? m_cfg.layerArrayCreator->layerArray(gctx, layers, rMin,
0139                                                            rMax, bType, bValue)
0140                      : m_cfg.layerArrayCreator->layerArray(gctx, layers, zMin,
0141                                                            zMax, bType, bValue);
0142 
0143   }  // layers are created and done
0144   // finally create the TrackingVolume
0145   tVolume = std::make_shared<TrackingVolume>(
0146       transform, volumeBounds, volumeMaterial, std::move(layerArray), nullptr,
0147       mtvVector, volumeName);
0148   // screen output
0149   ACTS_VERBOSE("Created cylindrical volume at z-position :"
0150                << tVolume->center(gctx).z());
0151   ACTS_VERBOSE("   created bounds : " << tVolume->volumeBounds());
0152   // return the constructed TrackingVolume
0153   return tVolume;
0154 }
0155 
0156 std::shared_ptr<TrackingVolume> CylinderVolumeHelper::createTrackingVolume(
0157     const GeometryContext& gctx, const LayerVector& layers,
0158     MutableTrackingVolumeVector mtvVector,
0159     std::shared_ptr<const IVolumeMaterial> volumeMaterial, double rMin,
0160     double rMax, double zMin, double zMax, const std::string& volumeName,
0161     BinningType bType) const {
0162   // Screen output
0163   ACTS_VERBOSE("Create cylindrical TrackingVolume '" << volumeName << "'.");
0164   ACTS_VERBOSE("    -> with given dimensions of (rMin/rMax/zMin/Max) = "
0165                << rMin << " / " << rMax << " / " << zMin << " / " << zMax);
0166 
0167   // check for consistency
0168   if (zMin > zMax || rMin > rMax) {
0169     ACTS_WARNING("Inconsistent dimensions given :"
0170                  << ((zMin > zMax) ? " zMin > zMax (" : " rMin > rMax (")
0171                  << ((zMin > zMax) ? zMin : rMin) << " > "
0172                  << ((zMin > zMax) ? zMax : rMax) << " ) - return 0");
0173     return nullptr;
0174   }
0175 
0176   // create a Transform3 and VolumeBounds out of the zMin/zMax
0177   double halflengthZ = 0.5 * (zMax - zMin);
0178   double zPosition = 0.5 * (zMin + zMax);
0179   zPosition = std::abs(zPosition) < 0.1 ? 0. : zPosition;
0180 
0181   // now create the cylinder volume bounds
0182   auto cBounds =
0183       std::make_shared<CylinderVolumeBounds>(rMin, rMax, halflengthZ);
0184 
0185   // transform
0186   const Transform3 transform = Transform3(Translation3(0., 0., zPosition));
0187   // call to the creation method with Bounds & Translation3
0188   return createTrackingVolume(gctx, layers, volumeMaterial, cBounds, mtvVector,
0189                               transform, volumeName, bType);
0190 }
0191 
0192 std::shared_ptr<TrackingVolume> CylinderVolumeHelper::createGapTrackingVolume(
0193     const GeometryContext& gctx, MutableTrackingVolumeVector& mtvVector,
0194     std::shared_ptr<const IVolumeMaterial> volumeMaterial, double rMin,
0195     double rMax, double zMin, double zMax, unsigned int materialLayers,
0196     bool cylinder, const std::string& volumeName) const {
0197   // screen output
0198   ACTS_VERBOSE("Create cylindrical gap TrackingVolume '"
0199                << volumeName << "' with (rMin/rMax/zMin/Max) = ");
0200   ACTS_VERBOSE("\t" << rMin << " / " << rMax << " / " << zMin << " / " << zMax);
0201 
0202   // assign min/max
0203   double min = cylinder ? rMin : zMin;
0204   double max = cylinder ? rMax : zMax;
0205 
0206   // create the layer r/z positions
0207   std::vector<double> layerPositions;
0208   if (materialLayers > 1) {
0209     double step = (max - min) / (materialLayers - 1);
0210     for (unsigned int il = 0; il < materialLayers; ++il) {
0211       layerPositions.push_back(min + il * step);
0212     }
0213   } else {
0214     layerPositions.push_back(0.5 * (min + max));
0215   }
0216 
0217   // now call the main method
0218   return createGapTrackingVolume(gctx, mtvVector, volumeMaterial, rMin, rMax,
0219                                  zMin, zMax, layerPositions, cylinder,
0220                                  volumeName, arbitrary);
0221 }
0222 
0223 std::shared_ptr<TrackingVolume> CylinderVolumeHelper::createGapTrackingVolume(
0224     const GeometryContext& gctx, MutableTrackingVolumeVector& mtvVector,
0225     std::shared_ptr<const IVolumeMaterial> volumeMaterial, double rMin,
0226     double rMax, double zMin, double zMax,
0227     const std::vector<double>& layerPositions, bool cylinder,
0228     const std::string& volumeName, BinningType bType) const {
0229   // screen output
0230   ACTS_VERBOSE("Create cylindrical gap TrackingVolume '"
0231                << volumeName << "' with (rMin/rMax/zMin/Max) = ");
0232   ACTS_VERBOSE("\t" << rMin << " / " << rMax << " / " << zMin << " / " << zMax);
0233 
0234   // create the layers
0235   LayerVector layers;
0236   layers.reserve(layerPositions.size());
0237 
0238   std::vector<double>::const_iterator layerPropIter = layerPositions.begin();
0239   std::vector<double>::const_iterator layerPropEnd = layerPositions.end();
0240   for (; layerPropIter != layerPropEnd; ++layerPropIter) {
0241     // create cylinder layers
0242     if (cylinder) {
0243       // take envelopes into account
0244       double zMinLayer = zMin;
0245       double zMaxLayer = zMax;
0246       // create the layer
0247       layers.push_back(createCylinderLayer(
0248           0.5 * (zMinLayer + zMaxLayer), (*layerPropIter),
0249           std::abs(0.5 * (zMaxLayer - zMinLayer)), m_cfg.passiveLayerThickness,
0250           m_cfg.passiveLayerPhiBins, m_cfg.passiveLayerRzBins));
0251 
0252     } else {
0253       // take the envelopes into account
0254       double rMinLayer = rMin;
0255       double rMaxLayer = rMax;
0256       // create the layer
0257       layers.push_back(createDiscLayer(
0258           (*layerPropIter), rMinLayer, rMaxLayer, m_cfg.passiveLayerThickness,
0259           m_cfg.passiveLayerPhiBins, m_cfg.passiveLayerRzBins));
0260     }
0261   }
0262   // now call the createTrackingVolume() method
0263   return createTrackingVolume(gctx, layers, mtvVector, volumeMaterial, rMin,
0264                               rMax, zMin, zMax, volumeName, bType);
0265 }
0266 
0267 std::shared_ptr<TrackingVolume>
0268 CylinderVolumeHelper::createContainerTrackingVolume(
0269     const GeometryContext& gctx, const TrackingVolumeVector& volumes) const {
0270   // check if you have more than one volume
0271   if (volumes.size() <= std::size_t{1}) {
0272     ACTS_WARNING(
0273         "None (only one) TrackingVolume given to create container "
0274         "volume (min required: 2) - returning 0 ");
0275     return nullptr;
0276   }
0277   // screen output
0278   std::string volumeName = "{ ";
0279   ACTS_VERBOSE("[start] Creating a container volume with " << volumes.size()
0280                                                            << " sub volumes:");
0281   // volumes need to be sorted in either r or z - both increasing
0282   // set the iterator to the volumes, the first and the end
0283   auto firstVolume = volumes.begin();
0284   auto lastVolume = volumes.end();
0285 
0286   for (std::size_t ivol = 0; firstVolume != lastVolume; ++firstVolume, ++ivol) {
0287     if (*firstVolume == nullptr) {
0288       ACTS_ERROR("Volume " << ivol << " is nullptr, return nullptr");
0289       return nullptr;
0290     }
0291     ACTS_VERBOSE("   - volume (" << ivol
0292                                  << ") is : " << (*firstVolume)->volumeName());
0293     ACTS_VERBOSE("     at position : "
0294                  << (*firstVolume)->center(gctx).x() << ", "
0295                  << (*firstVolume)->center(gctx).y() << ", "
0296                  << (*firstVolume)->center(gctx).z());
0297 
0298     ACTS_VERBOSE("     with bounds : " << (*firstVolume)->volumeBounds());
0299     // put the name together
0300     volumeName += (*firstVolume)->volumeName();
0301     if (ivol + 1 < volumes.size()) {
0302       volumeName += " | ";
0303     }
0304   }
0305   // close the volume name
0306   volumeName += " }";
0307   // reset the iterator -----
0308   firstVolume = volumes.begin();
0309   --lastVolume;  // set to the last volume
0310 
0311   if (firstVolume == lastVolume) {
0312     ACTS_WARNING(
0313         "Only one TrackingVolume given to create Top level volume "
0314         "(min required: 2) - returning 0 ");
0315     return nullptr;
0316   }
0317   // get the bounds
0318   const CylinderVolumeBounds* firstVolumeBounds =
0319       dynamic_cast<const CylinderVolumeBounds*>(
0320           &((*firstVolume)->volumeBounds()));
0321   const CylinderVolumeBounds* lastVolumeBounds =
0322       dynamic_cast<const CylinderVolumeBounds*>(
0323           &((*lastVolume)->volumeBounds()));
0324   // check the dynamic cast
0325   if ((firstVolumeBounds == nullptr) || (lastVolumeBounds == nullptr)) {
0326     ACTS_WARNING(
0327         "VolumeBounds given are not of type: CylinderVolumeBounds "
0328         "(required) - returning 0 ");
0329     return nullptr;
0330   }
0331   // Check whether it is an r-binned case or a z-binned case
0332   bool rCase =
0333       std::abs(firstVolumeBounds->get(CylinderVolumeBounds::eMinR) -
0334                lastVolumeBounds->get(CylinderVolumeBounds::eMinR)) > 0.1;
0335 
0336   // Fill these ones depending on the rCase though assignment
0337   double zMin = 0.;
0338   double zMax = 0.;
0339   double rMin = 0.;
0340   double rGlueMin = 0.;
0341   double rMax = 0.;
0342   double zSep1 = 0.;
0343   double zSep2 = 0.;
0344   if (rCase) {
0345     zMin = (*firstVolume)->center(gctx).z() -
0346            firstVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ);
0347     zMax = (*firstVolume)->center(gctx).z() +
0348            firstVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ);
0349     zSep1 = zMin;
0350     zSep2 = zMax;
0351     rMin = firstVolumeBounds->get(CylinderVolumeBounds::eMinR);
0352     rGlueMin = firstVolumeBounds->get(CylinderVolumeBounds::eMaxR);
0353     rMax = lastVolumeBounds->get(CylinderVolumeBounds::eMaxR);
0354   } else {
0355     zMin = (*firstVolume)->center(gctx).z() -
0356            firstVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ);
0357     zMax = (*lastVolume)->center(gctx).z() +
0358            lastVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ);
0359     zSep1 = (*firstVolume)->center(gctx).z() +
0360             firstVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ);
0361     zSep2 = zSep1;
0362     rMin = firstVolumeBounds->get(CylinderVolumeBounds::eMinR);
0363     rMax = firstVolumeBounds->get(CylinderVolumeBounds::eMaxR);
0364   }
0365   // Estimate the z - position
0366   double zPos = 0.5 * (zMin + zMax);
0367   // Create the transform from the stuff known so far
0368   const Transform3 topVolumeTransform = Transform3(Translation3(0., 0., zPos));
0369   // Create the bounds from the information gathered so far
0370   auto topVolumeBounds = std::make_shared<CylinderVolumeBounds>(
0371       rMin, rMax, 0.5 * std::abs(zMax - zMin));
0372 
0373   // some screen output
0374   ACTS_VERBOSE("Container volume bounds are " << (*topVolumeBounds));
0375 
0376   // create the volume array with the ITrackingVolumeArrayCreator
0377   std::shared_ptr<const TrackingVolumeArray> volumeArray =
0378       (rCase) ? m_cfg.trackingVolumeArrayCreator->trackingVolumeArray(
0379                     gctx, volumes, AxisDirection::AxisR)
0380               : m_cfg.trackingVolumeArrayCreator->trackingVolumeArray(
0381                     gctx, volumes, AxisDirection::AxisZ);
0382   if (volumeArray == nullptr) {
0383     ACTS_WARNING(
0384         "Creation of TrackingVolume array did not succeed - returning 0 ");
0385     return nullptr;
0386   }
0387   // we have the bounds and the volume array, create the volume
0388   std::shared_ptr<TrackingVolume> topVolume = std::make_shared<TrackingVolume>(
0389       topVolumeTransform, topVolumeBounds, nullptr, nullptr, volumeArray,
0390       MutableTrackingVolumeVector{}, volumeName);
0391   // glueing section
0392   // --------------------------------------------------------------------------------------
0393   if (!interGlueTrackingVolume(gctx, topVolume, rCase, rMin, rGlueMin, rMax,
0394                                zSep1, zSep2)) {
0395     ACTS_WARNING(
0396         "Problem with inter-glueing of TrackingVolumes (needed) - "
0397         "returning 0 ");
0398     return nullptr;
0399   }
0400 
0401   ACTS_VERBOSE(
0402       "[ end ] return newly created container : " << topVolume->volumeName());
0403 
0404   return topVolume;
0405 }
0406 
0407 /** private helper method to estimate and check the dimensions of a tracking
0408  * volume */
0409 bool CylinderVolumeHelper::estimateAndCheckDimension(
0410     const GeometryContext& gctx, const LayerVector& layers,
0411     std::shared_ptr<CylinderVolumeBounds>& cylinderVolumeBounds,
0412     const Transform3& transform, double& rMinClean, double& rMaxClean,
0413     double& zMinClean, double& zMaxClean, AxisDirection& bValue,
0414     BinningType /*bType*/) const {
0415   // some verbose output
0416 
0417   ACTS_VERBOSE("Parsing the " << layers.size()
0418                               << " layers to gather overall dimensions");
0419   if (cylinderVolumeBounds != nullptr) {
0420     ACTS_VERBOSE(
0421         "Cylinder volume bounds are given: (rmin/rmax/dz) = "
0422         << "(" << cylinderVolumeBounds->get(CylinderVolumeBounds::eMinR) << "/"
0423         << cylinderVolumeBounds->get(CylinderVolumeBounds::eMaxR) << "/"
0424         << cylinderVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ)
0425         << ")");
0426   }
0427 
0428   // prepare for parsing the layers
0429   double layerRmin = 10e10;
0430   double layerRmax = 0.;
0431   double layerZmin = 10e10;
0432   double layerZmax = -10e10;
0433   bool radial = false;
0434 
0435   rMinClean = 10e10;
0436   rMaxClean = 0.;
0437   zMinClean = 10e10;
0438   zMaxClean = -10e10;
0439 
0440   // find out what is there
0441   for (auto& layerIter : layers) {
0442     // initialize
0443     double currentRmin = 0.;
0444     double currentRmax = 0.;
0445     double currentZmin = 0.;
0446     double currentZmax = 0.;
0447     // dynamic cast the bounds either to CylinderBounds or DiscBounds
0448     const CylinderBounds* cylBounds = dynamic_cast<const CylinderBounds*>(
0449         &(layerIter->surfaceRepresentation()).bounds());
0450     // cylinder bounds
0451     if (cylBounds != nullptr) {
0452       radial = true;
0453       // get the raw data
0454       double currentR = cylBounds->get(CylinderBounds::eR);
0455       double centerZ = (layerIter->surfaceRepresentation()).center(gctx).z();
0456       // check for min/max in the cylinder bounds case
0457       currentRmin = currentR - (0.5 * (layerIter)->layerThickness());
0458       currentRmax = currentR + (0.5 * (layerIter)->layerThickness());
0459       currentZmin = centerZ - cylBounds->get(CylinderBounds::eHalfLengthZ);
0460       currentZmax = centerZ + cylBounds->get(CylinderBounds::eHalfLengthZ);
0461     }
0462     // dynamic cast to the DiscBounds
0463     const RadialBounds* discBounds = dynamic_cast<const RadialBounds*>(
0464         &(layerIter->surfaceRepresentation()).bounds());
0465     if (discBounds != nullptr) {
0466       // check for min/max in the cylinder bounds case
0467       double centerZ = (layerIter->surfaceRepresentation()).center(gctx).z();
0468       currentRmin = discBounds->rMin();
0469       currentRmax = discBounds->rMax();
0470       currentZmin = centerZ - (0.5 * (layerIter)->layerThickness());
0471       currentZmax = centerZ + (0.5 * (layerIter)->layerThickness());
0472     }
0473     // the raw data
0474     rMinClean = std::min(rMinClean, currentRmin);
0475     rMaxClean = std::max(rMaxClean, currentRmax);
0476     zMinClean = std::min(zMinClean, currentZmin);
0477     zMaxClean = std::max(zMaxClean, currentZmax);
0478     // assign if they overrule the minima/maxima (with layers thicknesses)
0479     layerRmin = std::min(layerRmin, currentRmin);
0480     layerRmax = std::max(layerRmax, currentRmax);
0481     layerZmin = std::min(layerZmin, currentZmin);
0482     layerZmax = std::max(layerZmax, currentZmax);
0483   }
0484 
0485   // set the binning value
0486   bValue = radial ? AxisDirection::AxisR : AxisDirection::AxisZ;
0487 
0488   ACTS_VERBOSE(
0489       "Estimate/check CylinderVolumeBounds from/w.r.t. enclosed "
0490       "layers + envelope covers");
0491   // the z from the layers w and w/o envelopes
0492   double zEstFromLayerEnv = 0.5 * (layerZmax + layerZmin);
0493   double halflengthFromLayer = 0.5 * std::abs(layerZmax - layerZmin);
0494 
0495   // using `sqrt(0.001) = 0.031622777` because previously it compared to
0496   // `zEstFromLayerEnv * zEstFromLayerEnv < 0.001` which was changed due to
0497   // underflow/overflow concerns
0498   bool concentric = std::abs(zEstFromLayerEnv) < 0.031622777;
0499 
0500   bool idTrf = transform.isApprox(Transform3::Identity());
0501 
0502   Transform3 vtransform = Transform3::Identity();
0503   // no CylinderBounds and Translation given - make it
0504   if ((cylinderVolumeBounds == nullptr) && idTrf) {
0505     // create the CylinderBounds from parsed layer inputs
0506     cylinderVolumeBounds = std::make_shared<CylinderVolumeBounds>(
0507         layerRmin, layerRmax, halflengthFromLayer);
0508     // and the transform
0509     vtransform = concentric ? Transform3(Translation3(0., 0., zEstFromLayerEnv))
0510                             : Transform3::Identity();
0511   } else if ((cylinderVolumeBounds != nullptr) && idTrf && !concentric) {
0512     vtransform = Transform3(Translation3(0., 0., zEstFromLayerEnv));
0513   } else if (!idTrf && (cylinderVolumeBounds == nullptr)) {
0514     // create the CylinderBounds from parsed layer inputs
0515     cylinderVolumeBounds = std::make_shared<CylinderVolumeBounds>(
0516         layerRmin, layerRmax, halflengthFromLayer);
0517   }
0518 
0519   ACTS_VERBOSE("    -> dimensions from layers   (rMin/rMax/zMin/zMax) = "
0520                << layerRmin << " / " << layerRmax << " / " << layerZmin << " / "
0521                << layerZmax);
0522 
0523   double zFromTransform = !idTrf ? transform.translation().z() : 0.;
0524   ACTS_VERBOSE(
0525       "    -> while created bounds are (rMin/rMax/zMin/zMax) = "
0526       << cylinderVolumeBounds->get(CylinderVolumeBounds::eMinR) << " / "
0527       << cylinderVolumeBounds->get(CylinderVolumeBounds::eMaxR) << " / "
0528       << zFromTransform -
0529              cylinderVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ)
0530       << " / "
0531       << zFromTransform +
0532              cylinderVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ));
0533 
0534   // both is NOW given --- check it -----------------------------
0535   if (cylinderVolumeBounds != nullptr) {
0536     // only check
0537     if (zFromTransform -
0538                 cylinderVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ) <=
0539             layerZmin &&
0540         zFromTransform +
0541                 cylinderVolumeBounds->get(CylinderVolumeBounds::eHalfLengthZ) >=
0542             layerZmax &&
0543         cylinderVolumeBounds->get(CylinderVolumeBounds::eMinR) <= layerRmin &&
0544         cylinderVolumeBounds->get(CylinderVolumeBounds::eMaxR) >= layerRmax) {
0545       return true;
0546     } else {
0547       ACTS_WARNING(
0548           "Provided layers are not contained by volume ! Bailing out. ");
0549       ACTS_WARNING("- zFromTransform: " << zFromTransform);
0550       ACTS_WARNING("- volumeZmin:"
0551                    << zFromTransform - cylinderVolumeBounds->get(
0552                                            CylinderVolumeBounds::eHalfLengthZ)
0553                    << ", layerZmin: " << layerZmin);
0554       ACTS_WARNING("- volumeZmax: "
0555                    << zFromTransform + cylinderVolumeBounds->get(
0556                                            CylinderVolumeBounds::eHalfLengthZ)
0557                    << ", layerZmax: " << layerZmax);
0558       ACTS_WARNING("- volumeRmin: "
0559                    << cylinderVolumeBounds->get(CylinderVolumeBounds::eMinR)
0560                    << ", layerRmin: " << layerRmin);
0561       ACTS_WARNING("- volumeRmax: "
0562                    << cylinderVolumeBounds->get(CylinderVolumeBounds::eMaxR)
0563                    << ", layerRmax: " << layerRmax);
0564       return false;
0565     }
0566   }
0567 
0568   ACTS_VERBOSE("Created/Checked " << *cylinderVolumeBounds);
0569   return true;
0570 }
0571 
0572 bool CylinderVolumeHelper::interGlueTrackingVolume(
0573     const GeometryContext& gctx, const std::shared_ptr<TrackingVolume>& tVolume,
0574     bool rBinned, double rMin, double rGlueMin, double rMax, double zMin,
0575     double zMax) const {
0576   ACTS_VERBOSE("Glue contained TrackingVolumes of container '"
0577                << tVolume->volumeName() << "'.");
0578 
0579   // only go on if you have confinedVolumes
0580   if (tVolume->confinedVolumes()) {
0581     // get the glueVolumes descriptor of the top volume to register the outside
0582     // volumes
0583     GlueVolumesDescriptor& glueDescr = tVolume->glueVolumesDescriptor();
0584 
0585     // now retrieve the volumes
0586     auto& volumes = tVolume->confinedVolumes()->arrayObjects();
0587 
0588     // list the volume names:
0589     //  and make the screen output readable
0590     std::size_t ivol = 0;
0591     for (auto& vol : volumes) {
0592       ACTS_VERBOSE("[" << ivol++ << "] - volume : " << vol->volumeName());
0593     }
0594 
0595     // the needed iterators
0596     auto tVolIter = volumes.begin();
0597     auto tVolFirst = volumes.begin();
0598     auto tVolLast = volumes.end();
0599     --tVolLast;
0600     auto tVolEnd = volumes.end();
0601 
0602     // the glue volumes for the description
0603     TrackingVolumeVector glueVolumesInnerTube;
0604     TrackingVolumeVector glueVolumesOuterTube;
0605     TrackingVolumeVector glueVolumesNegativeFace;
0606     TrackingVolumeVector glueVolumesPositiveFace;
0607     // reset ivol counter
0608     ivol = 0;
0609     // volumes of increasing r
0610     if (rBinned) {
0611       // loop over the volumes -------------------------------
0612       for (; tVolIter != tVolEnd;) {
0613         // screen output
0614         ACTS_VERBOSE("r-binning: Processing volume [" << ivol++ << "]");
0615         // for the first one
0616         std::shared_ptr<TrackingVolume> tVol =
0617             std::const_pointer_cast<TrackingVolume>(*tVolIter);
0618         if (tVolIter == tVolFirst) {
0619           addFaceVolumes(tVol, tubeInnerCover, glueVolumesInnerTube);
0620         }
0621         // add this or the subvolumes to the negativeFace and positiveFace
0622         addFaceVolumes(tVol, negativeFaceXY, glueVolumesNegativeFace);
0623         addFaceVolumes(tVol, positiveFaceXY, glueVolumesPositiveFace);
0624         if (tVolIter == tVolLast) {
0625           addFaceVolumes(tVol, tubeOuterCover, glueVolumesOuterTube);
0626           ++tVolIter;
0627         } else {
0628           std::shared_ptr<TrackingVolume> tVol1 =
0629               std::const_pointer_cast<TrackingVolume>(*tVolIter);
0630           std::shared_ptr<TrackingVolume> tVol2 =
0631               std::const_pointer_cast<TrackingVolume>(*(++tVolIter));
0632 
0633           // re-evalueate rGlueMin
0634           double rGlueR =
0635               0.5 * (tVol1->volumeBounds()
0636                          .values()[CylinderVolumeBounds::BoundValues::eMaxR] +
0637                      tVol2->volumeBounds()
0638                          .values()[CylinderVolumeBounds::BoundValues::eMinR]);
0639 
0640           glueTrackingVolumes(gctx, tVol1, tubeOuterCover, tVol2,
0641                               tubeInnerCover, rMin, rGlueR, rMax, zMin, zMax);
0642         }
0643       }
0644     } else {
0645       // Volumes in increasing z
0646       // Loop over the volumes
0647       for (; tVolIter != tVolEnd;) {
0648         // screen output
0649         ACTS_VERBOSE("z-binning: Processing volume '"
0650                      << (*tVolIter)->volumeName() << "'.");
0651         std::shared_ptr<TrackingVolume> tVol =
0652             std::const_pointer_cast<TrackingVolume>(*tVolIter);
0653         if (tVolIter == tVolFirst) {
0654           addFaceVolumes(tVol, negativeFaceXY, glueVolumesNegativeFace);
0655         }
0656         addFaceVolumes(tVol, tubeInnerCover, glueVolumesInnerTube);
0657         addFaceVolumes(tVol, tubeOuterCover, glueVolumesOuterTube);
0658         if (tVolIter == tVolLast) {
0659           addFaceVolumes(tVol, positiveFaceXY, glueVolumesPositiveFace);
0660           ++tVolIter;
0661         } else {
0662           std::shared_ptr<TrackingVolume> tVol1 =
0663               std::const_pointer_cast<TrackingVolume>(*tVolIter);
0664           std::shared_ptr<TrackingVolume> tVol2 =
0665               std::const_pointer_cast<TrackingVolume>(*(++tVolIter));
0666           glueTrackingVolumes(gctx, tVol1, positiveFaceXY, tVol2,
0667                               negativeFaceXY, rMin, rGlueMin, rMax, zMin, zMax);
0668         }
0669       }
0670     }
0671     // create BinnedArraysand register then to the glue volume descriptor for
0672     // upstream glueing
0673     if (!glueVolumesNegativeFace.empty()) {
0674       // create the outside volume array
0675       std::shared_ptr<const TrackingVolumeArray> glueVolumesNegativeFaceArray =
0676           m_cfg.trackingVolumeArrayCreator->trackingVolumeArray(
0677               gctx, glueVolumesNegativeFace, AxisDirection::AxisR);
0678       // register the glue voluems
0679       glueDescr.registerGlueVolumes(negativeFaceXY,
0680                                     glueVolumesNegativeFaceArray);
0681     }
0682     if (!glueVolumesPositiveFace.empty()) {
0683       // create the outside volume array
0684       std::shared_ptr<const TrackingVolumeArray> glueVolumesPositiveFaceArray =
0685           m_cfg.trackingVolumeArrayCreator->trackingVolumeArray(
0686               gctx, glueVolumesPositiveFace, AxisDirection::AxisR);
0687       // register the glue voluems
0688       glueDescr.registerGlueVolumes(positiveFaceXY,
0689                                     glueVolumesPositiveFaceArray);
0690     }
0691     if (!glueVolumesInnerTube.empty()) {
0692       // create the outside volume array
0693       std::shared_ptr<const TrackingVolumeArray> glueVolumesInnerTubeArray =
0694           m_cfg.trackingVolumeArrayCreator->trackingVolumeArray(
0695               gctx, glueVolumesInnerTube, AxisDirection::AxisZ);
0696       // register the glue voluems
0697       glueDescr.registerGlueVolumes(tubeInnerCover, glueVolumesInnerTubeArray);
0698     }
0699     if (!glueVolumesOuterTube.empty()) {
0700       // create the outside volume array
0701       std::shared_ptr<const TrackingVolumeArray> glueVolumesOuterTubeArray =
0702           m_cfg.trackingVolumeArrayCreator->trackingVolumeArray(
0703               gctx, glueVolumesOuterTube, AxisDirection::AxisZ);
0704       // register the glue voluems
0705       glueDescr.registerGlueVolumes(tubeOuterCover, glueVolumesOuterTubeArray);
0706     }
0707 
0708     ACTS_VERBOSE("[GV] Register " << glueVolumesNegativeFace.size()
0709                                   << " volumes at face negativeFaceXY:");
0710     for (tVolIter = glueVolumesNegativeFace.begin();
0711          tVolIter != glueVolumesNegativeFace.end(); ++tVolIter) {
0712       ACTS_VERBOSE("   -> volume '" << (*tVolIter)->volumeName() << "'");
0713     }
0714     ACTS_VERBOSE("[GV] Register " << glueVolumesPositiveFace.size()
0715                                   << " volumes at face positiveFaceXY: ");
0716     for (tVolIter = glueVolumesPositiveFace.begin();
0717          tVolIter != glueVolumesPositiveFace.end(); ++tVolIter) {
0718       ACTS_VERBOSE("   -> volume '" << (*tVolIter)->volumeName() << "'");
0719     }
0720     ACTS_VERBOSE("[GV] Register " << glueVolumesInnerTube.size()
0721                                   << " volumes at face tubeInnerCover: ");
0722     for (tVolIter = glueVolumesInnerTube.begin();
0723          tVolIter != glueVolumesInnerTube.end(); ++tVolIter) {
0724       ACTS_VERBOSE("   -> volume '" << (*tVolIter)->volumeName() << "'");
0725     }
0726     ACTS_VERBOSE("[GV] Register " << glueVolumesOuterTube.size()
0727                                   << " volumes at face tubeOuterCover:");
0728     for (tVolIter = glueVolumesOuterTube.begin();
0729          tVolIter != glueVolumesOuterTube.end(); ++tVolIter) {
0730       ACTS_VERBOSE("   -> volume '" << (*tVolIter)->volumeName() << "'");
0731     }
0732   }
0733   // return success
0734   return true;
0735 }
0736 
0737 /** private helper method to fill the glue volumes (or the volume itself in) */
0738 void CylinderVolumeHelper::glueTrackingVolumes(
0739     const GeometryContext& gctx, const std::shared_ptr<TrackingVolume>& tvolOne,
0740     BoundarySurfaceFace faceOne, const std::shared_ptr<TrackingVolume>& tvolTwo,
0741     BoundarySurfaceFace faceTwo, double rMin, double rGlueMin, double rMax,
0742     double zMin, double zMax) const {
0743   // get the two gluevolume descriptors
0744   const GlueVolumesDescriptor& gvDescriptorOne =
0745       tvolOne->glueVolumesDescriptor();
0746   const GlueVolumesDescriptor& gvDescriptorTwo =
0747       tvolTwo->glueVolumesDescriptor();
0748 
0749   std::size_t volOneGlueVols =
0750       gvDescriptorOne.glueVolumes(faceOne)
0751           ? gvDescriptorOne.glueVolumes(faceOne)->arrayObjects().size()
0752           : 0;
0753   ACTS_VERBOSE("GlueVolumeDescriptor of volume '"
0754                << tvolOne->volumeName() << "' has " << volOneGlueVols << " @ "
0755                << faceOne);
0756   std::size_t volTwoGlueVols =
0757       gvDescriptorTwo.glueVolumes(faceTwo)
0758           ? gvDescriptorTwo.glueVolumes(faceTwo)->arrayObjects().size()
0759           : 0;
0760   ACTS_VERBOSE("GlueVolumeDescriptor of volume '"
0761                << tvolTwo->volumeName() << "' has " << volTwoGlueVols << " @ "
0762                << faceTwo);
0763 
0764   // they could still be a container though - should not happen usually
0765   TrackingVolumePtr glueVolOne =
0766       volOneGlueVols != 0u
0767           ? gvDescriptorOne.glueVolumes(faceOne)->arrayObjects()[0]
0768           : tvolOne;
0769   TrackingVolumePtr glueVolTwo =
0770       volTwoGlueVols != 0u
0771           ? gvDescriptorTwo.glueVolumes(faceTwo)->arrayObjects()[0]
0772           : tvolTwo;
0773 
0774   // We'll need to mutate those volumes in order to glue them together
0775   auto mutableGlueVolOne = std::const_pointer_cast<TrackingVolume>(glueVolOne);
0776   auto mutableGlueVolTwo = std::const_pointer_cast<TrackingVolume>(glueVolTwo);
0777 
0778   // check the cases
0779   if (volOneGlueVols <= 1 && volTwoGlueVols <= 1) {
0780     // (i) one -> one
0781     ACTS_VERBOSE("      glue : one[ " << glueVolOne->volumeName() << " @ "
0782                                       << faceOne << " ]-to-one[ "
0783                                       << glueVolTwo->volumeName() << " @ "
0784                                       << faceTwo << " ]");
0785     // one to one is easy
0786     mutableGlueVolOne->glueTrackingVolume(gctx, faceOne,
0787                                           mutableGlueVolTwo.get(), faceTwo);
0788 
0789   } else if (volOneGlueVols <= 1) {
0790     // (ii) one -> many
0791     ACTS_VERBOSE("      glue : one[ "
0792                  << glueVolOne->volumeName() << " @ " << faceOne
0793                  << " ]-to-many[ " << tvolTwo->volumeName() << " @ " << faceTwo
0794                  << " ]");
0795     auto mutableFaceTwoVolumes = std::const_pointer_cast<TrackingVolumeArray>(
0796         gvDescriptorTwo.glueVolumes(faceTwo));
0797     mutableGlueVolOne->glueTrackingVolumes(gctx, faceOne, mutableFaceTwoVolumes,
0798                                            faceTwo);
0799   } else if (volTwoGlueVols <= 1) {
0800     // (iii) many -> one
0801     ACTS_VERBOSE("      glue : many[ "
0802                  << tvolOne->volumeName() << " @ " << faceOne << " ]-to-one[ "
0803                  << glueVolTwo->volumeName() << " @ " << faceTwo << " ]");
0804     auto mutableFaceOneVolumes = std::const_pointer_cast<TrackingVolumeArray>(
0805         gvDescriptorOne.glueVolumes(faceOne));
0806     mutableGlueVolTwo->glueTrackingVolumes(gctx, faceTwo, mutableFaceOneVolumes,
0807                                            faceOne);
0808   } else {
0809     // (iv) glue array to array
0810     ACTS_VERBOSE("      glue : many[ "
0811                  << tvolOne->volumeName() << " @ " << faceOne << " ]-to-many[ "
0812                  << tvolTwo->volumeName() << " @ " << faceTwo << " ]");
0813 
0814     // Create a new BoundarySurface as shared pointer
0815     std::shared_ptr<const BoundarySurfaceT<TrackingVolume>> boundarySurface =
0816         nullptr;
0817 
0818     // the transform of the new boundary surface
0819     Transform3 transform = Transform3::Identity();
0820     if (std::abs(zMin + zMax) > 0.1) {
0821       // it's not a concentric cylinder, so create a transform
0822       transform =
0823           Transform3(Translation3(Vector3(0., 0., 0.5 * (zMin + zMax))));
0824     }
0825     // 2 cases: r-Binning and zBinning
0826     if (faceOne == cylinderCover || faceOne == tubeOuterCover) {
0827       // (1) create the Boundary CylinderSurface
0828       auto cBounds =
0829           std::make_shared<CylinderBounds>(rGlueMin, 0.5 * (zMax - zMin));
0830       auto cSurface = Surface::makeShared<CylinderSurface>(transform, cBounds);
0831       ACTS_VERBOSE(
0832           "             creating a new cylindrical boundary surface "
0833           "with bounds = "
0834           << cSurface->bounds());
0835       ACTS_VERBOSE("             at " << cSurface->center(gctx).transpose());
0836       boundarySurface =
0837           std::make_shared<const BoundarySurfaceT<TrackingVolume>>(
0838               std::move(cSurface), gvDescriptorOne.glueVolumes(faceOne),
0839               gvDescriptorTwo.glueVolumes(faceTwo));
0840     } else {
0841       // Calculate correct position for disc surface
0842 
0843       // we assume it's cylinder bounds
0844       auto cylVolBounds =
0845           dynamic_cast<const CylinderVolumeBounds*>(&tvolOne->volumeBounds());
0846       double zPos = tvolOne->center(gctx).z();
0847       double zHL = cylVolBounds->get(CylinderVolumeBounds::eHalfLengthZ);
0848       transform = Transform3(Translation3(0, 0, zPos + zHL));
0849       // this puts the surface on the positive z side of the cyl vol bounds
0850       // iteration is from neg to pos, so it should always be in between.
0851 
0852       // (2) create the BoundaryDiscSurface, in that case the zMin/zMax provided
0853       // are both the position of the disk in question
0854       auto dSurface = Surface::makeShared<DiscSurface>(transform, rMin, rMax);
0855       ACTS_VERBOSE(
0856           "             creating a new disc-like boundary surface "
0857           "with bounds = "
0858           << dSurface->bounds());
0859       ACTS_VERBOSE("             at " << dSurface->center(gctx).transpose());
0860       boundarySurface =
0861           std::make_shared<const BoundarySurfaceT<TrackingVolume>>(
0862               std::move(dSurface), gvDescriptorOne.glueVolumes(faceOne),
0863               gvDescriptorTwo.glueVolumes(faceTwo));
0864     }
0865 
0866     // Collect the material - might be ambiguous, first one wins
0867     std::shared_ptr<const ISurfaceMaterial> boundaryMaterial = nullptr;
0868 
0869     ACTS_VERBOSE("New Boundary surface setting for containers");
0870     ACTS_VERBOSE(" - at first volume: " << tvolOne->volumeName());
0871     // Update the volume with the boundary surface accordingly
0872     // it's safe to access directly, they can not be nullptr
0873     for (auto& oneVolume :
0874          gvDescriptorOne.glueVolumes(faceOne)->arrayObjects()) {
0875       auto mutableOneVolume =
0876           std::const_pointer_cast<TrackingVolume>(oneVolume);
0877       // Look out for surface material
0878       if (boundaryMaterial == nullptr) {
0879         auto oneBSurface = mutableOneVolume->boundarySurfaces()[faceOne];
0880         boundaryMaterial =
0881             oneBSurface->surfaceRepresentation().surfaceMaterialSharedPtr();
0882       }
0883       mutableOneVolume->updateBoundarySurface(faceOne, boundarySurface);
0884       ACTS_VERBOSE(" -> setting boundary surface to volume: "
0885                    << mutableOneVolume->volumeName());
0886     }
0887     ACTS_VERBOSE(" - at second volume: " << tvolTwo->volumeName());
0888     for (auto& twoVolume :
0889          gvDescriptorTwo.glueVolumes(faceTwo)->arrayObjects()) {
0890       auto mutableTwoVolume =
0891           std::const_pointer_cast<TrackingVolume>(twoVolume);
0892       // Look out for surface material
0893       if (boundaryMaterial == nullptr) {
0894         auto twoBSurface = mutableTwoVolume->boundarySurfaces()[faceTwo];
0895         boundaryMaterial =
0896             twoBSurface->surfaceRepresentation().surfaceMaterialSharedPtr();
0897       }
0898       mutableTwoVolume->updateBoundarySurface(faceTwo, boundarySurface);
0899       ACTS_VERBOSE(" -> setting boundary surface to volume: "
0900                    << mutableTwoVolume->volumeName());
0901     }
0902 
0903     // If we have boundary material, let's assign it
0904     if (boundaryMaterial != nullptr) {
0905       // Adapt the boundary material
0906       ACTS_VERBOSE("- the new boundary surface has boundary material: ");
0907       ACTS_VERBOSE("    " << *boundaryMaterial);
0908       RegularSurface* newSurface = const_cast<RegularSurface*>(
0909           &(boundarySurface->surfaceRepresentation()));
0910       newSurface->assignSurfaceMaterial(boundaryMaterial);
0911     }
0912 
0913   }  // end of case (iv)
0914 }
0915 
0916 /** Private method - helper method not to duplicate code */
0917 void CylinderVolumeHelper::addFaceVolumes(
0918     const std::shared_ptr<TrackingVolume>& tvol, BoundarySurfaceFace glueFace,
0919     TrackingVolumeVector& vols) const {
0920   ACTS_VERBOSE("Adding face volumes of face " << glueFace << " for the volume '"
0921                                               << tvol->volumeName() << "'.");
0922   // retrieve the gluevolume descriptor
0923   const GlueVolumesDescriptor& gvDescriptor = tvol->glueVolumesDescriptor();
0924   // if volumes are registered: take them
0925   if (gvDescriptor.glueVolumes(glueFace)) {
0926     // get the navigation level subvolumes
0927     auto volIter = gvDescriptor.glueVolumes(glueFace)->arrayObjects().begin();
0928     auto volEnd = gvDescriptor.glueVolumes(glueFace)->arrayObjects().end();
0929     for (; volIter != volEnd; ++volIter) {
0930       ACTS_VERBOSE("   -> adding : " << (*volIter)->volumeName());
0931       vols.push_back(*volIter);
0932     }
0933     // screen output
0934     ACTS_VERBOSE(vols.size()
0935                  << " navigation volumes registered as glue volumes.");
0936   } else {
0937     // the volume itself is on navigation level
0938     ACTS_VERBOSE("     -> adding only volume itself (at navigation level).");
0939     vols.push_back(tvol);
0940   }
0941 }
0942 
0943 std::shared_ptr<const Layer> CylinderVolumeHelper::createCylinderLayer(
0944     double z, double r, double halflengthZ, double thickness, int binsPhi,
0945     int binsZ) const {
0946   ACTS_VERBOSE("Creating a CylinderLayer at position " << z << " and radius "
0947                                                        << r);
0948   // positioning
0949   const Transform3 transform(Translation3(0., 0., z));
0950 
0951   // z-binning
0952   BinUtility layerBinUtility(binsZ, z - halflengthZ, z + halflengthZ, open,
0953                              AxisDirection::AxisZ);
0954   if (binsPhi == 1) {
0955     // the BinUtility for the material
0956     // ---------------------> create material for the layer surface
0957     ACTS_VERBOSE(" -> Preparing the binned material with " << binsZ
0958                                                            << " bins in Z. ");
0959 
0960   } else {  // break the phi symmetry
0961     // update the BinUtility: local position on Cylinder is rPhi, z
0962     BinUtility layerBinUtilityPhiZ(binsPhi, -r * std::numbers::pi,
0963                                    r * std::numbers::pi, closed,
0964                                    AxisDirection::AxisPhi);
0965     layerBinUtilityPhiZ += layerBinUtility;
0966     // ---------------------> create material for the layer surface
0967     ACTS_VERBOSE(" -> Preparing the binned material with "
0968                  << binsPhi << " / " << binsZ << " bins in phi / Z. ");
0969   }
0970   // @todo create the SurfaceMaterial
0971   // bounds for cylinderical surface
0972   CylinderBounds* cylinderBounds = new CylinderBounds(r, halflengthZ);
0973   // create the cylinder
0974   return CylinderLayer::create(
0975       transform, std::shared_ptr<const CylinderBounds>(cylinderBounds), nullptr,
0976       thickness);
0977 }
0978 
0979 std::shared_ptr<const Layer> CylinderVolumeHelper::createDiscLayer(
0980     double z, double rMin, double rMax, double thickness, int binsPhi,
0981     int binsR) const {
0982   ACTS_VERBOSE("Creating a DiscLayer at position " << z << " and rMin/rMax "
0983                                                    << rMin << " / " << rMax);
0984 
0985   // positioning
0986   const Transform3 transform(Translation3(0., 0., z));
0987 
0988   // R is the primary binning for the material
0989   BinUtility materialBinUtility(binsR, rMin, rMax, open, AxisDirection::AxisR);
0990   if (binsPhi == 1) {
0991     ACTS_VERBOSE(" -> Preparing the binned material with " << binsR
0992                                                            << " bins in R. ");
0993   } else {
0994     // also binning in phi chosen
0995     materialBinUtility +=
0996         BinUtility(binsPhi, -std::numbers::pi_v<float>,
0997                    std::numbers::pi_v<float>, closed, AxisDirection::AxisPhi);
0998     ACTS_VERBOSE(" -> Preparing the binned material with "
0999                  << binsPhi << " / " << binsR << " bins in phi / R. ");
1000   }
1001 
1002   // @todo create the SurfaceMaterial
1003   // bounds for disk-like surface
1004   RadialBounds* discBounds = new RadialBounds(rMin, rMax);
1005   // create the disc
1006   return DiscLayer::create(transform,
1007                            std::shared_ptr<const DiscBounds>(discBounds),
1008                            nullptr, thickness);
1009 }
1010 
1011 }  // namespace Acts