ATLAS Offline Software
InputConverter.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 include
6 #include "InputConverter.h"
7 
8 #include <memory>
9 
10 // framework
12 #include "GaudiKernel/IPartPropSvc.h"
13 #include "GaudiKernel/PhysicalConstants.h"
14 
15 // ISF_HepMC include
16 #include "ISF_Event/TruthBinding.h"
18 // ISF_Event include
19 #include "ISF_Event/ISFParticle.h"
23 // MCTruth includes
26 // McEventCollection
28 // Geant4 includes
29 #include "G4PrimaryParticle.hh"
30 #include "G4Event.hh"
31 #include "G4Geantino.hh"
32 #include "G4ChargedGeantino.hh"
33 #include "G4ParticleTable.hh"
34 #include "G4LorentzVector.hh"
35 #include "G4TransportationManager.hh"
36 // HepMC includes
37 #include "AtlasHepMC/GenParticle.h"
38 #include "AtlasHepMC/GenEvent.h"
39 #include "AtlasHepMC/GenVertex.h"
40 // CLHEP includes
41 #include "CLHEP/Geometry/Point3D.h"
42 #include "CLHEP/Geometry/Vector3D.h"
43 #include "CLHEP/Units/SystemOfUnits.h"
44 // HepPDT
45 #include "HepPDT/ParticleID.hh"
46 #include "HepPDT/DecayData.hh"
47 #include "HepPDT/ParticleDataTable.hh"
49 
51 ISF::InputConverter::InputConverter(const std::string& name, ISvcLocator* svc)
52  : base_class(name, svc)
53  , m_particlePropSvc("PartPropSvc",name)
54  , m_particleDataTable(nullptr)
55  , m_useGeneratedParticleMass(false)
56  , m_genParticleFilters(this)
57  , m_quasiStableParticlesIncluded(false)
58 {
59  // particle mass from particle data table?
60  declareProperty("UseGeneratedParticleMass",
62  "Use particle mass assigned to GenParticle.");
63  // particle filters
64  declareProperty("GenParticleFilters",
66  "Tools for filtering out GenParticles.");
67  // the particle property service
68  declareProperty("ParticlePropertyService",
70  "ParticlePropertyService to retrieve the PDT.");
71  declareProperty("QuasiStableParticlesIncluded", m_quasiStableParticlesIncluded);
72 }
73 
74 
77 {
78 }
79 
80 
81 // Athena algtool's Hooks
84 {
85  ATH_MSG_VERBOSE("initialize() begin");
86 
87  // setup PDT if requested (to get particle masses later on)
88  if (!m_useGeneratedParticleMass) {
89  ATH_CHECK(m_particlePropSvc.retrieve());
90  m_particleDataTable = m_particlePropSvc->PDT();
91  if (!m_particleDataTable) {
92  ATH_MSG_FATAL( "Could not get ParticleDataTable from " << m_particlePropSvc << ". Abort" );
93  return StatusCode::FAILURE;
94  }
95  }
96 
97  if (!m_genParticleFilters.empty()) {
98  ATH_CHECK(m_genParticleFilters.retrieve());
99  }
100 
101  ATH_MSG_VERBOSE("initialize() successful");
102  return StatusCode::SUCCESS;
103 }
104 
105 
109 {
110  ATH_MSG_DEBUG("Finalizing ...");
111  return StatusCode::SUCCESS;
112 }
113 
114 
119  ISF::ISFParticleContainer& simParticles) const
120 {
121  for ( auto eventPtr : inputGenEvents ) {
122  // skip empty events
123  if (eventPtr == nullptr) { continue; }
124 
125  ATH_MSG_DEBUG("Starting conversion of GenEvent with"
126  " signal_process_id=" << HepMC::signal_process_id(eventPtr) <<
127  " and event_number=" << eventPtr->event_number() );
128 
129  // new collection containing all gen particles that passed filters
130  bool legacyOrdering = true; // FIXME: this is only to keep the same order of particles
131  // as the prior 'StackFiller' implementation
132  // TODO: remove this functionality from the
133  // getSelectedParticles function once
134  // happy with the results
135  const auto passedGenParticles = getSelectedParticles(*eventPtr, legacyOrdering);
136 
137  for ( auto& genPartPtr : passedGenParticles ) {
138  ATH_MSG_VERBOSE("Picking up following GenParticle for conversion to ISFParticle: " << genPartPtr);
139  auto simParticlePtr = convertParticle(genPartPtr);
140  if (!simParticlePtr) {
141  ATH_MSG_ERROR("Error while trying to convert input generator particles. Aborting.");
142  return StatusCode::FAILURE;
143  }
144  // add to collection that will be returned
145  simParticles.push_back(simParticlePtr);
146 
147  } // loop over passed gen particles
148 
149  } // loop over gen events
150 
151  ATH_MSG_DEBUG( "Created initial simulation particle collection with size " << simParticles.size() );
152 
153  return StatusCode::SUCCESS;
154 }
155 
157  McEventCollection& inputGenEvents, G4Event& outputG4Event,
158  McEventCollection& shadowGenEvents) const {
159  ISF::ISFParticleContainer simParticleList{}; // particles for ISF simulation
160  ATH_CHECK(this->convert(inputGenEvents, simParticleList));
161  //Convert from ISFParticleContainer to ConstISFParticleVector
162  ISF::ISFParticleVector simParticleVector{
163  std::make_move_iterator(std::begin(simParticleList)),
164  std::make_move_iterator(std::end(simParticleList))
165  };
166  HepMC::GenEvent* shadowGenEvent =
167  !shadowGenEvents.empty()
168  ? static_cast<HepMC::GenEvent*>(shadowGenEvents.back())
169  : nullptr;
170  this->ISF_to_G4Event(outputG4Event, simParticleVector, inputGenEvents.back(),
171  shadowGenEvent);
172  return StatusCode::SUCCESS;
173 }
174 
176  McEventCollection& inputGenEvents, G4Event& outputG4Event) const {
177  ISF::ISFParticleContainer simParticleList{}; // particles for ISF simulation
178  ATH_CHECK(this->convert(inputGenEvents, simParticleList));
179  //Convert from ISFParticleContainer to ConstISFParticleVector
180  ISF::ISFParticleVector simParticleVector{
181  std::make_move_iterator(std::begin(simParticleList)),
182  std::make_move_iterator(std::end(simParticleList))
183  };
184  this->ISF_to_G4Event(outputG4Event, simParticleVector, inputGenEvents.back(),
185  nullptr);
186  return StatusCode::SUCCESS;
187 }
188 
190 #ifdef HEPMC3
191 std::vector<HepMC::GenParticlePtr>
192 ISF::InputConverter::getSelectedParticles(HepMC::GenEvent& evnt, bool legacyOrdering) const {
193  auto allGenPartBegin = evnt.particles().begin();
194  auto allGenPartEnd = evnt.particles().end();
195 
196  // reserve destination container with maximum size, i.e. number of particles in input event
197  std::vector<HepMC::GenParticlePtr> passedGenParticles{};
198  size_t maxParticles = std::distance(allGenPartBegin, allGenPartEnd);
199  passedGenParticles.reserve(maxParticles);
200 
201  if (m_useShadowEvent) {
202  if (legacyOrdering) {
203  // FIXME: remove this block and the 'legacyOrdering' flag
204  // once we don't need the legacy order any longer
205  for (auto vtx: evnt.vertices() ) {
206  std::copy_if (vtx->particles_out().begin(),
207  vtx->particles_out().end(),
208  std::back_inserter(passedGenParticles),
209  [](HepMC::GenParticlePtr p){return p->attribute<HepMC3::IntAttribute>("ShadowParticleId");});
210  }
211  }
212  else {
213  std::copy_if (allGenPartBegin,
214  allGenPartEnd,
215  std::back_inserter(passedGenParticles),
216  [](HepMC::GenParticlePtr p){return p->attribute<HepMC3::IntAttribute>("ShadowParticleId");});
217  }
218  }
219  else {
220  if (legacyOrdering) {
221  // FIXME: remove this block and the 'legacyOrdering' flag
222  // once we don't need the legacy order any longer
223  for (auto vtx: evnt.vertices() ) {
224  std::copy_if (vtx->particles_out().begin(),
225  vtx->particles_out().end(),
226  std::back_inserter(passedGenParticles),
227  [this](HepMC::GenParticlePtr p){return this->passesFilters(std::const_pointer_cast<const HepMC3::GenParticle>(p));});
228  }
229  }
230  else {
231  std::copy_if (allGenPartBegin,
232  allGenPartEnd,
233  std::back_inserter(passedGenParticles),
234  [this](HepMC::GenParticlePtr p){return this->passesFilters(std::const_pointer_cast<const HepMC3::GenParticle>(p));});
235  }
236  }
237 
238  passedGenParticles.shrink_to_fit();
239 
240  return passedGenParticles;
241 }
242 #else
243 std::vector<HepMC::GenParticlePtr>
244 ISF::InputConverter::getSelectedParticles(HepMC::GenEvent& evnt, bool legacyOrdering) const {
245  auto allGenPartBegin = evnt.particles_begin();
246  auto allGenPartEnd = evnt.particles_end();
247 
248  // reserve destination container with maximum size, i.e. number of particles in input event
249  std::vector<HepMC::GenParticlePtr> passedGenParticles{};
250  size_t maxParticles = std::distance(allGenPartBegin, allGenPartEnd);
251  passedGenParticles.reserve(maxParticles);
252 
253  if (legacyOrdering) {
254  // FIXME: remove this block and the 'legacyOrdering' flag
255  // once we don't need the legacy order any longer
256  auto vtxIt = evnt.vertices_begin();
257  auto vtxItEnd = evnt.vertices_end();
258  for ( ; vtxIt != vtxItEnd; ++vtxIt ) {
259  const auto vtxPtr = *vtxIt;
260  std::copy_if (vtxPtr->particles_begin(HepMC::children),
261  vtxPtr->particles_end(HepMC::children),
262  std::back_inserter(passedGenParticles),
263  [this](HepMC::GenParticlePtr p){return this->passesFilters(*p);});
264  }
265  }
266  else {
267  std::copy_if (allGenPartBegin,
268  allGenPartEnd,
269  std::back_inserter(passedGenParticles),
270  [this](HepMC::GenParticlePtr p){return this->passesFilters(*p);});
271  }
272 
273  passedGenParticles.shrink_to_fit();
274 
275  return passedGenParticles;
276 }
277 #endif
278 
279 
283  if (!genPartPtr) { return nullptr; }
284 
285  auto pVertex = genPartPtr->production_vertex();
286  if (!pVertex) {
287  ATH_MSG_ERROR("Unable to convert following generator particle due to missing production vertex for: " << genPartPtr);
288  return nullptr;
289  }
290  auto parentEvent = genPartPtr->parent_event();
291  if (!parentEvent) {
292  ATH_MSG_ERROR("Cannot convert a GenParticle without a parent GenEvent into an ISFParticle!!!");
293  return nullptr;
294  }
295 
296  const Amg::Vector3D pos(pVertex->position().x(), pVertex->position().y(), pVertex->position().z());
297  const auto& pMomentum(genPartPtr->momentum());
298  const Amg::Vector3D mom(pMomentum.px(), pMomentum.py(), pMomentum.pz());
299 #ifdef HEPMC3
300  const double pMass = this->getParticleMass(genPartPtr);
301 #else
302  const double pMass = this->getParticleMass(*genPartPtr);
303 #endif
304  double e=pMomentum.e();
305  if (e>1) { //only test for >1 MeV in momentum
306  double px=pMomentum.px();
307  double py=pMomentum.py();
308  double pz=pMomentum.pz();
309  double teste=std::sqrt(px*px + py*py + pz*pz + pMass*pMass);
310  if (std::abs(e-teste)>0.01*e) {
311  ATH_MSG_WARNING("Difference in energy for: " << genPartPtr<<" Morg="<<pMomentum.m()<<" Mmod="<<pMass<<" Eorg="<<e<<" Emod="<<teste);
312  }
313  if (MC::isDecayed(genPartPtr) && pVertex && genPartPtr->end_vertex()) { //check for possible changes of gamma for quasi stable particles
314  const auto& prodVtx = genPartPtr->production_vertex()->position();
315  const auto& endVtx = genPartPtr->end_vertex()->position();
316  CLHEP::Hep3Vector dist3D(endVtx.x()-prodVtx.x(), endVtx.y()-prodVtx.y(), endVtx.z()-prodVtx.z());
317 
318  if (dist3D.mag()>1*Gaudi::Units::mm) {
319  CLHEP::HepLorentzVector mom( pMomentum.x(), pMomentum.y(), pMomentum.z(), pMomentum.t() );
320  double gamma_org=mom.gamma();
321  mom.setE(teste);
322  double gamma_new=mom.gamma();
323 
324  if (std::abs(gamma_new-gamma_org)/(gamma_new+gamma_org)>0.001) {
325  ATH_MSG_WARNING("Difference in boost gamma for Quasi stable particle "<<genPartPtr);
326  ATH_MSG_WARNING(" gamma(m="<<mom.m()<<")="<<gamma_org<<" gamma(m="<<pMass<<")="<<gamma_new);
327  } else {
328  ATH_MSG_VERBOSE("Quasi stable particle "<<genPartPtr);
329  ATH_MSG_VERBOSE(" gamma(m="<<mom.m()<<")="<<gamma_org<<" gamma(m="<<pMass<<")="<<gamma_new);
330  }
331  }
332  }
333  }
334 
335  const int pPdgId = genPartPtr->pdg_id();
336  const double charge = HepPDT::ParticleID(pPdgId).charge();
337  const double pTime = pVertex->position().t() / Gaudi::Units::c_light;
340  const auto pBarcode = HepMC::barcode(genPartPtr);
341  const auto particleID = HepMC::uniqueID(genPartPtr);
342  auto tBinding = std::make_unique<ISF::TruthBinding>(genPartPtr);
343 
344  auto hmpl = std::make_unique<HepMcParticleLink>(particleID, parentEvent->event_number(), HepMcParticleLink::IS_EVENTNUM, HepMcParticleLink::IS_ID);
345 
346  auto sParticle = std::make_unique<ISF::ISFParticle>( std::move(pos),
347  std::move(mom),
348  pMass,
349  charge,
350  pPdgId,
351  genPartPtr->status(),
352  pTime,
353  origin,
354  particleID,
355  pBarcode,
356  tBinding.release(),
357  hmpl.release() );
358  return sParticle.release();
359 }
360 
361 
363 #ifdef HEPMC3
364 double
366  // default value: generated particle mass
367  double mass = part->generated_mass();
368  ATH_MSG_VERBOSE("part->generated_mass, mass="<<mass);
369 
370  // 1. use PDT mass?
371  if ( !m_useGeneratedParticleMass ) {
372  const int absPDG = std::abs(part->pdg_id());
373  HepPDT::ParticleData const *pData = (m_particleDataTable)
374  ? m_particleDataTable->particle(absPDG)
375  : nullptr;
376  if (pData) {
377  mass = pData->mass();
378  ATH_MSG_VERBOSE("using pData mass, mass="<<mass);
379  }
380  else {
381  ATH_MSG_WARNING( "Unable to find mass of particle with PDG ID '" << absPDG << "' in ParticleDataTable. Will set mass to generated_mass: " << mass);
382  }
383  }
384  return mass;
385 }
386 #else
387 double
389 {
390  // default value: generated particle mass
391  double mass = part.generated_mass();
392  ATH_MSG_VERBOSE("part.generated_mass, mass="<<mass);
393 
394  // 1. use PDT mass?
395  if ( !m_useGeneratedParticleMass ) {
396  const int absPDG = std::abs(part.pdg_id());
397  HepPDT::ParticleData const *pData = (m_particleDataTable)
398  ? m_particleDataTable->particle(absPDG)
399  : nullptr;
400  if (pData) {
401  mass = pData->mass();
402  ATH_MSG_VERBOSE("using pData mass, mass="<<mass);
403  }
404  else {
405  ATH_MSG_WARNING( "Unable to find mass of particle with PDG ID '" << absPDG << "' in ParticleDataTable. Will set mass to generated_mass: " << mass);
406  }
407  }
408  return mass;
409 }
410 #endif
411 
412 
414 #ifdef HEPMC3
415 bool
417 {
418  // TODO: implement this as a std::find_if with a lambda function
419  for ( const auto& filter : m_genParticleFilters ) {
420  // determine if the particle passes current filter
421  bool passFilter = filter->pass(part);
422  ATH_MSG_VERBOSE("GenParticleFilter '" << filter.typeAndName() << "' returned: "
423  << (passFilter ? "true, will keep particle."
424  : "false, will remove particle."));
425  const auto& momentum = part->momentum();
426  ATH_MSG_VERBOSE("Particle: ("
427  <<momentum.px()<<", "
428  <<momentum.py()<<", "
429  <<momentum.pz()<<"), pdgCode: "
430  <<part->pdg_id() );
431 
432  if (!passFilter) {
433  return false;
434  }
435  }
436 
437  return true;
438 }
439 #else
440 bool
442 {
443  // TODO: implement this as a std::find_if with a lambda function
444  for ( const auto& filter : m_genParticleFilters ) {
445  // determine if the particle passes current filter
446  bool passFilter = filter->pass(part);
447  ATH_MSG_VERBOSE("GenParticleFilter '" << filter.typeAndName() << "' returned: "
448  << (passFilter ? "true, will keep particle."
449  : "false, will remove particle."));
450  const auto& momentum = part.momentum();
451  ATH_MSG_VERBOSE("Particle: ("
452  <<momentum.px()<<", "
453  <<momentum.py()<<", "
454  <<momentum.pz()<<"), pdgCode: "
455  <<part.pdg_id() );
456 
457  if (!passFilter) {
458  return false;
459  }
460  }
461 
462  return true;
463 }
464 #endif
465 
466 
467 //________________________________________________________________________
469  G4Event& event, const ISF::ISFParticleVector& ispVector,
470  HepMC::GenEvent* genEvent, HepMC::GenEvent* shadowGenEvent,
471  bool useHepMC) const {
472  // G4Event *g4evt = new G4Event(ctx.eventID().event_number());
473 
474  // retrieve world solid (volume)
475  const G4VSolid *worldSolid = G4TransportationManager::GetTransportationManager()->GetNavigatorForTracking()->GetWorldVolume()->GetLogicalVolume()->GetSolid();
476 
477  for ( ISF::ISFParticle *ispPtr: ispVector ) {
478  ISF::ISFParticle &isp = *ispPtr;
479  if ( !isInsideG4WorldVolume(isp, worldSolid) ) {
480  ATH_MSG_WARNING("Unable to convert ISFParticle to G4PrimaryParticle!");
481  ATH_MSG_WARNING(" ISFParticle: " << isp );
482  if (worldSolid) {
483  ATH_MSG_WARNING(" is outside Geant4 world volume: ");
484  worldSolid->DumpInfo();
485  G4cout << std::flush;
486  }
487  else {
488  ATH_MSG_WARNING(" is outside Geant4 world volume.");
489  }
490  continue;
491  }
492  this->addG4PrimaryVertex(event, isp, useHepMC, shadowGenEvent);
493  }
494 
495  AtlasG4EventUserInfo* atlasG4EvtUserInfo =
496  dynamic_cast<AtlasG4EventUserInfo*>(event.GetUserInformation());
497  if (!atlasG4EvtUserInfo) {
498  atlasG4EvtUserInfo = new AtlasG4EventUserInfo;
499  event.SetUserInformation(atlasG4EvtUserInfo);
500  }
501  atlasG4EvtUserInfo->SetLastProcessedTrackID(0); // TODO Check if it is better to set this to -1 initially
502  atlasG4EvtUserInfo->SetLastProcessedStep(0); // TODO Check if it is better to set this to -1 initially
503  atlasG4EvtUserInfo->SetHepMCEvent(genEvent);
504 }
505 
506 //________________________________________________________________________
507 const G4ParticleDefinition* ISF::InputConverter::getG4ParticleDefinition(int pdgcode) const
508 {
510  if (pdgcode==998) {
511  return G4ChargedGeantino::Definition();
512  }
513  if (pdgcode==999) {
514  return G4Geantino::GeantinoDefinition();
515  }
517  G4ParticleTable *ptable = G4ParticleTable::GetParticleTable();
518  if (ptable) {
519  return ptable->FindParticle(pdgcode);
520  }
521  ATH_MSG_ERROR("getG4ParticleDefinition - Failed to retrieve G4ParticleTable!");
522  return nullptr;
523 }
524 
525 double SetProperTimeFromDetectorFrameDecayLength(G4PrimaryParticle& g4particle,const double GeneratorDecayLength)
526 {
527  //particle with velocity v travels distance l in time t=l/v
528  //proper time: c^2 tau^2 = c^2 t^2 - l^2 = l^2/c^2 * (1/beta^2 -1)
529  //beta^2 = p^2/E^2 with particle momentum p and energy E; E^2=m^2 + p^2
530  //tau^2 = l^2/c^2 * m^2/p^2
531  const double p2=std::pow(g4particle.GetTotalMomentum(),2); //magnitude of particle momentum squared
532  const double m2=std::pow(g4particle.GetMass(),2); //mass^2 of particle
533  const double l2=std::pow(GeneratorDecayLength,2); //distance^2 of particle decay length
534  const double tau2=l2*m2/p2/CLHEP::c_squared;
535  const double tau=std::sqrt(tau2);
536  g4particle.SetProperTime( tau );
537  return tau;
538 }
539 
540 //________________________________________________________________________
541 #ifdef HEPMC3
542 G4PrimaryParticle* ISF::InputConverter::getDaughterG4PrimaryParticle(const HepMC::GenParticlePtr& genpart, bool makeLinkToTruth) const{
543  ATH_MSG_VERBOSE("Creating G4PrimaryParticle from GenParticle.");
544 
545  const G4ParticleDefinition *particleDefinition = this->getG4ParticleDefinition(genpart->pdg_id());
546 
547  if (particleDefinition==nullptr) {
548  ATH_MSG_ERROR("ISF_to_G4Event particle conversion failed. ISF_Particle PDG code = " << genpart->pdg_id() <<
549  "\n This usually indicates a problem with the evgen step.\n" <<
550  "Please report this to the Generators group, mentioning the release and generator used for evgen and the PDG code above." );
551  return nullptr;
552  }
553 
554  // create new primaries and set them to the vertex
555  // G4double mass = particleDefinition->GetPDGMass();
556  auto &genpartMomentum = genpart->momentum();
557  G4double px = genpartMomentum.x();
558  G4double py = genpartMomentum.y();
559  G4double pz = genpartMomentum.z();
560 
561  std::unique_ptr<G4PrimaryParticle> g4particle = std::make_unique<G4PrimaryParticle>(particleDefinition,px,py,pz);
562 
563  if (genpart->end_vertex()) {
564  // Set the lifetime appropriately - this is slow but rigorous, and we
565  // don't want to end up with something like vertex time that we have
566  // to validate for every generator on earth...
567  const auto& prodVtx = genpart->production_vertex()->position();
568  const auto& endVtx = genpart->end_vertex()->position();
569  //const G4LorentzVector lv0 ( prodVtx.x(), prodVtx.y(), prodVtx.z(), prodVtx.t() );
570  //const G4LorentzVector lv1 ( endVtx.x(), endVtx.y(), endVtx.z(), endVtx.t() );
571  //Old calculation, not taken because vertex information is not sufficiently precise
572  //g4particle->SetProperTime( (lv1-lv0).mag()/Gaudi::Units::c_light );
573 
574  CLHEP::Hep3Vector dist3D(endVtx.x()-prodVtx.x(), endVtx.y()-prodVtx.y(), endVtx.z()-prodVtx.z());
575  double tau=SetProperTimeFromDetectorFrameDecayLength(*g4particle,dist3D.mag());
576 
577  if (msgLvl(MSG::VERBOSE)) {
578  double pmag2=g4particle->GetTotalMomentum(); //magnitude of particle momentum
579  pmag2*=pmag2; //magnitude of particle momentum squared
580  double e2=g4particle->GetTotalEnergy(); //energy of particle
581  e2*=e2; //energy of particle squared
582  double beta2=pmag2/e2; //beta^2=v^2/c^2 for particle
583  double tau2=dist3D.mag2()*(1/beta2-1)/Gaudi::Units::c_light/Gaudi::Units::c_light;
584  ATH_MSG_VERBOSE("lifetime tau(beta)="<<std::sqrt(tau2)<<" tau="<<tau);
585  }
586  if (m_quasiStableParticlesIncluded) {
587  ATH_MSG_VERBOSE( "Detected primary particle with end vertex." );
588  ATH_MSG_VERBOSE( "Will add the primary particle set on." );
589  ATH_MSG_VERBOSE( "Primary Particle: " << genpart );
590  ATH_MSG_VERBOSE( "Number of daughters: " << genpart->end_vertex()->particles_out().size()<<" at position "<<genpart->end_vertex() );
591  }
592  else {
593  ATH_MSG_WARNING( "Detected primary particle with end vertex." );
594  ATH_MSG_WARNING( "Will add the primary particle set on." );
595  ATH_MSG_WARNING( "Primary Particle: " << genpart );
596  ATH_MSG_WARNING( "Number of daughters : " << genpart->end_vertex()->particles_out().size()<<" at position "<<genpart->end_vertex() );
597  }
598  // Add all necessary daughter particles
599  for ( auto daughter: genpart->end_vertex()->particles_out() ) {
600  if (m_quasiStableParticlesIncluded) {
601  ATH_MSG_VERBOSE ( "Attempting to add daughter particle : " << daughter );
602  }
603  else {
604  ATH_MSG_WARNING ( "Attempting to add daughter particle: " << daughter );
605  }
606  G4PrimaryParticle *daughterG4Particle = this->getDaughterG4PrimaryParticle( daughter, makeLinkToTruth );
607  if (!daughterG4Particle) {
608  ATH_MSG_ERROR("Bailing out of loop over daughters of particle: "<<
609  " due to errors - will not return G4Particle.");
610  return nullptr;
611  }
612  g4particle->SetDaughter( daughterG4Particle );
613  }
614  }
615 
616  if (makeLinkToTruth) {
617  // Set the user information for this primary to point to the HepMcParticleLink...
618  std::unique_ptr<PrimaryParticleInformation> primaryPartInfo = std::make_unique<PrimaryParticleInformation>(genpart);
619  primaryPartInfo->SetRegenerationNr(0);
620  ATH_MSG_VERBOSE("Making primary down the line with barcode " << primaryPartInfo->GetParticleUniqueID());
621  g4particle->SetUserInformation(primaryPartInfo.release());
622  }
623 
624  return g4particle.release();
625 }
626 
627 //________________________________________________________________________
629  ATH_MSG_VERBOSE("Creating G4PrimaryParticle from GenParticle.");
630 
631  const G4ParticleDefinition *particleDefinition = this->getG4ParticleDefinition(genpart->pdg_id());
632 
633  if (particleDefinition==nullptr) {
634  ATH_MSG_ERROR("ISF_to_G4Event particle conversion failed. ISF_Particle PDG code = " << genpart->pdg_id() <<
635  "\n This usually indicates a problem with the evgen step.\n" <<
636  "Please report this to the Generators group, mentioning the release and generator used for evgen and the PDG code above." );
637  return nullptr;
638  }
639 
640  // create new primaries and set them to the vertex
641  // G4double mass = particleDefinition->GetPDGMass();
642  auto &genpartMomentum = genpart->momentum();
643  G4double px = genpartMomentum.x();
644  G4double py = genpartMomentum.y();
645  G4double pz = genpartMomentum.z();
646 
647  std::unique_ptr<G4PrimaryParticle> g4particle = std::make_unique<G4PrimaryParticle>(particleDefinition,px,py,pz);
648 
649  if (genpart->end_vertex()) {
650  // Set the lifetime appropriately - this is slow but rigorous, and we
651  // don't want to end up with something like vertex time that we have
652  // to validate for every generator on earth...
653  const auto& prodVtx = genpart->production_vertex()->position();
654  const auto& endVtx = genpart->end_vertex()->position();
655  //const G4LorentzVector lv0 ( prodVtx.x(), prodVtx.y(), prodVtx.z(), prodVtx.t() );
656  //const G4LorentzVector lv1 ( endVtx.x(), endVtx.y(), endVtx.z(), endVtx.t() );
657  //Old calculation, not taken because vertex information is not sufficiently precise
658  //g4particle->SetProperTime( (lv1-lv0).mag()/Gaudi::Units::c_light );
659 
660  CLHEP::Hep3Vector dist3D(endVtx.x()-prodVtx.x(), endVtx.y()-prodVtx.y(), endVtx.z()-prodVtx.z());
661  double tau=SetProperTimeFromDetectorFrameDecayLength(*g4particle,dist3D.mag());
662 
663  if (msgLvl(MSG::VERBOSE)) {
664  double pmag2=g4particle->GetTotalMomentum(); //magnitude of particle momentum
665  pmag2*=pmag2; //magnitude of particle momentum squared
666  double e2=g4particle->GetTotalEnergy(); //energy of particle
667  e2*=e2; //energy of particle squared
668  double beta2=pmag2/e2; //beta^2=v^2/c^2 for particle
669  double tau2=dist3D.mag2()*(1/beta2-1)/Gaudi::Units::c_light/Gaudi::Units::c_light;
670  ATH_MSG_VERBOSE("lifetime tau(beta)="<<std::sqrt(tau2)<<" tau="<<tau);
671  }
672  if (m_quasiStableParticlesIncluded) {
673  ATH_MSG_VERBOSE( "Detected primary particle with end vertex." );
674  ATH_MSG_VERBOSE( "Will add the primary particle set on." );
675  ATH_MSG_VERBOSE( "Primary Particle: " << genpart );
676  ATH_MSG_VERBOSE( "Number of daughters : " << genpart->end_vertex()->particles_out().size()<<" at position "<<genpart->end_vertex() );
677  }
678  else {
679  ATH_MSG_WARNING( "Detected primary particle with end vertex." );
680  ATH_MSG_WARNING( "Will add the primary particle set on." );
681  ATH_MSG_WARNING( "Primary Particle: " << genpart );
682  ATH_MSG_WARNING( "Number of daughters: " << genpart->end_vertex()->particles_out().size()<<" at position "<<genpart->end_vertex() );
683  }
684  // Add all necessary daughter particles
685  for ( auto daughter: genpart->end_vertex()->particles_out() ) {
686  if (m_quasiStableParticlesIncluded) {
687  ATH_MSG_VERBOSE ( "Attempting to add daughter particle: " << daughter );
688  }
689  else {
690  ATH_MSG_WARNING ( "Attempting to add daughter particle: " << daughter );
691  }
692  G4PrimaryParticle *daughterG4Particle = this->getDaughterG4PrimaryParticle( daughter );
693  if (!daughterG4Particle) {
694  ATH_MSG_ERROR("Bailing out of loop over daughters of particle due to errors - will not return G4Particle.");
695  return nullptr;
696  }
697  g4particle->SetDaughter( daughterG4Particle );
698  }
699  }
700 
701  return g4particle.release();
702 }
703 #else
704 G4PrimaryParticle* ISF::InputConverter::getDaughterG4PrimaryParticle(HepMC::GenParticle& genpart, bool makeLinkToTruth) const
705 {
706  ATH_MSG_VERBOSE("Creating G4PrimaryParticle from GenParticle.");
707 
708  const G4ParticleDefinition *particleDefinition = this->getG4ParticleDefinition(genpart.pdg_id());
709 
710  if (particleDefinition==nullptr) {
711  ATH_MSG_ERROR("ISF_to_G4Event particle conversion failed. ISF_Particle PDG code = " << genpart.pdg_id() <<
712  "\n This usually indicates a problem with the evgen step.\n" <<
713  "Please report this to the Generators group, mentioning the release and generator used for evgen and the PDG code above." );
714  return nullptr;
715  }
716 
717  // create new primaries and set them to the vertex
718  // G4double mass = particleDefinition->GetPDGMass();
719  auto &genpartMomentum = genpart.momentum();
720  G4double px = genpartMomentum.x();
721  G4double py = genpartMomentum.y();
722  G4double pz = genpartMomentum.z();
723 
724  std::unique_ptr<G4PrimaryParticle> g4particle = std::make_unique<G4PrimaryParticle>(particleDefinition,px,py,pz);
725 
726  if (genpart.end_vertex()) {
727  // Set the lifetime appropriately - this is slow but rigorous, and we
728  // don't want to end up with something like vertex time that we have
729  // to validate for every generator on earth...
730  const auto& prodVtx = genpart.production_vertex()->position();
731  const auto& endVtx = genpart.end_vertex()->position();
732  //const G4LorentzVector lv0 ( prodVtx.x(), prodVtx.y(), prodVtx.z(), prodVtx.t() );
733  //const G4LorentzVector lv1 ( endVtx.x(), endVtx.y(), endVtx.z(), endVtx.t() );
734  //Old calculation, not taken because vertex information is not sufficiently precise
735  //g4particle->SetProperTime( (lv1-lv0).mag()/Gaudi::Units::c_light );
736 
737  CLHEP::Hep3Vector dist3D(endVtx.x()-prodVtx.x(), endVtx.y()-prodVtx.y(), endVtx.z()-prodVtx.z());
738  double tau=SetProperTimeFromDetectorFrameDecayLength(*g4particle,dist3D.mag());
739 
740  if (msgLvl(MSG::VERBOSE)) {
741  double pmag2=g4particle->GetTotalMomentum(); //magnitude of particle momentum
742  pmag2*=pmag2; //magnitude of particle momentum squared
743  double e2=g4particle->GetTotalEnergy(); //energy of particle
744  e2*=e2; //energy of particle squared
745  double beta2=pmag2/e2; //beta^2=v^2/c^2 for particle
746  double tau2=dist3D.mag2()*(1/beta2-1)/Gaudi::Units::c_light/Gaudi::Units::c_light;
747  ATH_MSG_VERBOSE("lifetime tau(beta)="<<std::sqrt(tau2)<<" tau="<<tau);
748  }
749  if (m_quasiStableParticlesIncluded) {
750  ATH_MSG_VERBOSE( "Detected primary particle with end vertex." );
751  ATH_MSG_VERBOSE( "Will add the primary particle set on." );
752  ATH_MSG_VERBOSE( "Primary Particle: " << genpart );
753  ATH_MSG_VERBOSE( "Number of daughters: " << genpart.end_vertex()->particles_out_size()<<" at position "<<genpart.end_vertex());
754  }
755  else {
756  ATH_MSG_WARNING( "Detected primary particle with end vertex." );
757  ATH_MSG_WARNING( "Will add the primary particle set on." );
758  ATH_MSG_WARNING( "Primary Particle: " << genpart );
759  ATH_MSG_WARNING( "Number of daughters: " << genpart.end_vertex()->particles_out_size()<<" at position "<<genpart.end_vertex() );
760  }
761  // Add all necessary daughter particles
762  for ( auto daughterIter=genpart.end_vertex()->particles_out_const_begin();
763  daughterIter!=genpart.end_vertex()->particles_out_const_end(); ++daughterIter ) {
764  if (m_quasiStableParticlesIncluded) {
765  ATH_MSG_VERBOSE ( "Attempting to add daughter particle: " << **daughterIter );
766  }
767  else {
768  ATH_MSG_WARNING ( "Attempting to add daughter particle: " << **daughterIter );
769  }
770  G4PrimaryParticle *daughterG4Particle = this->getDaughterG4PrimaryParticle( **daughterIter, makeLinkToTruth );
771  if (!daughterG4Particle) {
772  ATH_MSG_ERROR("Bailing out of loop over daughters of particle due to errors - will not return G4Particle.");
773  return nullptr;
774  }
775  g4particle->SetDaughter( daughterG4Particle );
776  }
777  }
778 
779  if (makeLinkToTruth) {
780  // Set the user information for this primary to point to the HepMcParticleLink...
781  std::unique_ptr<PrimaryParticleInformation> primaryPartInfo = std::make_unique<PrimaryParticleInformation>(&genpart);
782  primaryPartInfo->SetRegenerationNr(0);
783  ATH_MSG_VERBOSE("Making primary down the line with barcode " << primaryPartInfo->GetParticleUniqueID());
784  g4particle->SetUserInformation(primaryPartInfo.release());
785  }
786 
787  return g4particle.release();
788 }
789 #endif
790 
791 //________________________________________________________________________
793  const HepMC::ConstGenParticlePtr& p2) const // TODO Helper method?
794 {
795  return (HepMC::barcode(p1) == HepMC::barcode(p2))
796  && (p1->status() == p2->status())
797  && (p1->pdg_id() == p2->pdg_id())
798  && ((p1->momentum().px()) == (p2->momentum().px()))
799  && ((p1->momentum().py()) == (p2->momentum().py()))
800  && ((p1->momentum().pz()) == (p2->momentum().pz()))
801  && (float(p1->momentum().m()) == float(p2->momentum().m()));
802 }
803 
804 //________________________________________________________________________
805 HepMC::GenParticlePtr ISF::InputConverter::findShadowParticle(const HepMC::ConstGenParticlePtr& genParticle, HepMC::GenEvent *shadowGenEvent) const // TODO Helper method?
806 {
807  if (!shadowGenEvent) {
808  ATH_MSG_FATAL ("Found status==2 GenParticle with no end vertex and shadow GenEvent is missing - something is wrong here!");
809  abort();
810  }
811 #ifdef HEPMC3
812  // TODO in the future switch to using an Attribute which stores the shadow GenParticlePtr directly.
813  const int shadowId = genParticle->attribute<HepMC3::IntAttribute>("ShadowParticleId")->value();
814  for (auto& shadowParticle : shadowGenEvent->particles()) {
815  if (shadowParticle->id() == shadowId && matchedGenParticles(genParticle, shadowParticle) ) { return shadowParticle; }
816  }
817  return std::make_shared<HepMC::GenParticle>();
818 #else
819  for (HepMC::GenEvent::particle_iterator pitr=shadowGenEvent->particles_begin(); pitr != shadowGenEvent->particles_end(); ++pitr) {
820  HepMC::GenParticlePtr shadowParticle = (*pitr);
821  if (matchedGenParticles(genParticle, shadowParticle) ) { return shadowParticle; }
822  }
823  return nullptr;
824 #endif
825 
826 }
827 
828 #ifdef HEPMC3
829 //________________________________________________________________________
830 void ISF::InputConverter::processPredefinedDecays(const HepMC::ConstGenParticlePtr& genpart, ISF::ISFParticle& isp, G4PrimaryParticle* g4particle) const
831 {
835  const auto& prodVtx = genpart->production_vertex()->position();
836  const auto& endVtx = genpart->end_vertex()->position();
837 
838  CLHEP::Hep3Vector dist3D(endVtx.x()-prodVtx.x(), endVtx.y()-prodVtx.y(), endVtx.z()-prodVtx.z());
839  double tau=SetProperTimeFromDetectorFrameDecayLength(*g4particle,dist3D.mag());
840 
841  if (msgLvl(MSG::VERBOSE)) {
842  double pmag2=g4particle->GetTotalMomentum(); //magnitude of particle momentum
843  pmag2*=pmag2; //magnitude of particle momentum squared
844  double e2=g4particle->GetTotalEnergy(); //energy of particle
845  e2*=e2; //energy^2 of particle
846  double beta2=pmag2/e2; //beta^2=v^2/c^2 for particle
847  double mass2=g4particle->GetMass(); //mass of particle
848  mass2*=mass2; //mass^2 of particle
849 
850  double tau2=dist3D.mag2()*(1/beta2-1)/Gaudi::Units::c_squared;
851 
852  const G4LorentzVector lv0( prodVtx.x(), prodVtx.y(), prodVtx.z(), prodVtx.t() );
853  const G4LorentzVector lv1( endVtx.x(), endVtx.y(), endVtx.z(), endVtx.t() );
854  //Old calculation, not taken because vertex information is not sufficiently precise
855  //g4particle->SetProperTime( (lv1-lv0).mag()/Gaudi::Units::c_light );
856  G4LorentzVector dist4D(lv1);
857  dist4D-=lv0;
858 
859  double dist4Dgamma=std::numeric_limits<double>::infinity();
860  if (dist4D.t()>0 && dist4D.mag2()>0) {
861  dist4Dgamma=dist4D.gamma();
862  } else {
863  ATH_MSG_VERBOSE( "dist4D t="<<dist4D.t()<<" mag2="<<dist4D.mag2());
864  }
865 
866  G4LorentzVector fourmom(g4particle->GetMomentum(),g4particle->GetTotalEnergy());
867  double fourmomgamma=std::numeric_limits<double>::infinity();
868  if (fourmom.t()>0 && fourmom.mag2()>0) {
869  fourmomgamma=fourmom.gamma();
870  } else {
871  ATH_MSG_VERBOSE( "fourmom t="<<fourmom.t()<<" mag2="<<fourmom.mag2());
872  }
873 
874  ATH_MSG_VERBOSE( "gammaVertex="<<dist4Dgamma<<" gammamom="<<fourmomgamma<<" gamma(beta)="<<1/std::sqrt(1-beta2)<<" lifetime tau(beta)="<<std::sqrt(tau2)<<" lifetime tau="<<tau);
875  }
876  if (m_quasiStableParticlesIncluded) {
877  ATH_MSG_VERBOSE( "Detected primary particle with end vertex." );
878  ATH_MSG_VERBOSE( "Will add the primary particle set on." );
879  ATH_MSG_VERBOSE( "ISF Particle: " << isp );
880  ATH_MSG_VERBOSE( "Primary Particle: " << genpart );
881  ATH_MSG_VERBOSE( "Number of daughters: " << genpart->end_vertex()->particles_out().size() << " at position "<< genpart->end_vertex() );
882  }
883  else {
884  ATH_MSG_WARNING( "Detected primary particle with end vertex. This should only be the case if" );
885  ATH_MSG_WARNING( "you are running with quasi-stable particle simulation enabled. This is not" );
886  ATH_MSG_WARNING( "yet validated - you'd better know what you're doing. Will add the primary" );
887  ATH_MSG_WARNING( "particle set on." );
888  ATH_MSG_WARNING( "ISF Particle: " << isp );
889  ATH_MSG_WARNING( "Primary Particle: " << genpart );
890  ATH_MSG_VERBOSE( "Number of daughters: " << genpart->end_vertex()->particles_out().size() );
891  }
892  // Add all necessary daughter particles
893  for ( auto daughter: *(genpart->end_vertex())) {
894  if (m_quasiStableParticlesIncluded) {
895  ATH_MSG_VERBOSE ( "Attempting to add daughter particle" << daughter );
896  }
897  else {
898  ATH_MSG_WARNING ( "Attempting to add daughter particle: " << daughter );
899  }
900  G4PrimaryParticle *daughterG4Particle = this->getDaughterG4PrimaryParticle( daughter );
901  if (!daughterG4Particle) {
902  ATH_MSG_FATAL("Bailing out of loop over daughters due to errors.");
903  }
904  g4particle->SetDaughter( daughterG4Particle );
905  }
906 }
907 #endif
908 
909 //________________________________________________________________________
910 void ISF::InputConverter::processPredefinedDecays(const HepMC::GenParticlePtr& genpart, ISF::ISFParticle& isp, G4PrimaryParticle* g4particle, bool makeLinkToTruth) const
911 {
915  const auto& prodVtx = genpart->production_vertex()->position();
916  const auto& endVtx = genpart->end_vertex()->position();
917 
918  CLHEP::Hep3Vector dist3D(endVtx.x()-prodVtx.x(), endVtx.y()-prodVtx.y(), endVtx.z()-prodVtx.z());
919  double tau=SetProperTimeFromDetectorFrameDecayLength(*g4particle,dist3D.mag());
920 
921  if (msgLvl(MSG::VERBOSE)) {
922  double pmag2=g4particle->GetTotalMomentum(); //magnitude of particle momentum
923  pmag2*=pmag2; //magnitude of particle momentum squared
924  double e2=g4particle->GetTotalEnergy(); //energy of particle
925  e2*=e2; //energy^2 of particle
926  double beta2=pmag2/e2; //beta^2=v^2/c^2 for particle
927  double mass2=g4particle->GetMass(); //mass of particle
928  mass2*=mass2; //mass^2 of particle
929 
930  double tau2=dist3D.mag2()*(1/beta2-1)/Gaudi::Units::c_squared;
931 
932  const G4LorentzVector lv0( prodVtx.x(), prodVtx.y(), prodVtx.z(), prodVtx.t() );
933  const G4LorentzVector lv1( endVtx.x(), endVtx.y(), endVtx.z(), endVtx.t() );
934  //Old calculation, not taken because vertex information is not sufficiently precise
935  //g4particle->SetProperTime( (lv1-lv0).mag()/Gaudi::Units::c_light );
936  G4LorentzVector dist4D(lv1);
937  dist4D-=lv0;
938 
939  double dist4Dgamma=std::numeric_limits<double>::infinity();
940  if (dist4D.t()>0 && dist4D.mag2()>0) {
941  dist4Dgamma=dist4D.gamma();
942  } else {
943  ATH_MSG_VERBOSE( "dist4D t="<<dist4D.t()<<" mag2="<<dist4D.mag2());
944  }
945 
946  G4LorentzVector fourmom(g4particle->GetMomentum(),g4particle->GetTotalEnergy());
947  double fourmomgamma=std::numeric_limits<double>::infinity();
948  if (fourmom.t()>0 && fourmom.mag2()>0) {
949  fourmomgamma=fourmom.gamma();
950  } else {
951  ATH_MSG_VERBOSE( "fourmom t="<<fourmom.t()<<" mag2="<<fourmom.mag2());
952  }
953 
954  ATH_MSG_VERBOSE( "gammaVertex="<<dist4Dgamma<<" gammamom="<<fourmomgamma<<" gamma(beta)="<<1/std::sqrt(1-beta2)<<" lifetime tau(beta)="<<std::sqrt(tau2)<<" lifetime tau="<<tau);
955  }
956  if (m_quasiStableParticlesIncluded) {
957  ATH_MSG_VERBOSE( "Detected primary particle with end vertex." );
958  ATH_MSG_VERBOSE( "Will add the primary particle set on." );
959  ATH_MSG_VERBOSE( "ISF Particle: " << isp );
960  ATH_MSG_VERBOSE( "Primary Particle: " << genpart );
961  ATH_MSG_VERBOSE( "Number of daughters: " << genpart->end_vertex()->particles_out_size() << " at position "<< genpart->end_vertex() );
962  }
963  else {
964  ATH_MSG_WARNING( "Detected primary particle with end vertex. This should only be the case if" );
965  ATH_MSG_WARNING( "you are running with quasi-stable particle simulation enabled. This is not" );
966  ATH_MSG_WARNING( "yet validated - you'd better know what you're doing. Will add the primary" );
967  ATH_MSG_WARNING( "particle set on." );
968  ATH_MSG_WARNING( "ISF Particle: " << isp );
969  ATH_MSG_WARNING( "Primary Particle: " << genpart );
970  ATH_MSG_WARNING( "Number of daughters: " << genpart->end_vertex()->particles_out_size() );
971  }
972  // Add all necessary daughter particles
973  for ( auto daughter: *(genpart->end_vertex())) {
974  if (m_quasiStableParticlesIncluded) {
975  ATH_MSG_VERBOSE ( "Attempting to add daughter particle: " << daughter );
976  }
977  else {
978  ATH_MSG_WARNING ( "Attempting to add daughter particle: " << daughter );
979  }
980 #ifdef HEPMC3
981  G4PrimaryParticle *daughterG4Particle = this->getDaughterG4PrimaryParticle( daughter, makeLinkToTruth );
982 #else
983  G4PrimaryParticle *daughterG4Particle = this->getDaughterG4PrimaryParticle( *daughter, makeLinkToTruth );
984 #endif
985  if (!daughterG4Particle) {
986  ATH_MSG_FATAL("Bailing out of loop over daughters due to errors.");
987  }
988  g4particle->SetDaughter( daughterG4Particle );
989  }
990 }
991 
992 G4PrimaryParticle* ISF::InputConverter::getG4PrimaryParticle(ISF::ISFParticle& isp, bool useHepMC, HepMC::GenEvent *shadowGenEvent) const
993 {
994  ATH_MSG_VERBOSE("Creating G4PrimaryParticle from ISFParticle.");
995 
996  auto* truthBinding = isp.getTruthBinding();
997  if (!truthBinding) {
998  G4ExceptionDescription description;
999  description << G4String("getG4PrimaryParticle: ") + "No ISF::TruthBinding associated with ISParticle (" << isp <<")";
1000  G4Exception("iGeant4::TransportTool", "NoISFTruthBinding", FatalException, description);
1001  return nullptr; //The G4Exception call above should abort the job, but Coverity does not seem to pick this up.
1002  }
1003  HepMC::GenParticlePtr currentGenPart = truthBinding->getCurrentGenParticle();
1004  HepMC::GenParticlePtr primaryGenpart = truthBinding->getPrimaryGenParticle();
1005 
1006  const G4ParticleDefinition *particleDefinition = this->getG4ParticleDefinition(isp.pdgCode());
1007 
1008  if (particleDefinition==nullptr) {
1009  ATH_MSG_ERROR("ISF_to_G4Event particle conversion failed. ISF_Particle PDG code = " << isp.pdgCode() <<
1010  "\n This usually indicates a problem with the evgen step.\n" <<
1011  "Please report this to the Generators group, mentioning the release and generator used for evgen and the PDG code above." );
1012  return nullptr;
1013  }
1014 
1015  // create new primaries and set them to the vertex
1016  // G4double mass = particleDefinition->GetPDGMass();
1017  G4double px(0.0);
1018  G4double py(0.0);
1019  G4double pz(0.0);
1020  if (useHepMC && currentGenPart) {
1021  auto &currentGenPartMomentum = currentGenPart->momentum();
1022  px = currentGenPartMomentum.x();
1023  py = currentGenPartMomentum.y();
1024  pz = currentGenPartMomentum.z();
1025  }
1026  else {
1027  auto &ispMomentum = isp.momentum();
1028  px = ispMomentum.x();
1029  py = ispMomentum.y();
1030  pz = ispMomentum.z();
1031  }
1032 
1033  std::unique_ptr<G4PrimaryParticle> g4particle = std::make_unique<G4PrimaryParticle>(particleDefinition,px,py,pz);
1034  // UserInformation
1035  std::unique_ptr<PrimaryParticleInformation> primaryPartInfo = std::make_unique<PrimaryParticleInformation>(primaryGenpart,&isp);
1036 
1040  const int regenerationNr = HepMC::StatusBased::generations(&isp);
1041  if (HepMC::BarcodeBased::generations(&isp) != regenerationNr) {
1042  ATH_MSG_WARNING ("StatusBased::generations() = " << regenerationNr << ", BarcodeBased::generations() = " << HepMC::BarcodeBased::generations(&isp) << ", isp: " << isp);
1043  }
1044  primaryPartInfo->SetRegenerationNr(regenerationNr);
1045 
1046  if ( currentGenPart ) {
1047  if (currentGenPart->end_vertex()) {
1048  // Old approach particle had an end vertex - predefined decays taken from the main GenEvent
1049  // No longer supported
1050  ATH_MSG_ERROR ( "getG4PrimaryParticle(): GenParticle has a valid end GenVertexPtr!" );
1051  ATH_MSG_ERROR ( "getG4PrimaryParticle(): currentGenPart: " << currentGenPart << ", barcode: " << HepMC::barcode(currentGenPart) );
1052  ATH_MSG_ERROR ( "getG4PrimaryParticle(): currentGenPart->end_vertex(): " << currentGenPart->end_vertex() << ", barcode: " << HepMC::barcode(currentGenPart->end_vertex()) );
1053  ATH_MSG_FATAL ( "getG4PrimaryParticle(): Passing GenParticles with a valid end GenVertexPtr as input is no longer supported." );
1054  abort();
1055  }
1056  else if (MC::isDecayed(currentGenPart) // Some assumptions about main GenEvent here
1057  && !currentGenPart->end_vertex()) {
1058  // New approach - predefined decays taken from shadow GenEvent
1059  // Find the matching particle in the shadowGenEvent
1060 #ifdef HEPMC3
1061  auto A_part = currentGenPart->attribute<HepMC::ShadowParticle>("ShadowParticle");
1062  HepMC::ConstGenParticlePtr shadowPart = (A_part) ? A_part->value() : findShadowParticle(currentGenPart, shadowGenEvent);
1063 #else
1064  HepMC::GenParticlePtr shadowPart = findShadowParticle(currentGenPart, shadowGenEvent);
1065 #endif
1066  if (!shadowPart) {
1067  ATH_MSG_FATAL ("Found a GenParticle with no matching GenParticle in the shadowGenEvent - something is wrong here!");
1068  abort();
1069  }
1070  if (!shadowPart->end_vertex()) {
1071  ATH_MSG_FATAL ("Found status==2 shadow GenParticle with no end vertex - something is wrong here!");
1072  abort();
1073  }
1074 #ifdef HEPMC3
1075  processPredefinedDecays(shadowPart, isp, g4particle.get());
1076 #else
1077  processPredefinedDecays(shadowPart, isp, g4particle.get(), false); // false to avoid truth-links to the shadow GenEvent
1078 #endif
1079  }
1080 
1081  double px,py,pz;
1082  const double pmass = g4particle->GetMass();
1083  CLHEP::Hep3Vector gpv = g4particle->GetMomentum();
1084  double g4px=g4particle->GetMomentum().x();
1085  double g4py=g4particle->GetMomentum().y();
1086  double g4pz=g4particle->GetMomentum().z();
1087  if (useHepMC) {
1088  //Code adapted from TruthHepMCEventConverter::TransformHepMCParticle
1089  px=g4px;
1090  py=g4py;
1091  pz=g4pz;
1092  } else {
1093  //Take mass from g4particle, put keep momentum as in currentGenPart
1094  px=currentGenPart->momentum().px();
1095  py=currentGenPart->momentum().py();
1096  pz=currentGenPart->momentum().pz();
1097  //Now a dirty hack to keep backward compatibility in the truth:
1098  //When running AtlasG4 or FullG4 between 21.0.41 and 21.0.111, the currentGenPart 3-momentum and mass was reset to the values from the g4particle
1099  //together with the mass of the g4particle after the 1st initialization of the g4particle from the genevent. This is done for a consistent mass
1100  //value in the truth record compared to the used g4 mass. Since g4particles don't store the 3-momentum directly, but rather a
1101  //unit direction vector, the mass and the kinetic energy, this reduces the numeric accuracy.
1102  //For backward compatibility, if all 3-momentum components agree to the g4particle momentum within 1 keV, we keep
1103  //this old method. This comparison is needed, since in ISF this code could be rerun after the ID or CALO simulation, where
1104  //real energy was lost in previous detectors and hence currentGenPart should NOT be changed to some g4particle values!
1105  //TODO: find a way to implement this in a backward compatible way in ISF::InputConverter::convertParticle(HepMC::GenParticlePtr genPartPtr)
1106  if (std::abs(px-g4px)<CLHEP::keV && std::abs(py-g4py)<CLHEP::keV && std::abs(pz-g4pz)<CLHEP::keV) {
1107  px=g4px;
1108  py=g4py;
1109  pz=g4pz;
1110  }
1111  }
1112  const double mag2=px*px + py*py + pz*pz;
1113  const double pe = std::sqrt(mag2 + pmass*pmass); // this does only change for boosts, etc.
1114 
1115  double originalEnergy=currentGenPart->momentum().e();
1116  if (originalEnergy>0.01) { //only test for >1 MeV in momentum
1117  if ((originalEnergy-pe)/originalEnergy>0.01) {
1118  double genpx=currentGenPart->momentum().px();
1119  double genpy=currentGenPart->momentum().py();
1120  double genpz=currentGenPart->momentum().pz();
1121  double genp=sqrt(genpx*genpx + genpy*genpy + genpz*genpz);
1122  ATH_MSG_WARNING("Truth change in energy for: " << currentGenPart<<" Morg="<<currentGenPart->momentum().m()<<" Mmod="<<pmass<<" Eorg="<<originalEnergy<<" Emod="<<pe<<" porg="<<genp<<" pmod="<<gpv.mag());
1123  }
1124  }
1125 
1126 #ifdef HEPMC3
1127  auto& currentGenPart_nc = currentGenPart;
1128 #else
1129  auto* currentGenPart_nc = currentGenPart;
1130 #endif
1131  currentGenPart_nc->set_momentum(HepMC::FourVector(px,py,pz,pe));
1132  } // Truth was detected
1133 
1134  ATH_MSG_VERBOSE("PrimaryParticleInformation:");
1135  ATH_MSG_VERBOSE(" GetParticleUniqueID = " << primaryPartInfo->GetParticleUniqueID());
1136  ATH_MSG_VERBOSE(" GetRegenerationNr = " << primaryPartInfo->GetRegenerationNr());
1137  ATH_MSG_VERBOSE(" GetHepMCParticle = " << primaryPartInfo->GetHepMCParticle());
1138  ATH_MSG_VERBOSE(" GetISFParticle = " << primaryPartInfo->GetISFParticle());
1139  g4particle->SetUserInformation(primaryPartInfo.release());
1140 
1141  return g4particle.release();
1142 }
1143 
1144 //________________________________________________________________________
1146  G4Event& g4evt, ISF::ISFParticle& isp, bool useHepMC,
1147  HepMC::GenEvent* shadowGenEvent) const {
1148  /*
1149  see conversion from PrimaryParticleInformation to TrackInformation in
1150  http://acode-browser.usatlas.bnl.gov/lxr/source/atlas/Simulation/G4Atlas/G4AtlasAlg/src/AthenaStackingAction.cxx#0044
1151 
1152  need to check with
1153  http://acode-browser.usatlas.bnl.gov/lxr/source/atlas/Simulation/G4Atlas/G4AtlasAlg/src/TruthHepMCEventConverter.cxx#0151
1154 
1155  that we don't miss something
1156  */
1157 
1158  G4PrimaryParticle *g4particle = this->getG4PrimaryParticle( isp, useHepMC, shadowGenEvent );
1159  if (!g4particle) {
1160  ATH_MSG_ERROR("Failed to create G4PrimaryParticle for ISParticle (" << isp <<")");
1161  return;
1162  }// Already printed a warning
1163 
1164  // create a new vertex
1165  G4PrimaryVertex *g4vertex = new G4PrimaryVertex(isp.position().x(),
1166  isp.position().y(),
1167  isp.position().z(),
1168  isp.timeStamp());
1169  g4vertex->SetPrimary( g4particle );
1170  ATH_MSG_VERBOSE("Print G4PrimaryVertex: ");
1171  if (msgLevel(MSG::VERBOSE)) { g4vertex->Print(); }
1172  g4evt.AddPrimaryVertex(g4vertex);
1173  return;
1174 }
1175 
1176 //________________________________________________________________________
1177 bool ISF::InputConverter::isInsideG4WorldVolume(const ISF::ISFParticle& isp, const G4VSolid* worldSolid) const
1178 {
1179 
1180  const Amg::Vector3D &pos = isp.position();
1181  const G4ThreeVector g4Pos( pos.x(), pos.y(), pos.z() );
1182  EInside insideStatus = worldSolid->Inside( g4Pos );
1183 
1184  bool insideWorld = insideStatus != kOutside;
1185  return insideWorld;
1186 }
ISF::ISFParticleContainer
std::list< ISF::ISFParticle * > ISFParticleContainer
generic ISFParticle container (not necessarily a std::list!)
Definition: ISFParticleContainer.h:23
LArG4FSStartPointFilter.part
part
Definition: LArG4FSStartPointFilter.py:21
ISF::InputConverter::addG4PrimaryVertex
void addG4PrimaryVertex(G4Event &g4evt, ISF::ISFParticle &isp, bool useHepMC, HepMC::GenEvent *shadowGenEvent) const
Definition: InputConverter.cxx:1145
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
ISF::DetRegionSvcIDPair
std::pair< AtlasDetDescr::AtlasRegion, ISF::SimSvcID > DetRegionSvcIDPair
the datatype to be used to store each individual particle hop
Definition: ISFParticle.h:30
AtlasG4EventUserInfo::SetLastProcessedTrackID
void SetLastProcessedTrackID(int trackID)
record the value of G4Track::GetTrackID() for the current G4Step.
Definition: AtlasG4EventUserInfo.h:85
AtlasG4EventUserInfo
This class is attached to G4Event objects as UserInformation. It holds a pointer to the HepMC::GenEve...
Definition: AtlasG4EventUserInfo.h:23
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
GenEvent.h
test_pyathena.px
px
Definition: test_pyathena.py:18
python.SystemOfUnits.mm
float mm
Definition: SystemOfUnits.py:98
AtlasG4EventUserInfo::SetLastProcessedStep
void SetLastProcessedStep(int stepNumber)
record value of the G4Track::GetCurrentStepNumber() for the current G4Step.
Definition: AtlasG4EventUserInfo.h:102
ISF::InputConverter::getG4ParticleDefinition
const G4ParticleDefinition * getG4ParticleDefinition(int pdgcode) const
Definition: InputConverter.cxx:507
FullCPAlgorithmsTest_eljob.flush
flush
Definition: FullCPAlgorithmsTest_eljob.py:194
AthMsgStreamMacros.h
ISF::InputConverter::ISF_to_G4Event
void ISF_to_G4Event(G4Event &event, const std::vector< ISF::ISFParticle * > &isp, HepMC::GenEvent *genEvent, HepMC::GenEvent *shadowGenEvent=nullptr, bool useHepMC=false) const override final
Converts vector of ISF::ISFParticles to G4Event.
Definition: InputConverter.cxx:468
Base_Fragment.mass
mass
Definition: Sherpa_i/share/common/Base_Fragment.py:59
HepMC::StatusBased::generations
int generations(const T &p)
Method to return how many interactions a particle has undergone during simulation based on the status...
Definition: MagicNumbers.h:270
HepMC::signal_process_id
int signal_process_id(const GenEvent &e)
Definition: GenEvent.h:635
AtlasG4EventUserInfo::SetHepMCEvent
void SetHepMCEvent(HepMC::GenEvent *)
set m_theEvent, the pointer to the HepMC::GenEvent used to create the G4Event.
Definition: AtlasG4EventUserInfo.cxx:13
GenVertex.h
HepMC::GenParticlePtr
GenParticle * GenParticlePtr
Definition: GenParticle.h:37
TRTCalib_cfilter.p1
p1
Definition: TRTCalib_cfilter.py:130
PlotCalibFromCool.begin
begin
Definition: PlotCalibFromCool.py:94
ISF::ISFParticle
Definition: ISFParticle.h:42
ISF::ISFParticle::pdgCode
int pdgCode() const
PDG value.
AtlasDetDescr::fUndefinedAtlasRegion
@ fUndefinedAtlasRegion
Definition: AtlasRegion.h:23
athena.value
value
Definition: athena.py:124
PrimaryParticleInformation::GetRegenerationNr
int GetRegenerationNr()
return the number of times the particle represented by the G4PrimaryParticle has undergone a non-dest...
Definition: PrimaryParticleInformation.h:55
covarianceTool.passFilter
bool passFilter
Definition: covarianceTool.py:604
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
ISF::InputConverter::m_particlePropSvc
ServiceHandle< IPartPropSvc > m_particlePropSvc
ParticlePropertyService and ParticleDataTable.
Definition: InputConverter.h:132
Analysis::pMass
constexpr double pMass
Definition: JpsiPlus2Tracks.cxx:34
LArG4AODNtuplePlotter.pe
pe
Definition: LArG4AODNtuplePlotter.py:116
GenParticle.h
ISF::InputConverter::convertParticle
ISF::ISFParticle * convertParticle(const HepMC::GenParticlePtr &genPartPtr) const
convert GenParticle to ISFParticle
Definition: InputConverter.cxx:282
HepMC::BarcodeBased::generations
int generations(const T &p)
Method to return how many interactions a particle has undergone during simulation (only to be used in...
Definition: MagicNumbers.h:211
mergePhysValFiles.end
end
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:92
ISF::InputConverter::processPredefinedDecays
void processPredefinedDecays(const HepMC::GenParticlePtr &genpart, ISF::ISFParticle &isp, G4PrimaryParticle *g4particle, bool makeLinkToTruth=true) const
Definition: InputConverter.cxx:910
ISF::ISFParticle::position
const Amg::Vector3D & position() const
The current position of the ISFParticle.
ISF::InputConverter::InputConverter
InputConverter(const std::string &name, ISvcLocator *svc)
Constructor.
Definition: InputConverter.cxx:51
covarianceTool.filter
filter
Definition: covarianceTool.py:514
ISFParticleContainer.h
ISF::InputConverter::findShadowParticle
HepMC::GenParticlePtr findShadowParticle(const HepMC::ConstGenParticlePtr &genParticle, HepMC::GenEvent *shadowGenEvent) const
Definition: InputConverter.cxx:805
TruthBinding.h
ISF::InputConverter::convertHepMCToG4EventLegacy
virtual StatusCode convertHepMCToG4EventLegacy(McEventCollection &inputGenEvents, G4Event &outputG4Event) const override final
Definition: InputConverter.cxx:175
TRTCalib_cfilter.p2
p2
Definition: TRTCalib_cfilter.py:131
ISFParticle.h
skel.l2
l2
Definition: skel.GENtoEVGEN.py:410
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:209
ParticleGun_EoverP_Config.mom
mom
Definition: ParticleGun_EoverP_Config.py:63
ISF::InputConverter::initialize
virtual StatusCode initialize() override final
Athena algtool Hooks.
Definition: InputConverter.cxx:83
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
ISF::InputConverter::getG4PrimaryParticle
G4PrimaryParticle * getG4PrimaryParticle(ISF::ISFParticle &isp, bool useHepMC, HepMC::GenEvent *shadowGenEvent) const
Definition: InputConverter.cxx:992
ParticleGun_EoverP_Config.momentum
momentum
Definition: ParticleGun_EoverP_Config.py:63
event
POOL::TEvent event(POOL::TEvent::kClassAccess)
McEventCollection.h
InputConverter.h
PrimaryParticleInformation::GetISFParticle
const ISF::ISFParticle * GetISFParticle() const
return a pointer to the ISFParticle used to create the G4PrimaryParticle
Definition: PrimaryParticleInformation.h:66
ISF::InputConverter::isInsideG4WorldVolume
bool isInsideG4WorldVolume(const ISF::ISFParticle &isp, const G4VSolid *worldSolid) const
Tests whether the given ISFParticle is within the Geant4 world volume.
Definition: InputConverter.cxx:1177
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
HepMC::barcode
int barcode(const T *p)
Definition: Barcode.h:16
ISF::ISFParticleVector
std::vector< ISF::ISFParticle * > ISFParticleVector
ISFParticle vector.
Definition: ISFParticleContainer.h:26
HepMC::uniqueID
int uniqueID(const T &p)
Definition: MagicNumbers.h:116
Amg::pz
@ pz
Definition: GeoPrimitives.h:40
ISF::InputConverter::m_useGeneratedParticleMass
bool m_useGeneratedParticleMass
use GenParticle::generated_mass() in simulation
Definition: InputConverter.h:135
ISF::InputConverter::matchedGenParticles
bool matchedGenParticles(const HepMC::ConstGenParticlePtr &p1, const HepMC::ConstGenParticlePtr &p2) const
Definition: InputConverter.cxx:792
jobOptions.ParticleID
ParticleID
Definition: jobOptions.decayer.py:85
AnalysisUtils::copy_if
Out copy_if(In first, const In &last, Out res, const Pred &p)
Definition: IFilterUtils.h:30
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
ISF::InputConverter::convert
virtual StatusCode convert(McEventCollection &inputGenEvents, ISF::ISFParticleContainer &simParticles) const override final
Convert selected particles from the given McEventCollection into ISFParticles and push them into the ...
Definition: InputConverter.cxx:118
Handler::svc
AthROOTErrorHandlerSvc * svc
Definition: AthROOTErrorHandlerSvc.cxx:10
McEventCollection
This defines the McEventCollection, which is really just an ObjectVector of McEvent objects.
Definition: McEventCollection.h:32
DataVector::back
const T * back() const
Access the last element in the collection as an rvalue.
ISF::InputConverter::convertHepMCToG4Event
virtual StatusCode convertHepMCToG4Event(McEventCollection &inputGenEvents, G4Event &outputG4Event, McEventCollection &shadowGenEvents) const override final
Definition: InputConverter.cxx:156
HepMC::ConstGenParticlePtr
const GenParticle * ConstGenParticlePtr
Definition: GenParticle.h:38
ParticleUserInformation.h
Amg::py
@ py
Definition: GeoPrimitives.h:39
ISF::ISFParticle::timeStamp
double timeStamp() const
Timestamp of the ISFParticle.
ISF::InputConverter::getDaughterG4PrimaryParticle
G4PrimaryParticle * getDaughterG4PrimaryParticle(HepMC::GenParticle &gp, bool makeLinkToTruth=true) const
Definition: InputConverter.cxx:704
ISF::InputConverter::m_quasiStableParticlesIncluded
bool m_quasiStableParticlesIncluded
Definition: InputConverter.h:139
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
ISF::ISFParticle::momentum
const Amg::Vector3D & momentum() const
The current momentum vector of the ISFParticle.
python.PhysicalConstants.c_squared
float c_squared
Definition: PhysicalConstants.py:74
charge
double charge(const T &p)
Definition: AtlasPID.h:986
FakeBkgTools::maxParticles
constexpr uint8_t maxParticles()
Definition: FakeBkgInternals.h:93
python.PhysicalConstants.c_light
float c_light
Definition: PhysicalConstants.py:73
SetProperTimeFromDetectorFrameDecayLength
double SetProperTimeFromDetectorFrameDecayLength(G4PrimaryParticle &g4particle, const double GeneratorDecayLength)
Definition: InputConverter.cxx:525
PrimaryParticleInformation::SetRegenerationNr
void SetRegenerationNr(int i)
update the number of times the particle represented by the G4PrimaryParticle has undergone a non-dest...
Definition: PrimaryParticleInformation.h:61
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
TMVAToMVAUtils::convert
std::unique_ptr< MVAUtils::BDT > convert(TMVA::MethodBDT *bdt, bool isRegression=true, bool useYesNoLeaf=false)
Definition: TMVAToMVAUtils.h:114
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:16
PrimaryParticleInformation::GetHepMCParticle
HepMC::ConstGenParticlePtr GetHepMCParticle() const
return a pointer to the GenParticle used to create the G4PrimaryParticle
Definition: PrimaryParticleInformation.h:47
skel.genpart
tuple genpart
Check that the actual generators, tune, and main PDF are consistent with the JO name.
Definition: skel.ABtoEVGEN.py:262
python.SystemOfUnits.keV
float keV
Definition: SystemOfUnits.py:174
AtlasG4EventUserInfo.h
egammaEnergyPositionAllSamples::e2
double e2(const xAOD::CaloCluster &cluster)
return the uncorrected cluster energy in 2nd sampling
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
MC::isDecayed
bool isDecayed(const T &p)
Identify if the particle decayed.
Definition: HepMCHelpers.h:42
PrimaryParticleInformation.h
IGenParticleFilter.h
python.DecayParser.children
children
Definition: DecayParser.py:32
ISF::InputConverter::getSelectedParticles
std::vector< HepMC::GenParticlePtr > getSelectedParticles(HepMC::GenEvent &evnt, bool legacyOrdering=false) const
get all generator particles which pass filters
Definition: InputConverter.cxx:244
python.Constants.VERBOSE
int VERBOSE
Definition: Control/AthenaCommon/python/Constants.py:13
ISF::fEventGeneratorSimID
@ fEventGeneratorSimID
Definition: SimSvcID.h:34
mag2
Scalar mag2() const
mag2 method - forward to squaredNorm()
Definition: AmgMatrixBasePlugin.h:31
pow
constexpr int pow(int base, int exp) noexcept
Definition: ap_fixedTest.cxx:15
python.SystemOfUnits.m2
float m2
Definition: SystemOfUnits.py:107
Amg::distance
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Definition: GeoPrimitivesHelpers.h:54
ISF::InputConverter::passesFilters
bool passesFilters(const HepMC::GenParticle &p) const
check if the given particle passes all filters
Definition: InputConverter.cxx:441
ISF::InputConverter::~InputConverter
virtual ~InputConverter()
Destructor.
Definition: InputConverter.cxx:76
ISF::InputConverter::getParticleMass
double getParticleMass(const HepMC::GenParticle &p) const
get right GenParticle mass
Definition: InputConverter.cxx:388
DataVector::empty
bool empty() const noexcept
Returns true if the collection is empty.
HepMCHelpers.h
ISF::InputConverter::m_genParticleFilters
ToolHandleArray< IGenParticleFilter > m_genParticleFilters
HepMC::GenParticle filters.
Definition: InputConverter.h:137
ISF::ISFParticle::getTruthBinding
const TruthBinding * getTruthBinding() const
pointer to the simulation truth - optional, can be 0
GenParticle
@ GenParticle
Definition: TruthClasses.h:30
SelectedParticlesUtil::getSelectedParticles
void getSelectedParticles(const ParticleLinks< Container > *links, SelectedParticles &selparts)
Definition: SelectedParticlesUtil.h:66
description
std::string description
glabal timer - how long have I taken so far?
Definition: hcg.cxx:88
PrimaryParticleInformation::GetParticleUniqueID
int GetParticleUniqueID() const
Definition: PrimaryParticleInformation.cxx:28
python.LArMinBiasAlgConfig.float
float
Definition: LArMinBiasAlgConfig.py:65
ISF::InputConverter::finalize
virtual StatusCode finalize() override final
Athena algtool Hook.
Definition: InputConverter.cxx:108