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

openmc-dev / openmc / 21869438522

10 Feb 2026 02:43PM UTC coverage: 81.758% (-0.06%) from 81.817%
21869438522

Pull #3785

github

web-flow
Merge 659948af1 into 3f20a5e22
Pull Request #3785: Coincident source

17391 of 24439 branches covered (71.16%)

Branch coverage included in aggregate %.

137 of 214 new or added lines in 5 files covered. (64.02%)

505 existing lines in 13 files now uncovered.

56334 of 65736 relevant lines covered (85.7%)

46746837.89 hits per line

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

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

9
from endf.data import (ATOMIC_NUMBER, ATOMIC_SYMBOL, ELEMENT_SYMBOL,
11✔
10
                       EV_PER_MEV, K_BOLTZMANN)
11

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

118
DADZ = {
11✔
119
    '(n,2nd)': (-3, -1),
120
    '(n,2n)': (-1, 0),
121
    '(n,3n)': (-2, 0),
122
    '(n,na)': (-4, -2),
123
    '(n,n3a)': (-12, -6),
124
    '(n,2na)': (-5, -2),
125
    '(n,3na)': (-6, -2),
126
    '(n,np)': (-1, -1),
127
    '(n,n2a)': (-8, -4),
128
    '(n,2n2a)': (-9, -4),
129
    '(n,nd)': (-2, -1),
130
    '(n,nt)': (-3, -1),
131
    '(n,n3He)': (-3, -2),
132
    '(n,nd2a)': (-10, -5),
133
    '(n,nt2a)': (-11, -5),
134
    '(n,4n)': (-3, 0),
135
    '(n,2np)': (-2, -1),
136
    '(n,3np)': (-3, -1),
137
    '(n,n2p)': (-2, -2),
138
    '(n,npa)': (-5, -3),
139
    '(n,gamma)': (1, 0),
140
    '(n,p)': (0, -1),
141
    '(n,d)': (-1, -1),
142
    '(n,t)': (-2, -1),
143
    '(n,3He)': (-2, -2),
144
    '(n,a)': (-3, -2),
145
    '(n,2a)': (-7, -4),
146
    '(n,3a)': (-11, -6),
147
    '(n,2p)': (-1, -2),
148
    '(n,pa)': (-4, -3),
149
    '(n,t2a)': (-10, -5),
150
    '(n,d2a)': (-9, -5),
151
    '(n,pd)': (-2, -2),
152
    '(n,pt)': (-3, -2),
153
    '(n,da)': (-5, -3),
154
    '(n,5n)': (-4, 0),
155
    '(n,6n)': (-5, 0),
156
    '(n,2nt)': (-4, -1),
157
    '(n,ta)': (-6, -3),
158
    '(n,4np)': (-4, -1),
159
    '(n,3nd)': (-4, -1),
160
    '(n,nda)': (-6, -3),
161
    '(n,2npa)': (-6, -3),
162
    '(n,7n)': (-6, 0),
163
    '(n,8n)': (-7, 0),
164
    '(n,5np)': (-5, -1),
165
    '(n,6np)': (-6, -1),
166
    '(n,7np)': (-7, -1),
167
    '(n,4na)': (-7, -2),
168
    '(n,5na)': (-8, -2),
169
    '(n,6na)': (-9, -2),
170
    '(n,7na)': (-10, -2),
171
    '(n,4nd)': (-5, -1),
172
    '(n,5nd)': (-6, -1),
173
    '(n,6nd)': (-7, -1),
174
    '(n,3nt)': (-5, -1),
175
    '(n,4nt)': (-6, -1),
176
    '(n,5nt)': (-7, -1),
177
    '(n,6nt)': (-8, -1),
178
    '(n,2n3He)': (-4, -2),
179
    '(n,3n3He)': (-5, -2),
180
    '(n,4n3He)': (-6, -2),
181
    '(n,3n2p)': (-4, -2),
182
    '(n,3n2a)': (-10, -4),
183
    '(n,3npa)': (-7, -3),
184
    '(n,dt)': (-4, -2),
185
    '(n,npd)': (-3, -2),
186
    '(n,npt)': (-4, -2),
187
    '(n,ndt)': (-5, -2),
188
    '(n,np3He)': (-4, -3),
189
    '(n,nd3He)': (-5, -3),
190
    '(n,nt3He)': (-6, -3),
191
    '(n,nta)': (-7, -3),
192
    '(n,2n2p)': (-3, -2),
193
    '(n,p3He)': (-4, -3),
194
    '(n,d3He)': (-5, -3),
195
    '(n,3Hea)': (-6, -4),
196
    '(n,4n2p)': (-5, -2),
197
    '(n,4n2a)': (-11, -4),
198
    '(n,4npa)': (-8, -3),
199
    '(n,3p)': (-2, -3),
200
    '(n,n3p)': (-3, -3),
201
    '(n,3n2pa)': (-8, -4),
202
    '(n,5n2p)': (-6, -2),
203
}
204

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

