Skip to content

Commit

Permalink
feat: Allow configurable particle selection and reproducible seeds fo…
Browse files Browse the repository at this point in the history
…r Geant4 (#1428)

This PR does two improvements to the geant4 examples integration:

- Make particle selection configurable for `addGeant4` as for `addFatras`
- Allow reproducible seeds for the geant4 algorithm (set the seed for each event from an `ActsExamples::RandomNumbers` object)

I did the change for the examples binaries not in the most beautiful way (so they do compile, but not changed the command line options or so), since they are deprecated anyways...
  • Loading branch information
benjaminhuth committed Sep 19, 2022
1 parent 4a41d30 commit 9e22341
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Acts/Utilities/Logger.hpp"
#include "ActsExamples/Framework/BareAlgorithm.hpp"
#include "ActsExamples/Framework/ProcessCode.hpp"
#include "ActsExamples/Framework/RandomNumbers.hpp"

#include <memory>
#include <mutex>
Expand Down Expand Up @@ -60,8 +61,8 @@ class Geant4Simulation final : public BareAlgorithm {
// Name of the output collection: material tracks
std::string outputMaterialTracks = "";

// The Geant4 seed being used
std::size_t seed = 123;
/// Random number service.
std::shared_ptr<const RandomNumbers> randomNumbers;

/// The G4 run manager
std::shared_ptr<G4RunManager> runManager;
Expand Down
8 changes: 6 additions & 2 deletions Examples/Algorithms/Geant4/src/Geant4Simulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ ActsExamples::Geant4Simulation::Geant4Simulation(
if (!m_cfg.runManager) {
throw std::invalid_argument("Missing G4 RunManager object");
}
if (!m_cfg.randomNumbers) {
throw std::invalid_argument("Missing random numbers tool");
}

if (m_cfg.sensitiveSurfaceMapper) {
if (m_cfg.outputSimHits.empty()) {
Expand All @@ -70,8 +73,6 @@ ActsExamples::Geant4Simulation::Geant4Simulation(
}
}

G4Random::setTheSeed(m_cfg.seed);

// Set the detector construction
m_cfg.runManager->SetUserInitialization(m_cfg.detectorConstruction);

Expand Down Expand Up @@ -126,6 +127,9 @@ ActsExamples::ProcessCode ActsExamples::Geant4Simulation::execute(
// Ensure exclusive access to the Geant4 run manager
std::lock_guard<std::mutex> guard(m_runManagerLock);

// Set the seed new per event, so that we get reproducible results
G4Random::setTheSeed(m_cfg.randomNumbers->generateSeed(ctx));

// Get and reset event registry state
auto& eventData = EventStoreRegistry::eventData();
eventData = EventStoreRegistry::State{};
Expand Down
105 changes: 70 additions & 35 deletions Examples/Python/python/acts/examples/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,56 @@ def addPythia8(
return s


def addParticleSelection(
s: acts.examples.Sequencer,
preselectParticles: ParticleSelectorConfig,
inputParticles="particles_input",
outputParticles="particles_selected",
logLevel: Optional[acts.logging.Level] = None,
) -> None:
"""
This function steers the particle selection.
Parameters
----------
s: Sequencer
the sequencer module to which we add the ParticleSelector
preselectedParticles: ParticleSelectorConfig
the particle selection configuration
inputParticles: str
the identifier for the input particles to be selected
outputParticles: str
the identifier for the final selected particle collection
"""
customLogLevel = acts.examples.defaultLogging(s, logLevel)

s.addAlgorithm(
acts.examples.ParticleSelector(
**acts.examples.defaultKWArgs(
rhoMin=preselectParticles.rho[0],
rhoMax=preselectParticles.rho[1],
absZMin=preselectParticles.absZ[0],
absZMax=preselectParticles.absZ[1],
timeMin=preselectParticles.time[0],
timeMax=preselectParticles.time[1],
phiMin=preselectParticles.phi[0],
phiMax=preselectParticles.phi[1],
etaMin=preselectParticles.eta[0],
etaMax=preselectParticles.eta[1],
absEtaMin=preselectParticles.absEta[0],
absEtaMax=preselectParticles.absEta[1],
ptMin=preselectParticles.pt[0],
ptMax=preselectParticles.pt[1],
removeCharged=preselectParticles.removeCharged,
removeNeutral=preselectParticles.removeNeutral,
),
level=customLogLevel(),
inputParticles=inputParticles,
outputParticles=outputParticles,
)
)


@acts.examples.NamedTypeArgs(
preselectParticles=ParticleSelectorConfig,
)
Expand Down Expand Up @@ -343,30 +393,11 @@ def addFatras(
# Selector
if preselectParticles is not None:
particles_selected = "particles_selected"
s.addAlgorithm(
acts.examples.ParticleSelector(
**acts.examples.defaultKWArgs(
rhoMin=preselectParticles.rho[0],
rhoMax=preselectParticles.rho[1],
absZMin=preselectParticles.absZ[0],
absZMax=preselectParticles.absZ[1],
timeMin=preselectParticles.time[0],
timeMax=preselectParticles.time[1],
phiMin=preselectParticles.phi[0],
phiMax=preselectParticles.phi[1],
etaMin=preselectParticles.eta[0],
etaMax=preselectParticles.eta[1],
absEtaMin=preselectParticles.absEta[0],
absEtaMax=preselectParticles.absEta[1],
ptMin=preselectParticles.pt[0],
ptMax=preselectParticles.pt[1],
removeCharged=preselectParticles.removeCharged,
removeNeutral=preselectParticles.removeNeutral,
),
level=customLogLevel(),
inputParticles="particles_input",
outputParticles=particles_selected,
)
addParticleSelection(
s,
preselectParticles,
inputParticles="particles_input",
outputParticles=particles_selected,
)
else:
particles_selected = "particles_input"
Expand Down Expand Up @@ -480,10 +511,11 @@ def addGeant4(
geometryService: Any, # acts.examples.dd4hep.DD4hepGeometryService
trackingGeometry: acts.TrackingGeometry,
field: acts.MagneticFieldProvider,
rnd: acts.examples.RandomNumbers,
outputDirCsv: Optional[Union[Path, str]] = None,
outputDirRoot: Optional[Union[Path, str]] = None,
seed: Optional[int] = None,
preselectParticles: bool = True,
preselectParticles: Optional[ParticleSelectorConfig] = ParticleSelectorConfig(),
logLevel: Optional[acts.logging.Level] = None,
) -> None:
"""This function steers the detector simulation using Geant4
Expand All @@ -494,12 +526,16 @@ def addGeant4(
the sequencer module to which we add the Geant4 steps (returned from addGeant4)
trackingGeometry : tracking geometry
field : magnetic field
rnd : RandomNumbers, None
random number generator
outputDirCsv : Path|str, path, None
the output folder for the Csv output, None triggers no output
outputDirRoot : Path|str, path, None
the output folder for the Root output, None triggers no output
seed : int, None
random number generator seed
preselectParticles : ParticleSelectorConfig(rho, absZ, time, phi, eta, absEta, pt, removeCharged, removeNeutral), None
ParticleSelector configuration to select particles as input to Fatras. Each range is specified as a tuple of (min,max).
Default of no selections specified in Examples/Algorithms/TruthTracking/ActsExamples/TruthTracking/ParticleSelector.hpp
Specify preselectParticles=None to inhibit ParticleSelector altogether.
"""

from acts.examples.geant4 import Geant4Simulation, geant4SimulationConfig
Expand All @@ -508,14 +544,13 @@ def addGeant4(
customLogLevel = acts.examples.defaultLogging(s, logLevel)

# Selector
if preselectParticles:
if preselectParticles is not None:
particles_selected = "particles_selected"
s.addAlgorithm(
acts.examples.ParticleSelector(
level=customLogLevel(),
inputParticles="particles_input",
outputParticles=particles_selected,
)
addParticleSelection(
s,
preselectParticles,
inputParticles="particles_input",
outputParticles=particles_selected,
)
else:
particles_selected = "particles_input"
Expand All @@ -531,7 +566,7 @@ def addGeant4(
g4conf.outputSimHits = "simhits"
g4conf.outputParticlesInitial = "particles_initial"
g4conf.outputParticlesFinal = "particles_final"
g4conf.seed = seed
g4conf.randomNumbers = rnd

# Simulation
alg = Geant4Simulation(
Expand Down
7 changes: 5 additions & 2 deletions Examples/Python/src/Geant4Component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ PYBIND11_MODULE(ActsPythonBindingsGeant4, mod) {
ACTS_PYTHON_MEMBER(outputParticlesInitial);
ACTS_PYTHON_MEMBER(outputParticlesFinal);
ACTS_PYTHON_MEMBER(outputMaterialTracks);
ACTS_PYTHON_MEMBER(seed);
ACTS_PYTHON_MEMBER(randomNumbers);
ACTS_PYTHON_MEMBER(runManager);
ACTS_PYTHON_MEMBER(primaryGeneratorAction);
ACTS_PYTHON_MEMBER(runActions);
Expand All @@ -96,6 +96,7 @@ PYBIND11_MODULE(ActsPythonBindingsGeant4, mod) {
mod.def(
"materialRecordingConfig",
[](Acts::Logging::Level level, G4VUserDetectorConstruction* detector,
std::shared_ptr<const ActsExamples::RandomNumbers> randomNumbers,
const std::string& inputParticles,
const std::string& outputMaterialTracks) {
// The Geant4 actions needed
Expand All @@ -106,6 +107,7 @@ PYBIND11_MODULE(ActsPythonBindingsGeant4, mod) {
// Set the main Geant4 algorithm, primary generation, detector
// construction
Geant4Simulation::Config g4Cfg;
g4Cfg.randomNumbers = randomNumbers;
g4Cfg.runManager = std::make_shared<G4RunManager>();
g4Cfg.runManager->SetUserInitialization(new MaterialPhysicsList(
Acts::getDefaultLogger("MaterialPhysicsList", level)));
Expand Down Expand Up @@ -139,7 +141,8 @@ PYBIND11_MODULE(ActsPythonBindingsGeant4, mod) {

return g4Cfg;
},
"level"_a, "detector"_a, "inputParticles"_a, "outputMaterialTracks"_a);
"level"_a, "detector"_a, "randomNumbers"_a, "inputParticles"_a,
"outputMaterialTracks"_a);

mod.def(
"geant4SimulationConfig",
Expand Down
6 changes: 3 additions & 3 deletions Examples/Python/tests/root_file_hashes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ test_ckf_tracks_example[odd-truth_smeared]__tracksummary_ckf.root: 2350fe7e204e3
test_fatras__fatras_particles_final.root: 09b0d46ad7641fc5af97650cdcbf0e6c85966933a2e1b2bfcf7fbb9c6d90b2e1
test_fatras__fatras_particles_initial.root: 712a41d95ed1fccafccf708afddcd2177793934bb80cd40b1d99b532c7a21031
test_fatras__hits.root: 8d665a7fa47f2ae43c4c1393cdcd4a8a140ef37f9288d4b3a354259449607cbc
test_geant4__fatras_particles_final.root: 3d2def96c54107df7c7c6367d237ee14365a07e66d6742ad8d3424b59694b9a4
test_geant4__fatras_particles_initial.root: 9d40e9efd435ee6b07128e04172d48f3525c6e622efbbd6aac6ab3660648c159
test_geant4__hits.root: 1b01f6f7705cb33f46345fb508eb2a3af97e8a57c58fc44e47263a1f2c15815a
test_geant4__fatras_particles_final.root: 1d27428abe9c297d4adcd0e6d38ed58e2b630545e38489086c012e5a0dfe3535
test_geant4__fatras_particles_initial.root: 005484db8e3213d98d6e9ce1457181c926814309f63460e39a8bd360eae1b23d
test_geant4__hits.root: 7a7483989763a1634122c1e8ea8f4ede26de6e5650564379ad6da58d3e56a6c6
test_seeding__estimatedparams.root: 6e05c1d7452b1c7dd59c2244145c0c551e7a87c7caba5df73aa4d492593bb09e
test_seeding__performance_seeding_trees.root: c900a70a9881ce637a73ff730de4b2f4b6c0446854d666f70c7fc9c44c893666
test_seeding__particles.root: 4943f152bfad6ca6302563b57e495599fad4fea43b8e0b41abe5b8de31b391bc
Expand Down
4 changes: 3 additions & 1 deletion Examples/Run/Geant4/Common/Geant4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "Acts/Geometry/TrackingGeometry.hpp"
#include "Acts/MagneticField/MagneticFieldProvider.hpp"
#include "ActsExamples/Detector/IBaseDetector.hpp"
#include "ActsExamples/Framework/RandomNumbers.hpp"
#include "ActsExamples/Framework/Sequencer.hpp"
#include "ActsExamples/Geant4/EventStoreRegistry.hpp"
#include "ActsExamples/Geant4/Geant4Simulation.hpp"
Expand Down Expand Up @@ -66,7 +67,8 @@ void setupGeant4Simulation(
Geant4Simulation::Config g4Cfg;

g4Cfg.runManager = runManager;
g4Cfg.seed = seed;
g4Cfg.randomNumbers = std::make_shared<ActsExamples::RandomNumbers>(
ActsExamples::RandomNumbers::Config{seed});

// Read the particle from the generator
SimParticleTranslation::Config g4PrCfg;
Expand Down
3 changes: 1 addition & 2 deletions Examples/Scripts/Python/geant4.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ def runGeant4(
s = s or acts.examples.Sequencer(events=100, numThreads=1)
s.config.logLevel = acts.logging.INFO
rnd = acts.examples.RandomNumbers()
seed = 42
addParticleGun(
s,
EtaConfig(-2.0, 2.0),
Expand All @@ -34,7 +33,7 @@ def runGeant4(
field,
outputDirCsv=outputDir / "csv",
outputDirRoot=outputDir,
seed=seed,
rnd=rnd,
)
return s

Expand Down
1 change: 1 addition & 0 deletions Examples/Scripts/Python/material_recording.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def runMaterialRecording(g4geo, outputDir, tracksPerEvent=10000, s=None):
detector=g4geo,
inputParticles=evGen.config.outputParticles,
outputMaterialTracks="material_tracks",
randomNumbers=rnd,
)

g4AlgCfg.detectorConstruction = g4geo
Expand Down

0 comments on commit 9e22341

Please sign in to comment.