mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-29 06:35:48 -04:00
Merge branch 'develop' into integrator-class
Need new travis.yml to pass CI
This commit is contained in:
commit
b9683dbdba
114 changed files with 8323 additions and 4462 deletions
0
tests/unit_tests/dagmc/__init__.py
Normal file
0
tests/unit_tests/dagmc/__init__.py
Normal file
1
tests/unit_tests/dagmc/dagmc.h5m
Symbolic link
1
tests/unit_tests/dagmc/dagmc.h5m
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../regression_tests/dagmc/legacy/dagmc.h5m
|
||||
74
tests/unit_tests/dagmc/test.py
Normal file
74
tests/unit_tests/dagmc/test.py
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import shutil
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
import openmc
|
||||
import openmc.capi
|
||||
|
||||
from tests import cdtemp
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not openmc.capi._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.capi.init()
|
||||
yield
|
||||
|
||||
openmc.capi.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.capi.cells[cell_id]
|
||||
assert np.isclose(cell.get_temperature(), exp_temp)
|
||||
|
|
@ -35,6 +35,14 @@ def pincell_model():
|
|||
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()
|
||||
|
|
@ -73,7 +81,9 @@ def test_cell(capi_init):
|
|||
assert isinstance(cell.fill, openmc.capi.Material)
|
||||
cell.fill = openmc.capi.materials[1]
|
||||
assert str(cell) == 'Cell[0]'
|
||||
|
||||
assert cell.name == "Fuel"
|
||||
cell.name = "Not fuel"
|
||||
assert cell.name == "Not fuel"
|
||||
|
||||
def test_cell_temperature(capi_init):
|
||||
cell = openmc.capi.cells[1]
|
||||
|
|
@ -113,7 +123,7 @@ def test_material(capi_init):
|
|||
m.volume = 10.0
|
||||
assert m.volume == 10.0
|
||||
|
||||
with pytest.raises(exc.InvalidArgumentError):
|
||||
with pytest.raises(exc.OpenMCError):
|
||||
m.set_density(1.0, 'goblins')
|
||||
|
||||
rho = 2.25e-2
|
||||
|
|
@ -122,7 +132,9 @@ def test_material(capi_init):
|
|||
|
||||
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(capi_init):
|
||||
m = openmc.capi.materials[3]
|
||||
|
|
@ -166,12 +178,21 @@ def test_settings(capi_init):
|
|||
def test_tally_mapping(capi_init):
|
||||
tallies = openmc.capi.tallies
|
||||
assert isinstance(tallies, Mapping)
|
||||
assert len(tallies) == 2
|
||||
assert len(tallies) == 3
|
||||
for tally_id, tally in tallies.items():
|
||||
assert isinstance(tally, openmc.capi.Tally)
|
||||
assert tally_id == tally.id
|
||||
|
||||
|
||||
def test_energy_function_filter(capi_init):
|
||||
"""Test special __new__ and __init__ for EnergyFunctionFilter"""
|
||||
efunc = openmc.capi.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(capi_init):
|
||||
t = openmc.capi.tallies[1]
|
||||
assert t.type == 'volume'
|
||||
|
|
@ -207,6 +228,16 @@ def test_tally(capi_init):
|
|||
assert len(t2.filters[1].bins) == 3
|
||||
assert t2.filters[0].order == 5
|
||||
|
||||
t3 = openmc.capi.tallies[3]
|
||||
assert len(t3.filters) == 1
|
||||
t3_f = t3.filters[0]
|
||||
assert isinstance(t3_f, openmc.capi.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(capi_init):
|
||||
with pytest.raises(exc.AllocationError):
|
||||
|
|
@ -215,7 +246,7 @@ def test_new_tally(capi_init):
|
|||
new_tally.scores = ['flux']
|
||||
new_tally_with_id = openmc.capi.Tally(10)
|
||||
new_tally_with_id.scores = ['flux']
|
||||
assert len(openmc.capi.tallies) == 4
|
||||
assert len(openmc.capi.tallies) == 5
|
||||
|
||||
|
||||
def test_tally_activate(capi_simulation_init):
|
||||
|
|
@ -469,3 +500,13 @@ def test_position(capi_init):
|
|||
pos[2] = 3.3
|
||||
|
||||
assert tuple(pos) == (1.3, 2.3, 3.3)
|
||||
|
||||
|
||||
def test_global_bounding_box(capi_init):
|
||||
expected_llc = (-0.63, -0.63, -np.inf)
|
||||
expected_urc = (0.63, 0.63, np.inf)
|
||||
|
||||
llc, urc = openmc.capi.global_bounding_box()
|
||||
|
||||
assert tuple(llc) == expected_llc
|
||||
assert tuple(urc) == expected_urc
|
||||
|
|
|
|||
98
tests/unit_tests/test_complex_cell_capi.py
Normal file
98
tests/unit_tests/test_complex_cell_capi.py
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
import numpy as np
|
||||
import openmc.capi
|
||||
import pytest
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def complex_cell(run_in_tmpdir):
|
||||
|
||||
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(x0=-10.0, boundary_type='vacuum')
|
||||
s2 = openmc.XPlane(x0=-7.0)
|
||||
s3 = openmc.XPlane(x0=-4.0)
|
||||
s4 = openmc.XPlane(x0=4.0)
|
||||
s5 = openmc.XPlane(x0=7.0)
|
||||
s6 = openmc.XPlane(x0=10.0, boundary_type='vacuum')
|
||||
s7 = openmc.XPlane(x0=0.0)
|
||||
|
||||
s11 = openmc.YPlane(y0=-10.0, boundary_type='vacuum')
|
||||
s12 = openmc.YPlane(y0=-7.0)
|
||||
s13 = openmc.YPlane(y0=-4.0)
|
||||
s14 = openmc.YPlane(y0=4.0)
|
||||
s15 = openmc.YPlane(y0=7.0)
|
||||
s16 = openmc.YPlane(y0=10.0, boundary_type='vacuum')
|
||||
s17 = openmc.YPlane(y0=0.0)
|
||||
|
||||
c1 = openmc.Cell(fill=u235)
|
||||
c1.region = ~(-s3 | +s4 | ~(+s13 & -s14))
|
||||
|
||||
c2 = openmc.Cell(fill=u238)
|
||||
c2.region = +s2 & -s5 & +s12 & -s15 & ~(+s3 & -s4 & +s13 & -s14)
|
||||
|
||||
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.capi.finalize()
|
||||
openmc.capi.init()
|
||||
|
||||
yield
|
||||
|
||||
openmc.capi.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.capi.cells[cell_id].bounding_box
|
||||
assert tuple(cell_box[0]) == expected_box[0]
|
||||
assert tuple(cell_box[1]) == expected_box[1]
|
||||
|
|
@ -243,3 +243,89 @@ def test_set_fiss_q():
|
|||
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_capture_branches() == 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_capture_branches(new_br)
|
||||
assert new_chain.get_capture_branches() == new_br
|
||||
|
||||
# write, re-read
|
||||
new_chain.export_to_xml("chain_mod.xml")
|
||||
assert Chain.from_xml("chain_mod.xml").get_capture_branches() == 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_capture_branches(bad_br, strict=False)
|
||||
assert new_chain.get_capture_branches() == new_br
|
||||
|
||||
# Ensure capture reactions are removed
|
||||
rem_br = {"A": {"C": 1.0}}
|
||||
new_chain.set_capture_branches(rem_br)
|
||||
# A is not in returned dict because there is no branch
|
||||
assert "A" not in new_chain.get_capture_branches()
|
||||
|
||||
|
||||
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()
|
||||
xe136m.name = "Xe136_m1"
|
||||
|
||||
chain.nuclides.append(xe136m)
|
||||
chain.nuclide_dict[xe136m.name] = len(chain.nuclides) - 1
|
||||
|
||||
chain.set_capture_branches(infer_br)
|
||||
|
||||
assert chain.get_capture_branches() == 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()
|
||||
u5m.name = "U235_m1"
|
||||
|
||||
chain.nuclides.append(u5m)
|
||||
chain.nuclide_dict[u5m.name] = len(chain.nuclides) - 1
|
||||
|
||||
phrase = "U234 does not have capture reactions"
|
||||
with pytest.raises(AttributeError, match=phrase):
|
||||
chain.set_capture_branches(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_capture_branches(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_capture_branches(br)
|
||||
|
||||
# Sum of ratios > 1.0
|
||||
br = {"C": {"A": 1.0, "B": 1.0}}
|
||||
with pytest.raises(ValueError, match="C ratios"):
|
||||
simple_chain.set_capture_branches(br)
|
||||
|
|
|
|||
|
|
@ -189,6 +189,8 @@ def test_from_xml(run_in_tmpdir):
|
|||
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')
|
||||
|
|
@ -209,6 +211,8 @@ def test_from_xml(run_in_tmpdir):
|
|||
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
|
||||
|
|
|
|||
117
tests/unit_tests/test_pin.py
Normal file
117
tests/unit_tests/test_pin.py
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
"""
|
||||
Tests for constructing Pin universes
|
||||
"""
|
||||
|
||||
import numpy
|
||||
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 = numpy.square(bounds)
|
||||
assert 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 = numpy.square(radii[:N + 1])
|
||||
assert sqrs[1:] - sqrs[:-1] == pytest.approx(
|
||||
(good_radii[1] ** 2 - good_radii[0] ** 2) / N)
|
||||
|
|
@ -1,3 +1,6 @@
|
|||
from functools import partial
|
||||
from random import uniform, seed
|
||||
|
||||
import numpy as np
|
||||
import openmc
|
||||
import pytest
|
||||
|
|
@ -329,14 +332,61 @@ def test_quadric():
|
|||
|
||||
|
||||
def test_cylinder_from_points():
|
||||
# Generate 45-degree rotated cylinder in x-y plane with radius 1
|
||||
p1 = (0, 0, 0)
|
||||
p2 = (1, 1, 0)
|
||||
s = openmc.model.cylinder_from_points(p1, p2, 1)
|
||||
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
|
||||
assert (-1, 1, 0) in +s
|
||||
assert (1, -1, 0) in +s
|
||||
assert (0, 0, 1.5) in +s
|
||||
# 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.)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue