Skip to content

Commit 99c6514

Browse files
authored
Merge pull request #2432 from guyshtot/library_nuclides_specification
Library nuclides specification
2 parents 52f8618 + 3d1811a commit 99c6514

File tree

5 files changed

+322
-2
lines changed

5 files changed

+322
-2
lines changed

openmc/mgxs/library.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ class Library:
7272
Number of equi-width polar angle bins for angle discretization
7373
num_azimuthal : Integral
7474
Number of equi-width azimuthal angle bins for angle discretization
75+
nuclides : Iterable of str or 'sum'
76+
The optional user-specified nuclides for which to compute cross
77+
sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides
78+
are not specified by the user, all nuclides in the domain
79+
are included.
7580
estimator : str or None
7681
The tally estimator used to compute multi-group cross sections.
7782
If None, the default for each MGXS type is used.
@@ -107,6 +112,7 @@ def __init__(self, geometry, by_nuclide=False,
107112
self._energy_groups = None
108113
self._num_polar = 1
109114
self._num_azimuthal = 1
115+
self._nuclides = None
110116
self._num_delayed_groups = 0
111117
self._correction = 'P0'
112118
self._scatter_format = 'legendre'
@@ -145,6 +151,7 @@ def __deepcopy__(self, memo):
145151
clone._energy_groups = copy.deepcopy(self.energy_groups, memo)
146152
clone._num_polar = self.num_polar
147153
clone._num_azimuthal = self.num_azimuthal
154+
clone._nuclides = self._nuclides
148155
clone._num_delayed_groups = self.num_delayed_groups
149156
clone._tally_trigger = copy.deepcopy(self.tally_trigger, memo)
150157
clone._all_mgxs = copy.deepcopy(self.all_mgxs)
@@ -205,6 +212,10 @@ def domains(self):
205212
else:
206213
return self._domains
207214

215+
@property
216+
def nuclides(self):
217+
return self._nuclides
218+
208219
@property
209220
def energy_groups(self):
210221
return self._energy_groups
@@ -275,6 +286,11 @@ def name(self, name):
275286
cv.check_type('name', name, str)
276287
self._name = name
277288

289+
@nuclides.setter
290+
def nuclides(self, nuclides):
291+
cv.check_iterable_type('nuclides', nuclides, str)
292+
self._nuclides = nuclides
293+
278294
@mgxs_types.setter
279295
def mgxs_types(self, mgxs_types):
280296
all_mgxs_types = openmc.mgxs.MGXS_TYPES + openmc.mgxs.MDGXS_TYPES + \
@@ -524,6 +540,20 @@ def build_library(self):
524540
mgxs.legendre_order = self.legendre_order
525541
mgxs.histogram_bins = self.histogram_bins
526542

543+
if self.by_nuclide:
544+
try:
545+
domain_nuclides = domain.get_nuclides()
546+
except AttributeError:
547+
domain_nuclides = None
548+
if self.nuclides:
549+
if domain_nuclides:
550+
mgxs.nuclides = [
551+
nuclide for nuclide in self.nuclides
552+
if nuclide in domain_nuclides
553+
] + ["total"]
554+
else:
555+
mgxs.nuclides = self.nuclides
556+
527557
self.all_mgxs[domain.id][mgxs_type] = mgxs
528558

529559
def add_to_tallies_file(self, tallies_file, merge=True):
@@ -590,7 +620,7 @@ def load_from_statepoint(self, statepoint):
590620

591621
self._sp_filename = statepoint._f.filename
592622
self._geometry = statepoint.summary.geometry
593-
self._nuclides = statepoint.summary.nuclides
623+
self._atomic_weight_ratios = statepoint.summary.nuclides
594624

595625
if statepoint.run_mode == 'eigenvalue':
596626
self._keff = statepoint.keff.n
@@ -1005,7 +1035,7 @@ def get_xsdata(self, domain, xsdata_name, nuclide='total', xs_type='macro',
10051035
xsdata.num_azimuthal = self.num_azimuthal
10061036

10071037
if nuclide != 'total':
1008-
xsdata.atomic_weight_ratio = self._nuclides[nuclide]
1038+
xsdata.atomic_weight_ratio = self._atomic_weight_ratios[nuclide]
10091039

10101040
if subdomain is None:
10111041
subdomain = 'all'

tests/regression_tests/mgxs_library_specific_nuclides/__init__.py

Whitespace-only changes.
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
<?xml version='1.0' encoding='utf-8'?>
2+
<geometry>
3+
<cell id="1" material="1" name="Fuel" region="-1" universe="0" />
4+
<cell id="2" material="2" name="Cladding" region="1 -2" universe="0" />
5+
<cell id="3" material="3" name="Water" region="2 3 -4 5 -6" universe="0" />
6+
<surface coeffs="0 0 0.39218" id="1" name="Fuel OR" type="z-cylinder" />
7+
<surface coeffs="0 0 0.4572" id="2" name="Clad OR" type="z-cylinder" />
8+
<surface boundary="reflective" coeffs="-0.63" id="3" name="left" type="x-plane" />
9+
<surface boundary="reflective" coeffs="0.63" id="4" name="right" type="x-plane" />
10+
<surface boundary="reflective" coeffs="-0.63" id="5" name="bottom" type="y-plane" />
11+
<surface boundary="reflective" coeffs="0.63" id="6" name="top" type="y-plane" />
12+
</geometry>
13+
<?xml version='1.0' encoding='utf-8'?>
14+
<materials>
15+
<material depletable="true" id="1" name="UO2 (2.4%)">
16+
<density units="g/cm3" value="10.29769" />
17+
<nuclide ao="4.4843e-06" name="U234" />
18+
<nuclide ao="0.00055815" name="U235" />
19+
<nuclide ao="0.022408" name="U238" />
20+
<nuclide ao="0.045829" name="O16" />
21+
</material>
22+
<material id="2" name="Zircaloy">
23+
<density units="g/cm3" value="6.55" />
24+
<nuclide ao="0.021827" name="Zr90" />
25+
<nuclide ao="0.00476" name="Zr91" />
26+
<nuclide ao="0.0072758" name="Zr92" />
27+
<nuclide ao="0.0073734" name="Zr94" />
28+
<nuclide ao="0.0011879" name="Zr96" />
29+
</material>
30+
<material id="3" name="Hot borated water">
31+
<density units="g/cm3" value="0.740582" />
32+
<nuclide ao="0.049457" name="H1" />
33+
<nuclide ao="0.024672" name="O16" />
34+
<nuclide ao="8.0042e-06" name="B10" />
35+
<nuclide ao="3.2218e-05" name="B11" />
36+
<sab name="c_H_in_H2O" />
37+
</material>
38+
</materials>
39+
<?xml version='1.0' encoding='utf-8'?>
40+
<settings>
41+
<run_mode>eigenvalue</run_mode>
42+
<particles>100</particles>
43+
<batches>10</batches>
44+
<inactive>5</inactive>
45+
<source strength="1.0">
46+
<space type="fission">
47+
<parameters>-0.63 -0.63 -1 0.63 0.63 1</parameters>
48+
</space>
49+
</source>
50+
</settings>
51+
<?xml version='1.0' encoding='utf-8'?>
52+
<tallies>
53+
<filter id="383" type="material">
54+
<bins>1 2 3</bins>
55+
</filter>
56+
<filter id="2" type="energy">
57+
<bins>0.0 0.625 20000000.0</bins>
58+
</filter>
59+
<filter id="1" type="material">
60+
<bins>1</bins>
61+
</filter>
62+
<filter id="5" type="energyout">
63+
<bins>0.0 0.625 20000000.0</bins>
64+
</filter>
65+
<filter id="6" type="legendre">
66+
<order>1</order>
67+
</filter>
68+
<filter id="30" type="legendre">
69+
<order>3</order>
70+
</filter>
71+
<filter id="54" type="energy">
72+
<bins>0.0 20000000.0</bins>
73+
</filter>
74+
<filter id="106" type="material">
75+
<bins>2</bins>
76+
</filter>
77+
<filter id="251" type="material">
78+
<bins>3</bins>
79+
</filter>
80+
<tally id="528">
81+
<filters>383 2</filters>
82+
<nuclides>total</nuclides>
83+
<scores>flux</scores>
84+
<estimator>tracklength</estimator>
85+
</tally>
86+
<tally id="167">
87+
<filters>1 2</filters>
88+
<nuclides>U235 total</nuclides>
89+
<scores>total absorption (n,2n) (n,3n) (n,4n) fission nu-fission kappa-fission scatter inverse-velocity prompt-nu-fission (n,elastic) (n,level) (n,na) (n,nc) (n,gamma) (n,a) (n,Xa) heating damage-energy (n,n1) (n,a0)</scores>
90+
<estimator>tracklength</estimator>
91+
</tally>
92+
<tally id="540">
93+
<filters>383 2</filters>
94+
<nuclides>total</nuclides>
95+
<scores>flux</scores>
96+
<estimator>analog</estimator>
97+
</tally>
98+
<tally id="119">
99+
<filters>1 5 6</filters>
100+
<nuclides>U235 total</nuclides>
101+
<scores>scatter nu-scatter</scores>
102+
<estimator>analog</estimator>
103+
</tally>
104+
<tally id="54">
105+
<filters>1 2</filters>
106+
<nuclides>U235 total</nuclides>
107+
<scores>nu-scatter</scores>
108+
<estimator>analog</estimator>
109+
</tally>
110+
<tally id="84">
111+
<filters>1 2 5 30</filters>
112+
<nuclides>U235 total</nuclides>
113+
<scores>scatter nu-scatter</scores>
114+
<estimator>analog</estimator>
115+
</tally>
116+
<tally id="179">
117+
<filters>1 2 5</filters>
118+
<nuclides>U235 total</nuclides>
119+
<scores>nu-scatter scatter nu-fission prompt-nu-fission (n,nc) (n,n1) (n,2n)</scores>
120+
<estimator>analog</estimator>
121+
</tally>
122+
<tally id="90">
123+
<filters>1 54</filters>
124+
<nuclides>U235 total</nuclides>
125+
<scores>nu-fission prompt-nu-fission</scores>
126+
<estimator>analog</estimator>
127+
</tally>
128+
<tally id="91">
129+
<filters>1 5</filters>
130+
<nuclides>U235 total</nuclides>
131+
<scores>nu-fission prompt-nu-fission</scores>
132+
<estimator>analog</estimator>
133+
</tally>
134+
<tally id="348">
135+
<filters>106 2</filters>
136+
<nuclides>Zr90 total</nuclides>
137+
<scores>total absorption (n,2n) (n,3n) (n,4n) fission nu-fission kappa-fission scatter inverse-velocity prompt-nu-fission (n,elastic) (n,level) (n,na) (n,nc) (n,gamma) (n,a) (n,Xa) heating damage-energy (n,n1) (n,a0)</scores>
138+
<estimator>tracklength</estimator>
139+
</tally>
140+
<tally id="300">
141+
<filters>106 5 6</filters>
142+
<nuclides>Zr90 total</nuclides>
143+
<scores>scatter nu-scatter</scores>
144+
<estimator>analog</estimator>
145+
</tally>
146+
<tally id="235">
147+
<filters>106 2</filters>
148+
<nuclides>Zr90 total</nuclides>
149+
<scores>nu-scatter</scores>
150+
<estimator>analog</estimator>
151+
</tally>
152+
<tally id="265">
153+
<filters>106 2 5 30</filters>
154+
<nuclides>Zr90 total</nuclides>
155+
<scores>scatter nu-scatter</scores>
156+
<estimator>analog</estimator>
157+
</tally>
158+
<tally id="360">
159+
<filters>106 2 5</filters>
160+
<nuclides>Zr90 total</nuclides>
161+
<scores>nu-scatter scatter nu-fission prompt-nu-fission (n,nc) (n,n1) (n,2n)</scores>
162+
<estimator>analog</estimator>
163+
</tally>
164+
<tally id="271">
165+
<filters>106 54</filters>
166+
<nuclides>Zr90 total</nuclides>
167+
<scores>nu-fission prompt-nu-fission</scores>
168+
<estimator>analog</estimator>
169+
</tally>
170+
<tally id="272">
171+
<filters>106 5</filters>
172+
<nuclides>Zr90 total</nuclides>
173+
<scores>nu-fission prompt-nu-fission</scores>
174+
<estimator>analog</estimator>
175+
</tally>
176+
<tally id="529">
177+
<filters>251 2</filters>
178+
<nuclides>H1 total</nuclides>
179+
<scores>total absorption (n,2n) (n,3n) (n,4n) fission nu-fission kappa-fission scatter inverse-velocity prompt-nu-fission (n,elastic) (n,level) (n,na) (n,nc) (n,gamma) (n,a) (n,Xa) heating damage-energy (n,n1) (n,a0)</scores>
180+
<estimator>tracklength</estimator>
181+
</tally>
182+
<tally id="481">
183+
<filters>251 5 6</filters>
184+
<nuclides>H1 total</nuclides>
185+
<scores>scatter nu-scatter</scores>
186+
<estimator>analog</estimator>
187+
</tally>
188+
<tally id="416">
189+
<filters>251 2</filters>
190+
<nuclides>H1 total</nuclides>
191+
<scores>nu-scatter</scores>
192+
<estimator>analog</estimator>
193+
</tally>
194+
<tally id="446">
195+
<filters>251 2 5 30</filters>
196+
<nuclides>H1 total</nuclides>
197+
<scores>scatter nu-scatter</scores>
198+
<estimator>analog</estimator>
199+
</tally>
200+
<tally id="541">
201+
<filters>251 2 5</filters>
202+
<nuclides>H1 total</nuclides>
203+
<scores>nu-scatter scatter nu-fission prompt-nu-fission (n,nc) (n,n1) (n,2n)</scores>
204+
<estimator>analog</estimator>
205+
</tally>
206+
<tally id="452">
207+
<filters>251 54</filters>
208+
<nuclides>H1 total</nuclides>
209+
<scores>nu-fission prompt-nu-fission</scores>
210+
<estimator>analog</estimator>
211+
</tally>
212+
<tally id="453">
213+
<filters>251 5</filters>
214+
<nuclides>H1 total</nuclides>
215+
<scores>nu-fission prompt-nu-fission</scores>
216+
<estimator>analog</estimator>
217+
</tally>
218+
</tallies>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3e86542d1166b8a0bcc61742b88c9e931d63733477f3274b32b4da64d8f05413fa6330d5615f44f24735c2c2f77d3071f3dce38faba284c321ceab81c1064480
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import hashlib
2+
3+
import openmc
4+
import openmc.mgxs
5+
from openmc.examples import pwr_pin_cell
6+
7+
from tests.testing_harness import PyAPITestHarness
8+
9+
10+
class MGXSTestHarness(PyAPITestHarness):
11+
def __init__(self, *args, **kwargs):
12+
super().__init__(*args, **kwargs)
13+
14+
# Initialize a two-group structure
15+
energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6])
16+
17+
# Initialize MGXS Library for a few cross section types
18+
self.mgxs_lib = openmc.mgxs.Library(self._model.geometry)
19+
self.mgxs_lib.by_nuclide = True
20+
21+
# Test relevant MGXS types
22+
relevant_MGXS_TYPES = [item for item in openmc.mgxs.MGXS_TYPES
23+
if item != 'current']
24+
# Add in a subset of openmc.mgxs.ARBITRARY_VECTOR_TYPES and
25+
# openmc.mgxs.ARBITRARY_MATRIX_TYPES so we can see the code works,
26+
# but not use too much resources
27+
relevant_MGXS_TYPES += [
28+
"(n,elastic)", "(n,level)", "(n,2n)", "(n,na)", "(n,nc)",
29+
"(n,gamma)", "(n,a)", "(n,Xa)", "heating", "damage-energy",
30+
"(n,n1)", "(n,a0)", "(n,nc) matrix", "(n,n1) matrix",
31+
"(n,2n) matrix"]
32+
self.mgxs_lib.mgxs_types = tuple(relevant_MGXS_TYPES)
33+
self.mgxs_lib.energy_groups = energy_groups
34+
self.mgxs_lib.legendre_order = 3
35+
self.mgxs_lib.domain_type = 'material'
36+
self.mgxs_lib.nuclides = ['U235', 'Zr90', 'H1']
37+
self.mgxs_lib.build_library()
38+
39+
# Add tallies
40+
self.mgxs_lib.add_to_tallies_file(self._model.tallies, merge=True)
41+
42+
def _get_results(self, hash_output=True):
43+
"""Digest info in the statepoint and return as a string."""
44+
45+
# Read the statepoint file.
46+
sp = openmc.StatePoint(self._sp_name)
47+
48+
# Load the MGXS library from the statepoint
49+
self.mgxs_lib.load_from_statepoint(sp)
50+
51+
# Build a string from Pandas Dataframe for each MGXS
52+
outstr = ''
53+
for domain in self.mgxs_lib.domains:
54+
for mgxs_type in self.mgxs_lib.mgxs_types:
55+
mgxs = self.mgxs_lib.get_mgxs(domain, mgxs_type)
56+
df = mgxs.get_pandas_dataframe()
57+
outstr += df.to_string() + '\n'
58+
59+
# Hash the results if necessary
60+
if hash_output:
61+
sha512 = hashlib.sha512()
62+
sha512.update(outstr.encode('utf-8'))
63+
outstr = sha512.hexdigest()
64+
65+
return outstr
66+
67+
68+
def test_mgxs_library_specific_nuclides():
69+
model = pwr_pin_cell()
70+
harness = MGXSTestHarness('statepoint.10.h5', model)
71+
harness.main()

0 commit comments

Comments
 (0)