Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:12:03

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