Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-31 08:30:14

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/CuboidVolumeBuilder.hpp"
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Geometry/BoundarySurfaceFace.hpp"
0013 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0014 #include "Acts/Geometry/Extent.hpp"
0015 #include "Acts/Geometry/LayerArrayCreator.hpp"
0016 #include "Acts/Geometry/LayerCreator.hpp"
0017 #include "Acts/Geometry/ProtoLayer.hpp"
0018 #include "Acts/Geometry/SurfaceArrayCreator.hpp"
0019 #include "Acts/Geometry/TrackingGeometry.hpp"
0020 #include "Acts/Geometry/TrackingVolume.hpp"
0021 #include "Acts/Geometry/Volume.hpp"
0022 #include "Acts/Surfaces/PlaneSurface.hpp"
0023 #include "Acts/Surfaces/RectangleBounds.hpp"
0024 #include "Acts/Surfaces/Surface.hpp"
0025 #include "Acts/Utilities/BinUtility.hpp"
0026 #include "Acts/Utilities/BinnedArrayXD.hpp"
0027 #include "Acts/Utilities/BinningData.hpp"
0028 #include "Acts/Utilities/Logger.hpp"
0029 #include "Acts/Utilities/TransformHelpers.hpp"
0030 
0031 #include <algorithm>
0032 #include <limits>
0033 #include <stdexcept>
0034 
0035 namespace Acts {
0036 
0037 std::shared_ptr<const Surface> CuboidVolumeBuilder::buildSurface(
0038     const GeometryContext& /*gctx*/,
0039     const CuboidVolumeBuilder::SurfaceConfig& cfg) const {
0040   std::shared_ptr<PlaneSurface> surface;
0041 
0042   // Build transformation
0043   Transform3 trafo(Transform3::Identity() * cfg.rotation);
0044   trafo.translation() = cfg.position;
0045 
0046   // Create and store surface
0047   if (cfg.detElementConstructor) {
0048     surface = Surface::makeShared<PlaneSurface>(
0049         cfg.rBounds,
0050         *(cfg.detElementConstructor(trafo, cfg.rBounds, cfg.thickness)));
0051     surface->assignThickness(cfg.thickness);
0052   } else {
0053     surface = Surface::makeShared<PlaneSurface>(trafo, cfg.rBounds);
0054   }
0055   surface->assignSurfaceMaterial(cfg.surMat);
0056   return surface;
0057 }
0058 
0059 std::shared_ptr<const Layer> CuboidVolumeBuilder::buildLayer(
0060     const GeometryContext& gctx, CuboidVolumeBuilder::LayerConfig& cfg) const {
0061   if (cfg.surfaces.empty() && cfg.surfaceCfg.empty()) {
0062     throw std::runtime_error{
0063         "Neither surfaces nor config to build surfaces was provided. Cannot "
0064         "proceed"};
0065   }
0066 
0067   // Build the surface
0068   if (cfg.surfaces.empty()) {
0069     for (const auto& sCfg : cfg.surfaceCfg) {
0070       cfg.surfaces.emplace_back(buildSurface(gctx, sCfg));
0071     }
0072   }
0073   // Build transformation centered at the surface position
0074   Vector3 centroid{0., 0., 0.};
0075 
0076   for (const auto& surface : cfg.surfaces) {
0077     centroid += surface->localToGlobalTransform(gctx).translation();
0078   }
0079 
0080   centroid /= cfg.surfaces.size();
0081 
0082   // In the case the layer configuration doesn't define the rotation of the
0083   // layer use the orientation of the first surface to define the layer rotation
0084   // in space.
0085   const RotationMatrix3 rotation =
0086       cfg.rotation.has_value()
0087           ? *cfg.rotation
0088           : RotationMatrix3(
0089                 cfg.surfaces.front()->localToGlobalTransform(gctx).rotation());
0090   const Transform3 trafo = makeTransform3(rotation, centroid);
0091 
0092   LayerCreator::Config lCfg;
0093   lCfg.surfaceArrayCreator = std::make_shared<const SurfaceArrayCreator>();
0094   LayerCreator layerCreator(lCfg);
0095   ProtoLayer pl{gctx, cfg.surfaces};
0096   pl.envelope[AxisDirection::AxisX] = cfg.envelopeX;
0097   pl.envelope[AxisDirection::AxisY] = cfg.envelopeY;
0098   pl.envelope[AxisDirection::AxisZ] = cfg.envelopeZ;
0099   return layerCreator.planeLayer(gctx, cfg.surfaces, cfg.binsY, cfg.binsZ,
0100                                  cfg.binningDimension, pl, trafo);
0101 }
0102 
0103 std::pair<double, double> CuboidVolumeBuilder::binningRange(
0104     const GeometryContext& gctx,
0105     const CuboidVolumeBuilder::VolumeConfig& cfg) const {
0106   // Construct return value
0107   std::pair<double, double> minMax = std::make_pair(
0108       std::numeric_limits<double>::max(), -std::numeric_limits<double>::max());
0109 
0110   // Compute the min volume boundaries for computing the binning start
0111   // See
0112   // https://acts.readthedocs.io/en/latest/core/geometry/legacy/building.html
0113   // !! IMPORTANT !! The volume is assumed to be already rotated into the
0114   // telescope geometry
0115   Vector3 minVolumeBoundaries = cfg.position - 0.5 * cfg.length;
0116   Vector3 maxVolumeBoundaries = cfg.position + 0.5 * cfg.length;
0117 
0118   // Compute first the min-max from the layers
0119 
0120   for (const auto& layercfg : cfg.layerCfg) {
0121     // recreating the protolayer for each layer => slow, but only few sensors
0122     ProtoLayer pl{gctx, layercfg.surfaces};
0123     pl.envelope[cfg.binningDimension] = layercfg.envelopeX;
0124 
0125     double surfacePosMin = pl.min(cfg.binningDimension);
0126     double surfacePosMax = pl.max(cfg.binningDimension);
0127 
0128     // Test if new extreme is found and set it
0129     if (surfacePosMin < minMax.first) {
0130       minMax.first = surfacePosMin;
0131     }
0132     if (surfacePosMax > minMax.second) {
0133       minMax.second = surfacePosMax;
0134     }
0135   }
0136 
0137   // Use the volume boundaries as limits for the binning
0138   minMax.first = std::min(
0139       minMax.first, minVolumeBoundaries(toUnderlying(cfg.binningDimension)));
0140   minMax.second = std::max(
0141       minMax.second, maxVolumeBoundaries(toUnderlying(cfg.binningDimension)));
0142 
0143   return minMax;
0144 }
0145 
0146 std::shared_ptr<TrackingVolume> CuboidVolumeBuilder::buildVolume(
0147     const GeometryContext& gctx, CuboidVolumeBuilder::VolumeConfig& cfg) const {
0148   // Build transformation
0149   Transform3 trafo(Transform3::Identity());
0150   trafo.translation() = cfg.position;
0151   // Set bounds
0152   auto bounds = std::make_shared<CuboidVolumeBounds>(
0153       cfg.length.x() * 0.5, cfg.length.y() * 0.5, cfg.length.z() * 0.5);
0154 
0155   // Gather the layers
0156   LayerVector layVec;
0157   if (cfg.layers.empty()) {
0158     cfg.layers.reserve(cfg.layerCfg.size());
0159 
0160     for (auto& layerCfg : cfg.layerCfg) {
0161       cfg.layers.emplace_back(buildLayer(gctx, layerCfg));
0162       layVec.emplace_back(cfg.layers.back());
0163     }
0164   } else {
0165     for (auto& lay : cfg.layers) {
0166       layVec.emplace_back(lay);
0167     }
0168   }
0169 
0170   // Build layer array
0171   std::pair<double, double> minMax = binningRange(gctx, cfg);
0172   LayerArrayCreator::Config lacCnf;
0173   LayerArrayCreator layArrCreator(
0174       lacCnf, getDefaultLogger("LayerArrayCreator", Logging::INFO));
0175   std::unique_ptr<const LayerArray> layArr(
0176       layArrCreator.layerArray(gctx, layVec, minMax.first, minMax.second,
0177                                BinningType::arbitrary, cfg.binningDimension));
0178 
0179   // Build confined volumes
0180   if (cfg.trackingVolumes.empty()) {
0181     for (VolumeConfig vc : cfg.volumeCfg) {
0182       cfg.trackingVolumes.emplace_back(buildVolume(gctx, vc));
0183     }
0184   }
0185 
0186   std::shared_ptr<TrackingVolume> trackVolume;
0187   if (layVec.empty()) {
0188     // Build TrackingVolume
0189     trackVolume = std::make_shared<TrackingVolume>(
0190         trafo, bounds, cfg.volumeMaterial, nullptr, nullptr,
0191         cfg.trackingVolumes, cfg.name);
0192   } else {
0193     // Build TrackingVolume
0194     trackVolume = std::make_shared<TrackingVolume>(
0195         trafo, bounds, cfg.volumeMaterial, std::move(layArr), nullptr,
0196         cfg.trackingVolumes, cfg.name);
0197   }
0198   return trackVolume;
0199 }
0200 
0201 MutableTrackingVolumePtr CuboidVolumeBuilder::trackingVolume(
0202     const GeometryContext& gctx, TrackingVolumePtr /*gctx*/,
0203     std::shared_ptr<const VolumeBounds> /*bounds*/) const {
0204   // Build volumes
0205   std::vector<std::shared_ptr<TrackingVolume>> volumes;
0206   volumes.reserve(m_cfg.volumeCfg.size());
0207   for (VolumeConfig volCfg : m_cfg.volumeCfg) {
0208     volumes.emplace_back(buildVolume(gctx, volCfg));
0209   }
0210 
0211   // Sort the volumes vectors according to the center location, otherwise the
0212   // binning boundaries will fail
0213   std::ranges::sort(volumes, {},
0214                     [&](const auto& v) { return v->center(gctx).x(); });
0215 
0216   // Glue volumes
0217   for (unsigned int i = 0; i < volumes.size() - 1; i++) {
0218     volumes[i + 1]->glueTrackingVolume(
0219         gctx, BoundarySurfaceFace::negativeFaceYZ, volumes[i].get(),
0220         BoundarySurfaceFace::positiveFaceYZ);
0221     volumes[i]->glueTrackingVolume(gctx, BoundarySurfaceFace::positiveFaceYZ,
0222                                    volumes[i + 1].get(),
0223                                    BoundarySurfaceFace::negativeFaceYZ);
0224   }
0225 
0226   // Translation
0227   Transform3 trafo(Transform3::Identity());
0228   trafo.translation() = m_cfg.position;
0229 
0230   // Size of the volume
0231   auto volumeBounds = std::make_shared<CuboidVolumeBounds>(
0232       m_cfg.length.x() * 0.5, m_cfg.length.y() * 0.5, m_cfg.length.z() * 0.5);
0233 
0234   // Build vector of confined volumes
0235   std::vector<std::pair<TrackingVolumePtr, Vector3>> tapVec;
0236   tapVec.reserve(m_cfg.volumeCfg.size());
0237   for (auto& tVol : volumes) {
0238     tapVec.emplace_back(tVol, tVol->center(gctx));
0239   }
0240 
0241   // Set bin boundaries along binning
0242   std::vector<float> binBoundaries;
0243   binBoundaries.emplace_back(volumes[0]->center(gctx).x() -
0244                              m_cfg.volumeCfg[0].length.x() * 0.5);
0245   for (std::size_t i = 0; i < volumes.size(); i++) {
0246     binBoundaries.emplace_back(volumes[i]->center(gctx).x() +
0247                                m_cfg.volumeCfg[i].length.x() * 0.5);
0248   }
0249 
0250   // Build binning
0251   BinningData binData(BinningOption::open, AxisDirection::AxisX, binBoundaries);
0252   auto bu = std::make_unique<const BinUtility>(binData);
0253 
0254   // Build TrackingVolume array
0255   std::shared_ptr<const TrackingVolumeArray> trVolArr(
0256       new BinnedArrayXD<TrackingVolumePtr>(tapVec, std::move(bu)));
0257 
0258   // Create world volume
0259   MutableTrackingVolumePtr mtvp(std::make_shared<TrackingVolume>(
0260       trafo, volumeBounds, nullptr, nullptr, trVolArr,
0261       MutableTrackingVolumeVector{}, "World"));
0262 
0263   return mtvp;
0264 }
0265 
0266 }  // namespace Acts