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