mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-29 06:35:48 -04:00
adding back files to be reviewed
This commit is contained in:
parent
ae28233110
commit
bc09d1ef55
1244 changed files with 301904 additions and 0 deletions
16
tests/unit_tests/__init__.py
Normal file
16
tests/unit_tests/__init__.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import shutil
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
|
||||
# Check if NJOY is available
|
||||
needs_njoy = pytest.mark.skipif(shutil.which('njoy') is None,
|
||||
reason="NJOY not installed")
|
||||
|
||||
|
||||
def assert_unbounded(obj):
|
||||
"""Assert that a region/cell is unbounded."""
|
||||
ll, ur = obj.bounding_box
|
||||
assert ll == pytest.approx((-np.inf, -np.inf, -np.inf))
|
||||
assert ur == pytest.approx((np.inf, np.inf, np.inf))
|
||||
124
tests/unit_tests/conftest.py
Normal file
124
tests/unit_tests/conftest.py
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
import openmc
|
||||
import pytest
|
||||
|
||||
from tests.regression_tests import config
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def mpi_intracomm():
|
||||
if config['mpi']:
|
||||
from mpi4py import MPI
|
||||
return MPI.COMM_WORLD
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def uo2():
|
||||
m = openmc.Material(material_id=100, name='UO2')
|
||||
m.add_nuclide('U235', 1.0)
|
||||
m.add_nuclide('O16', 2.0)
|
||||
m.set_density('g/cm3', 10.0)
|
||||
m.depletable = True
|
||||
return m
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def water():
|
||||
m = openmc.Material(name='light water')
|
||||
m.add_nuclide('H1', 2.0)
|
||||
m.add_nuclide('O16', 1.0)
|
||||
m.set_density('g/cm3', 1.0)
|
||||
m.add_s_alpha_beta('c_H_in_H2O')
|
||||
return m
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def sphere_model():
|
||||
model = openmc.model.Model()
|
||||
m = openmc.Material()
|
||||
m.add_nuclide('U235', 1.0)
|
||||
m.set_density('g/cm3', 1.0)
|
||||
model.materials.append(m)
|
||||
|
||||
sph = openmc.Sphere(boundary_type='vacuum')
|
||||
c = openmc.Cell(fill=m, region=-sph)
|
||||
model.geometry.root_universe = openmc.Universe(cells=[c])
|
||||
|
||||
model.settings.particles = 100
|
||||
model.settings.batches = 10
|
||||
model.settings.run_mode = 'fixed source'
|
||||
model.settings.source = openmc.Source(space=openmc.stats.Point())
|
||||
return model
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cell_with_lattice():
|
||||
m_inside = [openmc.Material(), openmc.Material(), None, openmc.Material()]
|
||||
m_outside = openmc.Material()
|
||||
|
||||
cyl = openmc.ZCylinder(r=1.0)
|
||||
inside_cyl = openmc.Cell(fill=m_inside, region=-cyl)
|
||||
outside_cyl = openmc.Cell(fill=m_outside, region=+cyl)
|
||||
univ = openmc.Universe(cells=[inside_cyl, outside_cyl])
|
||||
|
||||
lattice = openmc.RectLattice(name='My Lattice')
|
||||
lattice.lower_left = (-4.0, -4.0)
|
||||
lattice.pitch = (4.0, 4.0)
|
||||
lattice.universes = [[univ, univ], [univ, univ]]
|
||||
main_cell = openmc.Cell(fill=lattice)
|
||||
|
||||
return ([inside_cyl, outside_cyl, main_cell],
|
||||
[m_inside[0], m_inside[1], m_inside[3], m_outside],
|
||||
univ, lattice)
|
||||
|
||||
@pytest.fixture
|
||||
def mixed_lattice_model(uo2, water):
|
||||
cyl = openmc.ZCylinder(r=0.4)
|
||||
c1 = openmc.Cell(fill=uo2, region=-cyl)
|
||||
c1.temperature = 600.0
|
||||
c2 = openmc.Cell(fill=water, region=+cyl)
|
||||
pin = openmc.Universe(cells=[c1, c2])
|
||||
|
||||
empty = openmc.Cell()
|
||||
empty_univ = openmc.Universe(cells=[empty])
|
||||
|
||||
hex_lattice = openmc.HexLattice()
|
||||
hex_lattice.center = (0.0, 0.0)
|
||||
hex_lattice.pitch = (1.2, 10.0)
|
||||
outer_ring = [pin]*6
|
||||
inner_ring = [empty_univ]
|
||||
axial_level = [outer_ring, inner_ring]
|
||||
hex_lattice.universes = [axial_level]*3
|
||||
hex_lattice.outer = empty_univ
|
||||
|
||||
cell_hex = openmc.Cell(fill=hex_lattice)
|
||||
u = openmc.Universe(cells=[cell_hex])
|
||||
rotated_cell_hex = openmc.Cell(fill=u)
|
||||
rotated_cell_hex.rotation = (0., 0., 30.)
|
||||
ur = openmc.Universe(cells=[rotated_cell_hex])
|
||||
|
||||
d = 6.0
|
||||
rect_lattice = openmc.RectLattice()
|
||||
rect_lattice.lower_left = (-d, -d)
|
||||
rect_lattice.pitch = (d, d)
|
||||
rect_lattice.outer = empty_univ
|
||||
rect_lattice.universes = [
|
||||
[ur, empty_univ],
|
||||
[empty_univ, u]
|
||||
]
|
||||
|
||||
xmin = openmc.XPlane(-d, 'periodic')
|
||||
xmax = openmc.XPlane(d, 'periodic')
|
||||
xmin.periodic_surface = xmax
|
||||
ymin = openmc.YPlane(-d, 'periodic')
|
||||
ymax = openmc.YPlane(d, 'periodic')
|
||||
main_cell = openmc.Cell(fill=rect_lattice,
|
||||
region=+xmin & -xmax & +ymin & -ymax)
|
||||
|
||||
# Create geometry and use unique material in each fuel cell
|
||||
geometry = openmc.Geometry([main_cell])
|
||||
geometry.determine_paths()
|
||||
c1.fill = [water.clone() for i in range(c1.num_instances)]
|
||||
|
||||
return openmc.model.Model(geometry)
|
||||
0
tests/unit_tests/dagmc/__init__.py
Normal file
0
tests/unit_tests/dagmc/__init__.py
Normal file
1
tests/unit_tests/dagmc/dagmc.h5m
Symbolic link
1
tests/unit_tests/dagmc/dagmc.h5m
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../regression_tests/dagmc/legacy/dagmc.h5m
|
||||
74
tests/unit_tests/dagmc/test.py
Normal file
74
tests/unit_tests/dagmc/test.py
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import shutil
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
import openmc
|
||||
import openmc.lib
|
||||
|
||||
from tests import cdtemp
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not openmc.lib._dagmc_enabled(),
|
||||
reason="DAGMC CAD geometry is not enabled.")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module", autouse=True)
|
||||
def dagmc_model(request):
|
||||
|
||||
model = openmc.model.Model()
|
||||
|
||||
# settings
|
||||
model.settings.batches = 5
|
||||
model.settings.inactive = 0
|
||||
model.settings.particles = 100
|
||||
model.settings.temperature = {'tolerance': 50.0}
|
||||
model.settings.verbosity = 1
|
||||
source_box = openmc.stats.Box([ -4, -4, -4 ],
|
||||
[ 4, 4, 4 ])
|
||||
source = openmc.Source(space=source_box)
|
||||
model.settings.source = source
|
||||
|
||||
model.settings.dagmc = True
|
||||
|
||||
# tally
|
||||
tally = openmc.Tally()
|
||||
tally.scores = ['total']
|
||||
tally.filters = [openmc.CellFilter(1)]
|
||||
model.tallies = [tally]
|
||||
|
||||
# materials
|
||||
u235 = openmc.Material(name="fuel")
|
||||
u235.add_nuclide('U235', 1.0, 'ao')
|
||||
u235.set_density('g/cc', 11)
|
||||
u235.id = 40
|
||||
u235.temperature = 320
|
||||
|
||||
water = openmc.Material(name="water")
|
||||
water.add_nuclide('H1', 2.0, 'ao')
|
||||
water.add_nuclide('O16', 1.0, 'ao')
|
||||
water.set_density('g/cc', 1.0)
|
||||
water.add_s_alpha_beta('c_H_in_H2O')
|
||||
water.id = 41
|
||||
|
||||
mats = openmc.Materials([u235, water])
|
||||
model.materials = mats
|
||||
|
||||
# location of dagmc file in test directory
|
||||
dagmc_file = request.fspath.dirpath() + "/dagmc.h5m"
|
||||
# move to a temporary directory
|
||||
with cdtemp():
|
||||
shutil.copyfile(dagmc_file, "./dagmc.h5m")
|
||||
model.export_to_xml()
|
||||
openmc.lib.init()
|
||||
yield
|
||||
|
||||
openmc.lib.finalize()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cell_id,exp_temp", ((1, 320.0), # assigned by material
|
||||
(2, 300.0), # assigned in dagmc file
|
||||
(3, 293.6))) # assigned by default
|
||||
def test_dagmc_temperatures(cell_id, exp_temp):
|
||||
cell = openmc.lib.cells[cell_id]
|
||||
assert np.isclose(cell.get_temperature(), exp_temp)
|
||||
168
tests/unit_tests/test_cell.py
Normal file
168
tests/unit_tests/test_cell.py
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
import xml.etree. ElementTree as ET
|
||||
|
||||
import numpy as np
|
||||
import openmc
|
||||
import pytest
|
||||
|
||||
from tests.unit_tests import assert_unbounded
|
||||
|
||||
|
||||
def test_contains():
|
||||
# Cell with specified region
|
||||
s = openmc.XPlane()
|
||||
c = openmc.Cell(region=+s)
|
||||
assert (1.0, 0.0, 0.0) in c
|
||||
assert (-1.0, 0.0, 0.0) not in c
|
||||
|
||||
# Cell with no region
|
||||
c = openmc.Cell()
|
||||
assert (10.0, -4., 2.0) in c
|
||||
|
||||
|
||||
def test_repr(cell_with_lattice):
|
||||
cells, mats, univ, lattice = cell_with_lattice
|
||||
repr(cells[0]) # cell with distributed materials
|
||||
repr(cells[1]) # cell with material
|
||||
repr(cells[2]) # cell with lattice
|
||||
|
||||
# Empty cell
|
||||
c = openmc.Cell()
|
||||
repr(c)
|
||||
|
||||
|
||||
def test_bounding_box():
|
||||
zcyl = openmc.ZCylinder()
|
||||
c = openmc.Cell(region=-zcyl)
|
||||
ll, ur = c.bounding_box
|
||||
assert ll == pytest.approx((-1., -1., -np.inf))
|
||||
assert ur == pytest.approx((1., 1., np.inf))
|
||||
|
||||
# Cell with no region specified
|
||||
c = openmc.Cell()
|
||||
assert_unbounded(c)
|
||||
|
||||
|
||||
def test_clone():
|
||||
m = openmc.Material()
|
||||
cyl = openmc.ZCylinder()
|
||||
c = openmc.Cell(fill=m, region=-cyl)
|
||||
c.temperature = 650.
|
||||
|
||||
c2 = c.clone()
|
||||
assert c2.id != c.id
|
||||
assert c2.fill != c.fill
|
||||
assert c2.region != c.region
|
||||
assert c2.temperature == c.temperature
|
||||
|
||||
|
||||
def test_temperature(cell_with_lattice):
|
||||
# Make sure temperature propagates through universes
|
||||
m = openmc.Material()
|
||||
s = openmc.XPlane()
|
||||
c1 = openmc.Cell(fill=m, region=+s)
|
||||
c2 = openmc.Cell(fill=m, region=-s)
|
||||
u1 = openmc.Universe(cells=[c1, c2])
|
||||
c = openmc.Cell(fill=u1)
|
||||
|
||||
c.temperature = 400.0
|
||||
assert c1.temperature == 400.0
|
||||
assert c2.temperature == 400.0
|
||||
with pytest.raises(ValueError):
|
||||
c.temperature = -100.
|
||||
|
||||
# distributed temperature
|
||||
cells, _, _, _ = cell_with_lattice
|
||||
c = cells[0]
|
||||
c.temperature = (300., 600., 900.)
|
||||
|
||||
|
||||
def test_rotation():
|
||||
u = openmc.Universe()
|
||||
c = openmc.Cell(fill=u)
|
||||
c.rotation = (180.0, 0.0, 0.0)
|
||||
assert np.allclose(c.rotation_matrix, [
|
||||
[1., 0., 0.],
|
||||
[0., -1., 0.],
|
||||
[0., 0., -1.]
|
||||
])
|
||||
|
||||
c.rotation = (0.0, 90.0, 0.0)
|
||||
assert np.allclose(c.rotation_matrix, [
|
||||
[0., 0., -1.],
|
||||
[0., 1., 0.],
|
||||
[1., 0., 0.]
|
||||
])
|
||||
|
||||
|
||||
def test_get_nuclides(uo2):
|
||||
c = openmc.Cell(fill=uo2)
|
||||
nucs = c.get_nuclides()
|
||||
assert nucs == ['U235', 'O16']
|
||||
|
||||
|
||||
def test_nuclide_densities(uo2):
|
||||
c = openmc.Cell(fill=uo2)
|
||||
expected_nucs = ['U235', 'O16']
|
||||
expected_density = [1.0, 2.0]
|
||||
tuples = list(c.get_nuclide_densities().values())
|
||||
for nuc, density, t in zip(expected_nucs, expected_density, tuples):
|
||||
assert nuc == t[0]
|
||||
assert density == t[1]
|
||||
|
||||
# Empty cell
|
||||
c = openmc.Cell()
|
||||
assert not c.get_nuclide_densities()
|
||||
|
||||
|
||||
def test_get_all_universes(cell_with_lattice):
|
||||
# Cell with nested universes
|
||||
c1 = openmc.Cell()
|
||||
u1 = openmc.Universe(cells=[c1])
|
||||
c2 = openmc.Cell(fill=u1)
|
||||
u2 = openmc.Universe(cells=[c2])
|
||||
c3 = openmc.Cell(fill=u2)
|
||||
univs = set(c3.get_all_universes().values())
|
||||
assert not (univs ^ {u1, u2})
|
||||
|
||||
# Cell with lattice
|
||||
cells, mats, univ, lattice = cell_with_lattice
|
||||
univs = set(cells[-1].get_all_universes().values())
|
||||
assert not (univs ^ {univ})
|
||||
|
||||
|
||||
def test_get_all_materials(cell_with_lattice):
|
||||
# Normal cell
|
||||
m = openmc.Material()
|
||||
c = openmc.Cell(fill=m)
|
||||
test_mats = set(c.get_all_materials().values())
|
||||
assert not(test_mats ^ {m})
|
||||
|
||||
# Cell filled with distributed materials
|
||||
cells, mats, univ, lattice = cell_with_lattice
|
||||
c = cells[0]
|
||||
test_mats = set(c.get_all_materials().values())
|
||||
assert not (test_mats ^ set(m for m in c.fill if m is not None))
|
||||
|
||||
# Cell filled with universe
|
||||
c = cells[-1]
|
||||
test_mats = set(c.get_all_materials().values())
|
||||
assert not (test_mats ^ set(mats))
|
||||
|
||||
|
||||
def test_to_xml_element(cell_with_lattice):
|
||||
cells, mats, univ, lattice = cell_with_lattice
|
||||
|
||||
c = cells[-1]
|
||||
root = ET.Element('geometry')
|
||||
elem = c.create_xml_subelement(root)
|
||||
assert elem.tag == 'cell'
|
||||
assert elem.get('id') == str(c.id)
|
||||
assert elem.get('region') is None
|
||||
surf_elem = root.find('surface')
|
||||
assert surf_elem.get('id') == str(cells[0].region.surface.id)
|
||||
|
||||
c = cells[0]
|
||||
c.temperature = 900.0
|
||||
elem = c.create_xml_subelement(root)
|
||||
assert elem.get('region') == str(c.region)
|
||||
assert elem.get('temperature') == str(c.temperature)
|
||||
98
tests/unit_tests/test_complex_cell_bb.py
Normal file
98
tests/unit_tests/test_complex_cell_bb.py
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
import numpy as np
|
||||
import openmc.lib
|
||||
import pytest
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def complex_cell(run_in_tmpdir, mpi_intracomm):
|
||||
|
||||
openmc.reset_auto_ids()
|
||||
|
||||
model = openmc.model.Model()
|
||||
|
||||
u235 = openmc.Material()
|
||||
u235.set_density('g/cc', 4.5)
|
||||
u235.add_nuclide("U235", 1.0)
|
||||
|
||||
u238 = openmc.Material()
|
||||
u238.set_density('g/cc', 4.5)
|
||||
u238.add_nuclide("U238", 1.0)
|
||||
|
||||
zr90 = openmc.Material()
|
||||
zr90.set_density('g/cc', 2.0)
|
||||
zr90.add_nuclide("Zr90", 1.0)
|
||||
|
||||
n14 = openmc.Material()
|
||||
n14.set_density('g/cc', 0.1)
|
||||
n14.add_nuclide("N14", 1.0)
|
||||
|
||||
model.materials = (u235, u238, zr90, n14)
|
||||
|
||||
s1 = openmc.XPlane(-10.0, 'vacuum')
|
||||
s2 = openmc.XPlane(-7.0)
|
||||
s3 = openmc.XPlane(-4.0)
|
||||
s4 = openmc.XPlane(4.0)
|
||||
s5 = openmc.XPlane(7.0)
|
||||
s6 = openmc.XPlane(10.0, 'vacuum')
|
||||
s7 = openmc.XPlane(0.0)
|
||||
|
||||
s11 = openmc.YPlane(-10.0, 'vacuum')
|
||||
s12 = openmc.YPlane(-7.0)
|
||||
s13 = openmc.YPlane(-4.0)
|
||||
s14 = openmc.YPlane(4.0)
|
||||
s15 = openmc.YPlane(7.0)
|
||||
s16 = openmc.YPlane(10.0, 'vacuum')
|
||||
s17 = openmc.YPlane(0.0)
|
||||
|
||||
c1 = openmc.Cell(fill=u235)
|
||||
c1.region = ~(-s3 | +s4 | ~(+s13 & -s14))
|
||||
|
||||
c2 = openmc.Cell(fill=u238)
|
||||
c2.region = ~(+s3 & -s4 & +s13 & -s14) & +s2 & -s5 & +s12 & -s15
|
||||
|
||||
c3 = openmc.Cell(fill=zr90)
|
||||
c3.region = ((+s1 & -s7 & +s17 & -s16) | (+s7 & -s6 & +s11 & -s17)) \
|
||||
& (-s2 | +s5 | -s12 | +s15)
|
||||
|
||||
c4 = openmc.Cell(fill=n14)
|
||||
c4.region = ((+s1 & -s7 & +s11 & -s17) | (+s7 & -s6 & +s17 & -s16)) & \
|
||||
~(+s2 & -s5 & +s12 & -s15)
|
||||
|
||||
c5 = openmc.Cell(fill=n14)
|
||||
c5.region = ~(+s1 & -s6 & +s11 & -s16)
|
||||
|
||||
model.geometry.root_universe = openmc.Universe()
|
||||
model.geometry.root_universe.add_cells([c1, c2, c3, c4, c5])
|
||||
|
||||
model.settings.batches = 10
|
||||
model.settings.inactive = 5
|
||||
model.settings.particles = 100
|
||||
model.settings.source = openmc.Source(space=openmc.stats.Box(
|
||||
[-10., -10., -1.], [10., 10., 1.]))
|
||||
|
||||
model.settings.verbosity = 1
|
||||
|
||||
model.export_to_xml()
|
||||
|
||||
openmc.lib.finalize()
|
||||
openmc.lib.init(intracomm=mpi_intracomm)
|
||||
|
||||
yield
|
||||
|
||||
openmc.lib.finalize()
|
||||
|
||||
|
||||
expected_results = ( (1, (( -4., -4., -np.inf),
|
||||
( 4., 4., np.inf))),
|
||||
(2, (( -7., -7., -np.inf),
|
||||
( 7., 7., np.inf))),
|
||||
(3, ((-10., -10., -np.inf),
|
||||
( 10., 10., np.inf))),
|
||||
(4, ((-10., -10., -np.inf),
|
||||
( 10., 10., np.inf))),
|
||||
(5, ((-np.inf, -np.inf, -np.inf),
|
||||
( np.inf, np.inf, np.inf))) )
|
||||
@pytest.mark.parametrize("cell_id,expected_box", expected_results)
|
||||
def test_cell_box(cell_id, expected_box):
|
||||
cell_box = openmc.lib.cells[cell_id].bounding_box
|
||||
assert tuple(cell_box[0]) == expected_box[0]
|
||||
assert tuple(cell_box[1]) == expected_box[1]
|
||||
81
tests/unit_tests/test_data_decay.py
Normal file
81
tests/unit_tests/test_data_decay.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from collections.abc import Mapping
|
||||
import os
|
||||
from math import log
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from uncertainties import ufloat
|
||||
import openmc.data
|
||||
|
||||
|
||||
def ufloat_close(a, b):
|
||||
assert a.nominal_value == pytest.approx(b.nominal_value)
|
||||
assert a.std_dev == pytest.approx(b.std_dev)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def nb90():
|
||||
"""Nb90 decay data."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'decay', 'dec-041_Nb_090.endf')
|
||||
return openmc.data.Decay.from_endf(filename)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def u235_yields():
|
||||
"""U235 fission product yield data."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'nfy', 'nfy-092_U_235.endf')
|
||||
return openmc.data.FissionProductYields.from_endf(filename)
|
||||
|
||||
|
||||
def test_nb90_halflife(nb90):
|
||||
ufloat_close(nb90.half_life, ufloat(52560.0, 180.0))
|
||||
ufloat_close(nb90.decay_constant, log(2.)/nb90.half_life)
|
||||
|
||||
|
||||
def test_nb90_nuclide(nb90):
|
||||
assert nb90.nuclide['atomic_number'] == 41
|
||||
assert nb90.nuclide['mass_number'] == 90
|
||||
assert nb90.nuclide['isomeric_state'] == 0
|
||||
assert nb90.nuclide['parity'] == 1.0
|
||||
assert nb90.nuclide['spin'] == 8.0
|
||||
assert not nb90.nuclide['stable']
|
||||
assert nb90.nuclide['mass'] == pytest.approx(89.13888)
|
||||
|
||||
|
||||
def test_nb90_modes(nb90):
|
||||
assert len(nb90.modes) == 2
|
||||
ec = nb90.modes[0]
|
||||
assert ec.modes == ['ec/beta+']
|
||||
assert ec.parent == 'Nb90'
|
||||
assert ec.daughter == 'Zr90'
|
||||
assert 'Nb90 -> Zr90' in str(ec)
|
||||
ufloat_close(ec.branching_ratio, ufloat(0.0147633, 0.0003386195))
|
||||
ufloat_close(ec.energy, ufloat(6111000., 4000.))
|
||||
|
||||
# Make sure branching ratios sum to 1
|
||||
total = sum(m.branching_ratio for m in nb90.modes)
|
||||
assert total.nominal_value == pytest.approx(1.0)
|
||||
|
||||
|
||||
def test_nb90_spectra(nb90):
|
||||
assert sorted(nb90.spectra.keys()) == ['e-', 'ec/beta+', 'gamma', 'xray']
|
||||
|
||||
|
||||
def test_fpy(u235_yields):
|
||||
assert u235_yields.nuclide['atomic_number'] == 92
|
||||
assert u235_yields.nuclide['mass_number'] == 235
|
||||
assert u235_yields.nuclide['isomeric_state'] == 0
|
||||
assert u235_yields.nuclide['name'] == 'U235'
|
||||
assert u235_yields.energies == pytest.approx([0.0253, 500.e3, 1.4e7])
|
||||
|
||||
assert len(u235_yields.cumulative) == 3
|
||||
thermal = u235_yields.cumulative[0]
|
||||
ufloat_close(thermal['I135'], ufloat(0.0628187, 0.000879461))
|
||||
|
||||
assert len(u235_yields.independent) == 3
|
||||
thermal = u235_yields.independent[0]
|
||||
ufloat_close(thermal['I135'], ufloat(0.0292737, 0.000819663))
|
||||
116
tests/unit_tests/test_data_misc.py
Normal file
116
tests/unit_tests/test_data_misc.py
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from collections.abc import Mapping
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
import openmc.data
|
||||
|
||||
|
||||
def test_data_library(tmpdir):
|
||||
lib = openmc.data.DataLibrary.from_xml()
|
||||
for f in lib.libraries:
|
||||
assert sorted(f.keys()) == ['materials', 'path', 'type']
|
||||
|
||||
f = lib.get_by_material('U235')
|
||||
assert f['type'] == 'neutron'
|
||||
assert 'U235' in f['materials']
|
||||
|
||||
f = lib.get_by_material('c_H_in_H2O')
|
||||
assert f['type'] == 'thermal'
|
||||
assert 'c_H_in_H2O' in f['materials']
|
||||
|
||||
filename = str(tmpdir.join('test.xml'))
|
||||
lib.export_to_xml(filename)
|
||||
assert os.path.exists(filename)
|
||||
|
||||
new_lib = openmc.data.DataLibrary()
|
||||
directory = os.path.dirname(os.environ['OPENMC_CROSS_SECTIONS'])
|
||||
new_lib.register_file(os.path.join(directory, 'H1.h5'))
|
||||
assert new_lib.libraries[-1]['type'] == 'neutron'
|
||||
new_lib.register_file(os.path.join(directory, 'c_Zr_in_ZrH.h5'))
|
||||
assert new_lib.libraries[-1]['type'] == 'thermal'
|
||||
|
||||
|
||||
def test_depletion_chain_data_library(run_in_tmpdir):
|
||||
dep_lib = openmc.data.DataLibrary.from_xml()
|
||||
prev_len = len(dep_lib.libraries)
|
||||
chain_path = Path(__file__).parents[1] / "chain_simple.xml"
|
||||
dep_lib.register_file(chain_path)
|
||||
assert len(dep_lib.libraries) == prev_len + 1
|
||||
# Inspect
|
||||
dep_dict = dep_lib.libraries[-1]
|
||||
assert dep_dict['materials'] == []
|
||||
assert dep_dict['type'] == 'depletion_chain'
|
||||
assert dep_dict['path'] == str(chain_path)
|
||||
|
||||
out_path = "cross_section_chain.xml"
|
||||
dep_lib.export_to_xml(out_path)
|
||||
|
||||
dep_import = openmc.data.DataLibrary.from_xml(out_path)
|
||||
for lib in reversed(dep_import.libraries):
|
||||
if lib['type'] == 'depletion_chain':
|
||||
break
|
||||
else:
|
||||
raise IndexError("depletion_chain not found in exported DataLibrary")
|
||||
assert os.path.exists(lib['path'])
|
||||
|
||||
|
||||
def test_linearize():
|
||||
"""Test linearization of a continuous function."""
|
||||
x, y = openmc.data.linearize([-1., 1.], lambda x: 1 - x*x)
|
||||
f = openmc.data.Tabulated1D(x, y)
|
||||
assert f(-0.5) == pytest.approx(1 - 0.5*0.5, 0.001)
|
||||
assert f(0.32) == pytest.approx(1 - 0.32*0.32, 0.001)
|
||||
|
||||
|
||||
def test_thin():
|
||||
"""Test thinning of a tabulated function."""
|
||||
x = np.linspace(0., 2*np.pi, 1000)
|
||||
y = np.sin(x)
|
||||
x_thin, y_thin = openmc.data.thin(x, y)
|
||||
f = openmc.data.Tabulated1D(x_thin, y_thin)
|
||||
assert f(1.0) == pytest.approx(np.sin(1.0), 0.001)
|
||||
|
||||
|
||||
def test_atomic_mass():
|
||||
assert openmc.data.atomic_mass('H1') == 1.00782503224
|
||||
assert openmc.data.atomic_mass('U235') == 235.04392819
|
||||
with pytest.raises(KeyError):
|
||||
openmc.data.atomic_mass('U100')
|
||||
|
||||
|
||||
def test_atomic_weight():
|
||||
assert openmc.data.atomic_weight('C') == 12.011115164864455
|
||||
with pytest.raises(ValueError):
|
||||
openmc.data.atomic_weight('Qt')
|
||||
|
||||
|
||||
def test_water_density():
|
||||
dens = openmc.data.water_density
|
||||
# These test values are from IAPWS R7-97(2012). They are actually specific
|
||||
# volumes so they need to be inverted. They also need to be divided by 1000
|
||||
# to convert from [kg / m^3] to [g / cm^3].
|
||||
assert dens(300.0, 3.0) == pytest.approx(1e-3/0.100215168e-2, 1e-6)
|
||||
assert dens(300.0, 80.0) == pytest.approx(1e-3/0.971180894e-3, 1e-6)
|
||||
assert dens(500.0, 3.0) == pytest.approx(1e-3/0.120241800e-2, 1e-6)
|
||||
|
||||
|
||||
def test_gnd_name():
|
||||
assert openmc.data.gnd_name(1, 1) == 'H1'
|
||||
assert openmc.data.gnd_name(40, 90) == ('Zr90')
|
||||
assert openmc.data.gnd_name(95, 242, 0) == ('Am242')
|
||||
assert openmc.data.gnd_name(95, 242, 1) == ('Am242_m1')
|
||||
assert openmc.data.gnd_name(95, 242, 10) == ('Am242_m10')
|
||||
|
||||
|
||||
def test_zam():
|
||||
assert openmc.data.zam('H1') == (1, 1, 0)
|
||||
assert openmc.data.zam('Zr90') == (40, 90, 0)
|
||||
assert openmc.data.zam('Am242') == (95, 242, 0)
|
||||
assert openmc.data.zam('Am242_m1') == (95, 242, 1)
|
||||
assert openmc.data.zam('Am242_m10') == (95, 242, 10)
|
||||
with pytest.raises(ValueError):
|
||||
openmc.data.zam('garbage')
|
||||
48
tests/unit_tests/test_data_multipole.py
Normal file
48
tests/unit_tests/test_data_multipole.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import os
|
||||
import pathlib
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
import openmc.data
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def u235():
|
||||
directory = pathlib.Path(os.environ['OPENMC_CROSS_SECTIONS']).parent
|
||||
u235 = directory / 'wmp' / '092235.h5'
|
||||
return openmc.data.WindowedMultipole.from_hdf5(u235)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def b10():
|
||||
directory = pathlib.Path(os.environ['OPENMC_CROSS_SECTIONS']).parent
|
||||
b10 = directory / 'wmp' / '005010.h5'
|
||||
return openmc.data.WindowedMultipole.from_hdf5(b10)
|
||||
|
||||
|
||||
def test_evaluate(u235):
|
||||
"""Test the cross section evaluation of a library."""
|
||||
energies = [1e-3, 1.0, 10.0, 50.]
|
||||
scattering, absorption, fission = u235(energies, 0.0)
|
||||
assert (scattering[1], absorption[1], fission[1]) == \
|
||||
pytest.approx((13.09, 77.56, 67.36), rel=1e-3)
|
||||
scattering, absorption, fission = u235(energies, 300.0)
|
||||
assert (scattering[2], absorption[2], fission[2]) == \
|
||||
pytest.approx((11.24, 21.26, 15.50), rel=1e-3)
|
||||
|
||||
|
||||
def test_evaluate_none_poles(b10):
|
||||
"""Test a library with no poles, i.e., purely polynomials."""
|
||||
energies = [1e-3, 1.0, 10.0, 1e3, 1e5]
|
||||
scattering, absorption, fission = b10(energies, 0.0)
|
||||
assert (scattering[0], absorption[0], fission[0]) == \
|
||||
pytest.approx((2.201, 19330., 0.), rel=1e-3)
|
||||
scattering, absorption, fission = b10(energies, 300.0)
|
||||
assert (scattering[-1], absorption[-1], fission[-1]) == \
|
||||
pytest.approx((2.878, 1.982, 0.), rel=1e-3)
|
||||
|
||||
|
||||
def test_export_to_hdf5(tmpdir, u235):
|
||||
filename = str(tmpdir.join('092235.h5'))
|
||||
u235.export_to_hdf5(filename)
|
||||
assert os.path.exists(filename)
|
||||
519
tests/unit_tests/test_data_neutron.py
Normal file
519
tests/unit_tests/test_data_neutron.py
Normal file
|
|
@ -0,0 +1,519 @@
|
|||
from collections.abc import Mapping, Callable
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import pytest
|
||||
import openmc.data
|
||||
|
||||
from . import needs_njoy
|
||||
|
||||
_TEMPERATURES = [300., 600., 900.]
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def pu239():
|
||||
"""Pu239 HDF5 data."""
|
||||
directory = os.path.dirname(os.environ['OPENMC_CROSS_SECTIONS'])
|
||||
filename = os.path.join(directory, 'Pu239.h5')
|
||||
return openmc.data.IncidentNeutron.from_hdf5(filename)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def xe135():
|
||||
"""Xe135 ENDF data (contains SLBW resonance range)"""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'neutrons', 'n-054_Xe_135.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def sm150():
|
||||
"""Sm150 ENDF data (contains MLBW resonance range)"""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'neutrons', 'n-062_Sm_150.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def gd154():
|
||||
"""Gd154 ENDF data (contains Reich Moore resonance range and reosnance
|
||||
covariance with LCOMP=1)."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'neutrons', 'n-064_Gd_154.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename, covariance=True)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def cl35():
|
||||
"""Cl35 ENDF data (contains RML resonance range)"""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'neutrons', 'n-017_Cl_035.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def am241():
|
||||
"""Am241 ENDF data (contains Madland-Nix fission energy distribution)."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'neutrons', 'n-095_Am_241.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def u233():
|
||||
"""U233 ENDF data (contains Watt fission energy distribution)."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'neutrons', 'n-092_U_233.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def u236():
|
||||
"""U236 ENDF data (contains Watt fission energy distribution)."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'neutrons', 'n-092_U_236.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def na22():
|
||||
"""Na22 ENDF data (contains evaporation spectrum)."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'neutrons', 'n-011_Na_022.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def na23():
|
||||
"""Na23 ENDF data (contains MLBW resonance covariance with LCOMP=0)."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'neutrons', 'n-011_Na_023.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename, covariance=True)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def be9():
|
||||
"""Be9 ENDF data (contains laboratory angle-energy distribution)."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'neutrons', 'n-004_Be_009.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def h2():
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
endf_file = os.path.join(endf_data, 'neutrons', 'n-001_H_002.endf')
|
||||
return openmc.data.IncidentNeutron.from_njoy(
|
||||
endf_file, temperatures=_TEMPERATURES)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def am244():
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
endf_file = os.path.join(endf_data, 'neutrons', 'n-095_Am_244.endf')
|
||||
return openmc.data.IncidentNeutron.from_njoy(endf_file)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def ti50():
|
||||
"""Ti50 ENDF data (contains Multi-level Breit-Wigner resonance range and
|
||||
resonance covariance with LCOMP=1)."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'neutrons', 'n-022_Ti_050.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename, covariance=True)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def cf252():
|
||||
"""Cf252 ENDF data (contains RM resonance covariance with LCOMP=0)."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'neutrons', 'n-098_Cf_252.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename, covariance=True)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def th232():
|
||||
"""Th232 ENDF data (contains RM resonance covariance with LCOMP=2)."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'neutrons', 'n-090_Th_232.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename, covariance=True)
|
||||
|
||||
|
||||
def test_attributes(pu239):
|
||||
assert pu239.name == 'Pu239'
|
||||
assert pu239.mass_number == 239
|
||||
assert pu239.metastable == 0
|
||||
assert pu239.atomic_symbol == 'Pu'
|
||||
assert pu239.atomic_weight_ratio == pytest.approx(236.9986)
|
||||
|
||||
|
||||
def test_fission_energy(pu239):
|
||||
fer = pu239.fission_energy
|
||||
assert isinstance(fer, openmc.data.FissionEnergyRelease)
|
||||
components = ['betas', 'delayed_neutrons', 'delayed_photons', 'fragments',
|
||||
'neutrinos', 'prompt_neutrons', 'prompt_photons', 'recoverable',
|
||||
'total', 'q_prompt', 'q_recoverable', 'q_total']
|
||||
for c in components:
|
||||
assert isinstance(getattr(fer, c), Callable)
|
||||
|
||||
|
||||
def test_energy_grid(pu239):
|
||||
assert isinstance(pu239.energy, Mapping)
|
||||
for temp, grid in pu239.energy.items():
|
||||
assert temp.endswith('K')
|
||||
assert np.all(np.diff(grid) >= 0.0)
|
||||
|
||||
|
||||
def test_reactions(pu239):
|
||||
assert 2 in pu239.reactions
|
||||
assert isinstance(pu239.reactions[2], openmc.data.Reaction)
|
||||
with pytest.raises(KeyError):
|
||||
pu239.reactions[14]
|
||||
|
||||
|
||||
def test_elastic(pu239):
|
||||
elastic = pu239.reactions[2]
|
||||
assert elastic.center_of_mass
|
||||
assert elastic.q_value == 0.0
|
||||
assert elastic.mt == 2
|
||||
assert '0K' in elastic.xs
|
||||
assert '294K' in elastic.xs
|
||||
assert len(elastic.products) == 1
|
||||
p = elastic.products[0]
|
||||
assert isinstance(p, openmc.data.Product)
|
||||
assert p.particle == 'neutron'
|
||||
assert p.emission_mode == 'prompt'
|
||||
assert len(p.distribution) == 1
|
||||
d = p.distribution[0]
|
||||
assert isinstance(d, openmc.data.UncorrelatedAngleEnergy)
|
||||
assert isinstance(d.angle, openmc.data.AngleDistribution)
|
||||
assert d.energy is None
|
||||
assert p.yield_(0.0) == 1.0
|
||||
|
||||
|
||||
def test_fission(pu239):
|
||||
fission = pu239.reactions[18]
|
||||
assert not fission.center_of_mass
|
||||
assert fission.q_value == pytest.approx(198902000.0)
|
||||
assert fission.mt == 18
|
||||
assert '294K' in fission.xs
|
||||
assert len(fission.products) == 8
|
||||
prompt = fission.products[0]
|
||||
assert prompt.particle == 'neutron'
|
||||
assert prompt.yield_(1.0e-5) == pytest.approx(2.874262)
|
||||
delayed = [p for p in fission.products if p.emission_mode == 'delayed']
|
||||
assert len(delayed) == 6
|
||||
assert all(d.particle == 'neutron' for d in delayed)
|
||||
assert sum(d.decay_rate for d in delayed) == pytest.approx(4.037212)
|
||||
assert sum(d.yield_(1.0) for d in delayed) == pytest.approx(0.00645)
|
||||
photon = fission.products[-1]
|
||||
assert photon.particle == 'photon'
|
||||
|
||||
|
||||
@needs_njoy
|
||||
def test_derived_products(am244):
|
||||
fission = am244.reactions[18]
|
||||
total_neutron = fission.derived_products[0]
|
||||
assert total_neutron.emission_mode == 'total'
|
||||
assert total_neutron.yield_(6e6) == pytest.approx(4.2558)
|
||||
|
||||
|
||||
def test_kerma(run_in_tmpdir, am244, h2):
|
||||
# Make sure kerma w/ local photon is >= regular kerma
|
||||
for nuc in (am244, h2):
|
||||
assert 301 in nuc
|
||||
assert 901 in nuc
|
||||
for T in nuc.temperatures:
|
||||
k, k_local = nuc[301].xs[T], nuc[901].xs[T]
|
||||
assert np.all(k.x == k_local.x)
|
||||
assert np.all(k_local.y >= k.y)
|
||||
|
||||
# Make sure 301/901 get exported/imported correctly
|
||||
h2.export_to_hdf5("H2.h5")
|
||||
read_in = openmc.data.IncidentNeutron.from_hdf5("H2.h5")
|
||||
assert 301 in read_in
|
||||
assert 901 in read_in
|
||||
assert np.all(read_in[901].xs['300K'].y == h2[901].xs['300K'].y)
|
||||
|
||||
|
||||
def test_urr(pu239):
|
||||
for T, ptable in pu239.urr.items():
|
||||
assert T.endswith('K')
|
||||
assert isinstance(ptable, openmc.data.ProbabilityTables)
|
||||
ptable = pu239.urr['294K']
|
||||
assert ptable.absorption_flag == -1
|
||||
assert ptable.energy[0] == pytest.approx(2500.001)
|
||||
assert ptable.energy[-1] == pytest.approx(29999.99)
|
||||
assert ptable.inelastic_flag == 51
|
||||
assert ptable.interpolation == 2
|
||||
assert not ptable.multiply_smooth
|
||||
assert ptable.table.shape == (70, 6, 20)
|
||||
assert ptable.table.shape[0] == ptable.energy.size
|
||||
|
||||
|
||||
@needs_njoy
|
||||
def test_get_reaction_components(h2):
|
||||
assert h2.get_reaction_components(1) == [2, 16, 102]
|
||||
assert h2.get_reaction_components(101) == [102]
|
||||
assert h2.get_reaction_components(16) == [16]
|
||||
assert h2.get_reaction_components(51) == []
|
||||
|
||||
|
||||
def test_export_to_hdf5(tmpdir, pu239, gd154):
|
||||
filename = str(tmpdir.join('pu239.h5'))
|
||||
pu239.export_to_hdf5(filename)
|
||||
assert os.path.exists(filename)
|
||||
with pytest.raises(NotImplementedError):
|
||||
gd154.export_to_hdf5('gd154.h5')
|
||||
|
||||
|
||||
def test_slbw(xe135):
|
||||
res = xe135.resonances
|
||||
assert isinstance(res, openmc.data.Resonances)
|
||||
assert len(res.ranges) == 2
|
||||
resolved = res.resolved
|
||||
assert isinstance(resolved, openmc.data.SingleLevelBreitWigner)
|
||||
assert resolved.energy_min == pytest.approx(1e-5)
|
||||
assert resolved.energy_max == pytest.approx(190.)
|
||||
assert resolved.target_spin == pytest.approx(1.5)
|
||||
assert isinstance(resolved.parameters, pd.DataFrame)
|
||||
s = resolved.parameters.iloc[0]
|
||||
assert s['energy'] == pytest.approx(0.084)
|
||||
|
||||
xs = resolved.reconstruct([10., 30., 100.])
|
||||
assert sorted(xs.keys()) == [2, 18, 102]
|
||||
assert np.all(xs[18] == 0.0)
|
||||
|
||||
|
||||
def test_mlbw(sm150):
|
||||
resolved = sm150.resonances.resolved
|
||||
assert isinstance(resolved, openmc.data.MultiLevelBreitWigner)
|
||||
assert resolved.energy_min == pytest.approx(1e-5)
|
||||
assert resolved.energy_max == pytest.approx(1570.)
|
||||
assert resolved.target_spin == 0.0
|
||||
|
||||
xs = resolved.reconstruct([10., 100., 1000.])
|
||||
assert sorted(xs.keys()) == [2, 18, 102]
|
||||
assert np.all(xs[18] == 0.0)
|
||||
|
||||
|
||||
def test_reichmoore(gd154):
|
||||
res = gd154.resonances
|
||||
assert isinstance(res, openmc.data.Resonances)
|
||||
assert len(res.ranges) == 2
|
||||
resolved, unresolved = res.ranges
|
||||
assert resolved is res.resolved
|
||||
assert unresolved is res.unresolved
|
||||
assert isinstance(resolved, openmc.data.ReichMoore)
|
||||
assert isinstance(unresolved, openmc.data.Unresolved)
|
||||
assert resolved.energy_min == pytest.approx(1e-5)
|
||||
assert resolved.energy_max == pytest.approx(2760.)
|
||||
assert resolved.target_spin == 0.0
|
||||
assert resolved.channel_radius[0](1.0) == pytest.approx(0.74)
|
||||
assert isinstance(resolved.parameters, pd.DataFrame)
|
||||
assert (resolved.parameters['L'] == 0).all()
|
||||
assert (resolved.parameters['J'] <= 0.5).all()
|
||||
assert (resolved.parameters['fissionWidthA'] == 0.0).all()
|
||||
|
||||
elastic = gd154.reactions[2].xs['0K']
|
||||
assert isinstance(elastic, openmc.data.ResonancesWithBackground)
|
||||
assert elastic(0.0253) == pytest.approx(5.7228949796394524)
|
||||
|
||||
|
||||
def test_rml(cl35):
|
||||
resolved = cl35.resonances.resolved
|
||||
assert isinstance(resolved, openmc.data.RMatrixLimited)
|
||||
assert resolved.energy_min == pytest.approx(1e-5)
|
||||
assert resolved.energy_max == pytest.approx(1.2e6)
|
||||
assert resolved.target_spin == 0.0
|
||||
for group in resolved.spin_groups:
|
||||
assert isinstance(group, openmc.data.SpinGroup)
|
||||
|
||||
|
||||
def test_mlbw_cov_lcomp0(cf252):
|
||||
# Testing on first range only
|
||||
cov = cf252.resonance_covariance.ranges[0]
|
||||
res = cf252.resonances.ranges[0]
|
||||
assert cov.parameters['energy'][0] == pytest.approx(-3.5)
|
||||
assert res.parameters['energy'][0] == cov.parameters['energy'][0]
|
||||
assert isinstance(cov, openmc.data.resonance_covariance.MultiLevelBreitWignerCovariance)
|
||||
assert cov.energy_min == pytest.approx(1e-5)
|
||||
assert cov.energy_max == pytest.approx(1000.)
|
||||
assert cov.covariance[0,0] == pytest.approx(1.225e-05)
|
||||
|
||||
subset = cov.subset('energy', [0, 100])
|
||||
assert not subset.parameters.empty
|
||||
assert (subset.file2res.parameters['energy'] < 100).all()
|
||||
samples = cov.sample(1)
|
||||
xs = samples[0].reconstruct([10., 100., 1000.])
|
||||
assert sorted(xs.keys()) == [2, 18, 102]
|
||||
|
||||
|
||||
def test_mlbw_cov_lcomp1(ti50):
|
||||
# Testing on first range only
|
||||
cov = ti50.resonance_covariance.ranges[0]
|
||||
res = ti50.resonances.ranges[0]
|
||||
assert cov.parameters['energy'][0] == pytest.approx(-21020.)
|
||||
assert res.parameters['energy'][0] == cov.parameters['energy'][0]
|
||||
assert isinstance(cov, openmc.data.resonance_covariance.MultiLevelBreitWignerCovariance)
|
||||
assert cov.energy_min == pytest.approx(1e-5)
|
||||
assert cov.energy_max == pytest.approx(587000.)
|
||||
assert cov.covariance[0,0] == pytest.approx(1.410177e5)
|
||||
|
||||
subset = cov.subset('L', [1, 1])
|
||||
assert not subset.parameters.empty
|
||||
assert (subset.file2res.parameters['L'] == 1).all()
|
||||
samples = cov.sample(1)
|
||||
xs = samples[0].reconstruct([10., 100., 1000.])
|
||||
assert sorted(xs.keys()) == [2, 18, 102]
|
||||
|
||||
|
||||
def test_mlbw_cov_lcomp2(na23):
|
||||
# Testing on first range only
|
||||
cov = na23.resonance_covariance.ranges[0]
|
||||
res = na23.resonances.ranges[0]
|
||||
assert cov.parameters['energy'][0] == pytest.approx(2810.)
|
||||
assert res.parameters['energy'][0] == cov.parameters['energy'][0]
|
||||
assert isinstance(cov, openmc.data.resonance_covariance.MultiLevelBreitWignerCovariance)
|
||||
assert cov.energy_min == pytest.approx(600)
|
||||
assert cov.energy_max == pytest.approx(500000.)
|
||||
assert cov.covariance[0,0] == pytest.approx(16.1064163584)
|
||||
|
||||
subset = cov.subset('L', [1, 1])
|
||||
assert not subset.parameters.empty
|
||||
assert (subset.file2res.parameters['L'] == 1).all()
|
||||
samples = cov.sample(1)
|
||||
xs = samples[0].reconstruct([10., 100., 1000.])
|
||||
assert sorted(xs.keys()) == [2, 18, 102]
|
||||
|
||||
|
||||
def test_rmcov_lcomp1(gd154):
|
||||
# Testing on first range only
|
||||
cov = gd154.resonance_covariance.ranges[0]
|
||||
res = gd154.resonances.ranges[0]
|
||||
assert cov.parameters['energy'][0] == pytest.approx(-2.200001)
|
||||
assert res.parameters['energy'][0] == cov.parameters['energy'][0]
|
||||
assert isinstance(cov, openmc.data.resonance_covariance.ReichMooreCovariance)
|
||||
assert cov.energy_min == pytest.approx(1e-5)
|
||||
assert cov.energy_max == pytest.approx(2760.)
|
||||
assert cov.covariance[0,0] == pytest.approx(0.8895997)
|
||||
|
||||
subset = cov.subset('energy', [0, 100])
|
||||
assert not subset.parameters.empty
|
||||
assert (subset.file2res.parameters['energy'] < 100).all()
|
||||
samples = cov.sample(1)
|
||||
xs = samples[0].reconstruct([10., 100., 1000.])
|
||||
assert sorted(xs.keys()) == [2, 18, 102]
|
||||
|
||||
|
||||
def test_rmcov_lcomp2(th232):
|
||||
# Testing on first range only
|
||||
cov = th232.resonance_covariance.ranges[0]
|
||||
res = th232.resonances.ranges[0]
|
||||
assert cov.parameters['energy'][0] == pytest.approx(-2000)
|
||||
assert res.parameters['energy'][0] == cov.parameters['energy'][0]
|
||||
assert isinstance(cov, openmc.data.resonance_covariance.ReichMooreCovariance)
|
||||
assert cov.energy_min == pytest.approx(1e-5)
|
||||
assert cov.energy_max == pytest.approx(4000.)
|
||||
assert cov.covariance[0,0] == pytest.approx(246.6043092496)
|
||||
|
||||
subset = cov.subset('energy', [0, 100])
|
||||
assert not subset.parameters.empty
|
||||
assert (subset.file2res.parameters['energy'] < 100).all()
|
||||
samples = cov.sample(1)
|
||||
xs = samples[0].reconstruct([10., 100., 1000.])
|
||||
assert sorted(xs.keys()) == [2, 18, 102]
|
||||
|
||||
|
||||
def test_madland_nix(am241):
|
||||
fission = am241.reactions[18]
|
||||
prompt_neutron = fission.products[0]
|
||||
dist = prompt_neutron.distribution[0].energy
|
||||
assert isinstance(dist, openmc.data.MadlandNix)
|
||||
assert dist.efl == pytest.approx(1029979.0)
|
||||
assert dist.efh == pytest.approx(546729.7)
|
||||
assert isinstance(dist.tm, Callable)
|
||||
|
||||
|
||||
def test_watt(u233):
|
||||
fission = u233.reactions[18]
|
||||
prompt_neutron = fission.products[0]
|
||||
dist = prompt_neutron.distribution[0].energy
|
||||
assert isinstance(dist, openmc.data.WattEnergy)
|
||||
|
||||
|
||||
def test_maxwell(u236):
|
||||
fission = u236.reactions[18]
|
||||
prompt_neutron = fission.products[0]
|
||||
dist = prompt_neutron.distribution[0].energy
|
||||
assert isinstance(dist, openmc.data.MaxwellEnergy)
|
||||
|
||||
|
||||
def test_evaporation(na22):
|
||||
n2n = na22.reactions[16]
|
||||
dist = n2n.products[0].distribution[0].energy
|
||||
assert isinstance(dist, openmc.data.Evaporation)
|
||||
|
||||
|
||||
def test_laboratory(be9):
|
||||
n2n = be9.reactions[16]
|
||||
dist = n2n.products[0].distribution[0]
|
||||
assert isinstance(dist, openmc.data.LaboratoryAngleEnergy)
|
||||
assert list(dist.breakpoints) == [18]
|
||||
assert list(dist.interpolation) == [2]
|
||||
assert dist.energy[0] == pytest.approx(1748830.)
|
||||
assert dist.energy[-1] == pytest.approx(20.e6)
|
||||
assert len(dist.energy) == len(dist.energy_out) == len(dist.mu)
|
||||
for eout, mu in zip(dist.energy_out, dist.mu):
|
||||
assert len(eout) == len(mu)
|
||||
assert np.all((-1. <= mu.x) & (mu.x <= 1.))
|
||||
|
||||
|
||||
@needs_njoy
|
||||
def test_correlated(tmpdir):
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
endf_file = os.path.join(endf_data, 'neutrons', 'n-014_Si_030.endf')
|
||||
si30 = openmc.data.IncidentNeutron.from_njoy(endf_file, heatr=False)
|
||||
|
||||
# Convert to HDF5 and read back
|
||||
filename = str(tmpdir.join('si30.h5'))
|
||||
si30.export_to_hdf5(filename)
|
||||
si30_copy = openmc.data.IncidentNeutron.from_hdf5(filename)
|
||||
|
||||
|
||||
@needs_njoy
|
||||
def test_nbody(tmpdir, h2):
|
||||
# Convert to HDF5 and read back
|
||||
filename = str(tmpdir.join('h2.h5'))
|
||||
h2.export_to_hdf5(filename)
|
||||
h2_copy = openmc.data.IncidentNeutron.from_hdf5(filename)
|
||||
|
||||
# Compare distributions
|
||||
nbody1 = h2[16].products[0].distribution[0]
|
||||
nbody2 = h2_copy[16].products[0].distribution[0]
|
||||
assert nbody1.total_mass == nbody2.total_mass
|
||||
assert nbody1.n_particles == nbody2.n_particles
|
||||
assert nbody1.q_value == nbody2.q_value
|
||||
|
||||
|
||||
@needs_njoy
|
||||
def test_ace_convert(run_in_tmpdir):
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'neutrons', 'n-001_H_001.endf')
|
||||
ace_ascii = 'ace_ascii'
|
||||
ace_binary = 'ace_binary'
|
||||
openmc.data.njoy.make_ace(filename, acer=ace_ascii)
|
||||
|
||||
# Convert to binary
|
||||
openmc.data.ace.ascii_to_binary(ace_ascii, ace_binary)
|
||||
|
||||
# Make sure conversion worked
|
||||
lib_ascii = openmc.data.ace.Library(ace_ascii)
|
||||
lib_binary = openmc.data.ace.Library(ace_binary)
|
||||
for tab_a, tab_b in zip(lib_ascii.tables, lib_binary.tables):
|
||||
assert tab_a.name == tab_b.name
|
||||
assert tab_a.atomic_weight_ratio == pytest.approx(tab_b.atomic_weight_ratio)
|
||||
assert tab_a.temperature == pytest.approx(tab_b.temperature)
|
||||
assert np.all(tab_a.nxs == tab_b.nxs)
|
||||
assert np.all(tab_a.jxs == tab_b.jxs)
|
||||
146
tests/unit_tests/test_data_photon.py
Normal file
146
tests/unit_tests/test_data_photon.py
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from collections.abc import Mapping, Callable
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import pytest
|
||||
import openmc.data
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def elements_endf():
|
||||
"""Dictionary of element ENDF data indexed by atomic symbol."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
elements = {'H': 1, 'O': 8, 'Al': 13, 'Cu': 29, 'Ag': 47, 'U': 92, 'Pu': 94}
|
||||
data = {}
|
||||
for symbol, Z in elements.items():
|
||||
p_file = 'photoat-{:03}_{}_000.endf'.format(Z, symbol)
|
||||
p_path = os.path.join(endf_data, 'photoat', p_file)
|
||||
a_file = 'atom-{:03}_{}_000.endf'.format(Z, symbol)
|
||||
a_path = os.path.join(endf_data, 'atomic_relax', a_file)
|
||||
data[symbol] = openmc.data.IncidentPhoton.from_endf(p_path, a_path)
|
||||
return data
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def element(request, elements_endf):
|
||||
"""Element ENDF data"""
|
||||
return elements_endf[request.param]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'element, atomic_number', [
|
||||
('Al', 13),
|
||||
('Cu', 29),
|
||||
('Pu', 94)
|
||||
],
|
||||
indirect=['element']
|
||||
)
|
||||
def test_attributes(element, atomic_number):
|
||||
assert element.atomic_number == atomic_number
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'element, subshell, binding_energy, num_electrons', [
|
||||
('H', 'K', 13.61, 1.0),
|
||||
('O', 'L3', 14.15, 2.67),
|
||||
('U', 'P2', 34.09, 2.0)
|
||||
],
|
||||
indirect=['element']
|
||||
)
|
||||
def test_atomic_relaxation(element, subshell, binding_energy, num_electrons):
|
||||
atom_relax = element.atomic_relaxation
|
||||
assert isinstance(atom_relax, openmc.data.photon.AtomicRelaxation)
|
||||
assert subshell in atom_relax.subshells
|
||||
assert atom_relax.binding_energy[subshell] == binding_energy
|
||||
assert atom_relax.num_electrons[subshell] == num_electrons
|
||||
|
||||
|
||||
@pytest.mark.parametrize('element', ['Al', 'Cu', 'Pu'], indirect=True)
|
||||
def test_transitions(element):
|
||||
transitions = element.atomic_relaxation.transitions
|
||||
assert transitions
|
||||
assert isinstance(transitions, Mapping)
|
||||
for matrix in transitions.values():
|
||||
assert isinstance(matrix, pd.core.frame.DataFrame)
|
||||
assert len(matrix.columns) == 4
|
||||
assert sum(matrix['probability']) == pytest.approx(1.0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'element, I, i_shell, ionization_energy, num_electrons', [
|
||||
('H', 19.2, 0, 13.6, 1),
|
||||
('O', 95.0, 2, 13.62, 4),
|
||||
('U', 890.0, 25, 6.033, -3)
|
||||
],
|
||||
indirect=['element']
|
||||
)
|
||||
def test_bremsstrahlung(element, I, i_shell, ionization_energy, num_electrons):
|
||||
brems = element.bremsstrahlung
|
||||
assert isinstance(brems, Mapping)
|
||||
assert brems['I'] == I
|
||||
assert brems['num_electrons'][i_shell] == num_electrons
|
||||
assert brems['ionization_energy'][i_shell] == ionization_energy
|
||||
assert np.all(np.diff(brems['electron_energy']) > 0.0)
|
||||
assert np.all(np.diff(brems['photon_energy']) > 0.0)
|
||||
assert brems['photon_energy'][0] == 0.0
|
||||
assert brems['photon_energy'][-1] == 1.0
|
||||
assert brems['dcs'].shape == (200, 30)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'element, n_shell', [
|
||||
('H', 1),
|
||||
('O', 3),
|
||||
('Al', 5)
|
||||
],
|
||||
indirect=['element']
|
||||
)
|
||||
def test_compton_profiles(element, n_shell):
|
||||
profile = element.compton_profiles
|
||||
assert profile
|
||||
assert isinstance(profile, Mapping)
|
||||
assert all(isinstance(x, Callable) for x in profile['J'])
|
||||
assert all(len(x) == n_shell for x in profile.values())
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'element, reaction', [
|
||||
('Cu', 541),
|
||||
('Ag', 502),
|
||||
('Pu', 504)
|
||||
],
|
||||
indirect=['element']
|
||||
)
|
||||
def test_reactions(element, reaction):
|
||||
reactions = element.reactions
|
||||
assert all(isinstance(x, openmc.data.PhotonReaction) for x in reactions.values())
|
||||
assert reaction in reactions
|
||||
with pytest.raises(KeyError):
|
||||
reactions[18]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('element', ['Pu'], indirect=True)
|
||||
def test_export_to_hdf5(tmpdir, element):
|
||||
filename = str(tmpdir.join('tmp.h5'))
|
||||
element.export_to_hdf5(filename)
|
||||
assert os.path.exists(filename)
|
||||
# Read in data from hdf5
|
||||
element2 = openmc.data.IncidentPhoton.from_hdf5(filename)
|
||||
# Check for some cross section and datasets of element and element2
|
||||
energy = np.logspace(np.log10(1.0), np.log10(1.0e10), num=100)
|
||||
for mt in (502, 504, 515, 517, 522, 541, 570):
|
||||
xs = element[mt].xs(energy)
|
||||
xs2 = element2[mt].xs(energy)
|
||||
assert np.allclose(xs, xs2)
|
||||
assert element[502].scattering_factor == element2[502].scattering_factor
|
||||
assert element.atomic_relaxation.transitions['O3'].equals(
|
||||
element2.atomic_relaxation.transitions['O3'])
|
||||
assert (element.compton_profiles['binding_energy'] ==
|
||||
element2.compton_profiles['binding_energy']).all()
|
||||
assert (element.bremsstrahlung['electron_energy'] ==
|
||||
element2.bremsstrahlung['electron_energy']).all()
|
||||
# Export to hdf5 again
|
||||
element2.export_to_hdf5(filename, 'w')
|
||||
264
tests/unit_tests/test_data_thermal.py
Normal file
264
tests/unit_tests/test_data_thermal.py
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
from collections.abc import Callable
|
||||
from math import exp
|
||||
import os
|
||||
import random
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
import openmc.data
|
||||
|
||||
from . import needs_njoy
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def h2o():
|
||||
"""H in H2O thermal scattering data."""
|
||||
directory = os.path.dirname(os.environ['OPENMC_CROSS_SECTIONS'])
|
||||
filename = os.path.join(directory, 'c_H_in_H2O.h5')
|
||||
return openmc.data.ThermalScattering.from_hdf5(filename)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def graphite():
|
||||
"""Graphite thermal scattering data."""
|
||||
directory = os.path.dirname(os.environ['OPENMC_CROSS_SECTIONS'])
|
||||
filename = os.path.join(directory, 'c_Graphite.h5')
|
||||
return openmc.data.ThermalScattering.from_hdf5(filename)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def h2o_njoy():
|
||||
"""H in H2O generated using NJOY."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
path_h1 = os.path.join(endf_data, 'neutrons', 'n-001_H_001.endf')
|
||||
path_h2o = os.path.join(endf_data, 'thermal_scatt', 'tsl-HinH2O.endf')
|
||||
return openmc.data.ThermalScattering.from_njoy(
|
||||
path_h1, path_h2o, temperatures=[293.6, 500.0])
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def hzrh():
|
||||
"""H in ZrH thermal scattering data."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'thermal_scatt', 'tsl-HinZrH.endf')
|
||||
return openmc.data.ThermalScattering.from_endf(filename)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def hzrh_njoy():
|
||||
"""H in ZrH generated using NJOY."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
path_h1 = os.path.join(endf_data, 'neutrons', 'n-001_H_001.endf')
|
||||
path_hzrh = os.path.join(endf_data, 'thermal_scatt', 'tsl-HinZrH.endf')
|
||||
with_endf_data = openmc.data.ThermalScattering.from_njoy(
|
||||
path_h1, path_hzrh, temperatures=[296.0], iwt=0
|
||||
)
|
||||
without_endf_data = openmc.data.ThermalScattering.from_njoy(
|
||||
path_h1, path_hzrh, temperatures=[296.0], use_endf_data=False, iwt=1
|
||||
)
|
||||
return with_endf_data, without_endf_data
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def sio2():
|
||||
"""SiO2 thermal scattering data."""
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'thermal_scatt', 'tsl-SiO2.endf')
|
||||
return openmc.data.ThermalScattering.from_endf(filename)
|
||||
|
||||
|
||||
def test_h2o_attributes(h2o):
|
||||
assert h2o.name == 'c_H_in_H2O'
|
||||
assert h2o.nuclides == ['H1']
|
||||
assert h2o.temperatures == ['294K']
|
||||
assert h2o.atomic_weight_ratio == pytest.approx(0.999167)
|
||||
assert h2o.energy_max == pytest.approx(4.46)
|
||||
assert isinstance(repr(h2o), str)
|
||||
|
||||
|
||||
def test_h2o_xs(h2o):
|
||||
assert not h2o.elastic
|
||||
for temperature, func in h2o.inelastic.xs.items():
|
||||
assert temperature.endswith('K')
|
||||
assert isinstance(func, Callable)
|
||||
|
||||
|
||||
def test_graphite_attributes(graphite):
|
||||
assert graphite.name == 'c_Graphite'
|
||||
assert graphite.nuclides == ['C0', 'C12', 'C13']
|
||||
assert graphite.temperatures == ['296K']
|
||||
assert graphite.atomic_weight_ratio == pytest.approx(11.898)
|
||||
assert graphite.energy_max == pytest.approx(4.46)
|
||||
|
||||
|
||||
def test_graphite_xs(graphite):
|
||||
for temperature, func in graphite.elastic.xs.items():
|
||||
assert temperature.endswith('K')
|
||||
assert isinstance(func, openmc.data.CoherentElastic)
|
||||
for temperature, func in graphite.inelastic.xs.items():
|
||||
assert temperature.endswith('K')
|
||||
assert isinstance(func, Callable)
|
||||
elastic = graphite.elastic.xs['296K']
|
||||
assert elastic([1e-3, 1.0]) == pytest.approx([0.0, 0.62586153])
|
||||
|
||||
@needs_njoy
|
||||
def test_graphite_njoy():
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
path_c0 = os.path.join(endf_data, 'neutrons', 'n-006_C_000.endf')
|
||||
path_gr = os.path.join(endf_data, 'thermal_scatt', 'tsl-graphite.endf')
|
||||
graphite = openmc.data.ThermalScattering.from_njoy(
|
||||
path_c0, path_gr, temperatures=[296.0])
|
||||
assert graphite.nuclides == ['C0', 'C12', 'C13']
|
||||
assert graphite.atomic_weight_ratio == pytest.approx(11.898)
|
||||
assert graphite.energy_max == pytest.approx(2.02)
|
||||
assert graphite.temperatures == ['296K']
|
||||
|
||||
|
||||
@needs_njoy
|
||||
def test_export_to_hdf5(tmpdir, h2o_njoy, hzrh_njoy, graphite):
|
||||
filename = str(tmpdir.join('water.h5'))
|
||||
h2o_njoy.export_to_hdf5(filename)
|
||||
assert os.path.exists(filename)
|
||||
|
||||
# Graphite covers export of coherent elastic data
|
||||
filename = str(tmpdir.join('graphite.h5'))
|
||||
graphite.export_to_hdf5(filename)
|
||||
assert os.path.exists(filename)
|
||||
|
||||
# H in ZrH covers export of incoherent elastic data, and incoherent
|
||||
# inelastic angle-energy distributions
|
||||
filename = str(tmpdir.join('hzrh.h5'))
|
||||
hzrh_njoy[0].export_to_hdf5(filename)
|
||||
assert os.path.exists(filename)
|
||||
hzrh_njoy[1].export_to_hdf5(filename, 'w')
|
||||
assert os.path.exists(filename)
|
||||
|
||||
|
||||
@needs_njoy
|
||||
def test_continuous_dist(h2o_njoy):
|
||||
for temperature, dist in h2o_njoy.inelastic.distribution.items():
|
||||
assert temperature.endswith('K')
|
||||
assert isinstance(dist, openmc.data.IncoherentInelasticAE)
|
||||
|
||||
|
||||
def test_h2o_endf():
|
||||
endf_data = os.environ['OPENMC_ENDF_DATA']
|
||||
filename = os.path.join(endf_data, 'thermal_scatt', 'tsl-HinH2O.endf')
|
||||
h2o = openmc.data.ThermalScattering.from_endf(filename)
|
||||
assert not h2o.elastic
|
||||
assert h2o.atomic_weight_ratio == pytest.approx(0.99917)
|
||||
assert h2o.energy_max == pytest.approx(3.99993)
|
||||
assert h2o.temperatures == ['294K', '350K', '400K', '450K', '500K', '550K',
|
||||
'600K', '650K', '800K']
|
||||
|
||||
|
||||
def test_hzrh_attributes(hzrh):
|
||||
assert hzrh.atomic_weight_ratio == pytest.approx(0.99917)
|
||||
assert hzrh.energy_max == pytest.approx(1.9734)
|
||||
assert hzrh.temperatures == ['296K', '400K', '500K', '600K', '700K', '800K',
|
||||
'1000K', '1200K']
|
||||
|
||||
|
||||
def test_hzrh_elastic(hzrh):
|
||||
rx = hzrh.elastic
|
||||
for temperature, func in rx.xs.items():
|
||||
assert temperature.endswith('K')
|
||||
assert isinstance(func, openmc.data.IncoherentElastic)
|
||||
|
||||
xs = rx.xs['296K']
|
||||
sig_b, W = xs.bound_xs, xs.debye_waller
|
||||
assert sig_b == pytest.approx(81.98006)
|
||||
assert W == pytest.approx(8.486993)
|
||||
for i in range(10):
|
||||
E = random.uniform(0.0, hzrh.energy_max)
|
||||
assert xs(E) == pytest.approx(sig_b/2 * ((1 - exp(-4*E*W))/(2*E*W)))
|
||||
|
||||
for temperature, dist in rx.distribution.items():
|
||||
assert temperature.endswith('K')
|
||||
assert dist.debye_waller > 0.0
|
||||
|
||||
|
||||
@needs_njoy
|
||||
def test_hzrh_njoy(hzrh_njoy):
|
||||
endf, ace = hzrh_njoy
|
||||
|
||||
# First check version using ENDF incoherent elastic data
|
||||
assert endf.atomic_weight_ratio == pytest.approx(0.999167)
|
||||
assert endf.energy_max == pytest.approx(1.855)
|
||||
assert endf.temperatures == ['296K']
|
||||
|
||||
# Now check version using ACE incoherent elastic data (discretized)
|
||||
assert ace.atomic_weight_ratio == endf.atomic_weight_ratio
|
||||
assert ace.energy_max == endf.energy_max
|
||||
|
||||
# Cross sections should be about the same (within 1%)
|
||||
E = np.linspace(1e-5, endf.energy_max)
|
||||
xs1 = endf.elastic.xs['296K'](E)
|
||||
xs2 = ace.elastic.xs['296K'](E)
|
||||
assert xs1 == pytest.approx(xs2, rel=0.01)
|
||||
|
||||
# Check discrete incoherent elastic distribution
|
||||
d = ace.elastic.distribution['296K']
|
||||
assert np.all((-1.0 <= d.mu_out) & (d.mu_out <= 1.0))
|
||||
|
||||
# Check discrete incoherent inelastic distribution
|
||||
d = endf.inelastic.distribution['296K']
|
||||
assert d.skewed
|
||||
assert np.all((-1.0 <= d.mu_out) & (d.mu_out <= 1.0))
|
||||
assert np.all((0.0 <= d.energy_out) & (d.energy_out < 3*endf.energy_max))
|
||||
|
||||
|
||||
def test_sio2_attributes(sio2):
|
||||
assert sio2.atomic_weight_ratio == pytest.approx(27.84423)
|
||||
assert sio2.energy_max == pytest.approx(2.46675)
|
||||
assert sio2.temperatures == ['294K', '350K', '400K', '500K', '800K',
|
||||
'1000K', '1200K']
|
||||
|
||||
|
||||
def test_sio2_elastic(sio2):
|
||||
rx = sio2.elastic
|
||||
for temperature, func in rx.xs.items():
|
||||
assert temperature.endswith('K')
|
||||
assert isinstance(func, openmc.data.CoherentElastic)
|
||||
xs = rx.xs['294K']
|
||||
assert len(xs) == 317
|
||||
assert xs.bragg_edges[0] == pytest.approx(0.000711634)
|
||||
assert xs.factors[0] == pytest.approx(2.6958e-14)
|
||||
|
||||
# Below first bragg edge, cross section should be zero
|
||||
E = xs.bragg_edges[0] / 2.0
|
||||
assert xs(E) == 0.0
|
||||
|
||||
# Between bragg edges, cross section is P/E where P is the factor
|
||||
E = (xs.bragg_edges[0] + xs.bragg_edges[1]) / 2.0
|
||||
P = xs.factors[0]
|
||||
assert xs(E) == pytest.approx(P / E)
|
||||
|
||||
# Check the last Bragg edge
|
||||
E = 1.1 * xs.bragg_edges[-1]
|
||||
P = xs.factors[-1]
|
||||
assert xs(E) == pytest.approx(P / E)
|
||||
|
||||
for temperature, dist in rx.distribution.items():
|
||||
assert temperature.endswith('K')
|
||||
assert dist.coherent_xs is rx.xs[temperature]
|
||||
|
||||
|
||||
def test_get_thermal_name():
|
||||
f = openmc.data.get_thermal_name
|
||||
# Names which are recognized
|
||||
assert f('lwtr') == 'c_H_in_H2O'
|
||||
assert f('hh2o') == 'c_H_in_H2O'
|
||||
|
||||
with pytest.warns(UserWarning, match='is not recognized'):
|
||||
# Names which can be guessed
|
||||
assert f('lw00') == 'c_H_in_H2O'
|
||||
assert f('graphite') == 'c_Graphite'
|
||||
assert f('D_in_D2O') == 'c_D_in_D2O'
|
||||
|
||||
# Not in values, but very close
|
||||
assert f('hluci') == 'c_H_in_C5O2H8'
|
||||
assert f('ortho_d') == 'c_ortho_D'
|
||||
|
||||
# Names that don't remotely match anything
|
||||
assert f('boogie_monster') == 'c_boogie_monster'
|
||||
147
tests/unit_tests/test_deplete_atom_number.py
Normal file
147
tests/unit_tests/test_deplete_atom_number.py
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
""" Tests for the AtomNumber class """
|
||||
|
||||
import numpy as np
|
||||
from openmc.deplete import atom_number
|
||||
|
||||
|
||||
def test_indexing():
|
||||
"""Tests the __getitem__ and __setitem__ routines simultaneously."""
|
||||
|
||||
local_mats = ["10000", "10001"]
|
||||
nuclides = ["U238", "U235", "U234"]
|
||||
volume = {"10000" : 0.38, "10001" : 0.21}
|
||||
|
||||
number = atom_number.AtomNumber(local_mats, nuclides, volume, 2)
|
||||
|
||||
number["10000", "U238"] = 1.0
|
||||
number["10001", "U238"] = 2.0
|
||||
number["10000", "U235"] = 3.0
|
||||
number["10001", "U235"] = 4.0
|
||||
|
||||
# String indexing
|
||||
assert number["10000", "U238"] == 1.0
|
||||
assert number["10001", "U238"] == 2.0
|
||||
assert number["10000", "U235"] == 3.0
|
||||
assert number["10001", "U235"] == 4.0
|
||||
|
||||
# Int indexing
|
||||
assert number[0, 0] == 1.0
|
||||
assert number[1, 0] == 2.0
|
||||
assert number[0, 1] == 3.0
|
||||
assert number[1, 1] == 4.0
|
||||
|
||||
number[0, 0] = 5.0
|
||||
|
||||
assert number[0, 0] == 5.0
|
||||
assert number["10000", "U238"] == 5.0
|
||||
|
||||
|
||||
def test_properties():
|
||||
"""Test properties. """
|
||||
local_mats = ["10000", "10001"]
|
||||
nuclides = ["U238", "U235", "Gd157"]
|
||||
volume = {"10000" : 0.38, "10001" : 0.21}
|
||||
|
||||
number = atom_number.AtomNumber(local_mats, nuclides, volume, 2)
|
||||
|
||||
assert list(number.materials) == ["10000", "10001"]
|
||||
assert number.n_nuc == 3
|
||||
assert list(number.nuclides) == ["U238", "U235", "Gd157"]
|
||||
assert number.burnable_nuclides == ["U238", "U235"]
|
||||
|
||||
|
||||
def test_density_indexing():
|
||||
"""Tests the get and set_atom_density routines simultaneously."""
|
||||
|
||||
local_mats = ["10000", "10001", "10002"]
|
||||
nuclides = ["U238", "U235", "U234"]
|
||||
volume = {"10000" : 0.38, "10001" : 0.21}
|
||||
|
||||
number = atom_number.AtomNumber(local_mats, nuclides, volume, 2)
|
||||
|
||||
number.set_atom_density("10000", "U238", 1.0)
|
||||
number.set_atom_density("10001", "U238", 2.0)
|
||||
number.set_atom_density("10002", "U238", 3.0)
|
||||
number.set_atom_density("10000", "U235", 4.0)
|
||||
number.set_atom_density("10001", "U235", 5.0)
|
||||
number.set_atom_density("10002", "U235", 6.0)
|
||||
number.set_atom_density("10000", "U234", 7.0)
|
||||
number.set_atom_density("10001", "U234", 8.0)
|
||||
number.set_atom_density("10002", "U234", 9.0)
|
||||
|
||||
# String indexing
|
||||
assert number.get_atom_density("10000", "U238") == 1.0
|
||||
assert number.get_atom_density("10001", "U238") == 2.0
|
||||
assert number.get_atom_density("10002", "U238") == 3.0
|
||||
assert number.get_atom_density("10000", "U235") == 4.0
|
||||
assert number.get_atom_density("10001", "U235") == 5.0
|
||||
assert number.get_atom_density("10002", "U235") == 6.0
|
||||
assert number.get_atom_density("10000", "U234") == 7.0
|
||||
assert number.get_atom_density("10001", "U234") == 8.0
|
||||
assert number.get_atom_density("10002", "U234") == 9.0
|
||||
|
||||
# Int indexing
|
||||
assert number.get_atom_density(0, 0) == 1.0
|
||||
assert number.get_atom_density(1, 0) == 2.0
|
||||
assert number.get_atom_density(2, 0) == 3.0
|
||||
assert number.get_atom_density(0, 1) == 4.0
|
||||
assert number.get_atom_density(1, 1) == 5.0
|
||||
assert number.get_atom_density(2, 1) == 6.0
|
||||
assert number.get_atom_density(0, 2) == 7.0
|
||||
assert number.get_atom_density(1, 2) == 8.0
|
||||
assert number.get_atom_density(2, 2) == 9.0
|
||||
|
||||
|
||||
number.set_atom_density(0, 0, 5.0)
|
||||
assert number.get_atom_density(0, 0) == 5.0
|
||||
|
||||
# Verify volume is used correctly
|
||||
assert number[0, 0] == 5.0 * 0.38
|
||||
assert number[1, 0] == 2.0 * 0.21
|
||||
assert number[2, 0] == 3.0 * 1.0
|
||||
assert number[0, 1] == 4.0 * 0.38
|
||||
assert number[1, 1] == 5.0 * 0.21
|
||||
assert number[2, 1] == 6.0 * 1.0
|
||||
assert number[0, 2] == 7.0 * 0.38
|
||||
assert number[1, 2] == 8.0 * 0.21
|
||||
assert number[2, 2] == 9.0 * 1.0
|
||||
|
||||
|
||||
def test_get_mat_slice():
|
||||
"""Tests getting slices."""
|
||||
|
||||
local_mats = ["10000", "10001", "10002"]
|
||||
nuclides = ["U238", "U235", "U234"]
|
||||
volume = {"10000" : 0.38, "10001" : 0.21}
|
||||
|
||||
number = atom_number.AtomNumber(local_mats, nuclides, volume, 2)
|
||||
|
||||
number.number = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]])
|
||||
|
||||
sl = number.get_mat_slice(0)
|
||||
|
||||
np.testing.assert_array_equal(sl, np.array([1.0, 2.0]))
|
||||
|
||||
sl = number.get_mat_slice("10000")
|
||||
|
||||
np.testing.assert_array_equal(sl, np.array([1.0, 2.0]))
|
||||
|
||||
|
||||
def test_set_mat_slice():
|
||||
"""Tests getting slices."""
|
||||
|
||||
local_mats = ["10000", "10001", "10002"]
|
||||
nuclides = ["U238", "U235", "U234"]
|
||||
volume = {"10000" : 0.38, "10001" : 0.21}
|
||||
|
||||
number = atom_number.AtomNumber(local_mats, nuclides, volume, 2)
|
||||
|
||||
number.set_mat_slice(0, [1.0, 2.0])
|
||||
|
||||
assert number[0, 0] == 1.0
|
||||
assert number[0, 1] == 2.0
|
||||
|
||||
number.set_mat_slice("10000", [3.0, 4.0])
|
||||
|
||||
assert number[0, 0] == 3.0
|
||||
assert number[0, 1] == 4.0
|
||||
459
tests/unit_tests/test_deplete_chain.py
Normal file
459
tests/unit_tests/test_deplete_chain.py
Normal file
|
|
@ -0,0 +1,459 @@
|
|||
"""Tests for openmc.deplete.Chain class."""
|
||||
|
||||
from collections.abc import Mapping
|
||||
import os
|
||||
from pathlib import Path
|
||||
from itertools import product
|
||||
|
||||
import numpy as np
|
||||
from openmc.data import zam, ATOMIC_SYMBOL
|
||||
from openmc.deplete import comm, Chain, reaction_rates, nuclide, cram
|
||||
import pytest
|
||||
|
||||
from tests import cdtemp
|
||||
|
||||
_TEST_CHAIN = """\
|
||||
<depletion_chain>
|
||||
<nuclide name="A" half_life="23652.0" decay_modes="2" decay_energy="0.0" reactions="1">
|
||||
<decay type="beta1" target="B" branching_ratio="0.6"/>
|
||||
<decay type="beta2" target="C" branching_ratio="0.4"/>
|
||||
<reaction type="(n,gamma)" Q="0.0" target="C"/>
|
||||
</nuclide>
|
||||
<nuclide name="B" half_life="32904.0" decay_modes="1" decay_energy="0.0" reactions="1">
|
||||
<decay type="beta" target="A" branching_ratio="1.0"/>
|
||||
<reaction type="(n,gamma)" Q="0.0" target="C"/>
|
||||
</nuclide>
|
||||
<nuclide name="C" reactions="3">
|
||||
<reaction type="fission" Q="200000000.0"/>
|
||||
<reaction type="(n,gamma)" Q="0.0" target="A" branching_ratio="0.7"/>
|
||||
<reaction type="(n,gamma)" Q="0.0" target="B" branching_ratio="0.3"/>
|
||||
<neutron_fission_yields>
|
||||
<energies>0.0253</energies>
|
||||
<fission_yields energy="0.0253">
|
||||
<products>A B</products>
|
||||
<data>0.0292737 0.002566345</data>
|
||||
</fission_yields>
|
||||
</neutron_fission_yields>
|
||||
</nuclide>
|
||||
</depletion_chain>
|
||||
"""
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def simple_chain():
|
||||
with cdtemp():
|
||||
with open('chain_test.xml', 'w') as fh:
|
||||
fh.write(_TEST_CHAIN)
|
||||
yield Chain.from_xml('chain_test.xml')
|
||||
|
||||
|
||||
def test_init():
|
||||
"""Test depletion chain initialization."""
|
||||
chain = Chain()
|
||||
|
||||
assert isinstance(chain.nuclides, list)
|
||||
assert isinstance(chain.nuclide_dict, Mapping)
|
||||
|
||||
|
||||
def test_len():
|
||||
"""Test depletion chain length."""
|
||||
chain = Chain()
|
||||
chain.nuclides = ["NucA", "NucB", "NucC"]
|
||||
|
||||
assert len(chain) == 3
|
||||
|
||||
|
||||
def test_from_endf():
|
||||
"""Test depletion chain building from ENDF files"""
|
||||
endf_data = Path(os.environ['OPENMC_ENDF_DATA'])
|
||||
decay_data = (endf_data / 'decay').glob('*.endf')
|
||||
fpy_data = (endf_data / 'nfy').glob('*.endf')
|
||||
neutron_data = (endf_data / 'neutrons').glob('*.endf')
|
||||
chain = Chain.from_endf(decay_data, fpy_data, neutron_data)
|
||||
|
||||
assert len(chain) == len(chain.nuclides) == len(chain.nuclide_dict) == 3820
|
||||
for nuc in chain.nuclides:
|
||||
assert nuc == chain[nuc.name]
|
||||
|
||||
|
||||
def test_from_xml(simple_chain):
|
||||
"""Read chain_test.xml and ensure all values are correct."""
|
||||
# Unfortunately, this routine touches a lot of the code, but most of
|
||||
# the components external to depletion_chain.py are simple storage
|
||||
# types.
|
||||
|
||||
chain = simple_chain
|
||||
|
||||
# Basic checks
|
||||
assert len(chain) == 3
|
||||
|
||||
# A tests
|
||||
nuc = chain["A"]
|
||||
|
||||
assert nuc.name == "A"
|
||||
assert nuc.half_life == 2.36520E+04
|
||||
assert nuc.n_decay_modes == 2
|
||||
modes = nuc.decay_modes
|
||||
assert [m.target for m in modes] == ["B", "C"]
|
||||
assert [m.type for m in modes] == ["beta1", "beta2"]
|
||||
assert [m.branching_ratio for m in modes] == [0.6, 0.4]
|
||||
assert nuc.n_reaction_paths == 1
|
||||
assert [r.target for r in nuc.reactions] == ["C"]
|
||||
assert [r.type for r in nuc.reactions] == ["(n,gamma)"]
|
||||
assert [r.branching_ratio for r in nuc.reactions] == [1.0]
|
||||
|
||||
# B tests
|
||||
nuc = chain["B"]
|
||||
|
||||
assert nuc.name == "B"
|
||||
assert nuc.half_life == 3.29040E+04
|
||||
assert nuc.n_decay_modes == 1
|
||||
modes = nuc.decay_modes
|
||||
assert [m.target for m in modes] == ["A"]
|
||||
assert [m.type for m in modes] == ["beta"]
|
||||
assert [m.branching_ratio for m in modes] == [1.0]
|
||||
assert nuc.n_reaction_paths == 1
|
||||
assert [r.target for r in nuc.reactions] == ["C"]
|
||||
assert [r.type for r in nuc.reactions] == ["(n,gamma)"]
|
||||
assert [r.branching_ratio for r in nuc.reactions] == [1.0]
|
||||
|
||||
# C tests
|
||||
nuc = chain["C"]
|
||||
|
||||
assert nuc.name == "C"
|
||||
assert nuc.n_decay_modes == 0
|
||||
assert nuc.n_reaction_paths == 3
|
||||
assert [r.target for r in nuc.reactions] == [None, "A", "B"]
|
||||
assert [r.type for r in nuc.reactions] == ["fission", "(n,gamma)", "(n,gamma)"]
|
||||
assert [r.branching_ratio for r in nuc.reactions] == [1.0, 0.7, 0.3]
|
||||
|
||||
# Yield tests
|
||||
assert nuc.yield_energies == (0.0253,)
|
||||
assert list(nuc.yield_data) == [0.0253]
|
||||
assert nuc.yield_data[0.0253].products == ("A", "B")
|
||||
assert (nuc.yield_data[0.0253].yields == [0.0292737, 0.002566345]).all()
|
||||
|
||||
|
||||
def test_export_to_xml(run_in_tmpdir):
|
||||
"""Test writing a depletion chain to XML."""
|
||||
|
||||
# Prevent different MPI ranks from conflicting
|
||||
filename = 'test{}.xml'.format(comm.rank)
|
||||
|
||||
A = nuclide.Nuclide("A")
|
||||
A.half_life = 2.36520e4
|
||||
A.decay_modes = [
|
||||
nuclide.DecayTuple("beta1", "B", 0.6),
|
||||
nuclide.DecayTuple("beta2", "C", 0.4)
|
||||
]
|
||||
A.reactions = [nuclide.ReactionTuple("(n,gamma)", "C", 0.0, 1.0)]
|
||||
|
||||
B = nuclide.Nuclide("B")
|
||||
B.half_life = 3.29040e4
|
||||
B.decay_modes = [nuclide.DecayTuple("beta", "A", 1.0)]
|
||||
B.reactions = [nuclide.ReactionTuple("(n,gamma)", "C", 0.0, 1.0)]
|
||||
|
||||
C = nuclide.Nuclide("C")
|
||||
C.reactions = [
|
||||
nuclide.ReactionTuple("fission", None, 2.0e8, 1.0),
|
||||
nuclide.ReactionTuple("(n,gamma)", "A", 0.0, 0.7),
|
||||
nuclide.ReactionTuple("(n,gamma)", "B", 0.0, 0.3)
|
||||
]
|
||||
C.yield_data = nuclide.FissionYieldDistribution({
|
||||
0.0253: {"A": 0.0292737, "B": 0.002566345}})
|
||||
|
||||
chain = Chain()
|
||||
chain.nuclides = [A, B, C]
|
||||
chain.export_to_xml(filename)
|
||||
|
||||
chain_xml = open(filename, 'r').read()
|
||||
assert _TEST_CHAIN == chain_xml
|
||||
|
||||
|
||||
def test_form_matrix(simple_chain):
|
||||
""" Using chain_test, and a dummy reaction rate, compute the matrix. """
|
||||
# Relies on test_from_xml passing.
|
||||
|
||||
chain = simple_chain
|
||||
|
||||
mats = ["10000", "10001"]
|
||||
nuclides = ["A", "B", "C"]
|
||||
|
||||
react = reaction_rates.ReactionRates(mats, nuclides, chain.reactions)
|
||||
|
||||
react.set("10000", "C", "fission", 1.0)
|
||||
react.set("10000", "A", "(n,gamma)", 2.0)
|
||||
react.set("10000", "B", "(n,gamma)", 3.0)
|
||||
react.set("10000", "C", "(n,gamma)", 4.0)
|
||||
|
||||
mat = chain.form_matrix(react[0, :, :])
|
||||
# Loss A, decay, (n, gamma)
|
||||
mat00 = -np.log(2) / 2.36520E+04 - 2
|
||||
# A -> B, decay, 0.6 branching ratio
|
||||
mat10 = np.log(2) / 2.36520E+04 * 0.6
|
||||
# A -> C, decay, 0.4 branching ratio + (n,gamma)
|
||||
mat20 = np.log(2) / 2.36520E+04 * 0.4 + 2
|
||||
|
||||
# B -> A, decay, 1.0 branching ratio
|
||||
mat01 = np.log(2)/3.29040E+04
|
||||
# Loss B, decay, (n, gamma)
|
||||
mat11 = -np.log(2)/3.29040E+04 - 3
|
||||
# B -> C, (n, gamma)
|
||||
mat21 = 3
|
||||
|
||||
# C -> A fission, (n, gamma)
|
||||
mat02 = 0.0292737 * 1.0 + 4.0 * 0.7
|
||||
# C -> B fission, (n, gamma)
|
||||
mat12 = 0.002566345 * 1.0 + 4.0 * 0.3
|
||||
# Loss C, fission, (n, gamma)
|
||||
mat22 = -1.0 - 4.0
|
||||
|
||||
assert mat[0, 0] == mat00
|
||||
assert mat[1, 0] == mat10
|
||||
assert mat[2, 0] == mat20
|
||||
assert mat[0, 1] == mat01
|
||||
assert mat[1, 1] == mat11
|
||||
assert mat[2, 1] == mat21
|
||||
assert mat[0, 2] == mat02
|
||||
assert mat[1, 2] == mat12
|
||||
assert mat[2, 2] == mat22
|
||||
|
||||
# Pass equivalent fission yields directly
|
||||
# Ensure identical matrix is formed
|
||||
f_yields = {"C": {"A": 0.0292737, "B": 0.002566345}}
|
||||
new_mat = chain.form_matrix(react[0], f_yields)
|
||||
for r, c in product(range(3), range(3)):
|
||||
assert new_mat[r, c] == mat[r, c]
|
||||
|
||||
|
||||
def test_getitem():
|
||||
""" Test nuc_by_ind converter function. """
|
||||
chain = Chain()
|
||||
chain.nuclides = ["NucA", "NucB", "NucC"]
|
||||
chain.nuclide_dict = {nuc: chain.nuclides.index(nuc)
|
||||
for nuc in chain.nuclides}
|
||||
|
||||
assert "NucA" == chain["NucA"]
|
||||
assert "NucB" == chain["NucB"]
|
||||
assert "NucC" == chain["NucC"]
|
||||
|
||||
|
||||
def test_set_fiss_q():
|
||||
"""Make sure new fission q values can be set on the chain"""
|
||||
new_q = {"U235": 2.0E8, "U238": 2.0E8, "U234": 5.0E7}
|
||||
chain_file = Path(__file__).parents[1] / "chain_simple.xml"
|
||||
mod_chain = Chain.from_xml(chain_file, new_q)
|
||||
for name, q in new_q.items():
|
||||
chain_nuc = mod_chain[name]
|
||||
for rx in chain_nuc.reactions:
|
||||
if rx.type == 'fission':
|
||||
assert rx.Q == q
|
||||
|
||||
|
||||
def test_get_set_chain_br(simple_chain):
|
||||
"""Test minor modifications to capture branch ratios"""
|
||||
expected = {"C": {"A": 0.7, "B": 0.3}}
|
||||
assert simple_chain.get_branch_ratios() == expected
|
||||
|
||||
# safely modify
|
||||
new_chain = Chain.from_xml("chain_test.xml")
|
||||
new_br = {"C": {"A": 0.5, "B": 0.5}, "A": {"C": 0.99, "B": 0.01}}
|
||||
new_chain.set_branch_ratios(new_br)
|
||||
assert new_chain.get_branch_ratios() == new_br
|
||||
|
||||
# write, re-read
|
||||
new_chain.export_to_xml("chain_mod.xml")
|
||||
assert Chain.from_xml("chain_mod.xml").get_branch_ratios() == new_br
|
||||
|
||||
# Test non-strict [warn, not error] setting
|
||||
bad_br = {"B": {"X": 0.6, "A": 0.4}, "X": {"A": 0.5, "C": 0.5}}
|
||||
bad_br.update(new_br)
|
||||
new_chain.set_branch_ratios(bad_br, strict=False)
|
||||
assert new_chain.get_branch_ratios() == new_br
|
||||
|
||||
# Ensure capture reactions are removed
|
||||
rem_br = {"A": {"C": 1.0}}
|
||||
new_chain.set_branch_ratios(rem_br)
|
||||
# A is not in returned dict because there is no branch
|
||||
assert "A" not in new_chain.get_branch_ratios()
|
||||
|
||||
|
||||
def test_capture_branch_infer_ground():
|
||||
"""Ensure the ground state is infered if not given"""
|
||||
# Make up a metastable capture transition:
|
||||
infer_br = {"Xe135": {"Xe136_m1": 0.5}}
|
||||
set_br = {"Xe135": {"Xe136": 0.5, "Xe136_m1": 0.5}}
|
||||
|
||||
chain_file = Path(__file__).parents[1] / "chain_simple.xml"
|
||||
chain = Chain.from_xml(chain_file)
|
||||
|
||||
# Create nuclide to be added into the chain
|
||||
xe136m = nuclide.Nuclide("Xe136_m1")
|
||||
|
||||
chain.nuclides.append(xe136m)
|
||||
chain.nuclide_dict[xe136m.name] = len(chain.nuclides) - 1
|
||||
|
||||
chain.set_branch_ratios(infer_br, "(n,gamma)")
|
||||
|
||||
assert chain.get_branch_ratios("(n,gamma)") == set_br
|
||||
|
||||
|
||||
def test_capture_branch_no_rxn():
|
||||
"""Ensure capture reactions that don't exist aren't created"""
|
||||
u4br = {"U234": {"U235": 0.5, "U235_m1": 0.5}}
|
||||
|
||||
chain_file = Path(__file__).parents[1] / "chain_simple.xml"
|
||||
chain = Chain.from_xml(chain_file)
|
||||
|
||||
u5m = nuclide.Nuclide("U235_m1")
|
||||
|
||||
chain.nuclides.append(u5m)
|
||||
chain.nuclide_dict[u5m.name] = len(chain.nuclides) - 1
|
||||
|
||||
with pytest.raises(AttributeError, match="U234"):
|
||||
chain.set_branch_ratios(u4br)
|
||||
|
||||
|
||||
def test_capture_branch_failures(simple_chain):
|
||||
"""Test failure modes for setting capture branch ratios"""
|
||||
|
||||
# Parent isotope not present
|
||||
br = {"X": {"A": 0.6, "B": 0.7}}
|
||||
with pytest.raises(KeyError, match="X"):
|
||||
simple_chain.set_branch_ratios(br)
|
||||
|
||||
# Product isotope not present
|
||||
br = {"C": {"X": 0.4, "A": 0.2, "B": 0.4}}
|
||||
with pytest.raises(KeyError, match="X"):
|
||||
simple_chain.set_branch_ratios(br)
|
||||
|
||||
# Sum of ratios > 1.0
|
||||
br = {"C": {"A": 1.0, "B": 1.0}}
|
||||
with pytest.raises(ValueError, match=r"Sum of \(n,gamma\).*for C"):
|
||||
simple_chain.set_branch_ratios(br, "(n,gamma)")
|
||||
|
||||
|
||||
def test_set_alpha_branches():
|
||||
"""Test setting of alpha reaction branching ratios"""
|
||||
# Build a mock chain
|
||||
chain = Chain()
|
||||
|
||||
parent = nuclide.Nuclide()
|
||||
parent.name = "A"
|
||||
|
||||
he4 = nuclide.Nuclide()
|
||||
he4.name = "He4"
|
||||
|
||||
ground_tgt = nuclide.Nuclide()
|
||||
ground_tgt.name = "B"
|
||||
|
||||
meta_tgt = nuclide.Nuclide()
|
||||
meta_tgt.name = "B_m1"
|
||||
|
||||
for ix, nuc in enumerate((parent, ground_tgt, meta_tgt, he4)):
|
||||
chain.nuclides.append(nuc)
|
||||
chain.nuclide_dict[nuc.name] = ix
|
||||
|
||||
# add reactions to parent
|
||||
parent.reactions.append(nuclide.ReactionTuple(
|
||||
"(n,a)", ground_tgt.name, 1.0, 0.6))
|
||||
parent.reactions.append(nuclide.ReactionTuple(
|
||||
"(n,a)", meta_tgt.name, 1.0, 0.4))
|
||||
parent.reactions.append(nuclide.ReactionTuple(
|
||||
"(n,a)", he4.name, 1.0, 1.0))
|
||||
|
||||
expected_ref = {"A": {"B": 0.6, "B_m1": 0.4}}
|
||||
|
||||
assert chain.get_branch_ratios("(n,a)") == expected_ref
|
||||
|
||||
# alter and check again
|
||||
|
||||
altered = {"A": {"B": 0.5, "B_m1": 0.5}}
|
||||
|
||||
chain.set_branch_ratios(altered, "(n,a)")
|
||||
assert chain.get_branch_ratios("(n,a)") == altered
|
||||
|
||||
# make sure that alpha particle still produced
|
||||
for r in parent.reactions:
|
||||
if r.target == he4.name:
|
||||
break
|
||||
else:
|
||||
raise ValueError("Helium has been removed and should not have been")
|
||||
|
||||
|
||||
def test_simple_fission_yields(simple_chain):
|
||||
"""Check the default fission yields that can be used to form the matrix
|
||||
"""
|
||||
fission_yields = simple_chain.get_default_fission_yields()
|
||||
assert fission_yields == {"C": {"A": 0.0292737, "B": 0.002566345}}
|
||||
|
||||
|
||||
def test_fission_yield_attribute(simple_chain):
|
||||
"""Test the fission_yields property"""
|
||||
thermal_yields = simple_chain.get_default_fission_yields()
|
||||
# generate default with property
|
||||
assert simple_chain.fission_yields[0] == thermal_yields
|
||||
empty_chain = Chain()
|
||||
empty_chain.fission_yields = thermal_yields
|
||||
assert empty_chain.fission_yields[0] == thermal_yields
|
||||
empty_chain.fission_yields = [thermal_yields] * 2
|
||||
assert empty_chain.fission_yields[0] == thermal_yields
|
||||
assert empty_chain.fission_yields[1] == thermal_yields
|
||||
|
||||
# test failure with deplete function
|
||||
# number fission yields != number of materials
|
||||
dummy_conc = [[1, 2]] * (len(empty_chain.fission_yields) + 1)
|
||||
with pytest.raises(
|
||||
ValueError, match="fission yield.*not equal.*compositions"):
|
||||
cram.deplete(empty_chain, dummy_conc, None, 0.5)
|
||||
|
||||
def test_validate(simple_chain):
|
||||
"""Test the validate method"""
|
||||
|
||||
# current chain is invalid
|
||||
# fission yields do not sum to 2.0
|
||||
with pytest.raises(ValueError, match="Nuclide C.*fission yields"):
|
||||
simple_chain.validate(strict=True, tolerance=0.0)
|
||||
|
||||
with pytest.warns(UserWarning) as record:
|
||||
assert not simple_chain.validate(strict=False, quiet=False, tolerance=0.0)
|
||||
assert not simple_chain.validate(strict=False, quiet=True, tolerance=0.0)
|
||||
assert len(record) == 1
|
||||
assert "Nuclide C" in record[0].message.args[0]
|
||||
|
||||
# Fix fission yields but keep to restore later
|
||||
old_yields = simple_chain["C"].yield_data
|
||||
simple_chain["C"].yield_data = {0.0253: {"A": 1.4, "B": 0.6}}
|
||||
|
||||
assert simple_chain.validate(strict=True, tolerance=0.0)
|
||||
with pytest.warns(None) as record:
|
||||
assert simple_chain.validate(strict=False, quiet=False, tolerance=0.0)
|
||||
assert len(record) == 0
|
||||
|
||||
# Mess up "earlier" nuclide's reactions
|
||||
decay_mode = simple_chain["A"].decay_modes.pop()
|
||||
|
||||
with pytest.raises(ValueError, match="Nuclide A.*decay mode"):
|
||||
simple_chain.validate(strict=True, tolerance=0.0)
|
||||
|
||||
# restore old fission yields
|
||||
simple_chain["C"].yield_data = old_yields
|
||||
|
||||
with pytest.warns(UserWarning) as record:
|
||||
assert not simple_chain.validate(strict=False, quiet=False, tolerance=0.0)
|
||||
assert len(record) == 2
|
||||
assert "Nuclide A" in record[0].message.args[0]
|
||||
assert "Nuclide C" in record[1].message.args[0]
|
||||
|
||||
# restore decay modes
|
||||
simple_chain["A"].decay_modes.append(decay_mode)
|
||||
|
||||
|
||||
def test_validate_inputs():
|
||||
c = Chain()
|
||||
|
||||
with pytest.raises(TypeError, match="tolerance"):
|
||||
c.validate(tolerance=None)
|
||||
|
||||
with pytest.raises(ValueError, match="tolerance"):
|
||||
c.validate(tolerance=-1)
|
||||
37
tests/unit_tests/test_deplete_cram.py
Normal file
37
tests/unit_tests/test_deplete_cram.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
""" Tests for cram.py
|
||||
|
||||
Compares a few Mathematica matrix exponentials to CRAM16/CRAM48.
|
||||
"""
|
||||
|
||||
from pytest import approx
|
||||
import numpy as np
|
||||
import scipy.sparse as sp
|
||||
from openmc.deplete.cram import CRAM16, CRAM48
|
||||
|
||||
|
||||
def test_CRAM16():
|
||||
"""Test 16-term CRAM."""
|
||||
x = np.array([1.0, 1.0])
|
||||
mat = sp.csr_matrix([[-1.0, 0.0], [-2.0, -3.0]])
|
||||
dt = 0.1
|
||||
|
||||
z = CRAM16(mat, x, dt)
|
||||
|
||||
# Solution from mathematica
|
||||
z0 = np.array((0.904837418035960, 0.576799023327476))
|
||||
|
||||
assert z == approx(z0)
|
||||
|
||||
|
||||
def test_CRAM48():
|
||||
"""Test 48-term CRAM."""
|
||||
x = np.array([1.0, 1.0])
|
||||
mat = sp.csr_matrix([[-1.0, 0.0], [-2.0, -3.0]])
|
||||
dt = 0.1
|
||||
|
||||
z = CRAM48(mat, x, dt)
|
||||
|
||||
# Solution from mathematica
|
||||
z0 = np.array((0.904837418035960, 0.576799023327476))
|
||||
|
||||
assert z == approx(z0)
|
||||
293
tests/unit_tests/test_deplete_fission_yields.py
Normal file
293
tests/unit_tests/test_deplete_fission_yields.py
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
"""Test the FissionYieldHelpers"""
|
||||
|
||||
import os
|
||||
from collections import namedtuple
|
||||
from unittest.mock import Mock
|
||||
import bisect
|
||||
|
||||
import pytest
|
||||
import numpy as np
|
||||
import openmc
|
||||
from openmc import lib
|
||||
from openmc.deplete.nuclide import Nuclide, FissionYieldDistribution
|
||||
from openmc.deplete.helpers import (
|
||||
FissionYieldCutoffHelper, ConstantFissionYieldHelper,
|
||||
AveragedFissionYieldHelper)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def materials(tmpdir_factory):
|
||||
"""Use C API to construct realistic materials for testing tallies"""
|
||||
tmpdir = tmpdir_factory.mktemp("lib")
|
||||
orig = tmpdir.chdir()
|
||||
# Create proxy problem to please openmc
|
||||
mfuel = openmc.Material(name="test_fuel")
|
||||
mfuel.volume = 1.0
|
||||
for nuclide in ["U235", "U238", "Xe135", "Pu239"]:
|
||||
mfuel.add_nuclide(nuclide, 1.0)
|
||||
openmc.Materials([mfuel]).export_to_xml()
|
||||
# Geometry
|
||||
box = openmc.rectangular_prism(1.0, 1.0, boundary_type="reflective")
|
||||
cell = openmc.Cell(fill=mfuel, region=box)
|
||||
root = openmc.Universe(cells=[cell])
|
||||
openmc.Geometry(root).export_to_xml()
|
||||
# settings
|
||||
settings = openmc.Settings()
|
||||
settings.particles = 100
|
||||
settings.inactive = 0
|
||||
settings.batches = 10
|
||||
settings.verbosity = 1
|
||||
settings.export_to_xml()
|
||||
|
||||
try:
|
||||
with lib.run_in_memory():
|
||||
yield [lib.Material(), lib.Material()]
|
||||
finally:
|
||||
# Convert to strings as os.remove in py 3.5 doesn't support Paths
|
||||
for file_path in ("settings.xml", "geometry.xml", "materials.xml",
|
||||
"summary.h5"):
|
||||
os.remove(str(tmpdir / file_path))
|
||||
orig.chdir()
|
||||
os.rmdir(str(tmpdir))
|
||||
|
||||
|
||||
def proxy_tally_data(tally, fill=None):
|
||||
"""Construct an empty matrix built from a C tally
|
||||
|
||||
The shape of tally.results will be
|
||||
``(n_bins, n_nuc * n_scores, 3)``
|
||||
"""
|
||||
n_nucs = max(len(tally.nuclides), 1)
|
||||
n_scores = max(len(tally.scores), 1)
|
||||
n_bins = 1
|
||||
for tfilter in tally.filters:
|
||||
if not hasattr(tfilter, "bins"):
|
||||
continue
|
||||
this_bins = len(tfilter.bins)
|
||||
if isinstance(tfilter, lib.EnergyFilter):
|
||||
this_bins -= 1
|
||||
n_bins *= max(this_bins, 1)
|
||||
data = np.empty((n_bins, n_nucs * n_scores, 3))
|
||||
if fill is not None:
|
||||
data.fill(fill)
|
||||
return data
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def nuclide_bundle():
|
||||
u5yield_dict = {
|
||||
0.0253: {"Xe135": 7.85e-4, "Gd155": 4.08e-12, "Sm149": 1.71e-12},
|
||||
5.0e5: {"Xe135": 7.85e-4, "Sm149": 1.71e-12},
|
||||
1.40e7: {"Xe135": 4.54e-3, "Gd155": 5.83e-8}}
|
||||
u235 = Nuclide("U235")
|
||||
u235.yield_data = FissionYieldDistribution(u5yield_dict)
|
||||
|
||||
u8yield_dict = {5.00e5: {"Xe135": 1.12e-3, "Gd155": 1.32e-12}}
|
||||
u238 = Nuclide("U238")
|
||||
u238.yield_data = FissionYieldDistribution(u8yield_dict)
|
||||
|
||||
xe135 = Nuclide("Xe135")
|
||||
|
||||
pu239 = Nuclide("Pu239")
|
||||
pu239.yield_data = FissionYieldDistribution({
|
||||
5.0e5: {"Xe135": 6.14e-3, "Sm149": 9.429e-10, "Gd155": 5.24e-9},
|
||||
2e6: {"Xe135": 6.15e-3, "Sm149": 9.42e-10, "Gd155": 5.29e-9}})
|
||||
|
||||
NuclideBundle = namedtuple("NuclideBundle", "u235 u238 xe135 pu239")
|
||||
return NuclideBundle(u235, u238, xe135, pu239)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input_energy, yield_energy",
|
||||
((0.0253, 0.0253), (0.01, 0.0253), (4e5, 5e5)))
|
||||
def test_constant_helper(nuclide_bundle, input_energy, yield_energy):
|
||||
helper = ConstantFissionYieldHelper(nuclide_bundle, energy=input_energy)
|
||||
assert helper.energy == input_energy
|
||||
assert helper.constant_yields == {
|
||||
"U235": nuclide_bundle.u235.yield_data[yield_energy],
|
||||
"U238": nuclide_bundle.u238.yield_data[5.00e5],
|
||||
"Pu239": nuclide_bundle.pu239.yield_data[5e5]}
|
||||
assert helper.constant_yields == helper.weighted_yields(1)
|
||||
|
||||
|
||||
def test_cutoff_construction(nuclide_bundle):
|
||||
u235 = nuclide_bundle.u235
|
||||
u238 = nuclide_bundle.u238
|
||||
pu239 = nuclide_bundle.pu239
|
||||
|
||||
# defaults
|
||||
helper = FissionYieldCutoffHelper(nuclide_bundle, 1)
|
||||
assert helper.constant_yields == {
|
||||
"U238": u238.yield_data[5.0e5],
|
||||
"Pu239": pu239.yield_data[5e5]}
|
||||
assert helper.thermal_yields == {"U235": u235.yield_data[0.0253]}
|
||||
assert helper.fast_yields == {"U235": u235.yield_data[5e5]}
|
||||
|
||||
# use 14 MeV yields
|
||||
helper = FissionYieldCutoffHelper(nuclide_bundle, 1, fast_energy=14e6)
|
||||
assert helper.constant_yields == {
|
||||
"U238": u238.yield_data[5.0e5],
|
||||
"Pu239": pu239.yield_data[5e5]}
|
||||
assert helper.thermal_yields == {"U235": u235.yield_data[0.0253]}
|
||||
assert helper.fast_yields == {"U235": u235.yield_data[14e6]}
|
||||
|
||||
# specify missing thermal yields -> use 0.0253
|
||||
helper = FissionYieldCutoffHelper(nuclide_bundle, 1, thermal_energy=1)
|
||||
assert helper.thermal_yields == {"U235": u235.yield_data[0.0253]}
|
||||
assert helper.fast_yields == {"U235": u235.yield_data[5e5]}
|
||||
|
||||
# request missing fast yields -> use epithermal
|
||||
helper = FissionYieldCutoffHelper(nuclide_bundle, 1, fast_energy=1e4)
|
||||
assert helper.thermal_yields == {"U235": u235.yield_data[0.0253]}
|
||||
assert helper.fast_yields == {"U235": u235.yield_data[5e5]}
|
||||
|
||||
# higher cutoff energy -> obtain fast and "faster" yields
|
||||
helper = FissionYieldCutoffHelper(nuclide_bundle, 1, cutoff=1e6,
|
||||
thermal_energy=5e5, fast_energy=14e6)
|
||||
assert helper.constant_yields == {"U238": u238.yield_data[5e5]}
|
||||
assert helper.thermal_yields == {
|
||||
"U235": u235.yield_data[5e5], "Pu239": pu239.yield_data[5e5]}
|
||||
assert helper.fast_yields == {
|
||||
"U235": u235.yield_data[14e6], "Pu239": pu239.yield_data[2e6]}
|
||||
|
||||
# test super low and super high cutoff energies
|
||||
helper = FissionYieldCutoffHelper(
|
||||
nuclide_bundle, 1, thermal_energy=0.001, cutoff=0.002)
|
||||
assert helper.fast_yields == {}
|
||||
assert helper.thermal_yields == {}
|
||||
assert helper.constant_yields == {
|
||||
"U235": u235.yield_data[0.0253], "U238": u238.yield_data[5e5],
|
||||
"Pu239": pu239.yield_data[5e5]}
|
||||
|
||||
helper = FissionYieldCutoffHelper(
|
||||
nuclide_bundle, 1, cutoff=15e6, fast_energy=17e6)
|
||||
assert helper.thermal_yields == {}
|
||||
assert helper.fast_yields == {}
|
||||
assert helper.constant_yields == {
|
||||
"U235": u235.yield_data[14e6], "U238": u238.yield_data[5e5],
|
||||
"Pu239": pu239.yield_data[2e6]}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("key", ("cutoff", "thermal_energy", "fast_energy"))
|
||||
def test_cutoff_failure(key):
|
||||
with pytest.raises(TypeError, match=key):
|
||||
FissionYieldCutoffHelper(None, None, **{key: None})
|
||||
with pytest.raises(ValueError, match=key):
|
||||
FissionYieldCutoffHelper(None, None, **{key: -1})
|
||||
|
||||
|
||||
# emulate some split between fast and thermal U235 fissions
|
||||
@pytest.mark.parametrize("therm_frac", (0.5, 0.2, 0.8))
|
||||
def test_cutoff_helper(materials, nuclide_bundle, therm_frac):
|
||||
helper = FissionYieldCutoffHelper(nuclide_bundle, len(materials),
|
||||
cutoff=1e6, fast_energy=14e6)
|
||||
helper.generate_tallies(materials, [0])
|
||||
|
||||
non_zero_nucs = [n.name for n in nuclide_bundle]
|
||||
tally_nucs = helper.update_tally_nuclides(non_zero_nucs)
|
||||
assert tally_nucs == ["Pu239", "U235"]
|
||||
|
||||
# Check tallies
|
||||
fission_tally = helper._fission_rate_tally
|
||||
assert fission_tally is not None
|
||||
filters = fission_tally.filters
|
||||
assert len(filters) == 2
|
||||
assert isinstance(filters[0], lib.MaterialFilter)
|
||||
assert len(filters[0].bins) == len(materials)
|
||||
assert isinstance(filters[1], lib.EnergyFilter)
|
||||
# lower, cutoff, and upper energy
|
||||
assert len(filters[1].bins) == 3
|
||||
|
||||
# Emulate building tallies
|
||||
# material x energy, tallied_nuclides, 3
|
||||
tally_data = proxy_tally_data(fission_tally)
|
||||
helper._fission_rate_tally = Mock()
|
||||
helper_flux = 1e6
|
||||
tally_data[0, :, 1] = therm_frac * helper_flux
|
||||
tally_data[1, :, 1] = (1 - therm_frac) * helper_flux
|
||||
helper._fission_rate_tally.results = tally_data
|
||||
|
||||
helper.unpack()
|
||||
# expected results of shape (n_mats, 2, n_tnucs)
|
||||
expected_results = np.empty((1, 2, len(tally_nucs)))
|
||||
expected_results[:, 0] = therm_frac
|
||||
expected_results[:, 1] = 1 - therm_frac
|
||||
assert helper.results == pytest.approx(expected_results)
|
||||
|
||||
actual_yields = helper.weighted_yields(0)
|
||||
assert actual_yields["U238"] == nuclide_bundle.u238.yield_data[5e5]
|
||||
for nuc in tally_nucs:
|
||||
assert actual_yields[nuc] == (
|
||||
helper.thermal_yields[nuc] * therm_frac
|
||||
+ helper.fast_yields[nuc] * (1 - therm_frac))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("avg_energy", (0.01, 6e5, 15e6))
|
||||
def test_averaged_helper(materials, nuclide_bundle, avg_energy):
|
||||
helper = AveragedFissionYieldHelper(nuclide_bundle)
|
||||
helper.generate_tallies(materials, [0])
|
||||
tallied_nucs = helper.update_tally_nuclides(
|
||||
[n.name for n in nuclide_bundle])
|
||||
assert tallied_nucs == ["Pu239", "U235"]
|
||||
|
||||
# check generated tallies
|
||||
fission_tally = helper._fission_rate_tally
|
||||
assert fission_tally is not None
|
||||
fission_filters = fission_tally.filters
|
||||
assert len(fission_filters) == 2
|
||||
assert isinstance(fission_filters[0], lib.MaterialFilter)
|
||||
assert len(fission_filters[0].bins) == len(materials)
|
||||
assert isinstance(fission_filters[1], lib.EnergyFilter)
|
||||
assert len(fission_filters[1].bins) == 2
|
||||
assert fission_tally.scores == ["fission"]
|
||||
assert fission_tally.nuclides == list(tallied_nucs)
|
||||
|
||||
weighted_tally = helper._weighted_tally
|
||||
assert weighted_tally is not None
|
||||
weighted_filters = weighted_tally.filters
|
||||
assert len(weighted_filters) == 2
|
||||
assert isinstance(weighted_filters[0], lib.MaterialFilter)
|
||||
assert len(weighted_filters[0].bins) == len(materials)
|
||||
assert isinstance(weighted_filters[1], lib.EnergyFunctionFilter)
|
||||
assert len(weighted_filters[1].energy) == 2
|
||||
assert len(weighted_filters[1].y) == 2
|
||||
assert weighted_tally.scores == ["fission"]
|
||||
assert weighted_tally.nuclides == list(tallied_nucs)
|
||||
|
||||
helper_flux = 1e16
|
||||
fission_results = proxy_tally_data(fission_tally, helper_flux)
|
||||
weighted_results = proxy_tally_data(
|
||||
weighted_tally, helper_flux * avg_energy)
|
||||
|
||||
helper._fission_rate_tally = Mock()
|
||||
helper._weighted_tally = Mock()
|
||||
helper._fission_rate_tally.results = fission_results
|
||||
helper._weighted_tally.results = weighted_results
|
||||
|
||||
helper.unpack()
|
||||
expected_results = np.ones((1, len(tallied_nucs))) * avg_energy
|
||||
assert helper.results == pytest.approx(expected_results)
|
||||
|
||||
actual_yields = helper.weighted_yields(0)
|
||||
# constant U238 => no interpolation
|
||||
assert actual_yields["U238"] == nuclide_bundle.u238.yield_data[5e5]
|
||||
# construct expected yields
|
||||
exp_u235_yields = interp_average_yields(nuclide_bundle.u235, avg_energy)
|
||||
assert actual_yields["U235"] == exp_u235_yields
|
||||
exp_pu239_yields = interp_average_yields(nuclide_bundle.pu239, avg_energy)
|
||||
assert actual_yields["Pu239"] == exp_pu239_yields
|
||||
|
||||
|
||||
def interp_average_yields(nuc, avg_energy):
|
||||
"""Construct a set of yields by interpolation between neighbors"""
|
||||
energies = nuc.yield_energies
|
||||
yields = nuc.yield_data
|
||||
if avg_energy < energies[0]:
|
||||
return yields[energies[0]]
|
||||
if avg_energy > energies[-1]:
|
||||
return yields[energies[-1]]
|
||||
thermal_ix = bisect.bisect_left(energies, avg_energy)
|
||||
thermal_E, fast_E = energies[thermal_ix - 1:thermal_ix + 1]
|
||||
assert thermal_E < avg_energy < fast_E
|
||||
split = (avg_energy - thermal_E)/(fast_E - thermal_E)
|
||||
return yields[thermal_E]*(1 - split) + yields[fast_E]*split
|
||||
161
tests/unit_tests/test_deplete_integrator.py
Normal file
161
tests/unit_tests/test_deplete_integrator.py
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
"""Tests for saving results
|
||||
|
||||
It is worth noting that openmc.deplete.integrate is extremely complex, to the
|
||||
point I am unsure if it can be reasonably unit-tested. For the time being, it
|
||||
will be left unimplemented and testing will be done via regression.
|
||||
|
||||
"""
|
||||
|
||||
import copy
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import numpy as np
|
||||
from uncertainties import ufloat
|
||||
import pytest
|
||||
|
||||
from openmc.deplete import (
|
||||
ReactionRates, Results, ResultsList, comm, OperatorResult,
|
||||
PredictorIntegrator, SICELIIntegrator)
|
||||
|
||||
from tests import dummy_operator
|
||||
|
||||
|
||||
def test_results_save(run_in_tmpdir):
|
||||
"""Test data save module"""
|
||||
|
||||
stages = 3
|
||||
|
||||
np.random.seed(comm.rank)
|
||||
|
||||
# Mock geometry
|
||||
op = MagicMock()
|
||||
|
||||
# Avoid DummyOperator thinking it's doing a restart calculation
|
||||
op.prev_res = None
|
||||
|
||||
vol_dict = {}
|
||||
full_burn_list = []
|
||||
|
||||
for i in range(comm.size):
|
||||
vol_dict[str(2*i)] = 1.2
|
||||
vol_dict[str(2*i + 1)] = 1.2
|
||||
full_burn_list.append(str(2*i))
|
||||
full_burn_list.append(str(2*i + 1))
|
||||
|
||||
burn_list = full_burn_list[2*comm.rank: 2*comm.rank + 2]
|
||||
nuc_list = ["na", "nb"]
|
||||
|
||||
op.get_results_info.return_value = (
|
||||
vol_dict, nuc_list, burn_list, full_burn_list)
|
||||
|
||||
# Construct x
|
||||
x1 = []
|
||||
x2 = []
|
||||
|
||||
for i in range(stages):
|
||||
x1.append([np.random.rand(2), np.random.rand(2)])
|
||||
x2.append([np.random.rand(2), np.random.rand(2)])
|
||||
|
||||
# Construct r
|
||||
r1 = ReactionRates(burn_list, ["na", "nb"], ["ra", "rb"])
|
||||
r1[:] = np.random.rand(2, 2, 2)
|
||||
|
||||
rate1 = []
|
||||
rate2 = []
|
||||
|
||||
for i in range(stages):
|
||||
rate1.append(copy.deepcopy(r1))
|
||||
r1[:] = np.random.rand(2, 2, 2)
|
||||
rate2.append(copy.deepcopy(r1))
|
||||
r1[:] = np.random.rand(2, 2, 2)
|
||||
|
||||
# Create global terms
|
||||
# Col 0: eig, Col 1: uncertainty
|
||||
eigvl1 = np.random.rand(stages, 2)
|
||||
eigvl2 = np.random.rand(stages, 2)
|
||||
|
||||
eigvl1 = comm.bcast(eigvl1, root=0)
|
||||
eigvl2 = comm.bcast(eigvl2, root=0)
|
||||
|
||||
t1 = [0.0, 1.0]
|
||||
t2 = [1.0, 2.0]
|
||||
|
||||
op_result1 = [OperatorResult(ufloat(*k), rates)
|
||||
for k, rates in zip(eigvl1, rate1)]
|
||||
op_result2 = [OperatorResult(ufloat(*k), rates)
|
||||
for k, rates in zip(eigvl2, rate2)]
|
||||
Results.save(op, x1, op_result1, t1, 0, 0)
|
||||
Results.save(op, x2, op_result2, t2, 0, 1)
|
||||
|
||||
# Load the files
|
||||
res = ResultsList.from_hdf5("depletion_results.h5")
|
||||
|
||||
for i in range(stages):
|
||||
for mat_i, mat in enumerate(burn_list):
|
||||
for nuc_i, nuc in enumerate(nuc_list):
|
||||
assert res[0][i, mat, nuc] == x1[i][mat_i][nuc_i]
|
||||
assert res[1][i, mat, nuc] == x2[i][mat_i][nuc_i]
|
||||
np.testing.assert_array_equal(res[0].rates[i], rate1[i])
|
||||
np.testing.assert_array_equal(res[1].rates[i], rate2[i])
|
||||
|
||||
np.testing.assert_array_equal(res[0].k, eigvl1)
|
||||
np.testing.assert_array_equal(res[0].time, t1)
|
||||
|
||||
np.testing.assert_array_equal(res[1].k, eigvl2)
|
||||
np.testing.assert_array_equal(res[1].time, t2)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("timesteps", (1, [1]))
|
||||
def test_bad_integrator_inputs(timesteps):
|
||||
"""Test failure modes for Integrator inputs"""
|
||||
|
||||
op = MagicMock()
|
||||
op.prev_res = None
|
||||
op.chain = None
|
||||
op.heavy_metal = 1.0
|
||||
|
||||
# No power nor power density given
|
||||
with pytest.raises(ValueError, match="Either power or power density"):
|
||||
PredictorIntegrator(op, timesteps)
|
||||
|
||||
# Length of power != length time
|
||||
with pytest.raises(ValueError, match="number of powers"):
|
||||
PredictorIntegrator(op, timesteps, power=[1, 2])
|
||||
|
||||
# Length of power density != length time
|
||||
with pytest.raises(ValueError, match="number of powers"):
|
||||
PredictorIntegrator(op, timesteps, power_density=[1, 2])
|
||||
|
||||
# SI integrator with bad steps
|
||||
with pytest.raises(TypeError, match="n_steps"):
|
||||
SICELIIntegrator(op, timesteps, [1], n_steps=2.5)
|
||||
|
||||
with pytest.raises(ValueError, match="n_steps"):
|
||||
SICELIIntegrator(op, timesteps, [1], n_steps=0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("scheme", dummy_operator.SCHEMES)
|
||||
def test_integrator(run_in_tmpdir, scheme):
|
||||
"""Test the integrators against their expected values"""
|
||||
|
||||
bundle = dummy_operator.SCHEMES[scheme]
|
||||
operator = dummy_operator.DummyOperator()
|
||||
bundle.solver(operator, [0.75, 0.75], 1.0).integrate()
|
||||
|
||||
# get expected results
|
||||
|
||||
res = ResultsList.from_hdf5(
|
||||
operator.output_dir / "depletion_results.h5")
|
||||
|
||||
t1, y1 = res.get_atoms("1", "1")
|
||||
t2, y2 = res.get_atoms("1", "2")
|
||||
|
||||
assert (t1 == [0.0, 0.75, 1.5]).all()
|
||||
assert y1 == pytest.approx(bundle.atoms_1)
|
||||
assert (t2 == [0.0, 0.75, 1.5]).all()
|
||||
assert y2 == pytest.approx(bundle.atoms_2)
|
||||
|
||||
# test structure of depletion time dataset
|
||||
dep_time = res.get_depletion_time()
|
||||
assert dep_time.shape == (2, )
|
||||
assert all(dep_time > 0)
|
||||
260
tests/unit_tests/test_deplete_nuclide.py
Normal file
260
tests/unit_tests/test_deplete_nuclide.py
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
"""Tests for the openmc.deplete.Nuclide class."""
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import numpy
|
||||
import pytest
|
||||
from openmc.deplete import nuclide
|
||||
|
||||
|
||||
def test_n_decay_modes():
|
||||
""" Test the decay mode count parameter. """
|
||||
|
||||
nuc = nuclide.Nuclide()
|
||||
|
||||
nuc.decay_modes = [
|
||||
nuclide.DecayTuple("beta1", "a", 0.5),
|
||||
nuclide.DecayTuple("beta2", "b", 0.3),
|
||||
nuclide.DecayTuple("beta3", "c", 0.2)
|
||||
]
|
||||
|
||||
assert nuc.n_decay_modes == 3
|
||||
|
||||
|
||||
def test_n_reaction_paths():
|
||||
""" Test the reaction path count parameter. """
|
||||
|
||||
nuc = nuclide.Nuclide()
|
||||
|
||||
nuc.reactions = [
|
||||
nuclide.ReactionTuple("(n,2n)", "a", 0.0, 1.0),
|
||||
nuclide.ReactionTuple("(n,3n)", "b", 0.0, 1.0),
|
||||
nuclide.ReactionTuple("(n,4n)", "c", 0.0, 1.0)
|
||||
]
|
||||
|
||||
assert nuc.n_reaction_paths == 3
|
||||
|
||||
|
||||
def test_from_xml():
|
||||
"""Test reading nuclide data from an XML element."""
|
||||
|
||||
data = """
|
||||
<nuclide name="U235" reactions="2">
|
||||
<decay type="sf" target="U235" branching_ratio="7.2e-11"/>
|
||||
<decay type="alpha" target="Th231" branching_ratio="0.999999999928"/>
|
||||
<reaction type="(n,2n)" target="U234" Q="-5297781.0"/>
|
||||
<reaction type="(n,3n)" target="U233" Q="-12142300.0"/>
|
||||
<reaction type="(n,4n)" target="U232" Q="-17885600.0"/>
|
||||
<reaction type="(n,gamma)" target="U236" Q="6545200.0"/>
|
||||
<reaction type="fission" Q="193405400.0"/>
|
||||
<neutron_fission_yields>
|
||||
<energies>0.0253</energies>
|
||||
<fission_yields energy="0.0253">
|
||||
<products>Te134 Zr100 Xe138</products>
|
||||
<data>0.062155 0.0497641 0.0481413</data>
|
||||
</fission_yields>
|
||||
</neutron_fission_yields>
|
||||
</nuclide>
|
||||
"""
|
||||
|
||||
element = ET.fromstring(data)
|
||||
u235 = nuclide.Nuclide.from_xml(element)
|
||||
|
||||
assert u235.decay_modes == [
|
||||
nuclide.DecayTuple('sf', 'U235', 7.2e-11),
|
||||
nuclide.DecayTuple('alpha', 'Th231', 1 - 7.2e-11)
|
||||
]
|
||||
assert u235.reactions == [
|
||||
nuclide.ReactionTuple('(n,2n)', 'U234', -5297781.0, 1.0),
|
||||
nuclide.ReactionTuple('(n,3n)', 'U233', -12142300.0, 1.0),
|
||||
nuclide.ReactionTuple('(n,4n)', 'U232', -17885600.0, 1.0),
|
||||
nuclide.ReactionTuple('(n,gamma)', 'U236', 6545200.0, 1.0),
|
||||
nuclide.ReactionTuple('fission', None, 193405400.0, 1.0),
|
||||
]
|
||||
expected_yield_data = nuclide.FissionYieldDistribution({
|
||||
0.0253: {"Xe138": 0.0481413, "Zr100": 0.0497641, "Te134": 0.062155}})
|
||||
assert u235.yield_data == expected_yield_data
|
||||
# test accessing the yield energies through the FissionYieldDistribution
|
||||
assert u235.yield_energies == (0.0253,)
|
||||
assert u235.yield_energies is u235.yield_data.energies
|
||||
with pytest.raises(AttributeError): # not settable
|
||||
u235.yield_energies = [0.0253, 5e5]
|
||||
|
||||
|
||||
def test_to_xml_element():
|
||||
"""Test writing nuclide data to an XML element."""
|
||||
|
||||
C = nuclide.Nuclide("C")
|
||||
C.half_life = 0.123
|
||||
C.decay_modes = [
|
||||
nuclide.DecayTuple('beta-', 'B', 0.99),
|
||||
nuclide.DecayTuple('alpha', 'D', 0.01)
|
||||
]
|
||||
C.reactions = [
|
||||
nuclide.ReactionTuple('fission', None, 2.0e8, 1.0),
|
||||
nuclide.ReactionTuple('(n,gamma)', 'A', 0.0, 1.0)
|
||||
]
|
||||
C.yield_data = nuclide.FissionYieldDistribution(
|
||||
{0.0253: {"A": 0.0292737, "B": 0.002566345}})
|
||||
element = C.to_xml_element()
|
||||
|
||||
assert element.get("half_life") == "0.123"
|
||||
|
||||
decay_elems = element.findall("decay")
|
||||
assert len(decay_elems) == 2
|
||||
assert decay_elems[0].get("type") == "beta-"
|
||||
assert decay_elems[0].get("target") == "B"
|
||||
assert decay_elems[0].get("branching_ratio") == "0.99"
|
||||
assert decay_elems[1].get("type") == "alpha"
|
||||
assert decay_elems[1].get("target") == "D"
|
||||
assert decay_elems[1].get("branching_ratio") == "0.01"
|
||||
|
||||
rx_elems = element.findall("reaction")
|
||||
assert len(rx_elems) == 2
|
||||
assert rx_elems[0].get("type") == "fission"
|
||||
assert float(rx_elems[0].get("Q")) == 2.0e8
|
||||
assert rx_elems[1].get("type") == "(n,gamma)"
|
||||
assert rx_elems[1].get("target") == "A"
|
||||
assert float(rx_elems[1].get("Q")) == 0.0
|
||||
|
||||
assert element.find('neutron_fission_yields') is not None
|
||||
|
||||
|
||||
def test_fission_yield_distribution():
|
||||
"""Test an energy-dependent yield distribution"""
|
||||
yield_dict = {
|
||||
0.0253: {"Xe135": 7.85e-4, "Gd155": 4.08e-12, "Sm149": 1.71e-12},
|
||||
1.40e7: {"Xe135": 4.54e-3, "Gd155": 5.83e-8, "Sm149": 2.69e-8},
|
||||
5.00e5: {"Xe135": 1.12e-3, "Gd155": 1.32e-12}, # drop Sm149
|
||||
}
|
||||
yield_dist = nuclide.FissionYieldDistribution(yield_dict)
|
||||
assert len(yield_dist) == len(yield_dict)
|
||||
assert yield_dist.energies == tuple(sorted(yield_dict.keys()))
|
||||
for exp_ene, exp_dist in yield_dict.items():
|
||||
act_dist = yield_dict[exp_ene]
|
||||
for exp_prod, exp_yield in exp_dist.items():
|
||||
assert act_dist[exp_prod] == exp_yield
|
||||
exp_yield = numpy.array([
|
||||
[4.08e-12, 1.71e-12, 7.85e-4],
|
||||
[1.32e-12, 0.0, 1.12e-3],
|
||||
[5.83e-8, 2.69e-8, 4.54e-3]])
|
||||
assert numpy.array_equal(yield_dist.yield_matrix, exp_yield)
|
||||
|
||||
# Test the operations / special methods for fission yield
|
||||
orig_yields = yield_dist[0.0253]
|
||||
assert len(orig_yields) == len(yield_dict[0.0253])
|
||||
for key, value in yield_dict[0.0253].items():
|
||||
assert key in orig_yields
|
||||
assert orig_yields[key] == value
|
||||
# __getitem__ return yields as a view into yield matrix
|
||||
assert orig_yields.yields.base is yield_dist.yield_matrix
|
||||
|
||||
# Fission yield feature uses scaled and incremented
|
||||
mod_yields = orig_yields * 2
|
||||
assert numpy.array_equal(orig_yields.yields * 2, mod_yields.yields)
|
||||
mod_yields += orig_yields
|
||||
assert numpy.array_equal(orig_yields.yields * 3, mod_yields.yields)
|
||||
|
||||
# Failure modes for adding, multiplying yields
|
||||
similar = numpy.empty_like(orig_yields.yields)
|
||||
with pytest.raises(TypeError):
|
||||
orig_yields + similar
|
||||
with pytest.raises(TypeError):
|
||||
similar + orig_yields
|
||||
with pytest.raises(TypeError):
|
||||
orig_yields += similar
|
||||
with pytest.raises(TypeError):
|
||||
orig_yields * similar
|
||||
with pytest.raises(TypeError):
|
||||
similar * orig_yields
|
||||
with pytest.raises(TypeError):
|
||||
orig_yields *= similar
|
||||
|
||||
|
||||
def test_validate():
|
||||
|
||||
nuc = nuclide.Nuclide()
|
||||
nuc.name = "Test"
|
||||
|
||||
# decay modes: type, target, branching_ratio
|
||||
|
||||
nuc.decay_modes = [
|
||||
nuclide.DecayTuple("type 0", "0", 0.5),
|
||||
nuclide.DecayTuple("type 1", "1", 0.5),
|
||||
]
|
||||
|
||||
# reactions: type, target, Q, branching_ratio
|
||||
nuc.reactions = [
|
||||
nuclide.ReactionTuple("0", "0", 1000, 0.3),
|
||||
nuclide.ReactionTuple("0", "1", 1000, 0.3),
|
||||
nuclide.ReactionTuple("1", "2", 1000, 1.0),
|
||||
nuclide.ReactionTuple("0", "3", 1000, 0.4),
|
||||
]
|
||||
|
||||
# fission yields
|
||||
|
||||
nuc.yield_data = {
|
||||
0.0253: {"0": 1.5, "1": 0.5},
|
||||
1e6: {"0": 1.5, "1": 0.5},
|
||||
}
|
||||
|
||||
# nuclide is good and should have no warnings raise
|
||||
with pytest.warns(None) as record:
|
||||
assert nuc.validate(strict=True, quiet=False, tolerance=0.0)
|
||||
assert len(record) == 0
|
||||
|
||||
# invalidate decay modes
|
||||
decay = nuc.decay_modes.pop()
|
||||
with pytest.raises(ValueError, match="decay mode"):
|
||||
nuc.validate(strict=True, quiet=False, tolerance=0.0)
|
||||
|
||||
with pytest.warns(UserWarning) as record:
|
||||
assert not nuc.validate(strict=False, quiet=False, tolerance=0.0)
|
||||
assert not nuc.validate(strict=False, quiet=True, tolerance=0.0)
|
||||
assert len(record) == 1
|
||||
assert "decay mode" in record[0].message.args[0]
|
||||
|
||||
# restore decay modes, invalidate reactions
|
||||
nuc.decay_modes.append(decay)
|
||||
reaction = nuc.reactions.pop()
|
||||
|
||||
with pytest.raises(ValueError, match="0 reaction"):
|
||||
nuc.validate(strict=True, quiet=False, tolerance=0.0)
|
||||
|
||||
with pytest.warns(UserWarning) as record:
|
||||
assert not nuc.validate(strict=False, quiet=False, tolerance=0.0)
|
||||
assert not nuc.validate(strict=False, quiet=True, tolerance=0.0)
|
||||
assert len(record) == 1
|
||||
assert "0 reaction" in record[0].message.args[0]
|
||||
|
||||
# restore reactions, invalidate fission yields
|
||||
nuc.reactions.append(reaction)
|
||||
nuc.yield_data[1e6].yields *= 2
|
||||
|
||||
with pytest.raises(ValueError, match=r"fission yields.*1\.0*e"):
|
||||
nuc.validate(strict=True, quiet=False, tolerance=0.0)
|
||||
|
||||
with pytest.warns(UserWarning) as record:
|
||||
assert not nuc.validate(strict=False, quiet=False, tolerance=0.0)
|
||||
assert not nuc.validate(strict=False, quiet=True, tolerance=0.0)
|
||||
assert len(record) == 1
|
||||
assert "1.0" in record[0].message.args[0]
|
||||
|
||||
# invalidate everything, check that error is raised at decay modes
|
||||
|
||||
decay = nuc.decay_modes.pop()
|
||||
reaction = nuc.reactions.pop()
|
||||
|
||||
with pytest.raises(ValueError, match="decay mode"):
|
||||
nuc.validate(strict=True, quiet=False, tolerance=0.0)
|
||||
|
||||
# check for warnings
|
||||
# should be one warning for decay modes, reactions, fission yields
|
||||
|
||||
with pytest.warns(UserWarning) as record:
|
||||
assert not nuc.validate(strict=False, quiet=False, tolerance=0.0)
|
||||
assert not nuc.validate(strict=False, quiet=True, tolerance=0.0)
|
||||
assert len(record) == 3
|
||||
assert "decay mode" in record[0].message.args[0]
|
||||
assert "0 reaction" in record[1].message.args[0]
|
||||
assert "1.0" in record[2].message.args[0]
|
||||
89
tests/unit_tests/test_deplete_operator.py
Normal file
89
tests/unit_tests/test_deplete_operator.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
"""Basic unit tests for openmc.deplete.Operator instantiation
|
||||
|
||||
Modifies and resets environment variable OPENMC_CROSS_SECTIONS
|
||||
to a custom file with new depletion_chain node
|
||||
"""
|
||||
|
||||
from os import environ
|
||||
from unittest import mock
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from openmc.deplete.abc import TransportOperator
|
||||
from openmc.deplete.chain import Chain
|
||||
|
||||
BARE_XS_FILE = "bare_cross_sections.xml"
|
||||
CHAIN_PATH = Path(__file__).parents[1] / "chain_simple.xml"
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def bare_xs(run_in_tmpdir):
|
||||
"""Create a very basic cross_sections file, return simple Chain.
|
||||
|
||||
"""
|
||||
|
||||
bare_xs_contents = """<?xml version="1.0"?>
|
||||
<cross_sections>
|
||||
<depletion_chain path="{}" />
|
||||
</cross_sections>
|
||||
""".format(CHAIN_PATH)
|
||||
|
||||
with open(BARE_XS_FILE, "w") as out:
|
||||
out.write(bare_xs_contents)
|
||||
|
||||
yield
|
||||
|
||||
|
||||
class BareDepleteOperator(TransportOperator):
|
||||
"""Very basic class for testing the initialization."""
|
||||
|
||||
@staticmethod
|
||||
def __call__(*args, **kwargs):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def initial_condition():
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def get_results_info():
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def write_bos_data():
|
||||
pass
|
||||
|
||||
|
||||
@mock.patch.dict(environ, {"OPENMC_CROSS_SECTIONS": BARE_XS_FILE})
|
||||
def test_operator_init(bare_xs):
|
||||
"""The test will set and unset environment variable OPENMC_CROSS_SECTIONS
|
||||
to point towards a temporary dummy file. This file will be removed
|
||||
at the end of the test, and only contains a
|
||||
depletion_chain node."""
|
||||
# force operator to read from OPENMC_CROSS_SECTIONS
|
||||
bare_op = BareDepleteOperator(chain_file=None)
|
||||
act_chain = bare_op.chain
|
||||
ref_chain = Chain.from_xml(CHAIN_PATH)
|
||||
assert len(act_chain) == len(ref_chain)
|
||||
for name in ref_chain.nuclide_dict:
|
||||
# compare openmc.deplete.Nuclide objects
|
||||
ref_nuc = ref_chain[name]
|
||||
act_nuc = act_chain[name]
|
||||
for prop in [
|
||||
'name', 'half_life', 'decay_energy', 'reactions',
|
||||
'decay_modes', 'yield_data', 'yield_energies',
|
||||
]:
|
||||
assert getattr(act_nuc, prop) == getattr(ref_nuc, prop), prop
|
||||
|
||||
|
||||
def test_operator_fiss_q():
|
||||
"""Make sure fission q values can be set"""
|
||||
new_q = {"U235": 2.0E8, "U238": 2.0E8, "U234": 5.0E7}
|
||||
chain_file = Path(__file__).parents[1] / "chain_simple.xml"
|
||||
operator = BareDepleteOperator(chain_file=chain_file, fission_q=new_q)
|
||||
mod_chain = operator.chain
|
||||
for name, q in new_q.items():
|
||||
chain_nuc = mod_chain[name]
|
||||
for rx in chain_nuc.reactions:
|
||||
if rx.type == 'fission':
|
||||
assert rx.Q == q
|
||||
63
tests/unit_tests/test_deplete_reaction.py
Normal file
63
tests/unit_tests/test_deplete_reaction.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
"""Tests for the openmc.deplete.ReactionRates class."""
|
||||
|
||||
import numpy as np
|
||||
from openmc.deplete import ReactionRates
|
||||
|
||||
|
||||
def test_get_set():
|
||||
"""Tests the get/set methods."""
|
||||
|
||||
local_mats = ["10000", "10001"]
|
||||
nuclides = ["U238", "U235"]
|
||||
reactions = ["fission", "(n,gamma)"]
|
||||
|
||||
rates = ReactionRates(local_mats, nuclides, reactions)
|
||||
assert rates.shape == (2, 2, 2)
|
||||
assert np.all(rates == 0.0)
|
||||
|
||||
rates.set("10000", "U238", "fission", 1.0)
|
||||
rates.set("10001", "U238", "fission", 2.0)
|
||||
rates.set("10000", "U235", "fission", 3.0)
|
||||
rates.set("10001", "U235", "fission", 4.0)
|
||||
rates.set("10000", "U238", "(n,gamma)", 5.0)
|
||||
rates.set("10001", "U238", "(n,gamma)", 6.0)
|
||||
rates.set("10000", "U235", "(n,gamma)", 7.0)
|
||||
rates.set("10001", "U235", "(n,gamma)", 8.0)
|
||||
|
||||
# String indexing
|
||||
assert rates.get("10000", "U238", "fission") == 1.0
|
||||
assert rates.get("10001", "U238", "fission") == 2.0
|
||||
assert rates.get("10000", "U235", "fission") == 3.0
|
||||
assert rates.get("10001", "U235", "fission") == 4.0
|
||||
assert rates.get("10000", "U238", "(n,gamma)") == 5.0
|
||||
assert rates.get("10001", "U238", "(n,gamma)") == 6.0
|
||||
assert rates.get("10000", "U235", "(n,gamma)") == 7.0
|
||||
assert rates.get("10001", "U235", "(n,gamma)") == 8.0
|
||||
|
||||
# Int indexing
|
||||
assert rates[0, 0, 0] == 1.0
|
||||
assert rates[1, 0, 0] == 2.0
|
||||
assert rates[0, 1, 0] == 3.0
|
||||
assert rates[1, 1, 0] == 4.0
|
||||
assert rates[0, 0, 1] == 5.0
|
||||
assert rates[1, 0, 1] == 6.0
|
||||
assert rates[0, 1, 1] == 7.0
|
||||
assert rates[1, 1, 1] == 8.0
|
||||
|
||||
rates[0, 0, 0] = 5.0
|
||||
|
||||
assert rates[0, 0, 0] == 5.0
|
||||
assert rates.get("10000", "U238", "fission") == 5.0
|
||||
|
||||
|
||||
def test_properties():
|
||||
"""Test number of materials property."""
|
||||
local_mats = ["10000", "10001"]
|
||||
nuclides = ["U238", "U235", "Gd157"]
|
||||
reactions = ["fission", "(n,gamma)", "(n,2n)", "(n,3n)"]
|
||||
|
||||
rates = ReactionRates(local_mats, nuclides, reactions)
|
||||
|
||||
assert rates.n_mat == 2
|
||||
assert rates.n_nuc == 3
|
||||
assert rates.n_react == 4
|
||||
94
tests/unit_tests/test_deplete_restart.py
Normal file
94
tests/unit_tests/test_deplete_restart.py
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
"""Regression tests for openmc.deplete restart capability.
|
||||
|
||||
These tests run in two steps, a first run then a restart run, a simple test
|
||||
problem described in dummy_geometry.py.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
import openmc.deplete
|
||||
|
||||
from tests import dummy_operator
|
||||
|
||||
|
||||
def test_restart_predictor_cecm(run_in_tmpdir):
|
||||
"""Test to ensure that schemes with different stages are not compatible"""
|
||||
|
||||
op = dummy_operator.DummyOperator()
|
||||
output_dir = "test_restart_predictor_cecm"
|
||||
op.output_dir = output_dir
|
||||
|
||||
# Perform simulation using the predictor algorithm
|
||||
dt = [0.75]
|
||||
power = 1.0
|
||||
openmc.deplete.PredictorIntegrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
prev_res = openmc.deplete.ResultsList.from_hdf5(
|
||||
op.output_dir / "depletion_results.h5")
|
||||
|
||||
# Re-create depletion operator and load previous results
|
||||
op = dummy_operator.DummyOperator(prev_res)
|
||||
op.output_dir = output_dir
|
||||
|
||||
# check ValueError is raised, indicating previous and current stages
|
||||
with pytest.raises(ValueError, match="incompatible.* 1.*2"):
|
||||
openmc.deplete.CECMIntegrator(op, dt, power)
|
||||
|
||||
|
||||
def test_restart_cecm_predictor(run_in_tmpdir):
|
||||
"""Integral regression test of integrator algorithm using CE/CM for the
|
||||
first run then predictor for the restart run."""
|
||||
|
||||
op = dummy_operator.DummyOperator()
|
||||
output_dir = "test_restart_cecm_predictor"
|
||||
op.output_dir = output_dir
|
||||
|
||||
# Perform simulation using the MCNPX/MCNP6 algorithm
|
||||
dt = [0.75]
|
||||
power = 1.0
|
||||
cecm = openmc.deplete.CECMIntegrator(op, dt, power)
|
||||
cecm.integrate()
|
||||
|
||||
# Load the files
|
||||
prev_res = openmc.deplete.ResultsList.from_hdf5(
|
||||
op.output_dir / "depletion_results.h5")
|
||||
|
||||
# Re-create depletion operator and load previous results
|
||||
op = dummy_operator.DummyOperator(prev_res)
|
||||
op.output_dir = output_dir
|
||||
|
||||
# check ValueError is raised, indicating previous and current stages
|
||||
with pytest.raises(ValueError, match="incompatible.* 2.*1"):
|
||||
openmc.deplete.PredictorIntegrator(op, dt, power)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("scheme", dummy_operator.SCHEMES)
|
||||
def test_restart(run_in_tmpdir, scheme):
|
||||
# set up the problem
|
||||
|
||||
bundle = dummy_operator.SCHEMES[scheme]
|
||||
|
||||
operator = dummy_operator.DummyOperator()
|
||||
|
||||
# take first step
|
||||
bundle.solver(operator, [0.75], 1.0).integrate()
|
||||
|
||||
# restart
|
||||
prev_res = openmc.deplete.ResultsList.from_hdf5(
|
||||
operator.output_dir / "depletion_results.h5")
|
||||
operator = dummy_operator.DummyOperator(prev_res)
|
||||
|
||||
# take second step
|
||||
bundle.solver(operator, [0.75], 1.0).integrate()
|
||||
|
||||
# compare results
|
||||
|
||||
results = openmc.deplete.ResultsList.from_hdf5(
|
||||
operator.output_dir / "depletion_results.h5")
|
||||
|
||||
_t, y1 = results.get_atoms("1", "1")
|
||||
_t, y2 = results.get_atoms("1", "2")
|
||||
|
||||
assert y1 == pytest.approx(bundle.atoms_1)
|
||||
assert y2 == pytest.approx(bundle.atoms_2)
|
||||
51
tests/unit_tests/test_deplete_resultslist.py
Normal file
51
tests/unit_tests/test_deplete_resultslist.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
"""Tests the ResultsList class"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
import openmc.deplete
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def res():
|
||||
"""Load the reference results"""
|
||||
filename = (Path(__file__).parents[1] / 'regression_tests' / 'deplete'
|
||||
/ 'test_reference.h5')
|
||||
return openmc.deplete.ResultsList.from_hdf5(filename)
|
||||
|
||||
|
||||
def test_get_atoms(res):
|
||||
"""Tests evaluating single nuclide concentration."""
|
||||
t, n = res.get_atoms("1", "Xe135")
|
||||
|
||||
t_ref = [0.0, 1296000.0, 2592000.0, 3888000.0]
|
||||
n_ref = [6.67473282e+08, 3.76986925e+14, 3.68587383e+14, 3.91338675e+14]
|
||||
|
||||
np.testing.assert_allclose(t, t_ref)
|
||||
np.testing.assert_allclose(n, n_ref)
|
||||
|
||||
|
||||
def test_get_reaction_rate(res):
|
||||
"""Tests evaluating reaction rate."""
|
||||
t, r = res.get_reaction_rate("1", "Xe135", "(n,gamma)")
|
||||
|
||||
t_ref = [0.0, 1296000.0, 2592000.0, 3888000.0]
|
||||
n_ref = [6.67473282e+08, 3.76986925e+14, 3.68587383e+14, 3.91338675e+14]
|
||||
xs_ref = [3.32282266e-05, 2.76207120e-05, 4.10986677e-05, 3.72453665e-05]
|
||||
|
||||
np.testing.assert_allclose(t, t_ref)
|
||||
np.testing.assert_allclose(r, np.array(n_ref) * xs_ref)
|
||||
|
||||
|
||||
def test_get_eigenvalue(res):
|
||||
"""Tests evaluating eigenvalue."""
|
||||
t, k = res.get_eigenvalue()
|
||||
|
||||
t_ref = [0.0, 1296000.0, 2592000.0, 3888000.0]
|
||||
k_ref = [1.16984322, 1.19097427, 1.03012572, 1.20045627]
|
||||
u_ref = [0.0375587, 0.0347639, 0.07216021, 0.02839642]
|
||||
|
||||
np.testing.assert_allclose(t, t_ref)
|
||||
np.testing.assert_allclose(k[:, 0], k_ref)
|
||||
np.testing.assert_allclose(k[:, 1], u_ref)
|
||||
41
tests/unit_tests/test_element_wo.py
Normal file
41
tests/unit_tests/test_element_wo.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from openmc import Material
|
||||
from openmc.data import NATURAL_ABUNDANCE, atomic_mass
|
||||
|
||||
|
||||
def test_element_wo():
|
||||
# This test doesn't require an OpenMC run. We just need to make sure the
|
||||
# element.expand() method expands elements with the proper nuclide
|
||||
# compositions.
|
||||
|
||||
h_am = (NATURAL_ABUNDANCE['H1'] * atomic_mass('H1') +
|
||||
NATURAL_ABUNDANCE['H2'] * atomic_mass('H2'))
|
||||
o_am = (NATURAL_ABUNDANCE['O17'] * atomic_mass('O17') +
|
||||
(NATURAL_ABUNDANCE['O16'] + NATURAL_ABUNDANCE['O18'])
|
||||
* atomic_mass('O16'))
|
||||
water_am = 2 * h_am + o_am
|
||||
|
||||
water = Material()
|
||||
water.add_element('O', o_am / water_am, 'wo')
|
||||
water.add_element('H', 2 * h_am / water_am, 'wo')
|
||||
densities = water.get_nuclide_densities()
|
||||
|
||||
for nuc in densities.keys():
|
||||
assert nuc in ('H1', 'H2', 'O16', 'O17')
|
||||
|
||||
if nuc in ('H1', 'H2'):
|
||||
val = 2 * NATURAL_ABUNDANCE[nuc] * atomic_mass(nuc) / water_am
|
||||
assert densities[nuc][1] == pytest.approx(val)
|
||||
if nuc == 'O16':
|
||||
val = (NATURAL_ABUNDANCE[nuc] + NATURAL_ABUNDANCE['O18']) \
|
||||
* atomic_mass(nuc) / water_am
|
||||
assert densities[nuc][1] == pytest.approx(val)
|
||||
if nuc == 'O17':
|
||||
val = NATURAL_ABUNDANCE[nuc] * atomic_mass(nuc) / water_am
|
||||
assert densities[nuc][1] == pytest.approx(val)
|
||||
29
tests/unit_tests/test_endf.py
Normal file
29
tests/unit_tests/test_endf.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
from openmc.data import endf
|
||||
from pytest import approx
|
||||
|
||||
|
||||
def test_float_endf():
|
||||
assert endf.float_endf('+3.2146') == approx(3.2146)
|
||||
assert endf.float_endf('.12345') == approx(0.12345)
|
||||
assert endf.float_endf('6.022+23') == approx(6.022e23)
|
||||
assert endf.float_endf('6.022-23') == approx(6.022e-23)
|
||||
assert endf.float_endf(' +1.01+ 2') == approx(101.0)
|
||||
assert endf.float_endf(' -1.01- 2') == approx(-0.0101)
|
||||
assert endf.float_endf('+ 2 . 3+ 1') == approx(23.0)
|
||||
assert endf.float_endf('-7 .8 -1') == approx(-0.78)
|
||||
assert endf.float_endf('3.14e0') == approx(3.14)
|
||||
assert endf.float_endf('3.14E0') == approx(3.14)
|
||||
assert endf.float_endf('3.14e-1') == approx(0.314)
|
||||
assert endf.float_endf('3.14d0') == approx(3.14)
|
||||
assert endf.float_endf('3.14D0') == approx(3.14)
|
||||
assert endf.float_endf('3.14d-1') == approx(0.314)
|
||||
assert endf.float_endf('1+2') == approx(100.0)
|
||||
assert endf.float_endf('-1+2') == approx(-100.0)
|
||||
assert endf.float_endf('1.+2') == approx(100.0)
|
||||
assert endf.float_endf('-1.+2') == approx(-100.0)
|
||||
assert endf.float_endf(' ') == 0.0
|
||||
|
||||
|
||||
def test_int_endf():
|
||||
assert endf.int_endf(' ') == 0
|
||||
assert endf.int_endf('+4032') == 4032
|
||||
165
tests/unit_tests/test_filters.py
Normal file
165
tests/unit_tests/test_filters.py
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
from math import sqrt, pi
|
||||
|
||||
import openmc
|
||||
from pytest import fixture, approx
|
||||
|
||||
|
||||
@fixture(scope='module')
|
||||
def box_model():
|
||||
model = openmc.model.Model()
|
||||
m = openmc.Material()
|
||||
m.add_nuclide('U235', 1.0)
|
||||
m.set_density('g/cm3', 1.0)
|
||||
|
||||
box = openmc.model.rectangular_prism(10., 10., boundary_type='vacuum')
|
||||
c = openmc.Cell(fill=m, region=box)
|
||||
model.geometry.root_universe = openmc.Universe(cells=[c])
|
||||
|
||||
model.settings.particles = 100
|
||||
model.settings.batches = 10
|
||||
model.settings.inactive = 0
|
||||
model.settings.source = openmc.Source(space=openmc.stats.Point())
|
||||
return model
|
||||
|
||||
|
||||
def test_legendre():
|
||||
n = 5
|
||||
f = openmc.LegendreFilter(n)
|
||||
assert f.order == n
|
||||
assert f.bins[0] == 'P0'
|
||||
assert f.bins[-1] == 'P5'
|
||||
assert len(f.bins) == n + 1
|
||||
|
||||
# Make sure __repr__ works
|
||||
repr(f)
|
||||
|
||||
# to_xml_element()
|
||||
elem = f.to_xml_element()
|
||||
assert elem.tag == 'filter'
|
||||
assert elem.attrib['type'] == 'legendre'
|
||||
assert elem.find('order').text == str(n)
|
||||
|
||||
|
||||
def test_spatial_legendre():
|
||||
n = 5
|
||||
axis = 'x'
|
||||
f = openmc.SpatialLegendreFilter(n, axis, -10., 10.)
|
||||
assert f.order == n
|
||||
assert f.axis == axis
|
||||
assert f.minimum == -10.
|
||||
assert f.maximum == 10.
|
||||
assert f.bins[0] == 'P0'
|
||||
assert f.bins[-1] == 'P5'
|
||||
assert len(f.bins) == n + 1
|
||||
|
||||
# Make sure __repr__ works
|
||||
repr(f)
|
||||
|
||||
# to_xml_element()
|
||||
elem = f.to_xml_element()
|
||||
assert elem.tag == 'filter'
|
||||
assert elem.attrib['type'] == 'spatiallegendre'
|
||||
assert elem.find('order').text == str(n)
|
||||
assert elem.find('axis').text == str(axis)
|
||||
|
||||
|
||||
def test_spherical_harmonics():
|
||||
n = 3
|
||||
f = openmc.SphericalHarmonicsFilter(n)
|
||||
f.cosine = 'particle'
|
||||
assert f.order == n
|
||||
assert f.bins[0] == 'Y0,0'
|
||||
assert f.bins[-1] == 'Y{0},{0}'.format(n, n)
|
||||
assert len(f.bins) == (n + 1)**2
|
||||
|
||||
# Make sure __repr__ works
|
||||
repr(f)
|
||||
|
||||
# to_xml_element()
|
||||
elem = f.to_xml_element()
|
||||
assert elem.tag == 'filter'
|
||||
assert elem.attrib['type'] == 'sphericalharmonics'
|
||||
assert elem.attrib['cosine'] == f.cosine
|
||||
assert elem.find('order').text == str(n)
|
||||
|
||||
|
||||
def test_zernike():
|
||||
n = 4
|
||||
f = openmc.ZernikeFilter(n, 0., 0., 1.)
|
||||
assert f.order == n
|
||||
assert f.bins[0] == 'Z0,0'
|
||||
assert f.bins[-1] == 'Z{0},{0}'.format(n)
|
||||
assert len(f.bins) == (n + 1)*(n + 2)//2
|
||||
|
||||
# Make sure __repr__ works
|
||||
repr(f)
|
||||
|
||||
# to_xml_element()
|
||||
elem = f.to_xml_element()
|
||||
assert elem.tag == 'filter'
|
||||
assert elem.attrib['type'] == 'zernike'
|
||||
assert elem.find('order').text == str(n)
|
||||
|
||||
def test_zernike_radial():
|
||||
n = 4
|
||||
f = openmc.ZernikeRadialFilter(n, 0., 0., 1.)
|
||||
assert f.order == n
|
||||
assert f.bins[0] == 'Z0,0'
|
||||
assert f.bins[-1] == 'Z{},0'.format(n)
|
||||
assert len(f.bins) == n//2 + 1
|
||||
|
||||
# Make sure __repr__ works
|
||||
repr(f)
|
||||
|
||||
# to_xml_element()
|
||||
elem = f.to_xml_element()
|
||||
assert elem.tag == 'filter'
|
||||
assert elem.attrib['type'] == 'zernikeradial'
|
||||
assert elem.find('order').text == str(n)
|
||||
|
||||
|
||||
def test_first_moment(run_in_tmpdir, box_model):
|
||||
plain_tally = openmc.Tally()
|
||||
plain_tally.scores = ['flux', 'scatter']
|
||||
|
||||
# Create tallies with expansion filters
|
||||
leg_tally = openmc.Tally()
|
||||
leg_tally.filters = [openmc.LegendreFilter(3)]
|
||||
leg_tally.scores = ['scatter']
|
||||
leg_sptl_tally = openmc.Tally()
|
||||
leg_sptl_tally.filters = [openmc.SpatialLegendreFilter(3, 'x', -5., 5.)]
|
||||
leg_sptl_tally.scores = ['scatter']
|
||||
sph_scat_filter = openmc.SphericalHarmonicsFilter(5)
|
||||
sph_scat_filter.cosine = 'scatter'
|
||||
sph_scat_tally = openmc.Tally()
|
||||
sph_scat_tally.filters = [sph_scat_filter]
|
||||
sph_scat_tally.scores = ['scatter']
|
||||
sph_flux_filter = openmc.SphericalHarmonicsFilter(5)
|
||||
sph_flux_filter.cosine = 'particle'
|
||||
sph_flux_tally = openmc.Tally()
|
||||
sph_flux_tally.filters = [sph_flux_filter]
|
||||
sph_flux_tally.scores = ['flux']
|
||||
zernike_tally = openmc.Tally()
|
||||
zernike_tally.filters = [openmc.ZernikeFilter(3, r=10.)]
|
||||
zernike_tally.scores = ['scatter']
|
||||
|
||||
# Add tallies to model and ensure they all use the same estimator
|
||||
box_model.tallies = [plain_tally, leg_tally, leg_sptl_tally,
|
||||
sph_scat_tally, sph_flux_tally, zernike_tally]
|
||||
for t in box_model.tallies:
|
||||
t.estimator = 'analog'
|
||||
|
||||
box_model.run()
|
||||
|
||||
# Check that first moment matches the score from the plain tally
|
||||
with openmc.StatePoint('statepoint.10.h5') as sp:
|
||||
# Get scores from tally without expansion filters
|
||||
flux, scatter = sp.tallies[plain_tally.id].mean.ravel()
|
||||
|
||||
# Check that first moment matches
|
||||
first_score = lambda t: sp.tallies[t.id].mean.ravel()[0]
|
||||
assert first_score(leg_tally) == scatter
|
||||
assert first_score(leg_sptl_tally) == scatter
|
||||
assert first_score(sph_scat_tally) == scatter
|
||||
assert first_score(sph_flux_tally) == approx(flux)
|
||||
assert first_score(zernike_tally) == approx(scatter)
|
||||
282
tests/unit_tests/test_geometry.py
Normal file
282
tests/unit_tests/test_geometry.py
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
import xml.etree.ElementTree as ET
|
||||
|
||||
import numpy as np
|
||||
import openmc
|
||||
import pytest
|
||||
|
||||
|
||||
def test_volume(run_in_tmpdir, uo2):
|
||||
"""Test adding volume information from a volume calculation."""
|
||||
# Create model with nested spheres
|
||||
model = openmc.model.Model()
|
||||
model.materials.append(uo2)
|
||||
inner = openmc.Sphere(r=1.)
|
||||
outer = openmc.Sphere(r=2., boundary_type='vacuum')
|
||||
c1 = openmc.Cell(fill=uo2, region=-inner)
|
||||
c2 = openmc.Cell(region=+inner & -outer)
|
||||
u = openmc.Universe(cells=[c1, c2])
|
||||
model.geometry.root_universe = u
|
||||
model.settings.particles = 100
|
||||
model.settings.batches = 10
|
||||
model.settings.run_mode = 'fixed source'
|
||||
model.settings.source = openmc.Source(space=openmc.stats.Point())
|
||||
|
||||
ll, ur = model.geometry.bounding_box
|
||||
assert ll == pytest.approx((-outer.r, -outer.r, -outer.r))
|
||||
assert ur == pytest.approx((outer.r, outer.r, outer.r))
|
||||
model.settings.volume_calculations
|
||||
|
||||
for domain in (c1, uo2, u):
|
||||
# Run stochastic volume calculation
|
||||
volume_calc = openmc.VolumeCalculation(
|
||||
domains=[domain], samples=1000, lower_left=ll, upper_right=ur)
|
||||
model.settings.volume_calculations = [volume_calc]
|
||||
model.export_to_xml()
|
||||
openmc.calculate_volumes()
|
||||
|
||||
# Load results and add volume information
|
||||
volume_calc.load_results('volume_1.h5')
|
||||
model.geometry.add_volume_information(volume_calc)
|
||||
|
||||
# get_nuclide_densities relies on volume information
|
||||
nucs = set(domain.get_nuclide_densities())
|
||||
assert not nucs ^ {'U235', 'O16'}
|
||||
|
||||
|
||||
def test_export_xml(run_in_tmpdir, uo2):
|
||||
s1 = openmc.Sphere(r=1.)
|
||||
s2 = openmc.Sphere(r=2., boundary_type='reflective')
|
||||
c1 = openmc.Cell(fill=uo2, region=-s1)
|
||||
c2 = openmc.Cell(fill=uo2, region=+s1 & -s2)
|
||||
geom = openmc.Geometry([c1, c2])
|
||||
geom.export_to_xml()
|
||||
|
||||
doc = ET.parse('geometry.xml')
|
||||
root = doc.getroot()
|
||||
assert root.tag == 'geometry'
|
||||
cells = root.findall('cell')
|
||||
assert [int(c.get('id')) for c in cells] == [c1.id, c2.id]
|
||||
surfs = root.findall('surface')
|
||||
assert [int(s.get('id')) for s in surfs] == [s1.id, s2.id]
|
||||
|
||||
|
||||
def test_find(uo2):
|
||||
xp = openmc.XPlane()
|
||||
c1 = openmc.Cell(fill=uo2, region=+xp)
|
||||
c2 = openmc.Cell(region=-xp)
|
||||
u1 = openmc.Universe(cells=(c1, c2))
|
||||
|
||||
cyl = openmc.ZCylinder()
|
||||
c3 = openmc.Cell(fill=u1, region=-cyl)
|
||||
c4 = openmc.Cell(region=+cyl)
|
||||
geom = openmc.Geometry((c3, c4))
|
||||
|
||||
seq = geom.find((0.5, 0., 0.))
|
||||
assert seq[-1] == c1
|
||||
seq = geom.find((-0.5, 0., 0.))
|
||||
assert seq[-1] == c2
|
||||
seq = geom.find((-1.5, 0., 0.))
|
||||
assert seq[-1] == c4
|
||||
|
||||
|
||||
def test_get_all_cells():
|
||||
cells = [openmc.Cell() for i in range(5)]
|
||||
cells2 = [openmc.Cell() for i in range(3)]
|
||||
cells[0].fill = openmc.Universe(cells=cells2)
|
||||
geom = openmc.Geometry(cells)
|
||||
|
||||
all_cells = set(geom.get_all_cells().values())
|
||||
assert not all_cells ^ set(cells + cells2)
|
||||
|
||||
|
||||
def test_get_all_materials():
|
||||
m1 = openmc.Material()
|
||||
m2 = openmc.Material()
|
||||
c1 = openmc.Cell(fill=m1)
|
||||
u1 = openmc.Universe(cells=[c1])
|
||||
|
||||
s = openmc.Sphere()
|
||||
c2 = openmc.Cell(fill=u1, region=-s)
|
||||
c3 = openmc.Cell(fill=m2, region=+s)
|
||||
geom = openmc.Geometry([c2, c3])
|
||||
|
||||
all_mats = set(geom.get_all_materials().values())
|
||||
assert not all_mats ^ {m1, m2}
|
||||
|
||||
|
||||
def test_get_all_material_cells():
|
||||
m1 = openmc.Material()
|
||||
m2 = openmc.Material()
|
||||
c1 = openmc.Cell(fill=m1)
|
||||
u1 = openmc.Universe(cells=[c1])
|
||||
|
||||
s = openmc.Sphere()
|
||||
c2 = openmc.Cell(fill=u1, region=-s)
|
||||
c3 = openmc.Cell(fill=m2, region=+s)
|
||||
geom = openmc.Geometry([c2, c3])
|
||||
|
||||
all_cells = set(geom.get_all_material_cells().values())
|
||||
assert not all_cells ^ {c1, c3}
|
||||
|
||||
|
||||
def test_get_all_material_universes():
|
||||
m1 = openmc.Material()
|
||||
m2 = openmc.Material()
|
||||
c1 = openmc.Cell(fill=m1)
|
||||
u1 = openmc.Universe(cells=[c1])
|
||||
|
||||
s = openmc.Sphere()
|
||||
c2 = openmc.Cell(fill=u1, region=-s)
|
||||
c3 = openmc.Cell(fill=m2, region=+s)
|
||||
geom = openmc.Geometry([c2, c3])
|
||||
|
||||
all_univs = set(geom.get_all_material_universes().values())
|
||||
assert not all_univs ^ {u1, geom.root_universe}
|
||||
|
||||
|
||||
def test_get_all_lattices(cell_with_lattice):
|
||||
cells, mats, univ, lattice = cell_with_lattice
|
||||
geom = openmc.Geometry([cells[-1]])
|
||||
|
||||
lats = list(geom.get_all_lattices().values())
|
||||
assert lats == [lattice]
|
||||
|
||||
|
||||
def test_get_all_surfaces(uo2):
|
||||
planes = [openmc.ZPlane(z0=z) for z in np.linspace(-100., 100.)]
|
||||
slabs = []
|
||||
for region in openmc.model.subdivide(planes):
|
||||
slabs.append(openmc.Cell(fill=uo2, region=region))
|
||||
geom = openmc.Geometry(slabs)
|
||||
|
||||
surfs = set(geom.get_all_surfaces().values())
|
||||
assert not surfs ^ set(planes)
|
||||
|
||||
|
||||
def test_get_by_name():
|
||||
m1 = openmc.Material(name='zircaloy')
|
||||
m1.add_element('Zr', 1.0)
|
||||
m2 = openmc.Material(name='Zirconium')
|
||||
m2.add_element('Zr', 1.0)
|
||||
|
||||
c1 = openmc.Cell(fill=m1, name='cell1')
|
||||
u1 = openmc.Universe(name='Zircaloy universe', cells=[c1])
|
||||
|
||||
cyl = openmc.ZCylinder()
|
||||
c2 = openmc.Cell(fill=u1, region=-cyl, name='cell2')
|
||||
c3 = openmc.Cell(fill=m2, region=+cyl, name='Cell3')
|
||||
root = openmc.Universe(name='root Universe', cells=[c2, c3])
|
||||
geom = openmc.Geometry(root)
|
||||
|
||||
mats = set(geom.get_materials_by_name('zirc'))
|
||||
assert not mats ^ {m1, m2}
|
||||
mats = set(geom.get_materials_by_name('zirc', True))
|
||||
assert not mats ^ {m1}
|
||||
mats = set(geom.get_materials_by_name('zirconium', False, True))
|
||||
assert not mats ^ {m2}
|
||||
mats = geom.get_materials_by_name('zirconium', True, True)
|
||||
assert not mats
|
||||
|
||||
cells = set(geom.get_cells_by_name('cell'))
|
||||
assert not cells ^ {c1, c2, c3}
|
||||
cells = set(geom.get_cells_by_name('cell', True))
|
||||
assert not cells ^ {c1, c2}
|
||||
cells = set(geom.get_cells_by_name('cell3', False, True))
|
||||
assert not cells ^ {c3}
|
||||
cells = geom.get_cells_by_name('cell3', True, True)
|
||||
assert not cells
|
||||
|
||||
cells = set(geom.get_cells_by_fill_name('Zircaloy'))
|
||||
assert not cells ^ {c1, c2}
|
||||
cells = set(geom.get_cells_by_fill_name('Zircaloy', True))
|
||||
assert not cells ^ {c2}
|
||||
cells = set(geom.get_cells_by_fill_name('Zircaloy', False, True))
|
||||
assert not cells ^ {c1}
|
||||
cells = geom.get_cells_by_fill_name('Zircaloy', True, True)
|
||||
assert not cells
|
||||
|
||||
univs = set(geom.get_universes_by_name('universe'))
|
||||
assert not univs ^ {u1, root}
|
||||
univs = set(geom.get_universes_by_name('universe', True))
|
||||
assert not univs ^ {u1}
|
||||
univs = set(geom.get_universes_by_name('universe', True, True))
|
||||
assert not univs
|
||||
|
||||
|
||||
def test_hex_prism():
|
||||
hex_prism = openmc.model.hexagonal_prism(edge_length=5.0,
|
||||
origin=(0.0, 0.0),
|
||||
orientation='y')
|
||||
# clear checks
|
||||
assert (0.0, 0.0, 0.0) in hex_prism
|
||||
assert (10.0, 10.0, 10.0) not in hex_prism
|
||||
# edge checks
|
||||
assert (0.0, 5.01, 0.0) not in hex_prism
|
||||
assert (0.0, 4.99, 0.0) in hex_prism
|
||||
|
||||
rounded_hex_prism = openmc.model.hexagonal_prism(edge_length=5.0,
|
||||
origin=(0.0, 0.0),
|
||||
orientation='y',
|
||||
corner_radius=1.0)
|
||||
|
||||
# clear checks
|
||||
assert (0.0, 0.0, 0.0) in rounded_hex_prism
|
||||
assert (10.0, 10.0, 10.0) not in rounded_hex_prism
|
||||
# edge checks
|
||||
assert (0.0, 5.01, 0.0) not in rounded_hex_prism
|
||||
assert (0.0, 4.99, 0.0) not in rounded_hex_prism
|
||||
|
||||
|
||||
def test_get_lattice_by_name(cell_with_lattice):
|
||||
cells, _, _, lattice = cell_with_lattice
|
||||
geom = openmc.Geometry([cells[-1]])
|
||||
|
||||
f = geom.get_lattices_by_name
|
||||
assert f('lattice') == [lattice]
|
||||
assert f('lattice', True) == []
|
||||
assert f('Lattice', True) == [lattice]
|
||||
assert f('my lattice', False, True) == [lattice]
|
||||
assert f('my lattice', True, True) == []
|
||||
|
||||
|
||||
def test_clone():
|
||||
c1 = openmc.Cell()
|
||||
c2 = openmc.Cell()
|
||||
root = openmc.Universe(cells=[c1, c2])
|
||||
geom = openmc.Geometry(root)
|
||||
|
||||
clone = geom.clone()
|
||||
root_clone = clone.root_universe
|
||||
|
||||
assert root.id != root_clone.id
|
||||
assert not (set(root.cells) & set(root_clone.cells))
|
||||
|
||||
|
||||
def test_determine_paths(cell_with_lattice):
|
||||
cells, mats, univ, lattice = cell_with_lattice
|
||||
u = openmc.Universe(cells=[cells[-1]])
|
||||
geom = openmc.Geometry(u)
|
||||
|
||||
geom.determine_paths()
|
||||
assert len(cells[0].paths) == 4
|
||||
assert len(cells[1].paths) == 4
|
||||
assert len(cells[2].paths) == 1
|
||||
assert len(mats[0].paths) == 1
|
||||
assert len(mats[-1].paths) == 4
|
||||
|
||||
# Test get_instances
|
||||
for i in range(4):
|
||||
assert geom.get_instances(cells[0].paths[i]) == i
|
||||
assert geom.get_instances(mats[-1].paths[i]) == i
|
||||
|
||||
|
||||
def test_from_xml(run_in_tmpdir, mixed_lattice_model):
|
||||
# Export model
|
||||
mixed_lattice_model.export_to_xml()
|
||||
|
||||
# Import geometry
|
||||
geom = openmc.Geometry.from_xml()
|
||||
assert isinstance(geom, openmc.Geometry)
|
||||
ll, ur = geom.bounding_box
|
||||
assert ll == pytest.approx((-6.0, -6.0, -np.inf))
|
||||
assert ur == pytest.approx((6.0, 6.0, np.inf))
|
||||
353
tests/unit_tests/test_lattice.py
Normal file
353
tests/unit_tests/test_lattice.py
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
from math import sqrt
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import openmc
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def pincell1(uo2, water):
|
||||
cyl = openmc.ZCylinder(r=0.35)
|
||||
fuel = openmc.Cell(fill=uo2, region=-cyl)
|
||||
moderator = openmc.Cell(fill=water, region=+cyl)
|
||||
|
||||
univ = openmc.Universe(cells=[fuel, moderator])
|
||||
univ.fuel = fuel
|
||||
univ.moderator = moderator
|
||||
return univ
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def pincell2(uo2, water):
|
||||
cyl = openmc.ZCylinder(r=0.4)
|
||||
fuel = openmc.Cell(fill=uo2, region=-cyl)
|
||||
moderator = openmc.Cell(fill=water, region=+cyl)
|
||||
|
||||
univ = openmc.Universe(cells=[fuel, moderator])
|
||||
univ.fuel = fuel
|
||||
univ.moderator = moderator
|
||||
return univ
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def zr():
|
||||
zr = openmc.Material()
|
||||
zr.add_element('Zr', 1.0)
|
||||
zr.set_density('g/cm3', 1.0)
|
||||
return zr
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def rlat2(pincell1, pincell2, uo2, water, zr):
|
||||
"""2D Rectangular lattice for testing."""
|
||||
all_zr = openmc.Cell(fill=zr)
|
||||
pitch = 1.2
|
||||
n = 3
|
||||
u1, u2 = pincell1, pincell2
|
||||
lattice = openmc.RectLattice()
|
||||
lattice.lower_left = (-pitch*n/2, -pitch*n/2)
|
||||
lattice.pitch = (pitch, pitch)
|
||||
lattice.outer = openmc.Universe(cells=[all_zr])
|
||||
lattice.universes = [
|
||||
[u1, u2, u1],
|
||||
[u2, u1, u2],
|
||||
[u2, u1, u1]
|
||||
]
|
||||
|
||||
# Add extra attributes for comparison purpose
|
||||
lattice.cells = [u1.fuel, u1.moderator, u2.fuel, u2.moderator, all_zr]
|
||||
lattice.mats = [uo2, water, zr]
|
||||
lattice.univs = [u1, u2, lattice.outer]
|
||||
return lattice
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def rlat3(pincell1, pincell2, uo2, water, zr):
|
||||
"""3D Rectangular lattice for testing."""
|
||||
|
||||
# Create another universe for top layer
|
||||
hydrogen = openmc.Material()
|
||||
hydrogen.add_element('H', 1.0)
|
||||
hydrogen.set_density('g/cm3', 0.09)
|
||||
h_cell = openmc.Cell(fill=hydrogen)
|
||||
u3 = openmc.Universe(cells=[h_cell])
|
||||
|
||||
all_zr = openmc.Cell(fill=zr)
|
||||
pitch = 1.2
|
||||
n = 3
|
||||
u1, u2 = pincell1, pincell2
|
||||
lattice = openmc.RectLattice()
|
||||
lattice.lower_left = (-pitch*n/2, -pitch*n/2, -10.0)
|
||||
lattice.pitch = (pitch, pitch, 10.0)
|
||||
lattice.outer = openmc.Universe(cells=[all_zr])
|
||||
lattice.universes = [
|
||||
[[u1, u2, u1],
|
||||
[u2, u1, u2],
|
||||
[u2, u1, u1]],
|
||||
[[u3, u1, u2],
|
||||
[u1, u3, u2],
|
||||
[u2, u1, u1]]
|
||||
]
|
||||
|
||||
# Add extra attributes for comparison purpose
|
||||
lattice.cells = [u1.fuel, u1.moderator, u2.fuel, u2.moderator,
|
||||
h_cell, all_zr]
|
||||
lattice.mats = [uo2, water, zr, hydrogen]
|
||||
lattice.univs = [u1, u2, u3, lattice.outer]
|
||||
return lattice
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def hlat2(pincell1, pincell2, uo2, water, zr):
|
||||
"""2D Hexagonal lattice for testing."""
|
||||
all_zr = openmc.Cell(fill=zr)
|
||||
pitch = 1.2
|
||||
u1, u2 = pincell1, pincell2
|
||||
lattice = openmc.HexLattice()
|
||||
lattice.center = (0., 0.)
|
||||
lattice.pitch = (pitch,)
|
||||
lattice.outer = openmc.Universe(cells=[all_zr])
|
||||
lattice.universes = [
|
||||
[u2, u1, u1, u1, u1, u1, u1, u1, u1, u1, u1, u1],
|
||||
[u2, u1, u1, u1, u1, u1],
|
||||
[u2]
|
||||
]
|
||||
|
||||
# Add extra attributes for comparison purpose
|
||||
lattice.cells = [u1.fuel, u1.moderator, u2.fuel, u2.moderator, all_zr]
|
||||
lattice.mats = [uo2, water, zr]
|
||||
lattice.univs = [u1, u2, lattice.outer]
|
||||
return lattice
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def hlat3(pincell1, pincell2, uo2, water, zr):
|
||||
"""3D Hexagonal lattice for testing."""
|
||||
|
||||
# Create another universe for top layer
|
||||
hydrogen = openmc.Material()
|
||||
hydrogen.add_element('H', 1.0)
|
||||
hydrogen.set_density('g/cm3', 0.09)
|
||||
h_cell = openmc.Cell(fill=hydrogen)
|
||||
u3 = openmc.Universe(cells=[h_cell])
|
||||
|
||||
all_zr = openmc.Cell(fill=zr)
|
||||
pitch = 1.2
|
||||
u1, u2 = pincell1, pincell2
|
||||
lattice = openmc.HexLattice()
|
||||
lattice.center = (0., 0., 0.)
|
||||
lattice.pitch = (pitch, 10.0)
|
||||
lattice.outer = openmc.Universe(cells=[all_zr])
|
||||
lattice.universes = [
|
||||
[[u2, u1, u1, u1, u1, u1, u1, u1, u1, u1, u1, u1],
|
||||
[u2, u1, u1, u1, u1, u1],
|
||||
[u2]],
|
||||
[[u1, u1, u1, u1, u1, u1, u3, u1, u1, u1, u1, u1],
|
||||
[u1, u1, u1, u3, u1, u1],
|
||||
[u3]]
|
||||
]
|
||||
|
||||
# Add extra attributes for comparison purpose
|
||||
lattice.cells = [u1.fuel, u1.moderator, u2.fuel, u2.moderator,
|
||||
h_cell, all_zr]
|
||||
lattice.mats = [uo2, water, zr, hydrogen]
|
||||
lattice.univs = [u1, u2, u3, lattice.outer]
|
||||
return lattice
|
||||
|
||||
|
||||
def test_get_nuclides(rlat2, rlat3, hlat2, hlat3):
|
||||
for lat in (rlat2, hlat2):
|
||||
nucs = rlat2.get_nuclides()
|
||||
assert sorted(nucs) == ['H1', 'O16', 'U235',
|
||||
'Zr90', 'Zr91', 'Zr92', 'Zr94', 'Zr96']
|
||||
for lat in (rlat3, hlat3):
|
||||
nucs = rlat3.get_nuclides()
|
||||
assert sorted(nucs) == ['H1', 'H2', 'O16', 'U235',
|
||||
'Zr90', 'Zr91', 'Zr92', 'Zr94', 'Zr96']
|
||||
|
||||
|
||||
def test_get_all_cells(rlat2, rlat3, hlat2, hlat3):
|
||||
for lat in (rlat2, rlat3, hlat2, hlat3):
|
||||
cells = set(lat.get_all_cells().values())
|
||||
assert not cells ^ set(lat.cells)
|
||||
|
||||
|
||||
def test_get_all_materials(rlat2, rlat3, hlat2, hlat3):
|
||||
for lat in (rlat2, rlat3, hlat2, hlat3):
|
||||
mats = set(lat.get_all_materials().values())
|
||||
assert not mats ^ set(lat.mats)
|
||||
|
||||
|
||||
def test_get_all_universes(rlat2, rlat3, hlat2, hlat3):
|
||||
for lat in (rlat2, rlat3, hlat2, hlat3):
|
||||
univs = set(lat.get_all_universes().values())
|
||||
assert not univs ^ set(lat.univs)
|
||||
|
||||
|
||||
def test_get_universe(rlat2, rlat3, hlat2, hlat3):
|
||||
u1, u2, outer = rlat2.univs
|
||||
assert rlat2.get_universe((0, 0)) == u2
|
||||
assert rlat2.get_universe((1, 0)) == u1
|
||||
assert rlat2.get_universe((0, 1)) == u2
|
||||
|
||||
u1, u2, u3, outer = rlat3.univs
|
||||
assert rlat3.get_universe((0, 0, 0)) == u2
|
||||
assert rlat3.get_universe((2, 2, 0)) == u1
|
||||
assert rlat3.get_universe((0, 2, 1)) == u3
|
||||
assert rlat3.get_universe((2, 1, 1)) == u2
|
||||
|
||||
u1, u2, outer = hlat2.univs
|
||||
assert hlat2.get_universe((0, 0)) == u2
|
||||
assert hlat2.get_universe((0, 2)) == u2
|
||||
assert hlat2.get_universe((1, 0)) == u1
|
||||
assert hlat2.get_universe((-2, 2)) == u1
|
||||
|
||||
hlat2.orientation = 'x'
|
||||
assert hlat2.get_universe((2, 0)) == u2
|
||||
assert hlat2.get_universe((1, 0)) == u2
|
||||
assert hlat2.get_universe((1, 1)) == u1
|
||||
assert hlat2.get_universe((-1, 1)) == u1
|
||||
hlat2.orientation = 'y'
|
||||
|
||||
u1, u2, u3, outer = hlat3.univs
|
||||
assert hlat3.get_universe((0, 0, 0)) == u2
|
||||
assert hlat3.get_universe((0, 0, 1)) == u3
|
||||
assert hlat3.get_universe((0, 2, 0)) == u2
|
||||
assert hlat3.get_universe((0, 2, 1)) == u1
|
||||
assert hlat3.get_universe((0, -2, 0)) == u1
|
||||
assert hlat3.get_universe((0, -2, 1)) == u3
|
||||
|
||||
|
||||
def test_find(rlat2, rlat3, hlat2, hlat3):
|
||||
pitch = rlat2.pitch[0]
|
||||
seq = rlat2.find((0., 0., 0.))
|
||||
assert seq[-1] == rlat2.cells[0]
|
||||
seq = rlat2.find((pitch, 0., 0.))
|
||||
assert seq[-1] == rlat2.cells[2]
|
||||
seq = rlat2.find((0., -pitch, 0.))
|
||||
assert seq[-1] == rlat2.cells[0]
|
||||
seq = rlat2.find((pitch*100, 0., 0.))
|
||||
assert seq[-1] == rlat2.cells[-1]
|
||||
seq = rlat3.find((-pitch, pitch, 5.0))
|
||||
assert seq[-1] == rlat3.cells[-2]
|
||||
|
||||
pitch = hlat2.pitch[0]
|
||||
seq = hlat2.find((0., 0., 0.))
|
||||
assert seq[-1] == hlat2.cells[2]
|
||||
seq = hlat2.find((0.5, 0., 0.))
|
||||
assert seq[-1] == hlat2.cells[3]
|
||||
seq = hlat2.find((sqrt(3)*pitch, 0., 0.))
|
||||
assert seq[-1] == hlat2.cells[0]
|
||||
seq = hlat2.find((0., pitch, 0.))
|
||||
assert seq[-1] == hlat2.cells[2]
|
||||
|
||||
# bottom of 3D lattice
|
||||
seq = hlat3.find((0., 0., -5.))
|
||||
assert seq[-1] == hlat3.cells[2]
|
||||
seq = hlat3.find((0., pitch, -5.))
|
||||
assert seq[-1] == hlat3.cells[2]
|
||||
seq = hlat3.find((0., -pitch, -5.))
|
||||
assert seq[-1] == hlat3.cells[0]
|
||||
seq = hlat3.find((sqrt(3)*pitch, 0., -5.))
|
||||
assert seq[-1] == hlat3.cells[0]
|
||||
|
||||
# top of 3D lattice
|
||||
seq = hlat3.find((0., 0., 5.))
|
||||
assert seq[-1] == hlat3.cells[-2]
|
||||
seq = hlat3.find((0., pitch, 5.))
|
||||
assert seq[-1] == hlat3.cells[0]
|
||||
seq = hlat3.find((0., -pitch, 5.))
|
||||
assert seq[-1] == hlat3.cells[-2]
|
||||
seq = hlat3.find((sqrt(3)*pitch, 0., 5.))
|
||||
assert seq[-1] == hlat3.cells[0]
|
||||
|
||||
|
||||
def test_clone(rlat2, hlat2, hlat3):
|
||||
rlat_clone = rlat2.clone()
|
||||
assert rlat_clone.id != rlat2.id
|
||||
assert rlat_clone.lower_left == rlat2.lower_left
|
||||
assert rlat_clone.pitch == rlat2.pitch
|
||||
|
||||
hlat_clone = hlat2.clone()
|
||||
assert hlat_clone.id != hlat2.id
|
||||
assert hlat_clone.center == hlat2.center
|
||||
assert hlat_clone.pitch == hlat2.pitch
|
||||
|
||||
hlat_clone = hlat3.clone()
|
||||
assert hlat_clone.id != hlat3.id
|
||||
assert hlat_clone.center == hlat3.center
|
||||
assert hlat_clone.pitch == hlat3.pitch
|
||||
|
||||
|
||||
def test_repr(rlat2, rlat3, hlat2, hlat3):
|
||||
repr(rlat2)
|
||||
repr(rlat3)
|
||||
repr(hlat2)
|
||||
repr(hlat3)
|
||||
|
||||
|
||||
def test_indices_rect(rlat2, rlat3):
|
||||
# (y, x) indices
|
||||
assert rlat2.indices == [(0, 0), (0, 1), (0, 2),
|
||||
(1, 0), (1, 1), (1, 2),
|
||||
(2, 0), (2, 1), (2, 2)]
|
||||
# (z, y, x) indices
|
||||
assert rlat3.indices == [
|
||||
(0, 0, 0), (0, 0, 1), (0, 0, 2),
|
||||
(0, 1, 0), (0, 1, 1), (0, 1, 2),
|
||||
(0, 2, 0), (0, 2, 1), (0, 2, 2),
|
||||
(1, 0, 0), (1, 0, 1), (1, 0, 2),
|
||||
(1, 1, 0), (1, 1, 1), (1, 1, 2),
|
||||
(1, 2, 0), (1, 2, 1), (1, 2, 2)
|
||||
]
|
||||
|
||||
|
||||
def test_indices_hex(hlat2, hlat3):
|
||||
# (r, i) indices
|
||||
assert hlat2.indices == (
|
||||
[(0, i) for i in range(12)] +
|
||||
[(1, i) for i in range(6)] +
|
||||
[(2, 0)]
|
||||
)
|
||||
|
||||
# (z, r, i) indices
|
||||
assert hlat3.indices == (
|
||||
[(0, 0, i) for i in range(12)] +
|
||||
[(0, 1, i) for i in range(6)] +
|
||||
[(0, 2, 0)] +
|
||||
[(1, 0, i) for i in range(12)] +
|
||||
[(1, 1, i) for i in range(6)] +
|
||||
[(1, 2, 0)]
|
||||
)
|
||||
|
||||
|
||||
def test_xml_rect(rlat2, rlat3):
|
||||
for lat in (rlat2, rlat3):
|
||||
geom = ET.Element('geometry')
|
||||
lat.create_xml_subelement(geom)
|
||||
elem = geom.find('lattice')
|
||||
assert elem.tag == 'lattice'
|
||||
assert elem.get('id') == str(lat.id)
|
||||
assert len(elem.find('pitch').text.split()) == lat.ndim
|
||||
assert len(elem.find('lower_left').text.split()) == lat.ndim
|
||||
assert len(elem.find('universes').text.split()) == len(lat.indices)
|
||||
|
||||
|
||||
def test_xml_hex(hlat2, hlat3):
|
||||
for lat in (hlat2, hlat3):
|
||||
geom = ET.Element('geometry')
|
||||
lat.create_xml_subelement(geom)
|
||||
elem = geom.find('hex_lattice')
|
||||
assert elem.tag == 'hex_lattice'
|
||||
assert elem.get('id') == str(lat.id)
|
||||
assert len(elem.find('center').text.split()) == lat.ndim
|
||||
assert len(elem.find('pitch').text.split()) == lat.ndim - 1
|
||||
assert len(elem.find('universes').text.split()) == len(lat.indices)
|
||||
|
||||
|
||||
def test_show_indices():
|
||||
for i in range(1, 11):
|
||||
lines = openmc.HexLattice.show_indices(i).split('\n')
|
||||
assert len(lines) == 4*i - 3
|
||||
lines_x = openmc.HexLattice.show_indices(i, 'x').split('\n')
|
||||
assert len(lines) == 4*i - 3
|
||||
521
tests/unit_tests/test_lib.py
Normal file
521
tests/unit_tests/test_lib.py
Normal file
|
|
@ -0,0 +1,521 @@
|
|||
from collections.abc import Mapping
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
import openmc
|
||||
import openmc.exceptions as exc
|
||||
import openmc.lib
|
||||
|
||||
from tests import cdtemp
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def pincell_model():
|
||||
"""Set up a model to test with and delete files when done"""
|
||||
openmc.reset_auto_ids()
|
||||
pincell = openmc.examples.pwr_pin_cell()
|
||||
pincell.settings.verbosity = 1
|
||||
|
||||
# Add a tally
|
||||
filter1 = openmc.MaterialFilter(pincell.materials)
|
||||
filter2 = openmc.EnergyFilter([0.0, 1.0, 1.0e3, 20.0e6])
|
||||
mat_tally = openmc.Tally()
|
||||
mat_tally.filters = [filter1, filter2]
|
||||
mat_tally.nuclides = ['U235', 'U238']
|
||||
mat_tally.scores = ['total', 'elastic', '(n,gamma)']
|
||||
pincell.tallies.append(mat_tally)
|
||||
|
||||
# Add an expansion tally
|
||||
zernike_tally = openmc.Tally()
|
||||
filter3 = openmc.ZernikeFilter(5, r=.63)
|
||||
cells = pincell.geometry.root_universe.cells
|
||||
filter4 = openmc.CellFilter(list(cells.values()))
|
||||
zernike_tally.filters = [filter3, filter4]
|
||||
zernike_tally.scores = ['fission']
|
||||
pincell.tallies.append(zernike_tally)
|
||||
|
||||
# Add an energy function tally
|
||||
energyfunc_tally = openmc.Tally()
|
||||
energyfunc_filter = openmc.EnergyFunctionFilter(
|
||||
[0.0, 20e6], [0.0, 20e6])
|
||||
energyfunc_tally.scores = ['fission']
|
||||
energyfunc_tally.filters = [energyfunc_filter]
|
||||
pincell.tallies.append(energyfunc_tally)
|
||||
|
||||
# Write XML files in tmpdir
|
||||
with cdtemp():
|
||||
pincell.export_to_xml()
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def lib_init(pincell_model, mpi_intracomm):
|
||||
openmc.lib.init(intracomm=mpi_intracomm)
|
||||
yield
|
||||
openmc.lib.finalize()
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def lib_simulation_init(lib_init):
|
||||
openmc.lib.simulation_init()
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def lib_run(lib_simulation_init):
|
||||
openmc.lib.run()
|
||||
|
||||
|
||||
def test_cell_mapping(lib_init):
|
||||
cells = openmc.lib.cells
|
||||
assert isinstance(cells, Mapping)
|
||||
assert len(cells) == 3
|
||||
for cell_id, cell in cells.items():
|
||||
assert isinstance(cell, openmc.lib.Cell)
|
||||
assert cell_id == cell.id
|
||||
|
||||
|
||||
def test_cell(lib_init):
|
||||
cell = openmc.lib.cells[1]
|
||||
assert isinstance(cell.fill, openmc.lib.Material)
|
||||
cell.fill = openmc.lib.materials[1]
|
||||
assert str(cell) == 'Cell[0]'
|
||||
assert cell.name == "Fuel"
|
||||
cell.name = "Not fuel"
|
||||
assert cell.name == "Not fuel"
|
||||
|
||||
def test_cell_temperature(lib_init):
|
||||
cell = openmc.lib.cells[1]
|
||||
cell.set_temperature(100.0, 0)
|
||||
assert cell.get_temperature(0) == 100.0
|
||||
cell.set_temperature(200)
|
||||
assert cell.get_temperature() == 200.0
|
||||
|
||||
|
||||
def test_new_cell(lib_init):
|
||||
with pytest.raises(exc.AllocationError):
|
||||
openmc.lib.Cell(1)
|
||||
new_cell = openmc.lib.Cell()
|
||||
new_cell_with_id = openmc.lib.Cell(10)
|
||||
assert len(openmc.lib.cells) == 5
|
||||
|
||||
|
||||
def test_material_mapping(lib_init):
|
||||
mats = openmc.lib.materials
|
||||
assert isinstance(mats, Mapping)
|
||||
assert len(mats) == 3
|
||||
for mat_id, mat in mats.items():
|
||||
assert isinstance(mat, openmc.lib.Material)
|
||||
assert mat_id == mat.id
|
||||
|
||||
|
||||
def test_material(lib_init):
|
||||
m = openmc.lib.materials[3]
|
||||
assert m.nuclides == ['H1', 'O16', 'B10', 'B11']
|
||||
|
||||
old_dens = m.densities
|
||||
test_dens = [1.0e-1, 2.0e-1, 2.5e-1, 1.0e-3]
|
||||
m.set_densities(m.nuclides, test_dens)
|
||||
assert m.densities == pytest.approx(test_dens)
|
||||
|
||||
assert m.volume is None
|
||||
m.volume = 10.0
|
||||
assert m.volume == 10.0
|
||||
|
||||
with pytest.raises(exc.OpenMCError):
|
||||
m.set_density(1.0, 'goblins')
|
||||
|
||||
rho = 2.25e-2
|
||||
m.set_density(rho)
|
||||
assert sum(m.densities) == pytest.approx(rho)
|
||||
|
||||
m.set_density(0.1, 'g/cm3')
|
||||
assert m.density == pytest.approx(0.1)
|
||||
assert m.name == "Hot borated water"
|
||||
m.name = "Not hot borated water"
|
||||
assert m.name == "Not hot borated water"
|
||||
|
||||
def test_material_add_nuclide(lib_init):
|
||||
m = openmc.lib.materials[3]
|
||||
m.add_nuclide('Xe135', 1e-12)
|
||||
assert m.nuclides[-1] == 'Xe135'
|
||||
assert m.densities[-1] == 1e-12
|
||||
|
||||
|
||||
def test_new_material(lib_init):
|
||||
with pytest.raises(exc.AllocationError):
|
||||
openmc.lib.Material(1)
|
||||
new_mat = openmc.lib.Material()
|
||||
new_mat_with_id = openmc.lib.Material(10)
|
||||
assert len(openmc.lib.materials) == 5
|
||||
|
||||
|
||||
def test_nuclide_mapping(lib_init):
|
||||
nucs = openmc.lib.nuclides
|
||||
assert isinstance(nucs, Mapping)
|
||||
assert len(nucs) == 13
|
||||
for name, nuc in nucs.items():
|
||||
assert isinstance(nuc, openmc.lib.Nuclide)
|
||||
assert name == nuc.name
|
||||
|
||||
|
||||
def test_settings(lib_init):
|
||||
settings = openmc.lib.settings
|
||||
assert settings.batches == 10
|
||||
settings.batches = 10
|
||||
assert settings.inactive == 5
|
||||
assert settings.generations_per_batch == 1
|
||||
assert settings.particles == 100
|
||||
assert settings.seed == 1
|
||||
settings.seed = 11
|
||||
|
||||
assert settings.run_mode == 'eigenvalue'
|
||||
settings.run_mode = 'volume'
|
||||
settings.run_mode = 'eigenvalue'
|
||||
|
||||
|
||||
def test_tally_mapping(lib_init):
|
||||
tallies = openmc.lib.tallies
|
||||
assert isinstance(tallies, Mapping)
|
||||
assert len(tallies) == 3
|
||||
for tally_id, tally in tallies.items():
|
||||
assert isinstance(tally, openmc.lib.Tally)
|
||||
assert tally_id == tally.id
|
||||
|
||||
|
||||
def test_energy_function_filter(lib_init):
|
||||
"""Test special __new__ and __init__ for EnergyFunctionFilter"""
|
||||
efunc = openmc.lib.EnergyFunctionFilter([0.0, 1.0], [0.0, 2.0])
|
||||
assert len(efunc.energy) == 2
|
||||
assert (efunc.energy == [0.0, 1.0]).all()
|
||||
assert len(efunc.y) == 2
|
||||
assert (efunc.y == [0.0, 2.0]).all()
|
||||
|
||||
|
||||
def test_tally(lib_init):
|
||||
t = openmc.lib.tallies[1]
|
||||
assert t.type == 'volume'
|
||||
assert len(t.filters) == 2
|
||||
assert isinstance(t.filters[0], openmc.lib.MaterialFilter)
|
||||
assert isinstance(t.filters[1], openmc.lib.EnergyFilter)
|
||||
|
||||
# Create new filter and replace existing
|
||||
with pytest.raises(exc.AllocationError):
|
||||
openmc.lib.MaterialFilter(uid=1)
|
||||
mats = openmc.lib.materials
|
||||
f = openmc.lib.MaterialFilter([mats[2], mats[1]])
|
||||
assert f.bins[0] == mats[2]
|
||||
assert f.bins[1] == mats[1]
|
||||
t.filters = [f]
|
||||
assert t.filters == [f]
|
||||
|
||||
assert t.nuclides == ['U235', 'U238']
|
||||
with pytest.raises(exc.DataError):
|
||||
t.nuclides = ['Zr2']
|
||||
t.nuclides = ['U234', 'Zr90']
|
||||
assert t.nuclides == ['U234', 'Zr90']
|
||||
|
||||
assert t.scores == ['total', '(n,elastic)', '(n,gamma)']
|
||||
new_scores = ['scatter', 'fission', 'nu-fission', '(n,2n)']
|
||||
t.scores = new_scores
|
||||
assert t.scores == new_scores
|
||||
|
||||
t2 = openmc.lib.tallies[2]
|
||||
assert len(t2.filters) == 2
|
||||
assert isinstance(t2.filters[0], openmc.lib.ZernikeFilter)
|
||||
assert isinstance(t2.filters[1], openmc.lib.CellFilter)
|
||||
assert len(t2.filters[1].bins) == 3
|
||||
assert t2.filters[0].order == 5
|
||||
|
||||
t3 = openmc.lib.tallies[3]
|
||||
assert len(t3.filters) == 1
|
||||
t3_f = t3.filters[0]
|
||||
assert isinstance(t3_f, openmc.lib.EnergyFunctionFilter)
|
||||
assert len(t3_f.energy) == 2
|
||||
assert len(t3_f.y) == 2
|
||||
t3_f.set_data([0.0, 1.0, 2.0], [0.0, 1.0, 4.0])
|
||||
assert len(t3_f.energy) == 3
|
||||
assert len(t3_f.y) == 3
|
||||
|
||||
|
||||
def test_new_tally(lib_init):
|
||||
with pytest.raises(exc.AllocationError):
|
||||
openmc.lib.Material(1)
|
||||
new_tally = openmc.lib.Tally()
|
||||
new_tally.scores = ['flux']
|
||||
new_tally_with_id = openmc.lib.Tally(10)
|
||||
new_tally_with_id.scores = ['flux']
|
||||
assert len(openmc.lib.tallies) == 5
|
||||
|
||||
|
||||
def test_tally_activate(lib_simulation_init):
|
||||
t = openmc.lib.tallies[1]
|
||||
assert not t.active
|
||||
t.active = True
|
||||
assert t.active
|
||||
|
||||
|
||||
def test_tally_writable(lib_simulation_init):
|
||||
t = openmc.lib.tallies[1]
|
||||
assert t.writable
|
||||
t.writable = False
|
||||
assert not t.writable
|
||||
# Revert tally to writable state for lib_run fixtures
|
||||
t.writable = True
|
||||
|
||||
|
||||
def test_tally_results(lib_run):
|
||||
t = openmc.lib.tallies[1]
|
||||
assert t.num_realizations == 10 # t was made active in test_tally_active
|
||||
assert np.all(t.mean >= 0)
|
||||
nonzero = (t.mean > 0.0)
|
||||
assert np.all(t.std_dev[nonzero] >= 0)
|
||||
assert np.all(t.ci_width()[nonzero] >= 1.95*t.std_dev[nonzero])
|
||||
|
||||
t2 = openmc.lib.tallies[2]
|
||||
n = 5
|
||||
assert t2.mean.size == (n + 1) * (n + 2) // 2 * 3 # Number of Zernike coeffs * 3 cells
|
||||
|
||||
|
||||
def test_global_tallies(lib_run):
|
||||
assert openmc.lib.num_realizations() == 5
|
||||
gt = openmc.lib.global_tallies()
|
||||
for mean, std_dev in gt:
|
||||
assert mean >= 0
|
||||
|
||||
|
||||
def test_statepoint(lib_run):
|
||||
openmc.lib.statepoint_write('test_sp.h5')
|
||||
assert os.path.exists('test_sp.h5')
|
||||
|
||||
|
||||
def test_source_bank(lib_run):
|
||||
source = openmc.lib.source_bank()
|
||||
assert np.all(source['E'] > 0.0)
|
||||
assert np.all(source['wgt'] == 1.0)
|
||||
assert np.allclose(np.linalg.norm(source['u'], axis=1), 1.0)
|
||||
|
||||
|
||||
def test_by_batch(lib_run):
|
||||
openmc.lib.hard_reset()
|
||||
|
||||
# Running next batch before simulation is initialized should raise an
|
||||
# exception
|
||||
with pytest.raises(exc.AllocationError):
|
||||
openmc.lib.next_batch()
|
||||
|
||||
openmc.lib.simulation_init()
|
||||
try:
|
||||
for _ in openmc.lib.iter_batches():
|
||||
# Make sure we can get k-effective during inactive/active batches
|
||||
mean, std_dev = openmc.lib.keff()
|
||||
assert 0.0 < mean < 2.5
|
||||
assert std_dev > 0.0
|
||||
assert openmc.lib.num_realizations() == 5
|
||||
|
||||
for i in range(3):
|
||||
openmc.lib.next_batch()
|
||||
assert openmc.lib.num_realizations() == 8
|
||||
|
||||
finally:
|
||||
openmc.lib.simulation_finalize()
|
||||
|
||||
|
||||
def test_reset(lib_run):
|
||||
# Init and run 10 batches.
|
||||
openmc.lib.hard_reset()
|
||||
openmc.lib.simulation_init()
|
||||
try:
|
||||
for i in range(10):
|
||||
openmc.lib.next_batch()
|
||||
|
||||
# Make sure there are 5 realizations for the 5 active batches.
|
||||
assert openmc.lib.num_realizations() == 5
|
||||
assert openmc.lib.tallies[2].num_realizations == 5
|
||||
_, keff_sd1 = openmc.lib.keff()
|
||||
tally_sd1 = openmc.lib.tallies[2].std_dev[0]
|
||||
|
||||
# Reset and run 3 more batches. Check the number of realizations.
|
||||
openmc.lib.reset()
|
||||
for i in range(3):
|
||||
openmc.lib.next_batch()
|
||||
assert openmc.lib.num_realizations() == 3
|
||||
assert openmc.lib.tallies[2].num_realizations == 3
|
||||
|
||||
# Check the tally std devs to make sure results were cleared.
|
||||
_, keff_sd2 = openmc.lib.keff()
|
||||
tally_sd2 = openmc.lib.tallies[2].std_dev[0]
|
||||
assert keff_sd2 > keff_sd1
|
||||
assert tally_sd2 > tally_sd1
|
||||
|
||||
finally:
|
||||
openmc.lib.simulation_finalize()
|
||||
|
||||
|
||||
def test_reproduce_keff(lib_init):
|
||||
# Get k-effective after run
|
||||
openmc.lib.hard_reset()
|
||||
openmc.lib.run()
|
||||
keff0 = openmc.lib.keff()
|
||||
|
||||
# Reset, run again, and get k-effective again. they should match
|
||||
openmc.lib.hard_reset()
|
||||
openmc.lib.run()
|
||||
keff1 = openmc.lib.keff()
|
||||
assert keff0 == pytest.approx(keff1)
|
||||
|
||||
|
||||
def test_find_cell(lib_init):
|
||||
cell, instance = openmc.lib.find_cell((0., 0., 0.))
|
||||
assert cell is openmc.lib.cells[1]
|
||||
cell, instance = openmc.lib.find_cell((0.4, 0., 0.))
|
||||
assert cell is openmc.lib.cells[2]
|
||||
with pytest.raises(exc.GeometryError):
|
||||
openmc.lib.find_cell((100., 100., 100.))
|
||||
|
||||
|
||||
def test_find_material(lib_init):
|
||||
mat = openmc.lib.find_material((0., 0., 0.))
|
||||
assert mat is openmc.lib.materials[1]
|
||||
mat = openmc.lib.find_material((0.4, 0., 0.))
|
||||
assert mat is openmc.lib.materials[2]
|
||||
|
||||
|
||||
def test_mesh(lib_init):
|
||||
mesh = openmc.lib.RegularMesh()
|
||||
mesh.dimension = (2, 3, 4)
|
||||
assert mesh.dimension == (2, 3, 4)
|
||||
with pytest.raises(exc.AllocationError):
|
||||
mesh2 = openmc.lib.RegularMesh(mesh.id)
|
||||
|
||||
# Make sure each combination of parameters works
|
||||
ll = (0., 0., 0.)
|
||||
ur = (10., 10., 10.)
|
||||
width = (1., 1., 1.)
|
||||
mesh.set_parameters(lower_left=ll, upper_right=ur)
|
||||
assert mesh.lower_left == pytest.approx(ll)
|
||||
assert mesh.upper_right == pytest.approx(ur)
|
||||
mesh.set_parameters(lower_left=ll, width=width)
|
||||
assert mesh.lower_left == pytest.approx(ll)
|
||||
assert mesh.width == pytest.approx(width)
|
||||
mesh.set_parameters(upper_right=ur, width=width)
|
||||
assert mesh.upper_right == pytest.approx(ur)
|
||||
assert mesh.width == pytest.approx(width)
|
||||
|
||||
meshes = openmc.lib.meshes
|
||||
assert isinstance(meshes, Mapping)
|
||||
assert len(meshes) == 1
|
||||
for mesh_id, mesh in meshes.items():
|
||||
assert isinstance(mesh, openmc.lib.RegularMesh)
|
||||
assert mesh_id == mesh.id
|
||||
|
||||
mf = openmc.lib.MeshFilter(mesh)
|
||||
assert mf.mesh == mesh
|
||||
|
||||
msf = openmc.lib.MeshSurfaceFilter(mesh)
|
||||
assert msf.mesh == mesh
|
||||
|
||||
|
||||
def test_restart(lib_init, mpi_intracomm):
|
||||
# Finalize and re-init to make internal state consistent with XML.
|
||||
openmc.lib.hard_reset()
|
||||
openmc.lib.finalize()
|
||||
openmc.lib.init(intracomm=mpi_intracomm)
|
||||
openmc.lib.simulation_init()
|
||||
|
||||
# Run for 7 batches then write a statepoint.
|
||||
for i in range(7):
|
||||
openmc.lib.next_batch()
|
||||
openmc.lib.statepoint_write('restart_test.h5', True)
|
||||
|
||||
# Run 3 more batches and copy the keff.
|
||||
for i in range(3):
|
||||
openmc.lib.next_batch()
|
||||
keff0 = openmc.lib.keff()
|
||||
|
||||
# Restart the simulation from the statepoint and the 3 remaining active batches.
|
||||
openmc.lib.simulation_finalize()
|
||||
openmc.lib.hard_reset()
|
||||
openmc.lib.finalize()
|
||||
openmc.lib.init(args=('-r', 'restart_test.h5'))
|
||||
openmc.lib.simulation_init()
|
||||
for i in range(3):
|
||||
openmc.lib.next_batch()
|
||||
keff1 = openmc.lib.keff()
|
||||
openmc.lib.simulation_finalize()
|
||||
|
||||
# Compare the keff values.
|
||||
assert keff0 == pytest.approx(keff1)
|
||||
|
||||
|
||||
def test_load_nuclide(lib_init):
|
||||
# load multiple nuclides
|
||||
openmc.lib.load_nuclide('H3')
|
||||
assert 'H3' in openmc.lib.nuclides
|
||||
openmc.lib.load_nuclide('Pu239')
|
||||
assert 'Pu239' in openmc.lib.nuclides
|
||||
# load non-existent nuclide
|
||||
with pytest.raises(exc.DataError):
|
||||
openmc.lib.load_nuclide('Pu3')
|
||||
|
||||
|
||||
def test_id_map(lib_init):
|
||||
expected_ids = np.array([[(3, 3), (2, 2), (3, 3)],
|
||||
[(2, 2), (1, 1), (2, 2)],
|
||||
[(3, 3), (2, 2), (3, 3)]], dtype='int32')
|
||||
|
||||
# create a plot object
|
||||
s = openmc.lib.plot._PlotBase()
|
||||
s.width = 1.26
|
||||
s.height = 1.26
|
||||
s.v_res = 3
|
||||
s.h_res = 3
|
||||
s.origin = (0.0, 0.0, 0.0)
|
||||
s.basis = 'xy'
|
||||
s.level = -1
|
||||
|
||||
ids = openmc.lib.plot.id_map(s)
|
||||
assert np.array_equal(expected_ids, ids)
|
||||
|
||||
def test_property_map(lib_init):
|
||||
expected_properties = np.array(
|
||||
[[(293.6, 0.740582), (293.6, 6.55), (293.6, 0.740582)],
|
||||
[ (293.6, 6.55), (293.6, 10.29769), (293.6, 6.55)],
|
||||
[(293.6, 0.740582), (293.6, 6.55), (293.6, 0.740582)]], dtype='float')
|
||||
|
||||
# create a plot object
|
||||
s = openmc.lib.plot._PlotBase()
|
||||
s.width = 1.26
|
||||
s.height = 1.26
|
||||
s.v_res = 3
|
||||
s.h_res = 3
|
||||
s.origin = (0.0, 0.0, 0.0)
|
||||
s.basis = 'xy'
|
||||
s.level = -1
|
||||
|
||||
properties = openmc.lib.plot.property_map(s)
|
||||
assert np.allclose(expected_properties, properties, atol=1e-04)
|
||||
|
||||
|
||||
def test_position(lib_init):
|
||||
|
||||
pos = openmc.lib.plot._Position(1.0, 2.0, 3.0)
|
||||
|
||||
assert tuple(pos) == (1.0, 2.0, 3.0)
|
||||
|
||||
pos[0] = 1.3
|
||||
pos[1] = 2.3
|
||||
pos[2] = 3.3
|
||||
|
||||
assert tuple(pos) == (1.3, 2.3, 3.3)
|
||||
|
||||
|
||||
def test_global_bounding_box(lib_init):
|
||||
expected_llc = (-0.63, -0.63, -np.inf)
|
||||
expected_urc = (0.63, 0.63, np.inf)
|
||||
|
||||
llc, urc = openmc.lib.global_bounding_box()
|
||||
|
||||
assert tuple(llc) == expected_llc
|
||||
assert tuple(urc) == expected_urc
|
||||
220
tests/unit_tests/test_material.py
Normal file
220
tests/unit_tests/test_material.py
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
import openmc
|
||||
import openmc.model
|
||||
import openmc.stats
|
||||
import openmc.examples
|
||||
import pytest
|
||||
|
||||
|
||||
def test_attributes(uo2):
|
||||
assert uo2.name == 'UO2'
|
||||
assert uo2.id == 100
|
||||
assert uo2.depletable
|
||||
|
||||
|
||||
def test_nuclides(uo2):
|
||||
"""Test adding/removing nuclides."""
|
||||
m = openmc.Material()
|
||||
m.add_nuclide('U235', 1.0)
|
||||
with pytest.raises(TypeError):
|
||||
m.add_nuclide('H1', '1.0')
|
||||
with pytest.raises(TypeError):
|
||||
m.add_nuclide(1.0, 'H1')
|
||||
with pytest.raises(ValueError):
|
||||
m.add_nuclide('H1', 1.0, 'oa')
|
||||
m.remove_nuclide('U235')
|
||||
|
||||
|
||||
def test_elements():
|
||||
"""Test adding elements."""
|
||||
m = openmc.Material()
|
||||
m.add_element('Zr', 1.0)
|
||||
m.add_element('U', 1.0, enrichment=4.5)
|
||||
with pytest.raises(ValueError):
|
||||
m.add_element('U', 1.0, enrichment=100.0)
|
||||
with pytest.raises(ValueError):
|
||||
m.add_element('Pu', 1.0, enrichment=3.0)
|
||||
|
||||
|
||||
def test_density():
|
||||
m = openmc.Material()
|
||||
for unit in ['g/cm3', 'g/cc', 'kg/m3', 'atom/b-cm', 'atom/cm3']:
|
||||
m.set_density(unit, 1.0)
|
||||
with pytest.raises(ValueError):
|
||||
m.set_density('g/litre', 1.0)
|
||||
|
||||
|
||||
def test_salphabeta():
|
||||
m = openmc.Material()
|
||||
m.add_s_alpha_beta('c_H_in_H2O', 0.5)
|
||||
|
||||
|
||||
def test_repr():
|
||||
m = openmc.Material()
|
||||
m.add_nuclide('Zr90', 1.0)
|
||||
m.add_nuclide('H2', 0.5)
|
||||
m.add_s_alpha_beta('c_D_in_D2O')
|
||||
m.set_density('sum')
|
||||
m.temperature = 600.0
|
||||
repr(m)
|
||||
|
||||
|
||||
def test_macroscopic(run_in_tmpdir):
|
||||
m = openmc.Material(name='UO2')
|
||||
m.add_macroscopic('UO2')
|
||||
with pytest.raises(ValueError):
|
||||
m.add_nuclide('H1', 1.0)
|
||||
with pytest.raises(ValueError):
|
||||
m.add_element('O', 1.0)
|
||||
with pytest.raises(ValueError):
|
||||
m.add_macroscopic('Other')
|
||||
|
||||
m2 = openmc.Material()
|
||||
m2.add_nuclide('He4', 1.0)
|
||||
with pytest.raises(ValueError):
|
||||
m2.add_macroscopic('UO2')
|
||||
|
||||
# Make sure we can remove/add macroscopic
|
||||
m.remove_macroscopic('UO2')
|
||||
m.add_macroscopic('UO2')
|
||||
repr(m)
|
||||
|
||||
# Make sure we can export a material with macroscopic data
|
||||
mats = openmc.Materials([m])
|
||||
mats.export_to_xml()
|
||||
|
||||
|
||||
def test_paths():
|
||||
model = openmc.examples.pwr_assembly()
|
||||
model.geometry.determine_paths()
|
||||
fuel = model.materials[0]
|
||||
assert fuel.num_instances == 264
|
||||
assert len(fuel.paths) == 264
|
||||
|
||||
|
||||
def test_isotropic():
|
||||
m1 = openmc.Material()
|
||||
m1.add_nuclide('U235', 1.0)
|
||||
m1.add_nuclide('O16', 2.0)
|
||||
m1.isotropic = ['O16']
|
||||
assert m1.isotropic == ['O16']
|
||||
|
||||
m2 = openmc.Material()
|
||||
m2.add_nuclide('H1', 1.0)
|
||||
mats = openmc.Materials([m1, m2])
|
||||
mats.make_isotropic_in_lab()
|
||||
assert m1.isotropic == ['U235', 'O16']
|
||||
assert m2.isotropic == ['H1']
|
||||
|
||||
|
||||
def test_get_nuclide_densities(uo2):
|
||||
nucs = uo2.get_nuclide_densities()
|
||||
for nuc, density, density_type in nucs.values():
|
||||
assert nuc in ('U235', 'O16')
|
||||
assert density > 0
|
||||
assert density_type in ('ao', 'wo')
|
||||
|
||||
|
||||
def test_get_nuclide_atom_densities(uo2):
|
||||
nucs = uo2.get_nuclide_atom_densities()
|
||||
for nuc, density in nucs.values():
|
||||
assert nuc in ('U235', 'O16')
|
||||
assert density > 0
|
||||
|
||||
|
||||
def test_mass():
|
||||
m = openmc.Material()
|
||||
m.add_nuclide('Zr90', 1.0, 'wo')
|
||||
m.add_nuclide('U235', 1.0, 'wo')
|
||||
m.set_density('g/cm3', 2.0)
|
||||
m.volume = 10.0
|
||||
|
||||
assert m.get_mass_density('Zr90') == pytest.approx(1.0)
|
||||
assert m.get_mass_density('U235') == pytest.approx(1.0)
|
||||
assert m.get_mass_density() == pytest.approx(2.0)
|
||||
|
||||
assert m.get_mass('Zr90') == pytest.approx(10.0)
|
||||
assert m.get_mass('U235') == pytest.approx(10.0)
|
||||
assert m.get_mass() == pytest.approx(20.0)
|
||||
assert m.fissionable_mass == pytest.approx(10.0)
|
||||
|
||||
|
||||
def test_materials(run_in_tmpdir):
|
||||
m1 = openmc.Material()
|
||||
m1.add_nuclide('U235', 1.0, 'wo')
|
||||
m1.add_nuclide('O16', 2.0, 'wo')
|
||||
m1.set_density('g/cm3', 10.0)
|
||||
m1.depletable = True
|
||||
m1.temperature = 900.0
|
||||
|
||||
m2 = openmc.Material()
|
||||
m2.add_nuclide('H1', 2.0)
|
||||
m2.add_nuclide('O16', 1.0)
|
||||
m2.add_s_alpha_beta('c_H_in_H2O')
|
||||
m2.set_density('kg/m3', 1000.0)
|
||||
|
||||
mats = openmc.Materials([m1, m2])
|
||||
mats.cross_sections = '/some/fake/cross_sections.xml'
|
||||
mats.export_to_xml()
|
||||
|
||||
|
||||
def test_borated_water():
|
||||
# Test against reference values from the BEAVRS benchmark.
|
||||
m = openmc.model.borated_water(975, 566.5, 15.51, material_id=50)
|
||||
assert m.density == pytest.approx(0.7405, 1e-3)
|
||||
assert m.temperature == pytest.approx(566.5)
|
||||
assert m._sab[0][0] == 'c_H_in_H2O'
|
||||
ref_dens = {'B10':8.0023e-06, 'B11':3.2210e-05, 'H1':4.9458e-02,
|
||||
'O16':2.4672e-02}
|
||||
nuc_dens = m.get_nuclide_atom_densities()
|
||||
for nuclide in ref_dens:
|
||||
assert nuc_dens[nuclide][1] == pytest.approx(ref_dens[nuclide], 1e-2)
|
||||
assert m.id == 50
|
||||
|
||||
# Test the Celsius conversion.
|
||||
m = openmc.model.borated_water(975, 293.35, 15.51, 'C')
|
||||
assert m.density == pytest.approx(0.7405, 1e-3)
|
||||
|
||||
# Test Fahrenheit and psi conversions.
|
||||
m = openmc.model.borated_water(975, 560.0, 2250.0, 'F', 'psi')
|
||||
assert m.density == pytest.approx(0.7405, 1e-3)
|
||||
|
||||
# Test the density override
|
||||
m = openmc.model.borated_water(975, 566.5, 15.51, density=0.9)
|
||||
assert m.density == pytest.approx(0.9, 1e-3)
|
||||
|
||||
|
||||
def test_from_xml(run_in_tmpdir):
|
||||
# Create a materials.xml file
|
||||
m1 = openmc.Material(1, 'water')
|
||||
m1.add_nuclide('H1', 1.0)
|
||||
m1.add_nuclide('O16', 2.0)
|
||||
m1.add_s_alpha_beta('c_H_in_H2O')
|
||||
m1.temperature = 300
|
||||
m1.volume = 100
|
||||
m1.set_density('g/cm3', 0.9)
|
||||
m1.isotropic = ['H1']
|
||||
m2 = openmc.Material(2, 'zirc')
|
||||
m2.add_nuclide('Zr90', 1.0, 'wo')
|
||||
m2.set_density('kg/m3', 10.0)
|
||||
m3 = openmc.Material(3)
|
||||
m3.add_nuclide('N14', 0.02)
|
||||
|
||||
mats = openmc.Materials([m1, m2, m3])
|
||||
mats.cross_sections = 'fake_path.xml'
|
||||
mats.export_to_xml()
|
||||
|
||||
# Regenerate materials from XML
|
||||
mats = openmc.Materials.from_xml()
|
||||
assert len(mats) == 3
|
||||
m1 = mats[0]
|
||||
assert m1.id == 1
|
||||
assert m1.name == 'water'
|
||||
assert m1.nuclides == [('H1', 1.0, 'ao'), ('O16', 2.0, 'ao')]
|
||||
assert m1.isotropic == ['H1']
|
||||
assert m1.temperature == 300
|
||||
assert m1.volume == 100
|
||||
m2 = mats[1]
|
||||
assert m2.nuclides == [('Zr90', 1.0, 'wo')]
|
||||
assert m2.density == 10.0
|
||||
assert m2.density_units == 'kg/m3'
|
||||
assert mats[2].density_units == 'sum'
|
||||
246
tests/unit_tests/test_math.py
Normal file
246
tests/unit_tests/test_math.py
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
import numpy as np
|
||||
import scipy as sp
|
||||
|
||||
import openmc
|
||||
import openmc.lib
|
||||
|
||||
import pytest
|
||||
|
||||
def test_t_percentile():
|
||||
# Permutations include 1 DoF, 2 DoF, and > 2 DoF
|
||||
# We will test 5 p-values at 3-DoF values
|
||||
test_ps = [0.02, 0.4, 0.5, 0.6, 0.98]
|
||||
test_dfs = [1, 2, 5]
|
||||
|
||||
# The reference solutions come from Scipy
|
||||
ref_ts = [[sp.stats.t.ppf(p, df) for p in test_ps] for df in test_dfs]
|
||||
|
||||
test_ts = [[openmc.lib.math.t_percentile(p, df) for p in test_ps]
|
||||
for df in test_dfs]
|
||||
|
||||
# The 5 DoF approximation in openmc.lib.math.t_percentile is off by up to
|
||||
# 8e-3 from the scipy solution, so test that one separately with looser
|
||||
# tolerance
|
||||
assert np.allclose(ref_ts[:-1], test_ts[:-1])
|
||||
assert np.allclose(ref_ts[-1], test_ts[-1], atol=1e-2)
|
||||
|
||||
|
||||
def test_calc_pn():
|
||||
max_order = 10
|
||||
test_xs = np.linspace(-1., 1., num=5, endpoint=True)
|
||||
|
||||
# Reference solutions from scipy
|
||||
ref_vals = np.array([sp.special.eval_legendre(n, test_xs)
|
||||
for n in range(0, max_order + 1)])
|
||||
|
||||
test_vals = []
|
||||
for x in test_xs:
|
||||
test_vals.append(openmc.lib.math.calc_pn(max_order, x).tolist())
|
||||
|
||||
test_vals = np.swapaxes(np.array(test_vals), 0, 1)
|
||||
|
||||
assert np.allclose(ref_vals, test_vals)
|
||||
|
||||
|
||||
def test_evaluate_legendre():
|
||||
max_order = 10
|
||||
# Coefficients are set to 1, but will incorporate the (2l+1)/2 norm factor
|
||||
# for the reference solution
|
||||
test_coeffs = [0.5 * (2. * l + 1.) for l in range(max_order + 1)]
|
||||
test_xs = np.linspace(-1., 1., num=5, endpoint=True)
|
||||
|
||||
ref_vals = np.polynomial.legendre.legval(test_xs, test_coeffs)
|
||||
|
||||
# Set the coefficients back to 1s for the test values since
|
||||
# evaluate legendre incorporates the (2l+1)/2 term on its own
|
||||
test_coeffs = [1. for l in range(max_order + 1)]
|
||||
|
||||
test_vals = np.array([openmc.lib.math.evaluate_legendre(test_coeffs, x)
|
||||
for x in test_xs])
|
||||
|
||||
assert np.allclose(ref_vals, test_vals)
|
||||
|
||||
|
||||
def test_calc_rn():
|
||||
max_order = 10
|
||||
test_ns = np.array([i for i in range(0, max_order + 1)])
|
||||
azi = 0.1 # Longitude
|
||||
pol = 0.2 # Latitude
|
||||
test_uvw = np.array([np.sin(pol) * np.cos(azi),
|
||||
np.sin(pol) * np.sin(azi),
|
||||
np.cos(pol)])
|
||||
|
||||
# Reference solutions from the equations
|
||||
ref_vals = []
|
||||
|
||||
def coeff(n, m):
|
||||
return np.sqrt((2. * n + 1) * sp.special.factorial(n - m) /
|
||||
(sp.special.factorial(n + m)))
|
||||
|
||||
def pnm_bar(n, m, mu):
|
||||
val = coeff(n, m)
|
||||
if m != 0:
|
||||
val *= np.sqrt(2.)
|
||||
val *= sp.special.lpmv([m], [n], [mu])
|
||||
return val[0]
|
||||
|
||||
ref_vals = []
|
||||
for n in test_ns:
|
||||
for m in range(-n, n + 1):
|
||||
if m < 0:
|
||||
ylm = pnm_bar(n, np.abs(m), np.cos(pol)) * \
|
||||
np.sin(np.abs(m) * azi)
|
||||
else:
|
||||
ylm = pnm_bar(n, m, np.cos(pol)) * np.cos(m * azi)
|
||||
|
||||
# Un-normalize for comparison
|
||||
ylm /= np.sqrt(2. * n + 1.)
|
||||
ref_vals.append(ylm)
|
||||
|
||||
test_vals = []
|
||||
test_vals = openmc.lib.math.calc_rn(max_order, test_uvw)
|
||||
|
||||
assert np.allclose(ref_vals, test_vals)
|
||||
|
||||
|
||||
def test_calc_zn():
|
||||
n = 10
|
||||
rho = 0.5
|
||||
phi = 0.5
|
||||
|
||||
# Reference solution from running the C++ implementation
|
||||
ref_vals = np.array([
|
||||
1.00000000e+00, 2.39712769e-01, 4.38791281e-01,
|
||||
2.10367746e-01, -5.00000000e-01, 1.35075576e-01,
|
||||
1.24686873e-01, -2.99640962e-01, -5.48489101e-01,
|
||||
8.84215021e-03, 5.68310892e-02, -4.20735492e-01,
|
||||
-1.25000000e-01, -2.70151153e-01, -2.60091773e-02,
|
||||
1.87022545e-02, -3.42888902e-01, 1.49820481e-01,
|
||||
2.74244551e-01, -2.43159131e-02, -2.50357380e-02,
|
||||
2.20500013e-03, -1.98908812e-01, 4.07587508e-01,
|
||||
4.37500000e-01, 2.61708929e-01, 9.10321205e-02,
|
||||
-1.54686328e-02, -2.74049397e-03, -7.94845816e-02,
|
||||
4.75368705e-01, 7.11647284e-02, 1.30266162e-01,
|
||||
3.37106977e-02, 1.06401886e-01, -7.31606787e-03,
|
||||
-2.95625975e-03, -1.10250006e-02, 3.55194307e-01,
|
||||
-1.44627826e-01, -2.89062500e-01, -9.28644588e-02,
|
||||
-1.62557358e-01, 7.73431638e-02, -2.55329539e-03,
|
||||
-1.90923851e-03, 1.57578403e-02, 1.72995854e-01,
|
||||
-3.66267690e-01, -1.81657333e-01, -3.32521518e-01,
|
||||
-2.59738162e-02, -2.31580576e-01, 4.20673902e-02,
|
||||
-4.11710546e-04, -9.36449487e-04, 1.92156884e-02,
|
||||
2.82515641e-02, -3.90713738e-01, -1.69280296e-01,
|
||||
-8.98437500e-02, -1.08693628e-01, 1.78813094e-01,
|
||||
-1.98191857e-01, 1.65964201e-02, 2.77013853e-04])
|
||||
|
||||
test_vals = openmc.lib.math.calc_zn(n, rho, phi)
|
||||
|
||||
assert np.allclose(ref_vals, test_vals)
|
||||
|
||||
|
||||
def test_calc_zn_rad():
|
||||
n = 10
|
||||
rho = 0.5
|
||||
|
||||
# Reference solution from running the C++ implementation
|
||||
ref_vals = np.array([
|
||||
1.00000000e+00, -5.00000000e-01, -1.25000000e-01,
|
||||
4.37500000e-01, -2.89062500e-01,-8.98437500e-02])
|
||||
|
||||
test_vals = openmc.lib.math.calc_zn_rad(n, rho)
|
||||
|
||||
assert np.allclose(ref_vals, test_vals)
|
||||
|
||||
|
||||
def test_rotate_angle():
|
||||
uvw0 = np.array([1., 0., 0.])
|
||||
phi = 0.
|
||||
mu = 0.
|
||||
|
||||
# reference: mu of 0 pulls the vector the bottom, so:
|
||||
ref_uvw = np.array([0., 0., -1.])
|
||||
|
||||
test_uvw = openmc.lib.math.rotate_angle(uvw0, mu, phi)
|
||||
|
||||
assert np.array_equal(ref_uvw, test_uvw)
|
||||
|
||||
# Repeat for mu = 1 (no change)
|
||||
mu = 1.
|
||||
ref_uvw = np.array([1., 0., 0.])
|
||||
|
||||
test_uvw = openmc.lib.math.rotate_angle(uvw0, mu, phi)
|
||||
|
||||
assert np.array_equal(ref_uvw, test_uvw)
|
||||
|
||||
# Now to test phi is None
|
||||
mu = 0.9
|
||||
settings = openmc.lib.settings
|
||||
settings.seed = 1
|
||||
|
||||
# When seed = 1, phi will be sampled as 1.9116495709698769
|
||||
# The resultant reference is from hand-calculations given the above
|
||||
ref_uvw = [0.9, 0.410813051297112, 0.1457142302040]
|
||||
test_uvw = openmc.lib.math.rotate_angle(uvw0, mu)
|
||||
|
||||
assert np.allclose(ref_uvw, test_uvw)
|
||||
|
||||
|
||||
def test_maxwell_spectrum():
|
||||
settings = openmc.lib.settings
|
||||
settings.seed = 1
|
||||
T = 0.5
|
||||
ref_val = 0.6129982175261098
|
||||
test_val = openmc.lib.math.maxwell_spectrum(T)
|
||||
|
||||
assert ref_val == test_val
|
||||
|
||||
|
||||
def test_watt_spectrum():
|
||||
settings = openmc.lib.settings
|
||||
settings.seed = 1
|
||||
a = 0.5
|
||||
b = 0.75
|
||||
ref_val = 0.6247242713640233
|
||||
test_val = openmc.lib.math.watt_spectrum(a, b)
|
||||
|
||||
assert ref_val == test_val
|
||||
|
||||
|
||||
def test_normal_dist():
|
||||
settings = openmc.lib.settings
|
||||
settings.seed = 1
|
||||
a = 14.08
|
||||
b = 0.0
|
||||
ref_val = 14.08
|
||||
test_val = openmc.lib.math.normal_variate(a, b)
|
||||
|
||||
assert ref_val == pytest.approx(test_val)
|
||||
|
||||
settings.seed = 1
|
||||
a = 14.08
|
||||
b = 1.0
|
||||
ref_val = 16.436645416691427
|
||||
test_val = openmc.lib.math.normal_variate(a, b)
|
||||
|
||||
assert ref_val == pytest.approx(test_val)
|
||||
|
||||
|
||||
def test_broaden_wmp_polynomials():
|
||||
# Two branches of the code to worry about, beta > 6 and otherwise
|
||||
# beta = sqrtE * dopp
|
||||
# First lets do beta > 6
|
||||
test_E = 0.5
|
||||
test_dopp = 100. # approximately U235 at room temperature
|
||||
n = 6
|
||||
|
||||
ref_val = [2., 1.41421356, 1.0001, 0.70731891, 0.50030001, 0.353907]
|
||||
test_val = openmc.lib.math.broaden_wmp_polynomials(test_E, test_dopp, n)
|
||||
|
||||
assert np.allclose(ref_val, test_val)
|
||||
|
||||
# now beta < 6
|
||||
test_dopp = 5.
|
||||
ref_val = [1.99999885, 1.41421356, 1.04, 0.79195959, 0.6224, 0.50346003]
|
||||
test_val = openmc.lib.math.broaden_wmp_polynomials(test_E, test_dopp, n)
|
||||
|
||||
assert np.allclose(ref_val, test_val)
|
||||
116
tests/unit_tests/test_mesh_from_lattice.py
Normal file
116
tests/unit_tests/test_mesh_from_lattice.py
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
import numpy as np
|
||||
import openmc
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def pincell1(uo2, water):
|
||||
cyl = openmc.ZCylinder(r=0.35)
|
||||
fuel = openmc.Cell(fill=uo2, region=-cyl)
|
||||
moderator = openmc.Cell(fill=water, region=+cyl)
|
||||
|
||||
univ = openmc.Universe(cells=[fuel, moderator])
|
||||
univ.fuel = fuel
|
||||
univ.moderator = moderator
|
||||
return univ
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def pincell2(uo2, water):
|
||||
cyl = openmc.ZCylinder(r=0.4)
|
||||
fuel = openmc.Cell(fill=uo2, region=-cyl)
|
||||
moderator = openmc.Cell(fill=water, region=+cyl)
|
||||
|
||||
univ = openmc.Universe(cells=[fuel, moderator])
|
||||
univ.fuel = fuel
|
||||
univ.moderator = moderator
|
||||
return univ
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def zr():
|
||||
zr = openmc.Material()
|
||||
zr.add_element('Zr', 1.0)
|
||||
zr.set_density('g/cm3', 1.0)
|
||||
return zr
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def rlat2(pincell1, pincell2, uo2, water, zr):
|
||||
"""2D Rectangular lattice for testing."""
|
||||
all_zr = openmc.Cell(fill=zr)
|
||||
pitch = 1.2
|
||||
n = 3
|
||||
u1, u2 = pincell1, pincell2
|
||||
lattice = openmc.RectLattice()
|
||||
lattice.lower_left = (-pitch*n/2, -pitch*n/2)
|
||||
lattice.pitch = (pitch, pitch)
|
||||
lattice.outer = openmc.Universe(cells=[all_zr])
|
||||
lattice.universes = [
|
||||
[u1, u2, u1],
|
||||
[u2, u1, u2],
|
||||
[u2, u1, u1]
|
||||
]
|
||||
|
||||
return lattice
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def rlat3(pincell1, pincell2, uo2, water, zr):
|
||||
"""3D Rectangular lattice for testing."""
|
||||
|
||||
# Create another universe for top layer
|
||||
hydrogen = openmc.Material()
|
||||
hydrogen.add_element('H', 1.0)
|
||||
hydrogen.set_density('g/cm3', 0.09)
|
||||
h_cell = openmc.Cell(fill=hydrogen)
|
||||
u3 = openmc.Universe(cells=[h_cell])
|
||||
|
||||
all_zr = openmc.Cell(fill=zr)
|
||||
pitch = 1.2
|
||||
n = 3
|
||||
u1, u2 = pincell1, pincell2
|
||||
lattice = openmc.RectLattice()
|
||||
lattice.lower_left = (-pitch*n/2, -pitch*n/2, -10.0)
|
||||
lattice.pitch = (pitch, pitch, 10.0)
|
||||
lattice.outer = openmc.Universe(cells=[all_zr])
|
||||
lattice.universes = [
|
||||
[[u1, u2, u1],
|
||||
[u2, u1, u2],
|
||||
[u2, u1, u1]],
|
||||
[[u3, u1, u2],
|
||||
[u1, u3, u2],
|
||||
[u2, u1, u1]]
|
||||
]
|
||||
|
||||
return lattice
|
||||
|
||||
|
||||
def test_mesh2d(rlat2):
|
||||
shape = np.array(rlat2.shape)
|
||||
width = shape*rlat2.pitch
|
||||
|
||||
mesh1 = openmc.RegularMesh.from_rect_lattice(rlat2)
|
||||
assert np.array_equal(mesh1.dimension, (3, 3))
|
||||
assert np.array_equal(mesh1.lower_left, rlat2.lower_left)
|
||||
assert np.array_equal(mesh1.upper_right, rlat2.lower_left + width)
|
||||
|
||||
mesh2 = openmc.RegularMesh.from_rect_lattice(rlat2, division=3)
|
||||
assert np.array_equal(mesh2.dimension, (9, 9))
|
||||
assert np.array_equal(mesh2.lower_left, rlat2.lower_left)
|
||||
assert np.array_equal(mesh2.upper_right, rlat2.lower_left + width)
|
||||
|
||||
|
||||
def test_mesh3d(rlat3):
|
||||
shape = np.array(rlat3.shape)
|
||||
width = shape*rlat3.pitch
|
||||
|
||||
mesh1 = openmc.RegularMesh.from_rect_lattice(rlat3)
|
||||
assert np.array_equal(mesh1.dimension, (3, 3, 2))
|
||||
assert np.array_equal(mesh1.lower_left, rlat3.lower_left)
|
||||
assert np.array_equal(mesh1.upper_right, rlat3.lower_left + width)
|
||||
|
||||
mesh2 = openmc.RegularMesh.from_rect_lattice(rlat3, division=3)
|
||||
assert np.array_equal(mesh2.dimension, (9, 9, 6))
|
||||
assert np.array_equal(mesh2.lower_left, rlat3.lower_left)
|
||||
assert np.array_equal(mesh2.upper_right, rlat3.lower_left + width)
|
||||
227
tests/unit_tests/test_model_triso.py
Normal file
227
tests/unit_tests/test_model_triso.py
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from math import pi
|
||||
|
||||
import numpy as np
|
||||
from numpy.linalg import norm
|
||||
import openmc
|
||||
import openmc.model
|
||||
import pytest
|
||||
import scipy.spatial
|
||||
|
||||
|
||||
_RADIUS = 0.1
|
||||
_PACKING_FRACTION = 0.35
|
||||
_PARAMS = [
|
||||
{'shape': 'rectangular_prism', 'volume': 1**3},
|
||||
{'shape': 'x_cylinder', 'volume': 1*pi*1**2},
|
||||
{'shape': 'y_cylinder', 'volume': 1*pi*1**2},
|
||||
{'shape': 'z_cylinder', 'volume': 1*pi*1**2},
|
||||
{'shape': 'sphere', 'volume': 4/3*pi*1**3},
|
||||
{'shape': 'spherical_shell', 'volume': 4/3*pi*(1**3 - 0.5**3)}
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope='module', params=_PARAMS)
|
||||
def container(request):
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def centers(request, container):
|
||||
return request.getfixturevalue('centers_' + container['shape'])
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def centers_rectangular_prism():
|
||||
min_x = openmc.XPlane(0)
|
||||
max_x = openmc.XPlane(1)
|
||||
min_y = openmc.YPlane(0)
|
||||
max_y = openmc.YPlane(1)
|
||||
min_z = openmc.ZPlane(0)
|
||||
max_z = openmc.ZPlane(1)
|
||||
region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z
|
||||
return openmc.model.pack_spheres(radius=_RADIUS, region=region,
|
||||
pf=_PACKING_FRACTION, initial_pf=0.2)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def centers_x_cylinder():
|
||||
cylinder = openmc.XCylinder(r=1, y0=1, z0=2)
|
||||
min_x = openmc.XPlane(0)
|
||||
max_x = openmc.XPlane(1)
|
||||
region = +min_x & -max_x & -cylinder
|
||||
return openmc.model.pack_spheres(radius=_RADIUS, region=region,
|
||||
pf=_PACKING_FRACTION, initial_pf=0.2)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def centers_y_cylinder():
|
||||
cylinder = openmc.YCylinder(r=1, x0=1, z0=2)
|
||||
min_y = openmc.YPlane(0)
|
||||
max_y = openmc.YPlane(1)
|
||||
region = +min_y & -max_y & -cylinder
|
||||
return openmc.model.pack_spheres(radius=_RADIUS, region=region,
|
||||
pf=_PACKING_FRACTION, initial_pf=0.2)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def centers_z_cylinder():
|
||||
cylinder = openmc.ZCylinder(r=1, x0=1, y0=2)
|
||||
min_z = openmc.ZPlane(0)
|
||||
max_z = openmc.ZPlane(1)
|
||||
region = +min_z & -max_z & -cylinder
|
||||
return openmc.model.pack_spheres(radius=_RADIUS, region=region,
|
||||
pf=_PACKING_FRACTION, initial_pf=0.2)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def centers_sphere():
|
||||
sphere = openmc.Sphere(r=1, x0=1, y0=2, z0=3)
|
||||
region = -sphere
|
||||
return openmc.model.pack_spheres(radius=_RADIUS, region=region,
|
||||
pf=_PACKING_FRACTION, initial_pf=0.2)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def centers_spherical_shell():
|
||||
sphere = openmc.Sphere(r=1, x0=1, y0=2, z0=3)
|
||||
inner_sphere = openmc.Sphere(r=0.5, x0=1, y0=2, z0=3)
|
||||
region = -sphere & +inner_sphere
|
||||
return openmc.model.pack_spheres(radius=_RADIUS, region=region,
|
||||
pf=_PACKING_FRACTION, initial_pf=0.2)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def triso_universe():
|
||||
sphere = openmc.Sphere(r=_RADIUS)
|
||||
cell = openmc.Cell(region=-sphere)
|
||||
univ = openmc.Universe(cells=[cell])
|
||||
return univ
|
||||
|
||||
|
||||
def test_overlap(centers):
|
||||
"""Check that none of the spheres in the packed configuration overlap."""
|
||||
# Create KD tree for quick nearest neighbor search
|
||||
tree = scipy.spatial.cKDTree(centers)
|
||||
|
||||
# Find distance to nearest neighbor for all spheres
|
||||
d = tree.query(centers, k=2)[0]
|
||||
|
||||
# Get the smallest distance between any two spheres
|
||||
d_min = min(d[:, 1])
|
||||
assert d_min > 2*_RADIUS or d_min == pytest.approx(2*_RADIUS)
|
||||
|
||||
|
||||
def test_contained_rectangular_prism(centers_rectangular_prism):
|
||||
"""Make sure all spheres are entirely contained within the domain."""
|
||||
d_max = np.amax(centers_rectangular_prism) + _RADIUS
|
||||
d_min = np.amin(centers_rectangular_prism) - _RADIUS
|
||||
assert d_max < 1 or d_max == pytest.approx(1)
|
||||
assert d_min > 0 or d_min == pytest.approx(0)
|
||||
|
||||
|
||||
def test_contained_x_cylinder(centers_x_cylinder):
|
||||
"""Make sure all spheres are entirely contained within the domain."""
|
||||
d = np.linalg.norm(centers_x_cylinder[:,[1,2]] - [1, 2], axis=1)
|
||||
r_max = max(d) + _RADIUS
|
||||
x_max = max(centers_x_cylinder[:,0]) + _RADIUS
|
||||
x_min = min(centers_x_cylinder[:,0]) - _RADIUS
|
||||
assert r_max < 1 or r_max == pytest.approx(1)
|
||||
assert x_max < 1 or x_max == pytest.approx(1)
|
||||
assert x_min > 0 or x_min == pytest.approx(0)
|
||||
|
||||
|
||||
def test_contained_y_cylinder(centers_y_cylinder):
|
||||
"""Make sure all spheres are entirely contained within the domain."""
|
||||
d = np.linalg.norm(centers_y_cylinder[:,[0,2]] - [1, 2], axis=1)
|
||||
r_max = max(d) + _RADIUS
|
||||
y_max = max(centers_y_cylinder[:,1]) + _RADIUS
|
||||
y_min = min(centers_y_cylinder[:,1]) - _RADIUS
|
||||
assert r_max < 1 or r_max == pytest.approx(1)
|
||||
assert y_max < 1 or y_max == pytest.approx(1)
|
||||
assert y_min > 0 or y_min == pytest.approx(0)
|
||||
|
||||
|
||||
def test_contained_z_cylinder(centers_z_cylinder):
|
||||
"""Make sure all spheres are entirely contained within the domain."""
|
||||
d = np.linalg.norm(centers_z_cylinder[:,[0,1]] - [1, 2], axis=1)
|
||||
r_max = max(d) + _RADIUS
|
||||
z_max = max(centers_z_cylinder[:,2]) + _RADIUS
|
||||
z_min = min(centers_z_cylinder[:,2]) - _RADIUS
|
||||
assert r_max < 1 or r_max == pytest.approx(1)
|
||||
assert z_max < 1 or z_max == pytest.approx(1)
|
||||
assert z_min > 0 or z_min == pytest.approx(0)
|
||||
|
||||
|
||||
def test_contained_sphere(centers_sphere):
|
||||
"""Make sure all spheres are entirely contained within the domain."""
|
||||
d = np.linalg.norm(centers_sphere - [1, 2, 3], axis=1)
|
||||
r_max = max(d) + _RADIUS
|
||||
assert r_max < 1 or r_max == pytest.approx(1)
|
||||
|
||||
|
||||
def test_contained_spherical_shell(centers_spherical_shell):
|
||||
"""Make sure all spheres are entirely contained within the domain."""
|
||||
d = np.linalg.norm(centers_spherical_shell - [1, 2, 3], axis=1)
|
||||
r_max = max(d) + _RADIUS
|
||||
r_min = min(d) - _RADIUS
|
||||
assert r_max < 1 or r_max == pytest.approx(1)
|
||||
assert r_min > 0.5 or r_min == pytest.approx(0.5)
|
||||
|
||||
|
||||
def test_packing_fraction(container, centers):
|
||||
"""Check that the actual PF is close to the requested PF."""
|
||||
pf = len(centers) * 4/3 * pi *_RADIUS**3 / container['volume']
|
||||
assert pf == pytest.approx(_PACKING_FRACTION, rel=1e-2)
|
||||
|
||||
|
||||
def test_num_spheres():
|
||||
"""Check that the function returns the correct number of spheres"""
|
||||
centers = openmc.model.pack_spheres(
|
||||
radius=_RADIUS, region=-openmc.Sphere(r=1), num_spheres=50
|
||||
)
|
||||
assert len(centers) == 50
|
||||
|
||||
|
||||
def test_triso_lattice(triso_universe, centers_rectangular_prism):
|
||||
trisos = [openmc.model.TRISO(_RADIUS, triso_universe, c)
|
||||
for c in centers_rectangular_prism]
|
||||
|
||||
lower_left = np.array((0, 0, 0))
|
||||
upper_right = np.array((1, 1, 1))
|
||||
shape = (3, 3, 3)
|
||||
pitch = (upper_right - lower_left)/shape
|
||||
background = openmc.Material()
|
||||
|
||||
lattice = openmc.model.create_triso_lattice(
|
||||
trisos, lower_left, pitch, shape, background
|
||||
)
|
||||
|
||||
|
||||
def test_container_input(triso_universe):
|
||||
# Invalid container shape
|
||||
with pytest.raises(ValueError):
|
||||
centers = openmc.model.pack_spheres(
|
||||
radius=_RADIUS, region=+openmc.Sphere(r=1), num_spheres=100
|
||||
)
|
||||
|
||||
|
||||
def test_packing_fraction_input():
|
||||
# Provide neither packing fraction nor number of spheres
|
||||
with pytest.raises(ValueError):
|
||||
centers = openmc.model.pack_spheres(
|
||||
radius=_RADIUS, region=-openmc.Sphere(r=1)
|
||||
)
|
||||
|
||||
# Specify a packing fraction that is too high for CRP
|
||||
with pytest.raises(ValueError):
|
||||
centers = openmc.model.pack_spheres(
|
||||
radius=_RADIUS, region=-openmc.Sphere(r=1), pf=1
|
||||
)
|
||||
|
||||
# Specify a packing fraction that is too high for RSP
|
||||
with pytest.raises(ValueError):
|
||||
centers = openmc.model.pack_spheres(
|
||||
radius=_RADIUS, region=-openmc.Sphere(r=1), pf=0.5, initial_pf=0.4
|
||||
)
|
||||
117
tests/unit_tests/test_pin.py
Normal file
117
tests/unit_tests/test_pin.py
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
"""
|
||||
Tests for constructing Pin universes
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
import openmc
|
||||
from openmc.model import pin
|
||||
|
||||
|
||||
def get_pin_radii(pin_univ):
|
||||
"""Return a sorted list of all radii from pin"""
|
||||
rads = set()
|
||||
|
||||
for cell in pin_univ.get_all_cells().values():
|
||||
surfs = cell.region.get_surfaces().values()
|
||||
rads.update(set(s.r for s in surfs))
|
||||
|
||||
return list(sorted(rads))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def pin_mats():
|
||||
fuel = openmc.Material(name="UO2")
|
||||
fuel.volume = 100
|
||||
clad = openmc.Material(name="zirc")
|
||||
clad.volume = 100
|
||||
water = openmc.Material(name="water")
|
||||
return fuel, clad, water
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def good_radii():
|
||||
return (0.4, 0.42)
|
||||
|
||||
|
||||
def test_failure(pin_mats, good_radii):
|
||||
"""Check for various failure modes"""
|
||||
good_surfaces = [openmc.ZCylinder(r=r) for r in good_radii]
|
||||
# Bad material type
|
||||
with pytest.raises(TypeError):
|
||||
pin(good_surfaces, [mat.name for mat in pin_mats])
|
||||
|
||||
# Incorrect lengths
|
||||
with pytest.raises(ValueError, match="length"):
|
||||
pin(good_surfaces[:len(pin_mats) - 2], pin_mats)
|
||||
|
||||
# Non-positive radii
|
||||
rad = [openmc.ZCylinder(r=-0.1)] + good_surfaces[1:]
|
||||
with pytest.raises(ValueError, match="index 0"):
|
||||
pin(rad, pin_mats)
|
||||
|
||||
# Non-increasing radii
|
||||
surfs = tuple(reversed(good_surfaces))
|
||||
with pytest.raises(ValueError, match="index 1"):
|
||||
pin(surfs, pin_mats)
|
||||
|
||||
# Bad orientation
|
||||
surfs = [openmc.XCylinder(r=good_surfaces[0].r)] + good_surfaces[1:]
|
||||
with pytest.raises(TypeError, match="surfaces"):
|
||||
pin(surfs, pin_mats)
|
||||
|
||||
# Passing cells argument
|
||||
with pytest.raises(SyntaxError, match="Cells"):
|
||||
pin(surfs, pin_mats, cells=[])
|
||||
|
||||
|
||||
def test_pins_of_universes(pin_mats, good_radii):
|
||||
"""Build a pin with a Universe in one ring"""
|
||||
u1 = openmc.Universe(cells=[openmc.Cell(fill=pin_mats[1])])
|
||||
new_items = pin_mats[:1] + (u1, ) + pin_mats[2:]
|
||||
new_pin = pin(
|
||||
[openmc.ZCylinder(r=r) for r in good_radii], new_items,
|
||||
subdivisions={0: 2}, divide_vols=True)
|
||||
assert len(new_pin.cells) == len(pin_mats) + 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"surf_type", [openmc.ZCylinder, openmc.XCylinder, openmc.YCylinder])
|
||||
def test_subdivide(pin_mats, good_radii, surf_type):
|
||||
"""Test the subdivision with various orientations"""
|
||||
surfs = [surf_type(r=r) for r in good_radii]
|
||||
fresh = pin(surfs, pin_mats, name="fresh pin")
|
||||
assert len(fresh.cells) == len(pin_mats)
|
||||
assert fresh.name == "fresh pin"
|
||||
|
||||
# subdivide inner region
|
||||
N = 5
|
||||
div0 = pin(surfs, pin_mats, {0: N})
|
||||
assert len(div0.cells) == len(pin_mats) + N - 1
|
||||
|
||||
# Check volume of fuel material
|
||||
for mid, mat in div0.get_all_materials().items():
|
||||
if mat.name == "UO2":
|
||||
assert mat.volume == pytest.approx(100 / N)
|
||||
|
||||
# check volumes of new rings
|
||||
radii = get_pin_radii(div0)
|
||||
bounds = [0] + radii[:N]
|
||||
sqrs = np.square(bounds)
|
||||
assert np.all(sqrs[1:] - sqrs[:-1] == pytest.approx(good_radii[0] ** 2 / N))
|
||||
|
||||
# subdivide non-inner most region
|
||||
new_pin = pin(surfs, pin_mats, {1: N})
|
||||
assert len(new_pin.cells) == len(pin_mats) + N - 1
|
||||
|
||||
# Check volume of clad material
|
||||
for mid, mat in div0.get_all_materials().items():
|
||||
if mat.name == "zirc":
|
||||
assert mat.volume == pytest.approx(100 / N)
|
||||
|
||||
# check volumes of new rings
|
||||
radii = get_pin_radii(new_pin)
|
||||
sqrs = np.square(radii[:N + 1])
|
||||
assert np.all(sqrs[1:] - sqrs[:-1] == pytest.approx(
|
||||
(good_radii[1] ** 2 - good_radii[0] ** 2) / N))
|
||||
94
tests/unit_tests/test_plots.py
Normal file
94
tests/unit_tests/test_plots.py
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
import openmc
|
||||
import openmc.examples
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def myplot():
|
||||
plot = openmc.Plot(name='myplot')
|
||||
plot.width = (100., 100.)
|
||||
plot.origin = (2., 3., -10.)
|
||||
plot.pixels = (500, 500)
|
||||
plot.filename = 'myplot'
|
||||
plot.type = 'slice'
|
||||
plot.basis = 'yz'
|
||||
plot.background = (0, 0, 0)
|
||||
plot.background = 'black'
|
||||
|
||||
plot.color_by = 'material'
|
||||
m1, m2 = openmc.Material(), openmc.Material()
|
||||
plot.colors = {m1: (0, 255, 0), m2: (0, 0, 255)}
|
||||
plot.colors = {m1: 'green', m2: 'blue'}
|
||||
|
||||
plot.mask_components = [openmc.Material()]
|
||||
plot.mask_background = (255, 255, 255)
|
||||
plot.mask_background = 'white'
|
||||
|
||||
plot.overlap_color = (255, 211, 0)
|
||||
plot.overlap_color = 'yellow'
|
||||
plot.show_overlaps = True
|
||||
|
||||
plot.level = 1
|
||||
plot.meshlines = {
|
||||
'type': 'tally',
|
||||
'id': 1,
|
||||
'linewidth': 2,
|
||||
'color': (40, 30, 20)
|
||||
}
|
||||
return plot
|
||||
|
||||
|
||||
def test_attributes(myplot):
|
||||
assert myplot.name == 'myplot'
|
||||
|
||||
|
||||
def test_repr(myplot):
|
||||
r = repr(myplot)
|
||||
assert isinstance(r, str)
|
||||
|
||||
|
||||
def test_from_geometry():
|
||||
width = 25.
|
||||
s = openmc.Sphere(r=width/2, boundary_type='vacuum')
|
||||
c = openmc.Cell(region=-s)
|
||||
univ = openmc.Universe(cells=[c])
|
||||
geom = openmc.Geometry(univ)
|
||||
|
||||
for basis in ('xy', 'yz', 'xz'):
|
||||
plot = openmc.Plot.from_geometry(geom, basis)
|
||||
assert plot.origin == pytest.approx((0., 0., 0.))
|
||||
assert plot.width == pytest.approx((width, width))
|
||||
|
||||
|
||||
def test_highlight_domains():
|
||||
plot = openmc.Plot()
|
||||
plot.color_by = 'material'
|
||||
plots = openmc.Plots([plot])
|
||||
|
||||
model = openmc.examples.pwr_pin_cell()
|
||||
mats = {m for m in model.materials if 'UO2' in m.name}
|
||||
plots.highlight_domains(model.geometry, mats)
|
||||
|
||||
|
||||
def test_to_xml_element(myplot):
|
||||
elem = myplot.to_xml_element()
|
||||
assert 'id' in elem.attrib
|
||||
assert 'color_by' in elem.attrib
|
||||
assert 'type' in elem.attrib
|
||||
assert elem.find('origin') is not None
|
||||
assert elem.find('width') is not None
|
||||
assert elem.find('pixels') is not None
|
||||
assert elem.find('background').text == '0 0 0'
|
||||
|
||||
|
||||
def test_plots(run_in_tmpdir):
|
||||
p1 = openmc.Plot(name='plot1')
|
||||
p2 = openmc.Plot(name='plot2')
|
||||
plots = openmc.Plots([p1, p2])
|
||||
assert len(plots) == 2
|
||||
|
||||
p3 = openmc.Plot(name='plot3')
|
||||
plots.append(p3)
|
||||
assert len(plots) == 3
|
||||
|
||||
plots.export_to_xml()
|
||||
44
tests/unit_tests/test_polynomials.py
Normal file
44
tests/unit_tests/test_polynomials.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import numpy as np
|
||||
|
||||
import openmc
|
||||
|
||||
|
||||
def test_zernike_radial():
|
||||
coeff = np.asarray([1.3, -3.0, 9e-1, -6e-1, 0.11])
|
||||
zn_rad = openmc.ZernikeRadial(coeff)
|
||||
assert zn_rad.order == 8
|
||||
assert zn_rad.radius == 1
|
||||
|
||||
coeff = np.asarray([1.3, -3.0, 9e-1, -6e-1, 0.11, 0.222])
|
||||
zn_rad = openmc.ZernikeRadial(coeff, 0.392)
|
||||
assert zn_rad.order == 10
|
||||
assert zn_rad.radius == 0.392
|
||||
norm_vec = (2 * np.arange(6) + 1) / (np.pi * 0.392 ** 2)
|
||||
norm_coeff = norm_vec * coeff
|
||||
|
||||
rho = 0.5
|
||||
# Reference solution from running the Fortran implementation
|
||||
raw_zn = np.array([
|
||||
1.00000000e+00, -5.00000000e-01, -1.25000000e-01,
|
||||
4.37500000e-01, -2.89062500e-01, -8.98437500e-02])
|
||||
|
||||
ref_vals = np.sum(norm_coeff * raw_zn)
|
||||
|
||||
test_vals = zn_rad(rho)
|
||||
|
||||
assert ref_vals == test_vals
|
||||
|
||||
rho = [0.2, 0.5]
|
||||
# Reference solution from running the Fortran implementation
|
||||
raw_zn1 = np.array([
|
||||
1.00000000e+00, -9.20000000e-01, 7.69600000e-01,
|
||||
-5.66720000e-01, 3.35219200e-01, -1.01747000e-01])
|
||||
raw_zn2 = np.array([
|
||||
1.00000000e+00, -5.00000000e-01, -1.25000000e-01,
|
||||
4.37500000e-01, -2.89062500e-01, -8.98437500e-02])
|
||||
|
||||
ref_vals = [np.sum(norm_coeff * raw_zn1), np.sum(norm_coeff * raw_zn2)]
|
||||
|
||||
test_vals = zn_rad(rho)
|
||||
|
||||
assert np.allclose(ref_vals, test_vals)
|
||||
180
tests/unit_tests/test_region.py
Normal file
180
tests/unit_tests/test_region.py
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
import numpy as np
|
||||
import pytest
|
||||
import openmc
|
||||
|
||||
from tests.unit_tests import assert_unbounded
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def reset():
|
||||
openmc.reset_auto_ids()
|
||||
|
||||
|
||||
def test_union(reset):
|
||||
s1 = openmc.XPlane(x0=5, surface_id=1)
|
||||
s2 = openmc.XPlane(x0=-5, surface_id=2)
|
||||
region = +s1 | -s2
|
||||
assert isinstance(region, openmc.Union)
|
||||
|
||||
# Check bounding box
|
||||
assert_unbounded(region)
|
||||
|
||||
# __contains__
|
||||
assert (6, 0, 0) in region
|
||||
assert (-6, 0, 0) in region
|
||||
assert (0, 0, 0) not in region
|
||||
|
||||
# string representation
|
||||
assert str(region) == '(1 | -2)'
|
||||
|
||||
# Combining region with intersection
|
||||
s3 = openmc.YPlane(surface_id=3)
|
||||
reg2 = region & +s3
|
||||
assert (6, 1, 0) in reg2
|
||||
assert (6, -1, 0) not in reg2
|
||||
assert str(reg2) == '((1 | -2) 3)'
|
||||
|
||||
# translate method
|
||||
regt = region.translate((2.0, 0.0, 0.0))
|
||||
assert (-4, 0, 0) in regt
|
||||
assert (6, 0, 0) not in regt
|
||||
assert (8, 0, 0) in regt
|
||||
|
||||
|
||||
def test_intersection(reset):
|
||||
s1 = openmc.XPlane(x0=5, surface_id=1)
|
||||
s2 = openmc.XPlane(x0=-5, surface_id=2)
|
||||
region = -s1 & +s2
|
||||
assert isinstance(region, openmc.Intersection)
|
||||
|
||||
# Check bounding box
|
||||
ll, ur = region.bounding_box
|
||||
assert ll == pytest.approx((-5, -np.inf, -np.inf))
|
||||
assert ur == pytest.approx((5, np.inf, np.inf))
|
||||
|
||||
# __contains__
|
||||
assert (6, 0, 0) not in region
|
||||
assert (-6, 0, 0) not in region
|
||||
assert (0, 0, 0) in region
|
||||
|
||||
# string representation
|
||||
assert str(region) == '(-1 2)'
|
||||
|
||||
# Combining region with union
|
||||
s3 = openmc.YPlane(surface_id=3)
|
||||
reg2 = region | +s3
|
||||
assert (-6, 2, 0) in reg2
|
||||
assert (-6, -2, 0) not in reg2
|
||||
assert str(reg2) == '((-1 2) | 3)'
|
||||
|
||||
# translate method
|
||||
regt = region.translate((2.0, 0.0, 0.0))
|
||||
assert (-4, 0, 0) not in regt
|
||||
assert (6, 0, 0) in regt
|
||||
assert (8, 0, 0) not in regt
|
||||
|
||||
|
||||
def test_complement(reset):
|
||||
zcyl = openmc.ZCylinder(r=1., surface_id=1)
|
||||
z0 = openmc.ZPlane(-5., surface_id=2)
|
||||
z1 = openmc.ZPlane(5., surface_id=3)
|
||||
outside = +zcyl | -z0 | +z1
|
||||
inside = ~outside
|
||||
outside_equiv = ~(-zcyl & +z0 & -z1)
|
||||
inside_equiv = ~outside_equiv
|
||||
|
||||
# Check bounding box
|
||||
for region in (inside, inside_equiv):
|
||||
ll, ur = region.bounding_box
|
||||
assert ll == pytest.approx((-1., -1., -5.))
|
||||
assert ur == pytest.approx((1., 1., 5.))
|
||||
assert_unbounded(outside)
|
||||
assert_unbounded(outside_equiv)
|
||||
|
||||
# string represention
|
||||
assert str(inside) == '~(1 | -2 | 3)'
|
||||
|
||||
# evaluate method
|
||||
assert (0, 0, 0) in inside
|
||||
assert (0, 0, 0) not in outside
|
||||
assert (0, 0, 6) not in inside
|
||||
assert (0, 0, 6) in outside
|
||||
|
||||
# translate method
|
||||
inside_t = inside.translate((1.0, 1.0, 1.0))
|
||||
ll, ur = inside_t.bounding_box
|
||||
assert ll == pytest.approx((0., 0., -4.))
|
||||
assert ur == pytest.approx((2., 2., 6.))
|
||||
|
||||
|
||||
def test_get_surfaces():
|
||||
s1 = openmc.XPlane()
|
||||
s2 = openmc.YPlane()
|
||||
s3 = openmc.ZPlane()
|
||||
region = (+s1 & -s2) | +s3
|
||||
|
||||
# Make sure get_surfaces() returns all surfaces
|
||||
surfs = set(region.get_surfaces().values())
|
||||
assert not (surfs ^ {s1, s2, s3})
|
||||
|
||||
inverse = ~region
|
||||
surfs = set(inverse.get_surfaces().values())
|
||||
assert not (surfs ^ {s1, s2, s3})
|
||||
|
||||
|
||||
def test_extend_clone():
|
||||
s1 = openmc.XPlane()
|
||||
s2 = openmc.YPlane()
|
||||
s3 = openmc.ZPlane()
|
||||
s4 = openmc.ZCylinder()
|
||||
|
||||
# extend intersection
|
||||
r1 = +s1 & -s2
|
||||
r1 &= +s3 & -s4
|
||||
assert r1[:] == [+s1, -s2, +s3, -s4]
|
||||
|
||||
# extend union
|
||||
r2 = +s1 | -s2
|
||||
r2 |= +s3 | -s4
|
||||
assert r2[:] == [+s1, -s2, +s3, -s4]
|
||||
|
||||
# clone methods
|
||||
r3 = r1.clone()
|
||||
assert len(r3) == len(r1)
|
||||
r4 = r2.clone()
|
||||
assert len(r4) == len(r2)
|
||||
|
||||
r5 = ~r1
|
||||
r6 = r5.clone()
|
||||
|
||||
|
||||
def test_from_expression(reset):
|
||||
# Create surface dictionary
|
||||
s1 = openmc.ZCylinder(surface_id=1)
|
||||
s2 = openmc.ZPlane(-10., surface_id=2)
|
||||
s3 = openmc.ZPlane(10., surface_id=3)
|
||||
surfs = {1: s1, 2: s2, 3: s3}
|
||||
|
||||
r = openmc.Region.from_expression('-1 2 -3', surfs)
|
||||
assert isinstance(r, openmc.Intersection)
|
||||
assert r[:] == [-s1, +s2, -s3]
|
||||
|
||||
r = openmc.Region.from_expression('+1 | -2 | +3', surfs)
|
||||
assert isinstance(r, openmc.Union)
|
||||
assert r[:] == [+s1, -s2, +s3]
|
||||
|
||||
r = openmc.Region.from_expression('~(-1)', surfs)
|
||||
assert r == +s1
|
||||
|
||||
# Since & has higher precendence than |, the resulting region should be an
|
||||
# instance of Union
|
||||
r = openmc.Region.from_expression('1 -2 | 3', surfs)
|
||||
assert isinstance(r, openmc.Union)
|
||||
assert isinstance(r[0], openmc.Intersection)
|
||||
assert r[0][:] == [+s1, -s2]
|
||||
|
||||
# ...but not if we use parentheses
|
||||
r = openmc.Region.from_expression('1 (-2 | 3)', surfs)
|
||||
assert isinstance(r, openmc.Intersection)
|
||||
assert isinstance(r[1], openmc.Union)
|
||||
assert r[1][:] == [-s2, +s3]
|
||||
106
tests/unit_tests/test_settings.py
Normal file
106
tests/unit_tests/test_settings.py
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
import openmc
|
||||
import openmc.stats
|
||||
|
||||
|
||||
def test_export_to_xml(run_in_tmpdir):
|
||||
s = openmc.Settings()
|
||||
s.run_mode = 'fixed source'
|
||||
s.batches = 1000
|
||||
s.generations_per_batch = 10
|
||||
s.inactive = 100
|
||||
s.particles = 1000000
|
||||
s.keff_trigger = {'type': 'std_dev', 'threshold': 0.001}
|
||||
s.energy_mode = 'continuous-energy'
|
||||
s.max_order = 5
|
||||
s.source = openmc.Source(space=openmc.stats.Point())
|
||||
s.output = {'summary': True, 'tallies': False, 'path': 'here'}
|
||||
s.verbosity = 7
|
||||
s.sourcepoint = {'batches': [50, 150, 500, 1000], 'separate': True,
|
||||
'write': True, 'overwrite': True}
|
||||
s.statepoint = {'batches': [50, 150, 500, 1000]}
|
||||
s.confidence_intervals = True
|
||||
s.ptables = True
|
||||
s.seed = 17
|
||||
s.survival_biasing = True
|
||||
s.cutoff = {'weight': 0.25, 'weight_avg': 0.5, 'energy_neutron': 1.0e-5,
|
||||
'energy_photon': 1000.0, 'energy_electron': 1.0e-5,
|
||||
'energy_positron': 1.0e-5}
|
||||
mesh = openmc.RegularMesh()
|
||||
mesh.lower_left = (-10., -10., -10.)
|
||||
mesh.upper_right = (10., 10., 10.)
|
||||
mesh.dimension = (5, 5, 5)
|
||||
s.entropy_mesh = mesh
|
||||
s.trigger_active = True
|
||||
s.trigger_max_batches = 10000
|
||||
s.trigger_batch_interval = 50
|
||||
s.no_reduce = False
|
||||
s.tabular_legendre = {'enable': True, 'num_points': 50}
|
||||
s.temperature = {'default': 293.6, 'method': 'interpolation',
|
||||
'multipole': True, 'range': (200., 1000.)}
|
||||
s.trace = (10, 1, 20)
|
||||
s.track = [1, 1, 1, 2, 1, 1]
|
||||
s.ufs_mesh = mesh
|
||||
s.resonance_scattering = {'enable': True, 'method': 'rvs',
|
||||
'energy_min': 1.0, 'energy_max': 1000.0,
|
||||
'nuclides': ['U235', 'U238', 'Pu239']}
|
||||
s.volume_calculations = openmc.VolumeCalculation(
|
||||
domains=[openmc.Cell()], samples=1000, lower_left=(-10., -10., -10.),
|
||||
upper_right = (10., 10., 10.))
|
||||
s.create_fission_neutrons = True
|
||||
s.log_grid_bins = 2000
|
||||
s.photon_transport = False
|
||||
s.electron_treatment = 'led'
|
||||
s.dagmc = False
|
||||
|
||||
# Make sure exporting XML works
|
||||
s.export_to_xml()
|
||||
|
||||
# Generate settings from XML
|
||||
s = openmc.Settings.from_xml()
|
||||
assert s.run_mode == 'fixed source'
|
||||
assert s.batches == 1000
|
||||
assert s.generations_per_batch == 10
|
||||
assert s.inactive == 100
|
||||
assert s.particles == 1000000
|
||||
assert s.keff_trigger == {'type': 'std_dev', 'threshold': 0.001}
|
||||
assert s.energy_mode == 'continuous-energy'
|
||||
assert s.max_order == 5
|
||||
assert isinstance(s.source[0], openmc.Source)
|
||||
assert isinstance(s.source[0].space, openmc.stats.Point)
|
||||
assert s.output == {'summary': True, 'tallies': False, 'path': 'here'}
|
||||
assert s.verbosity == 7
|
||||
assert s.sourcepoint == {'batches': [50, 150, 500, 1000], 'separate': True,
|
||||
'write': True, 'overwrite': True}
|
||||
assert s.statepoint == {'batches': [50, 150, 500, 1000]}
|
||||
assert s.confidence_intervals
|
||||
assert s.ptables
|
||||
assert s.seed == 17
|
||||
assert s.survival_biasing
|
||||
assert s.cutoff == {'weight': 0.25, 'weight_avg': 0.5,
|
||||
'energy_neutron': 1.0e-5, 'energy_photon': 1000.0,
|
||||
'energy_electron': 1.0e-5, 'energy_positron': 1.0e-5}
|
||||
assert isinstance(s.entropy_mesh, openmc.RegularMesh)
|
||||
assert s.entropy_mesh.lower_left == [-10., -10., -10.]
|
||||
assert s.entropy_mesh.upper_right == [10., 10., 10.]
|
||||
assert s.entropy_mesh.dimension == [5, 5, 5]
|
||||
assert s.trigger_active
|
||||
assert s.trigger_max_batches == 10000
|
||||
assert s.trigger_batch_interval == 50
|
||||
assert not s.no_reduce
|
||||
assert s.tabular_legendre == {'enable': True, 'num_points': 50}
|
||||
assert s.temperature == {'default': 293.6, 'method': 'interpolation',
|
||||
'multipole': True, 'range': [200., 1000.]}
|
||||
assert s.trace == [10, 1, 20]
|
||||
assert s.track == [1, 1, 1, 2, 1, 1]
|
||||
assert isinstance(s.ufs_mesh, openmc.RegularMesh)
|
||||
assert s.ufs_mesh.lower_left == [-10., -10., -10.]
|
||||
assert s.ufs_mesh.upper_right == [10., 10., 10.]
|
||||
assert s.ufs_mesh.dimension == [5, 5, 5]
|
||||
assert s.resonance_scattering == {'enable': True, 'method': 'rvs',
|
||||
'energy_min': 1.0, 'energy_max': 1000.0,
|
||||
'nuclides': ['U235', 'U238', 'Pu239']}
|
||||
assert s.create_fission_neutrons
|
||||
assert s.log_grid_bins == 2000
|
||||
assert not s.photon_transport
|
||||
assert s.electron_treatment == 'led'
|
||||
assert not s.dagmc
|
||||
36
tests/unit_tests/test_source.py
Normal file
36
tests/unit_tests/test_source.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import openmc
|
||||
import openmc.stats
|
||||
|
||||
|
||||
def test_source():
|
||||
space = openmc.stats.Point()
|
||||
energy = openmc.stats.Discrete([1.0e6], [1.0])
|
||||
angle = openmc.stats.Isotropic()
|
||||
|
||||
src = openmc.Source(space=space, angle=angle, energy=energy)
|
||||
assert src.space == space
|
||||
assert src.angle == angle
|
||||
assert src.energy == energy
|
||||
|
||||
elem = src.to_xml_element()
|
||||
assert 'strength' in elem.attrib
|
||||
assert elem.find('space') is not None
|
||||
assert elem.find('angle') is not None
|
||||
assert elem.find('energy') is not None
|
||||
|
||||
src = openmc.Source.from_xml_element(elem)
|
||||
assert isinstance(src.angle, openmc.stats.Isotropic)
|
||||
assert src.space.xyz == [0.0, 0.0, 0.0]
|
||||
assert src.energy.x == [1.0e6]
|
||||
assert src.energy.p == [1.0]
|
||||
assert src.strength == 1.0
|
||||
|
||||
|
||||
def test_source_file():
|
||||
filename = 'source.h5'
|
||||
src = openmc.Source(filename=filename)
|
||||
assert src.file == filename
|
||||
|
||||
elem = src.to_xml_element()
|
||||
assert 'strength' in elem.attrib
|
||||
assert 'file' in elem.attrib
|
||||
243
tests/unit_tests/test_stats.py
Normal file
243
tests/unit_tests/test_stats.py
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
from math import pi
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
import openmc
|
||||
import openmc.stats
|
||||
|
||||
|
||||
def test_discrete():
|
||||
x = [0.0, 1.0, 10.0]
|
||||
p = [0.3, 0.2, 0.5]
|
||||
d = openmc.stats.Discrete(x, p)
|
||||
elem = d.to_xml_element('distribution')
|
||||
|
||||
d = openmc.stats.Discrete.from_xml_element(elem)
|
||||
assert d.x == x
|
||||
assert d.p == p
|
||||
assert len(d) == len(x)
|
||||
|
||||
d = openmc.stats.Univariate.from_xml_element(elem)
|
||||
assert isinstance(d, openmc.stats.Discrete)
|
||||
|
||||
# Single point
|
||||
d2 = openmc.stats.Discrete(1e6, 1.0)
|
||||
assert d2.x == [1e6]
|
||||
assert d2.p == [1.0]
|
||||
assert len(d2) == 1
|
||||
|
||||
|
||||
def test_uniform():
|
||||
a, b = 10.0, 20.0
|
||||
d = openmc.stats.Uniform(a, b)
|
||||
elem = d.to_xml_element('distribution')
|
||||
|
||||
d = openmc.stats.Uniform.from_xml_element(elem)
|
||||
assert d.a == a
|
||||
assert d.b == b
|
||||
assert len(d) == 2
|
||||
|
||||
t = d.to_tabular()
|
||||
assert t.x == [a, b]
|
||||
assert t.p == [1/(b-a), 1/(b-a)]
|
||||
assert t.interpolation == 'histogram'
|
||||
|
||||
|
||||
def test_maxwell():
|
||||
theta = 1.2895e6
|
||||
d = openmc.stats.Maxwell(theta)
|
||||
elem = d.to_xml_element('distribution')
|
||||
|
||||
d = openmc.stats.Maxwell.from_xml_element(elem)
|
||||
assert d.theta == theta
|
||||
assert len(d) == 1
|
||||
|
||||
|
||||
def test_watt():
|
||||
a, b = 0.965e6, 2.29e-6
|
||||
d = openmc.stats.Watt(a, b)
|
||||
elem = d.to_xml_element('distribution')
|
||||
|
||||
d = openmc.stats.Watt.from_xml_element(elem)
|
||||
assert d.a == a
|
||||
assert d.b == b
|
||||
assert len(d) == 2
|
||||
|
||||
|
||||
def test_tabular():
|
||||
x = [0.0, 5.0, 7.0]
|
||||
p = [0.1, 0.2, 0.05]
|
||||
d = openmc.stats.Tabular(x, p, 'linear-linear')
|
||||
elem = d.to_xml_element('distribution')
|
||||
|
||||
d = openmc.stats.Tabular.from_xml_element(elem)
|
||||
assert d.x == x
|
||||
assert d.p == p
|
||||
assert d.interpolation == 'linear-linear'
|
||||
assert len(d) == len(x)
|
||||
|
||||
|
||||
def test_legendre():
|
||||
# Pu239 elastic scattering at 100 keV
|
||||
coeffs = [1.000e+0, 1.536e-1, 1.772e-2, 5.945e-4, 3.497e-5, 1.881e-5]
|
||||
d = openmc.stats.Legendre(coeffs)
|
||||
assert d.coefficients == pytest.approx(coeffs)
|
||||
assert len(d) == len(coeffs)
|
||||
|
||||
# Integrating distribution should yield one
|
||||
mu = np.linspace(-1., 1., 1000)
|
||||
assert np.trapz(d(mu), mu) == pytest.approx(1.0, rel=1e-4)
|
||||
|
||||
with pytest.raises(NotImplementedError):
|
||||
d.to_xml_element('distribution')
|
||||
|
||||
|
||||
def test_mixture():
|
||||
d1 = openmc.stats.Uniform(0, 5)
|
||||
d2 = openmc.stats.Uniform(3, 7)
|
||||
p = [0.5, 0.5]
|
||||
mix = openmc.stats.Mixture(p, [d1, d2])
|
||||
assert mix.probability == p
|
||||
assert mix.distribution == [d1, d2]
|
||||
assert len(mix) == 4
|
||||
|
||||
with pytest.raises(NotImplementedError):
|
||||
mix.to_xml_element('distribution')
|
||||
|
||||
|
||||
def test_polar_azimuthal():
|
||||
# default polar-azimuthal should be uniform in mu and phi
|
||||
d = openmc.stats.PolarAzimuthal()
|
||||
assert isinstance(d.mu, openmc.stats.Uniform)
|
||||
assert d.mu.a == -1.
|
||||
assert d.mu.b == 1.
|
||||
assert isinstance(d.phi, openmc.stats.Uniform)
|
||||
assert d.phi.a == 0.
|
||||
assert d.phi.b == 2*pi
|
||||
|
||||
mu = openmc.stats.Discrete(1., 1.)
|
||||
phi = openmc.stats.Discrete(0., 1.)
|
||||
d = openmc.stats.PolarAzimuthal(mu, phi)
|
||||
assert d.mu == mu
|
||||
assert d.phi == phi
|
||||
|
||||
elem = d.to_xml_element()
|
||||
assert elem.tag == 'angle'
|
||||
assert elem.attrib['type'] == 'mu-phi'
|
||||
assert elem.find('mu') is not None
|
||||
assert elem.find('phi') is not None
|
||||
|
||||
d = openmc.stats.PolarAzimuthal.from_xml_element(elem)
|
||||
assert d.mu.x == [1.]
|
||||
assert d.mu.p == [1.]
|
||||
assert d.phi.x == [0.]
|
||||
assert d.phi.p == [1.]
|
||||
|
||||
d = openmc.stats.UnitSphere.from_xml_element(elem)
|
||||
assert isinstance(d, openmc.stats.PolarAzimuthal)
|
||||
|
||||
|
||||
def test_isotropic():
|
||||
d = openmc.stats.Isotropic()
|
||||
elem = d.to_xml_element()
|
||||
assert elem.tag == 'angle'
|
||||
assert elem.attrib['type'] == 'isotropic'
|
||||
|
||||
d = openmc.stats.Isotropic.from_xml_element(elem)
|
||||
assert isinstance(d, openmc.stats.Isotropic)
|
||||
|
||||
|
||||
def test_monodirectional():
|
||||
d = openmc.stats.Monodirectional((1., 0., 0.))
|
||||
elem = d.to_xml_element()
|
||||
assert elem.tag == 'angle'
|
||||
assert elem.attrib['type'] == 'monodirectional'
|
||||
|
||||
d = openmc.stats.Monodirectional.from_xml_element(elem)
|
||||
assert d.reference_uvw == pytest.approx((1., 0., 0.))
|
||||
|
||||
|
||||
def test_cartesian():
|
||||
x = openmc.stats.Uniform(-10., 10.)
|
||||
y = openmc.stats.Uniform(-10., 10.)
|
||||
z = openmc.stats.Uniform(0., 20.)
|
||||
d = openmc.stats.CartesianIndependent(x, y, z)
|
||||
|
||||
elem = d.to_xml_element()
|
||||
assert elem.tag == 'space'
|
||||
assert elem.attrib['type'] == 'cartesian'
|
||||
assert elem.find('x') is not None
|
||||
assert elem.find('y') is not None
|
||||
|
||||
d = openmc.stats.CartesianIndependent.from_xml_element(elem)
|
||||
assert d.x == x
|
||||
assert d.y == y
|
||||
assert d.z == z
|
||||
|
||||
d = openmc.stats.Spatial.from_xml_element(elem)
|
||||
assert isinstance(d, openmc.stats.CartesianIndependent)
|
||||
|
||||
|
||||
def test_box():
|
||||
lower_left = (-10., -10., -10.)
|
||||
upper_right = (10., 10., 10.)
|
||||
d = openmc.stats.Box(lower_left, upper_right)
|
||||
|
||||
elem = d.to_xml_element()
|
||||
assert elem.tag == 'space'
|
||||
assert elem.attrib['type'] == 'box'
|
||||
assert elem.find('parameters') is not None
|
||||
|
||||
d = openmc.stats.Box.from_xml_element(elem)
|
||||
assert d.lower_left == pytest.approx(lower_left)
|
||||
assert d.upper_right == pytest.approx(upper_right)
|
||||
assert not d.only_fissionable
|
||||
|
||||
# only fissionable parameter
|
||||
d2 = openmc.stats.Box(lower_left, upper_right, True)
|
||||
assert d2.only_fissionable
|
||||
elem = d2.to_xml_element()
|
||||
assert elem.attrib['type'] == 'fission'
|
||||
d = openmc.stats.Spatial.from_xml_element(elem)
|
||||
assert isinstance(d, openmc.stats.Box)
|
||||
|
||||
|
||||
def test_point():
|
||||
p = (-4., 2., 10.)
|
||||
d = openmc.stats.Point(p)
|
||||
|
||||
elem = d.to_xml_element()
|
||||
assert elem.tag == 'space'
|
||||
assert elem.attrib['type'] == 'point'
|
||||
assert elem.find('parameters') is not None
|
||||
|
||||
d = openmc.stats.Point.from_xml_element(elem)
|
||||
assert d.xyz == pytest.approx(p)
|
||||
|
||||
def test_normal():
|
||||
mean = 10.0
|
||||
std_dev = 2.0
|
||||
d = openmc.stats.Normal(mean,std_dev)
|
||||
|
||||
elem = d.to_xml_element('distribution')
|
||||
assert elem.attrib['type'] == 'normal'
|
||||
|
||||
d = openmc.stats.Normal.from_xml_element(elem)
|
||||
assert d.mean_value == pytest.approx(mean)
|
||||
assert d.std_dev == pytest.approx(std_dev)
|
||||
assert len(d) == 2
|
||||
|
||||
def test_muir():
|
||||
mean = 10.0
|
||||
mass = 5.0
|
||||
temp = 20000.
|
||||
d = openmc.stats.Muir(mean,mass,temp)
|
||||
|
||||
elem = d.to_xml_element('energy')
|
||||
assert elem.attrib['type'] == 'muir'
|
||||
|
||||
d = openmc.stats.Muir.from_xml_element(elem)
|
||||
assert d.e0 == pytest.approx(mean)
|
||||
assert d.m_rat == pytest.approx(mass)
|
||||
assert d.kt == pytest.approx(temp)
|
||||
assert len(d) == 3
|
||||
392
tests/unit_tests/test_surface.py
Normal file
392
tests/unit_tests/test_surface.py
Normal file
|
|
@ -0,0 +1,392 @@
|
|||
from functools import partial
|
||||
from random import uniform, seed
|
||||
|
||||
import numpy as np
|
||||
import openmc
|
||||
import pytest
|
||||
|
||||
|
||||
def assert_infinite_bb(s):
|
||||
ll, ur = (-s).bounding_box
|
||||
assert np.all(np.isinf(ll))
|
||||
assert np.all(np.isinf(ur))
|
||||
ll, ur = (+s).bounding_box
|
||||
assert np.all(np.isinf(ll))
|
||||
assert np.all(np.isinf(ur))
|
||||
|
||||
|
||||
def test_plane():
|
||||
s = openmc.Plane(a=1, b=2, c=-1, d=3, name='my plane')
|
||||
assert s.a == 1
|
||||
assert s.b == 2
|
||||
assert s.c == -1
|
||||
assert s.d == 3
|
||||
assert s.boundary_type == 'transmission'
|
||||
assert s.name == 'my plane'
|
||||
assert s.type == 'plane'
|
||||
|
||||
# Generic planes don't have well-defined bounding boxes
|
||||
assert_infinite_bb(s)
|
||||
|
||||
# evaluate method
|
||||
x, y, z = (4, 3, 6)
|
||||
assert s.evaluate((x, y, z)) == pytest.approx(s.a*x + s.b*y + s.c*z - s.d)
|
||||
|
||||
# translate method
|
||||
st = s.translate((1.0, 0.0, 0.0))
|
||||
assert (st.a, st.b, st.c, st.d) == (s.a, s.b, s.c, 4)
|
||||
|
||||
# Make sure repr works
|
||||
repr(s)
|
||||
|
||||
|
||||
def test_plane_from_points():
|
||||
# Generate the plane x - y = 1 given three points
|
||||
p1 = (0, -1, 0)
|
||||
p2 = (1, 0, 0)
|
||||
p3 = (1, 0, 1)
|
||||
s = openmc.Plane.from_points(p1, p2, p3)
|
||||
|
||||
# Confirm correct coefficients
|
||||
assert s.a == 1.0
|
||||
assert s.b == -1.0
|
||||
assert s.c == 0.0
|
||||
assert s.d == 1.0
|
||||
|
||||
|
||||
def test_xplane():
|
||||
s = openmc.XPlane(3., 'reflective')
|
||||
assert s.x0 == 3.
|
||||
assert s.boundary_type == 'reflective'
|
||||
|
||||
# Check bounding box
|
||||
ll, ur = (+s).bounding_box
|
||||
assert ll == pytest.approx((3., -np.inf, -np.inf))
|
||||
assert np.all(np.isinf(ur))
|
||||
ll, ur = (-s).bounding_box
|
||||
assert ur == pytest.approx((3., np.inf, np.inf))
|
||||
assert np.all(np.isinf(ll))
|
||||
|
||||
# __contains__ on associated half-spaces
|
||||
assert (5, 0, 0) in +s
|
||||
assert (5, 0, 0) not in -s
|
||||
assert (-2, 1, 10) in -s
|
||||
assert (-2, 1, 10) not in +s
|
||||
|
||||
# evaluate method
|
||||
assert s.evaluate((5., 0., 0.)) == pytest.approx(2.)
|
||||
|
||||
# translate method
|
||||
st = s.translate((1.0, 0.0, 0.0))
|
||||
assert st.x0 == s.x0 + 1
|
||||
|
||||
# Make sure repr works
|
||||
repr(s)
|
||||
|
||||
|
||||
def test_yplane():
|
||||
s = openmc.YPlane(y0=3.)
|
||||
assert s.y0 == 3.
|
||||
|
||||
# Check bounding box
|
||||
ll, ur = (+s).bounding_box
|
||||
assert ll == pytest.approx((-np.inf, 3., -np.inf))
|
||||
assert np.all(np.isinf(ur))
|
||||
ll, ur = s.bounding_box('-')
|
||||
assert ur == pytest.approx((np.inf, 3., np.inf))
|
||||
assert np.all(np.isinf(ll))
|
||||
|
||||
# __contains__ on associated half-spaces
|
||||
assert (0, 5, 0) in +s
|
||||
assert (0, 5, 0) not in -s
|
||||
assert (-2, 1, 10) in -s
|
||||
assert (-2, 1, 10) not in +s
|
||||
|
||||
# evaluate method
|
||||
assert s.evaluate((0., 0., 0.)) == pytest.approx(-3.)
|
||||
|
||||
# translate method
|
||||
st = s.translate((0.0, 1.0, 0.0))
|
||||
assert st.y0 == s.y0 + 1
|
||||
|
||||
|
||||
def test_zplane():
|
||||
s = openmc.ZPlane(z0=3.)
|
||||
assert s.z0 == 3.
|
||||
|
||||
# Check bounding box
|
||||
ll, ur = (+s).bounding_box
|
||||
assert ll == pytest.approx((-np.inf, -np.inf, 3.))
|
||||
assert np.all(np.isinf(ur))
|
||||
ll, ur = (-s).bounding_box
|
||||
assert ur == pytest.approx((np.inf, np.inf, 3.))
|
||||
assert np.all(np.isinf(ll))
|
||||
|
||||
# __contains__ on associated half-spaces
|
||||
assert (0, 0, 5) in +s
|
||||
assert (0, 0, 5) not in -s
|
||||
assert (-2, 1, -10) in -s
|
||||
assert (-2, 1, -10) not in +s
|
||||
|
||||
# evaluate method
|
||||
assert s.evaluate((0., 0., 10.)) == pytest.approx(7.)
|
||||
|
||||
# translate method
|
||||
st = s.translate((0.0, 0.0, 1.0))
|
||||
assert st.z0 == s.z0 + 1
|
||||
|
||||
# Make sure repr works
|
||||
repr(s)
|
||||
|
||||
|
||||
def test_xcylinder():
|
||||
y, z, r = 3, 5, 2
|
||||
s = openmc.XCylinder(y0=y, z0=z, r=r)
|
||||
assert s.y0 == y
|
||||
assert s.z0 == z
|
||||
assert s.r == r
|
||||
|
||||
# Check bounding box
|
||||
ll, ur = (+s).bounding_box
|
||||
assert np.all(np.isinf(ll))
|
||||
assert np.all(np.isinf(ur))
|
||||
ll, ur = (-s).bounding_box
|
||||
assert ll == pytest.approx((-np.inf, y-r, z-r))
|
||||
assert ur == pytest.approx((np.inf, y+r, z+r))
|
||||
|
||||
# evaluate method
|
||||
assert s.evaluate((0, y, z)) == pytest.approx(-r**2)
|
||||
|
||||
# translate method
|
||||
st = s.translate((1.0, 1.0, 1.0))
|
||||
assert st.y0 == s.y0 + 1
|
||||
assert st.z0 == s.z0 + 1
|
||||
assert st.r == s.r
|
||||
|
||||
# Make sure repr works
|
||||
repr(s)
|
||||
|
||||
|
||||
def test_periodic():
|
||||
x = openmc.XPlane(boundary_type='periodic')
|
||||
y = openmc.YPlane(boundary_type='periodic')
|
||||
x.periodic_surface = y
|
||||
assert y.periodic_surface == x
|
||||
with pytest.raises(TypeError):
|
||||
x.periodic_surface = openmc.Sphere()
|
||||
|
||||
|
||||
def test_ycylinder():
|
||||
x, z, r = 3, 5, 2
|
||||
s = openmc.YCylinder(x0=x, z0=z, r=r)
|
||||
assert s.x0 == x
|
||||
assert s.z0 == z
|
||||
assert s.r == r
|
||||
|
||||
# Check bounding box
|
||||
ll, ur = (+s).bounding_box
|
||||
assert np.all(np.isinf(ll))
|
||||
assert np.all(np.isinf(ur))
|
||||
ll, ur = (-s).bounding_box
|
||||
assert ll == pytest.approx((x-r, -np.inf, z-r))
|
||||
assert ur == pytest.approx((x+r, np.inf, z+r))
|
||||
|
||||
# evaluate method
|
||||
assert s.evaluate((x, 0, z)) == pytest.approx(-r**2)
|
||||
|
||||
# translate method
|
||||
st = s.translate((1.0, 1.0, 1.0))
|
||||
assert st.x0 == s.x0 + 1
|
||||
assert st.z0 == s.z0 + 1
|
||||
assert st.r == s.r
|
||||
|
||||
|
||||
def test_zcylinder():
|
||||
x, y, r = 3, 5, 2
|
||||
s = openmc.ZCylinder(x0=x, y0=y, r=r)
|
||||
assert s.x0 == x
|
||||
assert s.y0 == y
|
||||
assert s.r == r
|
||||
|
||||
# Check bounding box
|
||||
ll, ur = (+s).bounding_box
|
||||
assert np.all(np.isinf(ll))
|
||||
assert np.all(np.isinf(ur))
|
||||
ll, ur = (-s).bounding_box
|
||||
assert ll == pytest.approx((x-r, y-r, -np.inf))
|
||||
assert ur == pytest.approx((x+r, y+r, np.inf))
|
||||
|
||||
# evaluate method
|
||||
assert s.evaluate((x, y, 0)) == pytest.approx(-r**2)
|
||||
|
||||
# translate method
|
||||
st = s.translate((1.0, 1.0, 1.0))
|
||||
assert st.x0 == s.x0 + 1
|
||||
assert st.y0 == s.y0 + 1
|
||||
assert st.r == s.r
|
||||
|
||||
# Make sure repr works
|
||||
repr(s)
|
||||
|
||||
|
||||
def test_sphere():
|
||||
x, y, z, r = -3, 5, 6, 2
|
||||
s = openmc.Sphere(x0=x, y0=y, z0=z, r=r)
|
||||
assert s.x0 == x
|
||||
assert s.y0 == y
|
||||
assert s.z0 == z
|
||||
assert s.r == r
|
||||
|
||||
# Check bounding box
|
||||
ll, ur = (+s).bounding_box
|
||||
assert np.all(np.isinf(ll))
|
||||
assert np.all(np.isinf(ur))
|
||||
ll, ur = (-s).bounding_box
|
||||
assert ll == pytest.approx((x-r, y-r, z-r))
|
||||
assert ur == pytest.approx((x+r, y+r, z+r))
|
||||
|
||||
# evaluate method
|
||||
assert s.evaluate((x, y, z)) == pytest.approx(-r**2)
|
||||
|
||||
# translate method
|
||||
st = s.translate((1.0, 1.0, 1.0))
|
||||
assert st.x0 == s.x0 + 1
|
||||
assert st.y0 == s.y0 + 1
|
||||
assert st.z0 == s.z0 + 1
|
||||
assert st.r == s.r
|
||||
|
||||
# Make sure repr works
|
||||
repr(s)
|
||||
|
||||
|
||||
def cone_common(apex, r2, cls):
|
||||
x, y, z = apex
|
||||
s = cls(x0=x, y0=y, z0=z, r2=r2)
|
||||
assert s.x0 == x
|
||||
assert s.y0 == y
|
||||
assert s.z0 == z
|
||||
assert s.r2 == r2
|
||||
|
||||
# Check bounding box
|
||||
assert_infinite_bb(s)
|
||||
|
||||
# evaluate method -- should be zero at apex
|
||||
assert s.evaluate((x, y, z)) == pytest.approx(0.0)
|
||||
|
||||
# translate method
|
||||
st = s.translate((1.0, 1.0, 1.0))
|
||||
assert st.x0 == s.x0 + 1
|
||||
assert st.y0 == s.y0 + 1
|
||||
assert st.z0 == s.z0 + 1
|
||||
assert st.r2 == s.r2
|
||||
|
||||
# Make sure repr works
|
||||
repr(s)
|
||||
|
||||
|
||||
def test_xcone():
|
||||
apex = (10, 0, 0)
|
||||
r2 = 4
|
||||
cone_common(apex, r2, openmc.XCone)
|
||||
|
||||
|
||||
def test_ycone():
|
||||
apex = (10, 0, 0)
|
||||
r2 = 4
|
||||
cone_common(apex, r2, openmc.YCone)
|
||||
|
||||
|
||||
def test_zcone():
|
||||
apex = (10, 0, 0)
|
||||
r2 = 4
|
||||
cone_common(apex, r2, openmc.ZCone)
|
||||
|
||||
|
||||
def test_quadric():
|
||||
# Make a sphere from a quadric
|
||||
r = 10.0
|
||||
coeffs = {'a': 1, 'b': 1, 'c': 1, 'k': -r**2}
|
||||
s = openmc.Quadric(**coeffs)
|
||||
assert s.a == coeffs['a']
|
||||
assert s.b == coeffs['b']
|
||||
assert s.c == coeffs['c']
|
||||
assert s.k == coeffs['k']
|
||||
|
||||
# All other coeffs should be zero
|
||||
for coeff in ('d', 'e', 'f', 'g', 'h', 'j'):
|
||||
assert getattr(s, coeff) == 0.0
|
||||
|
||||
# Check bounding box
|
||||
assert_infinite_bb(s)
|
||||
|
||||
# evaluate method
|
||||
assert s.evaluate((0., 0., 0.)) == pytest.approx(coeffs['k'])
|
||||
assert s.evaluate((1., 1., 1.)) == pytest.approx(3 + coeffs['k'])
|
||||
|
||||
# translate method
|
||||
st = s.translate((1.0, 1.0, 1.0))
|
||||
for coeff in 'abcdef':
|
||||
assert getattr(s, coeff) == getattr(st, coeff)
|
||||
assert (st.g, st.h, st.j) == (-2, -2, -2)
|
||||
assert st.k == s.k + 3
|
||||
|
||||
|
||||
def test_cylinder_from_points():
|
||||
seed(1) # Make random numbers reproducible
|
||||
for _ in range(100):
|
||||
# Generate cylinder in random direction
|
||||
xi = partial(uniform, -10.0, 10.0)
|
||||
p1 = np.array([xi(), xi(), xi()])
|
||||
p2 = np.array([xi(), xi(), xi()])
|
||||
r = uniform(1.0, 100.0)
|
||||
s = openmc.model.cylinder_from_points(p1, p2, r)
|
||||
|
||||
# Points p1 and p2 need to be inside cylinder
|
||||
assert p1 in -s
|
||||
assert p2 in -s
|
||||
|
||||
# Points further along the line should be inside cylinder as well
|
||||
t = uniform(-100.0, 100.0)
|
||||
p = p1 + t*(p2 - p1)
|
||||
assert p in -s
|
||||
|
||||
# Check that points outside cylinder are in positive half-space and
|
||||
# inside are in negative half-space. We do this by constructing a plane
|
||||
# that includes the cylinder's axis, finding the normal to the plane,
|
||||
# and using it to find a point slightly more/less than one radius away
|
||||
# from the axis.
|
||||
plane = openmc.Plane.from_points(p1, p2, (0., 0., 0.))
|
||||
n = np.array([plane.a, plane.b, plane.c])
|
||||
n /= np.linalg.norm(n)
|
||||
assert p1 + 1.1*r*n in +s
|
||||
assert p2 + 1.1*r*n in +s
|
||||
assert p1 + 0.9*r*n in -s
|
||||
assert p2 + 0.9*r*n in -s
|
||||
|
||||
|
||||
def test_cylinder_from_points_axis():
|
||||
# Create axis-aligned cylinders and confirm the coefficients are as expected
|
||||
|
||||
# (x - 3)^2 + (y - 4)^2 = 2^2
|
||||
# x^2 + y^2 - 6x - 8y + 21 = 0
|
||||
s = openmc.model.cylinder_from_points((3., 4., 0.), (3., 4., 1.), 2.)
|
||||
assert (s.a, s.b, s.c) == pytest.approx((1., 1., 0.))
|
||||
assert (s.d, s.e, s.f) == pytest.approx((0., 0., 0.))
|
||||
assert (s.g, s.h, s.j) == pytest.approx((-6., -8., 0.))
|
||||
assert s.k == pytest.approx(21.)
|
||||
|
||||
# (y + 7)^2 + (z - 1)^2 = 3^2
|
||||
# y^2 + z^2 + 14y - 2z + 41 = 0
|
||||
s = openmc.model.cylinder_from_points((0., -7, 1.), (1., -7., 1.), 3.)
|
||||
assert (s.a, s.b, s.c) == pytest.approx((0., 1., 1.))
|
||||
assert (s.d, s.e, s.f) == pytest.approx((0., 0., 0.))
|
||||
assert (s.g, s.h, s.j) == pytest.approx((0., 14., -2.))
|
||||
assert s.k == 41.
|
||||
|
||||
# (x - 2)^2 + (z - 5)^2 = 4^2
|
||||
# x^2 + z^2 - 4x - 10z + 13 = 0
|
||||
s = openmc.model.cylinder_from_points((2., 0., 5.), (2., 1., 5.), 4.)
|
||||
assert (s.a, s.b, s.c) == pytest.approx((1., 0., 1.))
|
||||
assert (s.d, s.e, s.f) == pytest.approx((0., 0., 0.))
|
||||
assert (s.g, s.h, s.j) == pytest.approx((-4., 0., -10.))
|
||||
assert s.k == pytest.approx(13.)
|
||||
46
tests/unit_tests/test_transfer_volumes.py
Normal file
46
tests/unit_tests/test_transfer_volumes.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
"""Regression tests for openmc.deplete.Results.transfer_volumes method.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
from pytest import approx
|
||||
import openmc
|
||||
from openmc.deplete import PredictorIntegrator, ResultsList
|
||||
|
||||
from tests import dummy_operator
|
||||
|
||||
|
||||
def test_transfer_volumes(run_in_tmpdir):
|
||||
"""Unit test of volume transfer in restart calculations."""
|
||||
|
||||
op = dummy_operator.DummyOperator()
|
||||
op.output_dir = "test_transfer_volumes"
|
||||
|
||||
# Perform simulation using the predictor algorithm
|
||||
dt = [0.75]
|
||||
power = 1.0
|
||||
PredictorIntegrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
# Create a dictionary of volumes to transfer
|
||||
res[0].volume['1'] = 1.5
|
||||
res[0].volume['2'] = 2.5
|
||||
|
||||
# Create dummy geometry
|
||||
mat1 = openmc.Material(material_id=1)
|
||||
mat1.depletable = True
|
||||
mat2 = openmc.Material(material_id=2)
|
||||
|
||||
cell = openmc.Cell()
|
||||
cell.fill = [mat1, mat2]
|
||||
root = openmc.Universe()
|
||||
root.add_cell(cell)
|
||||
geometry = openmc.Geometry(root)
|
||||
|
||||
# Transfer volumes
|
||||
res[0].transfer_volumes(geometry)
|
||||
|
||||
assert mat1.volume == 1.5
|
||||
assert mat2.volume is None
|
||||
112
tests/unit_tests/test_universe.py
Normal file
112
tests/unit_tests/test_universe.py
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
import xml.etree.ElementTree as ET
|
||||
|
||||
import numpy as np
|
||||
import openmc
|
||||
import pytest
|
||||
|
||||
from tests.unit_tests import assert_unbounded
|
||||
|
||||
|
||||
def test_basic():
|
||||
c1 = openmc.Cell()
|
||||
c2 = openmc.Cell()
|
||||
c3 = openmc.Cell()
|
||||
u = openmc.Universe(name='cool', cells=(c1, c2, c3))
|
||||
assert u.name == 'cool'
|
||||
|
||||
cells = set(u.cells.values())
|
||||
assert not (cells ^ {c1, c2, c3})
|
||||
|
||||
# Test __repr__
|
||||
repr(u)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
u.add_cell(openmc.Material())
|
||||
with pytest.raises(TypeError):
|
||||
u.add_cells(c1)
|
||||
|
||||
u.remove_cell(c3)
|
||||
cells = set(u.cells.values())
|
||||
assert not (cells ^ {c1, c2})
|
||||
|
||||
u.clear_cells()
|
||||
assert not set(u.cells)
|
||||
|
||||
|
||||
def test_bounding_box():
|
||||
cyl1 = openmc.ZCylinder(r=1.0)
|
||||
cyl2 = openmc.ZCylinder(r=2.0)
|
||||
c1 = openmc.Cell(region=-cyl1)
|
||||
c2 = openmc.Cell(region=+cyl1 & -cyl2)
|
||||
|
||||
u = openmc.Universe(cells=[c1, c2])
|
||||
ll, ur = u.bounding_box
|
||||
assert ll == pytest.approx((-2., -2., -np.inf))
|
||||
assert ur == pytest.approx((2., 2., np.inf))
|
||||
|
||||
u = openmc.Universe()
|
||||
assert_unbounded(u)
|
||||
|
||||
|
||||
def test_plot(run_in_tmpdir, sphere_model):
|
||||
m = sphere_model.materials[0]
|
||||
univ = sphere_model.geometry.root_universe
|
||||
|
||||
colors = {m: 'limegreen'}
|
||||
for basis in ('xy', 'yz', 'xz'):
|
||||
univ.plot(
|
||||
basis=basis,
|
||||
pixels=(10, 10),
|
||||
color_by='material',
|
||||
colors=colors,
|
||||
)
|
||||
|
||||
|
||||
def test_get_nuclides(uo2):
|
||||
c = openmc.Cell(fill=uo2)
|
||||
univ = openmc.Universe(cells=[c])
|
||||
nucs = univ.get_nuclides()
|
||||
assert nucs == ['U235', 'O16']
|
||||
|
||||
|
||||
def test_cells():
|
||||
cells = [openmc.Cell() for i in range(5)]
|
||||
cells2 = [openmc.Cell() for i in range(3)]
|
||||
cells[0].fill = openmc.Universe(cells=cells2)
|
||||
u = openmc.Universe(cells=cells)
|
||||
assert not (set(u.cells.values()) ^ set(cells))
|
||||
|
||||
all_cells = set(u.get_all_cells().values())
|
||||
assert not (all_cells ^ set(cells + cells2))
|
||||
|
||||
|
||||
def test_get_all_materials(cell_with_lattice):
|
||||
cells, mats, univ, lattice = cell_with_lattice
|
||||
test_mats = set(univ.get_all_materials().values())
|
||||
assert not (test_mats ^ set(mats))
|
||||
|
||||
|
||||
def test_get_all_universes():
|
||||
c1 = openmc.Cell()
|
||||
u1 = openmc.Universe(cells=[c1])
|
||||
c2 = openmc.Cell()
|
||||
u2 = openmc.Universe(cells=[c2])
|
||||
c3 = openmc.Cell(fill=u1)
|
||||
c4 = openmc.Cell(fill=u2)
|
||||
u3 = openmc.Universe(cells=[c3, c4])
|
||||
|
||||
univs = set(u3.get_all_universes().values())
|
||||
assert not (univs ^ {u1, u2})
|
||||
|
||||
|
||||
def test_create_xml(cell_with_lattice):
|
||||
cells = [openmc.Cell() for i in range(5)]
|
||||
u = openmc.Universe(cells=cells)
|
||||
|
||||
geom = ET.Element('geom')
|
||||
u.create_xml_subelement(geom)
|
||||
cell_elems = geom.findall('cell')
|
||||
assert len(cell_elems) == len(cells)
|
||||
assert all(c.get('universe') == str(u.id) for c in cell_elems)
|
||||
assert not (set(c.get('id') for c in cell_elems) ^
|
||||
set(str(c.id) for c in cells))
|
||||
Loading…
Add table
Add a link
Reference in a new issue