• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openmc-dev / openmc / 13591584831

28 Feb 2025 03:46PM UTC coverage: 85.051% (+0.3%) from 84.722%
13591584831

Pull #3067

github

web-flow
Merge 08055e996 into c26fde666
Pull Request #3067: Implement user-configurable random number stride

36 of 44 new or added lines in 8 files covered. (81.82%)

3588 existing lines in 111 files now uncovered.

51062 of 60037 relevant lines covered (85.05%)

32650986.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.75
/openmc/data/data.py
1
import itertools
12✔
2
import json
12✔
3
import os
12✔
4
import re
12✔
5
from pathlib import Path
12✔
6
from math import sqrt, log
12✔
7
from warnings import warn
12✔
8

9
# Isotopic abundances from Meija J, Coplen T B, et al, "Isotopic compositions
10
# of the elements 2013 (IUPAC Technical Report)", Pure. Appl. Chem. 88 (3),
11
# pp. 293-306 (2013). The "representative isotopic abundance" values from
12
# column 9 are used except where an interval is given, in which case the
13
# "best measurement" is used.
14
# Note that the abundances are given as atomic fractions!
15
NATURAL_ABUNDANCE = {
12✔
16
    'H1': 0.99984426, 'H2': 0.00015574, 'He3': 0.000002,
17
    'He4': 0.999998, 'Li6': 0.07589, 'Li7': 0.92411,
18
    'Be9': 1.0, 'B10': 0.1982, 'B11': 0.8018,
19
    'C12': 0.988922, 'C13': 0.011078, 'N14': 0.996337,
20
    'N15': 0.003663, 'O16': 0.9976206, 'O17': 0.000379,
21
    'O18': 0.0020004, 'F19': 1.0, 'Ne20': 0.9048,
22
    'Ne21': 0.0027, 'Ne22': 0.0925, 'Na23': 1.0,
23
    'Mg24': 0.78951, 'Mg25': 0.1002, 'Mg26': 0.11029,
24
    'Al27': 1.0, 'Si28': 0.9222968, 'Si29': 0.0468316,
25
    'Si30': 0.0308716, 'P31': 1.0, 'S32': 0.9504074,
26
    'S33': 0.0074869, 'S34': 0.0419599, 'S36': 0.0001458,
27
    'Cl35': 0.757647, 'Cl37': 0.242353, 'Ar36': 0.003336,
28
    'Ar38': 0.000629, 'Ar40': 0.996035, 'K39': 0.932581,
29
    'K40': 0.000117, 'K41': 0.067302, 'Ca40': 0.96941,
30
    'Ca42': 0.00647, 'Ca43': 0.00135, 'Ca44': 0.02086,
31
    'Ca46': 0.00004, 'Ca48': 0.00187, 'Sc45': 1.0,
32
    'Ti46': 0.0825, 'Ti47': 0.0744, 'Ti48': 0.7372,
33
    'Ti49': 0.0541, 'Ti50': 0.0518, 'V50': 0.0025,
34
    'V51': 0.9975, 'Cr50': 0.04345, 'Cr52': 0.83789,
35
    'Cr53': 0.09501, 'Cr54': 0.02365, 'Mn55': 1.0,
36
    'Fe54': 0.05845, 'Fe56': 0.91754, 'Fe57': 0.02119,
37
    'Fe58': 0.00282, 'Co59': 1.0, 'Ni58': 0.680769,
38
    'Ni60': 0.262231, 'Ni61': 0.011399, 'Ni62': 0.036345,
39
    'Ni64': 0.009256, 'Cu63': 0.6915, 'Cu65': 0.3085,
40
    'Zn64': 0.4917, 'Zn66': 0.2773, 'Zn67': 0.0404,
41
    'Zn68': 0.1845, 'Zn70': 0.0061, 'Ga69': 0.60108,
42
    'Ga71': 0.39892, 'Ge70': 0.2052, 'Ge72': 0.2745,
43
    'Ge73': 0.0776, 'Ge74': 0.3652, 'Ge76': 0.0775,
44
    'As75': 1.0, 'Se74': 0.0086, 'Se76': 0.0923,
45
    'Se77': 0.076, 'Se78': 0.2369, 'Se80': 0.498,
46
    'Se82': 0.0882, 'Br79': 0.50686, 'Br81': 0.49314,
47
    'Kr78': 0.00355, 'Kr80': 0.02286, 'Kr82': 0.11593,
48
    'Kr83': 0.115, 'Kr84': 0.56987, 'Kr86': 0.17279,
49
    'Rb85': 0.7217, 'Rb87': 0.2783, 'Sr84': 0.0056,
50
    'Sr86': 0.0986, 'Sr87': 0.07, 'Sr88': 0.8258,
51
    'Y89': 1.0, 'Zr90': 0.5145, 'Zr91': 0.1122,
52
    'Zr92': 0.1715, 'Zr94': 0.1738, 'Zr96': 0.028,
53
    'Nb93': 1.0, 'Mo92': 0.14649, 'Mo94': 0.09187,
54
    'Mo95': 0.15873, 'Mo96': 0.16673, 'Mo97': 0.09582,
55
    'Mo98': 0.24292, 'Mo100': 0.09744, 'Ru96': 0.0554,
56
    'Ru98': 0.0187, 'Ru99': 0.1276, 'Ru100': 0.126,
57
    'Ru101': 0.1706, 'Ru102': 0.3155, 'Ru104': 0.1862,
58
    'Rh103': 1.0, 'Pd102': 0.0102, 'Pd104': 0.1114,
59
    'Pd105': 0.2233, 'Pd106': 0.2733, 'Pd108': 0.2646,
60
    'Pd110': 0.1172, 'Ag107': 0.51839, 'Ag109': 0.48161,
61
    'Cd106': 0.01245, 'Cd108': 0.00888, 'Cd110': 0.1247,
62
    'Cd111': 0.12795, 'Cd112': 0.24109, 'Cd113': 0.12227,
63
    'Cd114': 0.28754, 'Cd116': 0.07512, 'In113': 0.04281,
64
    'In115': 0.95719, 'Sn112': 0.0097, 'Sn114': 0.0066,
65
    'Sn115': 0.0034, 'Sn116': 0.1454, 'Sn117': 0.0768,
66
    'Sn118': 0.2422, 'Sn119': 0.0859, 'Sn120': 0.3258,
67
    'Sn122': 0.0463, 'Sn124': 0.0579, 'Sb121': 0.5721,
68
    'Sb123': 0.4279, 'Te120': 0.0009, 'Te122': 0.0255,
69
    'Te123': 0.0089, 'Te124': 0.0474, 'Te125': 0.0707,
70
    'Te126': 0.1884, 'Te128': 0.3174, 'Te130': 0.3408,
71
    'I127': 1.0, 'Xe124': 0.00095, 'Xe126': 0.00089,
72
    'Xe128': 0.0191, 'Xe129': 0.26401, 'Xe130': 0.04071,
73
    'Xe131': 0.21232, 'Xe132': 0.26909, 'Xe134': 0.10436,
74
    'Xe136': 0.08857, 'Cs133': 1.0, 'Ba130': 0.0011,
75
    'Ba132': 0.001, 'Ba134': 0.0242, 'Ba135': 0.0659,
76
    'Ba136': 0.0785, 'Ba137': 0.1123, 'Ba138': 0.717,
77
    'La138': 0.0008881, 'La139': 0.9991119, 'Ce136': 0.00186,
78
    'Ce138': 0.00251, 'Ce140': 0.88449, 'Ce142': 0.11114,
79
    'Pr141': 1.0, 'Nd142': 0.27153, 'Nd143': 0.12173,
80
    'Nd144': 0.23798, 'Nd145': 0.08293, 'Nd146': 0.17189,
81
    'Nd148': 0.05756, 'Nd150': 0.05638, 'Sm144': 0.0308,
82
    'Sm147': 0.15, 'Sm148': 0.1125, 'Sm149': 0.1382,
83
    'Sm150': 0.0737, 'Sm152': 0.2674, 'Sm154': 0.2274,
84
    'Eu151': 0.4781, 'Eu153': 0.5219, 'Gd152': 0.002,
85
    'Gd154': 0.0218, 'Gd155': 0.148, 'Gd156': 0.2047,
86
    'Gd157': 0.1565, 'Gd158': 0.2484, 'Gd160': 0.2186,
87
    'Tb159': 1.0, 'Dy156': 0.00056, 'Dy158': 0.00095,
88
    'Dy160': 0.02329, 'Dy161': 0.18889, 'Dy162': 0.25475,
89
    'Dy163': 0.24896, 'Dy164': 0.2826, 'Ho165': 1.0,
90
    'Er162': 0.00139, 'Er164': 0.01601, 'Er166': 0.33503,
91
    'Er167': 0.22869, 'Er168': 0.26978, 'Er170': 0.1491,
92
    'Tm169': 1.0, 'Yb168': 0.00123, 'Yb170': 0.02982,
93
    'Yb171': 0.14086, 'Yb172': 0.21686, 'Yb173': 0.16103,
94
    'Yb174': 0.32025, 'Yb176': 0.12995, 'Lu175': 0.97401,
95
    'Lu176': 0.02599, 'Hf174': 0.0016, 'Hf176': 0.0526,
96
    'Hf177': 0.186, 'Hf178': 0.2728, 'Hf179': 0.1362,
97
    'Hf180': 0.3508, 'Ta180': 0.0001201, 'Ta181': 0.9998799,
98
    'W180': 0.0012, 'W182': 0.265, 'W183': 0.1431,
99
    'W184': 0.3064, 'W186': 0.2843, 'Re185': 0.374,
100
    'Re187': 0.626, 'Os184': 0.0002, 'Os186': 0.0159,
101
    'Os187': 0.0196, 'Os188': 0.1324, 'Os189': 0.1615,
102
    'Os190': 0.2626, 'Os192': 0.4078, 'Ir191': 0.373,
103
    'Ir193': 0.627, 'Pt190': 0.00012, 'Pt192': 0.00782,
104
    'Pt194': 0.32864, 'Pt195': 0.33775, 'Pt196': 0.25211,
105
    'Pt198': 0.07356, 'Au197': 1.0, 'Hg196': 0.0015,
106
    'Hg198': 0.1004, 'Hg199': 0.1694, 'Hg200': 0.2314,
107
    'Hg201': 0.1317, 'Hg202': 0.2974, 'Hg204': 0.0682,
108
    'Tl203': 0.29524, 'Tl205': 0.70476, 'Pb204': 0.014,
109
    'Pb206': 0.241, 'Pb207': 0.221, 'Pb208': 0.524,
110
    'Bi209': 1.0, 'Th230': 0.0002, 'Th232': 0.9998,
111
    'Pa231': 1.0, 'U234': 0.000054, 'U235': 0.007204,
112
    'U238': 0.992742
113
}
114