208
# Unit conversions
209
JOULE_PER_EV = 1.602176634e-19
11✔
210

211
# Avogadro's constant
212
AVOGADRO = 6.02214076e23
11✔
213

214
# Neutron mass in units of amu
215
NEUTRON_MASS = 1.00866491595
11✔
216

217
# Used in atomic_mass function as a cache
218
_ATOMIC_MASS: dict[str, float] = {}
11✔
219

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

223
# Used in half_life function as a cache
224
_HALF_LIFE: dict[str, float] = {}
11✔
225
_LOG_TWO = log(2.0)
11✔
226

227
def atomic_mass(isotope):
11✔
228
    """Return atomic mass of isotope in atomic mass units.
229

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

233
    Parameters
234
    ----------
235
    isotope : str
236
        Name of isotope, e.g., 'Pu239'
237

238
    Returns
239
    -------
240
    float
241
        Atomic mass of isotope in [amu]
242

243
    """
244
    if not _ATOMIC_MASS:
11✔
245

246
        # Load data from AME2020 file
247
        mass_file = os.path.join(os.path.dirname(__file__), 'mass_1.mas20.txt')
11✔
248
        with open(mass_file, 'r') as ame:
11✔
249
            # Read lines in file starting at line 37
250
            for line in itertools.islice(ame, 36, None):
11✔
251
                name = f'{line[20:22].strip()}{int(line[16:19])}'
11✔
252
                mass = float(line[106:109]) + 1e-6*float(
11✔
253
                    line[110:116] + '.' + line[117:123])
254
                _ATOMIC_MASS[name.lower()] = mass
11✔
255

256
        # For isotopes found in some libraries that represent all natural
257
        # isotopes of their element (e.g. C0), calculate the atomic mass as
258
        # the sum of the atomic mass times the natural abundance of the isotopes
259
        # that make up the element.
260
        for element in ['C', 'Zn', 'Pt', 'Os', 'Tl', 'V']:
11✔
261
            isotope_zero = element.lower() + '0'
11✔
262
            _ATOMIC_MASS[isotope_zero] = 0.
11✔
263
            for iso, abundance in isotopes(element):
11✔
264
                _ATOMIC_MASS[isotope_zero] += abundance * _ATOMIC_MASS[iso.lower()]
11✔
265

266
    # Get rid of metastable information
267
    if '_' in isotope:
11✔
268
        isotope = isotope[:isotope.find('_')]
11✔
269

270
    return _ATOMIC_MASS[isotope.lower()]
11✔
271

272

273
def atomic_weight(element):
11✔
274
    """Return atomic weight of an element in atomic mass units.
275

276
    Computes an average of the atomic mass of each of element's naturally
277
    occurring isotopes weighted by their relative abundance.
278

279
    Parameters
280
    ----------
281
    element : str
282
        Element symbol (e.g., 'H') or name (e.g., 'helium')
283

284
    Returns
285
    -------
286
    float
287
        Atomic weight of element in [amu]
288

289
    """
290
    weight = 0.
11✔
291
    for nuclide, abundance in isotopes(element):
11✔
292
        weight += atomic_mass(nuclide) * abundance
11✔
293
    if weight > 0.:
11✔
294
        return weight
11✔
295
    else:
296
        raise ValueError(f"No naturally-occurring isotopes for element '{element}'.")
11✔
297

298

299
def half_life(isotope):
11✔
300
    """Return half-life of isotope in seconds or None if isotope is stable
301

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

305
    .. versionadded:: 0.13.1
306

307
    Parameters
308
    ----------
309
    isotope : str
310
        Name of isotope, e.g., 'Pu239'
311

312
    Returns
313
    -------
314
    float
315
        Half-life of isotope in [s]
316

317
    """
318
    global _HALF_LIFE
319
    if not _HALF_LIFE:
11✔
320
        # Load ENDF/B-VIII.0 data from JSON file
321
        half_life_path = Path(__file__).with_name('half_life.json')
11✔
322
        _HALF_LIFE = json.loads(half_life_path.read_text())
11✔
323

324
    return _HALF_LIFE.get(isotope.lower())
11✔
325

326

327
def decay_constant(isotope):
11✔
328
    """Return decay constant of isotope in [s^-1]
329

330
    Decay constants are based on half-life values from the
331
    :func:`~openmc.data.half_life` function. When the isotope is stable, a decay
332
    constant of zero is returned.
333

334
    .. versionadded:: 0.13.1
335

336
    Parameters
337
    ----------
338
    isotope : str
339
        Name of isotope, e.g., 'Pu239'
340

341
    Returns
342
    -------
343
    float
344
        Decay constant of isotope in [s^-1]
345

346
    See also
347
    --------
348
    openmc.data.half_life
349

350
    """
