Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:11:20

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