mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 06:05:58 -04:00
Added tests of the openmc.Model class. Still need to do tests of deplete and the methods which change python and C attributes. Pushing this now to verify the CI shows passes for the MPI configs
This commit is contained in:
parent
24bca06310
commit
0d2f923be8
3 changed files with 308 additions and 3 deletions
|
|
@ -193,6 +193,8 @@ class Model:
|
|||
def from_xml(cls, geometry='geometry.xml', materials='materials.xml',
|
||||
settings='settings.xml'):
|
||||
"""Create model from existing XML files
|
||||
When initializing this way, the user must manually load plots, tallies,
|
||||
the chain_file and fission_q attributes.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
@ -428,7 +430,9 @@ class Model:
|
|||
Parameters
|
||||
----------
|
||||
**kwargs
|
||||
Keyword arguments passed to :func:`openmc.run`
|
||||
Keyword arguments passed to :func:`openmc.run`. Note that these are
|
||||
ignored if running via the C-API. Instead the parameters should be
|
||||
set via the Settings object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
|
|
|||
|
|
@ -1,9 +1,129 @@
|
|||
from math import pi
|
||||
import openmc
|
||||
import pytest
|
||||
|
||||
from tests.regression_tests import config
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def pin_model_attributes():
|
||||
uo2 = openmc.Material(name='UO2')
|
||||
uo2.set_density('g/cm3', 10.29769)
|
||||
uo2.add_element('U', 1., enrichment=2.4)
|
||||
uo2.add_element('O', 2.)
|
||||
|
||||
zirc = openmc.Material(name='Zirc')
|
||||
zirc.set_density('g/cm3', 6.55)
|
||||
zirc.add_element('Zr', 1.)
|
||||
|
||||
borated_water = openmc.Material(name='Borated water')
|
||||
borated_water.set_density('g/cm3', 0.740582)
|
||||
borated_water.add_element('B', 4.0e-5)
|
||||
borated_water.add_element('H', 5.0e-2)
|
||||
borated_water.add_element('O', 2.4e-2)
|
||||
borated_water.add_s_alpha_beta('c_H_in_H2O')
|
||||
|
||||
mats = openmc.Materials([uo2, zirc, borated_water])
|
||||
|
||||
pitch = 1.25984
|
||||
fuel_or = openmc.ZCylinder(r=0.39218, name='Fuel OR')
|
||||
clad_or = openmc.ZCylinder(r=0.45720, name='Clad OR')
|
||||
box = openmc.model.rectangular_prism(pitch, pitch, boundary_type='reflective')
|
||||
|
||||
# Define cells
|
||||
fuel = openmc.Cell(name='fuel', fill=uo2, region=-fuel_or)
|
||||
clad = openmc.Cell(fill=zirc, region=+fuel_or & -clad_or)
|
||||
water = openmc.Cell(fill=borated_water, region=+clad_or & box)
|
||||
|
||||
# Define overall geometry
|
||||
geom = openmc.Geometry([fuel, clad, water])
|
||||
uo2.volume = pi * fuel_or.r**2
|
||||
|
||||
settings = openmc.Settings()
|
||||
settings.batches = 100
|
||||
settings.inactive = 10
|
||||
settings.particles = 1000
|
||||
|
||||
# Create an initial uniform spatial source distribution over fissionable zones
|
||||
bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1]
|
||||
uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True)
|
||||
settings.source = openmc.source.Source(space=uniform_dist)
|
||||
|
||||
entropy_mesh = openmc.RegularMesh()
|
||||
entropy_mesh.lower_left = [-0.39218, -0.39218, -1.e50]
|
||||
entropy_mesh.upper_right = [0.39218, 0.39218, 1.e50]
|
||||
entropy_mesh.dimension = [10, 10, 1]
|
||||
settings.entropy_mesh = entropy_mesh
|
||||
|
||||
tals = openmc.Tallies()
|
||||
tal = openmc.Tally(name='test')
|
||||
tal.scores = ['flux']
|
||||
tals.append(tal)
|
||||
|
||||
plot = openmc.Plot()
|
||||
plot.origin = (0., 0., 0.)
|
||||
plot.width = (pitch, pitch)
|
||||
plot.pixels = (300, 300)
|
||||
plot.color_by = 'material'
|
||||
plots = openmc.Plots((plot,))
|
||||
|
||||
chain = './chain_simple.xml'
|
||||
fission_q = {'U235': 200e6}
|
||||
|
||||
chain_file_xml = """<?xml version="1.0"?>
|
||||
<depletion_chain>
|
||||
<nuclide name="I135" decay_modes="1" reactions="1" half_life="2.36520E+04">
|
||||
<decay type="beta" target="Xe135" branching_ratio="1.0" />
|
||||
<reaction type="(n,gamma)" Q="0.0" target="Xe136" /> <!-- Not precisely true, but whatever -->
|
||||
</nuclide>
|
||||
<nuclide name="Xe135" decay_modes="1" reactions="1" half_life="3.29040E+04">
|
||||
<decay type=" beta" target="Cs135" branching_ratio="1.0" />
|
||||
<reaction type="(n,gamma)" Q="0.0" target="Xe136" />
|
||||
</nuclide>
|
||||
<nuclide name="Xe136" decay_modes="0" reactions="0" />
|
||||
<nuclide name="Cs135" decay_modes="0" reactions="0" />
|
||||
<nuclide name="Gd157" decay_modes="0" reactions="1" >
|
||||
<reaction type="(n,gamma)" Q="0.0" target="Nothing" />
|
||||
</nuclide>
|
||||
<nuclide name="Gd156" decay_modes="0" reactions="1">
|
||||
<reaction type="(n,gamma)" Q="0.0" target="Gd157" />
|
||||
</nuclide>
|
||||
<nuclide name="U234" decay_modes="0" reactions="1">
|
||||
<reaction type="fission" Q="191840000."/>
|
||||
<neutron_fission_yields>
|
||||
<energies>2.53000e-02</energies>
|
||||
<fission_yields energy="2.53000e-02">
|
||||
<products>Gd157 Gd156 I135 Xe135 Xe136 Cs135</products>
|
||||
<data>1.093250e-04 2.087260e-04 2.780820e-02 6.759540e-03 2.392300e-02 4.356330e-05</data>
|
||||
</fission_yields>
|
||||
</neutron_fission_yields>
|
||||
</nuclide>
|
||||
<nuclide name="U235" decay_modes="0" reactions="1">
|
||||
<reaction type="fission" Q="193410000."/>
|
||||
<neutron_fission_yields>
|
||||
<energies>2.53000e-02</energies>
|
||||
<fission_yields energy="2.53000e-02">
|
||||
<products>Gd157 Gd156 I135 Xe135 Xe136 Cs135</products>
|
||||
<data>6.142710e-5 1.483250e-04 0.0292737 0.002566345 0.0219242 4.9097e-6</data>
|
||||
</fission_yields>
|
||||
</neutron_fission_yields>
|
||||
</nuclide>
|
||||
<nuclide name="U238" decay_modes="0" reactions="1">
|
||||
<reaction type="fission" Q="197790000."/>
|
||||
<neutron_fission_yields>
|
||||
<energies>2.53000e-02</energies>
|
||||
<fission_yields energy="2.53000e-02">
|
||||
<products>Gd157 Gd156 I135 Xe135 Xe136 Cs135</products>
|
||||
<data>4.141120e-04 7.605360e-04 0.0135457 0.00026864 0.0024432 3.7100E-07</data>
|
||||
</fission_yields>
|
||||
</neutron_fission_yields>
|
||||
</nuclide>
|
||||
</depletion_chain>
|
||||
"""
|
||||
|
||||
return (mats, geom, settings, tals, plots, chain, fission_q,
|
||||
chain_file_xml)
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def mpi_intracomm():
|
||||
if config['mpi']:
|
||||
|
|
|
|||
|
|
@ -1,18 +1,162 @@
|
|||
from typing import Type
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
import openmc
|
||||
import openmc.lib
|
||||
|
||||
|
||||
def test_init(run_in_tmpdir, pin_model_attributes):
|
||||
mats, geom, settings, tals, plots, chain, fission_q, _ = \
|
||||
pin_model_attributes
|
||||
|
||||
openmc.reset_auto_ids()
|
||||
# Check blank initialization of a model
|
||||
test_model = openmc.Model()
|
||||
assert test_model.geometry.root_universe is None
|
||||
assert len(test_model.materials) == 0
|
||||
ref_settings = openmc.Settings()
|
||||
assert sorted(test_model.settings.__dict__.keys()) == \
|
||||
sorted(ref_settings.__dict__.keys())
|
||||
for ref_k, ref_v in ref_settings.__dict__.items():
|
||||
assert test_model.settings.__dict__[ref_k] == ref_v
|
||||
assert len(test_model.tallies) == 0
|
||||
assert len(test_model.plots) == 0
|
||||
assert test_model.chain_file is None
|
||||
assert test_model.fission_q is None
|
||||
assert test_model._materials_by_id == {}
|
||||
assert test_model._materials_by_name == {}
|
||||
assert test_model._cells_by_id == {}
|
||||
assert test_model._cells_by_name == {}
|
||||
assert test_model.C_init is False
|
||||
|
||||
# Now check proper init of an actual model. Assume no interference between
|
||||
# parameters and so we can apply them all at once instead of testing one
|
||||
# parameter initialization at a time
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots, chain,
|
||||
fission_q)
|
||||
assert test_model.geometry is geom
|
||||
assert test_model.materials is mats
|
||||
assert test_model.settings is settings
|
||||
assert test_model.tallies is tals
|
||||
assert test_model.plots is plots
|
||||
assert test_model.chain_file == Path(chain).resolve()
|
||||
assert test_model.fission_q is fission_q
|
||||
assert test_model._materials_by_id == {1: mats[0], 2: mats[1], 3: mats[2]}
|
||||
assert test_model._materials_by_name == {'UO2': mats[0], 'Zirc': mats[1],
|
||||
'Borated water': mats[2]}
|
||||
assert test_model._cells_by_id == {1: geom.root_universe.cells[1],
|
||||
2: geom.root_universe.cells[2],
|
||||
3: geom.root_universe.cells[3]}
|
||||
# No cell name for 2 and 3, so we expect a blank name to be assigned to
|
||||
# cell 3 due to overwriting
|
||||
assert test_model._cells_by_name == {
|
||||
'fuel': geom.root_universe.cells[1], '': geom.root_universe.cells[3]}
|
||||
assert test_model.C_init is False
|
||||
|
||||
# Finally test the parameter type checking by passing bad types and
|
||||
# obtaining the right exception types
|
||||
def_params = [geom, mats, settings, tals, plots, chain, fission_q]
|
||||
for i in range(len(def_params)):
|
||||
args = def_params.copy()
|
||||
# Try an integer, as that is a bad type for all arguments
|
||||
args[i] = i
|
||||
with pytest.raises(TypeError):
|
||||
test_model = openmc.Model(*args)
|
||||
|
||||
|
||||
def test_from_xml(run_in_tmpdir, pin_model_attributes):
|
||||
mats, geom, settings, tals, plots, _, _, _ = pin_model_attributes
|
||||
|
||||
# This test will write the individual files to xml and then init that way
|
||||
# and run the same sort of test as in test_init
|
||||
mats.export_to_xml()
|
||||
geom.export_to_xml()
|
||||
settings.export_to_xml()
|
||||
tals.export_to_xml()
|
||||
plots.export_to_xml()
|
||||
|
||||
# This from_xml method cannot load chain and fission_q
|
||||
test_model = openmc.Model.from_xml()
|
||||
assert test_model.geometry.root_universe.cells.keys() == \
|
||||
geom.root_universe.cells.keys()
|
||||
assert [c.fill.name for c in test_model.geometry.root_universe.cells.values()] == \
|
||||
[c.fill.name for c in geom.root_universe.cells.values()]
|
||||
assert [mat.name for mat in test_model.materials] == [mat.name for mat in mats]
|
||||
# We will assume the attributes of settings that are custom objects are
|
||||
# OK if the others are so we dotn need to implement explicit comparisons
|
||||
no_test = ['_source', '_entropy_mesh']
|
||||
assert sorted(k for k in test_model.settings.__dict__.keys() if k not in no_test) == \
|
||||
sorted(k for k in settings.__dict__.keys() if k not in no_test)
|
||||
keys = sorted(k for k in settings.__dict__.keys() if k not in no_test)
|
||||
for ref_k in keys:
|
||||
assert test_model.settings.__dict__[ref_k] == settings.__dict__[ref_k]
|
||||
assert len(test_model.tallies) == 0
|
||||
assert len(test_model.plots) == 0
|
||||
assert test_model.chain_file is None
|
||||
assert test_model.fission_q is None
|
||||
assert test_model._materials_by_id == \
|
||||
{1: test_model.materials[0], 2: test_model.materials[1],
|
||||
3: test_model.materials[2]}
|
||||
assert test_model._materials_by_name == {
|
||||
'UO2': test_model.materials[0], 'Zirc': test_model.materials[1],
|
||||
'Borated water': test_model.materials[2]}
|
||||
assert test_model._cells_by_id == {\
|
||||
1: test_model.geometry.root_universe.cells[1],
|
||||
2: test_model.geometry.root_universe.cells[2],
|
||||
3: test_model.geometry.root_universe.cells[3]}
|
||||
# No cell name for 2 and 3, so we expect a blank name to be assigned to
|
||||
# cell 3 due to overwriting
|
||||
assert test_model._cells_by_name == {
|
||||
'fuel': test_model.geometry.root_universe.cells[1],
|
||||
'': test_model.geometry.root_universe.cells[3]}
|
||||
assert test_model.C_init is False
|
||||
|
||||
|
||||
def test_init_clear_C_api(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
||||
# We are going to init and then make sure data is loaded
|
||||
mats, geom, settings, tals, plots, _, _, _ = pin_model_attributes
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots)
|
||||
# Set the depletion module to use the test intracomm as the depletion mods
|
||||
# intracomm is the one that init uses. We will not perturb system state
|
||||
# outside of this test by re-setting the openmc.deplete.comm to what it was
|
||||
# before when we exist
|
||||
if mpi_intracomm is not None:
|
||||
orig_comm = openmc.deplete.comm
|
||||
openmc.deplete.comm = mpi_intracomm
|
||||
test_model.init_C_api()
|
||||
|
||||
# First check that the API is advertised as initialized
|
||||
assert openmc.lib.LIB_INIT is True
|
||||
assert test_model.C_init is True
|
||||
# Now make sure it actually is initialized by making a call to the lib
|
||||
c_mat = openmc.lib.find_material((0.6, 0., 0.))
|
||||
# This should be Borated water
|
||||
assert c_mat.name == 'Borated water'
|
||||
assert c_mat.id == 3
|
||||
|
||||
# Ok, now lets test that we can clear the data and check that it is cleared
|
||||
test_model.clear_C_api()
|
||||
|
||||
# First check that the API is advertised as initialized
|
||||
assert openmc.lib.LIB_INIT is False
|
||||
assert test_model.C_init is False
|
||||
# Note we cant actually test that a sys call fails because we should get a
|
||||
# seg fault
|
||||
|
||||
# And before done, reset the deplete communicator
|
||||
if mpi_intracomm is not None:
|
||||
openmc.deplete.comm = orig_comm
|
||||
|
||||
|
||||
def test_import_properties(run_in_tmpdir, mpi_intracomm):
|
||||
"""Test importing properties on the Model class """
|
||||
|
||||
# Create PWR pin cell model and write XML files
|
||||
openmc.reset_auto_ids()
|
||||
model = openmc.examples.pwr_pin_cell()
|
||||
model.export_to_xml()
|
||||
model.init_C_api()
|
||||
|
||||
# Change fuel temperature and density and export properties
|
||||
openmc.lib.init(intracomm=mpi_intracomm)
|
||||
cell = openmc.lib.cells[1]
|
||||
cell.set_temperature(600.0)
|
||||
cell.fill.set_density(5.0, 'g/cm3')
|
||||
|
|
@ -32,3 +176,40 @@ def test_import_properties(run_in_tmpdir, mpi_intracomm):
|
|||
cell = model_with_properties.geometry.get_all_cells()[1]
|
||||
assert cell.temperature == [600.0]
|
||||
assert cell.fill.get_mass_density() == pytest.approx(5.0)
|
||||
|
||||
|
||||
def test_run(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
||||
mats, geom, settings, tals, plots, _, _, _ = pin_model_attributes
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots)
|
||||
# Set the depletion module to use the test intracomm as the depletion mods
|
||||
# intracomm is the one that init uses. We will not perturb system state
|
||||
# outside of this test by re-setting the openmc.deplete.comm to what it was
|
||||
# before when we exist
|
||||
|
||||
# This case will run by getting the k-eff and tallies for command-line and
|
||||
# C-API execution modes and ensuring they give the same result.
|
||||
sp_path = test_model.run(output=False)
|
||||
with openmc.StatePoint(sp_path) as sp:
|
||||
cli_keff = sp.k_combined
|
||||
cli_flux = sp.get_tally(id=1).get_values()[0, 0, 0]
|
||||
|
||||
if mpi_intracomm is not None:
|
||||
orig_comm = openmc.deplete.comm
|
||||
openmc.deplete.comm = mpi_intracomm
|
||||
test_model.settings.verbosity = 1
|
||||
test_model.init_C_api()
|
||||
sp_path = test_model.run()
|
||||
with openmc.StatePoint(sp_path) as sp:
|
||||
C_keff = sp.k_combined
|
||||
C_flux = sp.get_tally(id=1).get_values()[0, 0, 0]
|
||||
test_model.clear_C_api()
|
||||
|
||||
# and lets compare results
|
||||
assert (C_keff - cli_keff) < 1e-15
|
||||
assert (C_flux - cli_flux) < 1e-15
|
||||
|
||||
# And before done, reset the deplete communicator
|
||||
if mpi_intracomm is not None:
|
||||
openmc.deplete.comm = orig_comm
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue