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

openmc-dev / openmc / 14840340664

05 May 2025 03:38PM UTC coverage: 85.195% (-0.009%) from 85.204%
14840340664

Pull #3392

github

web-flow
Merge 5bc1ec35f into 1e7d8324e
Pull Request #3392: Map Compton subshell data to atomic relaxation data

14 of 14 new or added lines in 2 files covered. (100.0%)

330 existing lines in 19 files now uncovered.

52194 of 61264 relevant lines covered (85.2%)

37398320.1 hits per line

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

87.72
/openmc/waste.py
1
from __future__ import annotations
11✔
2

3
import openmc
11✔
4
from openmc.data import half_life
11✔
5

6

7
def _waste_classification(mat: openmc.Material, metal: bool = True) -> str:
11✔
8
    """Classify a material for near-surface waste disposal.
9

10
    This method determines a waste classification for a material based on the
11
    NRC regulations (10 CFR 61.55).
12

13
    Parameters
14
    ----------
15
    mat : openmc.Material
16
        The material to classify.
17
    metal : bool, optional
18
        Whether or not the material is in metal form. This changes the
19
        acceptable limits in Tables 1 and 2 for certain nuclides.
20

21
    Returns
22
    -------
23
    str
24
        The waste disposal classification, which can be "Class A", "Class B",
25
        "Class C", or "GTCC" (greater than class C).
26

27
    """
28
    # Determine metrics based on Tables 1 and 2 using sum of fractions rule for
29
    # mixture of radionuclides from §61.55(a)(7)
30
    ratio1 = _waste_disposal_rating(mat, 'NRC_long', metal=metal)
11✔
31
    ratio2 = [
11✔
32
        _waste_disposal_rating(mat, 'NRC_short_A', metal=metal),
33
        _waste_disposal_rating(mat, 'NRC_short_B', metal=metal),
34
        _waste_disposal_rating(mat, 'NRC_short_C', metal=metal),
35
    ]
36

37
    # Determine which nuclides are present in Table 1 and Table 2
38
    table1_nuclides_present = (ratio1 > 0.0)
11✔
39
    table2_nuclides_present = any(x > 0.0 for x in ratio2)
11✔
40

41
    # Helper function for classifying based on Table 2
42
    def classify_table2(col1, col2, col3):
11✔
43
        if col1 < 1.0:
11✔
44
            return "Class A"
11✔
45
        elif col2 < 1.0:
11✔
46
            return "Class B"
11✔
47
        elif col3 < 1.0:
11✔
48
            return "Class C"
11✔
49
        else:
50
            return "GTCC"
11✔
51

52
    if table1_nuclides_present and table2_nuclides_present:
11✔
53
        # Classification based on §61.55(a)(5)
54
        if ratio1 < 0.1:
×
55
            return classify_table2(*ratio2)
×
56
        elif ratio1 < 1.0:
×
57
            return "Class C" if ratio2[2] < 1.0 else "GTCC"
×
58
        else:
59
            return "GTCC"
×
60

61
    elif table1_nuclides_present:
11✔
62
        # Classification based on §61.55(a)(3)
63
        if ratio1 < 0.1:
11✔
64
            return "Class A"
11✔
65
        elif ratio1 < 1.0:
11✔
66
            return "Class C"
11✔
67
        else:
68
            return "GTCC"
11✔
69

70
    elif table2_nuclides_present:
11✔
71
        # Classification based on §61.55(a)(4)
72
        return classify_table2(*ratio2)
11✔
73

74
    else:
75
        # Classification based on §61.55(a)(6)
76
        return "Class A"
×
77

78

