From b4391296dd8de227ba8e5d4a868aab1a79a714ff Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 18 Mar 2017 16:34:19 -0400 Subject: [PATCH] Added a model container and a keff search algorithm --- openmc/__init__.py | 2 + openmc/modelcontainer.py | 126 +++++++++++++++++++++++++++++++++++++++ openmc/search.py | 126 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 254 insertions(+) create mode 100644 openmc/modelcontainer.py create mode 100644 openmc/search.py diff --git a/openmc/__init__.py b/openmc/__init__.py index b355385580..4030063d9f 100644 --- a/openmc/__init__.py +++ b/openmc/__init__.py @@ -28,3 +28,5 @@ from openmc.summary import * from openmc.particle_restart import * from openmc.mixin import * from openmc.plotter import * +from openmc.search import * +from openmc.modelcontainer import * diff --git a/openmc/modelcontainer.py b/openmc/modelcontainer.py new file mode 100644 index 0000000000..384f3f84bf --- /dev/null +++ b/openmc/modelcontainer.py @@ -0,0 +1,126 @@ +import openmc +from openmc.checkvalue import check_type + + +class ModelContainer(object): + """OpenMC model container for the openmc.Geometry, openmc.Materials, + openmc.Settings, openmc.Tallies, and openmc.CMFD objects + + Parameters + ---------- + geometry : openmc.Geometry + Geometry information + materials : openmc.Materials + Materials information + settings : openmc.Settings + Settings information + tallies : openmc.Tallies + Tallies information, optional + cmfd : openmc.CMFD + CMFD information, optional + + Attributes + ---------- + geometry : openmc.Geometry + Geometry information + materials : openmc.Materials + Materials information + settings : openmc.Settings + Settings information + tallies : openmc.Tallies + Tallies information + cmfd : openmc.CMFD + CMFD information + + """ + + def __init__(self, geometry, materials, settings, tallies=None, cmfd=None): + self.geometry = geometry + self.materials = materials + self.settings = settings + if tallies: + self.tallies = tallies + else: + self._tallies = None + if cmfd: + self.cmfd = cmfd + else: + self._cmfd = None + + self.sp = None + + @property + def geometry(self): + return self._geometry + + @geometry.setter + def geometry(self, geometry): + check_type('geometry', geometry, openmc.Geometry) + self._geometry = geometry + + @property + def materials(self): + return self._materials + + @materials.setter + def materials(self, materials): + check_type('materials', materials, openmc.Materials) + self._materials = materials + + @property + def settings(self): + return self._settings + + @settings.setter + def settings(self, settings): + check_type('settings', settings, openmc.Settings) + self._settings = settings + + @property + def tallies(self): + return self._tallies + + @tallies.setter + def tallies(self, tallies): + check_type('tallies', tallies, openmc.Tallies) + self._tallies = tallies + + @property + def cmfd(self): + return self._cmfd + + @cmfd.setter + def cmfd(self, cmfd): + check_type('cmfd', cmfd, openmc.CMFD) + self._cmfd = cmfd + + def export_to_xml(self): + """Export model settings to XML files. + """ + + self.geometry.export_to_xml() + self.materials.export_to_xml() + self.settings.export_to_xml() + if self.tallies: + self.tallies.export_to_xml() + if self.cmfd: + self.cmfd.export_to_xml() + + def execute(self, output=True): + self.export_to_xml() + + openmc.run(output=output) + + statepoint_batches = self.settings.batches + if self.settings.statepoint is not None: + if 'batches' in self.settings.statepoint: + statepoint_batches = self.settings.statepoint['batches'][-1] + self.sp = openmc.StatePoint('statepoint.' + str(statepoint_batches) + + '.h5') + + return self.sp.k_combined + + def close(self): + if self.sp is not None: + self.sp._f.close() + self.sp.summary._f.close() diff --git a/openmc/search.py b/openmc/search.py new file mode 100644 index 0000000000..d99b427b00 --- /dev/null +++ b/openmc/search.py @@ -0,0 +1,126 @@ +from numbers import Real +from types import FunctionType +from inspect import getfullargspec + +import openmc +from openmc.checkvalue import check_type, check_length + + +class KeffSearch(object): + """Class to perform a search for a certain keff value given changes on an + arbitrary scalar input. + + Parameters + ---------- + model_builder : FunctionType + Callable function which builds a model according to a single, passed + parameter. This function must return an openmc.ModelContainer object. + guess : Real + Initial guess for the parameter modified in :param:`model_builder`. + target_keff : Real + keff value to search for, defaults to 1.0. + + Attributes + ---------- + model_builder : FunctionType + Callable function which builds a model according to a single, passed + parameter. This function must return an openmc.ModelContainer object. + guess : Real + Initial guess for the parameter modified in :param:`model_builder`. + target_keff : Real + keff value to search for. + guesses : List of Real + List of guesses attempted by the search + keffs : List of Real + List of keffs corresponding to the guess attempted by the search + keff_uncs : List of Real + List of keff uncertainties corresponding to the guess attempted by the + search + + """ + + def __init__(self, model_builder, guess, target_keff=1.0): + self.initial_guess = guess + self.model_builder = model_builder + self.target_keff = target_keff + self.guesses = [] + self.keffs = [] + self.keff_uncs = [] + + @property + def model_builder(self): + return self._model_builder + + @model_builder.setter + def model_builder(self, model_builder): + # Make sure model_builder is a function + check_type('model_builder', model_builder, FunctionType) + + # Make sure model_builder has only one parameter + argspec = getfullargspec(model_builder) + check_length('model_builder arguments', argspec.args, 1) + + # Run the model builder function once to make sure it provides the + # correct output types + model = model_builder(self.initial_guess) + check_type('model_builder return', model, openmc.ModelContainer) + self._model_builder = model_builder + + @property + def initial_guess(self): + return self._initial_guess + + @initial_guess.setter + def initial_guess(self, initial_guess): + self._initial_guess = initial_guess + + @property + def target_keff(self): + return self._target_keff + + @target_keff.setter + def target_keff(self, target_keff): + check_type('target_keff', target_keff, Real) + self._target_keff = target_keff + + def _search_function(self, guess): + # Build the model + model = self.model_builder(guess) + + # Run the model + keff = model.execute(output=False) + + # Close the model to ensure HDF5 will allow access during the next + # OpenMC execution + model.close() + + # Record the history + self.guesses.append(guess) + self.keffs.append(keff[0]) + self.keff_uncs.append(keff[1]) + + return (keff[0] - self.target_keff) + + def search(self, **kwargs): + """Searches for the target eigenvalue with the Newton-Raphson method + + Parameters + ---------- + **kwargs + Keyword arguments passed to :func:`scipy.optimize.newton`. + + Returns + zero_value : Real + Estimated value of the variable parameter where keff is the + targeted value + keff : Iterable of Real + keff calculated at the zero_value + + """ + + import scipy.optimize as sopt + + zero_value = sopt.newton(self._search_function, self.initial_guess, + **kwargs) + + return zero_value