mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-29 06:35:48 -04:00
Merge remote-tracking branch 'upstream/develop' into openmoc-complex-regions
This commit is contained in:
commit
29e067b7b1
21 changed files with 786 additions and 124 deletions
|
|
@ -37,9 +37,8 @@ In order to be considered suitable for inclusion in the *develop* branch, the
|
|||
following criteria must be satisfied for all proposed changes:
|
||||
|
||||
- Changes have a clear purpose and are useful.
|
||||
- Compiles under all conditions (MPI, OpenMP, HDF5, etc.). This is checked as
|
||||
part of the test suite.
|
||||
- Passes the regression suite.
|
||||
- Compiles and passes the regression suite with all configurations (This is
|
||||
checked by Travis CI).
|
||||
- If appropriate, test cases are added to regression suite.
|
||||
- No memory leaks (checked with valgrind_).
|
||||
- Conforms to the OpenMC `style guide`_.
|
||||
|
|
@ -81,8 +80,7 @@ features and bug fixes. The general steps for contributing are as follows:
|
|||
|
||||
At a minimum, you should describe what the changes you've made are and why
|
||||
you are making them. If the changes are related to an oustanding issue, make
|
||||
sure it is cross-referenced. A wise developer would also check whether their
|
||||
changes do indeed pass the regression test suite.
|
||||
sure it is cross-referenced.
|
||||
|
||||
5. A trusted developer will review your pull request based on the criteria
|
||||
above. Any issues with the pull request can be discussed directly on the pull
|
||||
|
|
@ -104,7 +102,7 @@ full OpenMC code is executed. Results from simulations are compared with
|
|||
expected results. The test suite is comprised of many build configurations
|
||||
(e.g. debug, mpi, hdf5) and the actual tests which reside in sub-directories
|
||||
in the tests directory. We recommend to developers to test their branches
|
||||
before submitting a formal pull request using gfortran and intel compilers
|
||||
before submitting a formal pull request using gfortran and Intel compilers
|
||||
if available.
|
||||
|
||||
The test suite is designed to integrate with cmake using ctest_.
|
||||
|
|
@ -113,9 +111,9 @@ download these cross sections please do the following:
|
|||
|
||||
.. code-block:: sh
|
||||
|
||||
cd ../data
|
||||
python get_nndc_data.py
|
||||
export CROSS_SECTIONS=<path_to_data_folder>/nndc/cross_sections.xml
|
||||
cd ../scripts
|
||||
./openmc-get-nndc-data
|
||||
export OPENMC_CROSS_SECTIONS=<path_to_data_folder>/nndc_hdf5/cross_sections.xml
|
||||
|
||||
The test suite can be run on an already existing build using:
|
||||
|
||||
|
|
@ -137,21 +135,29 @@ more control over which tests are executed.
|
|||
Before running the test suite python script, the following environmental
|
||||
variables should be set if the default paths are incorrect:
|
||||
|
||||
* **FC** - The command of the Fortran compiler (e.g. gfotran, ifort).
|
||||
* **FC** - The command for a Fortran compiler (e.g. gfotran, ifort).
|
||||
|
||||
* Default - *gfortran*
|
||||
|
||||
* **CC** - The command for a C compiler (e.g. gcc, icc).
|
||||
|
||||
* Default - *gcc*
|
||||
|
||||
* **CXX** - The command for a C++ compiler (e.g. g++, icpc).
|
||||
|
||||
* Default - *g++*
|
||||
|
||||
* **MPI_DIR** - The path to the MPI directory.
|
||||
|
||||
* Default - */opt/mpich/3.1.3-gnu*
|
||||
* Default - */opt/mpich/3.2-gnu*
|
||||
|
||||
* **HDF5_DIR** - The path to the HDF5 directory.
|
||||
|
||||
* Default - */opt/hdf5/1.8.14-gnu*
|
||||
* Default - */opt/hdf5/1.8.16-gnu*
|
||||
|
||||
* **PHDF5_DIR** - The path to the parallel HDF5 directory.
|
||||
|
||||
* Default - */opt/phdf5/1.8.14-gnu*
|
||||
* Default - */opt/phdf5/1.8.16-gnu*
|
||||
|
||||
To run the full test suite, the following command can be executed in the
|
||||
tests directory:
|
||||
|
|
@ -192,15 +198,12 @@ a test you need to add the following files to your new test directory,
|
|||
*test_name* for example:
|
||||
|
||||
* OpenMC input XML files
|
||||
* **test_name.py** - python test driver script, please refer to other
|
||||
* **test_name.py** - Python test driver script, please refer to other
|
||||
tests to see how to construct. Any output files that are generated
|
||||
during testing must be removed at the end of this script.
|
||||
* **results.py** - python script that extracts results from statepoint
|
||||
output files. By default it should look for a binary file, but can
|
||||
take an argument to overwrite which statepoint file is processed,
|
||||
whether it is at a different batch or with an HDF5 extension. This
|
||||
script must output a results file that is named *results_test.dat*.
|
||||
It is recommended that any real numbers reported use *12.6E* format.
|
||||
* **inputs_true.dat** - ASCII file that contains Python API-generated XML
|
||||
files concatenated together. When the test is run, inputs that are
|
||||
generated are compared to this file.
|
||||
* **results_true.dat** - ASCII file that contains the expected results
|
||||
from the test. The file *results_test.dat* is compared to this file
|
||||
during the execution of the python test driver script. When the
|
||||
|
|
|
|||
|
|
@ -23,4 +23,5 @@ features via the :ref:`pythonapi`.
|
|||
mg-mode-part-iii
|
||||
mdgxs-part-i
|
||||
mdgxs-part-ii
|
||||
search
|
||||
nuclear-data
|
||||
|
|
|
|||
238
docs/source/examples/search.ipynb
Normal file
238
docs/source/examples/search.ipynb
Normal file
File diff suppressed because one or more lines are too long
13
docs/source/examples/search.rst
Normal file
13
docs/source/examples/search.rst
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
.. _notebook_search:
|
||||
|
||||
==================
|
||||
Criticality Search
|
||||
==================
|
||||
|
||||
.. only:: html
|
||||
|
||||
.. notebook:: search.ipynb
|
||||
|
||||
.. only:: latex
|
||||
|
||||
IPython notebooks must be viewed in the online HTML documentation.
|
||||
|
|
@ -183,45 +183,43 @@ Multi-Group Data
|
|||
|
||||
The data governing the interaction of particles with various nuclei or materials
|
||||
are represented using a multi-group library format specific to the OpenMC code.
|
||||
The format is described in the :ref:`mgxs_lib_spec`.
|
||||
The data itself can be prepared via traditional paths or directly from a
|
||||
continuous-energy OpenMC calculation by use of the Python API as is shown in the
|
||||
:ref:`notebook_mgxs_part_iv` example notebook. This multi-group
|
||||
library consists of meta-data (such as the energy group structure) and multiple
|
||||
`xsdata` objects which contains the required microscopic or macroscopic
|
||||
multi-group data.
|
||||
The format is described in the :ref:`mgxs_lib_spec`. The data itself can be
|
||||
prepared via traditional paths or directly from a continuous-energy OpenMC
|
||||
calculation by use of the Python API as is shown in the
|
||||
:ref:`notebook_mg_mode_part_i` example notebook. This multi-group library
|
||||
consists of meta-data (such as the energy group structure) and multiple `xsdata`
|
||||
objects which contains the required microscopic or macroscopic multi-group data.
|
||||
|
||||
At a minimum, the library must contain the absorption cross section
|
||||
(:math:`\sigma_{a,g}`) and a scattering matrix. If the problem is an eigenvalue
|
||||
problem then all fissionable materials must also contain either
|
||||
a fission production matrix cross section
|
||||
(:math:`\nu\sigma_{f,g\rightarrow g'}`), or
|
||||
both the fission spectrum data (:math:`\chi_{g'}`) and a fission production
|
||||
cross section (:math:`\nu\sigma_{f,g}`), or, . The library must also contain
|
||||
the fission cross section (:math:`\sigma_{f,g}`) or the fission energy release
|
||||
cross section (:math:`\kappa\sigma_{f,g}`) if the associated tallies are
|
||||
required by the model using the library.
|
||||
problem then all fissionable materials must also contain either a fission
|
||||
production matrix cross section (:math:`\nu\sigma_{f,g\rightarrow g'}`), or both
|
||||
the fission spectrum data (:math:`\chi_{g'}`) and a fission production cross
|
||||
section (:math:`\nu\sigma_{f,g}`), or, . The library must also contain the
|
||||
fission cross section (:math:`\sigma_{f,g}`) or the fission energy release cross
|
||||
section (:math:`\kappa\sigma_{f,g}`) if the associated tallies are required by
|
||||
the model using the library.
|
||||
|
||||
After a scattering collision, the outgoing particle experiences a change in both
|
||||
energy and angle. The probability of a particle resulting in a given outgoing
|
||||
energy group (`g'`) given a certain incoming energy group (`g`) is provided
|
||||
by the scattering matrix data. The angular information can be expressed either
|
||||
via Legendre expansion of the particle's change-in-angle (:math:`\mu`), a
|
||||
tabular representation of the probability distribution function of :math:`\mu`,
|
||||
or a histogram representation of the same PDF. The formats used to
|
||||
represent these are described in the :ref:`mgxs_lib_spec`.
|
||||
energy group (`g'`) given a certain incoming energy group (`g`) is provided by
|
||||
the scattering matrix data. The angular information can be expressed either via
|
||||
Legendre expansion of the particle's change-in-angle (:math:`\mu`), a tabular
|
||||
representation of the probability distribution function of :math:`\mu`, or a
|
||||
histogram representation of the same PDF. The formats used to represent these
|
||||
are described in the :ref:`mgxs_lib_spec`.
|
||||
|
||||
Unlike the continuous-energy mode, the multi-group mode does not explicitly
|
||||
track particles produced from scattering multiplication (i.e., :math:`(n,xn)`)
|
||||
reactions. These are instead accounted for by adjusting the weight of the
|
||||
particle after the collision such that the correct total weight is maintained.
|
||||
The weight adjustment factor is optionally provided by the `multiplicity` data
|
||||
which is required to be provided in the form of a group-wise matrix.
|
||||
This data is provided as a group-wise matrix since the probability of producing
|
||||
multiple particles in a scattering reaction depends on both the incoming energy,
|
||||
`g`, and the sampled outgoing energy, `g'`. This data represents the average
|
||||
number of particles emitted from a scattering reaction, given a scattering
|
||||
reaction has occurred:
|
||||
which is required to be provided in the form of a group-wise matrix. This data
|
||||
is provided as a group-wise matrix since the probability of producing multiple
|
||||
particles in a scattering reaction depends on both the incoming energy, `g`, and
|
||||
the sampled outgoing energy, `g'`. This data represents the average number of
|
||||
particles emitted from a scattering reaction, given a scattering reaction has
|
||||
occurred:
|
||||
|
||||
.. math::
|
||||
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ Constructing Tallies
|
|||
openmc.EnergyFunctionFilter
|
||||
openmc.Mesh
|
||||
openmc.Trigger
|
||||
openmc.TallyDerivative
|
||||
openmc.Tally
|
||||
openmc.Tallies
|
||||
|
||||
|
|
@ -172,6 +173,7 @@ Running OpenMC
|
|||
openmc.calculate_volumes
|
||||
openmc.plot_geometry
|
||||
openmc.plot_inline
|
||||
openmc.search_for_keff
|
||||
|
||||
Post-processing
|
||||
---------------
|
||||
|
|
@ -336,6 +338,19 @@ Functions
|
|||
openmc.model.create_triso_lattice
|
||||
openmc.model.pack_trisos
|
||||
|
||||
Model Container
|
||||
---------------
|
||||
|
||||
Classes
|
||||
+++++++
|
||||
|
||||
.. autosummary::
|
||||
:toctree: generated
|
||||
:nosignatures:
|
||||
:template: myclass.rst
|
||||
|
||||
openmc.model.Model
|
||||
|
||||
--------------------------------------------
|
||||
:mod:`openmc.data` -- Nuclear Data Interface
|
||||
--------------------------------------------
|
||||
|
|
@ -469,6 +484,28 @@ Functions
|
|||
openmc.data.endf.get_tab2_record
|
||||
openmc.data.endf.get_text_record
|
||||
|
||||
---------------------------------------------------------
|
||||
:mod:`openmc.openmoc_compatible` -- OpenMOC Compatibility
|
||||
---------------------------------------------------------
|
||||
|
||||
.. autosummary::
|
||||
:toctree: generated
|
||||
:nosignatures:
|
||||
:template: myfunction.rst
|
||||
|
||||
openmc.openmoc_compatible.get_openmoc_material
|
||||
openmc.openmoc_compatible.get_openmc_material
|
||||
openmc.openmoc_compatible.get_openmoc_surface
|
||||
openmc.openmoc_compatible.get_openmc_surface
|
||||
openmc.openmoc_compatible.get_openmoc_cell
|
||||
openmc.openmoc_compatible.get_openmc_cell
|
||||
openmc.openmoc_compatible.get_openmoc_universe
|
||||
openmc.openmoc_compatible.get_openmc_universe
|
||||
openmc.openmoc_compatible.get_openmoc_lattice
|
||||
openmc.openmoc_compatible.get_openmc_lattice
|
||||
openmc.openmoc_compatible.get_openmoc_geometry
|
||||
openmc.openmoc_compatible.get_openmc_geometry
|
||||
|
||||
.. _Jupyter: https://jupyter.org/
|
||||
.. _NumPy: http://www.numpy.org/
|
||||
.. _Codecademy: https://www.codecademy.com/tracks/python
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
.. _pythonapi_openmoc_compatible:
|
||||
|
||||
=====================
|
||||
OpenMOC Compatibility
|
||||
=====================
|
||||
|
||||
.. automodule:: openmc.openmoc_compatible
|
||||
:members:
|
||||
|
|
@ -87,6 +87,22 @@ be validated using the following command:
|
|||
|
||||
/opt/openmc/bin/openmc-validate-xml
|
||||
|
||||
--------------
|
||||
Physical Units
|
||||
--------------
|
||||
|
||||
Unless specified otherwise, all length quantities are assumed to be in units of
|
||||
centimeters, all energy quantities are assumed to be in electronvolts, and all
|
||||
time quantities are assumed to be in seconds.
|
||||
|
||||
======= ============ ======
|
||||
Measure Default unit Symbol
|
||||
======= ============ ======
|
||||
length centimeter cm
|
||||
energy electronvolt eV
|
||||
time second s
|
||||
======= ============ ======
|
||||
|
||||
--------------------------------------
|
||||
Settings Specification -- settings.xml
|
||||
--------------------------------------
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import warnings
|
||||
|
||||
from openmc.arithmetic import *
|
||||
from openmc.cell import *
|
||||
from openmc.mesh import *
|
||||
|
|
@ -28,3 +26,4 @@ from openmc.summary import *
|
|||
from openmc.particle_restart import *
|
||||
from openmc.mixin import *
|
||||
from openmc.plotter import *
|
||||
from openmc.search import *
|
||||
|
|
@ -289,9 +289,10 @@ class Cell(object):
|
|||
c3, s3 = cos(phi), sin(phi)
|
||||
c2, s2 = cos(theta), sin(theta)
|
||||
c1, s1 = cos(psi), sin(psi)
|
||||
return np.array([[c1*c2, c1*s2*s3 - c3*s1, s1*s3 + c1*c3*s2],
|
||||
[c2*s1, c1*c3 + s1*s2*s3, c3*s1*s2 - c1*s3],
|
||||
[-s2, c2*s3, c2*c3]])
|
||||
self._rotation_matrix = np.array([
|
||||
[c1*c2, c1*s2*s3 - c3*s1, s1*s3 + c1*c3*s2],
|
||||
[c2*s1, c1*c3 + s1*s2*s3, c3*s1*s2 - c1*s3],
|
||||
[-s2, c2*s3, c2*c3]])
|
||||
|
||||
@translation.setter
|
||||
def translation(self, translation):
|
||||
|
|
|
|||
|
|
@ -361,18 +361,25 @@ class Geometry(object):
|
|||
if not case_sensitive:
|
||||
name = name.lower()
|
||||
|
||||
all_cells = self.get_all_cells().values()
|
||||
cells = set()
|
||||
|
||||
for cell in all_cells:
|
||||
cell_fill_name = cell.fill.name
|
||||
if not case_sensitive:
|
||||
cell_fill_name = cell_fill_name.lower()
|
||||
for cell in self.get_all_cells().values():
|
||||
names = []
|
||||
if cell.fill_type in ('material', 'universe', 'lattice'):
|
||||
names.append(cell.fill.name)
|
||||
elif cell.fill_type == 'distribmat':
|
||||
for mat in cell.fill:
|
||||
if mat is not None:
|
||||
names.append(mat.name)
|
||||
|
||||
if cell_fill_name == name:
|
||||
cells.add(cell)
|
||||
elif not matching and name in cell_fill_name:
|
||||
cells.add(cell)
|
||||
for fill_name in names:
|
||||
if not case_sensitive:
|
||||
fill_name = fill_name.lower()
|
||||
|
||||
if fill_name == name:
|
||||
cells.add(cell)
|
||||
elif not matching and name in fill_name:
|
||||
cells.add(cell)
|
||||
|
||||
cells = list(cells)
|
||||
cells.sort(key=lambda x: x.id)
|
||||
|
|
|
|||
|
|
@ -980,7 +980,7 @@ class Materials(cv.CheckedList):
|
|||
:envvar:`OPENMC_CROSS_SECTIONS` environment variable will be used for
|
||||
continuous-energy calculations and
|
||||
:envvar:`OPENMC_MG_CROSS_SECTIONS` will be used for multi-group
|
||||
calculations to find the path to the XML cross section file.
|
||||
calculations to find the path to the HDF5 cross section file.
|
||||
multipole_library : str
|
||||
Indicates the path to a directory containing a windowed multipole
|
||||
cross section library. If it is not set, the
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
from .triso import *
|
||||
from .model import *
|
||||
|
|
|
|||
164
openmc/model/model.py
Normal file
164
openmc/model/model.py
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
import openmc
|
||||
from openmc.checkvalue import check_type
|
||||
|
||||
|
||||
class Model(object):
|
||||
"""OpenMC model container for the openmc.Geometry, openmc.Materials,
|
||||
openmc.Settings, openmc.Tallies, openmc.CMFD objects, and openmc.Plot
|
||||
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
|
||||
plots : openmc.Plots
|
||||
Plot 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
|
||||
plots : openmc.Plots
|
||||
Plot information
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, geometry, materials, settings, tallies=None, cmfd=None,
|
||||
plots=None):
|
||||
self.geometry = geometry
|
||||
self.materials = materials
|
||||
self.settings = settings
|
||||
if tallies:
|
||||
self.tallies = tallies
|
||||
else:
|
||||
self._tallies = openmc.Tallies()
|
||||
if cmfd:
|
||||
self.cmfd = cmfd
|
||||
else:
|
||||
self._cmfd = None
|
||||
if plots:
|
||||
self.plots = plots
|
||||
else:
|
||||
self.plots = openmc.Plots()
|
||||
|
||||
self.sp = None
|
||||
|
||||
@property
|
||||
def geometry(self):
|
||||
return self._geometry
|
||||
|
||||
@property
|
||||
def materials(self):
|
||||
return self._materials
|
||||
|
||||
@property
|
||||
def settings(self):
|
||||
return self._settings
|
||||
|
||||
@property
|
||||
def tallies(self):
|
||||
return self._tallies
|
||||
|
||||
@property
|
||||
def cmfd(self):
|
||||
return self._cmfd
|
||||
|
||||
@property
|
||||
def plots(self):
|
||||
return self._plots
|
||||
|
||||
@geometry.setter
|
||||
def geometry(self, geometry):
|
||||
check_type('geometry', geometry, openmc.Geometry)
|
||||
self._geometry = geometry
|
||||
|
||||
@materials.setter
|
||||
def materials(self, materials):
|
||||
check_type('materials', materials, openmc.Materials)
|
||||
self._materials = materials
|
||||
|
||||
@settings.setter
|
||||
def settings(self, settings):
|
||||
check_type('settings', settings, openmc.Settings)
|
||||
self._settings = settings
|
||||
|
||||
@tallies.setter
|
||||
def tallies(self, tallies):
|
||||
check_type('tallies', tallies, openmc.Tallies)
|
||||
self._tallies = tallies
|
||||
|
||||
@cmfd.setter
|
||||
def cmfd(self, cmfd):
|
||||
check_type('cmfd', cmfd, openmc.CMFD)
|
||||
self._cmfd = cmfd
|
||||
|
||||
@plots.setter
|
||||
def plots(self, plots):
|
||||
check_type('plots', plots, openmc.Plots)
|
||||
self._plots = plots
|
||||
|
||||
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()
|
||||
self.tallies.export_to_xml()
|
||||
if self.cmfd is not None:
|
||||
self.cmfd.export_to_xml()
|
||||
self.plots.export_to_xml()
|
||||
|
||||
def run(self, **kwargs):
|
||||
"""Creates the XML files, runs OpenMC, and loads the statepoint.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
**kwargs
|
||||
All keyword arguments are passed to openmc.run
|
||||
|
||||
Returns
|
||||
-------
|
||||
2-tuple of float
|
||||
k_combined from the statepoint
|
||||
|
||||
"""
|
||||
|
||||
self.export_to_xml()
|
||||
|
||||
return_code = openmc.run(**kwargs)
|
||||
|
||||
assert (return_code == 0), "OpenMC did not execute successfully"
|
||||
|
||||
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.{}.h5'.format(statepoint_batches))
|
||||
|
||||
return self.sp.k_combined
|
||||
|
||||
def close(self):
|
||||
"""Close the statepoint and summary files
|
||||
"""
|
||||
|
||||
if self.sp is not None:
|
||||
self.sp._f.close()
|
||||
self.sp.summary._f.close()
|
||||
|
|
@ -636,7 +636,8 @@ class Plot(object):
|
|||
subelement.text = ' '.join(str(x) for x in color)
|
||||
|
||||
if self._colors:
|
||||
for domain, color in self._colors.items():
|
||||
for domain, color in sorted(self._colors.items(),
|
||||
key=lambda x: x[0].id):
|
||||
subelement = ET.SubElement(element, "color")
|
||||
subelement.set("id", str(domain.id))
|
||||
if isinstance(color, string_types):
|
||||
|
|
|
|||
201
openmc/search.py
Normal file
201
openmc/search.py
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
from collections import Callable
|
||||
from numbers import Real
|
||||
|
||||
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,
|
||||
print_output, 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.
|
||||
print_output : bool
|
||||
Whether or not to print the OpenMC output during the iterations.
|
||||
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
|
||||
keff = model.run(output=print_output)
|
||||
|
||||
# Close the model to ensure HDF5 will allow access during the next
|
||||
# OpenMC execution
|
||||
model.close()
|
||||
|
||||
# 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[0], keff[1]))
|
||||
|
||||
return (keff[0] - 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,
|
||||
print_output=False, **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.
|
||||
print_output : bool
|
||||
Whether or not to print the OpenMC output during the iterations.
|
||||
Defaults to False.
|
||||
**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)
|
||||
cv.check_type('print_output', print_output, bool)
|
||||
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)
|
||||
|
||||
import scipy.optimize as sopt
|
||||
|
||||
# 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,
|
||||
print_output, 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
|
||||
|
|
@ -54,7 +54,8 @@ class PolarAzimuthal(UnitSphere):
|
|||
"""Angular distribution represented by polar and azimuthal angles
|
||||
|
||||
This distribution allows one to specify the distribution of the cosine of
|
||||
the polar angle and the azimuthal angle independently of once another.
|
||||
the polar angle and the azimuthal angle independently of one another. The
|
||||
polar angle is measured relative to the reference angle.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
|
|||
|
|
@ -23,24 +23,24 @@ class TallyDerivative(EqualityMixin):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
derivative_id : Integral, optional
|
||||
derivative_id : int, optional
|
||||
Unique identifier for the tally derivative. If none is specified, an
|
||||
identifier will automatically be assigned
|
||||
variable : str, optional
|
||||
Accepted values are 'density', 'nuclide_density', and 'temperature'
|
||||
material : Integral, optional
|
||||
The perturubed material ID
|
||||
material : int, optional
|
||||
The perturbed material ID
|
||||
nuclide : str, optional
|
||||
The perturbed nuclide. Only needed for 'nuclide_density' derivatives.
|
||||
Ex: 'Xe135'
|
||||
|
||||
Attributes
|
||||
----------
|
||||
id : Integral
|
||||
id : int
|
||||
Unique identifier for the tally derivative
|
||||
variable : str
|
||||
Accepted values are 'density', 'nuclide_density', and 'temperature'
|
||||
material : Integral
|
||||
material : int
|
||||
The perturubed material ID
|
||||
nuclide : str
|
||||
The perturbed nuclide. Only needed for 'nuclide_density' derivatives.
|
||||
|
|
|
|||
|
|
@ -246,9 +246,9 @@ class VolumeCalculation(object):
|
|||
results = type(self).from_hdf5(filename)
|
||||
|
||||
# Make sure properties match
|
||||
assert self.domains == results.domains
|
||||
assert self.lower_left == results.lower_left
|
||||
assert self.upper_right == results.upper_right
|
||||
assert self.ids == results.ids
|
||||
assert np.all(self.lower_left == results.lower_left)
|
||||
assert np.all(self.upper_right == results.upper_right)
|
||||
|
||||
# Copy results
|
||||
self.volumes = results.volumes
|
||||
|
|
|
|||
|
|
@ -3,30 +3,24 @@
|
|||
from __future__ import division, print_function
|
||||
import struct
|
||||
import sys
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import numpy as np
|
||||
import h5py
|
||||
|
||||
def parse_options():
|
||||
"""Process command line arguments"""
|
||||
|
||||
from optparse import OptionParser
|
||||
usage = r"""%prog [options] <voxel_file>"""
|
||||
p = OptionParser(usage=usage)
|
||||
p.add_option('-o', '--output', action='store', dest='output',
|
||||
default='plot', help='Path to output SILO or VTK file.')
|
||||
p.add_option('-v', '--vtk', action='store_true', dest='vtk',
|
||||
default=False, help='Flag to convert to VTK instead of SILO.')
|
||||
parsed = p.parse_args()
|
||||
if not parsed[1]:
|
||||
p.print_help()
|
||||
return parsed
|
||||
return parsed
|
||||
def main():
|
||||
# Process command line arguments
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('voxel_file', help='Path to voxel file')
|
||||
parser.add_argument('-o', '--output', action='store',
|
||||
default='plot', help='Path to output SILO or VTK file.')
|
||||
parser.add_argument('-s', '--silo', action='store_true',
|
||||
default=False, help='Flag to convert to SILO instead of VTK.')
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
def main(filename, o):
|
||||
# Read data from voxel file
|
||||
fh = h5py.File(filename, 'r')
|
||||
fh = h5py.File(args.voxel_file, 'r')
|
||||
dimension = fh.attrs['num_voxels']
|
||||
width = fh.attrs['voxel_width']
|
||||
lower_left = fh.attrs['lower_left']
|
||||
|
|
@ -35,14 +29,8 @@ def main(filename, o):
|
|||
nx, ny, nz = dimension
|
||||
upper_right = lower_left + width*dimension
|
||||
|
||||
if o.vtk:
|
||||
try:
|
||||
import vtk
|
||||
except:
|
||||
print('The vtk python bindings do not appear to be installed '
|
||||
'properly.\nOn Ubuntu: sudo apt install python-vtk\n'
|
||||
'See: http://www.vtk.org/')
|
||||
return
|
||||
if not args.silo:
|
||||
import vtk
|
||||
|
||||
grid = vtk.vtkImageData()
|
||||
grid.SetDimensions(nx+1, ny+1, nz+1)
|
||||
|
|
@ -53,12 +41,12 @@ def main(filename, o):
|
|||
data.SetName("id")
|
||||
data.SetNumberOfTuples(nx*ny*nz)
|
||||
for x in range(nx):
|
||||
sys.stdout.write(" {0}%\r".format(int(x/nx*100)))
|
||||
sys.stdout.write(" {}%\r".format(int(x/nx*100)))
|
||||
sys.stdout.flush()
|
||||
for y in range(ny):
|
||||
for z in range(nz):
|
||||
i = z*nx*ny + y*nx + x
|
||||
data.SetValue(i, voxel_data[x,y,z])
|
||||
data.SetValue(i, voxel_data[x, y, z])
|
||||
grid.GetCellData().AddArray(data)
|
||||
|
||||
writer = vtk.vtkXMLImageDataWriter()
|
||||
|
|
@ -66,31 +54,27 @@ def main(filename, o):
|
|||
writer.SetInputData(grid)
|
||||
else:
|
||||
writer.SetInput(grid)
|
||||
if not o.output.endswith(".vti"):
|
||||
o.output += ".vti"
|
||||
writer.SetFileName(o.output)
|
||||
if not args.output.endswith(".vti"):
|
||||
args.output += ".vti"
|
||||
writer.SetFileName(args.output)
|
||||
writer.Write()
|
||||
|
||||
else:
|
||||
try:
|
||||
import silomesh
|
||||
except:
|
||||
print('The silomesh package does not appear to be installed '
|
||||
'properly.\nSee: https://github.com/nhorelik/silomesh/')
|
||||
return
|
||||
if not o.output.endswith(".silo"):
|
||||
o.output += ".silo"
|
||||
silomesh.init_silo(o.output)
|
||||
import silomesh
|
||||
|
||||
if not args.output.endswith(".silo"):
|
||||
args.output += ".silo"
|
||||
silomesh.init_silo(args.output)
|
||||
meshparams = list(map(int, dimension)) + list(map(float, lower_left)) + \
|
||||
list(map(float, upper_right))
|
||||
silomesh.init_mesh('plot', *meshparams)
|
||||
silomesh.init_var("id")
|
||||
for x in range(nx):
|
||||
sys.stdout.write(" {0}%\r".format(int(x/nx*100)))
|
||||
sys.stdout.write(" {}%\r".format(int(x/nx*100)))
|
||||
sys.stdout.flush()
|
||||
for y in range(ny):
|
||||
for z in range(nz):
|
||||
silomesh.set_value(float(voxel_data[x,y,z]),
|
||||
silomesh.set_value(float(voxel_data[x, y, z]),
|
||||
x + 1, y + 1, z + 1)
|
||||
print()
|
||||
silomesh.finalize_var()
|
||||
|
|
@ -99,6 +83,4 @@ def main(filename, o):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
(options, args) = parse_options()
|
||||
if args:
|
||||
main(args[0], options)
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ parser.add_option("-s", "--script", action="store_true", dest="script",
|
|||
# Default compiler paths
|
||||
FC='gfortran'
|
||||
CC='gcc'
|
||||
CXX='g++'
|
||||
MPI_DIR='/opt/mpich/3.2-gnu'
|
||||
HDF5_DIR='/opt/hdf5/1.8.16-gnu'
|
||||
PHDF5_DIR='/opt/phdf5/1.8.16-gnu'
|
||||
|
|
@ -55,6 +56,8 @@ if 'FC' in os.environ:
|
|||
FC = os.environ['FC']
|
||||
if 'CC' in os.environ:
|
||||
CC = os.environ['CC']
|
||||
if 'CXX' in os.environ:
|
||||
CXX = os.environ['CXX']
|
||||
if 'MPI_DIR' in os.environ:
|
||||
MPI_DIR = os.environ['MPI_DIR']
|
||||
if 'HDF5_DIR' in os.environ:
|
||||
|
|
@ -162,9 +165,11 @@ class Test(object):
|
|||
else:
|
||||
self.fc = os.path.join(MPI_DIR, 'bin', 'mpif90')
|
||||
self.cc = os.path.join(MPI_DIR, 'bin', 'mpicc')
|
||||
self.cxx = os.path.join(MPI_DIR, 'bin', 'mpicxx')
|
||||
else:
|
||||
self.fc = FC
|
||||
self.cc = CC
|
||||
self.cxx = CXX
|
||||
|
||||
# Sets the build name that will show up on the CDash
|
||||
def get_build_name(self):
|
||||
|
|
@ -195,6 +200,7 @@ class Test(object):
|
|||
def run_ctest_script(self):
|
||||
os.environ['FC'] = self.fc
|
||||
os.environ['CC'] = self.cc
|
||||
os.environ['CXX'] = self.cxx
|
||||
if self.mpi:
|
||||
os.environ['MPI_DIR'] = MPI_DIR
|
||||
if self.phdf5:
|
||||
|
|
@ -210,6 +216,7 @@ class Test(object):
|
|||
def run_cmake(self):
|
||||
os.environ['FC'] = self.fc
|
||||
os.environ['CC'] = self.cc
|
||||
os.environ['CXX'] = self.cxx
|
||||
if self.mpi:
|
||||
os.environ['MPI_DIR'] = MPI_DIR
|
||||
if self.phdf5:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue