Back to home page

EIC code displayed by LXR

 
 

    


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 // 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/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   /// Find the sensitive surfaces for a given position
0055   std::vector<const Surface*> queryPosition(
0056       const GeometryContext& gctx, const Vector3& position) const override {
0057     std::vector<const Surface*> surfaces;
0058     // Here's the detector volume
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              // Set a new surface finder
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              // Helper struct to find the sensitive surface candidates
0146 
0147              // Set a new surface finder
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     /// Helper function to test if the automatic geometry conversion works
0229     ///
0230     /// @param gdmlFileName is the name of the GDML file
0231     /// @param sensitiveMatches is a list of strings to match sensitive volumes
0232     /// @param passiveMatches is a list of strings to match passive volumes
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           // Initiate the detector construction & retrieve world
0239           ActsExamples::GdmlDetectorConstruction gdmlContruction(gdmlFileName,
0240                                                                  {});
0241           const auto* world = gdmlContruction.Construct();
0242 
0243           // Create the selectors
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           // Capture the sensitive elements and the surfaces
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           // Capture the passive surfaces
0276           Surfaces passiveSurfaces;
0277           passiveSurfaces.reserve(cache.passiveSurfaces.size());
0278           for (const auto& passive : cache.passiveSurfaces) {
0279             passiveSurfaces.push_back(passive);
0280           }
0281 
0282           // Return a convenient tuple for drawing
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 }