ATLAS Offline Software
Loading...
Searching...
No Matches
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
16
17// Gaudi & StoreGate
19#include "GaudiKernel/ISvcLocator.h"
21// CLHEP
22#include "CLHEP/Units/SystemOfUnits.h"
23#include "CLHEP/Units/PhysicalConstants.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
36namespace {
38 constexpr double s_speedOfLightSI = CLHEP::c_light*CLHEP::s/CLHEP::mm;
39}
40
41/*=========================================================================
42 * DESCRIPTION OF FUNCTION:
43 * ==> see headerfile
44 *=======================================================================*/
45iFatras::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),
51 m_randomEngineName("FatrasRnd"),
52 m_G4RandomEngineName("FatrasG4"),
53 m_g4RunManagerHelper("iGeant4::G4RunManagerHelper/G4RunManagerHelper"),
54 m_pdgToG4Conv("iFatras::PDGToG4Particle/PDGToG4ParticleConverter"),
55 m_validationMode(false),
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 *=======================================================================*/
81
82/*=========================================================================
83 * DESCRIPTION OF FUNCTION:
84 * ==> see headerfile
85 *=======================================================================*/
86StatusCode
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:
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 *=======================================================================*/
145StatusCode
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
271std::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}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Define macros for attributes used to control the static checker.
#define ATLAS_NOT_THREAD_SAFE
getNoisyStrip() Find noisy strips from hitmaps and write out into xml/db formats
#define ATLAS_THREAD_SAFE
The generic ISF particle definition,.
Definition ISFParticle.h:42
const Amg::Vector3D & momentum() const
The current momentum vector of the ISFParticle.
int pdgCode() const
PDG value.
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...
Each ISFParticle carries a pointer to this class.
bool initG4RunManager() const
initialize G4RunManager on first call if not done by then
std::vector< ISF::ISFParticle * > decayParticle(const ISF::ISFParticle &parent, const Amg::Vector3D &vertex, const Amg::Vector3D &mom, double timeStamp=0) const
decay
std::string m_randomEngineName
Name of the random number stream.
StatusCode finalize()
AlgTool finalize method.
ToolHandle< PDGToG4Particle > m_pdgToG4Conv
Handle for the PDGToG4Particle converter tool.
CLHEP::HepRandomEngine * m_randomEngine
Random engine (updated to streams)
ServiceHandle< IAtRndmGenSvc > m_rndmSvc
Random Svc.
void handleDecayParticles(const ISF::ISFParticle &isp, const ISF::ISFParticleVector &children) const
fill decay products: into broker svc, truth svc
void decay(const ISF::ISFParticle &isp, const Amg::Vector3D &vertex, const Amg::Vector3D &mom, double timeStamp=0) const
decay handling secondaries
ToolHandle< IPhysicsValidationTool > m_validationTool
the ntuple
bool m_validationMode
Validation output with histogram service.
ServiceHandle< ISF::ITruthSvc > m_truthRecordSvc
Truth Svc for truth tree.
G4ParticleDecayHelper(const std::string &, const std::string &, const IInterface *)
AlgTool constructor for ParticleDecayHelper.
double freePath(const ISF::ISFParticle &isp) const
free path estimator (-1 for stable particle)
ToolHandle< ISF::IG4RunManagerHelper > m_g4RunManagerHelper
G4RunManager needs to be initialized before G4 tables are accessed.
StatusCode initialize()
AlgTool initailize method.
ServiceHandle< ISF::IParticleBroker > m_particleBroker
Broker Svc for ISF particles.
std::string m_G4RandomEngineName
Name of the random number stream for G4 tools.
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...
@ fKillsPrimary
std::vector< ISF::ISFParticle * > ISFParticleVector
ISFParticle vector.