File indexing completed on 2025-10-29 07:54:47
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Definitions/Algebra.hpp"
0010 #include "Acts/Detector/Detector.hpp"
0011 #include "Acts/Geometry/TrackingGeometry.hpp"
0012 #include "Acts/MagneticField/MagneticFieldProvider.hpp"
0013 #include "Acts/Surfaces/SurfaceVisitorConcept.hpp"
0014 #include "Acts/Utilities/Logger.hpp"
0015 #include "ActsExamples/Geant4/Geant4ConstructionOptions.hpp"
0016 #include "ActsExamples/Geant4/Geant4Manager.hpp"
0017 #include "ActsExamples/Geant4/Geant4Simulation.hpp"
0018 #include "ActsExamples/Geant4/RegionCreator.hpp"
0019 #include "ActsExamples/Geant4/SensitiveSurfaceMapper.hpp"
0020 #include "ActsExamples/Geant4Detector/GdmlDetector.hpp"
0021 #include "ActsExamples/Geant4Detector/GdmlDetectorConstruction.hpp"
0022 #include "ActsExamples/Geant4Detector/Geant4Detector.hpp"
0023 #include "ActsExamples/MuonSpectrometerMockupDetector/MockupSectorBuilder.hpp"
0024 #include "ActsPlugins/Geant4/Geant4DetectorElement.hpp"
0025 #include "ActsPlugins/Geant4/Geant4DetectorSurfaceFactory.hpp"
0026 #include "ActsPlugins/Geant4/Geant4PhysicalVolumeSelectors.hpp"
0027 #include "ActsPython/Utilities/Helpers.hpp"
0028 #include "ActsPython/Utilities/Macros.hpp"
0029
0030 #include <algorithm>
0031 #include <memory>
0032 #include <ranges>
0033 #include <string>
0034 #include <tuple>
0035 #include <unordered_map>
0036 #include <utility>
0037 #include <vector>
0038
0039 #include <G4RunManager.hh>
0040 #include <G4Transform3D.hh>
0041 #include <G4UserEventAction.hh>
0042 #include <G4UserRunAction.hh>
0043 #include <pybind11/pybind11.h>
0044 #include <pybind11/stl.h>
0045
0046 namespace py = pybind11;
0047 using namespace pybind11::literals;
0048
0049 using namespace ActsExamples;
0050 using namespace Acts;
0051 using namespace ActsPlugins;
0052 using namespace ActsPython;
0053
0054 struct ExperimentalSensitiveCandidates
0055 : public Geant4::SensitiveCandidatesBase {
0056 std::shared_ptr<const Experimental::Detector> detector;
0057
0058
0059 std::vector<const Surface*> queryPosition(
0060 const GeometryContext& gctx, const Vector3& position) const override {
0061 std::vector<const Surface*> surfaces;
0062
0063 auto volume = detector->findDetectorVolume(gctx, position);
0064 if (volume != nullptr) {
0065 for (const auto& surface : volume->surfaces()) {
0066 if (surface->associatedDetectorElement() != nullptr) {
0067 surfaces.push_back(surface);
0068 }
0069 }
0070 }
0071 return surfaces;
0072 }
0073
0074 std::vector<const Surface*> queryAll() const override {
0075 std::vector<const Surface*> surfaces;
0076 detector->visitSurfaces([&](const Surface* surface) {
0077 if (surface->associatedDetectorElement() != nullptr) {
0078 surfaces.push_back(surface);
0079 }
0080 });
0081 return surfaces;
0082 }
0083 };
0084
0085 PYBIND11_MODULE(ActsPythonBindingsGeant4, mod) {
0086 py::class_<Geant4Manager, std::unique_ptr<Geant4Manager, py::nodelete>>(
0087 mod, "Geant4Manager")
0088 .def_static("instance", &Geant4Manager::instance,
0089 py::return_value_policy::reference)
0090 .def("currentHandle", &Geant4Manager::currentHandle);
0091
0092 py::class_<Geant4Handle, std::shared_ptr<Geant4Handle>>(mod, "Geant4Handle")
0093 .def("tweakLogging", &Geant4Handle::tweakLogging);
0094
0095 {
0096 py::class_<Geant4ConstructionOptions,
0097 std::shared_ptr<Geant4ConstructionOptions>>(
0098 mod, "Geant4ConstructionOptions")
0099 .def(py::init<>())
0100 .def_readwrite("regionCreators",
0101 &Geant4ConstructionOptions::regionCreators);
0102 }
0103
0104 {
0105 using Algorithm = Geant4SimulationBase;
0106 using Config = Algorithm::Config;
0107 auto alg =
0108 py::class_<Algorithm, IAlgorithm, std::shared_ptr<Algorithm>>(
0109 mod, "Geant4SimulationBase")
0110 .def_property_readonly("geant4Handle", &Algorithm::geant4Handle);
0111
0112 auto c1 = py::class_<Config, std::shared_ptr<Config>>(alg, "Config")
0113 .def(py::init<>());
0114 ACTS_PYTHON_STRUCT(c1, inputParticles, randomNumbers, detector,
0115 geant4Handle);
0116 }
0117
0118 {
0119 using Config = Geant4::SensitiveSurfaceMapper::Config;
0120 using State = Geant4::SensitiveSurfaceMapper::State;
0121 auto sm = py::class_<Geant4::SensitiveSurfaceMapper,
0122 std::shared_ptr<Geant4::SensitiveSurfaceMapper>>(
0123 mod, "SensitiveSurfaceMapper")
0124 .def(py::init([](const Config& cfg, Logging::Level level) {
0125 return std::make_shared<Geant4::SensitiveSurfaceMapper>(
0126 cfg, getDefaultLogger("SensitiveSurfaceMapper", level));
0127 }));
0128
0129 py::class_<State>(sm, "State").def(py::init<>());
0130
0131 auto c = py::class_<Config>(sm, "Config").def(py::init<>());
0132 ACTS_PYTHON_STRUCT(c, materialMappings, volumeMappings, candidateSurfaces);
0133
0134 sm.def("create",
0135 [](const Config& cfg, Logging::Level level,
0136 const std::shared_ptr<const TrackingGeometry>& tGeometry) {
0137
0138 Config ccfg = cfg;
0139 ccfg.candidateSurfaces =
0140 std::make_shared<Geant4::SensitiveCandidates>(
0141 tGeometry, getDefaultLogger("SensitiveCandidates", level));
0142 return std::make_shared<Geant4::SensitiveSurfaceMapper>(
0143 ccfg, getDefaultLogger("SensitiveSurfaceMapper", level));
0144 });
0145
0146 sm.def("create",
0147 [](const Config& cfg, Logging::Level level,
0148 const std::shared_ptr<const Experimental::Detector>& detector) {
0149
0150
0151
0152 Config ccfg = cfg;
0153 auto candidateSurfaces =
0154 std::make_shared<ExperimentalSensitiveCandidates>();
0155 candidateSurfaces->detector = detector;
0156 ccfg.candidateSurfaces = candidateSurfaces;
0157 return std::make_shared<Geant4::SensitiveSurfaceMapper>(
0158 ccfg, getDefaultLogger("SensitiveSurfaceMapper", level));
0159 });
0160
0161 sm.def(
0162 "remapSensitiveNames",
0163 [](Geant4::SensitiveSurfaceMapper& self, State& state,
0164 GeometryContext& gctx, Detector& detector, Transform3& transform) {
0165 return self.remapSensitiveNames(
0166 state, gctx,
0167 detector.buildGeant4DetectorConstruction({})->Construct(),
0168 transform);
0169 },
0170 "state"_a, "gctx"_a, "g4physicalVolume"_a, "motherTransform"_a);
0171 sm.def("checkMapping", &Geant4::SensitiveSurfaceMapper::checkMapping,
0172 "state"_a, "gctx"_a, "writeMappedAsObj"_a, "writeMissingAsObj"_a);
0173 }
0174
0175 {
0176 using Algorithm = Geant4Simulation;
0177 using Config = Algorithm::Config;
0178 auto alg =
0179 py::class_<Algorithm, Geant4SimulationBase, std::shared_ptr<Algorithm>>(
0180 mod, "Geant4Simulation")
0181 .def(py::init<const Config&, Logging::Level>(), py::arg("config"),
0182 py::arg("level"))
0183 .def_property_readonly("config", &Algorithm::config);
0184
0185 auto c1 = py::class_<Config, Geant4SimulationBase::Config,
0186 std::shared_ptr<Config>>(alg, "Config")
0187 .def(py::init<>());
0188 ACTS_PYTHON_STRUCT(
0189 c1, outputSimHits, outputParticles, outputPropagationSummaries,
0190 sensitiveSurfaceMapper, magneticField, physicsList, killVolume,
0191 killAfterTime, killSecondaries, recordHitsOfCharged,
0192 recordHitsOfNeutrals, recordHitsOfPrimaries, recordHitsOfSecondaries,
0193 keepParticlesWithoutHits, recordPropagationSummaries);
0194 }
0195
0196 {
0197 using Algorithm = Geant4MaterialRecording;
0198 using Config = Algorithm::Config;
0199 auto alg =
0200 py::class_<Algorithm, Geant4SimulationBase, std::shared_ptr<Algorithm>>(
0201 mod, "Geant4MaterialRecording")
0202 .def(py::init<const Config&, Logging::Level>(), py::arg("config"),
0203 py::arg("level"))
0204 .def_property_readonly("config", &Algorithm::config);
0205
0206 auto c = py::class_<Config, Geant4SimulationBase::Config,
0207 std::shared_ptr<Config>>(alg, "Config")
0208 .def(py::init<>());
0209 ACTS_PYTHON_STRUCT(c, outputMaterialTracks, excludeMaterials);
0210 }
0211
0212 {
0213 using ISelector = IGeant4PhysicalVolumeSelector;
0214 auto is = py::class_<ISelector, std::shared_ptr<ISelector>>(
0215 mod, "IVolumeSelector");
0216
0217 using NameSelector = Geant4PhysicalVolumeSelectors::NameSelector;
0218 auto ns = py::class_<NameSelector, std::shared_ptr<NameSelector>>(
0219 mod, "VolumeNameSelector", is)
0220 .def(py::init<const std::vector<std::string>&, bool>());
0221
0222 using Factory = Geant4DetectorSurfaceFactory;
0223 auto o = py::class_<Factory::Options>(mod, "SurfaceFactoryOptions")
0224 .def(py::init<>());
0225 ACTS_PYTHON_STRUCT(o, scaleConversion, convertMaterial,
0226 convertedMaterialThickness, sensitiveSurfaceSelector,
0227 passiveSurfaceSelector);
0228 }
0229
0230 {
0231 auto f =
0232 py::class_<Geant4Detector, Detector, std::shared_ptr<Geant4Detector>>(
0233 mod, "Geant4Detector")
0234 .def(py::init<const Geant4Detector::Config&>());
0235
0236 auto c = py::class_<Geant4Detector::Config>(f, "Config").def(py::init<>());
0237 ACTS_PYTHON_STRUCT(c, name, g4World, g4SurfaceOptions, protoDetector,
0238 geometryIdentifierHook, logLevel);
0239 }
0240
0241 {
0242 auto f = py::class_<GdmlDetector, Detector, std::shared_ptr<GdmlDetector>>(
0243 mod, "GdmlDetector")
0244 .def(py::init<const GdmlDetector::Config&>());
0245
0246 auto c = py::class_<GdmlDetector::Config>(f, "Config").def(py::init<>());
0247 ACTS_PYTHON_STRUCT(c, path, logLevel);
0248 }
0249
0250 {
0251
0252
0253
0254
0255
0256 mod.def(
0257 "convertSurfaces", [](const std::string& gdmlFileName,
0258 const std::vector<std::string>& sensitiveMatches,
0259 const std::vector<std::string>& passiveMatches,
0260 bool convertMaterial) {
0261
0262 ActsExamples::GdmlDetectorConstruction gdmlContruction(gdmlFileName,
0263 {});
0264 const auto* world = gdmlContruction.Construct();
0265
0266
0267 auto sensitiveSelectors =
0268 std::make_shared<Geant4PhysicalVolumeSelectors::NameSelector>(
0269 sensitiveMatches, false);
0270 auto passiveSelectors =
0271 std::make_shared<Geant4PhysicalVolumeSelectors::NameSelector>(
0272 passiveMatches, false);
0273
0274 Geant4DetectorSurfaceFactory::Config config;
0275 Geant4DetectorSurfaceFactory::Cache cache;
0276 Geant4DetectorSurfaceFactory::Options options;
0277 options.sensitiveSurfaceSelector = sensitiveSelectors;
0278 options.passiveSurfaceSelector = passiveSelectors;
0279 options.convertMaterial = convertMaterial;
0280
0281 G4Transform3D nominal;
0282 Geant4DetectorSurfaceFactory factory(config);
0283 factory.construct(cache, nominal, *world, options);
0284
0285
0286 using Elements = std::vector<std::shared_ptr<Geant4DetectorElement>>;
0287 Elements detectorElements;
0288 detectorElements.reserve(cache.sensitiveSurfaces.size());
0289 using Surfaces = std::vector<std::shared_ptr<Surface>>;
0290 Surfaces surfaces;
0291 surfaces.reserve(cache.sensitiveSurfaces.size());
0292 std::ranges::for_each(
0293 cache.sensitiveSurfaces, [&](const auto& sensitive) {
0294 detectorElements.push_back(std::get<0>(sensitive));
0295 surfaces.push_back(std::get<1>(sensitive));
0296 });
0297
0298
0299 Surfaces passiveSurfaces;
0300 passiveSurfaces.reserve(cache.passiveSurfaces.size());
0301 for (const auto& passive : cache.passiveSurfaces) {
0302 passiveSurfaces.push_back(passive);
0303 }
0304
0305
0306 return std::tuple<Elements, Surfaces, Surfaces>(
0307 std::move(detectorElements), std::move(surfaces),
0308 std::move(passiveSurfaces));
0309 });
0310 }
0311
0312 {
0313 using MockupSectorBuilder = MockupSectorBuilder;
0314 using Config = MockupSectorBuilder::Config;
0315 using ChamberConfig = MockupSectorBuilder::ChamberConfig;
0316
0317 auto ms =
0318 py::class_<MockupSectorBuilder, std::shared_ptr<MockupSectorBuilder>>(
0319 mod, "MockupSectorBuilder")
0320 .def(py::init<const Config&>())
0321 .def("buildChamber", &MockupSectorBuilder::buildChamber)
0322 .def("buildSector", &MockupSectorBuilder::buildSector)
0323 .def("drawSector", &MockupSectorBuilder::drawSector);
0324
0325 auto c = py::class_<Config>(ms, "Config").def(py::init<>());
0326 ACTS_PYTHON_STRUCT(c, gdmlPath, NumberOfSectors, toleranceOverlap);
0327
0328 auto cch = py::class_<ChamberConfig>(ms, "ChamberConfig").def(py::init<>());
0329 ACTS_PYTHON_STRUCT(cch, name, SensitiveNames, PassiveNames);
0330 }
0331
0332 {
0333 using Tool = Geant4::RegionCreator;
0334 using Config = Tool::Config;
0335 auto tool = py::class_<Tool>(mod, "RegionCreator")
0336 .def(py::init<const Config&>(), py::arg("config"))
0337 .def_property_readonly("config", &Tool::config);
0338
0339 auto c = py::class_<Config>(tool, "Config").def(py::init<>());
0340 ACTS_PYTHON_STRUCT(c, gammaCut, electronCut, positronCut, protonCut,
0341 volumes);
0342 }
0343
0344 Context ctx;
0345 ctx.modules["geant4"] = mod;
0346 }