mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-27 21:55:41 -04:00
remove obsolete bits and update unit test
This commit is contained in:
parent
3e9733b4ff
commit
17f10c4055
3 changed files with 177 additions and 178 deletions
|
|
@ -20,10 +20,10 @@ from warnings import warn
|
|||
import numpy as np
|
||||
from uncertainties import ufloat
|
||||
|
||||
from openmc.checkvalue import check_value, check_type, check_greater_than, PathLike
|
||||
from openmc.checkvalue import check_type, check_greater_than, PathLike
|
||||
from openmc.mpi import comm
|
||||
from openmc.utility_funcs import change_directory
|
||||
from openmc import Material, Cell
|
||||
from openmc import Material
|
||||
from .stepresult import StepResult
|
||||
from .chain import _get_chain
|
||||
from .results import Results, _SECONDS_PER_MINUTE, _SECONDS_PER_HOUR, \
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
from collections.abc import Callable
|
||||
from numbers import Real
|
||||
from warnings import warn
|
||||
|
||||
import scipy.optimize as sopt
|
||||
|
||||
|
|
@ -13,7 +12,7 @@ _SCALAR_BRACKETED_METHODS = {'brentq', 'brenth', 'ridder', 'bisect'}
|
|||
|
||||
|
||||
def _search_keff(guess, target, model_builder, model_args, print_iterations,
|
||||
run_args, guesses, results, run_in_memory):
|
||||
run_args, guesses, results):
|
||||
"""Function which will actually create our model, run the calculation, and
|
||||
obtain the result. This function will be passed to the root finding
|
||||
algorithm
|
||||
|
|
@ -40,8 +39,7 @@ def _search_keff(guess, target, model_builder, model_args, print_iterations,
|
|||
results : Iterable of Real
|
||||
Running list of results thus far, to be updated during the execution of
|
||||
this function.
|
||||
run_in_memory : bool
|
||||
Whether or not to run the openmc model in memory.
|
||||
|
||||
Returns
|
||||
-------
|
||||
float
|
||||
|
|
@ -53,11 +51,7 @@ def _search_keff(guess, target, model_builder, model_args, print_iterations,
|
|||
model = model_builder(guess, **model_args)
|
||||
|
||||
# Run the model and obtain keff
|
||||
if run_in_memory:
|
||||
openmc.lib.run(**run_args)
|
||||
sp_filepath = f'statepoint.{model.settings.batches}.h5'
|
||||
else:
|
||||
sp_filepath = model.run(**run_args)
|
||||
sp_filepath = model.run(**run_args)
|
||||
with openmc.StatePoint(sp_filepath) as sp:
|
||||
keff = sp.keff
|
||||
|
||||
|
|
@ -76,7 +70,7 @@ def _search_keff(guess, target, model_builder, model_args, print_iterations,
|
|||
def search_for_keff(model_builder, initial_guess=None, target=1.0,
|
||||
bracket=None, model_args=None, tol=None,
|
||||
bracketed_method='bisect', print_iterations=False,
|
||||
run_args=None, run_in_memory=False, **kwargs):
|
||||
run_args=None, **kwargs):
|
||||
"""Function to perform a keff search by modifying a model parametrized by a
|
||||
single independent variable.
|
||||
|
||||
|
|
@ -111,11 +105,6 @@ def search_for_keff(model_builder, initial_guess=None, target=1.0,
|
|||
run_args : dict, optional
|
||||
Keyword arguments to pass to :meth:`openmc.Model.run`. Defaults to no
|
||||
arguments.
|
||||
run_in_memory : bool
|
||||
Whether or not to run the openmc model in memory.
|
||||
Defaults to False.
|
||||
|
||||
.. versionadded:: 0.13.1
|
||||
**kwargs
|
||||
All remaining keyword arguments are passed to the root-finding
|
||||
method.
|
||||
|
|
@ -202,26 +191,12 @@ def search_for_keff(model_builder, initial_guess=None, target=1.0,
|
|||
|
||||
# Add information to be passed to the searching function
|
||||
args['args'] = (target, model_builder, model_args, print_iterations,
|
||||
run_args, guesses, results, run_in_memory)
|
||||
run_args, guesses, results)
|
||||
|
||||
# Create a new dictionary with the arguments from args and kwargs
|
||||
args.update(kwargs)
|
||||
|
||||
# Perform the search
|
||||
if not run_in_memory:
|
||||
zero_value = root_finder(**args)
|
||||
return zero_value, guesses, results
|
||||
zero_value = root_finder(**args)
|
||||
|
||||
else:
|
||||
try:
|
||||
zero_value, root_res = root_finder(**args, full_output=True, disp=False)
|
||||
if root_res.converged:
|
||||
return zero_value, guesses, results
|
||||
|
||||
else:
|
||||
warn(f'{root_res.flag}')
|
||||
return guesses, results
|
||||
# In case the root finder is not successful
|
||||
except Exception as e:
|
||||
warn(f'{e}')
|
||||
return guesses, results
|
||||
return zero_value, guesses, results
|
||||
|
|
@ -8,10 +8,7 @@ import numpy as np
|
|||
import openmc
|
||||
import openmc.lib
|
||||
from openmc.deplete import CoupledOperator
|
||||
from openmc.deplete import (
|
||||
CellReactivityController,
|
||||
MaterialReactivityController
|
||||
)
|
||||
from openmc.deplete import ReactivityController
|
||||
|
||||
CHAIN_PATH = Path(__file__).parents[1] / "chain_simple.xml"
|
||||
|
||||
|
|
@ -73,150 +70,177 @@ def integrator(operator):
|
|||
return openmc.deplete.PredictorIntegrator(
|
||||
operator, [1,1], 0.0, timestep_units = 'd')
|
||||
|
||||
@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, 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
|
||||
|
||||
else:
|
||||
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
|
||||
|
||||
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),
|
||||
('universe_cell', 'rotation', 0)
|
||||
])
|
||||
def test_cell_methods(run_in_tmpdir, model, operator, integrator, obj, attribute,
|
||||
value_to_set):
|
||||
"""
|
||||
Test cell base class internal method
|
||||
"""
|
||||
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()
|
||||
integrator.reactivity_control._set_lib_cell()
|
||||
integrator.reactivity_control._set_cell_attrib(value_to_set)
|
||||
assert integrator.reactivity_control._get_cell_attrib() == value_to_set
|
||||
|
||||
vol = integrator.reactivity_control._adjust_volumes()
|
||||
integrator.reactivity_control._update_x_and_set_volumes(operator.number.number, vol)
|
||||
|
||||
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("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, 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.
|
||||
"""
|
||||
|
||||
integrator.reactivity_control = MaterialReactivityController(
|
||||
material='fuel',
|
||||
operator=operator,
|
||||
material_to_mix=mix_mat,
|
||||
bracket=[-1,1],
|
||||
bracket_limit=[-10,10],
|
||||
units=units,
|
||||
dilute=dilute
|
||||
def test_reactivity_controller_init(operator):
|
||||
"""Test ReactivityController initialization"""
|
||||
def dummy_function(x):
|
||||
return x
|
||||
|
||||
# Valid initialization
|
||||
controller = ReactivityController(
|
||||
operator=operator,
|
||||
function=dummy_function,
|
||||
x0=0.0,
|
||||
x1=1.0,
|
||||
bracket=[0.0, 2.0]
|
||||
)
|
||||
|
||||
assert controller.operator == operator
|
||||
assert controller.function == dummy_function
|
||||
assert controller.x0 == 0.0
|
||||
assert controller.x1 == 1.0
|
||||
assert controller.kwargs['x_min'] == 0.0
|
||||
assert controller.kwargs['x_max'] == 2.0
|
||||
|
||||
# Test invalid bracket with wrong length
|
||||
with pytest.raises(ValueError, match="bracket must have exactly 2 elements"):
|
||||
ReactivityController(operator, dummy_function, 0.0, 1.0, [0.0])
|
||||
|
||||
# Test invalid bracket with wrong order
|
||||
with pytest.raises(ValueError, match="bracket\\[0\\] must be < bracket\\[1\\]"):
|
||||
ReactivityController(operator, dummy_function, 0.0, 1.0, [2.0, 1.0])
|
||||
|
||||
def test_reactivity_controller_call(operator):
|
||||
"""Test the __call__ method acts as a proxy to the function"""
|
||||
call_log = []
|
||||
|
||||
def test_function(x):
|
||||
call_log.append(x)
|
||||
return x * 2
|
||||
|
||||
controller = ReactivityController(
|
||||
operator=operator,
|
||||
function=test_function,
|
||||
x0=0.0,
|
||||
x1=1.0,
|
||||
bracket=[0.0, 2.0]
|
||||
)
|
||||
|
||||
# Test that calling the controller calls the underlying function
|
||||
result = controller(5.0)
|
||||
assert result == 10.0
|
||||
assert call_log == [5.0]
|
||||
|
||||
# Test with multiple arguments
|
||||
def multi_arg_function(x, y, z=3):
|
||||
return x + y + z
|
||||
|
||||
controller2 = ReactivityController(
|
||||
operator=operator,
|
||||
function=multi_arg_function,
|
||||
x0=0.0,
|
||||
x1=1.0,
|
||||
bracket=[0.0, 2.0]
|
||||
)
|
||||
|
||||
result = controller2(1, 2, z=4)
|
||||
assert result == 7
|
||||
|
||||
def translate_cell(position):
|
||||
"""Helper function to translate a cell"""
|
||||
cell = [c for c in openmc.lib.cells.values() if c.name == 'universe_cell'][0]
|
||||
openmc.lib.cells[cell.id].translation = [0, 0, position]
|
||||
return position
|
||||
|
||||
|
||||
def rotate_cell(angle):
|
||||
"""Helper function to rotate a cell"""
|
||||
cell = [c for c in openmc.lib.cells.values() if c.name == 'universe_cell'][0]
|
||||
openmc.lib.cells[cell.id].rotation = [0, 0, angle]
|
||||
return angle
|
||||
|
||||
|
||||
def adjust_fuel_density(density_factor):
|
||||
"""Helper function to adjust fuel density"""
|
||||
fuel = [m for m in openmc.lib.materials.values() if m.name == 'fuel'][0]
|
||||
nuclides = openmc.lib.materials[fuel.id].nuclides
|
||||
current_densities = openmc.lib.materials[fuel.id].densities
|
||||
new_densities = [d * density_factor for d in current_densities]
|
||||
openmc.lib.materials[fuel.id].set_densities(nuclides, new_densities)
|
||||
return density_factor
|
||||
|
||||
@pytest.mark.parametrize("function, x0, x1, bracket, test_value", [
|
||||
(translate_cell, -1.0, 1.0, [-5.0, 5.0], 0.5),
|
||||
(rotate_cell, -45.0, 45.0, [-90.0, 90.0], 10.0),
|
||||
(adjust_fuel_density, 0.8, 1.2, [0.5, 1.5], 1.0)
|
||||
])
|
||||
def test_reactivity_controller_with_openmc_functions(
|
||||
run_in_tmpdir, model, operator, function, x0, x1, bracket, test_value
|
||||
):
|
||||
"""Test ReactivityController with actual OpenMC geometry modification functions"""
|
||||
|
||||
controller = ReactivityController(
|
||||
operator=operator,
|
||||
function=function,
|
||||
x0=x0,
|
||||
x1=x1,
|
||||
bracket=bracket,
|
||||
kwargs={'output': False, 'k_tol': 0.1}
|
||||
)
|
||||
|
||||
# Export model and initialize OpenMC library
|
||||
model.export_to_xml()
|
||||
openmc.lib.init()
|
||||
|
||||
try:
|
||||
# Test that the controller can be called to modify the geometry
|
||||
result = controller(test_value)
|
||||
assert result == test_value
|
||||
|
||||
# Verify the function was actually called by checking it doesn't raise
|
||||
# (actual verification would require checking geometry state)
|
||||
|
||||
finally:
|
||||
openmc.lib.finalize()
|
||||
|
||||
# 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['U235']
|
||||
vol_before_mix = operator.number.get_mat_volume(str(mat.id))
|
||||
def test_controller_kwargs_handling(operator):
|
||||
"""Test that additional kwargs are properly stored and accessible"""
|
||||
def dummy_func(x):
|
||||
return x
|
||||
|
||||
custom_kwargs = {
|
||||
'target': 1.0,
|
||||
'k_tol': 1e-4,
|
||||
'output': True
|
||||
}
|
||||
|
||||
controller = ReactivityController(
|
||||
operator=operator,
|
||||
function=dummy_func,
|
||||
x0=0.0,
|
||||
x1=1.0,
|
||||
bracket=[0.0, 2.0],
|
||||
kwargs=custom_kwargs
|
||||
)
|
||||
|
||||
# Check that bracket limits were added to kwargs
|
||||
assert controller.kwargs['x_min'] == 0.0
|
||||
assert controller.kwargs['x_max'] == 2.0
|
||||
|
||||
# Check that custom kwargs were preserved
|
||||
assert controller.kwargs['target'] == 1.0
|
||||
assert controller.kwargs['k_tol'] == 1e-4
|
||||
assert controller.kwargs['output'] == True
|
||||
|
||||
# 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)
|
||||
def test_integrator_add_reactivity_control(run_in_tmpdir, model, operator, integrator):
|
||||
"""Test adding reactivity control to integrator using the add_reactivity_control method"""
|
||||
|
||||
def adjust_density(factor):
|
||||
# This would modify material density in practice
|
||||
return factor
|
||||
|
||||
# Test that add_reactivity_control method exists and works
|
||||
integrator.add_reactivity_control(
|
||||
function=adjust_density,
|
||||
x0=0.8,
|
||||
x1=1.2,
|
||||
bracket=[0.5, 1.5],
|
||||
kwargs={'k_tol': 0.1, 'output': False}
|
||||
)
|
||||
|
||||
assert integrator.reactivity_control is not None
|
||||
assert isinstance(integrator.reactivity_control, ReactivityController)
|
||||
assert integrator.reactivity_control.x0 == 0.8
|
||||
assert integrator.reactivity_control.x1 == 1.2
|
||||
assert integrator.reactivity_control.kwargs['x_min'] == 0.5
|
||||
assert integrator.reactivity_control.kwargs['x_max'] == 1.5
|
||||
|
||||
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('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)
|
||||
|
||||
# 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)) == vol_after_mix[str(mat.id)]
|
||||
|
||||
openmc.lib.finalize()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue