remove obsolete bits and update unit test

This commit is contained in:
church89 2026-01-19 14:35:00 +01:00
parent 3e9733b4ff
commit 17f10c4055
3 changed files with 177 additions and 178 deletions

View file

@ -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, \

View file

@ -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

View file

@ -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()