mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-21 06:25:30 -04:00
204 lines
7 KiB
Python
204 lines
7 KiB
Python
from collections.abc import Callable
|
|
from numbers import Real
|
|
|
|
import scipy.optimize as sopt
|
|
|
|
import openmc
|
|
import openmc.model
|
|
import openmc.checkvalue as cv
|
|
|
|
|
|
_SCALAR_BRACKETED_METHODS = {'brentq', 'brenth', 'ridder', 'bisect'}
|
|
|
|
|
|
def _search_keff(guess, target, model_builder, model_args, print_iterations,
|
|
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
|
|
|
|
Parameters
|
|
----------
|
|
guess : Real
|
|
Current guess for the parameter to be searched in `model_builder`.
|
|
target_keff : Real
|
|
Value to search for
|
|
model_builder : collections.Callable
|
|
Callable function which builds a model according to a passed
|
|
parameter. This function must return an openmc.model.Model object.
|
|
model_args : dict
|
|
Keyword-based arguments to pass to the `model_builder` method.
|
|
print_iterations : bool
|
|
Whether or not to print the guess and the resultant keff during the
|
|
iteration process.
|
|
run_args : dict
|
|
Keyword arguments to pass to :meth:`openmc.Model.run`.
|
|
guesses : Iterable of Real
|
|
Running list of guesses thus far, to be updated during the execution of
|
|
this function.
|
|
results : Iterable of Real
|
|
Running list of results thus far, to be updated during the execution of
|
|
this function.
|
|
|
|
Returns
|
|
-------
|
|
float
|
|
Value of the model for the current guess compared to the target value.
|
|
|
|
"""
|
|
|
|
# Build the model
|
|
model = model_builder(guess, **model_args)
|
|
|
|
# Run the model and obtain keff
|
|
sp_filepath = model.run(**run_args)
|
|
with openmc.StatePoint(sp_filepath) as sp:
|
|
keff = sp.keff
|
|
|
|
# Record the history
|
|
guesses.append(guess)
|
|
results.append(keff)
|
|
|
|
if print_iterations:
|
|
text = 'Iteration: {}; Guess of {:.2e} produced a keff of ' + \
|
|
'{:1.5f} +/- {:1.5f}'
|
|
print(text.format(len(guesses), guess, keff.n, keff.s))
|
|
|
|
return keff.n - target
|
|
|
|
|
|
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, **kwargs):
|
|
"""Function to perform a keff search by modifying a model parametrized by a
|
|
single independent variable.
|
|
|
|
Parameters
|
|
----------
|
|
model_builder : collections.Callable
|
|
Callable function which builds a model according to a passed
|
|
parameter. This function must return an openmc.model.Model object.
|
|
initial_guess : Real, optional
|
|
Initial guess for the parameter to be searched in
|
|
`model_builder`. One of `guess` or `bracket` must be provided.
|
|
target : Real, optional
|
|
keff value to search for, defaults to 1.0.
|
|
bracket : None or Iterable of Real, optional
|
|
Bracketing interval to search for the solution; if not provided,
|
|
a generic non-bracketing method is used. If provided, the brackets
|
|
are used. Defaults to no brackets provided. One of `guess` or `bracket`
|
|
must be provided. If both are provided, the bracket will be
|
|
preferentially used.
|
|
model_args : dict, optional
|
|
Keyword-based arguments to pass to the `model_builder` method. Defaults
|
|
to no arguments.
|
|
tol : float
|
|
Tolerance to pass to the search method
|
|
bracketed_method : {'brentq', 'brenth', 'ridder', 'bisect'}, optional
|
|
Solution method to use; only applies if
|
|
`bracket` is set, otherwise the Secant method is used.
|
|
Defaults to 'bisect'.
|
|
print_iterations : bool
|
|
Whether or not to print the guess and the result during the iteration
|
|
process. Defaults to False.
|
|
run_args : dict, optional
|
|
Keyword arguments to pass to :meth:`openmc.Model.run`. Defaults to no
|
|
arguments.
|
|
|
|
.. versionadded:: 0.13.1
|
|
**kwargs
|
|
All remaining keyword arguments are passed to the root-finding
|
|
method.
|
|
|
|
Returns
|
|
-------
|
|
zero_value : float
|
|
Estimated value of the variable parameter where keff is the
|
|
targeted value
|
|
guesses : List of Real
|
|
List of guesses attempted by the search
|
|
results : List of 2-tuple of Real
|
|
List of keffs and uncertainties corresponding to the guess attempted by
|
|
the search
|
|
|
|
"""
|
|
|
|
if initial_guess is not None:
|
|
cv.check_type('initial_guess', initial_guess, Real)
|
|
if bracket is not None:
|
|
cv.check_iterable_type('bracket', bracket, Real)
|
|
cv.check_length('bracket', bracket, 2)
|
|
cv.check_less_than('bracket values', bracket[0], bracket[1])
|
|
if model_args is None:
|
|
model_args = {}
|
|
else:
|
|
cv.check_type('model_args', model_args, dict)
|
|
cv.check_type('target', target, Real)
|
|
cv.check_type('tol', tol, Real)
|
|
cv.check_value('bracketed_method', bracketed_method,
|
|
_SCALAR_BRACKETED_METHODS)
|
|
cv.check_type('print_iterations', print_iterations, bool)
|
|
if run_args is None:
|
|
run_args = {}
|
|
else:
|
|
cv.check_type('run_args', run_args, dict)
|
|
cv.check_type('model_builder', model_builder, Callable)
|
|
|
|
# Run the model builder function once to make sure it provides the correct
|
|
# output type
|
|
if bracket is not None:
|
|
model = model_builder(bracket[0], **model_args)
|
|
elif initial_guess is not None:
|
|
model = model_builder(initial_guess, **model_args)
|
|
cv.check_type('model_builder return', model, openmc.model.Model)
|
|
|
|
# Set the iteration data storage variables
|
|
guesses = []
|
|
results = []
|
|
|
|
# Set the searching function (for easy replacement should a later
|
|
# generic function be added.
|
|
search_function = _search_keff
|
|
|
|
if bracket is not None:
|
|
# Generate our arguments
|
|
args = {'f': search_function, 'a': bracket[0], 'b': bracket[1]}
|
|
if tol is not None:
|
|
args['rtol'] = tol
|
|
|
|
# Set the root finding method
|
|
if bracketed_method == 'brentq':
|
|
root_finder = sopt.brentq
|
|
elif bracketed_method == 'brenth':
|
|
root_finder = sopt.brenth
|
|
elif bracketed_method == 'ridder':
|
|
root_finder = sopt.ridder
|
|
elif bracketed_method == 'bisect':
|
|
root_finder = sopt.bisect
|
|
|
|
elif initial_guess is not None:
|
|
|
|
# Generate our arguments
|
|
args = {'func': search_function, 'x0': initial_guess}
|
|
if tol is not None:
|
|
args['tol'] = tol
|
|
|
|
# Set the root finding method
|
|
root_finder = sopt.newton
|
|
|
|
else:
|
|
raise ValueError("Either the 'bracket' or 'initial_guess' parameters "
|
|
"must be set")
|
|
|
|
# Add information to be passed to the searching function
|
|
args['args'] = (target, model_builder, model_args, print_iterations,
|
|
run_args, guesses, results)
|
|
|
|
# Create a new dictionary with the arguments from args and kwargs
|
|
args.update(kwargs)
|
|
|
|
# Perform the search
|
|
zero_value = root_finder(**args)
|
|
|
|
return zero_value, guesses, results
|