File indexing completed on 2025-07-01 07:55:29
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <DD4hep/InstanceCount.h>
0016 #include <DD4hep/Primitives.h>
0017 #include <DD4hep/Printout.h>
0018 #include <DDG4/Geant4Particle.h>
0019
0020 #include <G4ChargedGeantino.hh>
0021 #include <G4Geantino.hh>
0022 #include <G4IonTable.hh>
0023 #include <G4ParticleDefinition.hh>
0024 #include <G4ParticleTable.hh>
0025 #include <G4VProcess.hh>
0026
0027 #include <TDatabasePDG.h>
0028 #include <TParticlePDG.h>
0029
0030
0031 #include <sstream>
0032 #include <iostream>
0033 #include <regex.h>
0034
0035 using namespace dd4hep::sim;
0036
0037
0038 ParticleExtension::~ParticleExtension() {
0039 }
0040
0041
0042 Geant4Particle::Geant4Particle() : ref(1)
0043 {
0044 InstanceCount::increment(this);
0045 }
0046
0047
0048 Geant4Particle::Geant4Particle(int part_id) : ref(1), id(part_id), originalG4ID(part_id)
0049 {
0050 InstanceCount::increment(this);
0051 }
0052
0053
0054 Geant4Particle::~Geant4Particle() {
0055 InstanceCount::decrement(this);
0056
0057 }
0058
0059 void Geant4Particle::release() {
0060
0061 if ( --ref <= 0 ) {
0062 delete this;
0063 }
0064 }
0065
0066
0067 Geant4Particle& Geant4Particle::get_data(Geant4Particle& c) {
0068 if ( this != &c ) {
0069 id = c.id;
0070 originalG4ID = c.originalG4ID;
0071 g4Parent = c.g4Parent;
0072 reason = c.reason;
0073 mask = c.mask;
0074 status = c.status;
0075 genStatus = c.genStatus;
0076 charge = c.charge;
0077 steps = c.steps;
0078 secondaries = c.secondaries;
0079 pdgID = c.pdgID;
0080 vsx = c.vsx;
0081 vsy = c.vsy;
0082 vsz = c.vsz;
0083 vex = c.vex;
0084 vey = c.vey;
0085 vez = c.vez;
0086 psx = c.psx;
0087 psy = c.psy;
0088 psz = c.psz;
0089 pex = c.pex;
0090 pey = c.pey;
0091 pez = c.pez;
0092 mass = c.mass;
0093 time = c.time;
0094 properTime = c.properTime;
0095 process = c.process;
0096
0097 daughters = c.daughters;
0098 parents = c.parents;
0099 extension.swap(c.extension);
0100
0101 }
0102 return *this;
0103 }
0104
0105
0106 void Geant4Particle::removeDaughter(int id_daughter) {
0107 if ( std::set<int>::iterator j = daughters.find(id_daughter); j != daughters.end() )
0108 daughters.erase(j);
0109 }
0110
0111
0112 const G4ParticleDefinition* Geant4ParticleHandle::definition() const {
0113 G4ParticleTable* tab = G4ParticleTable::GetParticleTable();
0114 G4ParticleDefinition* def = tab->FindParticle(particle->pdgID);
0115 if( 1000000000 < particle->pdgID) {
0116
0117
0118 int id = particle->pdgID - 1000000000;
0119 const int L = id / 10000000; id %= 10000000;
0120 const int Z = id / 10000; id %= 10000;
0121 const int A = id / 10; id %= 10;
0122 const int lvl = id;
0123 G4IonTable* tab_ion = G4IonTable::GetIonTable();
0124
0125 G4ParticleDefinition* def_ion = tab_ion->FindIon(Z, A, L, lvl);
0126 if(def_ion) {
0127
0128 printout(VERBOSE,"Geant4Particle","+++ Returning ion with PDG %10d", def_ion->GetPDGEncoding());
0129 return def_ion;
0130 } else if(lvl == 0) {
0131
0132 printout(VERBOSE,"Geant4Particle","+++ Creating ion with PDG %10d", particle->pdgID);
0133 return tab_ion->GetIon(Z, A, L, 0.0);
0134 }
0135
0136 printout(WARNING,"Geant4Particle","+++ Cannot find excited ion with PDG %10d, setting excitation level to zero",
0137 particle->pdgID);
0138 return tab_ion->GetIon(Z, A, L, 0.0);
0139 }
0140
0141 if ( 0 == def && 0 == particle->pdgID ) {
0142 if ( 0 == particle->charge )
0143 return G4Geantino::Definition();
0144 return G4ChargedGeantino::Definition();
0145 }
0146 return def;
0147 }
0148
0149
0150 std::string Geant4ParticleHandle::particleName() const {
0151 if ( const G4ParticleDefinition* def = definition() )
0152 return def->GetParticleName();
0153 #if 0
0154 TDatabasePDG* db = TDatabasePDG::Instance();
0155 TParticlePDG* pdef = db->GetParticle(particle->pdgID);
0156 if ( pdef ) return pdef->GetName();
0157 #endif
0158 char text[32];
0159 ::snprintf(text,sizeof(text),"PDG:%d",particle->pdgID);
0160 return text;
0161 }
0162
0163
0164 std::string Geant4ParticleHandle::particleType() const {
0165 if ( const G4ParticleDefinition* def = definition() )
0166 return def->GetParticleType();
0167 #if 0
0168 TDatabasePDG* db = TDatabasePDG::Instance();
0169 TParticlePDG* pdef = db->GetParticle(particle->pdgID);
0170 if ( pdef ) return pdef->ParticleClass();
0171 #endif
0172 char text[32];
0173 ::snprintf(text,sizeof(text),"PDG:%d",particle->pdgID);
0174 return text;
0175 }
0176
0177
0178 std::vector<G4ParticleDefinition*> Geant4ParticleHandle::g4DefinitionsRegEx(const std::string& expression) {
0179 std::vector<G4ParticleDefinition*> results;
0180 std::string exp = expression;
0181 G4ParticleTable* pt = G4ParticleTable::GetParticleTable();
0182 G4ParticleTable::G4PTblDicIterator* iter = pt->GetIterator();
0183
0184 iter->reset();
0185 if ( expression == "*" || expression == ".(*)" ) {
0186 while ((*iter)()) {
0187 G4ParticleDefinition* p = iter->value();
0188 results.emplace_back(p);
0189 }
0190 }
0191 else {
0192 regex_t reg;
0193 int ret = ::regcomp(®, exp.c_str(), 0);
0194 if (ret) {
0195 throw std::runtime_error(format("Geant4ParticleHandle", "REGEX: Failed to compile particle name %s", exp.c_str()));
0196 }
0197 while ((*iter)()) {
0198 G4ParticleDefinition* p = iter->value();
0199 ret = ::regexec(®, p->GetParticleName().c_str(), 0, NULL, 0);
0200 if (!ret)
0201 results.emplace_back(p);
0202 else if (ret == REG_NOMATCH)
0203 continue;
0204 else {
0205 char msgbuf[128];
0206 ::regerror(ret, ®, msgbuf, sizeof(msgbuf));
0207 ::regfree(®);
0208 throw std::runtime_error(format("Geant4ParticleHandle", "REGEX: Failed to match particle name %s err=%s", exp.c_str(), msgbuf));
0209 }
0210 }
0211 ::regfree(®);
0212 }
0213 return results;
0214 }
0215
0216
0217 G4ParticleDefinition* Geant4ParticleHandle::g4DefinitionsExact(const std::string& expression) {
0218 G4ParticleTable* tab = G4ParticleTable::GetParticleTable();
0219 G4ParticleDefinition* def = tab->FindParticle(expression);
0220 return def;
0221 }
0222
0223
0224 std::string Geant4ParticleHandle::processName() const {
0225 if ( particle->process ) return particle->process->GetProcessName();
0226 else if ( particle->reason&G4PARTICLE_PRIMARY ) return "Primary";
0227 else if ( particle->status&G4PARTICLE_GEN_EMPTY ) return "Gen.Empty";
0228 else if ( particle->status&G4PARTICLE_GEN_STABLE ) return "Gen.Stable";
0229 else if ( particle->status&G4PARTICLE_GEN_DECAYED ) return "Gen.Decay";
0230 else if ( particle->status&G4PARTICLE_GEN_DOCUMENTATION ) return "Gen.DOC";
0231 else if ( particle->status&G4PARTICLE_GEN_BEAM ) return "Gen.Beam";
0232 else if ( particle->status&G4PARTICLE_GEN_OTHER ) return "Gen.Other";
0233 return "???";
0234 }
0235
0236
0237 std::string Geant4ParticleHandle::processTypeName() const {
0238 if ( particle->process ) {
0239 return G4VProcess::GetProcessTypeName(particle->process->GetProcessType());
0240 }
0241 return "";
0242 }
0243
0244
0245 void Geant4ParticleHandle::offset(int off) const {
0246 std::set<int> temp;
0247 Geant4Particle* p = particle;
0248 p->id += off;
0249
0250 temp = p->daughters;
0251 p->daughters.clear();
0252 for(auto i : temp) p->daughters.insert(i+off);
0253
0254 temp = p->parents;
0255 p->parents.clear();
0256 for(auto i : temp ) p->parents.insert(i+off);
0257 }
0258
0259
0260 void Geant4ParticleHandle::dump1(int level, const std::string& src, const char* tag) const {
0261 char text[256];
0262 Geant4ParticleHandle p(*this);
0263 text[0]=0;
0264 if ( p->parents.size() == 1 )
0265 ::snprintf(text,sizeof(text),"/%d",*(p->parents.begin()));
0266 else if ( p->parents.size() > 1 ) {
0267 text[0]='/';text[1]=0;
0268 for(int i : p->parents )
0269 ::snprintf(text+strlen(text),sizeof(text)-strlen(text),"%d ",i);
0270 }
0271 printout((dd4hep::PrintLevel)level,src,
0272 "+++ %s %4d def [%-11s,%8s] reason:%8d E:%+.2e %3s #Dau:%3d #Par:%3d%-5s",
0273 tag, p->id,
0274 p.particleName().c_str(),
0275 p.particleType().c_str(),
0276 p->reason,
0277 p.energy(),
0278 p->g4Parent>0 ? "Sim" : "Gen",
0279 int(p->daughters.size()),
0280 int(p->parents.size()),text);
0281 }
0282
0283
0284 void Geant4ParticleHandle::dump2(int level, const std::string& src, const char* tag, int g4id, bool inrec) const {
0285 char text[32];
0286 Geant4ParticleHandle p(*this);
0287 if ( p->parents.size() == 0 ) text[0]=0;
0288 else if ( p->parents.size() == 1 ) ::snprintf(text,sizeof(text),"/%d",*(p->parents.begin()));
0289 else if ( p->parents.size() > 1 ) ::snprintf(text,sizeof(text),"/%d..",*(p->parents.begin()));
0290 printout((dd4hep::PrintLevel)level,src,
0291 "+++ %s %4d G4:%4d [%-12s,%8s] reason:%8d "
0292 "E:%+.2e in record:%s #Par:%3d%-5s #Dau:%3d",
0293 tag, p->id, g4id,
0294 p.particleName().c_str(),
0295 p.particleType().c_str(),
0296 p->reason,
0297 p.energy(),
0298 yes_no(inrec),
0299 int(p->parents.size()),text,
0300 int(p->daughters.size()));
0301 }
0302
0303
0304 void Geant4ParticleHandle::dumpWithVertex(int level, const std::string& src, const char* tag) const {
0305 char text[256];
0306 Geant4ParticleHandle p(*this);
0307 text[0]=0;
0308 if ( p->parents.size() == 1 )
0309 ::snprintf(text,sizeof(text),"/%d",*(p->parents.begin()));
0310 else if ( p->parents.size() > 1 ) {
0311 text[0]='/';text[1]=0;
0312 for(int i : p->parents )
0313 ::snprintf(text+strlen(text),sizeof(text)-strlen(text),"%d ",i);
0314 }
0315 printout((dd4hep::PrintLevel)level,src,
0316 "+++ %s ID:%3d %-12s status:%08X PDG:%6d Vtx:(%+.2e,%+.2e,%+.2e)[mm] "
0317 "time: %+.2e [ns] #Dau:%3d #Par:%1d%-6s",
0318 tag,p->id,p.particleName().c_str(),p->status,p->pdgID,
0319 p->vsx/CLHEP::mm,p->vsy/CLHEP::mm,p->vsz/CLHEP::mm,p->time/CLHEP::ns,
0320 p->daughters.size(),
0321 p->parents.size(),
0322 text);
0323 }
0324
0325
0326
0327 void Geant4ParticleHandle::dumpWithMomentum(int level, const std::string& src, const char* tag) const {
0328 char text[256];
0329 Geant4ParticleHandle p(*this);
0330 text[0]=0;
0331 if ( p->parents.size() == 1 )
0332 ::snprintf(text,sizeof(text),"/%d",*(p->parents.begin()));
0333 else if ( p->parents.size() > 1 ) {
0334 text[0]='/';text[1]=0;
0335 for(int i : p->parents )
0336 ::snprintf(text+strlen(text),sizeof(text)-strlen(text),"%d ",i);
0337 }
0338 printout((dd4hep::PrintLevel)level,src,
0339 "+++%s ID:%3d %-12s stat:%08X PDG:%6d Mom:(%+.2e,%+.2e,%+.2e)[MeV] "
0340 "time: %+.2e [ns] #Dau:%3d #Par:%1d%-6s",
0341 tag,p->id,p.particleName().c_str(),p->status,p->pdgID,
0342 p->psx/CLHEP::MeV,p->psy/CLHEP::MeV,p->psz/CLHEP::MeV,p->time/CLHEP::ns,
0343 int(p->daughters.size()),
0344 int(p->parents.size()),
0345 text);
0346 }
0347
0348
0349 void Geant4ParticleHandle::dumpWithMomentumAndVertex(int level, const std::string& src, const char* tag) const {
0350 char text[256];
0351 Geant4ParticleHandle p(*this);
0352 text[0]=0;
0353 if ( p->parents.size() == 1 )
0354 ::snprintf(text,sizeof(text),"/%d",*(p->parents.begin()));
0355 else if ( p->parents.size() > 1 ) {
0356 text[0]='/';text[1]=0;
0357 for(int i : p->parents )
0358 ::snprintf(text+strlen(text),sizeof(text)-strlen(text),"%d ",i);
0359 }
0360 printout((dd4hep::PrintLevel)level,src,
0361 "+++%s %3d %-12s stat:%08X PDG:%6d Mom:(%+.2e,%+.2e,%+.2e)[MeV] "
0362 "Vtx:(%+.2e,%+.2e,%+.2e)[mm] #Dau:%3d #Par:%1d%-6s",
0363 tag,p->id,p.particleName().c_str(),p->status,p->pdgID,
0364 p->psx/CLHEP::MeV,p->psy/CLHEP::MeV,p->psz/CLHEP::MeV,
0365 p->vsx/CLHEP::mm,p->vsy/CLHEP::mm,p->vsz/CLHEP::mm,
0366 int(p->daughters.size()),
0367 int(p->parents.size()),
0368 text);
0369 }
0370
0371 void Geant4ParticleHandle::header4(int level, const std::string& src, const char* tag) {
0372 printout((dd4hep::PrintLevel)level,src,
0373 "+++ %s %10s/%-7s %12s/%-10s %6s/%-6s %4s %4s "
0374 "%-4s %-3s %-3s %-10s "
0375 "%-5s %-6s %-3s %-3s %-20s %s",
0376 tag,"ID", "G4-ID", "Part-Name","PDG", "Parent","G4-ID", "#Par","#Dau",
0377 "Prim","Sec",">E","Energy",
0378 "EMPTY","STAB","DEC","DOC",
0379 "Process", "Processing Flags");
0380 }
0381
0382 void Geant4ParticleHandle::dump4(int level, const std::string& src, const char* tag) const {
0383 using PropertyMask = dd4hep::detail::ReferenceBitMask<int>;
0384 Geant4ParticleHandle p(*this);
0385
0386 PropertyMask mask(p->reason);
0387 PropertyMask status(p->status);
0388 std::string proc_name = p.processName();
0389 std::string proc_type = p.processTypeName();
0390 std::string proc = '['+proc_name+(p->process ? "/" : "")+proc_type+']';
0391 int parent_id = p->parents.empty() ? -1 : *(p->parents.begin());
0392
0393
0394
0395
0396
0397 std::stringstream str;
0398 str << "Parents: ";
0399 for( const auto i : p->parents )
0400 str << i << " ";
0401 str << " Daughters: ";
0402 for( const auto i : p->daughters )
0403 str << i << " ";
0404 printout((dd4hep::PrintLevel)level,src,
0405 "+++ %s ID:%7d/%-7d %12s/%-10d %6d/%-6d %4d %4d %-4s %-3s %-3s %+.3e "
0406 "%-5s %-4s %-3s %-3s %-20s %c%c%c%c -- %c%c%c%c%c%c%c%c%c %s",
0407 tag,
0408 p->id,p->originalG4ID,
0409 p.particleName().c_str(),
0410 p->pdgID,
0411 parent_id,p->g4Parent,
0412 p.numParent(),
0413 int(p->daughters.size()),
0414 yes_no(mask.isSet(G4PARTICLE_PRIMARY)),
0415 yes_no(mask.isSet(G4PARTICLE_HAS_SECONDARIES)),
0416 yes_no(mask.isSet(G4PARTICLE_ABOVE_ENERGY_THRESHOLD)),
0417 p.energy(),
0418
0419 yes_no(mask.isSet(G4PARTICLE_CREATED_CALORIMETER_HIT)),
0420 yes_no(mask.isSet(G4PARTICLE_CREATED_TRACKER_HIT)),
0421 yes_no(mask.isSet(G4PARTICLE_KEEP_PROCESS)),
0422 mask.isSet(G4PARTICLE_KEEP_PARENT) ? "YES" : "",
0423 proc.c_str(),
0424
0425 status.isSet(G4PARTICLE_GEN_EMPTY) ? 'E' : '.',
0426 status.isSet(G4PARTICLE_GEN_STABLE) ? 'S' : '.',
0427 status.isSet(G4PARTICLE_GEN_DECAYED) ? 'D' : '.',
0428 status.isSet(G4PARTICLE_GEN_DOCUMENTATION) ? 'd' : '.',
0429 status.isSet(G4PARTICLE_GEN_BEAM) ? 'B' : '.',
0430 status.isSet(G4PARTICLE_GEN_OTHER) ? 'o' : '.',
0431 status.isSet(G4PARTICLE_SIM_CREATED) ? 's' : '.',
0432 status.isSet(G4PARTICLE_SIM_BACKSCATTER) ? 'b' : '.',
0433 status.isSet(G4PARTICLE_SIM_PARENT_RADIATED) ? 'v' : '.',
0434 status.isSet(G4PARTICLE_SIM_DECAY_TRACKER) ? 't' : '.',
0435 status.isSet(G4PARTICLE_SIM_DECAY_CALO) ? 'c' : '.',
0436 status.isSet(G4PARTICLE_SIM_LEFT_DETECTOR) ? 'l' : '.',
0437 status.isSet(G4PARTICLE_SIM_STOPPED) ? 's' : '.',
0438 str.str().c_str()
0439 );
0440 #if 0
0441 printout((dd4hep::PrintLevel)level,src,
0442 "+++ %s ID:%7d %12s %6d%-7s %7s %3s %5d %3s %+.3e %-4s %-7s %-3s %-3s %2d [%s%s%s] %c%c%c%c -- %c%c%c%c%c%c%c",
0443 tag,
0444 p->id,
0445 p.particleName().c_str(),
0446 parent_id,equiv,
0447 yes_no(mask.isSet(G4PARTICLE_PRIMARY)),
0448 yes_no(mask.isSet(G4PARTICLE_HAS_SECONDARIES)),
0449 int(p->daughters.size()),
0450 yes_no(mask.isSet(G4PARTICLE_ABOVE_ENERGY_THRESHOLD)),
0451 p.energy(),
0452 yes_no(mask.isSet(G4PARTICLE_CREATED_CALORIMETER_HIT)),
0453 yes_no(mask.isSet(G4PARTICLE_CREATED_TRACKER_HIT)),
0454 yes_no(mask.isSet(G4PARTICLE_KEEP_PROCESS)),
0455 mask.isSet(G4PARTICLE_KEEP_PARENT) ? "YES" : "",
0456 p.numParent(),
0457 proc_name.c_str(),
0458 p->process ? "/" : "",
0459 proc_type.c_str(),
0460 status.isSet(G4PARTICLE_GEN_EMPTY) ? 'E' : '.',
0461 status.isSet(G4PARTICLE_GEN_STABLE) ? 'S' : '.',
0462 status.isSet(G4PARTICLE_GEN_DECAYED) ? 'D' : '.',
0463 status.isSet(G4PARTICLE_GEN_DOCUMENTATION) ? 'd' : '.',
0464 status.isSet(G4PARTICLE_GEN_BEAM) ? 'B' : '.',
0465 status.isSet(G4PARTICLE_GEN_OTHER) ? 'o' : '.',
0466
0467 status.isSet(G4PARTICLE_SIM_CREATED) ? 's' : '.',
0468 status.isSet(G4PARTICLE_SIM_BACKSCATTER) ? 'b' : '.',
0469 status.isSet(G4PARTICLE_SIM_PARENT_RADIATED) ? 'v' : '.',
0470 status.isSet(G4PARTICLE_SIM_DECAY_TRACKER) ? 't' : '.',
0471 status.isSet(G4PARTICLE_SIM_DECAY_CALO) ? 'c' : '.',
0472 status.isSet(G4PARTICLE_SIM_LEFT_DETECTOR) ? 'l' : '.',
0473 status.isSet(G4PARTICLE_SIM_STOPPED) ? 's' : '.'
0474 );
0475 #endif
0476 }
0477
0478
0479 Geant4ParticleMap::~Geant4ParticleMap() {
0480 clear();
0481 }
0482
0483
0484 void Geant4ParticleMap::clear() {
0485 detail::releaseObjects(particleMap);
0486 particleMap.clear();
0487 equivalentTracks.clear();
0488 }
0489
0490
0491 void Geant4ParticleMap::dump() const {
0492 int cnt;
0493 char text[64];
0494 const Geant4ParticleMap* m = this;
0495
0496 cnt = 0;
0497 std::cout << "Particle map:" << std::endl;
0498 for( const auto& p : m->particleMap ) {
0499 std::snprintf(text,sizeof(text)," [%-4d:%p]",p.second->id,(void*)p.second);
0500 std::cout << text;
0501 if ( ++cnt == 8 ) {
0502 std::cout << std::endl;
0503 cnt = 0;
0504 }
0505 }
0506 std::cout << std::endl;
0507
0508 cnt = 0;
0509 std::cout << "Equivalents:" << std::endl;
0510 for( const auto& p : m->equivalentTracks ) {
0511 std::snprintf(text,sizeof(text)," [%-5d : %-5d]",p.first,p.second);
0512 std::cout << text;
0513 if ( ++cnt == 8 ) {
0514 std::cout << std::endl;
0515 cnt = 0;
0516 }
0517 }
0518 std::cout << std::endl;
0519 }
0520
0521
0522 void Geant4ParticleMap::adopt(ParticleMap& pm, TrackEquivalents& equiv) {
0523 clear();
0524 particleMap = pm;
0525 equivalentTracks = equiv;
0526 pm.clear();
0527 equiv.clear();
0528
0529 }
0530
0531
0532 bool Geant4ParticleMap::isValid() const {
0533 return !equivalentTracks.empty();
0534 }
0535
0536
0537 int Geant4ParticleMap::particleID(int g4_id, bool) const {
0538 TrackEquivalents::const_iterator iequiv = equivalentTracks.find(g4_id);
0539 if ( iequiv != equivalentTracks.end() ) return (*iequiv).second;
0540 printout(ERROR,"Geant4ParticleMap","+++ No Equivalent particle for track:%d."
0541 " Monte Carlo truth record looks broken!",g4_id);
0542 dump();
0543 return -1;
0544 }