Back to home page

sPhenix code displayed by LXR

 
 

    


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

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