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