mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-21 14:35:27 -04:00
Co-authored-by: Patrick Shriwise <pshriwise@gmail.com> Co-authored-by: Paul Romano <paul.k.romano@gmail.com>
301 lines
9.8 KiB
Python
301 lines
9.8 KiB
Python
"""Test the 'surf_source_write' setting used to store particles that cross
|
|
surfaces in a file for a given simulation."""
|
|
|
|
from pathlib import Path
|
|
|
|
import openmc
|
|
import openmc.lib
|
|
import pytest
|
|
import h5py
|
|
import numpy as np
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def geometry():
|
|
"""Simple hydrogen sphere geometry"""
|
|
openmc.reset_auto_ids()
|
|
material = openmc.Material(name="H1")
|
|
material.add_element("H", 1.0)
|
|
sphere = openmc.Sphere(r=1.0, boundary_type="vacuum")
|
|
cell = openmc.Cell(region=-sphere, fill=material)
|
|
return openmc.Geometry([cell])
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"parameter",
|
|
[
|
|
{"max_particles": 200},
|
|
{"max_particles": 200, "cell": 1},
|
|
{"max_particles": 200, "cellto": 1},
|
|
{"max_particles": 200, "cellfrom": 1},
|
|
{"max_particles": 200, "surface_ids": [2]},
|
|
{"max_particles": 200, "surface_ids": [2], "cell": 1},
|
|
{"max_particles": 200, "surface_ids": [2], "cellto": 1},
|
|
{"max_particles": 200, "surface_ids": [2], "cellfrom": 1},
|
|
{"max_particles": 200, "surface_ids": [2], "max_source_files": 1},
|
|
],
|
|
)
|
|
def test_xml_serialization(parameter, run_in_tmpdir):
|
|
"""Check that the different use cases can be written and read in XML."""
|
|
settings = openmc.Settings()
|
|
settings.surf_source_write = parameter
|
|
settings.export_to_xml()
|
|
|
|
read_settings = openmc.Settings.from_xml()
|
|
assert read_settings.surf_source_write == parameter
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def model():
|
|
"""Simple hydrogen sphere geometry"""
|
|
openmc.reset_auto_ids()
|
|
model = openmc.Model()
|
|
|
|
# Material
|
|
h1 = openmc.Material(name="H1")
|
|
h1.add_nuclide("H1", 1.0)
|
|
h1.set_density('g/cm3', 1e-7)
|
|
|
|
# Geometry
|
|
radius = 1.0
|
|
sphere = openmc.Sphere(r=radius, boundary_type="vacuum")
|
|
cell = openmc.Cell(region=-sphere, fill=h1)
|
|
model.geometry = openmc.Geometry([cell])
|
|
|
|
# Settings
|
|
model.settings = openmc.Settings()
|
|
model.settings.run_mode = "fixed source"
|
|
model.settings.particles = 100
|
|
model.settings.batches = 3
|
|
model.settings.seed = 1
|
|
|
|
distribution = openmc.stats.Point()
|
|
model.settings.source = openmc.IndependentSource(space=distribution)
|
|
return model
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"max_particles, max_source_files",
|
|
[
|
|
(100, 2),
|
|
(100, 3),
|
|
(100, 1),
|
|
],
|
|
)
|
|
def test_number_surface_source_file_created(max_particles, max_source_files,
|
|
run_in_tmpdir, model):
|
|
"""Check the number of surface source files written."""
|
|
model.settings.surf_source_write = {
|
|
"max_particles": max_particles,
|
|
"max_source_files": max_source_files
|
|
}
|
|
model.run()
|
|
should_be_numbered = max_source_files > 1
|
|
for i in range(1, max_source_files + 1):
|
|
if should_be_numbered:
|
|
assert Path(f"surface_source.{i}.h5").exists()
|
|
if not should_be_numbered:
|
|
assert Path("surface_source.h5").exists()
|
|
|
|
ERROR_MSG_1 = (
|
|
"A maximum number of particles needs to be specified "
|
|
"using the 'max_particles' parameter to store surface "
|
|
"source points."
|
|
)
|
|
ERROR_MSG_2 = "'cell', 'cellfrom' and 'cellto' cannot be used at the same time."
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"parameter, error",
|
|
[
|
|
({"cell": 1}, ERROR_MSG_1),
|
|
({"max_particles": 200, "cell": 1, "cellto": 1}, ERROR_MSG_2),
|
|
({"max_particles": 200, "cell": 1, "cellfrom": 1}, ERROR_MSG_2),
|
|
({"max_particles": 200, "cellto": 1, "cellfrom": 1}, ERROR_MSG_2),
|
|
({"max_particles": 200, "cell": 1, "cellto": 1, "cellfrom": 1}, ERROR_MSG_2),
|
|
],
|
|
)
|
|
def test_exceptions(parameter, error, run_in_tmpdir, geometry):
|
|
"""Test parameters configuration that should return an error."""
|
|
settings = openmc.Settings(run_mode="fixed source", batches=5, particles=100)
|
|
settings.surf_source_write = parameter
|
|
model = openmc.Model(geometry=geometry, settings=settings)
|
|
with pytest.raises(RuntimeError, match=error):
|
|
model.run()
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def model():
|
|
"""Simple hydrogen sphere divided in two hemispheres
|
|
by a z-plane to form 2 cells."""
|
|
openmc.reset_auto_ids()
|
|
model = openmc.Model()
|
|
|
|
# Material
|
|
material = openmc.Material(name="H1")
|
|
material.add_element("H", 1.0)
|
|
|
|
# Geometry
|
|
radius = 1.0
|
|
sphere = openmc.Sphere(r=radius, boundary_type="reflective")
|
|
plane = openmc.ZPlane(0.0)
|
|
cell_1 = openmc.Cell(region=-sphere & -plane, fill=material)
|
|
cell_2 = openmc.Cell(region=-sphere & +plane, fill=material)
|
|
root = openmc.Universe(cells=[cell_1, cell_2])
|
|
model.geometry = openmc.Geometry(root)
|
|
|
|
# Settings
|
|
model.settings = openmc.Settings()
|
|
model.settings.run_mode = "fixed source"
|
|
model.settings.particles = 100
|
|
model.settings.batches = 3
|
|
model.settings.seed = 1
|
|
|
|
bounds = [-radius, -radius, -radius, radius, radius, radius]
|
|
distribution = openmc.stats.Box(bounds[:3], bounds[3:])
|
|
model.settings.source = openmc.IndependentSource(space=distribution)
|
|
|
|
return model
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"parameter",
|
|
[
|
|
{"max_particles": 200, "cellto": 2, "surface_ids": [2]},
|
|
{"max_particles": 200, "cellfrom": 2, "surface_ids": [2]},
|
|
],
|
|
)
|
|
def test_particle_direction(parameter, run_in_tmpdir, model):
|
|
"""Test the direction of particles with the 'cellfrom' and 'cellto' parameters
|
|
on a simple model with only one surface of interest.
|
|
|
|
Cell 2 is the upper hemisphere and surface 2 is the plane dividing the sphere
|
|
into two hemispheres.
|
|
|
|
"""
|
|
model.settings.surf_source_write = parameter
|
|
model.run()
|
|
with h5py.File("surface_source.h5", "r") as f:
|
|
source = f["source_bank"]
|
|
|
|
assert len(source) == 200
|
|
|
|
# We want to verify that the dot product of the surface's normal vector
|
|
# and the direction of the particle is either positive or negative
|
|
# depending on cellfrom or cellto. In this case, it is equivalent
|
|
# to just compare the z component of the direction of the particle.
|
|
for point in source:
|
|
if "cellto" in parameter.keys():
|
|
assert point["u"]["z"] > 0.0
|
|
elif "cellfrom" in parameter.keys():
|
|
assert point["u"]["z"] < 0.0
|
|
else:
|
|
assert False
|
|
|
|
|
|
@pytest.fixture
|
|
def model_dagmc(request):
|
|
"""Model based on the mesh file 'dagmc.h5m' available from
|
|
tests/regression_tests/dagmc/legacy.
|
|
|
|
"""
|
|
openmc.reset_auto_ids()
|
|
model = openmc.Model()
|
|
|
|
# =============================================================================
|
|
# Materials
|
|
# =============================================================================
|
|
|
|
u235 = openmc.Material(name="no-void fuel")
|
|
u235.add_nuclide("U235", 1.0, "ao")
|
|
u235.set_density("g/cc", 11)
|
|
u235.id = 40
|
|
|
|
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
|
|
|
|
model.materials = openmc.Materials([u235, water])
|
|
|
|
# =============================================================================
|
|
# Geometry
|
|
# =============================================================================
|
|
dagmc_path = Path(request.fspath).parent / "../regression_tests/dagmc/legacy/dagmc.h5m"
|
|
dagmc_univ = openmc.DAGMCUniverse(dagmc_path)
|
|
model.geometry = openmc.Geometry(dagmc_univ)
|
|
|
|
# =============================================================================
|
|
# Settings
|
|
# =============================================================================
|
|
|
|
model.settings = openmc.Settings()
|
|
model.settings.particles = 300
|
|
model.settings.batches = 5
|
|
model.settings.inactive = 1
|
|
model.settings.seed = 1
|
|
|
|
source_box = openmc.stats.Box([-4, -4, -20], [4, 4, 20])
|
|
model.settings.source = openmc.IndependentSource(space=source_box)
|
|
|
|
return model
|
|
|
|
|
|
@pytest.mark.skipif(
|
|
not openmc.lib._dagmc_enabled(), reason="DAGMC CAD geometry is not enabled."
|
|
)
|
|
@pytest.mark.parametrize(
|
|
"parameter",
|
|
[
|
|
{"max_particles": 200, "cellto": 1},
|
|
{"max_particles": 200, "cellfrom": 1},
|
|
],
|
|
)
|
|
def test_particle_direction_dagmc(parameter, run_in_tmpdir, model_dagmc):
|
|
"""Test the direction of particles with the 'cellfrom' and 'cellto' parameters
|
|
on a DAGMC model."""
|
|
model_dagmc.settings.surf_source_write = parameter
|
|
model_dagmc.run()
|
|
|
|
r = 7.0
|
|
h = 20.0
|
|
|
|
with h5py.File("surface_source.h5", "r") as f:
|
|
source = f["source_bank"]
|
|
|
|
assert len(source) == 200
|
|
|
|
for point in source:
|
|
|
|
x, y, z = point["r"]
|
|
ux, uy, uz = point["u"]
|
|
|
|
# If the point is on the upper or lower circle
|
|
if np.allclose(abs(z), h):
|
|
# If the point is also on the cylindrical surface
|
|
if np.allclose(np.sqrt(x**2 + y**2), r):
|
|
if "cellfrom" in parameter.keys():
|
|
assert (uz * z > 0) or (ux * x + uy * y > 0)
|
|
elif "cellto" in parameter.keys():
|
|
assert (uz * z < 0) or (ux * x + uy * y < 0)
|
|
else:
|
|
assert False
|
|
# If the point is not on the cylindrical surface
|
|
else:
|
|
if "cellfrom" in parameter.keys():
|
|
assert uz * z > 0
|
|
elif "cellto" in parameter.keys():
|
|
assert uz * z < 0
|
|
else:
|
|
assert False
|
|
# If the point is not on the upper or lower circle,
|
|
# meaning it is on the cylindrical surface
|
|
else:
|
|
if "cellfrom" in parameter.keys():
|
|
assert ux * x + uy * y > 0
|
|
elif "cellto" in parameter.keys():
|
|
assert ux * x + uy * y < 0
|
|
else:
|
|
assert False
|