115
# Dictionary to give element symbols from IUPAC names
116
# (and some common mispellings)
117
ELEMENT_SYMBOL = {'neutron': 'n', 'hydrogen': 'H', 'helium': 'He',
12✔
118
                 'lithium': 'Li', 'beryllium': 'Be', 'boron': 'B',
119
                 'carbon': 'C', 'nitrogen': 'N', 'oxygen': 'O', 'fluorine': 'F',
120
                 'neon': 'Ne', 'sodium': 'Na', 'magnesium': 'Mg',
121
                 'aluminium': 'Al', 'aluminum': 'Al', 'silicon': 'Si',
122
                 'phosphorus': 'P', 'sulfur': 'S', 'sulphur': 'S',
123
                 'chlorine': 'Cl', 'argon': 'Ar', 'potassium': 'K',
124
                 'calcium': 'Ca', 'scandium': 'Sc', 'titanium': 'Ti',
125
                 'vanadium': 'V', 'chromium': 'Cr', 'manganese': 'Mn',
126
                 'iron': 'Fe', 'cobalt': 'Co', 'nickel': 'Ni', 'copper': 'Cu',
127
                 'zinc': 'Zn', 'gallium': 'Ga', 'germanium': 'Ge',
128
                 'arsenic': 'As', 'selenium': 'Se', 'bromine': 'Br',
129
                 'krypton': 'Kr', 'rubidium': 'Rb', 'strontium': 'Sr',
130
                 'yttrium': 'Y', 'zirconium': 'Zr', 'niobium': 'Nb',
131
                 'molybdenum': 'Mo', 'technetium': 'Tc', 'ruthenium': 'Ru',
132
                 'rhodium': 'Rh', 'palladium': 'Pd', 'silver': 'Ag',
133
                 'cadmium': 'Cd', 'indium': 'In', 'tin': 'Sn', 'antimony': 'Sb',
134
                 'tellurium': 'Te', 'iodine': 'I', 'xenon': 'Xe',
135
                 'caesium': 'Cs', 'cesium': 'Cs', 'barium': 'Ba',
136
                 'lanthanum': 'La', 'cerium': 'Ce', 'praseodymium': 'Pr',
137
                 'neodymium': 'Nd', 'promethium': 'Pm', 'samarium': 'Sm',
138
                 'europium': 'Eu', 'gadolinium': 'Gd', 'terbium': 'Tb',
139
                 'dysprosium': 'Dy', 'holmium': 'Ho', 'erbium': 'Er',
140
                 'thulium': 'Tm', 'ytterbium': 'Yb', 'lutetium': 'Lu',
141
                 'hafnium': 'Hf', 'tantalum': 'Ta', 'tungsten': 'W',
142
                 'wolfram': 'W', 'rhenium': 'Re', 'osmium': 'Os',
143
                 'iridium': 'Ir', 'platinum': 'Pt', 'gold': 'Au',
144
                 'mercury': 'Hg', 'thallium': 'Tl', 'lead': 'Pb',
145
                 'bismuth': 'Bi', 'polonium': 'Po', 'astatine': 'At',
146
                 'radon': 'Rn', 'francium': 'Fr', 'radium': 'Ra',
147
                 'actinium': 'Ac', 'thorium': 'Th', 'protactinium': 'Pa',
148
                 'uranium': 'U', 'neptunium': 'Np', 'plutonium': 'Pu',
149
                 'americium': 'Am', 'curium': 'Cm', 'berkelium': 'Bk',
150
                 'californium': 'Cf', 'einsteinium': 'Es', 'fermium': 'Fm',
151
                 'mendelevium': 'Md', 'nobelium': 'No', 'lawrencium': 'Lr',
152
                 'rutherfordium': 'Rf', 'dubnium': 'Db', 'seaborgium': 'Sg',
153
                 'bohrium': 'Bh', 'hassium': 'Hs', 'meitnerium': 'Mt',
154
                 'darmstadtium': 'Ds', 'roentgenium': 'Rg', 'copernicium': 'Cn',
155
                 'nihonium': 'Nh', 'flerovium': 'Fl', 'moscovium': 'Mc',
156
                 'livermorium': 'Lv', 'tennessine': 'Ts', 'oganesson': 'Og'}