79
def _waste_disposal_rating(
11✔
80
    mat: openmc.Material,
81
    limits: str | dict[str, float] = 'Fetter',
82
    metal: bool = False,
83
    by_nuclide: bool = False,
84
) -> float | dict[str, float]:
85
    """Return the waste disposal rating for a material.
86

87
    This method returns a waste disposal rating for the material based on a set
88
    of specific activity limits. The waste disposal rating is a single number
89
    that represents the sum of the ratios of the specific activity for each
90
    radionuclide in the material against a nuclide-specific limit. A value less
91
    than 1.0 indicates that the material "meets" the limits whereas a value
92
    greater than 1.0 exceeds the limits.
93

94
    Parameters
95
    ----------
96
    mat : openmc.Material
97
        The material to classify.
98
    limits : str or dict, optional
99
        The name of a predefined set of specific activity limits or a dictionary
100
        that contains specific activity limits for radionuclides, where keys are
101
        nuclide names and values are activities in units of [Ci/m3]. The
102
        predefined options are:
103

104
        - 'Fetter': Uses limits from Fetter et al. (1990)
105
        - 'NRC_long': Uses the 10 CFR 61.55 limits for long-lived radionuclides
106
        - 'NRC_short_A': Uses the 10 CFR 61.55 class A limits for short-lived
107
          radionuclides
108
        - 'NRC_short_B': Uses the 10 CFR 61.55 class B limits for short-lived
109
          radionuclides
110
        - 'NRC_short_C': Uses the 10 CFR 61.55 class C limits for short-lived
111
          radionuclides
112
    metal : bool, optional
113
        Whether or not the material is in metal form (only applicable for NRC
114
        based limits)
115
    by_nuclide : bool, optional
116
        Whether to return the waste disposal rating for each nuclide in the
117
        material. If True, a dictionary is returned where the keys are the
118
        nuclide names and the values are the waste disposal ratings for each
119
        nuclide. If False, a single float value is returned that represents the
120
        overall waste disposal rating for the material.
121

122
    Returns
123
    -------
124
    float or dict
125
        The waste disposal rating for the material or its constituent nuclides.
126

127
    """
128
    if limits == 'Fetter':
11✔
129
        # Specific activity limits for radionuclides with half-lives between 5
130
        # years and 1e12 years from Table 2 in Fetter
131
        limits = {
11✔
132
            "Be10": 5.0e3,
133
            "C14": 6.0e2,
134
            "Al26": 9.0e-2,
135
            "Si32": 6.0e2,
136
            "Cl36": 1.0e1,
137
            "Ar39": 2.0e4,
138
            "Ar42": 2.0e4,
139
            "K40": 2.0e0,
140
            "Ca41": 1.0e4,
141
            "Ti44": 2.0e2,
142
            "Fe60": 1.0e-1,
143
            "Co60": 3.0e8,
144
            "Ni59": 9.0e2,
145
            "Ni63": 7.0e5,
146
            "Se79": 5.0e1,
147
            "Kr81": 3.0e1,
148
            "Sr90": 8.0e5,
149
            "Nb91": 2.0e2,
150
            "Nb92": 2.0e-1,
151
            "Nb94": 2.0e-1,
152
            "Mo93": 4.0e3,
153
            "Tc97": 4.0e-1,
154
            "Tc98": 1.0e-2,
155
            "Tc99": 6.0e-2,
156
            "Pd107": 9.0e2,
157
            "Ag108_m1": 3.0e0,
158
            "Sn121_m1": 7.0e5,
159
            "Sn126": 1.0e-1,
160
            "I129": 2.0e0,
161
            "Cs137": 5.0e4,
162
            "Ba133": 2.0e8,
163
            "La137": 2.0e2,
164
            "Sm151": 5.0e7,
165
            "Eu150_m1": 3.0e3,
166
            "Eu152": 3.0e5,
167
            "Eu154": 5.0e6,
168
            "Gd148": 2.0e5,
169
            "Gd150": 2.0e3,
170
            "Tb157": 5.0e3,
171
            "Tb158": 4.0e0,
172
            "Dy154": 1.0e3,
173
            "Ho166_m1": 2.0e-1,
174
            "Hf178_m1": 9.0e3,
175
            "Hf182": 2.0e-1,
176
            "Re186_m1": 2.0e1,
177
            "Ir192_m1": 1.0e0,
178
            "Pt193": 2.0e8,
179
            "Hg194": 5.0e-1,
180
            "Pb202": 6.0e-1,
181
            "Pb210": 3.0e7,
182
            "Bi207": 9.0e3,
183
            "Bi208": 8.0e-2,
184
            "Bi210_m1": 1.0e0,
185
            "Po209": 3.0e3,
186
            "Ra226": 1.0e-1,
187
            "Ra228": 3.0e7,
188
            "Ac227": 5.0e5,
189
            "Th229": 2.0e0,
190
            "Th230": 3.0e-1,
191
            "Th232": 1.0e-1,
192
            "Pa231": 7.0e-1,
193
            "U232": 3.0e1,
194
            "U233": 2.0e1,
195
            "U234": 9.0e1,
196
            "U235": 2.0e0,
197
            "Np236": 1.0e0,
198
            "Np237": 1.0e0,
199
            "Pu238": 7.0e4,
200
            "Pu239": 1.0e3,
201
            "Pu240": 1.0e3,
202
            "Pu241": 2.0e3,
203
            "Pu242": 1.0e3,
204
            "Pu244": 9.0e-1,
205
            "Am241": 5.0e1,
206
            "Am242_m1": 3.0e2,
207
            "Am243": 2.0e0,
208
            "Cm243": 6.0e2,
209
            "Cm244": 5.0e5,
210
            "Cm245": 5.0e0,
211
            "Cm246": 8.0e2,
212
            "Cm248": 8.0e2,
213
        }
