Source code for mcnpy.search

"""
Copyright (c) 2011-2023 Massachusetts Institute of Technology, UChicago Argonne
LLC, and OpenMC contributors

Copyright (c) 2023 NuCoMP

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""

import time
import scipy.optimize as sopt

[docs]def get_keff(file:str): """Get final keff from an MCTAL file. Parameters ---------- file : str Name of MCTAL file with keff outputs. Returns ------- keff_value : float Final keff value. keff_std : float Final keff standard deviation. """ from mcnptools import Mctal, MctalKcode m = Mctal(file+'m') kc = m.GetKcode() keff = MctalKcode.AVG_COMBINED_KEFF keff_std = MctalKcode.AVG_COMBINED_KEFF_STD return (kc.GetValue(keff, kc.GetCycles()-1), kc.GetValue(keff_std, kc.GetCycles()-1))
def _search_keff(guess, target, make_deck, run_mcnp, get_keff, deck_args, print_iterations, guesses, results): """Function which will actually create our deck, run the calculation, and obtain the result. This function will be passed to the root finding algorithm. Parameters ---------- guess : float Current guess for the parameter to be searched in `make_deck`. target_keff : float Value to search for make_deck : collections.Callable Callable function which builds a deck according to a passed parameter. This function must return the name of an on-disk MCNP deck. Can be helpful to generate a unique name for each deck, like `my_deck.iteration#.mcnp`. run_mcnp : collections.Callable Callable function which executes an MCNP simulation. Must accept the name of an on-disk MCNP file. Recommended to run MCNP with the `N=input_name` convention to create outputs with recognizable names. get_keff : collections.Callable Callable function which retrieves a keff value. Must accept the name of an on-disk MCNP file. Recommended to run MCNP with the `N=input_name` convention to create outputs with recognizable names. Also recommended to generate an MCTAL file and use MCNPTools to extract keff values. deck_args : dict Keyword-based arguments to pass to the `make_deck` method. print_iterations : bool Whether or not to print the guess and the resultant keff during the iteration process. guesses : Iterable of float Running list of guesses thus far, to be updated during the execution of this function. results : Iterable of float 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 print('Building the MCNP Deck...') filename = make_deck(float(guess), **deck_args) # Run the model and obtain keff print('Initiating MCNP Simulation...') start = time.time() run_mcnp(filename) run_time = (time.time()-start) / 60 keff = get_keff(filename) # Record the history guesses.append(guess) results.append(keff) if print_iterations: text = 'Iteration: {}; Guess of {:.5e} produced a keff of ' + \ '{:1.5f} +/- {:1.5f} in {:1.2f} minutes' print(text.format(len(guesses), guess, keff[0], keff[1], run_time)) return keff[0] - target
[docs]def search_for_keff(make_deck, run_mcnp, get_keff=get_keff, deck_args={}, initial_guess=None, target=1.0, bracket=None, tol=None, bracketed_method='bisect', print_iterations=False): """ Keff optimization search function. Parameters ---------- make_deck : collections.Callable Callable function which builds a deck according to a passed parameter. This function must return the name of an on-disk MCNP deck. Can be helpful to generate a unique name for each deck, like `my_deck.iteration#.mcnp`. run_mcnp : collections.Callable Callable function which executes an MCNP simulation. Must accept the name of an on-disk MCNP file. Recommended to run MCNP with the `N=input_name` convention to create outputs with recognizable names. get_keff : collections.Callable Callable function which retrieves a keff value. Must accept the name of an on-disk MCNP file. Recommended to run MCNP with the `N=input_name` convention to create outputs with recognizable names. Also recommended to generate an MCTAL file and use MCNPTools to extract keff values. deck_args : dict Keyword-based arguments to pass to the `make_deck` method. initial_guess : float Initial guess for keff. target : float Target value for keff. bracket : Iterable of float Lower and upper limits for bracketed search method. tol : float Absolute tolerance. bracketed_method : str Choice of bracketed methods. Valid option are `bisect`, `brentq`, `brenth`, and `ridder`. Names correspond to their SciPy functions. print_iterations : bool Whether to print information for each iteration. Returns ------- zero_value : float Value of the optimized parameter. guesses : list List of parameter guesses at each iteration. results : list List of keff result at each iteration. """ # 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['xtol'] = 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, make_deck, run_mcnp, get_keff, deck_args, print_iterations, guesses, results) # Perform the search zero_value = root_finder(**args) return zero_value, guesses, results