Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:03:11

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