ATLAS Offline Software
Toggle main menu visibility
Loading...
Searching...
No Matches
Simulation
G4Extensions
ExtraParticles
python
PDGHelpers.py
Go to the documentation of this file.
1
# Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
2
3
"""Parser for the PDGTABLE.MeV file
4
5
Creates a compact object that holds configuration
6
for the ExtraParticlesPhysicsTool.
7
8
Gaudi cannot parse nested std::map objects, so the extra
9
particles are converted into a
10
11
std::map< std::string, std::vector< double > >
12
13
object and ordering of the values is therefore important.
14
15
Rows are:
16
name
17
mass [MeV]
18
width [MeV]
19
pdg
20
lifetime [ns]
21
22
Charge, spin, parity, and isospin3 are set to zero.
23
24
AUTHOR: miha muskinja
25
DATE: August 2019
26
27
"""
28
29
import
os
30
31
from
AthenaCommon.SystemOfUnits
import
MeV, joule
32
from
AthenaCommon.PhysicalConstants
import
hbar_Planck, h_Planck
33
from
AthenaCommon.Logging
import
logging
34
from
functools
import
lru_cache
35
36
@lru_cache
37
def
getPDGTABLE
(table):
38
# Delete a local file if present
39
if
os.path.isfile(table):
40
os.remove(table)
41
# Grab the file
42
os.system(
'get_files -data %s'
% table)
43
return
True
44
45
46
@lru_cache
47
def
getExtraParticleAcceptList
(acceptlist):
48
# Delete a local file if present
49
if
os.path.isfile(acceptlist):
50
os.remove(acceptlist)
51
#create blank file
52
blank = open(
'G4particle_acceptlist_ExtraParticles.txt'
,
'x'
)
53
blank.close()
54
return
True
55
56
57
def
updateExtraParticleAcceptList
(listName='G4particle_acceptlist_ExtraParticles.txt', pdgcodes=[]):
58
if
getExtraParticleAcceptList
(listName):
59
import
shutil
60
shutil.copy(listName, listName+
'.org'
)
61
existingpdgcodes = [int(x)
for
x
in
open(listName).readlines()]
62
newpdgcodes = list(
set
(pdgcodes).difference(existingpdgcodes))
63
# update the acceptlist for GenParticleSimAcceptList
64
with
open(listName,
'a'
)
as
writer:
65
for
pdg
in
newpdgcodes:
66
writer.write(
'%s\n'
% pdg)
67
68
69
class
ExtraParticle
(object):
70
name =
""
71
mass = -1
72
width = -1
73
charge = 0
74
pdg = 0
75
lifetime = h_Planck / joule
76
77
def
__init__
(self, **kwargs):
78
self.__dict__.update(kwargs)
79
80
def
__str__
(self):
81
string =
''
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
88
return
string
89
90
def
__neg__
(self):
91
antiParticle =
ExtraParticle
(**self.__dict__)
92
antiParticle.name = self.
getAntiName
()
93
antiParticle.charge *= -1
94
antiParticle.pdg *= -1
95
return
antiParticle
96
97
def
getAntiName
(self):
98
if
self.
name
[-1] ==
'0'
:
99
if
'anti_'
in
self.
name
:
100
return
self.
name
.
replace
(
'anti_'
,
''
)
101
else
:
102
return
'anti_'
+ self.
name
103
elif
self.
name
[-1] ==
'+'
:
104
return
self.
name
.
replace
(
'+'
,
'-'
)
105
elif
self.
name
[-1] ==
'-'
:
106
return
self.
name
.
replace
(
'-'
,
'+'
)
107
108
109
class
PDGParser
(object):
110
111
def
__init__
(self, table, ranges):
112
self.
log
= logging.getLogger(__name__)
113
self.
table
= table
114
self.
ranges
= ranges
115
self.
extraParticles
= {}
116
self.
parsePDGTABLE
()
117
118
def
accept
(self, pdg):
119
"""Function to determine which extra particles are added
120
121
Function checks the ranges member variable
122
and evaluates whether the particle should be accepted.
123
124
TODO Consider adding a Sim.ExtraParticlesRanges ConfigFlag
125
126
For example, '111-556,1112-9090226' matches everything from
127
111 to 555 and 1112 to 9090225.
128
"""
129
ranges = [r.split(
"-"
)
for
r
in
self.
ranges
.
split
(
","
)]
130
for
r
in
ranges:
131
if
int(r[0]) <= pdg < int(r[1]):
132
return
True
133
134
def
parsePDGTABLE
(self):
135
136
# parse the PDGTABLE
137
with
open(self.
table
,
'r'
)
as
f:
138
for
line
in
f:
139
if
line.startswith(
'*'
):
140
# Comments start with '*'
141
continue
142
splitLine = line.split()
143
144
# Name of the particle
145
baseName = splitLine[-2]
146
147
# Number of particle entries
148
charges = splitLine[-1].
split
(
','
)
149
150
# Mass or Width
151
prop =
''
152
symbol = splitLine[0]
153
if
symbol ==
'M'
:
154
prop =
'mass'
155
elif
symbol ==
'W'
:
156
prop =
'width'
157
else
:
158
raise
ValueError(
159
'Unidentified symbol %s for particle %s'
% (
160
symbol, baseName))
161
162
pdgs = splitLine[1:1+len(charges)]
163
value = float(splitLine[1+len(charges)])
164
165
for
pdg, charge
in
zip(pdgs, charges):
166
if
not
self.
accept
(int(pdg)):
167
continue
168
name = self.
formatName
(baseName, charge)
169
kwargs = dict()
170
kwargs.setdefault(
'name'
, name)
171
kwargs.setdefault(prop, value * MeV)
172
kwargs.setdefault(
'pdg'
, int(pdg))
173
kwargs.setdefault(
'charge'
, self.
formatCharge
(charge))
174
if
name
not
in
self.
extraParticles
.keys():
175
self.
extraParticles
[name] =
ExtraParticle
(**kwargs)
176
else
:
177
if
getattr(self.
extraParticles
[name], prop) != -1:
178
self.
log
.warning(
179
"Property %s is already"
180
"set for particle %s."
181
"Current value is %s and"
182
"incoming value is %s."
,
183
prop, name,
184
getattr(self.
extraParticles
[name], prop),
185
value)
186
continue
187
setattr(self.
extraParticles
[name], prop, value)
188
189
for
name
in
self.
extraParticles
:
190
# calculate lifetime
191
width = self.
extraParticles
[name].width
192
if
width > 0:
193
self.
extraParticles
[name].lifetime = hbar_Planck/width
194
195
# create anti-particles
196
for
name
in
[x
for
x
in
self.
extraParticles
.keys()]:
197
antiParticle = -self.
extraParticles
[name]
198
self.
extraParticles
.update({antiParticle.name: antiParticle})
199
200
def
formatName
(self, name, charge):
201
nameOut = name
202
nameOut = nameOut.replace(
"*"
,
"_star"
).
replace
(
"'"
,
"_prime"
)
203
nameOut += charge
204
return
nameOut
205
206
def
formatCharge
(self, charge):
207
# check that all characters are the same
208
# e.g.: '0', '+', '--', ...
209
if
not
(charge == len(charge) * charge[0]):
210
raise
ValueError(
'Unexpected charge %s'
% charge)
211
212
# parse string
213
if
'+'
in
charge:
214
return
len(charge)
215
elif
'-'
in
charge:
216
return
-len(charge)
217
elif
'0'
in
charge:
218
return
0
219
else
:
220
raise
ValueError(
'Unexpected charge %s'
% charge)
221
222
def
createList
(self):
223
pdgcodes = [ self.
extraParticles
[name].pdg
for
name
in
self.
extraParticles
]
224
updateExtraParticleAcceptList
(
'G4particle_acceptlist_ExtraParticles.txt'
, pdgcodes)
225
226
# generate output in correct format
227
outDict = dict()
228
for
name
in
self.
extraParticles
:
229
outDict.update({name: [
230
self.
extraParticles
[name].mass,
231
self.
extraParticles
[name].width,
232
self.
extraParticles
[name].charge,
233
self.
extraParticles
[name].pdg,
234
self.
extraParticles
[name].lifetime
235
]})
236
237
return
outDict
PDGHelpers.ExtraParticle
Definition
PDGHelpers.py:69
PDGHelpers.ExtraParticle.lifetime
lifetime
Definition
PDGHelpers.py:75
PDGHelpers.ExtraParticle.pdg
int pdg
Definition
PDGHelpers.py:74
PDGHelpers.ExtraParticle.name
str name
Definition
PDGHelpers.py:70
PDGHelpers.ExtraParticle.__init__
__init__(self, **kwargs)
Definition
PDGHelpers.py:77
PDGHelpers.ExtraParticle.__neg__
__neg__(self)
Definition
PDGHelpers.py:90
PDGHelpers.ExtraParticle.mass
int mass
Definition
PDGHelpers.py:71
PDGHelpers.ExtraParticle.width
int width
Definition
PDGHelpers.py:72
PDGHelpers.ExtraParticle.__str__
__str__(self)
Definition
PDGHelpers.py:80
PDGHelpers.ExtraParticle.charge
int charge
Definition
PDGHelpers.py:73
PDGHelpers.ExtraParticle.getAntiName
getAntiName(self)
Definition
PDGHelpers.py:97
PDGHelpers.PDGParser
Definition
PDGHelpers.py:109
PDGHelpers.PDGParser.accept
accept(self, pdg)
Definition
PDGHelpers.py:118
PDGHelpers.PDGParser.parsePDGTABLE
parsePDGTABLE(self)
Definition
PDGHelpers.py:134
PDGHelpers.PDGParser.formatCharge
formatCharge(self, charge)
Definition
PDGHelpers.py:206
PDGHelpers.PDGParser.createList
createList(self)
Definition
PDGHelpers.py:222
PDGHelpers.PDGParser.log
log
Definition
PDGHelpers.py:112
PDGHelpers.PDGParser.__init__
__init__(self, table, ranges)
Definition
PDGHelpers.py:111
PDGHelpers.PDGParser.table
table
Definition
PDGHelpers.py:113
PDGHelpers.PDGParser.extraParticles
dict extraParticles
Definition
PDGHelpers.py:115
PDGHelpers.PDGParser.ranges
ranges
Definition
PDGHelpers.py:114
PDGHelpers.PDGParser.formatName
formatName(self, name, charge)
Definition
PDGHelpers.py:200
set
STL class.
replace
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition
hcg.cxx:312
split
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition
hcg.cxx:179
PDGHelpers.getExtraParticleAcceptList
getExtraParticleAcceptList(acceptlist)
Definition
PDGHelpers.py:47
PDGHelpers.updateExtraParticleAcceptList
updateExtraParticleAcceptList(listName='G4particle_acceptlist_ExtraParticles.txt', pdgcodes=[])
Definition
PDGHelpers.py:57
PDGHelpers.getPDGTABLE
getPDGTABLE(table)
Definition
PDGHelpers.py:37
Generated on
for ATLAS Offline Software by
1.17.0