157

158
ATOMIC_SYMBOL = {0: 'n', 1: 'H', 2: 'He', 3: 'Li', 4: 'Be', 5: 'B', 6: 'C',
12✔
159
                 7: 'N', 8: 'O', 9: 'F', 10: 'Ne', 11: 'Na', 12: 'Mg', 13: 'Al',
160
                 14: 'Si', 15: 'P', 16: 'S', 17: 'Cl', 18: 'Ar', 19: 'K',
161
                 20: 'Ca', 21: 'Sc', 22: 'Ti', 23: 'V', 24: 'Cr', 25: 'Mn',
162
                 26: 'Fe', 27: 'Co', 28: 'Ni', 29: 'Cu', 30: 'Zn', 31: 'Ga',
163
                 32: 'Ge', 33: 'As', 34: 'Se', 35: 'Br', 36: 'Kr', 37: 'Rb',
164
                 38: 'Sr', 39: 'Y', 40: 'Zr', 41: 'Nb', 42: 'Mo', 43: 'Tc',
165
                 44: 'Ru', 45: 'Rh', 46: 'Pd', 47: 'Ag', 48: 'Cd', 49: 'In',
166
                 50: 'Sn', 51: 'Sb', 52: 'Te', 53: 'I', 54: 'Xe', 55: 'Cs',
167
                 56: 'Ba', 57: 'La', 58: 'Ce', 59: 'Pr', 60: 'Nd', 61: 'Pm',
168
                 62: 'Sm', 63: 'Eu', 64: 'Gd', 65: 'Tb', 66: 'Dy', 67: 'Ho',
169
                 68: 'Er', 69: 'Tm', 70: 'Yb', 71: 'Lu', 72: 'Hf', 73: 'Ta',
170
                 74: 'W', 75: 'Re', 76: 'Os', 77: 'Ir', 78: 'Pt', 79: 'Au',
171
                 80: 'Hg', 81: 'Tl', 82: 'Pb', 83: 'Bi', 84: 'Po', 85: 'At',
172
                 86: 'Rn', 87: 'Fr', 88: 'Ra', 89: 'Ac', 90: 'Th', 91: 'Pa',
173
                 92: 'U', 93: 'Np', 94: 'Pu', 95: 'Am', 96: 'Cm', 97: 'Bk',
174
                 98: 'Cf', 99: 'Es', 100: 'Fm', 101: 'Md', 102: 'No',
175
                 103: 'Lr', 104: 'Rf', 105: 'Db', 106: 'Sg', 107: 'Bh',
176
                 108: 'Hs', 109: 'Mt', 110: 'Ds', 111: 'Rg', 112: 'Cn',
177
                 113: 'Nh', 114: 'Fl', 115: 'Mc', 116: 'Lv', 117: 'Ts',
178
                 118: 'Og'}
