ATLAS Offline Software
G4ParticleDecayHelper.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // class header
6 // iFatras
11 // ISF
12 #include "ISF_Event/ISFParticle.h"
16 
17 // Gaudi & StoreGate
19 #include "GaudiKernel/ISvcLocator.h"
20 #include "StoreGate/StoreGateSvc.h"
21 // CLHEP
22 #include "CLHEP/Units/SystemOfUnits.h"
23 #include "CLHEP/Units/PhysicalConstants.h"
24 #include "AtlasHepMC/GenParticle.h"
25 #include "CLHEP/Vector/LorentzVector.h"
26 #include "CLHEP/Random/RandFlat.h"
28 
29 // G4
30 #include "G4RunManager.hh"
31 #include "G4ParticleDefinition.hh"
32 #include "G4DecayTable.hh"
33 #include "G4DecayProducts.hh"
34 #include <cmath>
35 
36 namespace {
38  constexpr double s_speedOfLightSI = CLHEP::c_light*CLHEP::s/CLHEP::mm;
39 }
40 
41 /*=========================================================================
42  * DESCRIPTION OF FUNCTION:
43  * ==> see headerfile
44  *=======================================================================*/
45 iFatras::G4ParticleDecayHelper::G4ParticleDecayHelper(const std::string& t, const std::string& n, const IInterface* p):
46  base_class(t,n,p),
47  m_particleBroker("ISF_ParticleBroker", n),
48  m_truthRecordSvc("ISF_TruthRecordSvc", n),
49  m_rndmSvc("AtDSFMTGenSvc", n),
50  m_randomEngine(0),
51  m_randomEngineName("FatrasRnd"),
52  m_G4RandomEngineName("FatrasG4"),
53  m_g4RunManagerHelper("iGeant4::G4RunManagerHelper/G4RunManagerHelper"),
54  m_pdgToG4Conv("iFatras::PDGToG4Particle/PDGToG4ParticleConverter"),
55  m_validationMode(false),
56  m_validationTool("")
57 {
58  // ISF: truth and broker service
59  declareProperty("ParticleBroker", m_particleBroker, "ISF Particle Broker Svc");
60  declareProperty("ParticleTruthSvc", m_truthRecordSvc, "ISF Particle Truth Svc");
61  // random number initializations
62  declareProperty("RandomNumberService", m_rndmSvc, "Random number generator");
63  declareProperty("RandomStreamName", m_randomEngineName, "Name of the random number stream");
64  declareProperty("G4RandomStreamName", m_G4RandomEngineName, "Name of the random number stream for G4 tools");
65 
66  // tool declarations -------------------------------------------------
67  declareProperty("G4RunManagerHelper" , m_g4RunManagerHelper);
68  declareProperty("PDGToG4ParticleConverter", m_pdgToG4Conv);
69  // validation output section
70  declareProperty( "ValidationMode", m_validationMode );
71  declareProperty( "PhysicsValidationTool", m_validationTool );
72 
73 }
74 
75 /*=========================================================================
76  * DESCRIPTION OF FUNCTION:
77  * ==> see headerfile
78  *=======================================================================*/
80 {}
81 
82 /*=========================================================================
83  * DESCRIPTION OF FUNCTION:
84  * ==> see headerfile
85  *=======================================================================*/
88 {
89 
90  ATH_MSG_DEBUG( "initialize()" );
91 
92  ATH_CHECK( m_validationTool.retrieve( DisableTool{ m_validationTool.empty() || !m_validationMode } ) );
93  // ISF Services
94  if ( m_particleBroker.retrieve().isFailure()){
95  ATH_MSG_FATAL( "Could not retrieve " << m_particleBroker );
96  return StatusCode::FAILURE;
97  }
98  if (m_truthRecordSvc.retrieve().isFailure()){
99  ATH_MSG_FATAL( "Could not retrieve " << m_truthRecordSvc );
100  return StatusCode::FAILURE;
101  }
102 
103  // Random number service
104  if ( m_rndmSvc.retrieve().isFailure() ) {
105  ATH_MSG_FATAL( "Could not retrieve " << m_rndmSvc );
106  return StatusCode::FAILURE;
107  }
108  //Get own engine with own seeds:
109  m_randomEngine = m_rndmSvc->GetEngine(m_randomEngineName);
110  if (!m_randomEngine) {
111  ATH_MSG_FATAL( "Could not get random engine '" << m_randomEngineName << "'" );
112  return StatusCode::FAILURE;
113  }
114  // G4ParticleDecayCreator uses functions from G4 (G4VDecayChannel::DecayIt() and G4DecayTable::SelectADecayChannel())
115  // which use CLHEP::HepRandom directly with the default engine. Therefore we set the default engine to a special stream,
116  // analog to G4AtlasAlg.
117  // Set the random number generator to AtRndmGen
118  CLHEP::HepRandomEngine* engine = m_rndmSvc->GetEngine(m_G4RandomEngineName);
119  if (!engine) {
120  ATH_MSG_FATAL( "Could not get random engine '" << m_G4RandomEngineName << "'" );
121  return StatusCode::FAILURE;
122  }
123  CLHEP::HepRandom::setTheEngine(engine);
124 
125  // get G4RunManagerHelper ( no G4RunManager initialization done )
126  if (m_g4RunManagerHelper.retrieve().isFailure()) {
127  ATH_MSG_FATAL( "Could not get g4RunManagerHelper '" << m_g4RunManagerHelper << "'" );
128  return StatusCode::FAILURE;
129  } else {
130  std::cout <<"f4dec: g4RunManagerHelper retrieved:"<< m_g4RunManagerHelper<< std::endl;
131  }
132 
133  // Disable auto-retrieve of this tool: Geant will raise an exception
134  // if this happens before the run manager is created.
135  m_pdgToG4Conv.disable();
136 
137  ATH_MSG_DEBUG("initialize() successful");
138  return StatusCode::SUCCESS;
139 }
140 
141 /*=========================================================================
142  * DESCRIPTION OF FUNCTION:
143  * ==> see headerfile
144  *=======================================================================*/
147 {
148  ATH_MSG_DEBUG( "finalize() successful" );
149  return StatusCode::SUCCESS;
150 }
151 
153  // get the particle properties
154  int pdgCode = isp.pdgCode();
155 
156  // initialize G4RunManager if not done already
157  bool g4mgr = initG4RunManager();
158  if (!g4mgr) ATH_MSG_WARNING( "initialization of G4RunManager failed in G4ParticleDecayHelper" );
159 
160  if (!m_pdgToG4Conv && m_pdgToG4Conv.retrieve().isFailure()) return -1.;
161 
162  G4ParticleDefinition* pDef = m_pdgToG4Conv->getParticleDefinition(pdgCode);
163 
164  // for the processing
165  bool isStable = true;
166 
167  if( !pDef ) {
168  ATH_MSG_WARNING( "[ decay ] could not find particle properties" << " for PDG code " << pdgCode );
169  return -1.;
170  }
171  // set is stable from Geant4 particle definition
172  isStable = pDef->GetPDGStable();
173  // set muons to stable
174  if ( std::abs(pdgCode) == 13) isStable = true;
175  // we have a stable particle --- return
176  if (isStable) return -1.;
177 
178  double mass = pDef->GetPDGMass();
179  // take momentum from ParticleState rather than associated truth
180  CLHEP::HepLorentzVector particleMom( isp.momentum().x(),
181  isp.momentum().y(),
182  isp.momentum().z(),
183  sqrt(isp.momentum().mag2()+mass*mass) );
184 
185  // get average lifetime
186  double tau = pDef->GetPDGLifeTime()*1e-9;
187  // sample the lifetime
188  double lifeTime = -tau*log(CLHEP::RandFlat::shoot(m_randomEngine));
189  // distance in mm
190  double pathlength =
191  lifeTime*s_speedOfLightSI*particleMom.gamma()*particleMom.beta();
192  return pathlength;
193 }
194 
196  const Amg::Vector3D& vertex,
197  const Amg::Vector3D& momentum,
198  double timeStamp) const
199 {
200 
201  /*-------------------------------------------------------------------
202  * The actual decay
203  *-------------------------------------------------------------------*/
204  ATH_MSG_DEBUG( "[ decay ] calling G4ParticleDecayCreator with " << particleToDecay );
205 
206  // perform the decay
207  const ISF::ISFParticleVector decayProducts = decayParticle(particleToDecay,vertex,momentum,timeStamp);
208 
209  // fill them into broker & truth svc
210  handleDecayParticles(particleToDecay,decayProducts); // Registers TruthIncident internally
211 }
212 
213 
215  const ISF::ISFParticleVector& decayProducts) const {
216  // process the decay products ---------------------------------------
217  int process = 201;
218 
219  // (i) none
220  if (!decayProducts.size()) {
221  ATH_MSG_WARNING("[ decay ] Particle Decay Creator did not return any"
222  << " decay products for particle with PDG code "
223  << particle.pdgCode() );
224  } else {
225  // (ii) many
226  std::ostringstream productSummaryString;
227  productSummaryString << "[ decay ] products:";
228 
229  for (ISF::ISFParticle *decayProduct : decayProducts) {
230  productSummaryString << " - " << (*decayProduct) << '\n';
231  // in the validation mode, add process info
232  if (m_validationMode) {
234  validInfo->setProcess(process);
235  if (particle.getUserInformation()) validInfo->setGeneration(particle.getUserInformation()->generation()+1);
236  else validInfo->setGeneration(1); // assume parent is a primary track
237  decayProduct->setUserInformation(validInfo);
238  }
239  // register next geo (is current), next flavor can be defined by filter
240  decayProduct->setNextGeoID( particle.nextGeoID() );
241  }//loop over all decay products
242 
243  // register TruthIncident
244  ISF::ISFTruthIncident truth( const_cast<ISF::ISFParticle&>(particle),
245  decayProducts,
246  process,
247  particle.nextGeoID(), // inherits from the parent
249  m_truthRecordSvc->registerTruthIncident( truth);
250  // At this point we need to update the properties of the
251  // ISFParticles produced in the interaction
253 
254  // simulate the tracks of the daughter particles ------- run over decay products
255  for (ISF::ISFParticle *decayProduct : decayProducts) {
256  // feed it the particle broker with parent information
257  m_particleBroker->push(decayProduct, &particle);
258  }//loop over all decay products
259  ATH_MSG_VERBOSE( productSummaryString.str() );
260 
261  // save info for validation
262  if (m_validationMode && m_validationTool.isEnabled()) {
263  Amg::Vector3D* nMom = 0;
264  m_validationTool->saveISFVertexInfo(process,particle.position(),particle,particle.momentum(),nMom,decayProducts);
265  delete nMom;
266  }
267 
268  }
269 }
270 
271 std::vector<ISF::ISFParticle*>
273  const Amg::Vector3D& vertex,
274  const Amg::Vector3D& momentum,
275  double timeStamp) const
276 {
277  // Called from McMaterialEffectsUpdator::interact, McMaterialEffectsUpdator::interactLay and G4ParticleDecayHelper::decay
278  // return vector for children
279  std::vector<ISF::ISFParticle*> children;
280 
281  // initialize G4RunManager if not done already
282  bool g4mgr = initG4RunManager();
283  if (!g4mgr) ATH_MSG_WARNING( "initialization of G4RunManager failed in G4ParticleDecayHelper" );
284 
285  if (!m_pdgToG4Conv) {
286 
287  if( m_pdgToG4Conv.retrieve().isFailure()) return children;
288 
289  if( msgLvl(MSG::VERBOSE)) {
290  ATH_MSG_VERBOSE( "List of particles with decay info:" );
291  m_pdgToG4Conv->printListOfParticles( true);
292  }
293  }
294 
295  int pdgCode = parent.pdgCode();
296 
297  G4ParticleDefinition* pDef = m_pdgToG4Conv->getParticleDefinition( pdgCode);
298  if( !pDef)
299  {
300  ATH_MSG_WARNING( "[ decay ] could not find geant4 equivalent"
301  << " for particle with pdg id " << pdgCode );
302  return children;
303  }
304 
305  ATH_MSG_DEBUG( "[ decay ] Decaying " << pDef->GetParticleName() );
306 
307  G4DecayTable* dt = pDef->GetDecayTable();
308  if( !dt)
309  {
310  ATH_MSG_WARNING( "[ decay ] empty decay table for"
311  << " particle with pdg id " << pdgCode );
312  return children;
313  }
314 
315  if( msgLvl(MSG::VERBOSE))
316  {
317  ATH_MSG_VERBOSE( "[ decay ] Decay table:" );
318  dt->DumpInfo();
319  }
320 
321  G4VDecayChannel* channel = dt->SelectADecayChannel();
322  if( !channel)
323  {
324  ATH_MSG_ERROR( "[ decay ] error selecting decay channel for"
325  << " particle with pdg id " << pdgCode );
326  return children;
327  }
328 
329  if( msgLvl(MSG::DEBUG))
330  {
331  ATH_MSG_DEBUG( "[ decay ] Decay channel:" );
332  channel->DumpInfo();
333  }
334 
335  G4DecayProducts* products = channel->DecayIt();
336  if( !products)
337  {
338  ATH_MSG_ERROR( "[ decay ] error in decay product generation"
339  << " for particle with pdg id " << pdgCode );
340  return children;
341  }
342 
343  if( msgLvl(MSG::VERBOSE))
344  {
345  ATH_MSG_VERBOSE( "[ decay ] Decay products:" );
346  products->DumpInfo();
347  }
348 
349  // the parent energy
350  double parentE = std::sqrt( std::pow( pDef->GetPDGMass(), 2) +
351  momentum.mag2());
352 
353  products->Boost( momentum.x()/parentE,
354  momentum.y()/parentE,
355  momentum.z()/parentE);
356  if( msgLvl(MSG::VERBOSE))
357  {
358  ATH_MSG_VERBOSE( "[ decay ] Decay products after boost:" );
359  products->DumpInfo();
360  }
361 
362  G4int nProducts = products->entries();
363  for( G4int i=0; i < nProducts; ++i)
364  {
365  G4DynamicParticle* prod = products->PopProducts();
366  if( !prod)
367  {
368  ATH_MSG_WARNING( "[ decay ] Could not retrieve product " << i);
369  continue;
370  }
371 
372  // the decay product
373  const G4ThreeVector &mom= prod->GetMomentum();
374  Amg::Vector3D amgMom( mom.x(), mom.y(), mom.z() );
375 
376  const int status = 1 + HepMC::SIM_STATUS_THRESHOLD;
377  const int id = HepMC::UNDEFINED_ID;
378  ISF::ISFParticle* childParticle = new ISF::ISFParticle( vertex,
379  amgMom,
380  prod->GetMass(),
381  prod->GetCharge(),
382  prod->GetPDGcode(),
383  status,
384  timeStamp,
385  parent,
386  id );
387 
388  children.push_back( childParticle);
389  }
390  return children;
391 }
392 
394 
395  // safe because the static initialization ensures that this is only called once
396  static const G4RunManager* const g4runManager ATLAS_THREAD_SAFE = [&] ATLAS_NOT_THREAD_SAFE () {
397  auto helper_nc = const_cast<ISF::IG4RunManagerHelper*>(m_g4RunManagerHelper.get());
398  return helper_nc->fastG4RunManager();
399  }();
400 
401  return g4runManager ? true : false;
402 }
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
ISF::ISFTruthIncident::updateChildParticleProperties
void updateChildParticleProperties()
Update the id and particleLink properties of the child particles (to be called after registerTruthInc...
Definition: ISFTruthIncident.cxx:239
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
Trk::ParticleSwitcher::particle
constexpr ParticleHypothesis particle[PARTICLEHYPOTHESES]
the array of masses
Definition: ParticleHypothesis.h:76
iFatras::G4ParticleDecayHelper::m_truthRecordSvc
ServiceHandle< ISF::ITruthSvc > m_truthRecordSvc
Truth Svc for truth tree.
Definition: G4ParticleDecayHelper.h:85
python.SystemOfUnits.s
int s
Definition: SystemOfUnits.py:131
plotting.yearwise_efficiency.channel
channel
Definition: yearwise_efficiency.py:24
iFatras::G4ParticleDecayHelper::~G4ParticleDecayHelper
~G4ParticleDecayHelper()
Destructor.
Definition: G4ParticleDecayHelper.cxx:79
Base_Fragment.mass
mass
Definition: Sherpa_i/share/common/Base_Fragment.py:59
ATLAS_NOT_THREAD_SAFE
#define ATLAS_NOT_THREAD_SAFE
getNoisyStrip() Find noisy strips from hitmaps and write out into xml/db formats
Definition: checker_macros.h:212
ISF::ParticleUserInformation::setProcess
void setProcess(int proc)
Definition: ParticleUserInformation.h:90
IParticleBroker.h
conifer::pow
constexpr int pow(int x)
Definition: conifer.h:20
ISF::ISFParticle
Definition: ISFParticle.h:42
iFatras::G4ParticleDecayHelper::decay
void decay(const ISF::ISFParticle &isp, const Amg::Vector3D &vertex, const Amg::Vector3D &mom, double timeStamp=0) const
decay handling secondaries
Definition: G4ParticleDecayHelper.cxx:195
ISFTruthIncident.h
ISF::ISFParticle::pdgCode
int pdgCode() const
PDG value.
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
iFatras::G4ParticleDecayHelper::decayParticle
std::vector< ISF::ISFParticle * > decayParticle(const ISF::ISFParticle &parent, const Amg::Vector3D &vertex, const Amg::Vector3D &mom, double timeStamp=0) const
decay
Definition: G4ParticleDecayHelper.cxx:272
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
IPhysicsValidationTool.h
iFatras::G4ParticleDecayHelper::G4ParticleDecayHelper
G4ParticleDecayHelper(const std::string &, const std::string &, const IInterface *)
AlgTool constructor for ParticleDecayHelper.
Definition: G4ParticleDecayHelper.cxx:45
GenParticle.h
SUSY_SimplifiedModel_PostInclude.process
string process
Definition: SUSY_SimplifiedModel_PostInclude.py:42
ISF::IG4RunManagerHelper
Definition: IG4RunManagerHelper.h:26
iFatras::G4ParticleDecayHelper::m_g4RunManagerHelper
ToolHandle< ISF::IG4RunManagerHelper > m_g4RunManagerHelper
G4RunManager needs to be initialized before G4 tables are accessed.
Definition: G4ParticleDecayHelper.h:96
iFatras::G4ParticleDecayHelper::m_pdgToG4Conv
ToolHandle< PDGToG4Particle > m_pdgToG4Conv
Handle for the PDGToG4Particle converter tool.
Definition: G4ParticleDecayHelper.h:97
ISFParticle.h
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
ParticleGun_EoverP_Config.mom
mom
Definition: ParticleGun_EoverP_Config.py:63
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
ParticleGun_EoverP_Config.momentum
momentum
Definition: ParticleGun_EoverP_Config.py:63
ISF::ISFTruthIncident
Definition: ISFTruthIncident.h:35
IG4RunManagerHelper.h
lumiFormat.i
int i
Definition: lumiFormat.py:85
beamspotman.n
n
Definition: beamspotman.py:731
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
CaloNoise_fillDB.dt
dt
Definition: CaloNoise_fillDB.py:58
ISF::ParticleUserInformation
Definition: ParticleUserInformation.h:52
iFatras::G4ParticleDecayHelper::m_randomEngineName
std::string m_randomEngineName
Name of the random number stream.
Definition: G4ParticleDecayHelper.h:90
ISF::ISFParticleVector
std::vector< ISF::ISFParticle * > ISFParticleVector
ISFParticle vector.
Definition: ISFParticleContainer.h:26
iFatras::G4ParticleDecayHelper::m_rndmSvc
ServiceHandle< IAtRndmGenSvc > m_rndmSvc
Random Svc.
Definition: G4ParticleDecayHelper.h:88
test_pyathena.parent
parent
Definition: test_pyathena.py:15
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
iFatras::G4ParticleDecayHelper::initG4RunManager
bool initG4RunManager() const
initialize G4RunManager on first call if not done by then
Definition: G4ParticleDecayHelper.cxx:393
HepMC::UNDEFINED_ID
constexpr int UNDEFINED_ID
Definition: MagicNumbers.h:55
ISF::ParticleUserInformation::setGeneration
void setGeneration(int gen)
Definition: ParticleUserInformation.h:92
HepMC::SIM_STATUS_THRESHOLD
constexpr int SIM_STATUS_THRESHOLD
Constant definiting the status threshold for simulated particles, eg. can be used to separate generat...
Definition: MagicNumbers.h:45
MagicNumbers.h
ISF::ISFParticle::momentum
const Amg::Vector3D & momentum() const
The current momentum vector of the ISFParticle.
iFatras::G4ParticleDecayHelper::initialize
StatusCode initialize()
AlgTool initailize method.
Definition: G4ParticleDecayHelper.cxx:87
G4ParticleDecayHelper.h
python.PhysicalConstants.c_light
float c_light
Definition: PhysicalConstants.py:63
iFatras::G4ParticleDecayHelper::m_particleBroker
ServiceHandle< ISF::IParticleBroker > m_particleBroker
Broker Svc for ISF particles.
Definition: G4ParticleDecayHelper.h:84
PDGToG4Particle.h
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
iFatras::G4ParticleDecayHelper::m_validationTool
ToolHandle< IPhysicsValidationTool > m_validationTool
the ntuple
Definition: G4ParticleDecayHelper.h:101
xAOD::timeStamp
setEventNumber timeStamp
Definition: EventInfo_v1.cxx:128
python.SystemOfUnits.mm
int mm
Definition: SystemOfUnits.py:83
iFatras::G4ParticleDecayHelper::m_G4RandomEngineName
std::string m_G4RandomEngineName
Name of the random number stream for G4 tools.
Definition: G4ParticleDecayHelper.h:91
Trk::vertex
@ vertex
Definition: MeasurementType.h:21
MC::isStable
bool isStable(const T &p)
Identify if the particle is stable, i.e. has not decayed.
Definition: HepMCHelpers.h:45
iFatras::G4ParticleDecayHelper::handleDecayParticles
void handleDecayParticles(const ISF::ISFParticle &isp, const ISF::ISFParticleVector &children) const
fill decay products: into broker svc, truth svc
Definition: G4ParticleDecayHelper.cxx:214
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
DEBUG
#define DEBUG
Definition: page_access.h:11
python.CaloCondTools.log
log
Definition: CaloCondTools.py:20
iFatras::G4ParticleDecayHelper::m_validationMode
bool m_validationMode
Validation output with histogram service.
Definition: G4ParticleDecayHelper.h:100
python.DecayParser.children
children
Definition: DecayParser.py:32
merge.status
status
Definition: merge.py:17
ITruthSvc.h
ATLAS_THREAD_SAFE
#define ATLAS_THREAD_SAFE
Definition: checker_macros.h:211
python.Constants.VERBOSE
int VERBOSE
Definition: Control/AthenaCommon/python/Constants.py:14
iFatras::G4ParticleDecayHelper::freePath
double freePath(const ISF::ISFParticle &isp) const
free path estimator (-1 for stable particle)
Definition: G4ParticleDecayHelper.cxx:152
checker_macros.h
Define macros for attributes used to control the static checker.
iFatras::G4ParticleDecayHelper::finalize
StatusCode finalize()
AlgTool finalize method.
Definition: G4ParticleDecayHelper.cxx:146
StoreGateSvc.h
ISF::fKillsPrimary
@ fKillsPrimary
Definition: ISFTruthIncident.h:25