Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:17:33

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 #if __cplusplus >= 201103L
0100     extension.swap(c.extension);
0101 #else
0102     extension   = c.extension;
0103 #endif
0104     //DD4hep_ptr<ParticleExtension>(c.extension.release());
0105   }
0106   return *this;
0107 }
0108 
0109 /// Remove daughter from set
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 /// Access the Geant4 particle definition object (expensive!)
0116 const G4ParticleDefinition* Geant4ParticleHandle::definition() const   {
0117   G4ParticleTable*      tab = G4ParticleTable::GetParticleTable();
0118   G4ParticleDefinition* def = tab->FindParticle(particle->pdgID);
0119   if( 1000000000 < particle->pdgID) {
0120     // creating ions here
0121     // ion encoding is 10 L ZZZ AAA I
0122     int id = particle->pdgID - 1000000000;  // leading 10 is just identifier
0123     const int L = id / 10000000; id %= 10000000;  // strange-quark content
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     // Have to look for existing Ions, excited or not
0129     G4ParticleDefinition* def_ion = tab_ion->FindIon(Z, A, L, lvl);
0130     if(def_ion) {
0131       //We found an existing Ion, we are good to go
0132       printout(VERBOSE,"Geant4Particle","+++ Returning ion with PDG %10d", def_ion->GetPDGEncoding());
0133       return def_ion;
0134     } else if(lvl == 0) {
0135       // GetIon creates the Ion if it does not exist, if this does not work something is seriously wrong
0136       printout(VERBOSE,"Geant4Particle","+++ Creating ion with PDG %10d", particle->pdgID);
0137       return tab_ion->GetIon(Z, A, L, 0.0);
0138     }
0139     //Cannot use GetIon with lvl > 0, must give energy, but we don't know where to get energy from
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, /* E= */ 0.0);
0143   } // finished with ions
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 /// Access to the Geant4 particle name
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 /// Access to the Geant4 particle type
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 /// Access Geant4 particle definitions by regular expression
0182 std::vector<G4ParticleDefinition*> Geant4ParticleHandle::g4DefinitionsRegEx(const std::string& expression)   {
0183   std::vector<G4ParticleDefinition*> results;
0184   std::string exp = expression;   //'^'+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(&reg, 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(&reg, 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, &reg, msgbuf, sizeof(msgbuf));
0211     ::regfree(&reg);
0212     throw std::runtime_error(format("Geant4ParticleHandle", "REGEX: Failed to match particle name %s err=%s", exp.c_str(), msgbuf));
0213       }
0214     }
0215     ::regfree(&reg);
0216   }
0217   return results;
0218 }
0219 
0220 /// Access Geant4 particle definitions by exact match
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 /// Access to the creator process name
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 /// Access to the creator process type name
0241 std::string Geant4ParticleHandle::processTypeName() const   {
0242   if ( particle->process )   {
0243     return G4VProcess::GetProcessTypeName(particle->process->GetProcessType());
0244   }
0245   return "";
0246 }
0247 
0248 /// Offset all particle identifiers (id, parents, daughters) by a constant number
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 /// Output type 1:+++ <tag>   10 def:0xde4eaa8 [gamma     ,   gamma] reason:      20 E:+1.017927e+03  \#Par:  1/4    \#Dau:  2
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 /// 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
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 /// 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
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 /// 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
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 /// 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
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   //char equiv[32];
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   //equiv[0] = 0;
0398   //if ( p->parents.end() == p->parents.find(p->g4Parent) )  {
0399   //  ::snprintf(equiv,sizeof(equiv),"/%d",p->g4Parent);
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            // 13 flags in total
0429            status.isSet(G4PARTICLE_GEN_EMPTY) ? 'E' : '.',               // 1
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' : '.',                // 5
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' : '.',       // 10
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 /// Default destructor
0483 Geant4ParticleMap::~Geant4ParticleMap()    {
0484   clear();
0485 }
0486 
0487 /// Clear particle maps
0488 void Geant4ParticleMap::clear()    {
0489   detail::releaseObjects(particleMap);
0490   particleMap.clear();
0491   equivalentTracks.clear();
0492 }
0493 
0494 /// Dump content
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 /// Adopt particle maps
0526 void Geant4ParticleMap::adopt(ParticleMap& pm, TrackEquivalents& equiv)    {
0527   clear();
0528   particleMap = pm;
0529   equivalentTracks = equiv;
0530   pm.clear();
0531   equiv.clear();
0532   //dump();
0533 }
0534 
0535 /// Check if the particle map was ever filled (ie. some particle handler was present)
0536   bool Geant4ParticleMap::isValid() const   {
0537   return !equivalentTracks.empty();
0538 }
0539 
0540 /// Access the equivalent track id (shortcut to the usage of TrackEquivalents)
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 }