Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-01 07:55:29

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 // Author     : M.Frank
0011 //
0012 //==========================================================================
0013 
0014 // Framework include files
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 // C/C++ include files
0031 #include <sstream>
0032 #include <iostream>
0033 #include <regex.h>
0034 
0035 using namespace dd4hep::sim;
0036 
0037 /// Default destructor
0038 ParticleExtension::~ParticleExtension() {
0039 }
0040 
0041 /// Default constructor
0042 Geant4Particle::Geant4Particle() : ref(1)
0043 {
0044   InstanceCount::increment(this);
0045 }
0046 
0047 /// Constructor with ID initialization
0048 Geant4Particle::Geant4Particle(int part_id) : ref(1), id(part_id), originalG4ID(part_id)
0049 {
0050   InstanceCount::increment(this);
0051 }
0052 
0053 /// Default destructor
0054 Geant4Particle::~Geant4Particle()  {
0055   InstanceCount::decrement(this);
0056   //::printf("************ Delete Geant4Particle[%p]: ID:%d pdgID %d ref:%d\n",(void*)this,id,pdgID,ref);
0057 }
0058 
0059 void Geant4Particle::release()  {
0060   //::printf("************ Release Geant4Particle[%p]: ID:%d pdgID %d ref:%d\n",(void*)this,id,pdgID,ref-1);
0061   if ( --ref <= 0 )  {
0062     delete this;
0063   }
0064 }
0065 
0066 /// Assignment operator
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     //definition  = c.definition;
0097     daughters   = c.daughters;
0098     parents     = c.parents;
0099     extension.swap(c.extension);
0100     //DD4hep_ptr<ParticleExtension>(c.extension.release());
0101   }
0102   return *this;
0103 }
0104 
0105 /// Remove daughter from set
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 /// Access the Geant4 particle definition object (expensive!)
0112 const G4ParticleDefinition* Geant4ParticleHandle::definition() const   {
0113   G4ParticleTable*      tab = G4ParticleTable::GetParticleTable();
0114   G4ParticleDefinition* def = tab->FindParticle(particle->pdgID);
0115   if( 1000000000 < particle->pdgID) {
0116     // creating ions here
0117     // ion encoding is 10 L ZZZ AAA I
0118     int id = particle->pdgID - 1000000000;  // leading 10 is just identifier
0119     const int L = id / 10000000; id %= 10000000;  // strange-quark content
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     // Have to look for existing Ions, excited or not
0125     G4ParticleDefinition* def_ion = tab_ion->FindIon(Z, A, L, lvl);
0126     if(def_ion) {
0127       //We found an existing Ion, we are good to go
0128       printout(VERBOSE,"Geant4Particle","+++ Returning ion with PDG %10d", def_ion->GetPDGEncoding());
0129       return def_ion;
0130     } else if(lvl == 0) {
0131       // GetIon creates the Ion if it does not exist, if this does not work something is seriously wrong
0132       printout(VERBOSE,"Geant4Particle","+++ Creating ion with PDG %10d", particle->pdgID);
0133       return tab_ion->GetIon(Z, A, L, 0.0);
0134     }
0135     //Cannot use GetIon with lvl > 0, must give energy, but we don't know where to get energy from
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, /* E= */ 0.0);
0139   } // finished with ions
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 /// Access to the Geant4 particle name
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 /// Access to the Geant4 particle type
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 /// Access Geant4 particle definitions by regular expression
0178 std::vector<G4ParticleDefinition*> Geant4ParticleHandle::g4DefinitionsRegEx(const std::string& expression)   {
0179   std::vector<G4ParticleDefinition*> results;
0180   std::string exp = expression;   //'^'+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(&reg, 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(&reg, 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, &reg, msgbuf, sizeof(msgbuf));
0207     ::regfree(&reg);
0208     throw std::runtime_error(format("Geant4ParticleHandle", "REGEX: Failed to match particle name %s err=%s", exp.c_str(), msgbuf));
0209       }
0210     }
0211     ::regfree(&reg);
0212   }
0213   return results;
0214 }
0215 
0216 /// Access Geant4 particle definitions by exact match
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 /// Access to the creator process name
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 /// Access to the creator process type name
0237 std::string Geant4ParticleHandle::processTypeName() const   {
0238   if ( particle->process )   {
0239     return G4VProcess::GetProcessTypeName(particle->process->GetProcessType());
0240   }
0241   return "";
0242 }
0243 
0244 /// Offset all particle identifiers (id, parents, daughters) by a constant number
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 /// Output type 1:+++ <tag>   10 def:0xde4eaa8 [gamma     ,   gamma] reason:      20 E:+1.017927e+03  \#Par:  1/4    \#Dau:  2
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 /// Output type 2:+++ <tag>   20 G4:   7 def:0xde4eaa8 [gamma     ,   gamma] reason:      20 E:+3.304035e+01 in record:YES  \#Par:  1/18   \#Dau:  0
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 /// Output type 3:+++ <tag> ID:  0 e-           status:00000014 type:       11 Vertex:(+0.00e+00,+0.00e+00,+0.00e+00) [mm] time: +0.00e+00 [ns] \#Par:  0 \#Dau:  4
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 /// Output type 3:+++ <tag> ID:  0 e-           status:00000014 type:       11 Vertex:(+0.00e+00,+0.00e+00,+0.00e+00) [mm] time: +0.00e+00 [ns] \#Par:  0 \#Dau:  4
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 /// Output type 3:+++ <tag> ID:  0 e-           status:00000014 type:       11 Vertex:(+0.00e+00,+0.00e+00,+0.00e+00) [mm] time: +0.00e+00 [ns] \#Par:  0 \#Dau:  4
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   //char equiv[32];
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   //equiv[0] = 0;
0394   //if ( p->parents.end() == p->parents.find(p->g4Parent) )  {
0395   //  ::snprintf(equiv,sizeof(equiv),"/%d",p->g4Parent);
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            // 13 flags in total
0425            status.isSet(G4PARTICLE_GEN_EMPTY) ? 'E' : '.',               // 1
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' : '.',                // 5
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' : '.',       // 10
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 /// Default destructor
0479 Geant4ParticleMap::~Geant4ParticleMap()    {
0480   clear();
0481 }
0482 
0483 /// Clear particle maps
0484 void Geant4ParticleMap::clear()    {
0485   detail::releaseObjects(particleMap);
0486   particleMap.clear();
0487   equivalentTracks.clear();
0488 }
0489 
0490 /// Dump content
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 /// Adopt particle maps
0522 void Geant4ParticleMap::adopt(ParticleMap& pm, TrackEquivalents& equiv)    {
0523   clear();
0524   particleMap = pm;
0525   equivalentTracks = equiv;
0526   pm.clear();
0527   equiv.clear();
0528   //dump();
0529 }
0530 
0531 /// Check if the particle map was ever filled (ie. some particle handler was present)
0532   bool Geant4ParticleMap::isValid() const   {
0533   return !equivalentTracks.empty();
0534 }
0535 
0536 /// Access the equivalent track id (shortcut to the usage of TrackEquivalents)
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 }