Merge pull request #32 from openmsr/reactivity_control_abstrac

Reactivity control abstrac
This commit is contained in:
Lorenzo Chierici 2024-06-06 13:23:32 +02:00 committed by GitHub
commit c3a67058d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 338 additions and 707 deletions

View file

@ -31,11 +31,9 @@ from .reaction_rates import ReactionRates
from .transfer_rates import TransferRates
from openmc import Material, Cell
from .reactivity_control import (
ReactivityController,
CellReactivityController,
GeometricalCellReactivityController,
TemperatureCellReactivityController,
MaterialReactivityController,
RefuelMaterialReactivityController
MaterialReactivityController
)
__all__ = [
@ -718,25 +716,7 @@ class Integrator(ABC):
@reactivity_control.setter
def reactivity_control(self, reactivity_control):
if isinstance(reactivity_control, CellReactivityController):
if not isinstance(reactivity_control.cell, Cell):
raise TypeError(
"Reactivity control attribute must be Cell "
"not {}".format(type(reactivity_control.cell)))
elif isinstance(reactivity_control, MaterialReactivityController):
if not isinstance(reactivity_control.material, Material):
raise TypeError(
"Reactivity control attribute must be Material "
"not {}".format(type(reactivity_control.material)))
else:
raise TypeError(
"Reactivity Control must either be "
"CellReactivityController, or MaterialReactivityController, "
"not {}".format(type(reactivity_control)))
check_value('attribute', reactivity_control.attrib_name,
('translation', 'rotation', 'temperature', 'refuel'))
check_type('reactivity control', reactivity_control, ReactivityController)
self._reactivity_control = reactivity_control
def _timed_deplete(self, n, rates, dt, matrix_func=None):
@ -945,34 +925,26 @@ class Integrator(ABC):
def add_reactivity_control(
self,
obj: Union[Cell, Material, int, str],
attr: str,
obj: Union[Cell, Material],
**kwargs):
"""Add reactivity control to integrator scheme.
"""Add pre-defined Cell based or Material bases reactivity control to
integrator scheme.
Parameters
----------
obj : openmc.Cell or openmc.Material object or id or str name
Cell or Materials identifier to where add reactivity control
attr : str
Attribute to specify the type of reactivity control. Accepted values
are: 'translation', 'rotation', 'temperature' for an openmc.Cell
object; 'refuel' for an openmc.Material object.
obj : openmc.Cell or openmc.Material
Cell or Material identifier to where add reactivity control
**kwargs
keyword arguments that are passed to the ReactivityController class.
keyword arguments that are passed to the specific ReactivityController
class.
"""
check_value('attribute', attr, ('translation', 'rotation',
'temperature', 'refuel'))
if attr in ('translation', 'rotation'):
reactivity_control = GeometricalCellReactivityController
elif attr == 'temperature':
reactivity_control = TemperatureCellReactivityController
elif attr == 'refuel':
reactivity_control = RefuelMaterialReactivityController
self._reactivity_control = reactivity_control.from_params(obj, attr,
self.operator, **kwargs)
if isinstance(obj, Cell):
reactivity_control = CellReactivityController
elif isinstance(obj, Material):
reactivity_control = MaterialReactivityController
self._reactivity_control = reactivity_control.from_params(obj,
self.operator, **kwargs)
@add_params
class SIIntegrator(Integrator):

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,10 @@ import numpy as np
import openmc
import openmc.lib
from openmc.deplete import CoupledOperator
from openmc.deplete import (
CellReactivityController,
MaterialReactivityController
)
from tests.regression_tests import config
@ -78,13 +82,21 @@ def model():
return openmc.Model(geometry, materials, settings)
@pytest.mark.parametrize("obj, attribute, bracket_limit, axis, vec, ref_result", [
('trans_cell', 'translation', [-40,40], 2, None, 'depletion_with_translation'),
('rot_cell', 'rotation', [-90,90], 2, None, 'depletion_with_rotation'),
('f', 'refuel', [-100,100], None, {'U235':0.9, 'U238':0.1}, 'depletion_with_refuel')
@pytest.fixture
def mix_mat():
mix_mat = openmc.Material()
mix_mat.add_element("U", 1, percent_type="ao", enrichment=90)
mix_mat.add_element("O", 2)
mix_mat.set_density("g/cc", 10.4)
return mix_mat
@pytest.mark.parametrize("obj, attribute, bracket, bracket_limit, axis, ref_result", [
('trans_cell', 'translation', [-5,5], [-40,40], 2, 'depletion_with_translation'),
('rot_cell', 'rotation', [-5,5], [-90,90], 2, 'depletion_with_rotation'),
('f', None, [-1,2], [-100,100], None, 'depletion_with_refuel')
])
def test_reactivity_control(run_in_tmpdir, model, obj, attribute, bracket_limit,
axis, vec, ref_result):
def test_reactivity_control(run_in_tmpdir, model, obj, attribute, bracket,
bracket_limit, axis, ref_result, mix_mat):
chain_file = Path(__file__).parents[2] / 'chain_simple.xml'
op = CoupledOperator(model, chain_file)
@ -92,16 +104,23 @@ def test_reactivity_control(run_in_tmpdir, model, obj, attribute, bracket_limit,
integrator = openmc.deplete.PredictorIntegrator(
op, [1], 174., timestep_units = 'd')
kwargs = {'bracket': [-4,4], 'bracket_limit':bracket_limit,
'tol': 0.1,}
if vec is not None:
kwargs['mat_vector']=vec
if axis is not None:
kwargs['axis'] = axis
integrator.add_reactivity_control(obj, attribute, **kwargs)
if attribute:
integrator.reactivity_control = CellReactivityController(
cell=obj,
operator=op,
attribute=attribute,
bracket=bracket,
bracket_limit=bracket_limit,
axis=axis
)
else:
integrator.reactivity_control = MaterialReactivityController(
material=obj,
operator=op,
material_to_mix=mix_mat,
bracket=bracket,
bracket_limit=bracket_limit,
)
integrator.integrate()
# Get path to test and reference results

View file

@ -9,9 +9,8 @@ import openmc
import openmc.lib
from openmc.deplete import CoupledOperator
from openmc.deplete import (
GeometricalCellReactivityController,
TemperatureCellReactivityController,
RefuelMaterialReactivityController
CellReactivityController,
MaterialReactivityController
)
CHAIN_PATH = Path(__file__).parents[1] / "chain_simple.xml"
@ -74,62 +73,52 @@ def integrator(operator):
return openmc.deplete.PredictorIntegrator(
operator, [1,1], 0.0, timestep_units = 'd')
@pytest.mark.parametrize("case_name, obj, attribute, bracket, limit, axis, vec", [
('cell translation','universe_cell', 'translation', [-1,1], [-10,10], 2, None),
('cell rotation', 'universe_cell', 'rotation', [-1,1], [-10,10], 2, None),
('single cell temperature', 'fuel_cell', 'temperature', [-1,1], [-10,10], 2, None ),
('multi cell', 'universe_cell', 'temperature', [-1,1], [-10,10], 2, None ),
('material refuel', 'fuel', 'refuel', [-1,1], [-10,10], None, {'U235':0.1, 'U238':0.9}),
('invalid_1', 'universe_cell', 'refuel', [-1,1], [-10,10], None, {'U235':0.1, 'U238':0.9}),
('invalid_2', 'fuel', 'temperature', [-1,1], [-10,10], 2, None ),
('invalid_3', 'fuel', 'translation', [-1,1], [-10,10], 2, None),
@pytest.fixture
def mix_mat():
mix_mat = openmc.Material()
mix_mat.add_element("U", 1, percent_type="ao", enrichment=90)
mix_mat.add_element("O", 2)
mix_mat.set_density("g/cc", 10.4)
return mix_mat
@pytest.mark.parametrize("case_name, obj, attribute, bracket, limit, axis", [
('cell translation','universe_cell', 'translation', [-1,1], [-10,10], 2),
('cell rotation', 'universe_cell', 'rotation', [-1,1], [-10,10], 2),
('material mix', 'fuel', None, [0,5], [-10,10], None),
])
def test_attributes(case_name, model, operator, integrator, obj, attribute,
bracket, limit, axis, vec):
bracket, limit, axis, mix_mat):
"""
Test classes attributes are set correctly
"""
if attribute:
integrator.reactivity_control = CellReactivityController(
cell=obj,
operator=operator,
attribute=attribute,
bracket=bracket,
bracket_limit=limit,
axis=axis
)
assert integrator.reactivity_control.depletable_cells == [cell for cell in \
model.geometry.get_cells_by_name(obj)[0].fill.cells.values() \
if cell.fill.depletable]
assert integrator.reactivity_control.axis == axis
kwargs = {'bracket': bracket, 'bracket_limit':limit, 'tol': 0.1,}
if vec is not None:
kwargs['mat_vector']=vec
if axis is not None:
kwargs['axis'] = axis
if case_name == "invalid_1":
with pytest.raises(ValueError) as e:
integrator.add_reactivity_control(obj, attribute, **kwargs)
assert str(e.value) == 'Unable to set "Material name" to "universe_cell" '\
'since it is not in "[\'fuel\', \'water\']"'
elif case_name == "invalid_2":
with pytest.raises(ValueError) as e:
integrator.add_reactivity_control(obj, attribute, **kwargs)
assert str(e.value) == 'Unable to set "Cell name exists" to "fuel" since '\
'it is not in "[\'fuel_cell\', \'universe_cell\', \'\', \'\']"'
elif case_name == "invalid_3":
with pytest.raises(ValueError) as e:
integrator.add_reactivity_control(obj, attribute, **kwargs)
assert str(e.value) == 'Unable to set "Cell name exists" to "fuel" since '\
'it is not in "[\'fuel_cell\', \'universe_cell\', \'\', \'\']"'
else:
integrator.add_reactivity_control(obj, attribute, **kwargs)
if attribute in ('translation','rotation'):
assert integrator.reactivity_control.universe_cells == [cell for cell in \
model.geometry.get_cells_by_name(obj)[0].fill.cells.values() \
if cell.fill.depletable]
assert integrator.reactivity_control.axis == axis
integrator.reactivity_control = MaterialReactivityController(
material=obj,
operator=operator,
material_to_mix=mix_mat,
bracket=bracket,
bracket_limit=limit
)
assert integrator.reactivity_control.material_to_mix == mix_mat
elif attribute == 'refuel':
assert integrator.reactivity_control.mat_vector == vec
assert integrator.reactivity_control.attrib_name == attribute
assert integrator.reactivity_control.bracket == bracket
assert integrator.reactivity_control.bracket_limit == limit
assert integrator.reactivity_control.burn_mats == operator.burnable_mats
assert integrator.reactivity_control.local_mats == operator.local_mats
assert integrator.reactivity_control.bracket == bracket
assert integrator.reactivity_control.bracket_limit == limit
assert integrator.reactivity_control.burn_mats == operator.burnable_mats
assert integrator.reactivity_control.local_mats == operator.local_mats
@pytest.mark.parametrize("obj, attribute, value_to_set", [
('universe_cell', 'translation', 0),
@ -140,9 +129,14 @@ def test_cell_methods(run_in_tmpdir, model, operator, integrator, obj, attribute
"""
Test cell base class internal method
"""
kwargs = {'bracket':[-1,1], 'bracket_limit':[-10,10], 'axis':2, 'tol':0.1}
integrator.add_reactivity_control(obj, attribute, **kwargs)
integrator.reactivity_control = CellReactivityController(
cell=obj,
operator=operator,
attribute=attribute,
bracket=[-1,1],
bracket_limit=[-10,10],
axis=2
)
model.export_to_xml()
openmc.lib.init()
@ -150,63 +144,79 @@ def test_cell_methods(run_in_tmpdir, model, operator, integrator, obj, attribute
integrator.reactivity_control._set_cell_attrib(value_to_set)
assert integrator.reactivity_control._get_cell_attrib() == value_to_set
vol = integrator.reactivity_control._calculate_volumes()
vol = integrator.reactivity_control._adjust_volumes()
integrator.reactivity_control._update_x_and_set_volumes(operator.number.number, vol)
for cell in integrator.reactivity_control.universe_cells:
for cell in integrator.reactivity_control.depletable_cells:
mat_id = str(cell.fill.id)
index_mat = operator.number.index_mat[mat_id]
assert vol[mat_id] == operator.number.volume[index_mat]
openmc.lib.finalize()
@pytest.mark.parametrize("nuclide, atoms_to_add", [
('U238', 1.0e22),
('Xe135', 1.0e21)
@pytest.mark.parametrize("units, value, dilute", [
('cc', 1.0, True),
('cm3', 1.0, False),
('grams', 1.0, True),
('grams', 1.0, False),
('atoms', 1.0, True),
('atoms', 1.0, False),
])
def test_internal_methods(run_in_tmpdir, model, operator, integrator, nuclide,
atoms_to_add):
def test_internal_methods(run_in_tmpdir, model, operator, integrator, mix_mat,
units, value, dilute):
"""
Method to update volume in AtomNumber after depletion step.
Method inheritated by all derived classes so one check is enough.
"""
kwargs = {'bracket':[-1,1], 'bracket_limit':[-10,10], 'mat_vector':{}}
integrator.add_reactivity_control('fuel', 'refuel', **kwargs)
integrator.reactivity_control = MaterialReactivityController(
material='fuel',
operator=operator,
material_to_mix=mix_mat,
bracket=[-1,1],
bracket_limit=[-10,10],
units=units,
dilute=dilute
)
model.export_to_xml()
openmc.lib.init()
#Increase number of atoms of U238 in fuel by fix amount and check the
# volume increase at constant-density
#extract fuel material from model materials
# check material volume are adjusted correctly
mat = integrator.reactivity_control.material
mat_index = operator.number.index_mat[str(mat.id)]
nuc_index = operator.number.index_nuc[nuclide]
vol = operator.number.get_mat_volume(str(mat.id))
operator.number.number[mat_index][nuc_index] += atoms_to_add
integrator.reactivity_control._update_volumes()
nuc_index = operator.number.index_nuc['U235']
vol_before_mix = operator.number.get_mat_volume(str(mat.id))
vol_to_compare = vol + (atoms_to_add * openmc.data.atomic_mass(nuclide) /\
openmc.data.AVOGADRO / mat.density)
# set mix_mat volume
integrator.reactivity_control._set_mix_material_volume(value)
mix_mat_vol = mix_mat.volume
#extract nuclide in atoms
mix_nuc_atoms = mix_mat.get_nuclide_atoms()['U235']
operator.number.number[mat_index][nuc_index] += mix_nuc_atoms
#update volume
vol_after_mix = integrator.reactivity_control._adjust_volumes(mix_mat_vol)
assert operator.number.get_mat_volume(str(mat.id)) == pytest.approx(vol_to_compare)
if dilute:
assert vol_before_mix + mix_mat_vol == vol_after_mix[str(mat.id)]
else:
assert vol_before_mix == vol_after_mix[str(mat.id)]
#check nuclide densities get assigned correctly in memory
x = [i[:operator.number.n_nuc_burn] for i in operator.number.number]
integrator.reactivity_control._update_materials(x)
nuc_index_lib = openmc.lib.materials[mat.id].nuclides.index(nuclide)
dens_to_compare = 1.0e-24 * operator.number.get_atom_density(str(mat.id), nuclide)
nuc_index_lib = openmc.lib.materials[mat.id].nuclides.index('U235')
dens_to_compare = 1.0e-24 * operator.number.get_atom_density(str(mat.id), 'U235')
assert openmc.lib.materials[mat.id].densities[nuc_index_lib] == pytest.approx(dens_to_compare)
volumes = {str(mat.id): vol + 1}
new_x = integrator.reactivity_control._update_x_and_set_volumes(x, volumes)
dens_to_compare = 1.0e24 * volumes[str(mat.id)] *\
# check volumes get assigned correctly in AtomNumber
new_x = integrator.reactivity_control._update_x_and_set_volumes(x, vol_after_mix)
dens_to_compare = 1.0e24 * vol_after_mix[str(mat.id)] *\
openmc.lib.materials[mat.id].densities[nuc_index_lib]
assert new_x[mat_index][nuc_index] == pytest.approx(dens_to_compare)
# assert volume in AtomNumber is set correctly
assert operator.number.get_mat_volume(str(mat.id)) == volumes[str(mat.id)]
assert operator.number.get_mat_volume(str(mat.id)) == vol_after_mix[str(mat.id)]
openmc.lib.finalize()