File indexing completed on 2026-07-16 08:08:33
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Definitions/Algebra.hpp"
0010 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0011 #include "Acts/Geometry/CylinderVolumeStack.hpp"
0012 #include "Acts/Geometry/Extent.hpp"
0013 #include "Acts/Geometry/GeometryContext.hpp"
0014 #include "Acts/Geometry/GeometryHierarchyMap.hpp"
0015 #include "Acts/Geometry/GeometryIdentifier.hpp"
0016 #include "Acts/Geometry/Portal.hpp"
0017 #include "Acts/Geometry/PortalLinkBase.hpp"
0018 #include "Acts/Geometry/PortalShell.hpp"
0019 #include "Acts/Geometry/ProtoLayer.hpp"
0020 #include "Acts/Geometry/TrackingGeometry.hpp"
0021 #include "Acts/Geometry/TrackingGeometryVisitor.hpp"
0022 #include "Acts/Geometry/Volume.hpp"
0023 #include "Acts/Geometry/VolumeAttachmentStrategy.hpp"
0024 #include "Acts/Geometry/VolumeBounds.hpp"
0025 #include "Acts/Geometry/VolumeResizeStrategy.hpp"
0026 #include "Acts/Material/ISurfaceMaterial.hpp"
0027 #include "Acts/Surfaces/Surface.hpp"
0028 #include "Acts/Surfaces/SurfaceArray.hpp"
0029 #include "Acts/Utilities/AxisDefinitions.hpp"
0030 #include "Acts/Utilities/Helpers.hpp"
0031 #include "Acts/Utilities/RangeXD.hpp"
0032 #include "Acts/Visualization/ViewConfig.hpp"
0033 #include "ActsPython/Utilities/Helpers.hpp"
0034 #include "ActsPython/Utilities/Macros.hpp"
0035
0036 #include <array>
0037 #include <memory>
0038 #include <numbers>
0039 #include <unordered_map>
0040 #include <utility>
0041 #include <vector>
0042
0043 #include <boost/algorithm/string/join.hpp>
0044 #include <pybind11/pybind11.h>
0045 #include <pybind11/stl.h>
0046
0047 namespace py = pybind11;
0048 using namespace pybind11::literals;
0049
0050 using namespace Acts;
0051 using namespace ActsExamples;
0052
0053 namespace {
0054 struct GeometryIdentifierHookBinding : public GeometryIdentifierHook {
0055 py::object callable;
0056
0057 GeometryIdentifier decorateIdentifier(GeometryIdentifier identifier,
0058 const Surface& surface) const override {
0059 return callable(identifier, surface.getSharedPtr())
0060 .cast<GeometryIdentifier>();
0061 }
0062 };
0063
0064 struct MaterialSurfaceSelector {
0065 std::vector<const Surface*> surfaces = {};
0066
0067
0068 void operator()(const Surface* surface) {
0069 if (surface->surfaceMaterial() != nullptr &&
0070 !rangeContainsValue(surfaces, surface)) {
0071 surfaces.push_back(surface);
0072 }
0073 }
0074 };
0075
0076 #define _INVOKE(method, name, arg) \
0077 pybind11::gil_scoped_acquire gil; \
0078 pybind11::function override = pybind11::get_override(this, name); \
0079 if (!override) { \
0080 method(arg); \
0081 return; \
0082 } \
0083 override(&arg);
0084
0085
0086
0087 class PyTrackingGeometryVisitor : public TrackingGeometryMutableVisitor {
0088 public:
0089 void visitVolume(TrackingVolume& volume) override {
0090 _INVOKE(TrackingGeometryMutableVisitor::visitVolume, "visitVolume", volume);
0091 }
0092
0093 void visitPortal(Portal& portal) override {
0094 _INVOKE(TrackingGeometryMutableVisitor::visitPortal, "visitPortal", portal);
0095 }
0096
0097 void visitLayer(Layer& layer) override {
0098 _INVOKE(TrackingGeometryMutableVisitor::visitLayer, "visitLayer", layer);
0099 }
0100
0101 void visitSurface(Surface& surface) override {
0102 _INVOKE(TrackingGeometryMutableVisitor::visitSurface, "visitSurface",
0103 surface);
0104 }
0105
0106 void visitBoundarySurface(
0107 Acts::BoundarySurfaceT<Acts::TrackingVolume>& boundary) override {
0108 _INVOKE(Acts::TrackingGeometryMutableVisitor::visitBoundarySurface,
0109 "visitBoundarySurface", boundary);
0110 }
0111 };
0112
0113 #undef _INVOKE
0114
0115 }
0116
0117 namespace ActsPython {
0118
0119
0120
0121 void addGeometry(py::module_& m) {
0122 {
0123 py::class_<GeometryContext>(m, "GeometryContext")
0124 .def(py::init([]() {
0125
0126 auto warnings = py::module_::import("warnings");
0127 auto builtins = py::module_::import("builtins");
0128 warnings.attr("warn")(
0129 "GeometryContext::dangerouslyDefaultConstruct() is deprecated. "
0130 "Use "
0131 "GeometryContext.dangerouslyDefaultConstruct() instead to "
0132 "make empty context construction explicit.",
0133 builtins.attr("DeprecationWarning"));
0134 return GeometryContext::dangerouslyDefaultConstruct();
0135 }))
0136 .def_static("dangerouslyDefaultConstruct",
0137 &GeometryContext::dangerouslyDefaultConstruct,
0138 "Create a default GeometryContext (empty, no alignment "
0139 "data)");
0140
0141 py::class_<GeometryIdentifier>(m, "GeometryIdentifier")
0142 .def(py::init<>())
0143 .def(py::init<GeometryIdentifier::Value>())
0144 .def(py::init([](int volume, int boundary, int layer, int approach,
0145 int sensitive, int extra) {
0146 return GeometryIdentifier()
0147 .withVolume(volume)
0148 .withBoundary(boundary)
0149 .withLayer(layer)
0150 .withApproach(approach)
0151 .withSensitive(sensitive)
0152 .withExtra(extra);
0153 }),
0154 py::arg("volume") = 0, py::arg("boundary") = 0,
0155 py::arg("layer") = 0, py::arg("approach") = 0,
0156 py::arg("sensitive") = 0, py::arg("extra") = 0)
0157 .def_property(
0158 "layer", &GeometryIdentifier::layer,
0159 [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0160 self = self.withLayer(value);
0161 })
0162 .def_property(
0163 "volume", &GeometryIdentifier::volume,
0164 [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0165 self = self.withVolume(value);
0166 })
0167 .def_property(
0168 "boundary", &GeometryIdentifier::boundary,
0169 [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0170 self = self.withBoundary(value);
0171 })
0172 .def_property(
0173 "approach", &GeometryIdentifier::approach,
0174 [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0175 self = self.withApproach(value);
0176 })
0177 .def_property(
0178 "sensitive", &GeometryIdentifier::sensitive,
0179 [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0180 self = self.withSensitive(value);
0181 })
0182 .def_property(
0183 "extra", &GeometryIdentifier::extra,
0184 [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0185 self = self.withExtra(value);
0186 })
0187 .def_property_readonly("value", &GeometryIdentifier::value)
0188 .def("__str__", [](const GeometryIdentifier& self) {
0189 std::stringstream ss;
0190 ss << self;
0191 return ss.str();
0192 });
0193 }
0194
0195 {
0196 py::class_<SurfacePlacementBase, std::shared_ptr<SurfacePlacementBase>>(
0197 m, "SurfacePlacementBase");
0198 }
0199
0200 {
0201 py::enum_<VolumeBounds::BoundsType>(m, "VolumeBoundsType")
0202 .value("Cone", VolumeBounds::BoundsType::eCone)
0203 .value("Cuboid", VolumeBounds::BoundsType::eCuboid)
0204 .value("CutoutCylinder", VolumeBounds::BoundsType::eCutoutCylinder)
0205 .value("Cylinder", VolumeBounds::BoundsType::eCylinder)
0206 .value("GenericCuboid", VolumeBounds::BoundsType::eGenericCuboid)
0207 .value("Trapezoid", VolumeBounds::BoundsType::eTrapezoid)
0208 .value("Other", VolumeBounds::BoundsType::eOther);
0209 }
0210
0211 {
0212 auto trkGeo =
0213 py::class_<TrackingGeometry, std::shared_ptr<TrackingGeometry>>(
0214 m, "TrackingGeometry")
0215 .def(py::init(
0216 [](const MutableTrackingVolumePtr& volPtr,
0217 const std::shared_ptr<const IMaterialDecorator>& matDec,
0218 const GeometryIdentifierHook& hook,
0219 Acts::Logging::Level level) {
0220 auto logger =
0221 Acts::getDefaultLogger("TrackingGeometry", level);
0222 auto obj = std::make_shared<Acts::TrackingGeometry>(
0223 volPtr, matDec.get(), hook, *logger);
0224 return obj;
0225 }))
0226 .def("visitSurfaces",
0227 [](TrackingGeometry& self, py::function& func) {
0228 self.visitSurfaces(func);
0229 })
0230 .def("geoIdSurfaceMap", &TrackingGeometry::geoIdSurfaceMap)
0231 .def("extractMaterialSurfaces",
0232 [](TrackingGeometry& self) {
0233 MaterialSurfaceSelector selector;
0234 self.visitSurfaces(selector, false);
0235 return selector.surfaces;
0236 })
0237 .def_property_readonly("highestTrackingVolume",
0238 &TrackingGeometry::highestTrackingVolumePtr)
0239 .def("visualize", &TrackingGeometry::visualize, py::arg("helper"),
0240 py::arg("gctx"), py::arg("viewConfig") = s_viewVolume,
0241 py::arg("portalViewConfig") = s_viewPortal,
0242 py::arg("sensitiveViewConfig") = s_viewSensitive);
0243
0244 using apply_ptr_t =
0245 void (TrackingGeometry::*)(TrackingGeometryMutableVisitor&);
0246
0247 trkGeo.def("apply", static_cast<apply_ptr_t>(&TrackingGeometry::apply));
0248 }
0249
0250 {
0251 py::class_<VolumeBounds, std::shared_ptr<VolumeBounds>>(m, "VolumeBounds")
0252 .def("type", &VolumeBounds::type)
0253 .def("__str__", [](const VolumeBounds& self) {
0254 std::stringstream ss;
0255 ss << self;
0256 return ss.str();
0257 });
0258
0259 auto cvb =
0260 py::class_<CylinderVolumeBounds, std::shared_ptr<CylinderVolumeBounds>,
0261 VolumeBounds>(m, "CylinderVolumeBounds")
0262 .def(py::init<double, double, double, double, double, double,
0263 double>(),
0264 "rmin"_a, "rmax"_a, "halfz"_a, "halfphi"_a = std::numbers::pi,
0265 "avgphi"_a = 0., "bevelMinZ"_a = 0., "bevelMaxZ"_a = 0.);
0266
0267 py::enum_<CylinderVolumeBounds::Face>(cvb, "Face")
0268 .value("PositiveDisc", CylinderVolumeBounds::Face::PositiveDisc)
0269 .value("NegativeDisc", CylinderVolumeBounds::Face::NegativeDisc)
0270 .value("OuterCylinder", CylinderVolumeBounds::Face::OuterCylinder)
0271 .value("InnerCylinder", CylinderVolumeBounds::Face::InnerCylinder)
0272 .value("NegativePhiPlane", CylinderVolumeBounds::Face::NegativePhiPlane)
0273 .value("PositivePhiPlane",
0274 CylinderVolumeBounds::Face::PositivePhiPlane);
0275 }
0276
0277 {
0278 py::class_<Volume, std::shared_ptr<Volume>>(m, "Volume");
0279
0280 py::class_<TrackingVolume, Volume, std::shared_ptr<TrackingVolume>>(
0281 m, "TrackingVolume")
0282 .def(py::init<const Transform3&, std::shared_ptr<VolumeBounds>,
0283 std::string>());
0284 }
0285
0286 {
0287 py::class_<GeometryIdentifierHook, std::shared_ptr<GeometryIdentifierHook>>(
0288 m, "GeometryIdentifierHook")
0289 .def(py::init([](py::object callable) {
0290 auto hook = std::make_shared<GeometryIdentifierHookBinding>();
0291 hook->callable = std::move(callable);
0292 return hook;
0293 }));
0294 }
0295
0296 {
0297 py::class_<TrackingGeometryMutableVisitor, PyTrackingGeometryVisitor,
0298 std::shared_ptr<TrackingGeometryMutableVisitor>>(
0299 m, "TrackingGeometryMutableVisitor")
0300 .def(py::init<>());
0301 }
0302
0303 py::class_<ExtentEnvelope>(m, "ExtentEnvelope")
0304 .def(py::init<>())
0305 .def(py::init<const Envelope&>())
0306 .def(py::init([](Envelope x, Envelope y, Envelope z, Envelope r,
0307 Envelope phi, Envelope rPhi, Envelope theta,
0308 Envelope eta, Envelope mag) {
0309 return ExtentEnvelope({.x = x,
0310 .y = y,
0311 .z = z,
0312 .r = r,
0313 .phi = phi,
0314 .rPhi = rPhi,
0315 .theta = theta,
0316 .eta = eta,
0317 .mag = mag});
0318 }),
0319 py::arg("x") = zeroEnvelope, py::arg("y") = zeroEnvelope,
0320 py::arg("z") = zeroEnvelope, py::arg("r") = zeroEnvelope,
0321 py::arg("phi") = zeroEnvelope, py::arg("rPhi") = zeroEnvelope,
0322 py::arg("theta") = zeroEnvelope, py::arg("eta") = zeroEnvelope,
0323 py::arg("mag") = zeroEnvelope)
0324 .def_static("Zero", &ExtentEnvelope::Zero)
0325 .def("__getitem__", [](ExtentEnvelope& self,
0326 AxisDirection bValue) { return self[bValue]; })
0327 .def("__setitem__", [](ExtentEnvelope& self, AxisDirection bValue,
0328 const Envelope& value) { self[bValue] = value; })
0329 .def("__str__", [](const ExtentEnvelope& self) {
0330 std::array<std::string, numAxisDirections()> values;
0331
0332 std::stringstream ss;
0333 for (AxisDirection val : allAxisDirections()) {
0334 ss << val << "=(" << self[val][0] << ", " << self[val][1] << ")";
0335 values.at(toUnderlying(val)) = ss.str();
0336 ss.str("");
0337 }
0338
0339 ss.str("");
0340 ss << "ExtentEnvelope(";
0341 ss << boost::algorithm::join(values, ", ");
0342 ss << ")";
0343 return ss.str();
0344 });
0345
0346 py::class_<Extent>(m, "Extent")
0347 .def(py::init<const ExtentEnvelope&>(),
0348 py::arg("envelope") = ExtentEnvelope::Zero())
0349 .def("range",
0350 [](const Extent& self, AxisDirection bval) -> std::array<double, 2> {
0351 return {self.min(bval), self.max(bval)};
0352 })
0353 .def("setRange",
0354 [](Extent& self, AxisDirection bval,
0355 const std::array<double, 2>& range) {
0356 self.set(bval, range[0], range[1]);
0357 })
0358 .def("__str__", &Extent::toString);
0359
0360 {
0361 py::enum_<VolumeAttachmentStrategy>(m, "VolumeAttachmentStrategy")
0362 .value("Gap", VolumeAttachmentStrategy::Gap)
0363 .value("First", VolumeAttachmentStrategy::First)
0364 .value("Second", VolumeAttachmentStrategy::Second)
0365 .value("Midpoint", VolumeAttachmentStrategy::Midpoint);
0366
0367 py::enum_<VolumeResizeStrategy>(m, "VolumeResizeStrategy")
0368 .value("Gap", VolumeResizeStrategy::Gap)
0369 .value("Expand", VolumeResizeStrategy::Expand);
0370 }
0371
0372 py::class_<PortalShellBase>(m, "PortalShellBase");
0373
0374 py::class_<ProtoLayer>(m, "ProtoLayer")
0375 .def(py::init<const GeometryContext&,
0376 const std::vector<std::shared_ptr<Surface>>&,
0377 const Transform3&>(),
0378 "gctx"_a, "surfaces"_a, "transform"_a = Transform3::Identity())
0379 .def("min", &ProtoLayer::min, "bval"_a, "addenv"_a = true)
0380 .def("max", &ProtoLayer::max, "bval"_a, "addenv"_a = true)
0381 .def_property_readonly("surfaces", &ProtoLayer::surfaces);
0382 }
0383
0384 }