179
ATOMIC_NUMBER = {value: key for key, value in ATOMIC_SYMBOL.items()}
12✔
180

181
DADZ = {
12✔
182
    '(n,2nd)': (-3, -1),
183
    '(n,2n)': (-1, 0),
184
    '(n,3n)': (-2, 0),
185
    '(n,na)': (-4, -2),
186
    '(n,n3a)': (-12, -6),
187
    '(n,2na)': (-5, -2),
188
    '(n,3na)': (-6, -2),
189
    '(n,np)': (-1, -1),
190
    '(n,n2a)': (-8, -4),
191
    '(n,2n2a)': (-9, -4),
192
    '(n,nd)': (-2, -1),
193
    '(n,nt)': (-3, -1),
194
    '(n,n3He)': (-3, -2),
195
    '(n,nd2a)': (-10, -5),
196
    '(n,nt2a)': (-11, -5),
197
    '(n,4n)': (-3, 0),
198
    '(n,2np)': (-2, -1),
199
    '(n,3np)': (-3, -1),
200
    '(n,n2p)': (-2, -2),
201
    '(n,npa)': (-5, -3),
202
    '(n,gamma)': (1, 0),
203
    '(n,p)': (0, -1),
204
    '(n,d)': (-1, -1),
205
    '(n,t)': (-2, -1),
206
    '(n,3He)': (-2, -2),
207
    '(n,a)': (-3, -2),
208
    '(n,2a)': (-7, -4),
209
    '(n,3a)': (-11, -6),
210
    '(n,2p)': (-1, -2),
211
    '(n,pa)': (-4, -3),
212
    '(n,t2a)': (-10, -5),
213
    '(n,d2a)': (-9, -5),
214
    '(n,pd)': (-2, -2),
215
    '(n,pt)': (-3, -2),
216
    '(n,da)': (-5, -3),
217
    '(n,5n)': (-4, 0),
218
    '(n,6n)': (-5, 0),
219
    '(n,2nt)': (-4, -1),
220
    '(n,ta)': (-6, -3),
221
    '(n,4np)': (-4, -1),
222
    '(n,3nd)': (-4, -1),
223
    '(n,nda)': (-6, -3),
224
    '(n,2npa)': (-6, -3),
225
    '(n,7n)': (-6, 0),
226
    '(n,8n)': (-7, 0),
227
    '(n,5np)': (-5, -1),
228
    '(n,6np)': (-6, -1),
229
    '(n,7np)': (-7, -1),
230
    '(n,4na)': (-7, -2),
231
    '(n,5na)': (-8, -2),
232
    '(n,6na)': (-9, -2),
233
    '(n,7na)': (-10, -2),
234
    '(n,4nd)': (-5, -1),
235
    '(n,5nd)': (-6, -1),
236
    '(n,6nd)': (-7, -1),
237
    '(n,3nt)': (-5, -1),
238
    '(n,4nt)': (-6, -1),
239
    '(n,5nt)': (-7, -1),
240
    '(n,6nt)': (-8, -1),
241
    '(n,2n3He)': (-4, -2),
242
    '(n,3n3He)': (-5, -2),
243
    '(n,4n3He)': (-6, -2),
244
    '(n,3n2p)': (-4, -2),
245
    '(n,3n2a)': (-10, -4),
246
    '(n,3npa)': (-7, -3),
247
    '(n,dt)': (-4, -2),
248
    '(n,npd)': (-3, -2),
249
    '(n,npt)': (-4, -2),
250
    '(n,ndt)': (-5, -2),
251
    '(n,np3He)': (-4, -3),
252
    '(n,nd3He)': (-5, -3),
253
    '(n,nt3He)': (-6, -3),
254
    '(n,nta)': (-7, -3),
255
    '(n,2n2p)': (-3, -2),
256
    '(n,p3He)': (-4, -3),
257
    '(n,d3He)': (-5, -3),
258
    '(n,3Hea)': (-6, -4),
259
    '(n,4n2p)': (-5, -2),
260
    '(n,4n2a)': (-11, -4),
261
    '(n,4npa)': (-8, -3),
262
    '(n,3p)': (-2, -3),
263
    '(n,n3p)': (-3, -3),
264
    '(n,3n2pa)': (-8, -4),
265
    '(n,5n2p)': (-6, -2),
266
}
267

