Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-17 09:21:36

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").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 }  // namespace ActsPython