Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2026-07-16 08:08:33

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/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   /// @param surface is the test surface
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 // We only implement the mutable visitor here, because pybind11 always casts
0086 // away const ness in any case
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 }  // namespace
0116 
0117 namespace ActsPython {
0118 
0119 /// This adds the geometry bindings to the python module
0120 /// @param m the module to add the bindings to
0121 void addGeometry(py::module_& m) {
0122   {
0123     py::class_<GeometryContext>(m, "GeometryContext")
0124         .def(py::init([]() {
0125           // Issue Python warning about deprecated default constructor
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         }))  // Keep for backward compatibility but warn
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 }  // namespace ActsPython