Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:12:02

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/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   /// Find the sensitive surfaces for a given position
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     // Here's the detector volume
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              // Set a new surface finder
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              // Helper struct to find the sensitive surface candidates
0161 
0162              // Set a new surface finder
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     /// Helper function to test if the automatic geometry conversion works
0290     ///
0291     /// @param gdmlFileName is the name of the GDML file
0292     /// @param sensitiveMatches is a list of strings to match sensitive volumes
0293     /// @param passiveMatches is a list of strings to match passive volumes
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       // Initiate the detector construction & retrieve world
0301       ActsExamples::GdmlDetectorConstruction gdmlContruction(gdmlFileName, {});
0302       const auto* world = gdmlContruction.Construct();
0303 
0304       // Create the selectors
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       // Capture the sensitive elements and the surfaces
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       // Capture the passive surfaces
0337       Surfaces passiveSurfaces;
0338       passiveSurfaces.reserve(cache.passiveSurfaces.size());
0339       for (const auto& passive : cache.passiveSurfaces) {
0340         passiveSurfaces.push_back(passive);
0341       }
0342 
0343       // Return a convenient tuple for drawing
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 }