File indexing completed on 2026-01-09 09:26:46
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Definitions/Algebra.hpp"
0010 #include "Acts/Geometry/TrackingGeometry.hpp"
0011 #include "Acts/MagneticField/MagneticFieldProvider.hpp"
0012 #include "Acts/Surfaces/SurfaceVisitorConcept.hpp"
0013 #include "Acts/Utilities/Logger.hpp"
0014 #include "ActsExamples/Geant4/Geant4ConstructionOptions.hpp"
0015 #include "ActsExamples/Geant4/Geant4Manager.hpp"
0016 #include "ActsExamples/Geant4/Geant4Simulation.hpp"
0017 #include "ActsExamples/Geant4/RegionCreator.hpp"
0018 #include "ActsExamples/Geant4/SensitiveSurfaceMapper.hpp"
0019 #include "ActsExamples/Geant4Detector/GdmlDetector.hpp"
0020 #include "ActsExamples/Geant4Detector/GdmlDetectorConstruction.hpp"
0021 #include "ActsExamples/Geant4Detector/Geant4Detector.hpp"
0022 #include "ActsPython/Utilities/Helpers.hpp"
0023 #include "ActsPython/Utilities/Macros.hpp"
0024
0025 #include <algorithm>
0026 #include <memory>
0027 #include <ranges>
0028 #include <string>
0029 #include <tuple>
0030 #include <unordered_map>
0031 #include <utility>
0032 #include <vector>
0033
0034 #include <G4RunManager.hh>
0035 #include <G4Transform3D.hh>
0036 #include <G4UserEventAction.hh>
0037 #include <G4UserRunAction.hh>
0038 #include <pybind11/pybind11.h>
0039 #include <pybind11/stl.h>
0040
0041 namespace py = pybind11;
0042 using namespace pybind11::literals;
0043
0044 using namespace ActsExamples;
0045 using namespace Acts;
0046 using namespace ActsPlugins;
0047 using namespace ActsPython;
0048
0049 PYBIND11_MODULE(ActsExamplesPythonBindingsGeant4, mod) {
0050 py::class_<Geant4Manager, std::unique_ptr<Geant4Manager, py::nodelete>>(
0051 mod, "Geant4Manager")
0052 .def_static("instance", &Geant4Manager::instance,
0053 py::return_value_policy::reference)
0054 .def("currentHandle", &Geant4Manager::currentHandle);
0055
0056 py::class_<Geant4Handle, std::shared_ptr<Geant4Handle>>(mod, "Geant4Handle")
0057 .def("tweakLogging", &Geant4Handle::tweakLogging);
0058
0059 {
0060 py::class_<Geant4ConstructionOptions,
0061 std::shared_ptr<Geant4ConstructionOptions>>(
0062 mod, "Geant4ConstructionOptions")
0063 .def(py::init<>())
0064 .def_readwrite("regionCreators",
0065 &Geant4ConstructionOptions::regionCreators);
0066 }
0067
0068 {
0069 using Algorithm = Geant4SimulationBase;
0070 using Config = Algorithm::Config;
0071 auto alg =
0072 py::class_<Algorithm, IAlgorithm, std::shared_ptr<Algorithm>>(
0073 mod, "Geant4SimulationBase")
0074 .def_property_readonly("geant4Handle", &Algorithm::geant4Handle);
0075
0076 auto c1 = py::class_<Config, std::shared_ptr<Config>>(alg, "Config")
0077 .def(py::init<>());
0078 ACTS_PYTHON_STRUCT(c1, inputParticles, randomNumbers, detector,
0079 geant4Handle);
0080 }
0081
0082 {
0083 using Config = Geant4::SensitiveSurfaceMapper::Config;
0084 using State = Geant4::SensitiveSurfaceMapper::State;
0085 auto sm = py::class_<Geant4::SensitiveSurfaceMapper,
0086 std::shared_ptr<Geant4::SensitiveSurfaceMapper>>(
0087 mod, "SensitiveSurfaceMapper")
0088 .def(py::init([](const Config& cfg, Logging::Level level) {
0089 return std::make_shared<Geant4::SensitiveSurfaceMapper>(
0090 cfg, getDefaultLogger("SensitiveSurfaceMapper", level));
0091 }));
0092
0093 py::class_<State>(sm, "State").def(py::init<>());
0094
0095 auto c = py::class_<Config>(sm, "Config").def(py::init<>());
0096 ACTS_PYTHON_STRUCT(c, materialMappings, volumeMappings, candidateSurfaces);
0097
0098 sm.def("create",
0099 [](const Config& cfg, Logging::Level level,
0100 const std::shared_ptr<const TrackingGeometry>& tGeometry) {
0101
0102 Config ccfg = cfg;
0103 ccfg.candidateSurfaces =
0104 std::make_shared<Geant4::SensitiveCandidates>(
0105 tGeometry, getDefaultLogger("SensitiveCandidates", level));
0106 return std::make_shared<Geant4::SensitiveSurfaceMapper>(
0107 ccfg, getDefaultLogger("SensitiveSurfaceMapper", level));
0108 });
0109
0110 sm.def(
0111 "remapSensitiveNames",
0112 [](Geant4::SensitiveSurfaceMapper& self, State& state,
0113 GeometryContext& gctx, Detector& detector, Transform3& transform) {
0114 return self.remapSensitiveNames(
0115 state, gctx,
0116 detector.buildGeant4DetectorConstruction({})->Construct(),
0117 transform);
0118 },
0119 "state"_a, "gctx"_a, "g4physicalVolume"_a, "motherTransform"_a);
0120 sm.def("checkMapping", &Geant4::SensitiveSurfaceMapper::checkMapping,
0121 "state"_a, "gctx"_a, "writeMappedAsObj"_a, "writeMissingAsObj"_a);
0122 }
0123
0124 {
0125 using Algorithm = Geant4Simulation;
0126 using Config = Algorithm::Config;
0127 auto alg =
0128 py::class_<Algorithm, Geant4SimulationBase, std::shared_ptr<Algorithm>>(
0129 mod, "Geant4Simulation")
0130 .def(py::init<const Config&, Logging::Level>(), py::arg("config"),
0131 py::arg("level"))
0132 .def_property_readonly("config", &Algorithm::config);
0133
0134 auto c1 = py::class_<Config, Geant4SimulationBase::Config,
0135 std::shared_ptr<Config>>(alg, "Config")
0136 .def(py::init<>());
0137 ACTS_PYTHON_STRUCT(
0138 c1, outputSimHits, outputParticles, outputPropagationSummaries,
0139 sensitiveSurfaceMapper, magneticField, physicsList, killVolume,
0140 killAfterTime, killSecondaries, recordHitsOfCharged,
0141 recordHitsOfNeutrals, recordHitsOfPrimaries, recordHitsOfSecondaries,
0142 keepParticlesWithoutHits, recordPropagationSummaries);
0143 }
0144
0145 {
0146 using Algorithm = Geant4MaterialRecording;
0147 using Config = Algorithm::Config;
0148 auto alg =
0149 py::class_<Algorithm, Geant4SimulationBase, std::shared_ptr<Algorithm>>(
0150 mod, "Geant4MaterialRecording")
0151 .def(py::init<const Config&, Logging::Level>(), py::arg("config"),
0152 py::arg("level"))
0153 .def_property_readonly("config", &Algorithm::config);
0154
0155 auto c = py::class_<Config, Geant4SimulationBase::Config,
0156 std::shared_ptr<Config>>(alg, "Config")
0157 .def(py::init<>());
0158 ACTS_PYTHON_STRUCT(c, outputMaterialTracks, excludeMaterials);
0159 }
0160
0161 {
0162 auto f =
0163 py::class_<Geant4Detector, Detector, std::shared_ptr<Geant4Detector>>(
0164 mod, "Geant4Detector")
0165 .def(py::init<const Geant4Detector::Config&>());
0166
0167 auto c = py::class_<Geant4Detector::Config>(f, "Config").def(py::init<>());
0168 ACTS_PYTHON_STRUCT(c, name, g4World, g4SurfaceOptions, logLevel);
0169 }
0170
0171 {
0172 auto f = py::class_<GdmlDetector, Detector, std::shared_ptr<GdmlDetector>>(
0173 mod, "GdmlDetector")
0174 .def(py::init<const GdmlDetector::Config&>());
0175
0176 auto c = py::class_<GdmlDetector::Config>(f, "Config").def(py::init<>());
0177 ACTS_PYTHON_STRUCT(c, path, logLevel);
0178 }
0179
0180 {
0181
0182
0183
0184
0185
0186 mod.def(
0187 "convertSurfaces", [](const std::string& gdmlFileName,
0188 const std::vector<std::string>& sensitiveMatches,
0189 const std::vector<std::string>& passiveMatches,
0190 bool convertMaterial) {
0191
0192 ActsExamples::GdmlDetectorConstruction gdmlContruction(gdmlFileName,
0193 {});
0194 const auto* world = gdmlContruction.Construct();
0195
0196
0197 auto sensitiveSelectors =
0198 std::make_shared<Geant4PhysicalVolumeSelectors::NameSelector>(
0199 sensitiveMatches, false);
0200 auto passiveSelectors =
0201 std::make_shared<Geant4PhysicalVolumeSelectors::NameSelector>(
0202 passiveMatches, false);
0203
0204 Geant4DetectorSurfaceFactory::Config config;
0205 Geant4DetectorSurfaceFactory::Cache cache;
0206 Geant4DetectorSurfaceFactory::Options options;
0207 options.sensitiveSurfaceSelector = sensitiveSelectors;
0208 options.passiveSurfaceSelector = passiveSelectors;
0209 options.convertMaterial = convertMaterial;
0210
0211 G4Transform3D nominal;
0212 Geant4DetectorSurfaceFactory factory(config);
0213 factory.construct(cache, nominal, *world, options);
0214
0215
0216 using Elements = std::vector<std::shared_ptr<Geant4DetectorElement>>;
0217 Elements detectorElements;
0218 detectorElements.reserve(cache.sensitiveSurfaces.size());
0219 using Surfaces = std::vector<std::shared_ptr<Surface>>;
0220 Surfaces surfaces;
0221 surfaces.reserve(cache.sensitiveSurfaces.size());
0222 std::ranges::for_each(
0223 cache.sensitiveSurfaces, [&](const auto& sensitive) {
0224 detectorElements.push_back(std::get<0>(sensitive));
0225 surfaces.push_back(std::get<1>(sensitive));
0226 });
0227
0228
0229 Surfaces passiveSurfaces;
0230 passiveSurfaces.reserve(cache.passiveSurfaces.size());
0231 for (const auto& passive : cache.passiveSurfaces) {
0232 passiveSurfaces.push_back(passive);
0233 }
0234
0235
0236 return std::tuple<Elements, Surfaces, Surfaces>(
0237 std::move(detectorElements), std::move(surfaces),
0238 std::move(passiveSurfaces));
0239 });
0240 }
0241
0242 {
0243 using Tool = Geant4::RegionCreator;
0244 using Config = Tool::Config;
0245 auto tool = py::class_<Tool>(mod, "RegionCreator")
0246 .def(py::init<const Config&>(), py::arg("config"))
0247 .def_property_readonly("config", &Tool::config);
0248
0249 auto c = py::class_<Config>(tool, "Config").def(py::init<>());
0250 ACTS_PYTHON_STRUCT(c, gammaCut, electronCut, positronCut, protonCut,
0251 volumes);
0252 }
0253 }