351
    t = half_life(isotope)
11✔
352
    return _LOG_TWO / t if t else 0.0
11✔
353

354

355
def water_density(temperature, pressure=0.1013):
11✔
356
    """Return the density of liquid water at a given temperature and pressure.
357

358
    The density is calculated from a polynomial fit using equations and values
359
    from the 2012 version of the IAPWS-IF97 formulation.  Only the equations
360
    for region 1 are implemented here.  Region 1 is limited to liquid water
361
    below 100 [MPa] with a temperature above 273.15 [K], below 623.15 [K], and
362
    below saturation.
363

364
    Reference: International Association for the Properties of Water and Steam,
365
    "Revised Release on the IAPWS Industrial Formulation 1997 for the
366
    Thermodynamic Properties of Water and Steam", IAPWS R7-97(2012).
367

368
    Parameters
369
    ----------
370
    temperature : float
371
        Water temperature in units of [K]
372
    pressure : float
373
        Water pressure in units of [MPa]
374

375
    Returns
376
    -------
377
    float
378
        Water density in units of [g/cm^3]
379

380
    """
381

382
    # Make sure the temperature and pressure are inside the min/max region 1
383
    # bounds.  (Relax the 273.15 bound to 273 in case a user wants 0 deg C data
384
    # but they only use 3 digits for their conversion to K.)
385
    if pressure > 100.0:
11✔
UNCOV
386
        warn("Results are not valid for pressures above 100 MPa.")
×
387
    elif pressure < 0.0:
11✔
UNCOV
388
        raise ValueError("Pressure must be positive.")
×
389
    if temperature < 273:
11✔
UNCOV
390
        warn("Results are not valid for temperatures below 273.15 K.")
×
391
    elif temperature > 623.15:
11✔
UNCOV
392
        warn("Results are not valid for temperatures above 623.15 K.")
×
393
    elif temperature <= 0.0:
11✔
UNCOV
394
        raise ValueError('Temperature must be positive.')
×
395

396
    # IAPWS region 4 parameters
397
    n4 = [0.11670521452767e4, -0.72421316703206e6, -0.17073846940092e2,
11✔
398
          0.12020824702470e5, -0.32325550322333e7, 0.14915108613530e2,
399
          -0.48232657361591e4, 0.40511340542057e6, -0.23855557567849,
400
          0.65017534844798e3]
401

402
    # Compute the saturation temperature at the given pressure.
403
    beta = pressure**(0.25)
11✔
404
    E = beta**2 + n4[2] * beta + n4[5]
11✔
405
    F = n4[0] * beta**2 + n4[3] * beta + n4[6]
11✔
406
    G = n4[1] * beta**2 + n4[4] * beta + n4[7]
11✔
407
    D = 2.0 * G / (-F - sqrt(F**2 - 4 * E * G))
11✔
408
    T_sat = 0.5 * (n4[9] + D
11✔
409
                   - sqrt((n4[9] + D)**2  - 4.0 * (n4[8] + n4[9] * D)))
410

411
    # Make sure we aren't above saturation.  (Relax this bound by .2 degrees
412
    # for deg C to K conversions.)
413
    if temperature > T_sat + 0.2:
11✔
UNCOV
414
        warn("Results are not valid for temperatures above saturation "
×
415
             "(above the boiling point).")
416

417
    # IAPWS region 1 parameters
418
    R_GAS_CONSTANT = 0.461526  # kJ / kg / K
11✔
419
    ref_p = 16.53  # MPa
11✔
420
    ref_T = 1386  # K
11✔
421
    n1f = [0.14632971213167, -0.84548187169114, -0.37563603672040e1,
11✔
422
           0.33855169168385e1, -0.95791963387872, 0.15772038513228,
423
           -0.16616417199501e-1, 0.81214629983568e-3, 0.28319080123804e-3,
424
           -0.60706301565874e-3, -0.18990068218419e-1, -0.32529748770505e-1,
425
           -0.21841717175414e-1, -0.52838357969930e-4, -0.47184321073267e-3,
426
           -0.30001780793026e-3, 0.47661393906987e-4, -0.44141845330846e-5,
427
           -0.72694996297594e-15, -0.31679644845054e-4, -0.28270797985312e-5,
428
           -0.85205128120103e-9, -0.22425281908000e-5, -0.65171222895601e-6,
429
           -0.14341729937924e-12, -0.40516996860117e-6, -0.12734301741641e-8,
430
           -0.17424871230634e-9, -0.68762131295531e-18, 0.14478307828521e-19,
431
           0.26335781662795e-22, -0.11947622640071e-22, 0.18228094581404e-23,
432
           -0.93537087292458e-25]
