Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-06-30 07:52:43

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/Definitions/Algebra.hpp"
0010 #include "Acts/Detector/CuboidalContainerBuilder.hpp"
0011 #include "Acts/Detector/CylindricalContainerBuilder.hpp"
0012 #include "Acts/Detector/Detector.hpp"
0013 #include "Acts/Detector/DetectorBuilder.hpp"
0014 #include "Acts/Detector/DetectorVolume.hpp"
0015 #include "Acts/Detector/DetectorVolumeBuilder.hpp"
0016 #include "Acts/Detector/GeometryIdGenerator.hpp"
0017 #include "Acts/Detector/IndexedRootVolumeFinderBuilder.hpp"
0018 #include "Acts/Detector/KdtSurfacesProvider.hpp"
0019 #include "Acts/Detector/LayerStructureBuilder.hpp"
0020 #include "Acts/Detector/VolumeStructureBuilder.hpp"
0021 #include "Acts/Detector/interface/IDetectorBuilder.hpp"
0022 #include "Acts/Detector/interface/IDetectorComponentBuilder.hpp"
0023 #include "Acts/Detector/interface/IExternalStructureBuilder.hpp"
0024 #include "Acts/Detector/interface/IGeometryIdGenerator.hpp"
0025 #include "Acts/Detector/interface/IInternalStructureBuilder.hpp"
0026 #include "Acts/Detector/interface/IRootVolumeFinderBuilder.hpp"
0027 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0028 #include "Acts/Geometry/CylinderVolumeStack.hpp"
0029 #include "Acts/Geometry/Extent.hpp"
0030 #include "Acts/Geometry/GeometryContext.hpp"
0031 #include "Acts/Geometry/GeometryHierarchyMap.hpp"
0032 #include "Acts/Geometry/GeometryIdentifier.hpp"
0033 #include "Acts/Geometry/Portal.hpp"
0034 #include "Acts/Geometry/PortalLinkBase.hpp"
0035 #include "Acts/Geometry/PortalShell.hpp"
0036 #include "Acts/Geometry/ProtoLayer.hpp"
0037 #include "Acts/Geometry/TrackingGeometry.hpp"
0038 #include "Acts/Geometry/TrackingGeometryVisitor.hpp"
0039 #include "Acts/Geometry/Volume.hpp"
0040 #include "Acts/Geometry/VolumeAttachmentStrategy.hpp"
0041 #include "Acts/Geometry/VolumeBounds.hpp"
0042 #include "Acts/Geometry/VolumeResizeStrategy.hpp"
0043 #include "Acts/Material/ISurfaceMaterial.hpp"
0044 #include "Acts/Plugins/Python/Utilities.hpp"
0045 #include "Acts/Surfaces/Surface.hpp"
0046 #include "Acts/Surfaces/SurfaceArray.hpp"
0047 #include "Acts/Utilities/AxisDefinitions.hpp"
0048 #include "Acts/Utilities/Helpers.hpp"
0049 #include "Acts/Utilities/RangeXD.hpp"
0050 #include "Acts/Visualization/ViewConfig.hpp"
0051 #include "ActsExamples/Geometry/VolumeAssociationTest.hpp"
0052 
0053 #include <array>
0054 #include <memory>
0055 #include <numbers>
0056 #include <unordered_map>
0057 #include <vector>
0058 
0059 #include <boost/algorithm/string/join.hpp>
0060 #include <pybind11/pybind11.h>
0061 #include <pybind11/stl.h>
0062 
0063 namespace py = pybind11;
0064 using namespace pybind11::literals;
0065 
0066 namespace {
0067 struct GeometryIdentifierHookBinding : public Acts::GeometryIdentifierHook {
0068   py::object callable;
0069 
0070   Acts::GeometryIdentifier decorateIdentifier(
0071       Acts::GeometryIdentifier identifier,
0072       const Acts::Surface& surface) const override {
0073     return callable(identifier, surface.getSharedPtr())
0074         .cast<Acts::GeometryIdentifier>();
0075   }
0076 };
0077 
0078 struct MaterialSurfaceSelector {
0079   std::vector<const Acts::Surface*> surfaces = {};
0080 
0081   /// @param surface is the test surface
0082   void operator()(const Acts::Surface* surface) {
0083     if (surface->surfaceMaterial() != nullptr &&
0084         !rangeContainsValue(surfaces, surface)) {
0085       surfaces.push_back(surface);
0086     }
0087   }
0088 };
0089 
0090 struct IdentifierSurfacesCollector {
0091   std::unordered_map<Acts::GeometryIdentifier, const Acts::Surface*> surfaces;
0092   /// @param surface is the test surface
0093   void operator()(const Acts::Surface* surface) {
0094     surfaces[surface->geometryId()] = surface;
0095   }
0096 };
0097 
0098 #define _INVOKE(method, name, arg)                                  \
0099   pybind11::gil_scoped_acquire gil;                                 \
0100   pybind11::function override = pybind11::get_override(this, name); \
0101   if (!override) {                                                  \
0102     method(arg);                                                    \
0103     return;                                                         \
0104   }                                                                 \
0105   override(&arg);
0106 
0107 // We only implement the mutable visitor here, because pybind11 always casts
0108 // away const ness in any case
0109 class PyTrackingGeometryVisitor : public Acts::TrackingGeometryMutableVisitor {
0110  public:
0111   void visitVolume(Acts::TrackingVolume& volume) override {
0112     _INVOKE(Acts::TrackingGeometryMutableVisitor::visitVolume, "visitVolume",
0113             volume);
0114   }
0115 
0116   void visitPortal(Acts::Portal& portal) override {
0117     _INVOKE(Acts::TrackingGeometryMutableVisitor::visitPortal, "visitPortal",
0118             portal);
0119   }
0120 
0121   void visitLayer(Acts::Layer& layer) override {
0122     _INVOKE(Acts::TrackingGeometryMutableVisitor::visitLayer, "visitLayer",
0123             layer);
0124   }
0125 
0126   void visitSurface(Acts::Surface& surface) override {
0127     _INVOKE(Acts::TrackingGeometryMutableVisitor::visitSurface, "visitSurface",
0128             surface);
0129   }
0130 };
0131 
0132 #undef _INVOKE
0133 
0134 }  // namespace
0135 
0136 namespace Acts::Python {
0137 
0138 void addBlueprint(Context& ctx);
0139 
0140 void addGeometry(Context& ctx) {
0141   auto m = ctx.get("main");
0142   {
0143     py::class_<Acts::GeometryIdentifier>(m, "GeometryIdentifier")
0144         .def(py::init<>())
0145         .def(py::init<Acts::GeometryIdentifier::Value>())
0146         .def_property(
0147             "layer", &Acts::GeometryIdentifier::layer,
0148             [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0149               self = self.withLayer(value);
0150             })
0151         .def_property(
0152             "volume", &Acts::GeometryIdentifier::volume,
0153             [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0154               self = self.withVolume(value);
0155             })
0156         .def_property(
0157             "boundary", &Acts::GeometryIdentifier::boundary,
0158             [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0159               self = self.withBoundary(value);
0160             })
0161         .def_property(
0162             "approach", &Acts::GeometryIdentifier::approach,
0163             [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0164               self = self.withApproach(value);
0165             })
0166         .def_property(
0167             "sensitive", &Acts::GeometryIdentifier::sensitive,
0168             [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0169               self = self.withSensitive(value);
0170             })
0171         .def_property(
0172             "extra", &Acts::GeometryIdentifier::extra,
0173             [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0174               self = self.withExtra(value);
0175             })
0176         .def_property_readonly("value", &Acts::GeometryIdentifier::value)
0177         .def("__str__", [](const Acts::GeometryIdentifier& self) {
0178           std::stringstream ss;
0179           ss << self;
0180           return ss.str();
0181         });
0182   }
0183 
0184   {
0185     py::class_<Acts::Surface, std::shared_ptr<Acts::Surface>>(m, "Surface")
0186         // Can't bind directly because GeometryObject is virtual base of Surface
0187         .def_property_readonly(
0188             "geometryId", [](const Surface& self) { return self.geometryId(); })
0189         .def("center", &Surface::center)
0190         .def_property_readonly("type", &Surface::type)
0191         .def("visualize", &Surface::visualize)
0192         .def_property_readonly("surfaceMaterial",
0193                                &Acts::Surface::surfaceMaterialSharedPtr);
0194   }
0195 
0196   {
0197     py::enum_<Acts::Surface::SurfaceType>(m, "SurfaceType")
0198         .value("Cone", Acts::Surface::SurfaceType::Cone)
0199         .value("Cylinder", Acts::Surface::SurfaceType::Cylinder)
0200         .value("Disc", Acts::Surface::SurfaceType::Disc)
0201         .value("Perigee", Acts::Surface::SurfaceType::Perigee)
0202         .value("Plane", Acts::Surface::SurfaceType::Plane)
0203         .value("Straw", Acts::Surface::SurfaceType::Straw)
0204         .value("Curvilinear", Acts::Surface::SurfaceType::Curvilinear)
0205         .value("Other", Acts::Surface::SurfaceType::Other);
0206   }
0207 
0208   {
0209     py::enum_<Acts::VolumeBounds::BoundsType>(m, "VolumeBoundsType")
0210         .value("Cone", Acts::VolumeBounds::BoundsType::eCone)
0211         .value("Cuboid", Acts::VolumeBounds::BoundsType::eCuboid)
0212         .value("CutoutCylinder",
0213                Acts::VolumeBounds::BoundsType::eCutoutCylinder)
0214         .value("Cylinder", Acts::VolumeBounds::BoundsType::eCylinder)
0215         .value("GenericCuboid", Acts::VolumeBounds::BoundsType::eGenericCuboid)
0216         .value("Trapezoid", Acts::VolumeBounds::BoundsType::eTrapezoid)
0217         .value("Other", Acts::VolumeBounds::BoundsType::eOther);
0218   }
0219 
0220   {
0221     auto trkGeo =
0222         py::class_<Acts::TrackingGeometry,
0223                    std::shared_ptr<Acts::TrackingGeometry>>(m,
0224                                                             "TrackingGeometry")
0225             .def(py::init([](const MutableTrackingVolumePtr& volPtr,
0226                              std::shared_ptr<const IMaterialDecorator> matDec,
0227                              const GeometryIdentifierHook& hook,
0228                              Acts::Logging::Level level) {
0229               auto logger = Acts::getDefaultLogger("TrackingGeometry", level);
0230               auto obj = std::make_shared<Acts::TrackingGeometry>(
0231                   volPtr, matDec.get(), hook, *logger);
0232               return obj;
0233             }))
0234             .def("visitSurfaces",
0235                  [](Acts::TrackingGeometry& self, py::function& func) {
0236                    self.visitSurfaces(func);
0237                  })
0238             .def("geoIdSurfaceMap", &Acts::TrackingGeometry::geoIdSurfaceMap)
0239             .def("extractMaterialSurfaces",
0240                  [](Acts::TrackingGeometry& self) {
0241                    MaterialSurfaceSelector selector;
0242                    self.visitSurfaces(selector, false);
0243                    return selector.surfaces;
0244                  })
0245             .def_property_readonly(
0246                 "highestTrackingVolume",
0247                 &Acts::TrackingGeometry::highestTrackingVolumePtr)
0248             .def("visualize", &Acts::TrackingGeometry::visualize,
0249                  py::arg("helper"), py::arg("gctx"),
0250                  py::arg("viewConfig") = s_viewVolume,
0251                  py::arg("portalViewConfig") = s_viewPortal,
0252                  py::arg("sensitiveViewConfig") = s_viewSensitive);
0253 
0254     using apply_ptr_t =
0255         void (TrackingGeometry::*)(TrackingGeometryMutableVisitor&);
0256 
0257     trkGeo.def("apply", static_cast<apply_ptr_t>(&TrackingGeometry::apply));
0258   }
0259 
0260   {
0261     py::class_<Acts::VolumeBounds, std::shared_ptr<Acts::VolumeBounds>>(
0262         m, "VolumeBounds")
0263         .def("type", &Acts::VolumeBounds::type)
0264         .def("__str__", [](const Acts::VolumeBounds& self) {
0265           std::stringstream ss;
0266           ss << self;
0267           return ss.str();
0268         });
0269 
0270     auto cvb =
0271         py::class_<Acts::CylinderVolumeBounds,
0272                    std::shared_ptr<Acts::CylinderVolumeBounds>,
0273                    Acts::VolumeBounds>(m, "CylinderVolumeBounds")
0274             .def(py::init<double, double, double, double, double, double,
0275                           double>(),
0276                  "rmin"_a, "rmax"_a, "halfz"_a, "halfphi"_a = std::numbers::pi,
0277                  "avgphi"_a = 0., "bevelMinZ"_a = 0., "bevelMaxZ"_a = 0.);
0278 
0279     py::enum_<CylinderVolumeBounds::Face>(cvb, "Face")
0280         .value("PositiveDisc", CylinderVolumeBounds::Face::PositiveDisc)
0281         .value("NegativeDisc", CylinderVolumeBounds::Face::NegativeDisc)
0282         .value("OuterCylinder", CylinderVolumeBounds::Face::OuterCylinder)
0283         .value("InnerCylinder", CylinderVolumeBounds::Face::InnerCylinder)
0284         .value("NegativePhiPlane", CylinderVolumeBounds::Face::NegativePhiPlane)
0285         .value("PositivePhiPlane",
0286                CylinderVolumeBounds::Face::PositivePhiPlane);
0287   }
0288 
0289   {
0290     py::class_<Acts::Volume, std::shared_ptr<Acts::Volume>>(m, "Volume");
0291 
0292     py::class_<Acts::TrackingVolume, Acts::Volume,
0293                std::shared_ptr<Acts::TrackingVolume>>(m, "TrackingVolume")
0294         .def(py::init<const Transform3&, std::shared_ptr<Acts::VolumeBounds>,
0295                       std::string>());
0296   }
0297 
0298   {
0299     py::class_<Acts::GeometryIdentifierHook,
0300                std::shared_ptr<Acts::GeometryIdentifierHook>>(
0301         m, "GeometryIdentifierHook")
0302         .def(py::init([](py::object callable) {
0303           auto hook = std::make_shared<GeometryIdentifierHookBinding>();
0304           hook->callable = callable;
0305           return hook;
0306         }));
0307   }
0308 
0309   {
0310     py::class_<TrackingGeometryMutableVisitor, PyTrackingGeometryVisitor,
0311                std::shared_ptr<TrackingGeometryMutableVisitor>>(
0312         m, "TrackingGeometryMutableVisitor")
0313         .def(py::init<>());
0314   }
0315 
0316   py::class_<ExtentEnvelope>(m, "ExtentEnvelope")
0317       .def(py::init<>())
0318       .def(py::init<const Envelope&>())
0319       .def(py::init([](Envelope x, Envelope y, Envelope z, Envelope r,
0320                        Envelope phi, Envelope rPhi, Envelope theta,
0321                        Envelope eta, Envelope mag) {
0322              return ExtentEnvelope({.x = x,
0323                                     .y = y,
0324                                     .z = z,
0325                                     .r = r,
0326                                     .phi = phi,
0327                                     .rPhi = rPhi,
0328                                     .theta = theta,
0329                                     .eta = eta,
0330                                     .mag = mag});
0331            }),
0332            py::arg("x") = zeroEnvelope, py::arg("y") = zeroEnvelope,
0333            py::arg("z") = zeroEnvelope, py::arg("r") = zeroEnvelope,
0334            py::arg("phi") = zeroEnvelope, py::arg("rPhi") = zeroEnvelope,
0335            py::arg("theta") = zeroEnvelope, py::arg("eta") = zeroEnvelope,
0336            py::arg("mag") = zeroEnvelope)
0337       .def_static("Zero", &ExtentEnvelope::Zero)
0338       .def("__getitem__", [](ExtentEnvelope& self,
0339                              AxisDirection bValue) { return self[bValue]; })
0340       .def("__setitem__", [](ExtentEnvelope& self, AxisDirection bValue,
0341                              const Envelope& value) { self[bValue] = value; })
0342       .def("__str__", [](const ExtentEnvelope& self) {
0343         std::array<std::string, numAxisDirections()> values;
0344 
0345         std::stringstream ss;
0346         for (AxisDirection val : allAxisDirections()) {
0347           ss << val << "=(" << self[val][0] << ", " << self[val][1] << ")";
0348           values.at(toUnderlying(val)) = ss.str();
0349           ss.str("");
0350         }
0351 
0352         ss.str("");
0353         ss << "ExtentEnvelope(";
0354         ss << boost::algorithm::join(values, ", ");
0355         ss << ")";
0356         return ss.str();
0357       });
0358 
0359   py::class_<Extent>(m, "Extent")
0360       .def(py::init<const ExtentEnvelope&>(),
0361            py::arg("envelope") = ExtentEnvelope::Zero())
0362       .def("range",
0363            [](const Acts::Extent& self,
0364               Acts::AxisDirection bval) -> std::array<double, 2> {
0365              return {self.min(bval), self.max(bval)};
0366            })
0367       .def("setRange",
0368            [](Extent& self, Acts::AxisDirection bval,
0369               const std::array<double, 2>& range) {
0370              self.set(bval, range[0], range[1]);
0371            })
0372       .def("__str__", &Extent::toString);
0373 
0374   {
0375     py::enum_<VolumeAttachmentStrategy>(m, "VolumeAttachmentStrategy")
0376         .value("Gap", VolumeAttachmentStrategy::Gap)
0377         .value("First", VolumeAttachmentStrategy::First)
0378         .value("Second", VolumeAttachmentStrategy::Second)
0379         .value("Midpoint", VolumeAttachmentStrategy::Midpoint);
0380 
0381     py::enum_<VolumeResizeStrategy>(m, "VolumeResizeStrategy")
0382         .value("Gap", VolumeResizeStrategy::Gap)
0383         .value("Expand", VolumeResizeStrategy::Expand);
0384   }
0385 
0386   py::class_<PortalShellBase>(m, "PortalShellBase");
0387 
0388   addBlueprint(ctx);
0389 }
0390 
0391 void addExperimentalGeometry(Context& ctx) {
0392   auto [m, mex] = ctx.get("main", "examples");
0393 
0394   using namespace Acts::Experimental;
0395 
0396   // Detector volume definition
0397   py::class_<DetectorVolume, std::shared_ptr<DetectorVolume>>(m,
0398                                                               "DetectorVolume")
0399       .def("surfaces", &DetectorVolume::surfaces)
0400       .def("surfacePtrs", &DetectorVolume::surfacePtrs);
0401 
0402   // Detector definition
0403   py::class_<Detector, std::shared_ptr<Detector>>(m, "Detector")
0404       .def("volumes", &Detector::volumes)
0405       .def("volumePtrs", &Detector::volumePtrs)
0406       .def("numberVolumes",
0407            [](const Detector& self) { return self.volumes().size(); })
0408       .def("extractMaterialSurfaces",
0409            [](const Detector& self) {
0410              MaterialSurfaceSelector selector;
0411              self.visitSurfaces(selector);
0412              return selector.surfaces;
0413            })
0414       .def("geoIdSurfaceMap",
0415            [](const Detector& self) {
0416              IdentifierSurfacesCollector collector;
0417              self.visitSurfaces(collector);
0418              return collector.surfaces;
0419            })
0420       .def("cylindricalVolumeRepresentation",
0421            [](const Detector& self, const Acts::GeometryContext& gctx) {
0422              // Loop over the volumes and gather the extent
0423              Extent extent;
0424              for (const auto& volume : self.volumes()) {
0425                extent.extend(volume->extent(gctx));
0426              }
0427              auto bounds = std::make_shared<Acts::CylinderVolumeBounds>(
0428                  0., extent.max(Acts::AxisDirection::AxisR),
0429                  extent.max(Acts::AxisDirection::AxisZ));
0430 
0431              return std::make_shared<Acts::Volume>(Transform3::Identity(),
0432                                                    std::move(bounds));
0433            });
0434 
0435   // Portal definition
0436   py::class_<Experimental::Portal, std::shared_ptr<Experimental::Portal>>(
0437       m, "Portal");
0438 
0439   {
0440     // The surface hierarchy map
0441     using SurfaceHierarchyMap =
0442         Acts::GeometryHierarchyMap<std::shared_ptr<Surface>>;
0443 
0444     py::class_<SurfaceHierarchyMap, std::shared_ptr<SurfaceHierarchyMap>>(
0445         m, "SurfaceHierarchyMap");
0446 
0447     // Extract volume / layer surfaces
0448     mex.def("extractVolumeLayerSurfaces", [](const SurfaceHierarchyMap& smap,
0449                                              bool sensitiveOnly) {
0450       std::map<unsigned int,
0451                std::map<unsigned int, std::vector<std::shared_ptr<Surface>>>>
0452           surfaceVolumeLayerMap;
0453       for (const auto& surface : smap) {
0454         auto gid = surface->geometryId();
0455         // Exclusion criteria
0456         if (sensitiveOnly && gid.sensitive() == 0) {
0457           continue;
0458         };
0459         surfaceVolumeLayerMap[gid.volume()][gid.layer()].push_back(surface);
0460       }
0461       // Return the surface volume map
0462       return surfaceVolumeLayerMap;
0463     });
0464   }
0465 
0466   {
0467     // Be able to construct a proto binning
0468     py::class_<ProtoAxis>(m, "ProtoAxis")
0469         .def(py::init<Acts::AxisBoundaryType, const std::vector<double>&>(),
0470              "bType"_a, "e"_a)
0471         .def(py::init<Acts::AxisBoundaryType, double, double, std::size_t>(),
0472              "bType"_a, "minE"_a, "maxE"_a, "nbins"_a)
0473         .def(py::init<Acts::AxisBoundaryType, std::size_t>(), "bType"_a,
0474              "nbins"_a);
0475 
0476     py::class_<DirectedProtoAxis>(m, "DirectedProtoAxis")
0477         .def(py::init<Acts::AxisDirection, Acts::AxisBoundaryType,
0478                       const std::vector<double>&>(),
0479              "bValue"_a, "bType"_a, "e"_a)
0480         .def(py::init<Acts::AxisDirection, Acts::AxisBoundaryType, double,
0481                       double, std::size_t>(),
0482              "bValue"_a, "bType"_a, "minE"_a, "maxE"_a, "nbins"_a)
0483         .def(py::init<Acts::AxisDirection, Acts::AxisBoundaryType,
0484                       std::size_t>(),
0485              "bValue"_a, "bType"_a, "nbins"_a);
0486   }
0487 
0488   {
0489     // The internal layer structure builder
0490     py::class_<Acts::Experimental::IInternalStructureBuilder,
0491                std::shared_ptr<Acts::Experimental::IInternalStructureBuilder>>(
0492         m, "IInternalStructureBuilder");
0493 
0494     auto lsBuilder =
0495         py::class_<LayerStructureBuilder,
0496                    Acts::Experimental::IInternalStructureBuilder,
0497                    std::shared_ptr<LayerStructureBuilder>>(
0498             m, "LayerStructureBuilder")
0499             .def(py::init([](const LayerStructureBuilder::Config& config,
0500                              const std::string& name,
0501                              Acts::Logging::Level level) {
0502               return std::make_shared<LayerStructureBuilder>(
0503                   config, getDefaultLogger(name, level));
0504             }));
0505 
0506     auto lsConfig =
0507         py::class_<LayerStructureBuilder::Config>(lsBuilder, "Config")
0508             .def(py::init<>());
0509     ACTS_PYTHON_STRUCT(lsConfig, surfacesProvider, supports, binnings,
0510                        quarterSegments, auxiliary);
0511 
0512     // The internal layer structure builder
0513     py::class_<Acts::Experimental::ISurfacesProvider,
0514                std::shared_ptr<Acts::Experimental::ISurfacesProvider>>(
0515         m, "ISurfacesProvider");
0516 
0517     py::class_<LayerStructureBuilder::SurfacesHolder,
0518                Acts::Experimental::ISurfacesProvider,
0519                std::shared_ptr<LayerStructureBuilder::SurfacesHolder>>(
0520         lsBuilder, "SurfacesHolder")
0521         .def(py::init<std::vector<std::shared_ptr<Surface>>>());
0522   }
0523 
0524   {
0525     using RangeXDDim1 = Acts::RangeXD<1u, double>;
0526     using KdtSurfacesDim1Bin100 = Acts::Experimental::KdtSurfaces<1u, 100u>;
0527     using KdtSurfacesProviderDim1Bin100 =
0528         Acts::Experimental::KdtSurfacesProvider<1u, 100u>;
0529 
0530     py::class_<RangeXDDim1>(m, "RangeXDDim1")
0531         .def(py::init([](const std::array<double, 2u>& irange) {
0532           RangeXDDim1 range;
0533           range[0].shrink(irange[0], irange[1]);
0534           return range;
0535         }));
0536 
0537     py::class_<KdtSurfacesDim1Bin100, std::shared_ptr<KdtSurfacesDim1Bin100>>(
0538         m, "KdtSurfacesDim1Bin100")
0539         .def(py::init<const GeometryContext&,
0540                       const std::vector<std::shared_ptr<Acts::Surface>>&,
0541                       const std::array<Acts::AxisDirection, 1u>&>())
0542         .def("surfaces", py::overload_cast<const RangeXDDim1&>(
0543                              &KdtSurfacesDim1Bin100::surfaces, py::const_));
0544 
0545     py::class_<KdtSurfacesProviderDim1Bin100,
0546                Acts::Experimental::ISurfacesProvider,
0547                std::shared_ptr<KdtSurfacesProviderDim1Bin100>>(
0548         m, "KdtSurfacesProviderDim1Bin100")
0549         .def(py::init<std::shared_ptr<KdtSurfacesDim1Bin100>, const Extent&>());
0550   }
0551 
0552   {
0553     using RangeXDDim2 = Acts::RangeXD<2u, double>;
0554     using KdtSurfacesDim2Bin100 = Acts::Experimental::KdtSurfaces<2u, 100u>;
0555     using KdtSurfacesProviderDim2Bin100 =
0556         Acts::Experimental::KdtSurfacesProvider<2u, 100u>;
0557 
0558     py::class_<RangeXDDim2>(m, "RangeXDDim2")
0559         .def(py::init([](const std::array<double, 2u>& range0,
0560                          const std::array<double, 2u>& range1) {
0561           RangeXDDim2 range;
0562           range[0].shrink(range0[0], range0[1]);
0563           range[1].shrink(range1[0], range1[1]);
0564           return range;
0565         }));
0566 
0567     py::class_<KdtSurfacesDim2Bin100, std::shared_ptr<KdtSurfacesDim2Bin100>>(
0568         m, "KdtSurfacesDim2Bin100")
0569         .def(py::init<const GeometryContext&,
0570                       const std::vector<std::shared_ptr<Acts::Surface>>&,
0571                       const std::array<Acts::AxisDirection, 2u>&>())
0572         .def("surfaces", py::overload_cast<const RangeXDDim2&>(
0573                              &KdtSurfacesDim2Bin100::surfaces, py::const_));
0574 
0575     py::class_<KdtSurfacesProviderDim2Bin100,
0576                Acts::Experimental::ISurfacesProvider,
0577                std::shared_ptr<KdtSurfacesProviderDim2Bin100>>(
0578         m, "KdtSurfacesProviderDim2Bin100")
0579         .def(py::init<std::shared_ptr<KdtSurfacesDim2Bin100>, const Extent&>());
0580   }
0581 
0582   {
0583     using RangeXDDim3 = Acts::RangeXD<3u, double>;
0584 
0585     py::class_<RangeXDDim3>(m, "RangeXDDim3")
0586         .def(py::init([](const std::array<double, 2u>& range0,
0587                          const std::array<double, 2u>& range1,
0588                          const std::array<double, 2u>& range2) {
0589           RangeXDDim3 range;
0590           range[0].shrink(range0[0], range0[1]);
0591           range[1].shrink(range1[0], range1[1]);
0592           range[2].shrink(range2[0], range2[1]);
0593           return range;
0594         }));
0595   }
0596 
0597   {
0598     // The external volume structure builder
0599     py::class_<Acts::Experimental::IExternalStructureBuilder,
0600                std::shared_ptr<Acts::Experimental::IExternalStructureBuilder>>(
0601         m, "IExternalStructureBuilder");
0602 
0603     auto vsBuilder =
0604         py::class_<VolumeStructureBuilder,
0605                    Acts::Experimental::IExternalStructureBuilder,
0606                    std::shared_ptr<VolumeStructureBuilder>>(
0607             m, "VolumeStructureBuilder")
0608             .def(py::init([](const VolumeStructureBuilder::Config& config,
0609                              const std::string& name,
0610                              Acts::Logging::Level level) {
0611               return std::make_shared<VolumeStructureBuilder>(
0612                   config, getDefaultLogger(name, level));
0613             }));
0614 
0615     auto vsConfig =
0616         py::class_<VolumeStructureBuilder::Config>(vsBuilder, "Config")
0617             .def(py::init<>());
0618     ACTS_PYTHON_STRUCT(vsConfig, boundsType, boundValues, transform, auxiliary);
0619   }
0620 
0621   {
0622     py::class_<Acts::Experimental::IGeometryIdGenerator,
0623                std::shared_ptr<Acts::Experimental::IGeometryIdGenerator>>(
0624         m, "IGeometryIdGenerator");
0625 
0626     auto geoIdGen =
0627         py::class_<Acts::Experimental::GeometryIdGenerator,
0628                    Acts::Experimental::IGeometryIdGenerator,
0629                    std::shared_ptr<Acts::Experimental::GeometryIdGenerator>>(
0630             m, "GeometryIdGenerator")
0631             .def(py::init([](Acts::Experimental::GeometryIdGenerator::Config&
0632                                  config,
0633                              const std::string& name,
0634                              Acts::Logging::Level level) {
0635               return std::make_shared<Acts::Experimental::GeometryIdGenerator>(
0636                   config, getDefaultLogger(name, level));
0637             }));
0638 
0639     auto geoIdGenConfig =
0640         py::class_<Acts::Experimental::GeometryIdGenerator::Config>(geoIdGen,
0641                                                                     "Config")
0642             .def(py::init<>());
0643     ACTS_PYTHON_STRUCT(geoIdGenConfig, containerMode, containerId,
0644                        resetSubCounters, overrideExistingIds);
0645   }
0646 
0647   {
0648     // Put them together to a detector volume
0649     py::class_<Acts::Experimental::IDetectorComponentBuilder,
0650                std::shared_ptr<Acts::Experimental::IDetectorComponentBuilder>>(
0651         m, "IDetectorComponentBuilder");
0652 
0653     auto dvBuilder =
0654         py::class_<DetectorVolumeBuilder,
0655                    Acts::Experimental::IDetectorComponentBuilder,
0656                    std::shared_ptr<DetectorVolumeBuilder>>(
0657             m, "DetectorVolumeBuilder")
0658             .def(py::init([](const DetectorVolumeBuilder::Config& config,
0659                              const std::string& name,
0660                              Acts::Logging::Level level) {
0661               return std::make_shared<DetectorVolumeBuilder>(
0662                   config, getDefaultLogger(name, level));
0663             }))
0664             .def("construct", &DetectorVolumeBuilder::construct);
0665 
0666     auto dvConfig =
0667         py::class_<DetectorVolumeBuilder::Config>(dvBuilder, "Config")
0668             .def(py::init<>());
0669     ACTS_PYTHON_STRUCT(dvConfig, name, internalsBuilder, externalsBuilder,
0670                        geoIdGenerator, auxiliary);
0671   }
0672 
0673   {
0674     // The external volume structure builder
0675     py::class_<Acts::Experimental::IRootVolumeFinderBuilder,
0676                std::shared_ptr<Acts::Experimental::IRootVolumeFinderBuilder>>(
0677         m, "IRootVolumeFinderBuilder");
0678 
0679     auto irvBuilder =
0680         py::class_<Acts::Experimental::IndexedRootVolumeFinderBuilder,
0681                    Acts::Experimental::IRootVolumeFinderBuilder,
0682                    std::shared_ptr<
0683                        Acts::Experimental::IndexedRootVolumeFinderBuilder>>(
0684             m, "IndexedRootVolumeFinderBuilder")
0685             .def(py::init<std::vector<Acts::AxisDirection>>());
0686   }
0687 
0688   {
0689     // Cylindrical container builder
0690     auto ccBuilder =
0691         py::class_<CylindricalContainerBuilder,
0692                    Acts::Experimental::IDetectorComponentBuilder,
0693                    std::shared_ptr<CylindricalContainerBuilder>>(
0694             m, "CylindricalContainerBuilder")
0695             .def(py::init([](const CylindricalContainerBuilder::Config& config,
0696                              const std::string& name,
0697                              Acts::Logging::Level level) {
0698               return std::make_shared<CylindricalContainerBuilder>(
0699                   config, getDefaultLogger(name, level));
0700             }))
0701             .def("construct", &CylindricalContainerBuilder::construct);
0702 
0703     auto ccConfig =
0704         py::class_<CylindricalContainerBuilder::Config>(ccBuilder, "Config")
0705             .def(py::init<>());
0706     ACTS_PYTHON_STRUCT(ccConfig, builders, binning, rootVolumeFinderBuilder,
0707                        geoIdGenerator, geoIdReverseGen, auxiliary);
0708   }
0709 
0710   {
0711     // Cuboidal container builder
0712     auto ccBuilder =
0713         py::class_<CuboidalContainerBuilder,
0714                    Acts::Experimental::IDetectorComponentBuilder,
0715                    std::shared_ptr<CuboidalContainerBuilder>>(
0716             m, "CuboidalContainerBuilder")
0717             .def(py::init([](const CuboidalContainerBuilder::Config& config,
0718                              const std::string& name,
0719                              Acts::Logging::Level level) {
0720               return std::make_shared<CuboidalContainerBuilder>(
0721                   config, getDefaultLogger(name, level));
0722             }))
0723             .def("construct", &CuboidalContainerBuilder::construct);
0724 
0725     auto ccConfig =
0726         py::class_<CuboidalContainerBuilder::Config>(ccBuilder, "Config")
0727             .def(py::init<>());
0728     ACTS_PYTHON_STRUCT(ccConfig, builders, binning, rootVolumeFinderBuilder,
0729                        geoIdGenerator, geoIdReverseGen, auxiliary);
0730   }
0731 
0732   {
0733     // Detector builder
0734     auto dBuilder =
0735         py::class_<DetectorBuilder, std::shared_ptr<DetectorBuilder>>(
0736             m, "DetectorBuilder")
0737             .def(py::init([](const DetectorBuilder::Config& config,
0738                              const std::string& name,
0739                              Acts::Logging::Level level) {
0740               return std::make_shared<DetectorBuilder>(
0741                   config, getDefaultLogger(name, level));
0742             }))
0743             .def("construct", &DetectorBuilder::construct);
0744 
0745     auto dConfig = py::class_<DetectorBuilder::Config>(dBuilder, "Config")
0746                        .def(py::init<>());
0747     ACTS_PYTHON_STRUCT(dConfig, name, builder, geoIdGenerator,
0748                        materialDecorator, auxiliary);
0749   }
0750 
0751   ACTS_PYTHON_DECLARE_ALGORITHM(ActsExamples::VolumeAssociationTest, mex,
0752                                 "VolumeAssociationTest", name, ntests,
0753                                 randomNumbers, randomRange, detector);
0754 
0755   py::class_<ProtoLayer>(m, "ProtoLayer")
0756       .def(py::init<const GeometryContext&,
0757                     const std::vector<std::shared_ptr<Surface>>&,
0758                     const Transform3&>(),
0759            "gctx"_a, "surfaces"_a, "transform"_a = Transform3::Identity())
0760       .def("min", &ProtoLayer::min, "bval"_a, "addenv"_a = true)
0761       .def("max", &ProtoLayer::max, "bval"_a, "addenv"_a = true)
0762       .def_property_readonly("surfaces", &ProtoLayer::surfaces);
0763 }
0764 
0765 }  // namespace Acts::Python