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