3 """Parser for the PDGTABLE.MeV file 
    5     Creates a compact object that holds configuration 
    6     for the ExtraParticlesPhysicsTool. 
    8     Gaudi cannot parse nested std::map objects, so the extra 
    9     particles are converted into a 
   11       std::map< std::string, std::vector< double > > 
   13     object and ordering of the values is therefore important. 
   22     Charge, spin, parity, and isospin3 are set to zero. 
   32 from AthenaCommon.PhysicalConstants 
import hbar_Planck, h_Planck
 
   33 from AthenaCommon.Logging 
import logging
 
   34 from functools 
import lru_cache
 
   39     if os.path.isfile(table):
 
   42     os.system(
'get_files -data %s' % table)
 
   49     if os.path.isfile(acceptlist):
 
   52     blank = 
open(
'G4particle_acceptlist_ExtraParticles.txt', 
'x')
 
   60         shutil.copy(listName, listName+
'.org')
 
   61     existingpdgcodes = [
int(x) 
for x 
in open(listName).readlines()]
 
   64     with open(listName, 
'a') 
as writer:
 
   65         for pdg 
in newpdgcodes:
 
   66             writer.write(
'%s\n' % pdg)
 
   75     lifetime = h_Planck / joule
 
   78         self.__dict__.update(kwargs)
 
   82         string += 
'name: %s\n' % self.
name 
   83         string += 
'  mass: %s\n' % self.
mass 
   84         string += 
'  width: %s\n' % self.
width 
   85         string += 
'  charge: %s\n' % self.
charge 
   86         string += 
'  pdg: %s\n' % self.
pdg 
   87         string += 
'  lifetime: %s\n' % self.
lifetime 
   93         antiParticle.charge *= -1
 
   94         antiParticle.pdg *= -1
 
   98         if self.
name[-1] == 
'0':
 
   99             if 'anti_' in self.
name:
 
  102                 return 'anti_' + self.
name 
  103         elif self.
name[-1] == 
'+':
 
  105         elif self.
name[-1] == 
'-':
 
  112         self.
log = logging.getLogger(__name__)
 
  119         """Function to determine which extra particles are added 
  121         Function checks the ranges member variable 
  122         and evaluates whether the particle should be accepted. 
  124         TODO Consider adding a Sim.ExtraParticlesRanges ConfigFlag 
  126         For example, '111-556,1112-9090226' matches everything from 
  127         111 to 555 and 1112 to 9090225. 
  129         ranges = [r.split(
"-") 
for r 
in self.
ranges.
split(
",")]
 
  131             if int(r[0]) <= pdg < 
int(r[1]):
 
  139                 if line.startswith(
'*'):
 
  142                 splitLine = line.split()
 
  145                 baseName = splitLine[-2]
 
  148                 charges = splitLine[-1].
split(
',')
 
  152                 symbol = splitLine[0]
 
  159                         'Unidentified symbol %s for particle %s' % (
 
  162                 pdgs = splitLine[1:1+len(charges)]
 
  163                 value = 
float(splitLine[1+len(charges)])
 
  165                 for pdg, charge 
in zip(pdgs, charges):
 
  170                     kwargs.setdefault(
'name', name)
 
  171                     kwargs.setdefault(prop, value * MeV)
 
  172                     kwargs.setdefault(
'pdg', 
int(pdg))
 
  179                                 "Property %s is already" 
  180                                 "set for particle %s." 
  181                                 "Current value is %s and" 
  182                                 "incoming value is %s.",
 
  202         nameOut = nameOut.replace(
"*", 
"_star").
replace(
"'", 
"_prime")
 
  209         if not (charge == len(charge) * charge[0]):
 
  210             raise ValueError(
'Unexpected charge %s' % charge)
 
  220             raise ValueError(
'Unexpected charge %s' % charge)
 
  229             outDict.update({name: [