File indexing completed on 2025-12-17 09:21:36
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").def(py::init<>());
0124
0125 py::class_<GeometryIdentifier>(m, "GeometryIdentifier")
0126 .def(py::init<>())
0127 .def(py::init<GeometryIdentifier::Value>())
0128 .def(py::init([](int volume, int boundary, int layer, int approach,
0129 int sensitive, int extra) {
0130 return GeometryIdentifier()
0131 .withVolume(volume)
0132 .withBoundary(boundary)
0133 .withLayer(layer)
0134 .withApproach(approach)
0135 .withSensitive(sensitive)
0136 .withExtra(extra);
0137 }),
0138 py::arg("volume") = 0, py::arg("boundary") = 0,
0139 py::arg("layer") = 0, py::arg("approach") = 0,
0140 py::arg("sensitive") = 0, py::arg("extra") = 0)
0141 .def_property(
0142 "layer", &GeometryIdentifier::layer,
0143 [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0144 self = self.withLayer(value);
0145 })
0146 .def_property(
0147 "volume", &GeometryIdentifier::volume,
0148 [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0149 self = self.withVolume(value);
0150 })
0151 .def_property(
0152 "boundary", &GeometryIdentifier::boundary,
0153 [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0154 self = self.withBoundary(value);
0155 })
0156 .def_property(
0157 "approach", &GeometryIdentifier::approach,
0158 [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0159 self = self.withApproach(value);
0160 })
0161 .def_property(
0162 "sensitive", &GeometryIdentifier::sensitive,
0163 [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0164 self = self.withSensitive(value);
0165 })
0166 .def_property(
0167 "extra", &GeometryIdentifier::extra,
0168 [](GeometryIdentifier& self, GeometryIdentifier::Value value) {
0169 self = self.withExtra(value);
0170 })
0171 .def_property_readonly("value", &GeometryIdentifier::value)
0172 .def("__str__", [](const GeometryIdentifier& self) {
0173 std::stringstream ss;
0174 ss << self;
0175 return ss.str();
0176 });
0177 }
0178
0179 {
0180 py::enum_<VolumeBounds::BoundsType>(m, "VolumeBoundsType")
0181 .value("Cone", VolumeBounds::BoundsType::eCone)
0182 .value("Cuboid", VolumeBounds::BoundsType::eCuboid)
0183 .value("CutoutCylinder", VolumeBounds::BoundsType::eCutoutCylinder)
0184 .value("Cylinder", VolumeBounds::BoundsType::eCylinder)
0185 .value("GenericCuboid", VolumeBounds::BoundsType::eGenericCuboid)
0186 .value("Trapezoid", VolumeBounds::BoundsType::eTrapezoid)
0187 .value("Other", VolumeBounds::BoundsType::eOther);
0188 }
0189
0190 {
0191 auto trkGeo =
0192 py::class_<TrackingGeometry, std::shared_ptr<TrackingGeometry>>(
0193 m, "TrackingGeometry")
0194 .def(py::init(
0195 [](const MutableTrackingVolumePtr& volPtr,
0196 const std::shared_ptr<const IMaterialDecorator>& matDec,
0197 const GeometryIdentifierHook& hook,
0198 Acts::Logging::Level level) {
0199 auto logger =
0200 Acts::getDefaultLogger("TrackingGeometry", level);
0201 auto obj = std::make_shared<Acts::TrackingGeometry>(
0202 volPtr, matDec.get(), hook, *logger);
0203 return obj;
0204 }))
0205 .def("visitSurfaces",
0206 [](TrackingGeometry& self, py::function& func) {
0207 self.visitSurfaces(func);
0208 })
0209 .def("geoIdSurfaceMap", &TrackingGeometry::geoIdSurfaceMap)
0210 .def("extractMaterialSurfaces",
0211 [](TrackingGeometry& self) {
0212 MaterialSurfaceSelector selector;
0213 self.visitSurfaces(selector, false);
0214 return selector.surfaces;
0215 })
0216 .def_property_readonly("highestTrackingVolume",
0217 &TrackingGeometry::highestTrackingVolumePtr)
0218 .def("visualize", &TrackingGeometry::visualize, py::arg("helper"),
0219 py::arg("gctx"), py::arg("viewConfig") = s_viewVolume,
0220 py::arg("portalViewConfig") = s_viewPortal,
0221 py::arg("sensitiveViewConfig") = s_viewSensitive);
0222
0223 using apply_ptr_t =
0224 void (TrackingGeometry::*)(TrackingGeometryMutableVisitor&);
0225
0226 trkGeo.def("apply", static_cast<apply_ptr_t>(&TrackingGeometry::apply));
0227 }
0228
0229 {
0230 py::class_<VolumeBounds, std::shared_ptr<VolumeBounds>>(m, "VolumeBounds")
0231 .def("type", &VolumeBounds::type)
0232 .def("__str__", [](const VolumeBounds& self) {
0233 std::stringstream ss;
0234 ss << self;
0235 return ss.str();
0236 });
0237
0238 auto cvb =
0239 py::class_<CylinderVolumeBounds, std::shared_ptr<CylinderVolumeBounds>,
0240 VolumeBounds>(m, "CylinderVolumeBounds")
0241 .def(py::init<double, double, double, double, double, double,
0242 double>(),
0243 "rmin"_a, "rmax"_a, "halfz"_a, "halfphi"_a = std::numbers::pi,
0244 "avgphi"_a = 0., "bevelMinZ"_a = 0., "bevelMaxZ"_a = 0.);
0245
0246 py::enum_<CylinderVolumeBounds::Face>(cvb, "Face")
0247 .value("PositiveDisc", CylinderVolumeBounds::Face::PositiveDisc)
0248 .value("NegativeDisc", CylinderVolumeBounds::Face::NegativeDisc)
0249 .value("OuterCylinder", CylinderVolumeBounds::Face::OuterCylinder)
0250 .value("InnerCylinder", CylinderVolumeBounds::Face::InnerCylinder)
0251 .value("NegativePhiPlane", CylinderVolumeBounds::Face::NegativePhiPlane)
0252 .value("PositivePhiPlane",
0253 CylinderVolumeBounds::Face::PositivePhiPlane);
0254 }
0255
0256 {
0257 py::class_<Volume, std::shared_ptr<Volume>>(m, "Volume");
0258
0259 py::class_<TrackingVolume, Volume, std::shared_ptr<TrackingVolume>>(
0260 m, "TrackingVolume")
0261 .def(py::init<const Transform3&, std::shared_ptr<VolumeBounds>,
0262 std::string>());
0263 }
0264
0265 {
0266 py::class_<GeometryIdentifierHook, std::shared_ptr<GeometryIdentifierHook>>(
0267 m, "GeometryIdentifierHook")
0268 .def(py::init([](py::object callable) {
0269 auto hook = std::make_shared<GeometryIdentifierHookBinding>();
0270 hook->callable = std::move(callable);
0271 return hook;
0272 }));
0273 }
0274
0275 {
0276 py::class_<TrackingGeometryMutableVisitor, PyTrackingGeometryVisitor,
0277 std::shared_ptr<TrackingGeometryMutableVisitor>>(
0278 m, "TrackingGeometryMutableVisitor")
0279 .def(py::init<>());
0280 }
0281
0282 py::class_<ExtentEnvelope>(m, "ExtentEnvelope")
0283 .def(py::init<>())
0284 .def(py::init<const Envelope&>())
0285 .def(py::init([](Envelope x, Envelope y, Envelope z, Envelope r,
0286 Envelope phi, Envelope rPhi, Envelope theta,
0287 Envelope eta, Envelope mag) {
0288 return ExtentEnvelope({.x = x,
0289 .y = y,
0290 .z = z,
0291 .r = r,
0292 .phi = phi,
0293 .rPhi = rPhi,
0294 .theta = theta,
0295 .eta = eta,
0296 .mag = mag});
0297 }),
0298 py::arg("x") = zeroEnvelope, py::arg("y") = zeroEnvelope,
0299 py::arg("z") = zeroEnvelope, py::arg("r") = zeroEnvelope,
0300 py::arg("phi") = zeroEnvelope, py::arg("rPhi") = zeroEnvelope,
0301 py::arg("theta") = zeroEnvelope, py::arg("eta") = zeroEnvelope,
0302 py::arg("mag") = zeroEnvelope)
0303 .def_static("Zero", &ExtentEnvelope::Zero)
0304 .def("__getitem__", [](ExtentEnvelope& self,
0305 AxisDirection bValue) { return self[bValue]; })
0306 .def("__setitem__", [](ExtentEnvelope& self, AxisDirection bValue,
0307 const Envelope& value) { self[bValue] = value; })
0308 .def("__str__", [](const ExtentEnvelope& self) {
0309 std::array<std::string, numAxisDirections()> values;
0310
0311 std::stringstream ss;
0312 for (AxisDirection val : allAxisDirections()) {
0313 ss << val << "=(" << self[val][0] << ", " << self[val][1] << ")";
0314 values.at(toUnderlying(val)) = ss.str();
0315 ss.str("");
0316 }
0317
0318 ss.str("");
0319 ss << "ExtentEnvelope(";
0320 ss << boost::algorithm::join(values, ", ");
0321 ss << ")";
0322 return ss.str();
0323 });
0324
0325 py::class_<Extent>(m, "Extent")
0326 .def(py::init<const ExtentEnvelope&>(),
0327 py::arg("envelope") = ExtentEnvelope::Zero())
0328 .def("range",
0329 [](const Extent& self, AxisDirection bval) -> std::array<double, 2> {
0330 return {self.min(bval), self.max(bval)};
0331 })
0332 .def("setRange",
0333 [](Extent& self, AxisDirection bval,
0334 const std::array<double, 2>& range) {
0335 self.set(bval, range[0], range[1]);
0336 })
0337 .def("__str__", &Extent::toString);
0338
0339 {
0340 py::enum_<VolumeAttachmentStrategy>(m, "VolumeAttachmentStrategy")
0341 .value("Gap", VolumeAttachmentStrategy::Gap)
0342 .value("First", VolumeAttachmentStrategy::First)
0343 .value("Second", VolumeAttachmentStrategy::Second)
0344 .value("Midpoint", VolumeAttachmentStrategy::Midpoint);
0345
0346 py::enum_<VolumeResizeStrategy>(m, "VolumeResizeStrategy")
0347 .value("Gap", VolumeResizeStrategy::Gap)
0348 .value("Expand", VolumeResizeStrategy::Expand);
0349 }
0350
0351 py::class_<PortalShellBase>(m, "PortalShellBase");
0352
0353 py::class_<ProtoLayer>(m, "ProtoLayer")
0354 .def(py::init<const GeometryContext&,
0355 const std::vector<std::shared_ptr<Surface>>&,
0356 const Transform3&>(),
0357 "gctx"_a, "surfaces"_a, "transform"_a = Transform3::Identity())
0358 .def("min", &ProtoLayer::min, "bval"_a, "addenv"_a = true)
0359 .def("max", &ProtoLayer::max, "bval"_a, "addenv"_a = true)
0360 .def_property_readonly("surfaces", &ProtoLayer::surfaces);
0361 }
0362
0363 }