268
# Values here are from the Committee on Data for Science and Technology
269
# (CODATA) 2018 recommendation (https://physics.nist.gov/cuu/Constants/).
270

271
# The value of the Boltzman constant in units of eV / K
272
K_BOLTZMANN = 8.617333262e-5
12✔
273

274
# Unit conversions
275
EV_PER_MEV = 1.0e6
12✔
276
JOULE_PER_EV = 1.602176634e-19
12✔
277

278
# Avogadro's constant
279
AVOGADRO = 6.02214076e23
12✔
280

281
# Neutron mass in units of amu
282
NEUTRON_MASS = 1.00866491595
12✔
283

284
# Used in atomic_mass function as a cache
285
_ATOMIC_MASS: dict[str, float] = {}
12✔
286

287
# Regex for GNDS nuclide names (used in zam function)
288
_GNDS_NAME_RE = re.compile(r'([A-Zn][a-z]*)(\d+)((?:_[em]\d+)?)')
12✔
289

290
# Used in half_life function as a cache
291
_HALF_LIFE: dict[str, float] = {}
12✔
292
_LOG_TWO = log(2.0)
12✔
293

294
def atomic_mass(isotope):
12✔
295
    """Return atomic mass of isotope in atomic mass units.
296

297
    Atomic mass data comes from the `Atomic Mass Evaluation 2020
298
    <https://doi.org/10.1088/1674-1137/abddaf>`_.
299

300
    Parameters
301
    ----------
302
    isotope : str
303
        Name of isotope, e.g., 'Pu239'
304

305
    Returns
306
    -------
307
    float
308
        Atomic mass of isotope in [amu]
309

310
    """
