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