433
    I1f = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4,
11✔
434
           4, 4, 5, 8, 8, 21, 23, 29, 30, 31, 32]
435
    J1f = [-2, -1, 0, 1, 2, 3, 4, 5, -9, -7, -1, 0, 1, 3, -3, 0, 1, 3, 17, -4,
11✔
436
           0, 6, -5, -2, 10, -8, -11, -6, -29, -31, -38, -39, -40, -41]
437

438
    # Nondimensionalize the pressure and temperature.
439
    pi = pressure / ref_p
11✔
440
    tau = ref_T / temperature
11✔
441

442
    # Compute the derivative of gamma (dimensionless Gibbs free energy) with
443
    # respect to pi.
444
    gamma1_pi = 0.0
11✔
445
    for n, I, J in zip(n1f, I1f, J1f):
11✔
446
        gamma1_pi -= n * I * (7.1 - pi)**(I - 1) * (tau - 1.222)**J
11✔
447

448
    # Compute the leading coefficient.  This sets the units at
449
    #   1 [MPa] * [kg K / kJ] * [1 / K]
450
    # = 1e6 [N / m^2] * 1e-3 [kg K / N / m] * [1 / K]
451
    # = 1e3 [kg / m^3]
452
    # = 1 [g / cm^3]
453
    coeff = pressure / R_GAS_CONSTANT / temperature
11✔
454

455
    # Compute and return the density.
456
    return coeff / pi / gamma1_pi
11✔
457

458

459
def gnds_name(Z, A, m=0):
11✔
460
    """Return nuclide name using GNDS convention
461

462
    .. versionchanged:: 0.14.0
463
        Function name changed from ``gnd_name`` to ``gnds_name``
464

465
    Parameters
466
    ----------
467
    Z : int
468
        Atomic number
469
    A : int
470
        Mass number
471
    m : int, optional
472
        Metastable state
473

474
    Returns
475
    -------
476
    str
477
        Nuclide name in GNDS convention, e.g., 'Am242_m1'
478

479
    """
480
    if m > 0:
11✔
481
        return f'{ATOMIC_SYMBOL[Z]}{A}_m{m}'
11✔
482
    return f'{ATOMIC_SYMBOL[Z]}{A}'
11✔
483

484

485

486
def _get_element_symbol(element: str) -> str:
11✔
487
    if len(element) > 2:
11✔
488
        symbol = ELEMENT_SYMBOL.get(element.lower())
11✔
489
        if symbol is None:
11✔
490
            raise ValueError(f'Element name "{element}" not recognized')
11✔
491
        return symbol
11✔
492
    else:
493
        return element
11✔
494

495

496
def isotopes(element: str) -> list[tuple[str, float]]:
11✔
497
    """Return naturally occurring isotopes and their abundances
498

499
    .. versionadded:: 0.12.1
500

501
    Parameters
502
    ----------
503
    element : str
504
        Element symbol (e.g., 'H') or name (e.g., 'helium')
505

506
    Returns
507
    -------
508
    list
509
        A list of tuples of (isotope, abundance)
510

511
    Raises
512
    ------
513
    ValueError
514
        If the element name is not recognized
515

516
    """
517
    element = _get_element_symbol(element)
11✔
518

519
    # Get the nuclides present in nature
520
    result = []
11✔
521
    for kv in NATURAL_ABUNDANCE.items():
11✔
522
        if re.match(r'{}\d+'.format(element), kv[0]):
11✔
523
            result.append(kv)
11✔
524

525
    return result
11✔
526

527

528
def zam(name):
11✔
529
    """Return tuple of (atomic number, mass number, metastable state)
530

531
    Parameters
532
    ----------
533
    name : str
534
        Name of nuclide using GNDS convention, e.g., 'Am242_m1'
535

536
    Returns
537
    -------
538
    3-tuple of int
539
        Atomic number, mass number, and metastable state
540

541
    """
542
    try:
11✔
543
        symbol, A, state = _GNDS_NAME_RE.fullmatch(name).groups()
11✔
544
    except AttributeError:
11✔
545
        raise ValueError(f"'{name}' does not appear to be a nuclide name in "
11✔
546
                         "GNDS format")
547

548
    if symbol not in ATOMIC_NUMBER:
11✔
UNCOV
549
        raise ValueError(f"'{symbol}' is not a recognized element symbol")
×
550

551
    metastable = int(state[2:]) if state else 0
11✔
552
    return (ATOMIC_NUMBER[symbol], int(A), metastable)
11✔
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