311
    if not _ATOMIC_MASS:
12✔
312

313
        # Load data from AME2020 file
314
        mass_file = os.path.join(os.path.dirname(__file__), 'mass_1.mas20.txt')
12✔
315
        with open(mass_file, 'r') as ame:
12✔
316
            # Read lines in file starting at line 37
317
            for line in itertools.islice(ame, 36, None):
12✔
318
                name = f'{line[20:22].strip()}{int(line[16:19])}'
12✔
319
                mass = float(line[106:109]) + 1e-6*float(
12✔
320
                    line[110:116] + '.' + line[117:123])
321
                _ATOMIC_MASS[name.lower()] = mass
12✔
322

323
        # For isotopes found in some libraries that represent all natural
324
        # isotopes of their element (e.g. C0), calculate the atomic mass as
325
        # the sum of the atomic mass times the natural abundance of the isotopes
326
        # that make up the element.
327
        for element in ['C', 'Zn', 'Pt', 'Os', 'Tl']:
12✔
328
            isotope_zero = element.lower() + '0'
12✔
329
            _ATOMIC_MASS[isotope_zero] = 0.
12✔
330
            for iso, abundance in isotopes(element):
12✔
331
                _ATOMIC_MASS[isotope_zero] += abundance * _ATOMIC_MASS[iso.lower()]
12✔
332

333
    # Get rid of metastable information
334
    if '_' in isotope:
12✔
335
        isotope = isotope[:isotope.find('_')]
12✔
336

337
    return _ATOMIC_MASS[isotope.lower()]
12✔
338

339

340
def atomic_weight(element):
12✔
341
    """Return atomic weight of an element in atomic mass units.
342

343
    Computes an average of the atomic mass of each of element's naturally
344
    occurring isotopes weighted by their relative abundance.
345

346
    Parameters
347
    ----------
348
    element : str
349
        Element symbol (e.g., 'H') or name (e.g., 'helium')
350

351
    Returns
352
    -------
353
    float
354
        Atomic weight of element in [amu]
355

356
    """
357
    weight = 0.
12✔
358
    for nuclide, abundance in isotopes(element):
12✔
359
        weight += atomic_mass(nuclide) * abundance
12✔
360
    if weight > 0.:
12✔
361
        return weight
12✔
362
    else:
363
        raise ValueError(f"No naturally-occurring isotopes for element '{element}'.")
12✔
364

365

366
def half_life(isotope):
12✔
367
    """Return half-life of isotope in seconds or None if isotope is stable
368

369
    Half-life values are from the `ENDF/B-VIII.0 decay sublibrary
370
    <https://www.nndc.bnl.gov/endf-b8.0/download.html>`_.
371

372
    .. versionadded:: 0.13.1
373

374
    Parameters
375
    ----------
376
    isotope : str
377
        Name of isotope, e.g., 'Pu239'
378

379
    Returns
380
    -------
381
    float
382
        Half-life of isotope in [s]
383

384
    """
385
    global _HALF_LIFE
386
    if not _HALF_LIFE:
12✔
387
        # Load ENDF/B-VIII.0 data from JSON file
388
        half_life_path = Path(__file__).with_name('half_life.json')
12✔
389
        _HALF_LIFE = json.loads(half_life_path.read_text())
12✔
390

391
    return _HALF_LIFE.get(isotope.lower())
12✔
392

393

394
def decay_constant(isotope):
12✔
395
    """Return decay constant of isotope in [s^-1]
396

397
    Decay constants are based on half-life values from the
398
    :func:`~openmc.data.half_life` function. When the isotope is stable, a decay
399
    constant of zero is returned.
400

401
    .. versionadded:: 0.13.1
402

403
    Parameters
404
    ----------
405
    isotope : str
406
        Name of isotope, e.g., 'Pu239'
407

408
    Returns
409
    -------
410
    float
411
        Decay constant of isotope in [s^-1]
412

413
    See also
414
    --------
415
    openmc.data.half_life
416

417
    """
