File indexing completed on 2025-08-05 08:09:37
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Geometry/KDTreeTrackingGeometryBuilder.hpp"
0010
0011 #include "Acts/Geometry/CylinderLayer.hpp"
0012 #include "Acts/Geometry/DiscLayer.hpp"
0013 #include "Acts/Geometry/Extent.hpp"
0014 #include "Acts/Geometry/ITrackingVolumeHelper.hpp"
0015 #include "Acts/Geometry/Layer.hpp"
0016 #include "Acts/Geometry/LayerCreator.hpp"
0017 #include "Acts/Geometry/Polyhedron.hpp"
0018 #include "Acts/Geometry/ProtoLayer.hpp"
0019 #include "Acts/Geometry/TrackingGeometry.hpp"
0020 #include "Acts/Geometry/TrackingVolume.hpp"
0021 #include "Acts/Geometry/Volume.hpp"
0022 #include "Acts/Geometry/VolumeBounds.hpp"
0023 #include "Acts/Surfaces/CylinderBounds.hpp"
0024 #include "Acts/Surfaces/RadialBounds.hpp"
0025 #include "Acts/Surfaces/Surface.hpp"
0026 #include "Acts/Surfaces/SurfaceArray.hpp"
0027 #include "Acts/Surfaces/SurfaceBounds.hpp"
0028 #include "Acts/Utilities/BinningType.hpp"
0029 #include "Acts/Utilities/RangeXD.hpp"
0030
0031 #include <cstddef>
0032 #include <optional>
0033 #include <ostream>
0034 #include <stdexcept>
0035 #include <utility>
0036
0037 Acts::KDTreeTrackingGeometryBuilder::KDTreeTrackingGeometryBuilder(
0038 const Acts::KDTreeTrackingGeometryBuilder::Config& cfg,
0039 std::unique_ptr<const Logger> logger)
0040 : m_cfg(cfg), m_logger(std::move(logger)) {
0041 m_cfg.protoDetector.harmonize();
0042 }
0043
0044 std::unique_ptr<const Acts::TrackingGeometry>
0045 Acts::KDTreeTrackingGeometryBuilder::trackingGeometry(
0046 const GeometryContext& gctx) const {
0047 using MeasuredSurface =
0048 std::pair<std::array<ActsScalar, 2u>, std::shared_ptr<Surface>>;
0049
0050 std::vector<MeasuredSurface> surfacesMeasured;
0051 surfacesMeasured.reserve(m_cfg.surfaces.size());
0052 for (auto& s : m_cfg.surfaces) {
0053 auto ext = s->polyhedronRepresentation(gctx, 1u).extent();
0054 surfacesMeasured.push_back(MeasuredSurface{
0055 std::array<ActsScalar, 2u>{ext.medium(binZ), ext.medium(binR)}, s});
0056 }
0057
0058
0059 ACTS_INFO("Full KDTree has " << surfacesMeasured.size() << " surfaces.");
0060 SurfaceKDT surfaceKDT(std::move(surfacesMeasured));
0061
0062
0063 auto protoWorld = m_cfg.protoDetector.worldVolume;
0064
0065 KDTreeTrackingGeometryBuilder::Cache cCache;
0066
0067 auto worldTrackingVolume =
0068 translateVolume(cCache, gctx, surfaceKDT, protoWorld);
0069
0070 ACTS_INFO("Retrieved " << cCache.surfaceCounter
0071 << " surfaces from the KDTree.");
0072
0073
0074 return std::make_unique<const Acts::TrackingGeometry>(worldTrackingVolume);
0075 }
0076
0077 std::shared_ptr<Acts::TrackingVolume>
0078 Acts::KDTreeTrackingGeometryBuilder::translateVolume(
0079 Cache& cCache, const GeometryContext& gctx, const SurfaceKDT& kdt,
0080 const ProtoVolume& ptVolume, const std::string& indent) const {
0081 ACTS_DEBUG(indent << "Processing ProtoVolume: " << ptVolume.name);
0082 std::vector<std::shared_ptr<const TrackingVolume>> translatedVolumes = {};
0083
0084
0085 auto rangeR = ptVolume.extent.range(Acts::binR);
0086 auto rangeZ = ptVolume.extent.range(Acts::binZ);
0087
0088
0089 if (!ptVolume.container.has_value()) {
0090 ACTS_VERBOSE(indent << "> empty volume to be built");
0091 MutableTrackingVolumeVector mtv = {};
0092 auto tVolume = m_cfg.trackingVolumeHelper->createGapTrackingVolume(
0093 gctx, mtv, nullptr, rangeR.min(), rangeR.max(), rangeZ.min(),
0094 rangeZ.max(), 0, false, ptVolume.name);
0095 ACTS_DEBUG(indent << "> translated into gap volume bounds: "
0096 << tVolume->volumeBounds());
0097 return tVolume;
0098 } else {
0099
0100 auto& cts = ptVolume.container.value();
0101
0102
0103 if (cts.constituentVolumes.empty()) {
0104 throw std::invalid_argument(
0105 "KDTreeTrackingGeometryBuilder: no constituents given.");
0106 }
0107
0108
0109 if (!cts.layerContainer) {
0110 ACTS_VERBOSE(indent << "> volume container with "
0111 << cts.constituentVolumes.size() << " constituents.");
0112 for (auto& cVolume : cts.constituentVolumes) {
0113 auto dtVolume = translateVolume(cCache, gctx, kdt, cVolume,
0114 indent + m_cfg.hierarchyIndent);
0115 translatedVolumes.push_back(dtVolume);
0116 }
0117 auto tVolume = m_cfg.trackingVolumeHelper->createContainerTrackingVolume(
0118 gctx, translatedVolumes);
0119 ACTS_DEBUG(indent << "> translated into container volume bounds: "
0120 << tVolume->volumeBounds());
0121 return tVolume;
0122 } else {
0123
0124 std::vector<std::shared_ptr<const Layer>> layers = {};
0125 ACTS_VERBOSE(indent << "> layer container with "
0126 << cts.constituentVolumes.size() << " layers.");
0127 for (auto& plVolume : cts.constituentVolumes) {
0128 if (plVolume.internal.has_value()) {
0129 layers.push_back(translateLayer(cCache, gctx, kdt, plVolume,
0130 indent + m_cfg.hierarchyIndent));
0131 } else {
0132 ACTS_WARNING(indent << "> layer type volume has no internal "
0133 "description, layer not built.");
0134 }
0135 }
0136
0137 auto tVolume = m_cfg.trackingVolumeHelper->createTrackingVolume(
0138 gctx, layers, {}, nullptr, rangeR.min(), rangeR.max(), rangeZ.min(),
0139 rangeZ.max(), ptVolume.name);
0140 ACTS_DEBUG(indent << "> translated into bounds: "
0141 << tVolume->volumeBounds());
0142 return tVolume;
0143 }
0144 }
0145 }
0146
0147
0148 std::shared_ptr<const Acts::Layer>
0149 Acts::KDTreeTrackingGeometryBuilder::translateLayer(
0150 Cache& cCache, const GeometryContext& gctx, const SurfaceKDT& kdt,
0151 const ProtoVolume& plVolume, const std::string& indent) const {
0152 ACTS_DEBUG(indent + "Processing ProtoVolume: " << plVolume.name);
0153
0154
0155 auto& its = plVolume.internal.value();
0156
0157
0158 RangeXD<2u, ActsScalar> zrRange;
0159 zrRange[0u] = plVolume.extent.range(Acts::binZ);
0160 zrRange[1u] = plVolume.extent.range(Acts::binR);
0161
0162 auto layerSurfaces = kdt.rangeSearchWithKey(zrRange);
0163 ACTS_VERBOSE(indent + ">> looking z/r range = " << zrRange.toString());
0164 ACTS_VERBOSE(indent + ">> found " << layerSurfaces.size()
0165 << " surfaces in the KDTree.");
0166 cCache.surfaceCounter += layerSurfaces.size();
0167
0168 std::shared_ptr<const Acts::Layer> tLayer = nullptr;
0169
0170 if (layerSurfaces.size() == 1u) {
0171 auto surface = layerSurfaces[0u].second;
0172 const auto& transform = surface->transform(gctx);
0173 if (its.layerType == Acts::Surface::SurfaceType::Cylinder) {
0174 ACTS_VERBOSE(indent +
0175 ">> creating cylinder layer from a single surface.");
0176
0177 auto cylinderBounds =
0178 dynamic_cast<const CylinderBounds*>(&(surface->bounds()));
0179 auto cylinderBoundsClone =
0180 std::make_shared<const CylinderBounds>(*cylinderBounds);
0181 auto cylinderLayer =
0182 CylinderLayer::create(transform, cylinderBoundsClone, nullptr, 1.);
0183 cylinderLayer->assignSurfaceMaterial(surface->surfaceMaterialSharedPtr());
0184 tLayer = cylinderLayer;
0185 } else if (its.layerType == Acts::Surface::SurfaceType::Disc) {
0186 ACTS_VERBOSE(indent +
0187 ">> creating cylinder layer from a single surface.");
0188
0189 auto radialBounds =
0190 dynamic_cast<const RadialBounds*>(&(surface->bounds()));
0191 auto radialBoundsClone =
0192 std::make_shared<const RadialBounds>(*radialBounds);
0193 auto discLayer =
0194 DiscLayer::create(transform, radialBoundsClone, nullptr, 1.);
0195 discLayer->assignSurfaceMaterial(surface->surfaceMaterialSharedPtr());
0196 tLayer = discLayer;
0197 } else {
0198 throw std::invalid_argument(
0199 "KDTreeTrackingGeometryBuilder: layer type is neither cylinder nor "
0200 "disk.");
0201 }
0202
0203 } else if (layerSurfaces.size() > 1u) {
0204
0205 std::vector<std::shared_ptr<const Surface>> cLayerSurfaces;
0206 cLayerSurfaces.reserve(layerSurfaces.size());
0207 for (const auto& s : layerSurfaces) {
0208 cLayerSurfaces.push_back(s.second);
0209 }
0210
0211 Acts::BinningType bType0 = Acts::equidistant;
0212 Acts::BinningType bType1 = Acts::equidistant;
0213 std::size_t bins0 = 0;
0214 std::size_t bins1 = 0;
0215
0216 if (its.surfaceBinning.size() == 2u) {
0217 bType0 = its.surfaceBinning[0u].type;
0218 bType1 = its.surfaceBinning[1u].type;
0219
0220 if (bType0 == Acts::equidistant && bType1 == Acts::equidistant &&
0221 its.surfaceBinning[0u].bins() > 1u &&
0222 its.surfaceBinning[1u].bins() > 1u) {
0223 bins0 = its.surfaceBinning[0u].bins();
0224 bins1 = its.surfaceBinning[1u].bins();
0225 ACTS_VERBOSE(indent + ">> binning provided externally to be "
0226 << bins0 << " x " << bins1 << ".");
0227 }
0228 }
0229
0230 Acts::ProtoLayer pLayer(gctx, cLayerSurfaces);
0231 pLayer.envelope = plVolume.extent.envelope();
0232 if (its.layerType == Acts::Surface::SurfaceType::Cylinder) {
0233 ACTS_VERBOSE(indent + ">> creating cylinder layer with "
0234 << cLayerSurfaces.size() << " surfaces.");
0235
0236 tLayer = (bins0 * bins1 > 0)
0237 ? m_cfg.layerCreator->cylinderLayer(gctx, cLayerSurfaces,
0238 bins0, bins1, pLayer)
0239 : m_cfg.layerCreator->cylinderLayer(gctx, cLayerSurfaces,
0240 bType0, bType1, pLayer);
0241
0242 } else if (its.layerType == Acts::Surface::SurfaceType::Disc) {
0243 ACTS_VERBOSE(indent + ">> creating disc layer with "
0244 << cLayerSurfaces.size() << " surfaces.");
0245
0246 tLayer = (bins0 * bins1 > 0)
0247 ? m_cfg.layerCreator->discLayer(gctx, cLayerSurfaces, bins0,
0248 bins1, pLayer)
0249
0250 : m_cfg.layerCreator->discLayer(gctx, cLayerSurfaces, bType0,
0251 bType1, pLayer);
0252 } else {
0253 throw std::invalid_argument(
0254 "KDTreeTrackingGeometryBuilder: layer type is neither cylinder nor "
0255 "disk.");
0256 }
0257 }
0258 if (tLayer != nullptr && tLayer->representingVolume() != nullptr) {
0259 ACTS_DEBUG(indent << "> translated into layer bounds: "
0260 << tLayer->representingVolume()->volumeBounds());
0261 } else {
0262 throw std::runtime_error(
0263 "KDTreeTrackingGeometryBuilder: layer was not built.");
0264 }
0265
0266 return tLayer;
0267 }