18 #include <G4HadronElasticProcess.hh>
24 #include "G4Material.hh"
25 #include "G4RunManager.hh"
26 #include "G4ParticleGun.hh"
28 #include "G4LogicalVolume.hh"
29 #include "G4PVPlacement.hh"
30 #include "QGSP_BERT.hh"
31 #include "QGSP_BIC.hh"
32 #include "FTFP_BERT.hh"
33 #include "G4UImanager.hh"
34 #include "G4NistManager.hh"
35 #include "G4VEnergyLossProcess.hh"
36 #include <G4MaterialCutsCouple.hh>
37 #include <G4HadronInelasticProcess.hh>
40 #include "G4CrossSectionDataStore.hh"
41 #include "G4Element.hh"
42 #include "G4ElementVector.hh"
43 #include "G4IsotopeVector.hh"
44 #include "G4Neutron.hh"
45 #include "G4ProductionCutsTable.hh"
52 #include "CLHEP/Units/SystemOfUnits.h"
55 #include "CLHEP/Random/RandExponential.h"
56 #include "CLHEP/Random/RandFlat.h"
63 const double s_projectionFactor = sqrt(2.);
69 m_rndGenSvc(
"AtDSFMTGenSvc",
n),
70 m_g4RunManagerHelper(
"iGeant4::G4RunManagerHelper/G4RunManagerHelper"),
72 m_hadIntProbScale(1.0),
74 m_particleBroker(
"ISF_ParticleBrokerSvc",
n),
75 m_truthRecordSvc(
"ISF_ValidationTruthService",
n),
77 m_randomEngineName(
"FatrasRnd")
81 declareProperty(
"DoElasticInteractions" ,
m_doElastic );
82 declareProperty(
"HadronicInteractionScaleFactor" ,
m_hadIntProbScale=1.0 ,
"Scale probability of HadrInteractions" );
84 declareProperty(
"ParticleBroker" ,
m_particleBroker ,
"ISF Particle Broker" );
85 declareProperty(
"TruthRecordSvc" ,
m_truthRecordSvc ,
"ISF Particle Truth Svc" );
87 declareProperty(
"RandomNumberService" ,
m_rndGenSvc ,
"Random number generator");
88 declareProperty(
"RandomStreamName" ,
m_randomEngineName ,
"Name of the random number stream");
105 if (m_particleBroker.retrieve().isFailure()){
106 ATH_MSG_FATAL(
"Could not retrieve ParticleBroker: " << m_particleBroker );
107 return StatusCode::FAILURE;
109 if (m_truthRecordSvc.retrieve().isFailure()){
110 ATH_MSG_FATAL(
"Could not retrieve TruthRecordSvc: " << m_truthRecordSvc );
111 return StatusCode::FAILURE;
115 if (m_rndGenSvc.retrieve().isFailure()){
117 return StatusCode::FAILURE;
122 m_randomEngine = m_rndGenSvc->GetEngine(m_randomEngineName);
123 if (!m_randomEngine) {
124 ATH_MSG_FATAL(
"Could not get random engine '" << m_randomEngineName <<
"'" );
125 return StatusCode::FAILURE;
130 return StatusCode::SUCCESS;
138 return StatusCode::SUCCESS;
144 ATH_MSG_VERBOSE(
" [ g4sim ] Registering Geant4 processes for particles with pdg code " << pdg );
147 std::map<int,G4VProcess*>::const_iterator ret = m_g4HadrInelasticProcesses.end();
150 G4ParticleDefinition *parDef = G4ParticleTable::GetParticleTable()->FindParticle( pdg);
153 if ( !parDef || !parDef->GetProcessManager() ) {
154 ATH_MSG_WARNING(
" [ ---- ] Unable to register particle type with PDG code " << pdg );
160 G4ProcessVector *physIntVector = parDef->GetProcessManager()->GetPostStepProcessVector(typeGPIL);
163 if ( !physIntVector) {
164 ATH_MSG_WARNING(
" [ ---- ] No Geant4 processes registered for PDG code " << pdg <<
" particles" );
165 return m_g4HadrInelasticProcesses.end();
169 for(
size_t np=0;
np < physIntVector->size();
np++) {
171 G4VProcess* curProc = (*physIntVector)(
np);
173 if ( curProc == 0 )
continue;
175 ATH_MSG_VERBOSE(
" [ g4sim ] Found Geant4 process " << curProc->GetProcessName());
177 G4HadronInelasticProcess *hadInelastic =
dynamic_cast<G4HadronInelasticProcess*
>( curProc);
178 G4HadronElasticProcess *hadElastic =
dynamic_cast<G4HadronElasticProcess*
>( curProc);
179 ATH_MSG_DEBUG(
" hadronic process inelastic,elastic " << hadInelastic <<
", " << hadElastic);
180 if ( !hadInelastic && !hadElastic) {
181 ATH_MSG_VERBOSE(
" [ g4sim ] Current process not an inelastic or elastic hadronic process -> process not registered" );
185 if (hadInelastic || hadElastic) {
187 curProc->PreparePhysicsTable(*parDef);
188 curProc->BuildPhysicsTable(*parDef);
192 ret = m_g4HadrInelasticProcesses.insert( std::pair<int,G4VProcess*>( pdg, hadInelastic) ).first;
193 ATH_MSG_DEBUG(
" [ g4sim ] Registered Geant4 hadronic interaction processes for particles with pdg code " << pdg );
195 if(m_doElastic && hadElastic ){
196 ret = m_g4HadrElasticProcesses.insert( std::pair<int,G4VProcess*>( pdg, hadElastic) ).first;
197 G4ProcessType pType = curProc->GetProcessType();
198 ATH_MSG_DEBUG(
" [ g4sim ] Registered Geant4 ELASTIC hadronic interaction processes for particles with pdg code "
199 << pdg <<
"and process " << pType);
210 double,
double,
double,
217 bool processSecondaries =
true;
222 ATH_MSG_WARNING(
"[ ---- ] Unable to cast MaterialProperties->MaterialProperties -> no material interactions for this particle");
229 double meanIntLength = pathCorrection*ematprop->
l0();
230 double rndIntLength = CLHEP::RandExponential::shoot(m_randomEngine, meanIntLength);
231 double thickness = pathCorrection*ematprop->
thickness();
234 if ( rndIntLength < thickness ) {
235 ATH_MSG_DEBUG(
" [ g4sim ] computing hadronic interaction on current particle in current material layer");
236 return doHadronicInteraction( 0., position,
momentum, &(ematprop->
material()), particle, processSecondaries);
249 ATH_CHECK( m_g4RunManagerHelper.retrieve() );
251 G4RunManager* g4runManager = m_g4RunManagerHelper->fastG4RunManager();
252 g4runManager->SetVerboseLevel(10);
254 initProcessPDG( 211);
255 initProcessPDG(-211);
256 initProcessPDG(2212);
257 initProcessPDG(-2212);
258 initProcessPDG(2112);
259 initProcessPDG( 130);
260 initProcessPDG( 321);
261 initProcessPDG( 111);
262 initProcessPDG(-321);
265 m_g4Material.clear();
267 G4NistManager* G4Nist = G4NistManager::Instance();
268 G4Material* air = G4Nist->G4NistManager::FindOrBuildMaterial(
"G4_AIR");
270 G4MaterialCutsCouple airCuts = G4MaterialCutsCouple(air);
272 std::pair<G4Material*,G4MaterialCutsCouple> airMat(air,airCuts);
273 m_g4Material.push_back(std::pair<
float,std::pair<G4Material*,G4MaterialCutsCouple> >(0.,airMat));
275 G4Material*
h = G4Nist->G4NistManager::FindOrBuildMaterial(
"G4_H");
277 G4MaterialCutsCouple hCuts = G4MaterialCutsCouple(
h);
278 std::pair<G4Material*,G4MaterialCutsCouple> hMat(
h,hCuts);
279 m_g4Material.push_back(std::pair<
float,std::pair<G4Material*,G4MaterialCutsCouple> >(1.,hMat));
281 G4Material* al = G4Nist->G4NistManager::FindOrBuildMaterial(
"G4_Al");
283 G4MaterialCutsCouple alCuts = G4MaterialCutsCouple(al);
284 std::pair<G4Material*,G4MaterialCutsCouple> alMat(al,alCuts);
285 m_g4Material.push_back(std::pair<
float,std::pair<G4Material*,G4MaterialCutsCouple> >(13.,alMat));
287 G4Material* si = G4Nist->G4NistManager::FindOrBuildMaterial(
"G4_Si");
289 G4MaterialCutsCouple siCuts = G4MaterialCutsCouple(si);
290 std::pair<G4Material*,G4MaterialCutsCouple> siMat(si,siCuts);
291 m_g4Material.push_back(std::pair<
float,std::pair<G4Material*,G4MaterialCutsCouple> >(14.,siMat));
293 G4Material* ar = G4Nist->G4NistManager::FindOrBuildMaterial(
"G4_Ar");
295 G4MaterialCutsCouple arCuts = G4MaterialCutsCouple(ar);
296 std::pair<G4Material*,G4MaterialCutsCouple> arMat(ar,arCuts);
297 m_g4Material.push_back(std::pair<
float,std::pair<G4Material*,G4MaterialCutsCouple> >(18.,arMat));
299 G4Material* fe = G4Nist->G4NistManager::FindOrBuildMaterial(
"G4_Fe");
301 G4MaterialCutsCouple feCuts = G4MaterialCutsCouple(fe);
302 std::pair<G4Material*,G4MaterialCutsCouple> feMat(fe,feCuts);
303 m_g4Material.push_back(std::pair<
float,std::pair<G4Material*,G4MaterialCutsCouple> >(26.,feMat));
305 G4Material*
pb = G4Nist->G4NistManager::FindOrBuildMaterial(
"G4_Pb");
307 G4MaterialCutsCouple pbCuts = G4MaterialCutsCouple(
pb);
308 std::pair<G4Material*,G4MaterialCutsCouple> pbMat(
pb,pbCuts);
309 m_g4Material.push_back(std::pair<
float,std::pair<G4Material*,G4MaterialCutsCouple> >(82.,pbMat));
312 ATH_MSG_INFO(
"material vector size for had interaction:"<< m_g4Material.size());
320 return StatusCode::SUCCESS;
329 const int pdg =
parent->pdgCode();
332 if ( pdg>10000 )
return chDef;
342 static const StatusCode g4RunManagerInit = [&]() {
343 std::scoped_lock lock(processMapMutex);
348 if (g4RunManagerInit.isFailure())
return chDef;
352 std::map<int, G4VProcess*>::const_iterator processIter_inelast = m_g4HadrInelasticProcesses.find(pdg);
353 std::map<int, G4VProcess*>::const_iterator processIter_elast = m_g4HadrElasticProcesses.find(pdg);
355 if ( (processIter_inelast==m_g4HadrInelasticProcesses.end()) && (processIter_elast==m_g4HadrElasticProcesses.end()) ) {
356 ATH_MSG_DEBUG (
" [ g4sim ] No hadronic interactions registered for current particle type (pdg=" << pdg <<
")" );
357 std::scoped_lock lock(processMapMutex);
364 ATH_MSG_DEBUG (
" [ g4sim ] Found registered hadronic interactions for current particle type (pdg=" << pdg <<
")" );
368 const G4ParticleDefinition *g4parDef = G4ParticleTable::GetParticleTable()->FindParticle(pdg);
370 ATH_MSG_WARNING(
"[ ---- ] Unable to find G4ParticleDefinition for particle with PID=" << pdg <<
" --> skipping hadronic interactions" );
373 G4DynamicParticle* inputPar =
new G4DynamicParticle();
374 inputPar->SetDefinition( g4parDef);
381 inputPar->SetMomentum(
mom);
383 G4Track g4track( inputPar, 0 , {0, 0, 0} );
388 unsigned int g4matInd = retrieveG4MaterialIndex(ematprop);
390 if (g4matInd >= m_g4Material.size()) {
396 G4StepPoint* g4stepPoint =
new G4StepPoint();
397 g4step.SetPreStepPoint( g4stepPoint);
399 g4stepPoint->SetMaterial(m_g4Material[g4matInd].
second.first);
400 g4stepPoint->SetMaterialCutsCouple(&(m_g4Material[g4matInd].
second.second));
403 g4track.SetStep( &g4step);
406 G4VProcess *
process = processIter_inelast!=m_g4HadrInelasticProcesses.end() ? processIter_inelast->second : 0;
410 if( m_doElastic && (processIter_elast!=m_g4HadrElasticProcesses.end()) ) {
411 double rand = CLHEP::RandFlat::shoot(m_randomEngine, 0., 1.);
414 if(
rand < 0.5)
process = processIter_elast->second;
417 ATH_MSG_VERBOSE (
" [ g4sim ] Computing " <<
process->GetProcessName() <<
" process with current particle" );
423 G4VParticleChange* g4change =
process->PostStepDoIt(g4track, g4step);
425 ATH_MSG_WARNING(
" [ ---- ] Geant4 did not return any hadronic interaction information of particle with pdg=" << pdg );
430 unsigned int numSecondaries = g4change->GetNumberOfSecondaries();
431 ATH_MSG_DEBUG(
"[ g4sim ] Material update created " << numSecondaries <<
" Geant4 particle (s)." );
434 if ( numSecondaries ) {
438 unsigned short numChildren = 0;
439 for (
unsigned int i = 0;
i < numSecondaries;
i++ ){
442 G4Track *trk = g4change->GetSecondary(
i);
443 const G4DynamicParticle *dynPar = trk->GetDynamicParticle();
446 if ( dynPar->GetTotalMomentum() < m_minMomentum)
450 const G4ParticleDefinition *parDef = trk->GetParticleDefinition();
453 if (parDef->GetPDGEncoding()>1.e09)
continue;
459 ATH_MSG_VERBOSE(
" [ g4sim ] Adding child particle to particle stack (pdg=" << parDef->GetPDGEncoding()
460 <<
" p=" << dynPar->GetTotalMomentum() );
464 const G4ThreeVector &momG4 = dynPar->GetMomentum();
471 parDef->GetPDGMass(),
472 parDef->GetPDGCharge(),
473 parDef->GetPDGEncoding(),
481 *childrenIt = cParticle;
482 ++childrenIt; numChildren++;
488 const int processForTI = 121;
494 m_truthRecordSvc->registerTruthIncident( truth);
500 for (
auto *childParticle :
children) {
501 if (!childParticle->getTruthBinding()) {
502 ATH_MSG_ERROR(
"Could not retrieve TruthBinding from child ISFParticle "<< *childParticle);
522 bool processSecondaries)
const
533 if (ispVec.empty())
return false;
536 if (processSecondaries) {
537 for (
auto *childParticle : ispVec) {
539 if (!childParticle->getTruthBinding()) {
540 ATH_MSG_ERROR(
"Could not retrieve TruthBinding from child ISFParticle "<< *childParticle);
542 m_particleBroker->push(childParticle,
parent);
562 unsigned int nMaterials = m_g4Material.size();
563 unsigned int invalidIndex = nMaterials + 1;
566 ATH_MSG_WARNING(
" no predefined G4 material available for hadronic interaction " );
567 return (invalidIndex);
572 float iZ = ematprop ? ematprop->
averageZ() : 13 ;
577 while (imat < nMaterials && iZ > m_g4Material[imat].
first ) imat++;
579 unsigned int iSel=imat< nMaterials ? imat : nMaterials-1;
586 float dz2 = -
pow(m_g4Material[iSel-1].
first,2)+
pow(m_g4Material[iSel].
first,2);
587 double rnd = CLHEP::RandFlat::shoot(m_randomEngine, 0., 1.);
588 if (iZ*iZ+
pow(m_g4Material[iSel-1].
first,2) < rnd*dz2) iSel--;