adding back files to be reviewed

This commit is contained in:
Paul Romano 2019-10-28 11:55:45 -05:00
parent ae28233110
commit bc09d1ef55
1244 changed files with 301904 additions and 0 deletions

View 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))

View 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)

View file

View file

@ -0,0 +1 @@
../../regression_tests/dagmc/legacy/dagmc.h5m

View 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)

View 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)

View 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]

View 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))

View 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')

View 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)

View 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)

View 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')

View 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'

View 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

View 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)

View 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)

View 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

View 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)

View 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]

View 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

View 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

View 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)

View 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)

View 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)

View 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

View 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)

View 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))

View 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

View 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

View 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'

View 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)

View 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)

View 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
)

View 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))

View 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()

View 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)

View 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]

View 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

View 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

View 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

View 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.)

View 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

View 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))