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"
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.);
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");
107 return StatusCode::FAILURE;
111 return StatusCode::FAILURE;
117 return StatusCode::FAILURE;
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 );
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" );
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);
193 ATH_MSG_DEBUG(
" [ g4sim ] Registered Geant4 hadronic interaction processes for particles with pdg code " << pdg );
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");
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());
317 G4cout << std::flush;
318 G4cerr << std::flush;
320 return StatusCode::SUCCESS;
329 const int pdg = parent->pdgCode();
332 if ( pdg>10000 )
return chDef;
339 static std::mutex processMapMutex;
342 static const StatusCode g4RunManagerInit = [&]() {
343 std::scoped_lock lock(processMapMutex);
348 if (g4RunManagerInit.isFailure())
return chDef;
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);
376 if ( momentum.mag()>1.e08 ) {
377 ATH_MSG_WARNING(
"input momentum beyond limit" << momentum.mag() <<
" --> skipping hadronic interaction" );
380 const G4ThreeVector mom( momentum.x(), momentum.y(), momentum.z() );
381 inputPar->SetMomentum( mom);
383 G4Track g4track( inputPar, 0 , {0, 0, 0} );
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);
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 ) {
437 ISF::ISFParticleVector::iterator childrenIt = children.begin();
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();
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++;
485 children.resize(numChildren);
488 const int processForTI = 121;
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);
556 return getHadState(parent, time, position, momentum, emat);
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;
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
constexpr int pow(int base, int exp) noexcept
#define ATLAS_NOT_THREAD_SAFE
getNoisyStrip() Find noisy strips from hitmaps and write out into xml/db formats
#define ATLAS_THREAD_SAFE
Header file for AthHistogramAlgorithm.
The generic ISF particle definition,.
void setNextSimID(SimSvcID simID)
register the next SimSvcID
void setNextGeoID(AtlasDetDescr::AtlasRegion geoID)
register the next AtlasDetDescr::AtlasRegion
Interface class for all truth incidents handled by the ISF.
void updateChildParticleProperties()
Update the id and particleLink properties of the child particles (to be called after registerTruthInc...
static ParticleClipboard & getInstance()
get the singleton instance
const ISF::ISFParticle * getParticle() const
get the particle from the clipboard
Material with information about thickness of material.
float thicknessInX0() const
Return the radiationlength fraction.
float thicknessInL0() const
Return the nuclear interaction length fraction.
const Material & material() const
Return the stored Material.
float l0() const
Return the nuclear interaction length.
float thickness() const
Return the thickness in mm.
A common object to be contained by.
Wrapper class for multiple scattering, energyloss, hadronic interaction tool from Geant4.
ServiceHandle< ISF::ITruthSvc > m_truthRecordSvc
double m_minMomentum
Geant4 processes <PDGcode, process> TODO : fission, capture.
std::map< int, G4VProcess * > m_g4HadrInelasticProcesses
ISF::ISFParticleVector doHadIntOnLayer(const ISF::ISFParticle *parent, double time, const Amg::Vector3D &position, const Amg::Vector3D &momentum, const Trk::Material *ematprop, Trk::ParticleHypothesis particle=Trk::pion) const
interface for processing of the presampled nuclear interactions on layer
std::vector< std::pair< float, std::pair< G4Material *, G4MaterialCutsCouple > > > m_g4Material
CLHEP::HepRandomEngine * m_randomEngine
Random engine.
ISF::ISFParticleVector getHadState(const ISF::ISFParticle *parent, double time, const Amg::Vector3D &position, const Amg::Vector3D &momentum, const Trk::Material *ematprop) const
collect secondaries for layer material update
G4HadIntProcessor(const std::string &, const std::string &, const IInterface *)
AlgTool constructor for G4HadIntProcessor.
bool doHadronicInteraction(double time, const Amg::Vector3D &position, const Amg::Vector3D &momentum, const Trk::Material *ematprop, Trk::ParticleHypothesis particle=Trk::pion, bool processSecondaries=true) const
std::map< int, G4VProcess * > m_g4HadrElasticProcesses
ServiceHandle< IAtRndmGenSvc > m_rndGenSvc
bool hadronicInteraction(const Amg::Vector3D &position, const Amg::Vector3D &momentum, double p, double E, double charge, const Trk::MaterialProperties &mprop, double pathCorrection, Trk::ParticleHypothesis particle=Trk::pion) const
interface for processing of the nuclear interactions
ServiceHandle< ISF::IParticleBroker > m_particleBroker
ISF services & Tools.
unsigned int retrieveG4MaterialIndex(const Trk::Material *ematprop) const
random number service
StatusCode finalize()
AlgTool finalize method.
std::map< int, G4VProcess * >::const_iterator initProcessPDG(int pdg)
choose for list of predefined (pure) materials
std::string m_randomEngineName
Name of the random number stream.
virtual ~G4HadIntProcessor()
Destructor.
ToolHandle< ISF::IG4RunManagerHelper > m_g4RunManagerHelper
steering: enable elastic interactions?
StatusCode initialize()
AlgTool initailize method.
const std::string process
Eigen::Matrix< double, 3, 1 > Vector3D
constexpr int UNDEFINED_ID
constexpr int SIM_STATUS_THRESHOLD
Constant definiting the status threshold for simulated particles, eg. can be used to separate generat...
std::vector< ISF::ISFParticle * > ISFParticleVector
ISFParticle vector.
ParticleHypothesis
Enumeration for Particle hypothesis respecting the interaction with material.