418
    t = half_life(isotope)
12✔
419
    return _LOG_TWO / t if t else 0.0
12✔
420

421

422
def water_density(temperature, pressure=0.1013):
12✔
423
    """Return the density of liquid water at a given temperature and pressure.
424

425
    The density is calculated from a polynomial fit using equations and values
426
    from the 2012 version of the IAPWS-IF97 formulation.  Only the equations
427
    for region 1 are implemented here.  Region 1 is limited to liquid water
428
    below 100 [MPa] with a temperature above 273.15 [K], below 623.15 [K], and
429
    below saturation.
430

431
    Reference: International Association for the Properties of Water and Steam,
432
    "Revised Release on the IAPWS Industrial Formulation 1997 for the
433
    Thermodynamic Properties of Water and Steam", IAPWS R7-97(2012).
434

435
    Parameters
436
    ----------
437
    temperature : float
438
        Water temperature in units of [K]
439
    pressure : float
440
        Water pressure in units of [MPa]
441

442
    Returns
443
    -------
444
    float
445
        Water density in units of [g/cm^3]
446

447
    """
448

449
    # Make sure the temperature and pressure are inside the min/max region 1
450
    # bounds.  (Relax the 273.15 bound to 273 in case a user wants 0 deg C data
451
    # but they only use 3 digits for their conversion to K.)
452
    if pressure > 100.0:
12✔
UNCOV
453
        warn("Results are not valid for pressures above 100 MPa.")
×
454
    elif pressure < 0.0:
12✔
UNCOV
455
        raise ValueError("Pressure must be positive.")
×
456
    if temperature < 273:
12✔
UNCOV
457
        warn("Results are not valid for temperatures below 273.15 K.")
×
458
    elif temperature > 623.15:
12✔
UNCOV
459
        warn("Results are not valid for temperatures above 623.15 K.")
×
460
    elif temperature <= 0.0:
12✔
UNCOV
461
        raise ValueError('Temperature must be positive.')
×
462

463
    # IAPWS region 4 parameters
464
    n4 = [0.11670521452767e4, -0.72421316703206e6, -0.17073846940092e2,
12✔
465
          0.12020824702470e5, -0.32325550322333e7, 0.14915108613530e2,
466
          -0.48232657361591e4, 0.40511340542057e6, -0.23855557567849,
467
          0.65017534844798e3]
468

469
    # Compute the saturation temperature at the given pressure.
470
    beta = pressure**(0.25)
12✔
471
    E = beta**2 + n4[2] * beta + n4[5]
12✔
472
    F = n4[0] * beta**2 + n4[3] * beta + n4[6]
12✔
473
    G = n4[1] * beta**2 + n4[4] * beta + n4[7]
12✔
474
    D = 2.0 * G / (-F - sqrt(F**2 - 4 * E * G))
12✔
475
    T_sat = 0.5 * (n4[9] + D
12✔
476
                   - sqrt((n4[9] + D)**2  - 4.0 * (n4[8] + n4[9] * D)))
477

478
    # Make sure we aren't above saturation.  (Relax this bound by .2 degrees
479
    # for deg C to K conversions.)
480
    if temperature > T_sat + 0.2:
12✔
UNCOV
481
        warn("Results are not valid for temperatures above saturation "
×
482
             "(above the boiling point).")
483

484
    # IAPWS region 1 parameters
485
    R_GAS_CONSTANT = 0.461526  # kJ / kg / K
12✔
486
    ref_p = 16.53  # MPa
12✔
487
    ref_T = 1386  # K
12✔
488
    n1f = [0.14632971213167, -0.84548187169114, -0.37563603672040e1,
12✔
489
           0.33855169168385e1, -0.95791963387872, 0.15772038513228,
490
           -0.16616417199501e-1, 0.81214629983568e-3, 0.28319080123804e-3,
491
           -0.60706301565874e-3, -0.18990068218419e-1, -0.32529748770505e-1,
492
           -0.21841717175414e-1, -0.52838357969930e-4, -0.47184321073267e-3,
493
           -0.30001780793026e-3, 0.47661393906987e-4, -0.44141845330846e-5,
494
           -0.72694996297594e-15, -0.31679644845054e-4, -0.28270797985312e-5,
495
           -0.85205128120103e-9, -0.22425281908000e-5, -0.65171222895601e-6,
496
           -0.14341729937924e-12, -0.40516996860117e-6, -0.12734301741641e-8,
497
           -0.17424871230634e-9, -0.68762131295531e-18, 0.14478307828521e-19,
498
           0.26335781662795e-22, -0.11947622640071e-22, 0.18228094581404e-23,
499
           -0.93537087292458e-25]
