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

openmc-dev / openmc / 22007957997

14 Feb 2026 12:50AM UTC coverage: 81.717% (-0.05%) from 81.763%
22007957997

Pull #3765

github

web-flow
Merge 6111ffe2e into 19c0aafdc
Pull Request #3765: Store atomic mass in ParticleType.

17526 of 24626 branches covered (71.17%)

Branch coverage included in aggregate %.

6 of 7 new or added lines in 2 files covered. (85.71%)

1820 existing lines in 34 files now uncovered.

56937 of 66497 relevant lines covered (85.62%)

44324210.02 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
10✔
2
import json
10✔
3
import os
10✔
4
import re
10✔
5
from pathlib import Path
10✔
6
from math import sqrt, log
10✔
7
from warnings import warn
10✔
8

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

12
gnds_name.__module__ = __name__
10✔
13
zam.__module__ = __name__
10✔
14

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

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

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

211
# Unit conversions
212
JOULE_PER_EV = 1.602176634e-19
10✔
213

214
# Avogadro's constant
215
AVOGADRO = 6.02214076e23
10✔
216

217
# Neutron mass in units of amu
218
NEUTRON_MASS = 1.00866491595
10✔
219

220
# Used in atomic_mass function as a cache
221
_ATOMIC_MASS: dict[str, float] = {}
10✔
222

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

227
def atomic_mass(isotope):
10✔
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:
10✔
245

246
        # Load data from AME2020 file
247
        mass_file = os.path.join(os.path.dirname(__file__), 'mass_1.mas20.txt')
10✔
248
        with open(mass_file, 'r') as ame:
10✔
249
            # Read lines in file starting at line 37
250
            for line in itertools.islice(ame, 36, None):
10✔
251
                name = f'{line[20:22].strip()}{int(line[16:19])}'
10✔
252
                mass = float(line[106:109]) + 1e-6*float(
10✔
253
                    line[110:116] + '.' + line[117:123])
254
                _ATOMIC_MASS[name.lower()] = mass
10✔
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']:
10✔
261
            isotope_zero = element.lower() + '0'
10✔
262
            _ATOMIC_MASS[isotope_zero] = 0.
10✔
263
            for iso, abundance in isotopes(element):
10✔
264
                _ATOMIC_MASS[isotope_zero] += abundance * _ATOMIC_MASS[iso.lower()]
10✔
265

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

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

272

273
def atomic_weight(element):
10✔
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.
10✔
291
    for nuclide, abundance in isotopes(element):
10✔
292
        weight += atomic_mass(nuclide) * abundance
10✔
293
    if weight > 0.:
10✔
294
        return weight
10✔
295
    else:
296
        raise ValueError(f"No naturally-occurring isotopes for element '{element}'.")
10✔
297

298

299
def half_life(isotope):
10✔
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:
10✔
320
        # Load ENDF/B-VIII.0 data from JSON file
321
        half_life_path = Path(__file__).with_name('half_life.json')
10✔
322
        _HALF_LIFE = json.loads(half_life_path.read_text())
10✔
323

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

326

327
def decay_constant(isotope):
10✔
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)
10✔
352
    return _LOG_TWO / t if t else 0.0
10✔
353

354

355
def water_density(temperature, pressure=0.1013):
10✔
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:
10✔
UNCOV
386
        warn("Results are not valid for pressures above 100 MPa.")
×
387
    elif pressure < 0.0:
10✔
UNCOV
388
        raise ValueError("Pressure must be positive.")
×
389
    if temperature < 273:
10✔
UNCOV
390
        warn("Results are not valid for temperatures below 273.15 K.")
×
391
    elif temperature > 623.15:
10✔
UNCOV
392
        warn("Results are not valid for temperatures above 623.15 K.")
×
393
    elif temperature <= 0.0:
10✔
UNCOV
394
        raise ValueError('Temperature must be positive.')
×
395

396
    # IAPWS region 4 parameters
397
    n4 = [0.11670521452767e4, -0.72421316703206e6, -0.17073846940092e2,
10✔
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)
10✔
404
    E = beta**2 + n4[2] * beta + n4[5]
10✔
405
    F = n4[0] * beta**2 + n4[3] * beta + n4[6]
10✔
406
    G = n4[1] * beta**2 + n4[4] * beta + n4[7]
10✔
407
    D = 2.0 * G / (-F - sqrt(F**2 - 4 * E * G))
10✔
408
    T_sat = 0.5 * (n4[9] + D
10✔
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:
10✔
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
10✔
419
    ref_p = 16.53  # MPa
10✔
420
    ref_T = 1386  # K
10✔
421
    n1f = [0.14632971213167, -0.84548187169114, -0.37563603672040e1,
10✔
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,
10✔
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,
10✔
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
10✔
440
    tau = ref_T / temperature
10✔
441

442
    # Compute the derivative of gamma (dimensionless Gibbs free energy) with
443
    # respect to pi.
444
    gamma1_pi = 0.0
10✔
445
    for n, I, J in zip(n1f, I1f, J1f):
10✔
446
        gamma1_pi -= n * I * (7.1 - pi)**(I - 1) * (tau - 1.222)**J
10✔
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
10✔
454

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

458

459
def _get_element_symbol(element: str) -> str:
10✔
460
    if len(element) > 2:
10✔
461
        symbol = ELEMENT_SYMBOL.get(element.lower())
10✔
462
        if symbol is None:
10✔
463
            raise ValueError(f'Element name "{element}" not recognized')
10✔
464
        return symbol
10✔
465
    else:
466
        return element
10✔
467

468

469
def isotopes(element: str) -> list[tuple[str, float]]:
10✔
470
    """Return naturally occurring isotopes and their abundances
471

472
    .. versionadded:: 0.12.1
473

474
    Parameters
475
    ----------
476
    element : str
477
        Element symbol (e.g., 'H') or name (e.g., 'helium')
478

479
    Returns
480
    -------
481
    list
482
        A list of tuples of (isotope, abundance)
483

484
    Raises
485
    ------
486
    ValueError
487
        If the element name is not recognized
488

489
    """
490
    element = _get_element_symbol(element)
10✔
491

492
    # Get the nuclides present in nature
493
    result = []
10✔
494
    for kv in NATURAL_ABUNDANCE.items():
10✔
495
        if re.match(r'{}\d+'.format(element), kv[0]):
10✔
496
            result.append(kv)
10✔
497

498
    return result
10✔
499

500

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