214

215
    elif limits == 'NRC_long':
11✔
216
        # Specific activity limits for long-lived radionuclides from Table 1 in
217
        # 10 CFR 61.55 in Ci/m3.
218
        limits = {
11✔
219
            'C14': 8.0,
220
            'Tc99': 3.0,
221
            'I129': 0.08,
222
        }
223
        if metal:
11✔
224
            limits['C14'] = 80.0
11✔
225
            limits['Ni59'] = 220.0
11✔
226
            limits['Nb94'] = 0.2
11✔
227

228
        # Convert values in nCi/g to Ci/m3
229
        factor = (1e6 * mat.get_mass_density()) / 1e9
11✔
230
        limits.update({
11✔
231
            'Pu241': 3500.0 * factor,
232
            'Cm242': 20000.0 * factor,
233
            'Np237': 100.0 * factor,
234
            'Pu238': 100.0 * factor,
235
            'Pu239': 100.0 * factor,
236
            'Pu240': 100.0 * factor,
237
            'Pu242': 100.0 * factor,
238
            'Pu244': 100.0 * factor,
239
            'Am241': 100.0 * factor,
240
            'Am243': 100.0 * factor,
241
            'Cm243': 100.0 * factor,
242
            'Cm244': 100.0 * factor,
243
            'Cm245': 100.0 * factor,
244
            'Cm246': 100.0 * factor,
245
            'Cm247': 100.0 * factor,
246
            'Cm248': 100.0 * factor,
247
            'Bk247': 100.0 * factor,
248
            'Cf249': 100.0 * factor,
249
            'Cf250': 100.0 * factor,
250
            'Cf251': 100.0 * factor,
251
        })
252

253
    elif limits == 'NRC_short_A':
11✔
254
        # Get Class A specific activity limits for short-lived radionuclides
255
        # from Table 2 in 10 CFR 61.55
256
        limits = {
11✔
257
            'H3': 40.0,
258
            'Co60': 700.0,
259
            'Ni63': 35.0 if metal else 3.5,
260
            'Sr90': 0.04,
261
            'Cs137': 1.0
262
        }
263

264
        # Add radionuclides with half-lives < 5 years to limits for class A
265
        five_years = 60.0 * 60.0 * 24.0 * 365.25 * 5.0
11✔
266
        for nuc in mat.get_nuclides():
11✔
267
            if half_life(nuc) is not None and half_life(nuc) < five_years:
11✔
UNCOV
268
                limits[nuc] = 700.0
×
269

270
    elif limits == 'NRC_short_B':
11✔
271
        # Get Class B specific activity limits for short-lived radionuclides
272
        # from Table 2 in 10 CFR 61.55
273
        limits = {'Ni63': 700.0 if metal else 70.0, 'Sr90': 150.0, 'Cs137': 44.0}
11✔
274

275
    elif limits == 'NRC_short_C':
11✔
276
        # Get Class C specific activity limits for short-lived radionuclides
277
        # from Table 2 in 10 CFR 61.55
278
        limits = {'Ni63': 7000.0 if metal else 700.0, 'Sr90': 7000.0, 'Cs137': 4600.0}
11✔
279

280
    # Calculate the sum of the fractions of the activity of each radionuclide
281
    # compared to the specified limits
282
    ratio = {}
11✔
283
    for nuc, ci_m3 in mat.get_activity(units="Ci/m3", by_nuclide=True).items():
11✔
284
        if nuc in limits:
11✔
285
            ratio[nuc] = ci_m3 / limits[nuc]
11✔
286
    return ratio if by_nuclide else sum(ratio.values())
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