9 #include <simulation/modules/fullsim/FullSimModule.h>
10 #include <simulation/kernel/RunManager.h>
11 #include <simulation/kernel/DetectorConstruction.h>
13 #include <simulation/physicslist/Belle2PhysicsList.h>
14 #include <simulation/kernel/ExtPhysicsConstructor.h>
15 #include <simulation/kernel/MagneticField.h>
16 #include <simulation/kernel/PrimaryGeneratorAction.h>
17 #include <simulation/kernel/EventAction.h>
18 #include <simulation/kernel/TrackingAction.h>
19 #include <simulation/kernel/SteppingAction.h>
20 #include <simulation/kernel/StackingAction.h>
22 #include <mdst/dataobjects/MCParticle.h>
23 #include <framework/datastore/StoreObjPtr.h>
24 #include <framework/datastore/StoreArray.h>
25 #include <framework/dataobjects/EventMetaData.h>
26 #include <framework/gearbox/Unit.h>
28 #include <CLHEP/Units/SystemOfUnits.h>
30 #include <simulation/monopoles/G4MonopolePhysics.h>
31 #include <simulation/longlivedneutral/G4LongLivedNeutralPhysics.h>
33 #include <G4TransportationManager.hh>
34 #include <G4Transportation.hh>
35 #include <G4PhysListFactory.hh>
36 #include <G4ProcessVector.hh>
37 #include <G4OpticalPhysics.hh>
38 #include <G4ParticleDefinition.hh>
39 #include <G4ParticleTable.hh>
40 #include <G4EventManager.hh>
41 #include <G4RunManager.hh>
42 #include <G4UImanager.hh>
43 #include <G4VisExecutive.hh>
44 #include <G4StepLimiter.hh>
45 #include <G4EmParameters.hh>
46 #include <G4HadronicProcessStore.hh>
47 #include <G4InuclParticleNames.hh>
49 #include <G4Mag_UsualEqRhs.hh>
50 #include <G4NystromRK4.hh>
51 #include <G4HelixExplicitEuler.hh>
52 #include <G4HelixSimpleRunge.hh>
53 #include <G4CachedMagneticField.hh>
57 using namespace Belle2::Simulation;
58 using namespace Belle2::Monopoles;
59 using namespace G4InuclParticleNames;
73 setDescription(
"Performs the full Geant4 detector simulation. Requires a valid geometry in memory.");
74 setPropertyFlags(c_ParallelProcessingCertified | c_TerminateInAllProcesses);
77 addParam(
"InputMCParticleCollection", m_mcParticleInputColName,
"The name of the input MCParticle collection.",
string(
""));
78 addParam(
"ThresholdImportantEnergy", m_thresholdImportantEnergy,
79 "[GeV] A particle which got 'stuck' and has less than this energy will be killed after 'ThresholdTrials' trials.", 0.250);
80 addParam(
"ThresholdTrials", m_thresholdTrials,
81 "Geant4 will try 'ThresholdTrials' times to move a particle which got 'stuck' and has an energy less than 'ThresholdImportantEnergy'.",
83 addParam(
"RunEventVerbosity", m_runEventVerbosity,
"Geant4 run/event verbosity: 0=silent; 1=info level; 2=debug level", 0);
84 addParam(
"TrackingVerbosity", m_trackingVerbosity,
85 "Tracking verbosity: 0=Silent; 1=Min info per step; 2=sec particles; 3=pre/post step info; 4=like 3 but more info; 5=proposed step length info.",
87 addParam(
"HadronProcessVerbosity", m_hadronProcessVerbosity,
"Hadron Process verbosity: 0=Silent; 1=info level; 2=debug level", 0);
88 addParam(
"EmProcessVerbosity", m_emProcessVerbosity,
"Em Process verbosity: 0=Silent; 1=info level; 2=debug level", 0);
89 addParam(
"PhysicsList", m_physicsList,
"The name of the physics list which is used for the simulation.",
string(
"Belle2"));
90 addParam(
"StandardEM", m_standardEM,
"If true, replaces fast EM physics with standard EM physics.",
false);
91 addParam(
"RegisterOptics", m_optics,
"If true, G4OpticalPhysics is registered in Geant4 PhysicsList.",
true);
92 addParam(
"UseHighPrecisionNeutrons", m_HPneutrons,
"If true, high precision neutron models used below 20 MeV.",
false);
93 addParam(
"RegisterMonopoles", m_monopoles,
"If set to true, G4MonopolePhysics is registered in Geant4 PhysicsList.",
false);
94 addParam(
"MonopoleMagCharge", m_monopoleMagneticCharge,
"The value of monopole magnetic charge in units of e+.", 1.0);
95 addParam(
"ProductionCut", m_productionCut,
96 "[cm] Apply continuous energy loss to primary particle which has no longer enough energy to produce secondaries which travel at least the specified productionCut distance.",
98 addParam(
"PXDProductionCut", m_pxdProductionCut,
"[cm] Secondary production threshold in PXD envelope.", 0.0);
99 addParam(
"SVDProductionCut", m_svdProductionCut,
"[cm] Secondary production threshold in SVD envelope.", 0.0);
100 addParam(
"CDCProductionCut", m_cdcProductionCut,
"[cm] Secondary production threshold in CDC envelope.", 0.0);
101 addParam(
"ARICHTOPProductionCut", m_arichtopProductionCut,
"[cm] Secondary production threshold in ARICH and TOP envelopes.", 0.0);
102 addParam(
"ECLProductionCut", m_eclProductionCut,
"[cm] Secondary production threshold in ECL envelope.", 0.0);
103 addParam(
"KLMProductionCut", m_klmProductionCut,
"[cm] Secondary production threshold in BKLM and EKLM envelopes.", 0.0);
104 addParam(
"MaxNumberSteps", m_maxNumberSteps,
105 "The maximum number of steps before the track transportation is stopped and the track is killed.", 100000);
106 addParam(
"PhotonFraction", m_photonFraction,
"The fraction of Cerenkov photons which will be kept and propagated.", 0.5);
107 addParam(
"EnableVisualization", m_EnableVisualization,
"If set to True, the Geant4 visualization support is enabled.",
false);
109 addParam(
"StoreOpticalPhotons", m_storeOpticalPhotons,
"If set to True, optical photons are stored in MCParticles.",
false);
110 addParam(
"StoreAllSecondaries", m_storeSecondaries,
111 "If set to True, all secondaries produced by Geant4 over a kinetic energy cut are stored in MCParticles. Otherwise do not store them.",
113 addParam(
"SecondariesEnergyCut", m_secondariesEnergyCut,
"[MeV] Kinetic energy cut for storing secondaries", 1.0);
114 addParam(
"StoreBremsstrahlungPhotons", m_storeBremsstrahlungPhotons,
115 "If set to True, store BremsstrahlungPhotons over a kinetic energy cut in MCParticles. Otherwise do not store them.",
false);
116 addParam(
"BremsstrahlungPhotonsEnergyCut", m_bremsstrahlungPhotonsEnergyCut,
117 "[MeV] Kinetic energy cut for storing bremsstrahlung photons", 10.0);
118 addParam(
"StorePairConversions", m_storePairConversions,
119 "If set to True, store e+ or e- from pair conversions over a kinetic energy cut in MCParticles. Otherwise do not store them.",
121 addParam(
"PairConversionsEnergyCut", m_pairConversionsEnergyCut,
122 "[MeV] Kinetic energy cut for storing e+ or e- from pair conversions", 10.0);
124 addParam(
"magneticField", m_magneticFieldName,
125 "Chooses the magnetic field stepper used by Geant4. Possible values are: default, nystrom, expliciteuler, simplerunge",
127 addParam(
"magneticCacheDistance", m_magneticCacheDistance,
128 "Minimum distance for BField lookup in cm. If the next requested point is closer than this distance than return the flast BField value. 0 means no caching",
130 addParam(
"deltaChordInMagneticField", m_deltaChordInMagneticField,
131 "[mm] The maximum miss-distance between the trajectory curve and its linear cord(s) approximation", 0.25);
132 vector<string> defaultCommandsAtPreInit;
133 addParam(
"UICommandsAtPreInit", m_uiCommandsAtPreInit,
134 "A list of Geant4 UI commands that should be applied at PreInit state, before the simulation starts.",
135 defaultCommandsAtPreInit);
136 vector<string> defaultCommandsAtIdle;
137 addParam(
"UICommandsAtIdle", m_uiCommandsAtIdle,
138 "A list of Geant4 UI commands that should be applied at Idle state, before the simulation starts.",
139 defaultCommandsAtIdle);
140 addParam(
"trajectoryStore", m_trajectoryStore,
141 "If non-zero save the full trajectory of 1=primary, 2=non-optical or 3=all particles", 0);
142 addParam(
"trajectoryDistanceTolerance", m_trajectoryDistanceTolerance,
143 "Maximum deviation from the real trajectory points when merging "
144 "segments (in cm)", 5e-4);
145 vector<float> defaultAbsorbers;
146 addParam(
"AbsorbersRadii", m_absorbers,
147 "Radii (in cm) of absorbers across which tracks will be destroyed.", defaultAbsorbers);
150 RunManager::Instance();
151 m_magneticField = NULL;
152 m_uncachedField = NULL;
153 m_magFldEquation = NULL;
155 m_chordFinder = NULL;
157 m_stepLimiter = NULL;
161 FullSimModule::~FullSimModule()
167 void FullSimModule::initialize()
174 if (m_mcParticleInputColName.empty()) {
188 RunManager& runManager = RunManager::Instance();
199 if (m_physicsList ==
"Belle2") {
216 if (m_uiCommandsAtPreInit.size() > 0) {
217 G4UImanager* uiManager = G4UImanager::GetUIpointer();
218 for (vector<string>::iterator iter = m_uiCommandsAtPreInit.begin(); iter != m_uiCommandsAtPreInit.end(); ++iter) {
219 uiManager->ApplyCommand(*iter);
223 runManager.SetUserInitialization(physicsList);
226 G4PhysListFactory physListFactory;
227 physListFactory.SetVerbose(m_runEventVerbosity);
228 G4VModularPhysicsList* physicsList = NULL;
229 if (physListFactory.IsReferencePhysList(m_physicsList)) physicsList = physListFactory.GetReferencePhysList(m_physicsList);
230 if (physicsList == NULL) B2FATAL(
"Could not load the physics list " << m_physicsList);
232 if (m_optics) physicsList->RegisterPhysics(
new G4OpticalPhysics);
239 physicsList->SetDefaultCutValue((m_productionCut / Unit::mm) * CLHEP::mm);
242 if (m_uiCommandsAtPreInit.size() > 0) {
243 G4UImanager* uiManager = G4UImanager::GetUIpointer();
244 for (vector<string>::iterator iter = m_uiCommandsAtPreInit.begin(); iter != m_uiCommandsAtPreInit.end(); ++iter) {
245 uiManager->ApplyCommand(*iter);
251 G4ParticleTable::G4PTblDicIterator* myParticleIterator = G4ParticleTable::GetParticleTable()->GetIterator();
252 myParticleIterator->reset();
253 while ((*myParticleIterator)()) {
254 G4ParticleDefinition* particle = myParticleIterator->value();
255 if (particle->GetParticleName().compare(0, 4,
"g4e_") == 0) {
256 physicsList->SetParticleCuts(1.0E+9 * CLHEP::cm, particle);
259 runManager.SetUserInitialization(physicsList);
263 if (m_magneticFieldName !=
"none") {
265 if (m_magneticCacheDistance > 0) {
266 m_uncachedField = m_magneticField;
267 m_magneticField =
new G4CachedMagneticField(m_uncachedField, m_magneticCacheDistance);
269 G4FieldManager* fieldManager = G4TransportationManager::GetTransportationManager()->GetFieldManager();
270 fieldManager->SetDetectorField(m_magneticField);
271 if (m_magneticFieldName !=
"default") {
274 m_magFldEquation =
new G4Mag_UsualEqRhs(m_magneticField);
275 if (m_magneticFieldName ==
"nystrom") {
276 m_stepper =
new G4NystromRK4(m_magFldEquation);
277 }
else if (m_magneticFieldName ==
"expliciteuler") {
278 m_stepper =
new G4HelixExplicitEuler(m_magFldEquation);
279 }
else if (m_magneticFieldName ==
"simplerunge") {
280 m_stepper =
new G4HelixSimpleRunge(m_magFldEquation);
282 B2FATAL(
"Unknown magnetic field option: " << m_magneticFieldName);
287 m_chordFinder =
new G4ChordFinder(m_magneticField, 1e-2 * CLHEP::mm, m_stepper);
288 fieldManager->SetChordFinder(m_chordFinder);
290 fieldManager->CreateChordFinder(m_magneticField);
294 G4ChordFinder* chordFinder = fieldManager->GetChordFinder();
295 B2DEBUG(1,
"Geant4 default deltaChord = " << chordFinder->GetDeltaChord());
296 chordFinder->SetDeltaChord(m_deltaChordInMagneticField * CLHEP::mm);
297 B2DEBUG(1,
"DeltaChord after reset = " << chordFinder->GetDeltaChord());
303 G4VUserPrimaryGeneratorAction* generatorAction =
new PrimaryGeneratorAction(m_mcParticleInputColName, m_mcParticleGraph);
304 runManager.SetUserAction(generatorAction);
309 runManager.SetUserAction(eventAction);
321 runManager.SetUserAction(trackingAction);
327 for (
auto& rAbsorber : m_absorbers) {
328 B2INFO(
"An absorber found at R = " << rAbsorber <<
" cm");
330 runManager.SetUserAction(steppingAction);
335 runManager.SetUserAction(stackingAction);
344 m_stepLimiter =
new G4StepLimiter();
345 G4ParticleTable::G4PTblDicIterator* partIter = G4ParticleTable::GetParticleTable()->GetIterator();
347 while ((*partIter)()) {
348 G4ParticleDefinition* currParticle = partIter->value();
349 G4ProcessVector& currProcList = *currParticle->GetProcessManager()->GetProcessList();
350 assert(currProcList.size() < INT_MAX);
351 for (
int iProcess = 0; iProcess < static_cast<int>(currProcList.size()); ++iProcess) {
352 G4Transportation* transport =
dynamic_cast<G4Transportation*
>(currProcList[iProcess]);
353 if (transport !=
nullptr) {
355 transport->SetThresholdImportantEnergy(m_thresholdImportantEnergy / Unit::MeV * CLHEP::MeV);
356 transport->SetThresholdTrials(m_thresholdTrials);
361 double zeroChargeTol = 0.01 * Unit::e;
362 if (fabs(currParticle->GetPDGCharge()) > zeroChargeTol) {
363 currParticle->GetProcessManager()->AddDiscreteProcess(m_stepLimiter);
364 B2DEBUG(100,
"Added StepLimiter process for " << currParticle->GetParticleName());
372 while ((*partIter)()) {
373 G4ParticleDefinition* currParticle = partIter->value();
374 if (currParticle->GetParticleName().compare(0, 4,
"g4e_") == 0) {
375 G4ProcessManager* processManager = currParticle->GetProcessManager();
376 if (processManager) {
377 G4ProcessVector* processList = processManager->GetProcessList();
378 assert(processList->size() < INT_MAX);
379 for (
int i = 0; i < static_cast<int>(processList->size()); ++i) {
380 if (((*processList)[i]->GetProcessName() ==
"Cerenkov") ||
381 ((*processList)[i]->GetProcessName() ==
"Scintillation") ||
382 ((*processList)[i]->GetProcessName() ==
"hFritiofCaptureAtRest")) {
383 processManager->SetProcessActivation(i,
false);
401 G4EventManager::GetEventManager()->SetVerboseLevel(m_runEventVerbosity);
402 G4RunManager::GetRunManager()->SetVerboseLevel(m_runEventVerbosity);
403 G4EventManager::GetEventManager()->GetTrackingManager()->SetVerboseLevel(
404 m_trackingVerbosity);
405 G4HadronicProcessStore::Instance()->SetVerbose(m_hadronProcessVerbosity);
406 G4EmParameters::Instance()->SetVerbose(m_emProcessVerbosity);
409 if (m_EnableVisualization) {
410 m_visManager =
new G4VisExecutive;
411 m_visManager->Initialize();
415 if (m_uiCommandsAtIdle.size() > 0) {
416 G4UImanager* uiManager = G4UImanager::GetUIpointer();
417 for (vector<string>::iterator iter = m_uiCommandsAtIdle.begin(); iter != m_uiCommandsAtIdle.end(); ++iter) {
418 uiManager->ApplyCommand(*iter);
423 if (m_trajectoryStore) {
432 B2INFO(
"Perform Geant4 final initialization: Geometry optimization, PhysicsList calculations...");
433 RunManager::Instance().beginRun(0);
434 B2INFO(
"done, Geant4 ready");
441 void FullSimModule::beginRun()
447 void FullSimModule::event()
453 RunManager::Instance().processEvent(eventMetaDataPtr->getEvent());
457 void FullSimModule::endRun()
462 void FullSimModule::terminate()
465 RunManager::Instance().endRun();
467 if (m_visManager !=
nullptr)
delete m_visManager;
468 RunManager::Instance().destroy();
470 delete m_stepLimiter;
472 if (m_chordFinder)
delete m_chordFinder;
473 if (m_stepper)
delete m_stepper;
474 if (m_magFldEquation)
delete m_magFldEquation;
475 if (m_uncachedField)
delete m_uncachedField;
476 if (m_magneticField)
delete m_magneticField;
Class responsible to connect to geometry to simulation.
The full Geant4 simulation module.
LongLivedNeutral physics Class – to be registered in the physics list.
Monopole physics class to register on the physics list.
Custom Geant4 physics list for Belle II with options to add optical physics, standard EM physics and ...
void SetSVDProductionCutValue(G4double)
Set cut value for SVD envelope.
void SetProductionCutValue(G4double)
Use parameter to set global cut value.
void SetARICHTOPProductionCutValue(G4double)
Set cut value for ARICH and TOP envelopes.
void SetECLProductionCutValue(G4double)
Set cut value for ECL barrel, forward and backward envelopes.
void UseHighPrecisionNeutrons(G4bool)
Use high precision neutron models below 20 MeV.
void SetPXDProductionCutValue(G4double)
Set cut value for PXD envelope.
void UseLongLivedNeutralParticles()
Simulate neutral long-lived particles with given pdg and mass value.
void UseOpticalPhysics(G4bool)
Add optical photon physics.
void SetVerbosity(G4int verb)
Run/event verbosity level.
void SetCDCProductionCutValue(G4double)
Set cut value for CDC envelope.
void SetKLMProductionCutValue(G4double)
Set cut value for BKLM and EKLM envelopes.
void UseStandardEMPhysics(G4bool)
Use standard EM physics instead of EM option1.
Define geant4e-specific physics.
The Class for the Belle2 magnetic field implementation for Geant4.
The PrimaryGeneratorAction class inherits from G4VuserPrimaryGeneratorAction and specifies how a prim...
The run manager controls the flow of the Geant4 program and manages the event loop(s) within a run.
void Initialize()
Initialize the Kernel.
The basf2 stacking action.
void setPropagatedPhotonFraction(double fraction)
Set fraction of Cerenkov photons that are actually propagated.
The Class for the stepping action.
void setAbsorbersR(const std::vector< float > &vec)
Sets the radii of absorbers for killing tracks across them.
void setStoreTrajectories(bool store)
Sets the trajectory option to enable storing of the simulated particle trajectories.
void setMaxNumberSteps(int maxSteps)
Sets the maximum number of steps before a track is stopped and killed.
The Tracking Action class.
void setIgnorePairConversions(bool ignore=true)
Set ignore flag for e+ or e- coming from gamma conversions into a pair if set to true,...
void setIgnoreBremsstrahlungPhotons(bool ignore=true)
Set ignore flag for low energy breamsstrahlung photons if set to true, breamsstrahlung photons with k...
void setSecondariesEnergyCut(double cut_MeV)
Set kinetic energy cut for secondaries.
void setStoreTrajectories(int store, double distanceTolerance)
Sets the trajectory option to enable storing of the simulated particle trajectories.
void setBremsstrahlungPhotonsEnergyCut(double cut_MeV)
Set kinetic energy cut for bremsstrahlung photons.
void setPairConversionsEnergyCut(double cut_MeV)
Set kinetic energy cut for e+ e- pair conversions.
void setIgnoreSecondaries(bool ignore=true)
Set ignore flag for low energy Geant-produced secondary particles if set to true, secondaries with ki...
void setIgnoreOpticalPhotons(bool ignore=true)
Set ignore flag for optical photons if set to true, optical photons will not be stored in MCParticles...
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
Type-safe access to single objects in the data store.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Abstract base class for different kinds of events.