500
    I1f = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4,
12✔
501
           4, 4, 5, 8, 8, 21, 23, 29, 30, 31, 32]
502
    J1f = [-2, -1, 0, 1, 2, 3, 4, 5, -9, -7, -1, 0, 1, 3, -3, 0, 1, 3, 17, -4,
12✔
503
           0, 6, -5, -2, 10, -8, -11, -6, -29, -31, -38, -39, -40, -41]
504

505
    # Nondimensionalize the pressure and temperature.
506
    pi = pressure / ref_p
12✔
507
    tau = ref_T / temperature
12✔
508

509
    # Compute the derivative of gamma (dimensionless Gibbs free energy) with
510
    # respect to pi.
511
    gamma1_pi = 0.0
12✔
512
    for n, I, J in zip(n1f, I1f, J1f):
12✔
513
        gamma1_pi -= n * I * (7.1 - pi)**(I - 1) * (tau - 1.222)**J
12✔
514

515
    # Compute the leading coefficient.  This sets the units at
516
    #   1 [MPa] * [kg K / kJ] * [1 / K]
517
    # = 1e6 [N / m^2] * 1e-3 [kg K / N / m] * [1 / K]
518
    # = 1e3 [kg / m^3]
519
    # = 1 [g / cm^3]
520
    coeff = pressure / R_GAS_CONSTANT / temperature
12✔
521

522
    # Compute and return the density.
523
    return coeff / pi / gamma1_pi
12✔
524

525

526
def gnds_name(Z, A, m=0):
12✔
527
    """Return nuclide name using GNDS convention
528

529
    .. versionchanged:: 0.14.0
530
        Function name changed from ``gnd_name`` to ``gnds_name``
531

532
    Parameters
533
    ----------
534
    Z : int
535
        Atomic number
536
    A : int
537
        Mass number
538
    m : int, optional
539
        Metastable state
540

541
    Returns
542
    -------
543
    str
544
        Nuclide name in GNDS convention, e.g., 'Am242_m1'
545

546
    """
547
    if m > 0:
12✔
548
        return f'{ATOMIC_SYMBOL[Z]}{A}_m{m}'
12✔
549
    return f'{ATOMIC_SYMBOL[Z]}{A}'
12✔
550

551

552

553
def _get_element_symbol(element: str) -> str:
12✔
554
    if len(element) > 2:
12✔
555
        symbol = ELEMENT_SYMBOL.get(element.lower())
12✔
556
        if symbol is None:
12✔
557
            raise ValueError(f'Element name "{element}" not recognized')
12✔
558
        return symbol
12✔
559
    else:
560
        return element
12✔
561

562

563
def isotopes(element: str) -> list[tuple[str, float]]:
12✔
564
    """Return naturally occurring isotopes and their abundances
565

566
    .. versionadded:: 0.12.1
567

568
    Parameters
569
    ----------
570
    element : str
571
        Element symbol (e.g., 'H') or name (e.g., 'helium')
572

573
    Returns
574
    -------
575
    list
576
        A list of tuples of (isotope, abundance)
577

578
    Raises
579
    ------
580
    ValueError
581
        If the element name is not recognized
582

583
    """
584
    element = _get_element_symbol(element)
12✔
585

586
    # Get the nuclides present in nature
587
    result = []
12✔
588
    for kv in NATURAL_ABUNDANCE.items():
12✔
589
        if re.match(r'{}\d+'.format(element), kv[0]):
12✔
590
            result.append(kv)
12✔
591

592
    return result
12✔
593

594

595
def zam(name):
12✔
596
    """Return tuple of (atomic number, mass number, metastable state)
597

598
    Parameters
599
    ----------
600
    name : str
601
        Name of nuclide using GNDS convention, e.g., 'Am242_m1'
602

603
    Returns
604
    -------
605
    3-tuple of int
606
        Atomic number, mass number, and metastable state
607

608
    """
609
    try:
12✔
610
        symbol, A, state = _GNDS_NAME_RE.match(name).groups()
12✔
611
    except AttributeError:
12✔
612
        raise ValueError(f"'{name}' does not appear to be a nuclide name in "
12✔
613
                         "GNDS format")
614

615
    if symbol not in ATOMIC_NUMBER:
12✔
UNCOV
616
        raise ValueError(f"'{symbol}' is not a recognized element symbol")
×
617

618
    metastable = int(state[2:]) if state else 0
12✔
619
    return (ATOMIC_NUMBER[symbol], int(A), metastable)
12✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc