Merge pull request #1118 from paulromano/data-updates

Allow WMP in cross_sections.xml, other data updates
This commit is contained in:
Jingang Liang 2018-11-14 12:06:03 -05:00 committed by GitHub
commit a73b328ffd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
79 changed files with 1377 additions and 1330 deletions

View file

@ -15,11 +15,12 @@ addons:
- libhdf5-mpich-dev
- libblas-dev
- liblapack-dev
config:
retries: true
cache:
directories:
- $HOME/nndc_hdf5
- $HOME/endf-b-vii.1
- $HOME/WMP_Library
env:
global:
- FC=gfortran
@ -28,7 +29,6 @@ env:
- OMP_NUM_THREADS=2
- OPENMC_CROSS_SECTIONS=$HOME/nndc_hdf5/cross_sections.xml
- OPENMC_ENDF_DATA=$HOME/endf-b-vii.1
- OPENMC_MULTIPOLE_LIBRARY=$HOME/WMP_Library
- LD_LIBRARY_PATH=$HOME/MOAB/lib:$HOME/DAGMC/lib
- PATH=$PATH:$HOME/NJOY2016/build
- DISPLAY=:99.0
@ -39,7 +39,7 @@ env:
- OMP=n MPI=y PHDF5=n
- OMP=n MPI=y PHDF5=y
- OMP=n MPI=y PHDF5=y DAGMC=y
- OMP=y MPI=y PHDF5=y DAGMC=y
- OMP=y MPI=y PHDF5=y DAGMC=y
notifications:
webhooks: https://coveralls.io/webhook?repo_token=$COVERALLS_REPO_TOKEN
install:

View file

@ -384,6 +384,7 @@ add_library(libopenmc SHARED
src/dagmc.cpp
src/cell.cpp
src/cmfd_execute.cpp
src/cross_sections.cpp
src/distribution.cpp
src/distribution_angle.cpp
src/distribution_energy.cpp
@ -425,7 +426,7 @@ add_library(libopenmc SHARED
src/simulation.cpp
src/source.cpp
src/state_point.cpp
src/string_functions.cpp
src/string_utils.cpp
src/summary.cpp
src/surface.cpp
src/tallies/filter.cpp

View file

@ -5,7 +5,6 @@ ENV FC=/usr/bin/mpif90 CC=/usr/bin/mpicc CXX=/usr/bin/mpicxx \
PATH=/opt/openmc/bin:/opt/NJOY2016/build:$PATH \
LD_LIBRARY_PATH=/opt/openmc/lib:$LD_LIBRARY_PATH \
OPENMC_CROSS_SECTIONS=/root/nndc_hdf5/cross_sections.xml \
OPENMC_MULTIPOLE_LIBRARY=/root/WMP_Library \
OPENMC_ENDF_DATA=/root/endf-b-vii.1
# Install dependencies from Debian package manager
@ -36,4 +35,4 @@ RUN git clone https://github.com/openmc-dev/openmc.git /opt/openmc && \
cd .. && pip install -e .[test]
# Download cross sections (NNDC and WMP) and ENDF data needed by test suite
RUN ./opt/openmc/tools/ci/download-xs.sh
RUN ./opt/openmc/tools/ci/download-xs.sh

View file

@ -333,12 +333,14 @@ Functions
:return: Return status (negative if an error occurred)
:rtype: int
.. c:function:: int openmc_material_set_density(int32_t index, double density)
.. c:function:: int openmc_material_set_density(int32_t index, double density, const char* units)
Set the density of a material.
:param int32_t index: Index in the materials array
:param double density: Density of the material in atom/b-cm
:param double density: Density of the material
:param units: Units for density
:type units: const char*
:return: Return status (negative if an error occurs)
:rtype: int

View file

@ -30,11 +30,11 @@ or using pip (recommended)::
pip install -e .[test]
It is also assumed that you have cross section data available that is pointed to
by the :envvar:`OPENMC_CROSS_SECTIONS` and :envvar:`OPENMC_MULTIPOLE_LIBRARY`
environment variables. Furthermore, to run unit tests for the :mod:`openmc.data`
module, it is necessary to have ENDF/B-VII.1 data available and pointed to by
the :envvar:`OPENMC_ENDF_DATA` environment variable. All data sources can be
obtained using the ``tools/ci/travis-before-script.sh`` script.
by the :envvar:`OPENMC_CROSS_SECTIONS` environment variables. Furthermore, to
run unit tests for the :mod:`openmc.data` module, it is necessary to have
ENDF/B-VII.1 data available and pointed to by the :envvar:`OPENMC_ENDF_DATA`
environment variable. All data sources can be obtained using the
``tools/ci/travis-before-script.sh`` script.
To execute the test suite, go to the ``tests/`` directory and run::

View file

@ -25,9 +25,10 @@ node. For example,
``<library>`` Element
---------------------
The ``<library>`` element indicates where an HDF5 cross section file is located,
whether it contains incident neutron or thermal scattering data, and what
materials are listed within. It has the following attributes:
The ``<library>`` element indicates where an HDF5 data file is located, whether
it contains incident neutron, incident photon, thermal scattering, or windowed
multipole data, and what materials are listed within. It has the following
attributes:
:materials:
@ -48,4 +49,5 @@ materials are listed within. It has the following attributes:
directory containing the ``cross_sections.xml`` file.
:type:
The type of data contained in the file, either 'neutron' or 'thermal'.
The type of data contained in the file. Accepted values are 'neutron',
'thermal', 'photon', and 'wmp'.

View file

@ -18,21 +18,6 @@ path to the XML cross section listing when in continuous-energy mode, and the
:envvar:`OPENMC_MG_CROSS_SECTIONS` environment variable will be used in
multi-group mode.
.. _multipole_library:
-------------------------------
``<multipole_library>`` Element
-------------------------------
The ``<multipole_library>`` element indicates the directory containing a
windowed multipole library. If a windowed multipole library is available,
OpenMC can use it for on-the-fly Doppler-broadening of resolved resonance range
cross sections. If this element is absent from the settings.xml file, the
:envvar:`OPENMC_MULTIPOLE_LIBRARY` environment variable will be used.
.. note:: The <temperature_multipole> element must also be set to "true" for
windowed multipole functionality.
.. _material:
----------------------

View file

@ -41,11 +41,6 @@ following environment variables are used:
user has not specified :attr:`Materials.cross_sections` (equivalently, the
:ref:`cross_sections` in :ref:`materials.xml <io_materials>`).
:envvar:`OPENMC_MULTIPOLE_LIBRARY`
Indicates the path to a directory containing windowed multipole data if the
user has not specified :attr:`Materials.multipole_library` (equivalently, the
:ref:`multipole_library` in :ref:`materials.xml <io_materials>`)
:envvar:`OPENMC_MG_CROSS_SECTIONS`
Indicates the path to the an :ref:`HDF5 file <io_mgxs_library>` that contains
multi-group cross sections if the user has not specified
@ -306,12 +301,12 @@ Windowed Multipole Data
-----------------------
OpenMC is capable of using windowed multipole data for on-the-fly Doppler
broadening. While such data is not yet available for all nuclides, an
experimental multipole library is available that contains data for 70
nuclides. To obtain this library, you can run :ref:`scripts_multipole` which
will download and extract it into a ``wmp`` directory. Once the library has been
downloaded, set the :envvar:`OPENMC_MULTIPOLE_LIBRARY` environment variable (or
the :attr:`Materials.multipole_library` attribute) to the ``wmp`` directory.
broadening. A comprehensive multipole data library containing all nuclides in
ENDF/B-VII.1 is available on `GitHub
<https://github.com/mit-crpg/WMP_Library>`_. To obtain this library, download
and unpack an archive (.zip or .tag.gz) from GitHub. Once unpacked, you can use
the :class:`openmc.data.DataLibrary` class to register the .h5 files as
described in :ref:`create_xs_library`.
--------------------------
Multi-Group Cross Sections

View file

@ -149,17 +149,6 @@ the following optional arguments:
and processing the data may require as much as 40 GB of additional
free disk space.
.. _scripts_multipole:
-----------------------------
``openmc-get-multipole-data``
-----------------------------
This script downloads and extracts windowed multipole data based on
ENDF/B-VII.1. It has the following optional arguments:
-b, --batch Suppress standard in
.. _scripts_nndc:
------------------------

File diff suppressed because one or more lines are too long

View file

@ -60,7 +60,7 @@ extern "C" {
int openmc_material_get_id(int32_t index, int32_t* id);
int openmc_material_get_fissionable(int32_t index, bool* fissionable);
int openmc_material_get_volume(int32_t index, double* volume);
int openmc_material_set_density(int32_t index, double density);
int openmc_material_set_density(int32_t index, double density, const char* units);
int openmc_material_set_densities(int32_t index, int n, const char** name, const double* density);
int openmc_material_set_id(int32_t index, int32_t id);
int openmc_material_set_volume(int32_t index, double volume);

View file

@ -25,7 +25,7 @@ constexpr int VERSION_RELEASE {0};
constexpr std::array<int, 3> VERSION {VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE};
// HDF5 data format
constexpr int HDF5_VERSION[] {1, 0};
constexpr int HDF5_VERSION[] {2, 0};
// Version numbers for binary files
constexpr std::array<int, 2> VERSION_PARTICLE_RESTART {2, 0};

View file

@ -0,0 +1,67 @@
#ifndef OPENMC_CROSS_SECTIONS_H
#define OPENMC_CROSS_SECTIONS_H
#include "pugixml.hpp"
#include <string>
#include <map>
#include <vector>
namespace openmc {
//==============================================================================
// Library class
//==============================================================================
class Library {
public:
// Types, enums
enum class Type {
neutron = 1, photon = 3, thermal = 2, multigroup = 4, wmp = 5
};
// Constructors
Library() { };
Library(pugi::xml_node node, const std::string& directory);
// Comparison operator (for using in map)
bool operator<(const Library& other) {
return path_ < other.path_;
}
// Data members
Type type_; //!< Type of data library
std::vector<std::string> materials_; //!< Materials contained in library
std::string path_; //!< File path to library
};
using LibraryKey = std::pair<Library::Type, std::string>;
//==============================================================================
// Global variable declarations
//==============================================================================
namespace data {
//!< Data libraries
extern std::vector<Library> libraries;
//! Maps (type, name) to index in libraries
extern std::map<LibraryKey, std::size_t> library_map;
} // namespace data
//==============================================================================
// Non-member functions
//==============================================================================
//! Read cross sections file (either XML or multigroup H5) and populate data
//! libraries
extern "C" void read_cross_sections_xml();
//! Read cross_sections.xml and populate data libraries
void read_ce_cross_sections_xml();
} // namespace openmc
#endif // OPENMC_CROSS_SECTIONS_H

View file

@ -52,7 +52,6 @@ extern "C" bool dagmc; //!< indicator of DAGMC geometry
// Paths to various files
extern std::string path_cross_sections; //!< path to cross_sections.xml
extern std::string path_input; //!< directory where main .xml files resides
extern std::string path_multipole; //!< directory containing multipole files
extern std::string path_output; //!< directory where output files are written
extern std::string path_particle_restart; //!< path to a particle restart file
extern std::string path_source;
@ -62,7 +61,7 @@ extern std::string path_statepoint; //!< path to a statepoint file
extern "C" int32_t index_entropy_mesh; //!< Index of entropy mesh in global mesh array
extern "C" int32_t index_ufs_mesh; //!< Index of UFS mesh in global mesh array
extern "C" int32_t index_cmfd_mesh; //!< Index of CMFD mesh in global mesh array
extern "C" int32_t n_batches; //!< number of (inactive+active) batches
extern "C" int32_t n_inactive; //!< number of inactive batches
extern "C" int32_t gen_per_batch; //!< number of generations per batch
@ -77,6 +76,7 @@ extern "C" int n_max_batches; //!< Maximum number of batches
extern "C" int res_scat_method; //!< resonance upscattering method
extern "C" double res_scat_energy_min; //!< Min energy in [eV] for res. upscattering
extern "C" double res_scat_energy_max; //!< Max energy in [eV] for res. upscattering
extern std::vector<std::string> res_scat_nuclides; //!< Nuclides using res. upscattering treatment
extern "C" int run_mode; //!< Run mode (eigenvalue, fixed src, etc.)
extern std::unordered_set<int> sourcepoint_batch; //!< Batches when source should be written
extern std::unordered_set<int> statepoint_batch; //!< Batches when state should be written

View file

@ -1,20 +0,0 @@
//! \file string_functions.h
//! A collection of helper routines for C-strings and STL strings
#ifndef OPENMC_STRING_FUNCTIONS_H
#define OPENMC_STRING_FUNCTIONS_H
#include <string>
namespace openmc {
std::string& strtrim(std::string& s);
char* strtrim(char* c_str);
void to_lower(std::string& str);
int word_count(std::string const& str);
} // namespace openmc
#endif // STRING_FUNCTIONS_H

View file

@ -1,42 +1,24 @@
#ifndef OPENMC_STRING_UTILS_H
#define OPENMC_STRING_UTILS_H
#include <algorithm>
#include <string>
#include <vector>
namespace openmc {
inline std::vector<std::string>
split(const std::string& in)
{
std::vector<std::string> out;
std::string& strtrim(std::string& s);
for (int i = 0; i < in.size(); ) {
// Increment i until we find a non-whitespace character.
if (std::isspace(in[i])) {
i++;
char* strtrim(char* c_str);
} else {
// Find the next whitespace character at j.
int j = i + 1;
while (j < in.size() && std::isspace(in[j]) == 0) {j++;}
void to_lower(std::string& str);
// Push-back everything between i and j.
out.push_back(in.substr(i, j-i));
i = j + 1; // j is whitespace so leapfrog to j+1
}
}
int word_count(std::string const& str);
return out;
}
std::vector<std::string> split(const std::string& in);
inline bool
ends_with(const std::string& value, const std::string& ending)
{
if (ending.size() > value.size()) return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
bool ends_with(const std::string& value, const std::string& ending);
bool starts_with(const std::string& value, const std::string& beginning);
} // namespace openmc
#endif // OPENMC_STRING_UTILS_H

View file

@ -53,11 +53,6 @@ to locate HDF5 format cross section libraries if the user has not specified the
Indicates the default path to an HDF5 file that contains multi-group cross
section libraries if the user has not specified the <cross_sections> tag in
.I materials.xml\fP.
.TP
.B OPENMC_MULTIPOLE_LIBRARY
Indicates the default path to a directory containing windowed multipole data if
the user has not specified the <multipole_library> tag in
.I materials.xml\fP.
.SH LICENSE
Copyright \(co 2011-2018 Massachusetts Institute of Technology and OpenMC
contributors.

View file

@ -1,3 +1,4 @@
import hashlib
import os.path
from pathlib import Path
from urllib.parse import urlparse
@ -6,13 +7,15 @@ from urllib.request import urlopen
_BLOCK_SIZE = 16384
def download(url):
def download(url, checksum=None):
"""Download file from a URL
Parameters
----------
url : str
URL from which to download
checksum : str or None
MD5 checksum to check against
Returns
-------
@ -46,4 +49,13 @@ def download(url):
downloaded, downloaded * 100. / file_size)
print(status + '\b'*len(status), end='')
print('')
if checksum is not None:
downloadsum = hashlib.md5(open(basename, 'rb').read()).hexdigest()
if downloadsum != checksum:
raise IOError("MD5 checksum for {} does not match. If this is your first "
"time receiving this message, please re-run the script. "
"Otherwise, please contact OpenMC developers by emailing "
"openmc-users@googlegroups.com.".format(basename))
return basename

View file

@ -35,7 +35,7 @@ _dll.openmc_material_get_densities.errcheck = _error_handler
_dll.openmc_material_get_volume.argtypes = [c_int32, POINTER(c_double)]
_dll.openmc_material_get_volume.restype = c_int
_dll.openmc_material_get_volume.errcheck = _error_handler
_dll.openmc_material_set_density.argtypes = [c_int32, c_double]
_dll.openmc_material_set_density.argtypes = [c_int32, c_double, c_char_p]
_dll.openmc_material_set_density.restype = c_int
_dll.openmc_material_set_density.errcheck = _error_handler
_dll.openmc_material_set_densities.argtypes = [
@ -178,16 +178,18 @@ class Material(_FortranObjectWithID):
"""
_dll.openmc_material_add_nuclide(self._index, name.encode(), density)
def set_density(self, density):
def set_density(self, density, units='atom/b-cm'):
"""Set density of a material.
Parameters
----------
density : float
Density in atom/b-cm
Density
units : {'atom/b-cm', 'g/cm3'}
Units for density
"""
_dll.openmc_material_set_density(self._index, density)
_dll.openmc_material_set_density(self._index, density, units.encode())
def set_densities(self, nuclides, densities):
"""Set the densities of a list of nuclides in a material

View file

@ -1,5 +1,5 @@
# Version of HDF5 nuclear data format
HDF5_VERSION_MAJOR = 1
HDF5_VERSION_MAJOR = 2
HDF5_VERSION_MINOR = 0
HDF5_VERSION = (HDF5_VERSION_MAJOR, HDF5_VERSION_MINOR)

View file

@ -106,7 +106,7 @@ def ascii_to_binary(ascii_file, binary_file):
"""
# Open ASCII file
ascii = open(ascii_file, 'r')
ascii = open(str(ascii_file), 'r')
# Set default record length
record_length = 4096
@ -116,7 +116,7 @@ def ascii_to_binary(ascii_file, binary_file):
ascii.close()
# Open binary file
binary = open(binary_file, 'wb')
binary = open(str(binary_file), 'wb')
idx = 0
@ -228,8 +228,9 @@ class Library(EqualityMixin):
self.tables = []
# Determine whether file is ASCII or binary
filename = str(filename)
try:
fh = open(str(filename), 'rb')
fh = open(filename, 'rb')
# Grab 10 lines of the library
sb = b''.join([fh.readline() for i in range(10)])

View file

@ -348,7 +348,7 @@ def get_evaluations(filename):
"""
evaluations = []
with open(filename, 'r') as fh:
with open(str(filename), 'r') as fh:
while True:
pos = fh.tell()
line = fh.readline()

View file

@ -279,11 +279,11 @@ class FissionEnergyRelease(EqualityMixin):
# the delayed neutron fraction is so small that the difference
# is negligible. MT=18 (n, fission) might not be available so
# try MT=19 (n, f) as well.
if 18 in incident_neutron.reactions:
if 18 in incident_neutron and not incident_neutron[18].redundant:
nu = [p.yield_ for p in incident_neutron[18].products
if p.particle == 'neutron'
and p.emission_mode in ('prompt', 'total')]
elif 19 in incident_neutron.reactions:
elif 19 in incident_neutron:
nu = [p.yield_ for p in incident_neutron[19].products
if p.particle == 'neutron'
and p.emission_mode in ('prompt', 'total')]

View file

@ -518,7 +518,7 @@ class Sum(EqualityMixin):
"""
def __init__(self, functions):
self.functions = functions
self.functions = list(functions)
def __call__(self, x):
return sum(f(x) for f in self.functions)

View file

@ -52,17 +52,13 @@ class DataLibrary(EqualityMixin):
Path to the file to be registered.
"""
with h5py.File(filename, 'r') as h5file:
# Support pathlib
# TODO: Remove when support is Python 3.6+ only
filename = str(filename)
materials = []
if 'filetype' in h5file.attrs:
filetype = h5file.attrs['filetype'].decode().lstrip('data_')
else:
filetype = 'neutron'
for name in h5file:
if name.startswith('c_'):
filetype = 'thermal'
materials.append(name)
with h5py.File(filename, 'r') as h5file:
filetype = h5file.attrs['filetype'].decode()[5:]
materials = list(h5file)
library = {'path': filename, 'type': filetype, 'materials': materials}
self.libraries.append(library)
@ -84,7 +80,7 @@ class DataLibrary(EqualityMixin):
if common_dir == '':
common_dir = '.'
if os.path.relpath(common_dir, os.path.dirname(path)) != '.':
if os.path.relpath(common_dir, os.path.dirname(str(path))) != '.':
dir_element = ET.SubElement(root, "directory")
dir_element.text = os.path.realpath(common_dir)
@ -99,7 +95,7 @@ class DataLibrary(EqualityMixin):
# Write XML file
tree = ET.ElementTree(root)
tree.write(path, xml_declaration=True, encoding='utf-8',
tree.write(str(path), xml_declaration=True, encoding='utf-8',
method='xml')
@classmethod
@ -131,7 +127,9 @@ class DataLibrary(EqualityMixin):
raise ValueError("Either path or OPENMC_CROSS_SECTIONS "
"environmental variable must be set")
check_type('path', path, str)
# Convert to string to support pathlib
# TODO: Remove when support is Python 3.6+ only
path = str(path)
tree = ET.parse(path)
root = tree.getroot()

View file

@ -333,7 +333,7 @@ class WindowedMultipole(EqualityMixin):
if isinstance(group_or_filename, h5py.Group):
group = group_or_filename
else:
h5file = h5py.File(group_or_filename, 'r')
h5file = h5py.File(str(group_or_filename), 'r')
# Make sure version matches
if 'version' in h5file.attrs:
@ -515,7 +515,7 @@ class WindowedMultipole(EqualityMixin):
"""
# Open file and write version.
with h5py.File(path, mode, libver=libver) as f:
with h5py.File(str(path), mode, libver=libver) as f:
f.attrs['filetype'] = np.string_('data_wmp')
f.attrs['version'] = np.array(WMP_VERSION)

View file

@ -2,7 +2,6 @@ import sys
from collections import OrderedDict
from collections.abc import Iterable, Mapping, MutableMapping
from io import StringIO
from itertools import chain
from math import log10
from numbers import Integral, Real
import os
@ -86,9 +85,6 @@ class IncidentNeutron(EqualityMixin):
Resonance parameters
resonance_covariance : openmc.data.ResonanceCovariance or None
Covariance for resonance parameters
redundant_reactions : collections.OrderedDict
Contains redundant cross sections, e.g., the total cross section. The keys
are the MT values and the values are Reaction objects.
temperatures : list of str
List of string representations the temperatures of the target nuclide
in the data set. The temperatures are strings of the temperature,
@ -113,18 +109,15 @@ class IncidentNeutron(EqualityMixin):
self.energy = {}
self._fission_energy = None
self.reactions = OrderedDict()
self.redundant_reactions = OrderedDict()
self._urr = {}
self._resonances = None
def __contains__(self, mt):
return mt in self.reactions or mt in self.redundant_reactions
return mt in self.reactions
def __getitem__(self, mt):
if mt in self.reactions:
return self.reactions[mt]
elif mt in self.redundant_reactions:
return self.redundant_reactions[mt]
else:
raise KeyError('No reaction with MT={}.'.format(mt))
@ -170,10 +163,6 @@ class IncidentNeutron(EqualityMixin):
def resonance_covariance(self):
return self._resonance_covariance
@property
def redundant_reactions(self):
return self._redundant_reactions
@property
def urr(self):
return self._urr
@ -237,11 +226,6 @@ class IncidentNeutron(EqualityMixin):
res_cov.ResonanceCovariances)
self._resonance_covariance = resonance_covariance
@redundant_reactions.setter
def redundant_reactions(self, redundant_reactions):
cv.check_type('redundant reactions', redundant_reactions, Mapping)
self._redundant_reactions = redundant_reactions
@urr.setter
def urr(self, urr):
cv.check_type('probability table dictionary', urr, MutableMapping)
@ -288,7 +272,7 @@ class IncidentNeutron(EqualityMixin):
self.energy[strT] = data.energy[strT]
# Add normal and redundant reactions
for mt in chain(data.reactions, data.redundant_reactions):
for mt in data.reactions:
if mt in self:
self[mt].xs[strT] = data[mt].xs[strT]
else:
@ -406,24 +390,14 @@ class IncidentNeutron(EqualityMixin):
have cross sections provided.
"""
if mt in self.reactions:
return [mt]
elif mt in SUM_RULES:
mts = SUM_RULES[mt]
mts = []
if mt in SUM_RULES:
for mt_i in SUM_RULES[mt]:
mts += self.get_reaction_components(mt_i)
if mts:
return mts
else:
return []
complete = False
while not complete:
new_mts = []
complete = True
for i, mt_i in enumerate(mts):
if mt_i in self.reactions:
new_mts.append(mt_i)
elif mt_i in SUM_RULES:
new_mts += SUM_RULES[mt_i]
complete = False
mts = new_mts
return mts
return [mt] if mt in self else []
def export_to_hdf5(self, path, mode='a', libver='earliest'):
"""Export incident neutron data to an HDF5 file.
@ -446,7 +420,7 @@ class IncidentNeutron(EqualityMixin):
'originated from an ENDF file.')
# Open file and write version
f = h5py.File(path, mode, libver=libver)
f = h5py.File(str(path), mode, libver=libver)
f.attrs['filetype'] = np.string_('data_neutron')
f.attrs['version'] = np.array(HDF5_VERSION)
@ -472,6 +446,15 @@ class IncidentNeutron(EqualityMixin):
# Write reaction data
rxs_group = g.create_group('reactions')
for rx in self.reactions.values():
# Skip writing redundant reaction if it doesn't have photon
# production or is a summed transmutation reaction. MT=4 is also
# sometimes needed for probability tables.
if rx.redundant:
photon_rx = any(p.particle == 'photon' for p in rx.products)
transmutation_rx = (rx.mt in (16, 103, 104, 105, 106, 107))
if not (photon_rx or transmutation_rx or rx.mt == 4):
continue
rx_group = rxs_group.create_group('reaction_{:03}'.format(rx.mt))
rx.to_hdf5(rx_group)
@ -480,12 +463,6 @@ class IncidentNeutron(EqualityMixin):
tgroup = g.create_group('total_nu')
rx.derived_products[0].to_hdf5(tgroup)
# Write redundant reaction data only for reactions with photon production
for rx in self.redundant_reactions.values():
if any(p.particle == 'photon' for p in rx.products):
rx_group = rxs_group.create_group('reaction_{:03}'.format(rx.mt))
rx.to_hdf5(rx_group)
# Write unresolved resonance probability tables
if self.urr:
urr_group = g.create_group('urr')
@ -520,16 +497,12 @@ class IncidentNeutron(EqualityMixin):
if isinstance(group_or_filename, h5py.Group):
group = group_or_filename
else:
h5file = h5py.File(group_or_filename, 'r')
h5file = h5py.File(str(group_or_filename), 'r')
# Make sure version matches
if 'version' in h5file.attrs:
major, minor = h5file.attrs['version']
if major != HDF5_VERSION_MAJOR:
raise IOError(
'HDF5 data format uses version {}.{} whereas your '
'installation of the OpenMC Python API expects version '
'{}.x.'.format(major, minor, HDF5_VERSION_MAJOR))
# For now all versions of HDF5 data can be read
else:
raise IOError(
'HDF5 data does not indicate a version. Your installation of '
@ -561,10 +534,7 @@ class IncidentNeutron(EqualityMixin):
for name, obj in sorted(rxs_group.items()):
if name.startswith('reaction_'):
rx = Reaction.from_hdf5(obj, data.energy)
if rx.redundant:
data.redundant_reactions[rx.mt] = rx
else:
data.reactions[rx.mt] = rx
data.reactions[rx.mt] = rx
# Read total nu data if available
if rx.mt in (18, 19, 20, 21, 38) and 'total_nu' in group:
@ -577,7 +547,8 @@ class IncidentNeutron(EqualityMixin):
if mt_sum not in data:
rxs = [data[mt] for mt in SUM_RULES[mt_sum] if mt in data]
if len(rxs) > 0:
data.redundant_reactions[mt_sum] = rx = Reaction(mt_sum)
data.reactions[mt_sum] = rx = Reaction(mt_sum)
rx.redundant = True
if rx.mt == 18 and 'total_nu' in group:
tgroup = group['total_nu']
rx.derived_products.append(Product.from_hdf5(tgroup))
@ -654,18 +625,21 @@ class IncidentNeutron(EqualityMixin):
total = Reaction(1)
total.xs[strT] = Tabulated1D(energy, total_xs)
total.redundant = True
data.redundant_reactions[1] = total
data.reactions[1] = total
if np.count_nonzero(absorption_xs) > 0:
absorption = Reaction(27)
absorption = Reaction(101)
absorption.xs[strT] = Tabulated1D(energy, absorption_xs)
absorption.redundant = True
data.redundant_reactions[27] = absorption
data.reactions[101] = absorption
# Read each reaction
n_reaction = ace.nxs[4] + 1
for i in range(n_reaction):
rx = Reaction.from_ace(ace, i)
# Don't include gas production / damage cross sections
if 200 < rx.mt < 219 or rx.mt == 444:
continue
data.reactions[rx.mt] = rx
# Some photon production reactions may be assigned to MTs that don't
@ -683,23 +657,39 @@ class IncidentNeutron(EqualityMixin):
continue
# Create redundant reaction with appropriate cross section
rx = Reaction(mt)
mts = data.get_reaction_components(mt)
if len(mts) == 0:
warn('Photon production is present for MT={} but no '
'reaction components exist.'.format(mt))
continue
xss = [data.reactions[mt_i].xs[strT] for mt_i in mts]
idx = min([xs._threshold_idx if hasattr(xs, '_threshold_idx')
else 0 for xs in xss])
rx.xs[strT] = Tabulated1D(energy[idx:], Sum(xss)(energy[idx:]))
rx.xs[strT]._threshold_idx = idx
rx.redundant = True
# Determine redundant cross section
rx = data._get_redundant_reaction(mt, mts)
rx.products += _get_photon_products_ace(ace, rx)
data.reactions[mt] = rx
# For transmutation reactions, sometimes only individual levels are
# present in an ACE file, e.g. MT=600-649 instead of the summation
# MT=103. In this case, if a user wants to tally (n,p), OpenMC doesn't
# know about the total cross section. Here, we explicitly create a
# redundant reaction for this purpose.
for mt in (16, 103, 104, 105, 106, 107):
if mt not in data:
# Determine if any individual levels are present
mts = data.get_reaction_components(mt)
if len(mts) == 0:
continue
# Determine redundant cross section
rx.products += _get_photon_products_ace(ace, rx)
data.redundant_reactions[mt] = rx
rx = data._get_redundant_reaction(mt, mts)
data.reactions[mt] = rx
# Make sure redundant cross sections that are present in an ACE file get
# marked as such
for rx in data:
mts = data.get_reaction_components(rx.mt)
if mts != [rx.mt]:
rx.redundant = True
# Read unresolved resonance probability tables
urr = ProbabilityTables.from_ace(ace)
@ -842,3 +832,33 @@ class IncidentNeutron(EqualityMixin):
data[2].xs['0K'] = xs
return data
def _get_redundant_reaction(self, mt, mts):
"""Create redundant reaction from its components
Parameters
----------
mt : int
MT value of the desired reaction
mts : iterable of int
MT values of its components
Returns
-------
openmc.Reaction
Redundant reaction
"""
# Get energy grid
strT = self.temperatures[0]
energy = self.energy[strT]
rx = Reaction(mt)
xss = [self.reactions[mt_i].xs[strT] for mt_i in mts]
idx = min([xs._threshold_idx if hasattr(xs, '_threshold_idx')
else 0 for xs in xss])
rx.xs[strT] = Tabulated1D(energy[idx:], Sum(xss)(energy[idx:]))
rx.xs[strT]._threshold_idx = idx
rx.redundant = True
return rx

View file

@ -146,14 +146,14 @@ def run(commands, tapein, tapeout, input_filename=None, stdout=False,
"""
if input_filename is not None:
with open(input_filename, 'w') as f:
with open(str(input_filename), 'w') as f:
f.write(commands)
with tempfile.TemporaryDirectory() as tmpdir:
# Copy evaluations to appropriates 'tapes'
for tape_num, filename in tapein.items():
tmpfilename = os.path.join(tmpdir, 'tape{}'.format(tape_num))
shutil.copy(filename, tmpfilename)
shutil.copy(str(filename), tmpfilename)
# Start up NJOY process
njoy = Popen([njoy_exec], cwd=tmpdir, stdin=PIPE, stdout=PIPE,
@ -182,7 +182,7 @@ def run(commands, tapein, tapeout, input_filename=None, stdout=False,
for tape_num, filename in tapeout.items():
tmpfilename = os.path.join(tmpdir, 'tape{}'.format(tape_num))
if os.path.isfile(tmpfilename):
shutil.move(tmpfilename, filename)
shutil.move(tmpfilename, str(filename))
def make_pendf(filename, pendf='pendf', error=0.001, stdout=False):
@ -422,7 +422,7 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None,
commands = ""
nendf, nthermal_endf, npendf = 20, 21, 22
tapein = {nendf: filename, nthermal_endf:filename_thermal}
tapein = {nendf: filename, nthermal_endf: filename_thermal}
tapeout = {}
# reconr

View file

@ -373,9 +373,6 @@ class IncidentPhoton(EqualityMixin):
excitation energy), 's_collision' (collision stopping power in
[eV cm\ :sup:`2`/g]), and 's_radiative' (radiative stopping power in
[eV cm\ :sup:`2`/g])
redundant_reactions : collections.OrderedDict
Contains redundant cross sections. The keys are MT values and the values
are instances of :class:`PhotonReaction`.
"""
@ -383,19 +380,16 @@ class IncidentPhoton(EqualityMixin):
self.atomic_number = atomic_number
self._atomic_relaxation = None
self.reactions = OrderedDict()
self.redundant_reactions = OrderedDict()
self.compton_profiles = {}
self.stopping_powers = {}
self.bremsstrahlung = {}
def __contains__(self, mt):
return mt in self.reactions or mt in self.redundant_reactions
return mt in self.reactions
def __getitem__(self, mt):
if mt in self.reactions:
return self.reactions[mt]
elif mt in self.redundant_reactions:
return self.redundant_reactions[mt]
else:
raise KeyError('No reaction with MT={}.'.format(mt))
@ -668,7 +662,7 @@ class IncidentPhoton(EqualityMixin):
"""
# Open file and write version
f = h5py.File(path, mode, libver=libver)
f = h5py.File(str(path), mode, libver=libver)
f.attrs['filetype'] = np.string_('data_photon')
if 'version' not in f.attrs:
f.attrs['version'] = np.array(HDF5_VERSION)

View file

@ -278,7 +278,7 @@ class ThermalScattering(EqualityMixin):
"""
# Open file and write version
f = h5py.File(path, mode, libver=libver)
f = h5py.File(str(path), mode, libver=libver)
f.attrs['filetype'] = np.string_('data_thermal')
f.attrs['version'] = np.array(HDF5_VERSION)
@ -387,7 +387,7 @@ class ThermalScattering(EqualityMixin):
if isinstance(group_or_filename, h5py.Group):
group = group_or_filename
else:
h5file = h5py.File(group_or_filename, 'r')
h5file = h5py.File(str(group_or_filename), 'r')
# Make sure version matches
if 'version' in h5file.attrs:

View file

@ -989,18 +989,12 @@ class Materials(cv.CheckedList):
continuous-energy calculations and
:envvar:`OPENMC_MG_CROSS_SECTIONS` will be used for multi-group
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
:envvar:`OPENMC_MULTIPOLE_LIBRARY` environment variable will be used. A
multipole library is optional.
"""
def __init__(self, materials=None):
super().__init__(Material, 'materials collection')
self._cross_sections = None
self._multipole_library = None
if materials is not None:
self += materials
@ -1009,20 +1003,11 @@ class Materials(cv.CheckedList):
def cross_sections(self):
return self._cross_sections
@property
def multipole_library(self):
return self._multipole_library
@cross_sections.setter
def cross_sections(self, cross_sections):
cv.check_type('cross sections', cross_sections, str)
self._cross_sections = cross_sections
@multipole_library.setter
def multipole_library(self, multipole_library):
cv.check_type('cross sections', multipole_library, str)
self._multipole_library = multipole_library
def append(self, material):
"""Append material to collection
@ -1060,11 +1045,6 @@ class Materials(cv.CheckedList):
element = ET.SubElement(root_element, "cross_sections")
element.text = str(self._cross_sections)
def _create_multipole_library_subelement(self, root_element):
if self._multipole_library is not None:
element = ET.SubElement(root_element, "multipole_library")
element.text = str(self._multipole_library)
def export_to_xml(self, path='materials.xml'):
"""Export material collection to an XML file.
@ -1077,7 +1057,6 @@ class Materials(cv.CheckedList):
root_element = ET.Element("materials")
self._create_cross_sections_subelement(root_element)
self._create_multipole_library_subelement(root_element)
self._create_material_subelements(root_element)
# Clean the indentation in the file to be user-readable
@ -1114,8 +1093,5 @@ class Materials(cv.CheckedList):
xs = tree.find('cross_sections')
if xs is not None:
materials.cross_sections = xs.text
mpl = tree.find('multipole_library')
if mpl is not None:
materials.multipole_library = mpl.text
return materials

View file

@ -180,7 +180,6 @@ class Settings(object):
self._confidence_intervals = None
self._cross_sections = None
self._electron_treatment = None
self._multipole_library = None
self._photon_transport = None
self._ptables = None
self._run_cmfd = None

View file

@ -0,0 +1,99 @@
#!/usr/bin/env python3
import argparse
from collections import defaultdict
import glob
import os
import openmc.data
description = """
Convert ENDF/B-VIII.0 ACE data from LANL into an HDF5 library
that can be used by OpenMC. This assumes that you have a directory containing
subdirectories 'Lib80x' and 'ENDF80SaB'.
"""
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter,
argparse.RawDescriptionHelpFormatter):
pass
parser = argparse.ArgumentParser(
description=description,
formatter_class=CustomFormatter
)
parser.add_argument('-o', '--output_dir', default='lib80x_hdf5',
help='Directory to create new library in')
parser.add_argument('--libver', choices=['earliest', 'latest'],
default='earliest', help="Output HDF5 versioning. Use "
"'earliest' for backwards compatibility or 'latest' for "
"performance")
parser.add_argument('--datadir', help='Directory containing Lib80x and ENDF80SaB',
default=os.curdir)
args = parser.parse_args()
assert os.path.isdir(args.datadir)
# Get a list of all ACE files
lib80x = glob.glob(os.path.join(args.datadir, 'Lib80x', '**', '*.80?nc'), recursive=True)
lib80sab = glob.glob(os.path.join(args.datadir, 'ENDF80SaB', '**', '*.??t'), recursive=True)
# Find and fix B10 ACE files
b10files = glob.glob(os.path.join(args.datadir, 'Lib80x', '**', '5010.80?nc'), recursive=True)
nxs1_position = 523
for filename in b10files:
with open(filename, 'r+') as fh:
# Read NXS(1)
fh.seek(nxs1_position)
nxs1 = int(fh.read(5))
# Increase length to match actual length of XSS, but make sure this
# isn't done twice by checking the current length
if nxs1 < 86870:
fh.seek(nxs1_position)
fh.write(str(nxs1 + 53))
# Group together tables for the same nuclide
suffixes = defaultdict(list)
for filename in sorted(lib80x + lib80sab):
dirname, basename = os.path.split(filename)
zaid, xs = basename.split('.')
suffixes[os.path.join(dirname, zaid)].append(xs)
# Create output directory if it doesn't exist
if not os.path.isdir(args.output_dir):
os.mkdir(args.output_dir)
library = openmc.data.DataLibrary()
for basename, xs_list in sorted(suffixes.items()):
# Convert first temperature for the table
filename = '.'.join((basename, xs_list[0]))
print('Converting: ' + filename)
if filename.endswith('t'):
data = openmc.data.ThermalScattering.from_ace(filename)
else:
data = openmc.data.IncidentNeutron.from_ace(filename, 'mcnp')
# For each higher temperature, add cross sections to the existing table
for xs in xs_list[1:]:
filename = '.'.join((basename, xs))
print('Adding: ' + filename)
if filename.endswith('t'):
data.add_temperature_from_ace(filename)
else:
data.add_temperature_from_ace(filename, 'mcnp')
# Export HDF5 file
h5_file = os.path.join(args.output_dir, data.name + '.h5')
print('Writing {}...'.format(h5_file))
data.export_to_hdf5(h5_file, 'w', libver=args.libver)
# Register with library
library.register_file(h5_file)
# Write cross_sections.xml
libpath = os.path.join(args.output_dir, 'cross_sections.xml')
library.export_to_xml(libpath)

View file

@ -1,120 +0,0 @@
#!/usr/bin/env python3
import os
import shutil
import subprocess
import sys
import tarfile
import glob
import hashlib
import argparse
from urllib.request import urlopen
description = """
Download and extract windowed multipole data based on ENDF/B-VII.1.
"""
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter,
argparse.RawDescriptionHelpFormatter):
pass
parser = argparse.ArgumentParser(
description=description,
formatter_class=CustomFormatter
)
parser.add_argument('-b', '--batch', action='store_true',
help='supresses standard in')
args = parser.parse_args()
baseUrl = 'https://github.com/mit-crpg/WMP_Library/releases/download/v1.1/'
files = ['WMP_Library_v1.1.tar.gz']
checksums = ['8523895928dd6ba63fba803e3a45d4f3']
block_size = 16384
# ==============================================================================
# DOWNLOAD FILES FROM GITHUB REPO
filesComplete = []
for f in files:
# Establish connection to URL
url = baseUrl + f
req = urlopen(url)
# Get file size from header
if sys.version_info[0] < 3:
file_size = int(req.info().getheaders('Content-Length')[0])
else:
file_size = req.length
downloaded = 0
# Remove GitHub junk from the file name.
fname = f[:-9] if f.endswith('?raw=true') else f
# Check if file already downloaded
if os.path.exists(fname):
if os.path.getsize(fname) == file_size:
print('Skipping ' + fname)
filesComplete.append(fname)
continue
else:
overwrite = input('Overwrite {0}? ([y]/n) '.format(fname))
if overwrite.lower().startswith('n'):
continue
# Copy file to disk
print('Downloading {0}... '.format(f), end='')
with open(fname, 'wb') as fh:
while True:
chunk = req.read(block_size)
if not chunk: break
fh.write(chunk)
downloaded += len(chunk)
status = '{0:10} [{1:3.2f}%]'.format(downloaded, downloaded * 100. / file_size)
print(status + chr(8)*len(status), end='')
print('')
filesComplete.append(fname)
# ==============================================================================
# VERIFY MD5 CHECKSUMS
print('Verifying MD5 checksums...')
for f, checksum in zip(files, checksums):
fname = f[:-9] if f.endswith('?raw=true') else f
downloadsum = hashlib.md5(open(fname, 'rb').read()).hexdigest()
if downloadsum != checksum:
raise IOError("MD5 checksum for {} does not match. If this is your first "
"time receiving this message, please re-run the script. "
"Otherwise, please contact OpenMC developers by emailing "
"openmc-users@googlegroups.com.".format(f))
# ==============================================================================
# EXTRACT FILES FROM TGZ
for f in files:
fname = f[:-9] if f.endswith('?raw=true') else f
if fname not in filesComplete:
continue
# Extract files
with tarfile.open(fname, 'r') as tgz:
print('Extracting {0}...'.format(fname))
tgz.extractall(path='')
# ==============================================================================
# PROMPT USER TO DELETE .TAR.GZ FILES
# Ask user to delete
if not args.batch:
response = input('Delete *.tar.gz files? ([y]/n) ')
else:
response = 'y'
# Delete files if requested
if not response or response.lower().startswith('y'):
for f in files:
if os.path.exists(f):
print('Removing {0}...'.format(f))
os.remove(f)

164
scripts/openmc-make-test-data Executable file
View file

@ -0,0 +1,164 @@
#!/usr/bin/env python3
"""
Download ENDF/B-VII.1 ENDF and ACE files from NNDC and WMP files from GitHub and
generate a full HDF5 library with incident neutron, incident photon, thermal
scattering data, and windowed multipole data. This data is used for OpenMC's
regression test suite.
"""
import glob
import os
from pathlib import Path
import tarfile
import tempfile
from urllib.parse import urljoin
import zipfile
import openmc.data
from openmc._utils import download
base_ace = 'http://www.nndc.bnl.gov/endf/b7.1/aceFiles/'
base_endf = 'http://www.nndc.bnl.gov/endf/b7.1/zips/'
base_wmp = 'https://github.com/mit-crpg/WMP_Library/releases/download/v1.1/'
files = [
(base_ace, 'ENDF-B-VII.1-neutron-293.6K.tar.gz', '9729a17eb62b75f285d8a7628ace1449'),
(base_ace, 'ENDF-B-VII.1-tsl.tar.gz', 'e17d827c92940a30f22f096d910ea186'),
(base_endf, 'ENDF-B-VII.1-neutrons.zip', 'e5d7f441fc4c92893322c24d1725e29c'),
(base_endf, 'ENDF-B-VII.1-photoat.zip', '5192f94e61f0b385cf536f448ffab4a4'),
(base_endf, 'ENDF-B-VII.1-atomic_relax.zip', 'fddb6035e7f2b6931e51a58fc754bd10'),
(base_wmp, 'WMP_Library_v1.1.tar.gz', '8523895928dd6ba63fba803e3a45d4f3')
]
def fix_zaid(table, old, new):
filename = os.path.join('tsl', table)
with open(filename, 'r') as fh:
text = fh.read()
text = text.replace(old, new, 1)
with open(filename, 'w') as fh:
fh.write(text)
pwd = Path.cwd()
output_dir = pwd / 'nndc_hdf5'
os.makedirs('nndc_hdf5/photon', exist_ok=True)
with tempfile.TemporaryDirectory() as tmpdir:
# Temporarily change dir
os.chdir(tmpdir)
# =========================================================================
# Download files from NNDC server
for base, fname, checksum in files:
download(urljoin(base, fname), checksum)
# =========================================================================
# EXTRACT FILES FROM TGZ
for _, f, _ in files:
print('Extracting {}...'.format(f))
path = Path(f)
if path.suffix == '.gz':
with tarfile.open(f, 'r') as tgz:
if 'tsl' in f:
tgz.extractall(path='tsl')
else:
tgz.extractall()
elif path.suffix == '.zip':
zipfile.ZipFile(f).extractall()
# =========================================================================
# FIX ZAID ASSIGNMENTS FOR VARIOUS S(A,B) TABLES
print('Fixing ZAIDs for S(a,b) tables')
fix_zaid('bebeo.acer', '8016', ' 0')
fix_zaid('obeo.acer', '4009', ' 0')
library = openmc.data.DataLibrary()
# =========================================================================
# INCIDENT NEUTRON DATA
neutron_files = sorted(glob.glob('ENDF-B-VII.1-neutron-293.6K/*.ace'))
for f in neutron_files:
print('Converting {}...'.format(os.path.basename(f)))
data = openmc.data.IncidentNeutron.from_ace(f)
# Check for fission energy release data
endf_filename = 'neutrons/n-{:03}_{}_{:03}{}.endf'.format(
data.atomic_number,
data.atomic_symbol,
data.mass_number,
'm{}'.format(data.metastable) if data.metastable else ''
)
ev = openmc.data.endf.Evaluation(endf_filename)
if (1, 458) in ev.section:
endf_data = openmc.data.IncidentNeutron.from_endf(ev)
data.fission_energy = endf_data.fission_energy
# Add 0K elastic scattering data for select nuclides
if data.name in ('U235', 'U238', 'Pu239'):
data.add_elastic_0K_from_endf(endf_filename)
# Determine filename
outfile = output_dir / (data.name + '.h5')
data.export_to_hdf5(outfile, 'w', 'earliest')
# Register with library
library.register_file(outfile)
# =========================================================================
# THERMAL SCATTERING DATA
thermal_files = sorted(glob.glob('tsl/*.acer'))
for f in thermal_files:
print('Converting {}...'.format(os.path.basename(f)))
data = openmc.data.ThermalScattering.from_ace(f)
# Determine filename
outfile = output_dir / (data.name + '.h5')
data.export_to_hdf5(outfile, 'w', 'earliest')
# Register with library
library.register_file(outfile)
# =========================================================================
# INCIDENT PHOTON DATA
for z in range(1, 101):
element = openmc.data.ATOMIC_SYMBOL[z]
print('Generating HDF5 file for Z={} ({})...'.format(z, element))
# Generate instance of IncidentPhoton
photo_file = Path('photoat') / 'photoat-{:03}_{}_000.endf'.format(z, element)
atom_file = Path('atomic_relax') / 'atom-{:03}_{}_000.endf'.format(z, element)
data = openmc.data.IncidentPhoton.from_endf(photo_file, atom_file)
# Write HDF5 file and register it
outfile = output_dir / 'photon' / (element + '.h5')
data.export_to_hdf5(outfile, 'w', 'earliest')
library.register_file(outfile)
# =========================================================================
# WINDOWED MULTIPOLE DATA
# Move data into output directory
os.rename('WMP_Library', str(output_dir / 'wmp'))
# Add multipole data to library
for f in sorted(glob.glob('{}/wmp/*.h5'.format(output_dir))):
print('Registering WMP file {}...'.format(f))
library.register_file(f)
library.export_to_xml(output_dir / 'cross_sections.xml')
# =========================================================================
# CREATE TARBALL AND MOVE BACK
print('Creating compressed archive...')
test_tar = pwd / 'nndc_hdf5_test.tar.xz'
with tarfile.open(str(test_tar), 'w:xz') as txz:
txz.add('nndc_hdf5')
# Change back to original directory
os.chdir(str(pwd))

View file

@ -79,6 +79,9 @@ contains
subroutine free_memory_mesh() bind(C)
end subroutine free_memory_mesh
subroutine free_memory_settings() bind(C)
end subroutine free_memory_settings
end interface
call free_memory_geometry()

View file

@ -15,7 +15,7 @@ module constants
VERSION(3) = [VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE]
! HDF5 data format
integer, parameter :: HDF5_VERSION(2) = [1, 0]
integer, parameter :: HDF5_VERSION(2) = [2, 0]
! WMP data format
integer, parameter :: WMP_VERSION(2) = [1, 1]
@ -238,7 +238,8 @@ module constants
LIBRARY_NEUTRON = 1, &
LIBRARY_THERMAL = 2, &
LIBRARY_PHOTON = 3, &
LIBRARY_MULTIGROUP = 4
LIBRARY_MULTIGROUP = 4, &
LIBRARY_WMP = 5
! Probability table parameters
integer, parameter :: &

226
src/cross_sections.cpp Normal file
View file

@ -0,0 +1,226 @@
#include "openmc/cross_sections.h"
#include "openmc/constants.h"
#include "openmc/container_util.h"
#include "openmc/error.h"
#include "openmc/file_utils.h"
#include "openmc/settings.h"
#include "openmc/string_utils.h"
#include "openmc/xml_interface.h"
#include "pugixml.hpp"
#include <cstdlib> // for getenv
namespace openmc {
//==============================================================================
// Global variable declarations
//==============================================================================
namespace data {
std::vector<Library> libraries;
std::map<LibraryKey, std::size_t> library_map;
}
//==============================================================================
// Library methods
//==============================================================================
Library::Library(pugi::xml_node node, const std::string& directory)
{
// Get type of library
if (check_for_node(node, "type")) {
auto type = get_node_value(node, "type");
if (type == "neutron") {
type_ = Type::neutron;
} else if (type == "thermal") {
type_ = Type::thermal;
} else if (type == "photon") {
type_ = Type::photon;
} else if (type == "wmp") {
type_ = Type::wmp;
} else {
fatal_error("Unrecognized library type: " + type);
}
} else {
fatal_error("Missing library type");
}
// Get list of materials
if (check_for_node(node, "materials")) {
materials_ = get_node_array<std::string>(node, "materials");
}
// determine path of cross section table
if (!check_for_node(node, "path")) {
fatal_error("Missing library path");
}
std::string path = get_node_value(node, "path");
if (starts_with(path, "/")) {
path_ = path;
} else if (ends_with(directory, "/")) {
path_ = directory + path;
} else {
path_ = directory + "/" + path;
}
if (!file_exists(path_)) {
warning("Cross section library " + path_ + " does not exist.");
}
}
//==============================================================================
// Non-member functions
//==============================================================================
extern "C" void read_mg_cross_sections_header();
void read_cross_sections_xml()
{
// Check if materials.xml exists
std::string filename = settings::path_input + "materials.xml";
if (!file_exists(filename)) {
fatal_error("Material XML file '" + filename + "' does not exist.");
}
// Parse materials.xml file
pugi::xml_document doc;
doc.load_file(filename.c_str());
auto root = doc.document_element();
// Find cross_sections.xml file -- the first place to look is the
// materials.xml file. If no file is found there, then we check the
// OPENMC_CROSS_SECTIONS environment variable
if (!check_for_node(root, "cross_sections")) {
// No cross_sections.xml file specified in settings.xml, check
// environment variable
if (settings::run_CE) {
char* envvar = std::getenv("OPENMC_CROSS_SECTIONS");
if (!envvar) {
fatal_error("No cross_sections.xml file was specified in "
"materials.xml or in the OPENMC_CROSS_SECTIONS"
" environment variable. OpenMC needs such a file to identify "
"where to find data libraries. Please consult the"
" user's guide at https://openmc.readthedocs.io for "
"information on how to set up data libraries.");
}
settings::path_cross_sections = envvar;
} else {
char* envvar = std::getenv("OPENMC_MG_CROSS_SECTIONS");
if (!envvar) {
fatal_error("No mgxs.h5 file was specified in "
"materials.xml or in the OPENMC_MG_CROSS_SECTIONS environment "
"variable. OpenMC needs such a file to identify where to "
"find MG cross section libraries. Please consult the user's "
"guide at http://openmc.readthedocs.io for information on "
"how to set up MG cross section libraries.");
}
settings::path_cross_sections = envvar;
}
} else {
settings::path_cross_sections = get_node_value(root, "cross_sections");
}
// Now that the cross_sections.xml or mgxs.h5 has been located, read it in
if (settings::run_CE) {
read_ce_cross_sections_xml();
} else {
read_mg_cross_sections_header();
}
// Establish mapping between (type, material) and index in libraries
int i = 0;
for (const auto& lib : data::libraries) {
for (const auto& name : lib.materials_) {
std::string lower_name = name;
to_lower(lower_name);
LibraryKey key {lib.type_, lower_name};
data::library_map.insert({key, i});
}
++i;
}
// Check that 0K nuclides are listed in the cross_sections.xml file
for (const auto& name : settings::res_scat_nuclides) {
std::string lower_name = name;
to_lower(lower_name);
LibraryKey key {Library::Type::neutron, lower_name};
if (data::library_map.find(key) == data::library_map.end()) {
fatal_error("Could not find resonant scatterer " +
name + " in cross_sections.xml file!");
}
}
}
void read_ce_cross_sections_xml()
{
// Check if cross_sections.xml exists
const auto& filename = settings::path_cross_sections;
if (!file_exists(filename)) {
// Could not find cross_sections.xml file
fatal_error("Cross sections XML file '" + filename +
"' does not exist.");
}
write_message("Reading cross sections XML file...", 5);
// Parse cross_sections.xml file
pugi::xml_document doc;
auto result = doc.load_file(filename.c_str());
if (!result) {
fatal_error("Error processing cross_sections.xml file.");
}
auto root = doc.document_element();
std::string directory;
if (check_for_node(root, "directory")) {
// Copy directory information if present
directory = get_node_value(root, "directory");
} else {
// If no directory is listed in cross_sections.xml, by default select the
// directory in which the cross_sections.xml file resides
auto pos = filename.rfind("/");
directory = filename.substr(0, pos);
}
for (const auto& node_library : root.children("library")) {
data::libraries.emplace_back(node_library, directory);
}
// Make sure file was not empty
if (data::libraries.empty()) {
fatal_error("No cross section libraries present in cross_sections.xml file.");
}
}
//==============================================================================
// Fortran compatibility functions
//==============================================================================
extern "C" void library_clear() {
data::libraries.clear();
data::library_map.clear();
}
extern "C" const char* library_path(int type, const char* name) {
auto lib_type = static_cast<Library::Type>(type);
LibraryKey key {lib_type, name};
if (data::library_map.find(key) == data::library_map.end()) {
return nullptr;
} else {
auto idx = data::library_map[key];
return data::libraries[idx].path_.c_str();
}
}
extern "C" bool library_present(int type, const char* name) {
auto lib_type = static_cast<Library::Type>(type);
LibraryKey key {lib_type, name};
return data::library_map.find(key) != data::library_map.end();
}
} // namespace openmc

View file

@ -1,7 +1,7 @@
#include "openmc/dagmc.h"
#include "openmc/error.h"
#include "openmc/string_functions.h"
#include "openmc/string_utils.h"
#include "openmc/settings.h"
#include "openmc/geometry.h"

View file

@ -229,7 +229,7 @@ contains
integer, intent(in) :: MT
logical :: dis
if (MT >= N_GAMMA .and. MT <= N_DA) then
if (MT >= N_DISAPPEAR .and. MT <= N_DA) then
dis = .true.
elseif (MT >= N_P0 .and. MT <= N_AC) then
dis = .true.
@ -242,25 +242,27 @@ contains
end function is_disappearance
!===============================================================================
! IS_SCATTER determines if a given MT number is that of a scattering event
! IS_INELASTIC_SCATTER determines if a given MT number is that of an inelastic
! scattering event
!===============================================================================
function is_scatter(MT) result(scatter_event)
function is_inelastic_scatter(MT) result(retval)
integer, intent(in) :: MT
logical :: scatter_event
logical :: retval
if (MT < 100) then
if (MT == N_FISSION .or. MT == N_F .or. MT == N_NF .or. MT == N_2NF &
.or. MT == N_3NF) then
scatter_event = .false.
if (is_fission(MT)) then
retval = .false.
else
scatter_event = .true.
retval = (MT >= MISC .and. MT /= 27)
end if
elseif (MT <= 200) then
retval = (.not. is_disappearance(MT))
else
scatter_event = .false.
retval = .false.
end if
end function is_scatter
end function
end module endf

View file

@ -362,7 +362,7 @@ member_names(hid_t group_id, H5O_type_t type)
char buffer[size];
H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i,
buffer, size, H5P_DEFAULT);
names.emplace_back(&buffer[0], size);
names.emplace_back(&buffer[0]);
}
return names;
}

View file

@ -8,23 +8,23 @@ module initialize
implicit none
interface
function openmc_path_input() result(ptr) bind(C)
function path_input_c() result(ptr) bind(C)
import C_PTR
type(C_PTR) :: ptr
end function
function openmc_path_output() result(ptr) bind(C)
function path_output_c() result(ptr) bind(C)
import C_PTR
type(C_PTR) :: ptr
end function
function openmc_path_particle_restart() result(ptr) bind(C)
function path_particle_restart_c() result(ptr) bind(C)
import C_PTR
type(C_PTR) :: ptr
end function
function openmc_path_statepoint() result(ptr) bind(C)
function path_statepoint_c() result(ptr) bind(C)
import C_PTR
type(C_PTR) :: ptr
end function
function openmc_path_sourcepoint() result(ptr) bind(C)
function path_sourcepoint_c() result(ptr) bind(C)
import C_PTR
type(C_PTR) :: ptr
end function
@ -49,22 +49,22 @@ contains
end function is_null
end interface
if (.not. is_null(openmc_path_input())) then
call c_f_pointer(openmc_path_input(), string, [255])
if (.not. is_null(path_input_c())) then
call c_f_pointer(path_input_c(), string, [255])
path_input = to_f_string(string)
else
path_input = ''
end if
if (.not. is_null(openmc_path_statepoint())) then
call c_f_pointer(openmc_path_statepoint(), string, [255])
if (.not. is_null(path_statepoint_c())) then
call c_f_pointer(path_statepoint_c(), string, [255])
path_state_point = to_f_string(string)
end if
if (.not. is_null(openmc_path_sourcepoint())) then
call c_f_pointer(openmc_path_sourcepoint(), string, [255])
if (.not. is_null(path_sourcepoint_c())) then
call c_f_pointer(path_sourcepoint_c(), string, [255])
path_source_point = to_f_string(string)
end if
if (.not. is_null(openmc_path_particle_restart())) then
call c_f_pointer(openmc_path_particle_restart(), string, [255])
if (.not. is_null(path_particle_restart_c())) then
call c_f_pointer(path_particle_restart_c(), string, [255])
path_particle_restart = to_f_string(string)
end if
end subroutine read_command_line

View file

@ -72,6 +72,9 @@ module input_xml
type(C_PTR) :: node_ptr
end subroutine read_cells
subroutine read_cross_sections_xml() bind(C)
end subroutine
subroutine read_lattices(node_ptr) bind(C)
import C_PTR
type(C_PTR) :: node_ptr
@ -123,15 +126,14 @@ contains
type(VectorReal), allocatable :: nuc_temps(:) ! List of T to read for each nuclide
type(VectorReal), allocatable :: sab_temps(:) ! List of T to read for each S(a,b)
real(8), allocatable :: material_temps(:)
call read_settings_xml()
call read_cross_sections_xml()
call read_materials_xml(material_temps)
call read_materials_xml()
call read_geometry_xml()
! Set up neighbor lists, convert user IDs -> indices, assign temperatures
call finalize_geometry(material_temps, nuc_temps, sab_temps)
call finalize_geometry(nuc_temps, sab_temps)
if (run_mode /= MODE_PLOTTING) then
call time_read_xs % start()
@ -172,8 +174,7 @@ contains
end subroutine read_input_xml
subroutine finalize_geometry(material_temps, nuc_temps, sab_temps)
real(8), intent(in) :: material_temps(:)
subroutine finalize_geometry(nuc_temps, sab_temps)
type(VectorReal), allocatable, intent(out) :: nuc_temps(:)
type(VectorReal), optional, allocatable, intent(out) :: sab_temps(:)
@ -215,27 +216,12 @@ contains
integer :: i
integer :: n
type(XMLNode) :: root
type(XMLNode) :: node_res_scat
type(XMLNode) :: node_vol
type(XMLNode), allocatable :: node_vol_list(:)
! Get proper XMLNode type given pointer
root % ptr = root_ptr
! Resonance scattering parameters
if (check_for_node(root, "resonance_scattering")) then
node_res_scat = root % child("resonance_scattering")
! Get nuclides that resonance scattering should be applied to
if (check_for_node(node_res_scat, "nuclides")) then
n = node_word_count(node_res_scat, "nuclides")
allocate(res_scat_nuclides(n))
if (n > 0) then
call get_node_array(node_res_scat, "nuclides", res_scat_nuclides)
end if
end if
end if
call get_node_list(root, "volume_calc", node_vol_list)
n = size(node_vol_list)
allocate(volume_calcs(n))
@ -547,128 +533,12 @@ contains
end do
end subroutine allocate_cells
!===============================================================================
! READ_MATERIAL_XML reads data from a materials.xml file and parses it, checking
! for errors and placing properly-formatted data in the right data structures
!===============================================================================
subroutine read_cross_sections_xml()
integer :: i, j
logical :: file_exists
character(MAX_FILE_LEN) :: env_variable
character(MAX_LINE_LEN) :: filename
type(XMLDocument) :: doc
type(XMLNode) :: root
! Check if materials.xml exists
filename = trim(path_input) // "materials.xml"
inquire(FILE=filename, EXIST=file_exists)
if (.not. file_exists) then
call fatal_error("Material XML file '" // trim(filename) // "' does not &
&exist!")
end if
! Parse materials.xml file
call doc % load_file(filename)
root = doc % document_element()
! Find cross_sections.xml file -- the first place to look is the
! materials.xml file. If no file is found there, then we check the
! OPENMC_CROSS_SECTIONS environment variable
if (.not. check_for_node(root, "cross_sections")) then
! No cross_sections.xml file specified in settings.xml, check
! environment variable
if (run_CE) then
call get_environment_variable("OPENMC_CROSS_SECTIONS", env_variable)
if (len_trim(env_variable) == 0) then
call get_environment_variable("CROSS_SECTIONS", env_variable)
! FIXME: When deprecated option of setting the cross sections in
! settings.xml is removed, remove ".and. path_cross_sections == ''"
if (len_trim(env_variable) == 0 .and. path_cross_sections == '') then
call fatal_error("No cross_sections.xml file was specified in &
&materials.xml, settings.xml, or in the OPENMC_CROSS_SECTIONS&
& environment variable. OpenMC needs such a file to identify &
&where to find ACE cross section libraries. Please consult the&
& user's guide at http://openmc.readthedocs.io for &
&information on how to set up ACE cross section libraries.")
else
call warning("The CROSS_SECTIONS environment variable is &
&deprecated. Please update your environment to use &
&OPENMC_CROSS_SECTIONS instead.")
end if
end if
path_cross_sections = trim(env_variable)
else
call get_environment_variable("OPENMC_MG_CROSS_SECTIONS", env_variable)
! FIXME: When deprecated option of setting the mg cross sections in
! settings.xml is removed, remove ".and. path_cross_sections == ''"
if (len_trim(env_variable) == 0 .and. path_cross_sections == '') then
call fatal_error("No mgxs.h5 file was specified in &
&materials.xml or in the OPENMC_MG_CROSS_SECTIONS environment &
&variable. OpenMC needs such a file to identify where to &
&find MG cross section libraries. Please consult the user's &
&guide at http://openmc.readthedocs.io for information on &
&how to set up MG cross section libraries.")
else if (len_trim(env_variable) /= 0) then
path_cross_sections = trim(env_variable)
end if
end if
else
call get_node_value(root, "cross_sections", path_cross_sections)
end if
! Find the windowed multipole library
if (run_mode /= MODE_PLOTTING) then
if (.not. check_for_node(root, "multipole_library")) then
! No library location specified in materials.xml, check
! environment variable
call get_environment_variable("OPENMC_MULTIPOLE_LIBRARY", env_variable)
path_multipole = trim(env_variable)
else
call get_node_value(root, "multipole_library", path_multipole)
end if
if (.not. ends_with(path_multipole, "/")) &
path_multipole = trim(path_multipole) // "/"
end if
! Close materials XML file
call doc % clear()
! Now that the cross_sections.xml or mgxs.h5 has been located, read it in
if (run_CE) then
call read_ce_cross_sections_xml()
else
call read_mg_cross_sections_header()
end if
! Creating dictionary that maps the name of the material to the entry
do i = 1, size(libraries)
do j = 1, size(libraries(i) % materials)
call library_dict % set(to_lower(libraries(i) % materials(j)), i)
end do
end do
! Check that 0K nuclides are listed in the cross_sections.xml file
if (allocated(res_scat_nuclides)) then
do i = 1, size(res_scat_nuclides)
if (.not. library_dict % has(to_lower(res_scat_nuclides(i)))) then
call fatal_error("Could not find resonant scatterer " &
// trim(res_scat_nuclides(i)) // " in cross_sections.xml file!")
end if
end do
end if
end subroutine read_cross_sections_xml
subroutine read_materials_xml(material_temps)
real(8), allocatable, intent(out) :: material_temps(:)
subroutine read_materials_xml()
integer :: i ! loop index for materials
integer :: j ! loop index for nuclides
integer :: k ! loop index
integer :: n ! number of nuclides
integer :: n_sab ! number of sab tables for a material
integer :: i_library ! index in libraries array
integer :: index_nuclide ! index in nuclides
integer :: index_element ! index in elements
integer :: index_sab ! index in sab_tables
@ -720,7 +590,6 @@ contains
! Allocate materials array
n_materials = size(node_mat_list)
allocate(materials(n_materials))
allocate(material_temps(n_materials))
! Initialize count for number of nuclides/S(a,b) tables
index_nuclide = 0
@ -745,13 +614,6 @@ contains
call get_node_value(node_mat, "name", mat % name)
end if
! Get material default temperature
if (check_for_node(node_mat, "temperature")) then
call get_node_value(node_mat, "temperature", material_temps(i))
else
material_temps(i) = -1.0
end if
! Get pointer to density element
if (check_for_node(node_mat, "density")) then
node_dens = node_mat % child("density")
@ -940,19 +802,10 @@ contains
ALL_NUCLIDES: do j = 1, mat % n_nuclides
! Check that this nuclide is listed in the cross_sections.xml file
name = trim(names % data(j))
if (.not. library_dict % has(to_lower(name))) then
if (.not. library_present(LIBRARY_NEUTRON, (to_lower(name)))) then
call fatal_error("Could not find nuclide " // trim(name) &
// " in cross_sections data file!")
end if
i_library = library_dict % get(to_lower(name))
if (run_CE) then
! Check to make sure cross-section is continuous energy neutron table
if (libraries(i_library) % type /= LIBRARY_NEUTRON) then
call fatal_error("Cross-section table " // trim(name) &
// " is not a continuous-energy neutron table.")
end if
end if
! If this nuclide hasn't been encountered yet, we need to add its name
! and alias to the nuclide_dict
@ -971,7 +824,7 @@ contains
element = name(1:scan(name, '0123456789') - 1)
! Make sure photon cross section data is available
if (.not. library_dict % has(to_lower(element))) then
if (.not. library_present(LIBRARY_PHOTON, to_lower(element))) then
call fatal_error("Could not find element " // trim(element) &
// " in cross_sections data file!")
end if
@ -1065,23 +918,11 @@ contains
end if
! Check that this nuclide is listed in the cross_sections.xml file
if (.not. library_dict % has(to_lower(name))) then
if (.not. library_present(LIBRARY_THERMAL, to_lower(name))) then
call fatal_error("Could not find S(a,b) table " // trim(name) &
// " in cross_sections.xml file!")
end if
! Find index in xs_listing and set the name and alias according to the
! listing
i_library = library_dict % get(to_lower(name))
if (run_CE) then
! Check to make sure cross-section is continuous energy neutron table
if (libraries(i_library) % type /= LIBRARY_THERMAL) then
call fatal_error("Cross-section table " // trim(name) &
// " is not a S(a,b) table.")
end if
end if
! If this S(a,b) table hasn't been encountered yet, we need to add its
! name and alias to the sab_dict
if (.not. sab_dict % has(to_lower(name))) then
@ -2064,130 +1905,27 @@ contains
end subroutine read_plots_xml
!===============================================================================
! READ_*_CROSS_SECTIONS_XML reads information from a cross_sections.xml file. This
! file contains a listing of the CE and MG cross sections that may be used.
!===============================================================================
subroutine read_ce_cross_sections_xml()
subroutine read_mg_cross_sections_header() bind(C)
integer :: i ! loop index
integer :: n
integer :: n_libraries
logical :: file_exists ! does cross_sections.xml exist?
character(MAX_WORD_LEN) :: directory ! directory with cross sections
character(MAX_WORD_LEN) :: words(MAX_WORDS)
character(10000) :: temp_str
type(XMLDocument) :: doc
type(XMLNode) :: root
type(XMLNode) :: node_library
type(XMLNode), allocatable :: node_library_list(:)
! Check if cross_sections.xml exists
inquire(FILE=path_cross_sections, EXIST=file_exists)
if (.not. file_exists) then
! Could not find cross_sections.xml file
call fatal_error("Cross sections XML file '" &
// trim(path_cross_sections) // "' does not exist!")
end if
call write_message("Reading cross sections XML file...", 5)
! Parse cross_sections.xml file
call doc % load_file(path_cross_sections)
root = doc % document_element()
if (check_for_node(root, "directory")) then
! Copy directory information if present
call get_node_value(root, "directory", directory)
else
! If no directory is listed in cross_sections.xml, by default select the
! directory in which the cross_sections.xml file resides
i = index(path_cross_sections, "/", BACK=.true.)
directory = path_cross_sections(1:i)
end if
! Get node list of all <library>
call get_node_list(root, "library", node_library_list)
n_libraries = size(node_library_list)
! Allocate xs_listings array
if (n_libraries == 0) then
call fatal_error("No cross section libraries present in cross_sections.xml &
&file!")
else
allocate(libraries(n_libraries))
end if
do i = 1, n_libraries
! Get pointer to ace table XML node
node_library = node_library_list(i)
! Get list of materials
if (check_for_node(node_library, "materials")) then
call get_node_value(node_library, "materials", temp_str)
call split_string(temp_str, words, n)
allocate(libraries(i) % materials(n))
libraries(i) % materials(:) = words(1:n)
end if
! Get type of library
if (check_for_node(node_library, "type")) then
call get_node_value(node_library, "type", temp_str)
select case(to_lower(temp_str))
case ('neutron')
libraries(i) % type = LIBRARY_NEUTRON
case ('thermal')
libraries(i) % type = LIBRARY_THERMAL
case ('photon')
libraries(i) % type = LIBRARY_PHOTON
end select
else
call fatal_error("Missing library type")
end if
! determine path of cross section table
if (check_for_node(node_library, "path")) then
call get_node_value(node_library, "path", temp_str)
else
call fatal_error("Missing library path")
end if
if (starts_with(temp_str, '/')) then
libraries(i) % path = trim(temp_str)
else
if (ends_with(directory,'/')) then
libraries(i) % path = trim(directory) // trim(temp_str)
else
libraries(i) % path = trim(directory) // '/' // trim(temp_str)
end if
end if
inquire(FILE=libraries(i) % path, EXIST=file_exists)
if (.not. file_exists) then
call warning("Cross section library " // trim(libraries(i) % path) // &
" does not exist.")
end if
end do
! Close cross sections XML file
call doc % clear()
end subroutine read_ce_cross_sections_xml
subroutine read_mg_cross_sections_header()
integer :: i ! loop index
integer :: n_libraries
logical :: file_exists ! does mgxs.h5 exist?
integer(HID_T) :: file_id
character(len=MAX_WORD_LEN), allocatable :: names(:)
character(kind=C_CHAR), pointer :: string(:)
interface
subroutine read_mg_cross_sections_header_c(file_id) bind(C)
import HID_T
integer(HID_T), value :: file_id
end subroutine
function path_cross_sections_c() result(ptr) bind(C)
import C_PTR
type(C_PTR) :: ptr
end function
end interface
call c_f_pointer(path_cross_sections_c(), string, [255])
path_cross_sections = to_f_string(string)
! Check if MGXS Library exists
inquire(FILE=path_cross_sections, EXIST=file_exists)
if (.not. file_exists) then
@ -2244,24 +1982,6 @@ contains
call set_particle_energy_bounds(NEUTRON, energy_min(NEUTRON), &
energy_max(NEUTRON))
! Get the datasets present in the library
call get_groups(file_id, names)
n_libraries = size(names)
! Allocate libraries array
if (n_libraries == 0) then
call fatal_error("At least one MGXS data set must be present in &
&mgxs library file!")
else
allocate(libraries(n_libraries))
end if
do i = 1, n_libraries
! Get name of material
allocate(libraries(i) % materials(1))
libraries(i) % materials(1) = names(i)
end do
! Close MGXS HDF5 file
call file_close(file_id)
@ -2350,7 +2070,6 @@ contains
type(VectorReal), intent(in) :: sab_temps(:)
integer :: i, j
integer :: i_library
integer :: i_nuclide
integer :: i_element
integer :: i_sab
@ -2358,6 +2077,7 @@ contains
integer(HID_T) :: group_id
logical :: mp_found ! if windowed multipole libraries were found
character(MAX_WORD_LEN) :: name
character(MAX_FILE_LEN) :: filename
character(3) :: element
type(SetChar) :: already_read
type(SetChar) :: element_already_read
@ -2375,14 +2095,14 @@ contains
name = materials(i) % names(j)
if (.not. already_read % contains(name)) then
i_library = library_dict % get(to_lower(name))
filename = library_path(LIBRARY_NEUTRON, to_lower(name))
i_nuclide = nuclide_dict % get(to_lower(name))
call write_message('Reading ' // trim(name) // ' from ' // &
trim(libraries(i_library) % path), 6)
trim(filename), 6)
! Open file and make sure version is sufficient
file_id = file_open(libraries(i_library) % path, 'r')
file_id = file_open(filename, 'r')
call check_data_version(file_id)
! Read nuclide data from HDF5
@ -2415,13 +2135,13 @@ contains
if (photon_transport) then
if (.not. element_already_read % contains(element)) then
! Read photon interaction data from HDF5 photon library
i_library = library_dict % get(to_lower(element))
filename = library_path(LIBRARY_PHOTON, to_lower(element))
i_element = element_dict % get(element)
call write_message('Reading ' // trim(element) // ' from ' // &
trim(libraries(i_library) % path), 6)
trim(filename), 6)
! Open file and make sure version is sufficient
file_id = file_open(libraries(i_library) % path, 'r')
file_id = file_open(filename, 'r')
call check_data_version(file_id)
! Read element data from HDF5
@ -2505,14 +2225,14 @@ contains
name = materials(i) % sab_names(j)
if (.not. already_read % contains(name)) then
i_library = library_dict % get(to_lower(name))
filename = library_path(LIBRARY_THERMAL, to_lower(name))
i_sab = sab_dict % get(to_lower(name))
call write_message('Reading ' // trim(name) // ' from ' // &
trim(libraries(i_library) % path), 6)
trim(filename), 6)
! Open file and make sure version matches
file_id = file_open(libraries(i_library) % path, 'r')
file_id = file_open(filename, 'r')
call check_data_version(file_id)
! Read S(a,b) data from HDF5
@ -2556,9 +2276,8 @@ contains
end if
end do
if (.not. mp_found) call warning("Windowed multipole functionality is &
&turned on, but no multipole libraries were found. Set the &
&<multipole_library> element in settings.xml or the &
&OPENMC_MULTIPOLE_LIBRARY environment variable.")
&turned on, but no multipole libraries were found. Make sure that &
&windowed multipole data is present in your cross_sections.xml file.")
end if
call already_read % clear()
@ -2578,20 +2297,18 @@ contains
logical :: file_exists ! Does multipole library exist?
character(7) :: readable ! Is multipole library readable?
character(MAX_FILE_LEN) :: filename ! Path to multipole xs library
character(kind=C_CHAR), pointer :: string(:)
integer(HID_T) :: file_id
integer(HID_T) :: group_id
! For the time being, and I know this is a bit hacky, we just assume
! that the file will be ZZZAAAmM.h5.
associate (nuc => nuclides(i_table))
if (nuc % metastable > 0) then
filename = trim(path_multipole) // trim(zero_padded(nuc % Z, 3)) // &
trim(zero_padded(nuc % A, 3)) // 'm' // &
trim(to_str(nuc % metastable)) // ".h5"
! Look for WMP data in cross_sections.xml
if (library_present(LIBRARY_WMP, to_lower(nuc % name))) then
filename = library_path(LIBRARY_WMP, to_lower(nuc % name))
else
filename = trim(path_multipole) // trim(zero_padded(nuc % Z, 3)) // &
trim(zero_padded(nuc % A, 3)) // ".h5"
nuc % mp_present = .false.
return
end if
! Check if Multipole library exists and is readable
@ -2605,7 +2322,8 @@ contains
end if
! Display message
call write_message("Loading Windowed Multipole XS from " // filename, 6)
call write_message("Reading " // trim(nuc % name) // " WMP data from " &
// filename, 6)
! Open file and make sure version is sufficient
file_id = file_open(filename, 'r')

View file

@ -12,7 +12,7 @@ module material_header
use sab_header
use simulation_header, only: log_spacing
use stl_vector, only: VectorReal, VectorInt
use string, only: to_str
use string, only: to_str, to_f_string
implicit none
@ -166,34 +166,52 @@ contains
call material_set_fissionable_c(this % ptr, logical(fissionable, C_BOOL))
end subroutine material_set_fissionable
function material_set_density(this, density) result(err)
function material_set_density(this, density, units) result(err)
class(Material), intent(inout) :: this
real(8), intent(in) :: density
character(*), intent(in) :: units
integer :: err
integer :: i
real(8) :: sum_percent
real(8) :: awr
real(8) :: previous_density_gpcc
real(8) :: f
if (allocated(this % atom_density)) then
! Set total density based on value provided
this % density = density
! Determine normalized atom percents
sum_percent = sum(this % atom_density)
this % atom_density(:) = this % atom_density / sum_percent
! Recalculate nuclide atom densities based on given density
this % atom_density(:) = density * this % atom_density
! Calculate density in g/cm^3.
this % density_gpcc = ZERO
do i = 1, this % n_nuclides
awr = nuclides(this % nuclide(i)) % awr
this % density_gpcc = this % density_gpcc &
+ this % atom_density(i) * awr * MASS_NEUTRON / N_AVOGADRO
end do
err = 0
select case (units)
case ('atom/b-cm')
! Set total density based on value provided
this % density = density
! Determine normalized atom percents
sum_percent = sum(this % atom_density)
this % atom_density(:) = this % atom_density / sum_percent
! Recalculate nuclide atom densities based on given density
this % atom_density(:) = density * this % atom_density
! Calculate density in g/cm^3.
this % density_gpcc = ZERO
do i = 1, this % n_nuclides
awr = nuclides(this % nuclide(i)) % awr
this % density_gpcc = this % density_gpcc &
+ this % atom_density(i) * awr * MASS_NEUTRON / N_AVOGADRO
end do
case ('g/cm3', 'g/cc')
! Determine factor by which to change densities
previous_density_gpcc = this % density_gpcc
f = density / previous_density_gpcc
! Update densities
this % density_gpcc = density
this % density = f * this % density
this % atom_density(:) = f * this % atom_density(:)
case default
err = E_INVALID_ARGUMENT
call set_errmsg("Invalid units '" // trim(units) // "' specified.")
end select
else
err = E_ALLOCATE
call set_errmsg("Material atom density array hasn't been allocated.")
@ -738,16 +756,22 @@ contains
end function openmc_material_set_id
function openmc_material_set_density(index, density) result(err) bind(C)
! Set the total density of a material in atom/b-cm
function openmc_material_set_density(index, density, units) result(err) bind(C)
! Set the total density of a material
integer(C_INT32_T), value, intent(in) :: index
real(C_DOUBLE), value, intent(in) :: density
character(kind=C_CHAR), intent(in) :: units(*)
integer(C_INT) :: err
character(:), allocatable :: units_
! Convert C string to Fortran string
units_ = to_f_string(units)
err = E_UNASSIGNED
if (index >= 1 .and. index <= size(materials)) then
associate (m => materials(index))
err = m % set_density(density)
err = m % set_density(density, units_)
end associate
else
err = E_OUT_OF_BOUNDS
@ -794,7 +818,7 @@ contains
m % n_nuclides = n
! Set total density to the sum of the vector
err = m % set_density(sum(density))
err = m % set_density(sum(density), 'atom/b-cm')
! Assign S(a,b) tables
call m % assign_sab_tables()

View file

@ -17,7 +17,7 @@
#include "openmc/error.h"
#include "openmc/math_functions.h"
#include "openmc/random_lcg.h"
#include "openmc/string_functions.h"
#include "openmc/string_utils.h"
namespace openmc {

View file

@ -2,6 +2,7 @@
#include <string>
#include "openmc/cross_sections.h"
#include "openmc/error.h"
#include "openmc/math_functions.h"
@ -109,6 +110,20 @@ void read_mg_cross_sections_header_c(hid_t file_id)
for (int i = 0; i < energy_bins.size() - 1; ++i) {
energy_bin_avg.push_back(0.5*(energy_bins[i] + energy_bins[i+1]));
}
// Add entries into libraries for MG data
auto names = group_names(file_id);
if (names.empty()) {
fatal_error("At least one MGXS data set must be present in mgxs "
"library file!");
}
for (auto& name : names) {
Library lib {};
lib.type_ = Library::Type::neutron;
lib.materials_.push_back(name);
data::libraries.push_back(lib);
}
}
//==============================================================================

View file

@ -6,7 +6,8 @@ module nuclide_header
use algorithm, only: sort, find, binary_search
use constants
use dict_header, only: DictIntInt, DictCharInt
use endf, only: reaction_name, is_fission, is_disappearance
use endf, only: reaction_name, is_fission, is_disappearance, &
is_inelastic_scatter
use endf_header, only: Function1D, Polynomial, Tabulated1D
use error
use hdf5_interface
@ -176,20 +177,6 @@ module nuclide_header
real(C_DOUBLE) :: pair_production ! macroscopic pair production xs
end type MaterialMacroXS
!===============================================================================
! LIBRARY contains data read from a cross_sections.xml file
!===============================================================================
type Library
integer :: type
character(MAX_WORD_LEN), allocatable :: materials(:)
character(MAX_FILE_LEN) :: path
end type Library
! Cross section libraries
type(Library), allocatable :: libraries(:)
type(DictCharInt) :: library_dict
! Nuclear data for each nuclide
type(Nuclide), allocatable, target :: nuclides(:)
integer(C_INT), bind(C) :: n_nuclides
@ -204,8 +191,46 @@ module nuclide_header
real(8) :: energy_min(2) = [ZERO, ZERO]
real(8) :: energy_max(2) = [INFINITY, INFINITY]
interface
function library_present_c(type, name) result(b) bind(C, name='library_present')
import C_INT, C_CHAR, C_BOOL
integer(C_INT), value :: type
character(kind=C_CHAR), intent(in) :: name(*)
logical(C_BOOL) :: b
end function
function library_path_c(type, name) result(path) bind(C, name='library_path')
import C_INT, C_CHAR, C_PTR
integer(C_INT), value :: type
character(kind=C_CHAR), intent(in) :: name(*)
type(C_PTR) :: path
end function
end interface
contains
function library_path(type, name) result(path)
integer, intent(in) :: type
character(len=*), intent(in) :: name
character(MAX_FILE_LEN) :: path
type(C_PTR) :: ptr
character(kind=C_CHAR), pointer :: string(:)
ptr = library_path_c(type, to_c_string(name))
call c_f_pointer(ptr, string, [255])
path = to_f_string(string)
end function
function library_present(type, name) result(b)
integer, intent(in) :: type
character(len=*), intent(in) :: name
logical :: b
b = library_present_c(type, to_c_string(name))
end function
!===============================================================================
! ASSIGN_0K_ELASTIC_SCATTERING
!===============================================================================
@ -216,11 +241,30 @@ contains
integer :: i
real(8) :: xs_cdf_sum
interface
function res_scat_nuclides_empty() result(empty) bind(C)
import C_BOOL
logical(C_BOOL) :: empty
end function
function res_scat_nuclides_size() result(n) bind(C)
import C_INT
integer(C_INT) :: n
end function
function res_scat_nuclides_cmp(i, name) result(b) bind(C)
import C_INT, C_CHAR, C_BOOL
integer(C_INT), value :: i
character(kind=C_CHAR), intent(in) :: name(*)
logical(C_BOOL) :: b
end function
end interface
this % resonant = .false.
if (allocated(res_scat_nuclides)) then
if (.not. res_scat_nuclides_empty()) then
! If resonant nuclides were specified, check the list explicitly
do i = 1, size(res_scat_nuclides)
if (this % name == res_scat_nuclides(i)) then
do i = 1, res_scat_nuclides_size()
if (res_scat_nuclides_cmp(i, to_c_string(this % name))) then
this % resonant = .true.
! Make sure nuclide has 0K data
@ -486,12 +530,7 @@ contains
! Add the reaction index to the scattering array if this is an inelastic
! scatter reaction
if (MTs % data(i) /= N_FISSION .and. MTs % data(i) /= N_F .and. &
MTs % data(i) /= N_NF .and. MTs % data(i) /= N_2NF .and. &
MTs % data(i) /= N_3NF .and. MTs % data(i) < 200 .and. &
MTs % data(i) /= N_LEVEL .and. MTs % data(i) /= ELASTIC .and. &
.not. this % reactions(i) % redundant) then
if (is_inelastic_scatter(MTs % data(i))) then
call index_inelastic_scatter % push_back(i)
end if
@ -653,20 +692,10 @@ contains
end if
end do
! Skip total inelastic level scattering, gas production cross sections
! (MT=200+), etc.
if (rx % MT == N_LEVEL .or. rx % MT == N_NONELASTIC) cycle
! Skip gas production cross sections (MT=200+), etc.
if (rx % MT > N_5N2P .and. rx % MT < N_P0) cycle
! Skip level cross sections if total is available
if (rx % MT >= N_P0 .and. rx % MT <= N_PC .and. find(MTs, N_P) /= -1) cycle
if (rx % MT >= N_D0 .and. rx % MT <= N_DC .and. find(MTs, N_D) /= -1) cycle
if (rx % MT >= N_T0 .and. rx % MT <= N_TC .and. find(MTs, N_T) /= -1) cycle
if (rx % MT >= N_3HE0 .and. rx % MT <= N_3HEC .and. find(MTs, N_3HE) /= -1) cycle
if (rx % MT >= N_A0 .and. rx % MT <= N_AC .and. find(MTs, N_A) /= -1) cycle
if (rx % MT >= N_2N0 .and. rx % MT <= N_2NC .and. find(MTs, N_2N) /= -1) cycle
! Skip redundant reactions, which are used for photon production
! Skip any reaction that has been marked as redundant
if (rx % redundant) cycle
! Add contribution to total cross section
@ -1540,6 +1569,11 @@ contains
subroutine free_memory_nuclide()
integer :: i
interface
subroutine library_clear() bind(C)
end subroutine
end interface
! Deallocate cross section data, listings, and cache
if (allocated(nuclides)) then
! First call the clear routines
@ -1550,10 +1584,8 @@ contains
end if
n_nuclides = 0
if (allocated(libraries)) deallocate(libraries)
call nuclide_dict % clear()
call library_dict % clear()
call library_clear()
end subroutine free_memory_nuclide
@ -1593,11 +1625,11 @@ contains
character(kind=C_CHAR), intent(in) :: name(*)
integer(C_INT) :: err
integer :: i_library
integer :: n
integer(HID_T) :: file_id
integer(HID_T) :: group_id
character(:), allocatable :: name_
character(MAX_FILE_LEN) :: filename
real(8) :: minmax(2) = [ZERO, INFINITY]
type(VectorReal) :: temperature
type(Nuclide), allocatable :: new_nuclides(:)
@ -1607,7 +1639,7 @@ contains
err = 0
if (.not. nuclide_dict % has(to_lower(name_))) then
if (library_dict % has(to_lower(name_))) then
if (library_present(LIBRARY_NEUTRON, to_lower(name_))) then
! allocate extra space in nuclides array
n = n_nuclides
allocate(new_nuclides(n + 1))
@ -1615,10 +1647,10 @@ contains
call move_alloc(FROM=new_nuclides, TO=nuclides)
n = n + 1
i_library = library_dict % get(to_lower(name_))
filename = library_path(LIBRARY_NEUTRON, to_lower(name_))
! Open file and make sure version is sufficient
file_id = file_open(libraries(i_library) % path, 'r')
file_id = file_open(filename, 'r')
call check_data_version(file_id)
! Read nuclide data from HDF5

View file

@ -9,7 +9,7 @@
#include "openmc/geometry.h"
#include "openmc/cell.h"
#include "openmc/material.h"
#include "openmc/string_functions.h"
#include "openmc/string_utils.h"
#include "openmc/mesh.h"
#include "openmc/output.h"
#include "openmc/hdf5_interface.h"

View file

@ -37,7 +37,5 @@ element materials {
}*
}+ &
element cross_sections { xsd:string { maxLength = "255" } }? &
element multipole_library { xsd:string { maxLength = "255" } }?
element cross_sections { xsd:string { maxLength = "255" } }?
}

View file

@ -161,12 +161,5 @@
</data>
</element>
</optional>
<optional>
<element name="multipole_library">
<data type="string">
<param name="maxLength">255</param>
</data>
</element>
</optional>
</interleave>
</element>

View file

@ -101,7 +101,6 @@ module settings
character(MAX_FILE_LEN) :: path_input ! Path to input file
character(MAX_FILE_LEN) :: path_cross_sections = '' ! Path to cross_sections.xml
character(MAX_FILE_LEN) :: path_multipole ! Path to wmp library
character(MAX_FILE_LEN) :: path_state_point ! Path to binary state point
character(MAX_FILE_LEN) :: path_source_point ! Path to binary source point
character(MAX_FILE_LEN) :: path_particle_restart ! Path to particle restart
@ -115,7 +114,6 @@ module settings
integer(C_INT), bind(C) :: res_scat_method ! resonance scattering method
real(C_DOUBLE), bind(C) :: res_scat_energy_min
real(C_DOUBLE), bind(C) :: res_scat_energy_max
character(10), allocatable :: res_scat_nuclides(:)
! Is CMFD active
logical(C_BOOL), bind(C) :: cmfd_run
@ -123,21 +121,4 @@ module settings
! No reduction at end of batch
logical(C_BOOL), bind(C) :: reduce_tallies
contains
!===============================================================================
! FREE_MEMORY_SETTINGS deallocates global arrays defined in this module
!===============================================================================
subroutine free_memory_settings()
interface
subroutine free_memory_settings_c() bind(C)
end subroutine
end interface
if (allocated(res_scat_nuclides)) deallocate(res_scat_nuclides)
call free_memory_settings_c()
end subroutine free_memory_settings
end module settings

View file

@ -63,7 +63,6 @@ bool dagmc {false};
std::string path_cross_sections;
std::string path_input;
std::string path_multipole;
std::string path_output;
std::string path_particle_restart;
std::string path_source;
@ -73,7 +72,7 @@ std::string path_statepoint;
int32_t index_entropy_mesh {-1};
int32_t index_ufs_mesh {-1};
int32_t index_cmfd_mesh {-1};
int32_t n_batches;
int32_t n_inactive {0};
int32_t gen_per_batch {1};
@ -88,6 +87,7 @@ int n_max_batches;
int res_scat_method {RES_SCAT_ARES};
double res_scat_energy_min {0.01};
double res_scat_energy_max {1000.0};
std::vector<std::string> res_scat_nuclides;
int run_mode {-1};
std::unordered_set<int> sourcepoint_batch;
std::unordered_set<int> statepoint_batch;
@ -187,7 +187,7 @@ void read_settings_xml()
using namespace pugi;
// Check if settings.xml exists
std::string filename = std::string(path_input) + "settings.xml";
std::string filename = path_input + "settings.xml";
if (!file_exists(filename)) {
if (run_mode != RUN_MODE_PLOTTING) {
std::stringstream msg;
@ -256,21 +256,6 @@ void read_settings_xml()
path_cross_sections = get_node_value(root, "cross_sections");
}
// Look for deprecated windowed_multipole file in settings.xml
if (run_mode != RUN_MODE_PLOTTING) {
if (check_for_node(root, "multipole_library")) {
warning("Setting multipole_library in settings.xml has been "
"deprecated. The multipole_library is now set in materials.xml and"
" the multipole_library input to materials.xml and the "
"OPENMC_MULTIPOLE_LIBRARY environment variable will take "
"precendent over setting multipole_library in settings.xml.");
path_multipole = get_node_value(root, "multipole_library");
}
if (!ends_with(path_multipole, "/")) {
path_multipole += "/";
}
}
if (!run_CE) {
// Scattering Treatments
if (check_for_node(root, "max_order")) {
@ -749,7 +734,10 @@ void read_settings_xml()
"lower resonance scattering energy bound.");
}
// TODO: Get resonance scattering nuclides
// Get resonance scattering nuclides
if (check_for_node(node_res_scat, "nuclides")) {
res_scat_nuclides = get_node_array<std::string>(node_res_scat, "nuclides");
}
}
// TODO: Get volume calculations
@ -817,22 +805,38 @@ void read_settings_xml()
//==============================================================================
extern "C" {
const char* openmc_path_input() {
bool res_scat_nuclides_empty() {
return settings::res_scat_nuclides.empty();
}
int res_scat_nuclides_size() {
return settings::res_scat_nuclides.size();
}
bool res_scat_nuclides_cmp(int i, const char* name) {
return settings::res_scat_nuclides[i - 1] == name;
}
const char* path_cross_sections_c() {
return settings::path_cross_sections.c_str();
}
const char* path_input_c() {
return settings::path_input.c_str();
}
const char* openmc_path_statepoint() {
const char* path_statepoint_c() {
return settings::path_statepoint.c_str();
}
const char* openmc_path_sourcepoint() {
const char* path_sourcepoint_c() {
return settings::path_sourcepoint.c_str();
}
const char* openmc_path_particle_restart() {
const char* path_particle_restart_c() {
return settings::path_particle_restart.c_str();
}
void free_memory_settings_c() {
void free_memory_settings() {
settings::statepoint_batch.clear();
settings::sourcepoint_batch.clear();
settings::res_scat_nuclides.clear();
}
}

View file

@ -1,40 +0,0 @@
#include "openmc/string_functions.h"
#include <sstream>
namespace openmc {
std::string& strtrim(std::string& s)
{
const char* t = " \t\n\r\f\v";
s.erase(s.find_last_not_of(t) + 1);
s.erase(0, s.find_first_not_of(t));
return s;
}
char* strtrim(char* c_str)
{
std::string std_str;
std_str.assign(c_str);
strtrim(std_str);
int length = std_str.copy(c_str, std_str.size());
c_str[length] = '\0';
return c_str;
}
void to_lower(std::string& str)
{
for (int i = 0; i < str.size(); i++) str[i] = std::tolower(str[i]);
}
int word_count(std::string const& str)
{
std::stringstream stream(str);
std::string dum;
int count = 0;
while (stream >> dum) {count++;}
return count;
}
} // namespace openmc

78
src/string_utils.cpp Normal file
View file

@ -0,0 +1,78 @@
#include "openmc/string_utils.h"
#include <algorithm> // for equal
#include <cctype> // for tolower, isspace
#include <sstream>
namespace openmc {
std::string& strtrim(std::string& s)
{
const char* t = " \t\n\r\f\v";
s.erase(s.find_last_not_of(t) + 1);
s.erase(0, s.find_first_not_of(t));
return s;
}
char* strtrim(char* c_str)
{
std::string std_str;
std_str.assign(c_str);
strtrim(std_str);
int length = std_str.copy(c_str, std_str.size());
c_str[length] = '\0';
return c_str;
}
void to_lower(std::string& str)
{
for (int i = 0; i < str.size(); i++) str[i] = std::tolower(str[i]);
}
int word_count(std::string const& str)
{
std::stringstream stream(str);
std::string dum;
int count = 0;
while (stream >> dum) {count++;}
return count;
}
std::vector<std::string> split(const std::string& in)
{
std::vector<std::string> out;
for (int i = 0; i < in.size(); ) {
// Increment i until we find a non-whitespace character.
if (std::isspace(in[i])) {
i++;
} else {
// Find the next whitespace character at j.
int j = i + 1;
while (j < in.size() && std::isspace(in[j]) == 0) {j++;}
// Push-back everything between i and j.
out.push_back(in.substr(i, j-i));
i = j + 1; // j is whitespace so leapfrog to j+1
}
}
return out;
}
bool ends_with(const std::string& value, const std::string& ending)
{
if (ending.size() > value.size()) return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
bool starts_with(const std::string& value, const std::string& beginning)
{
if (beginning.size() > value.size()) return false;
return std::equal(beginning.begin(), beginning.end(), value.begin());
}
} // namespace openmc

View file

@ -8,7 +8,7 @@
#include "openmc/error.h"
#include "openmc/hdf5_interface.h"
#include "openmc/xml_interface.h"
#include "openmc/string_functions.h"
#include "openmc/string_utils.h"
namespace openmc {

View file

@ -1 +1 @@
bd3fd10177bc0c7b8542f15228decf8608de013872d201e6ae885cf9b5b6d7516ddb32044ee2f7fd5b207e7d37d5ce3f03e347a2e850953bba4fc26b150c89d2
4b75e203d06d0fc1b4c4dfcb8c180d6f3df8fa2bc44e9775b59bbfd8f7a3785f956f9a9f301526f69c0f8a963ce2e553e0c62c7f6c696656ce1d47b415af6076

View file

@ -438,7 +438,7 @@ cmfd balance
0.000000E+00
0.000000E+00
4.009062E-03
4.869662E-03
4.869661E-03
2.997290E-03
2.711191E-03
1.688329E-03

View file

@ -1,5 +1,5 @@
d_material,d_nuclide,d_variable,score,mean,std. dev.
3,,density,flux,-4.7291290e+00,8.8503902e-01
3,,density,flux,-4.7291290e+00,8.8503901e-01
3,,density,flux,-1.0533184e+01,3.0256001e+00
1,,density,flux,-4.9634223e-01,1.3190338e-01
1,,density,flux,-4.7458622e-01,5.6426916e-02
@ -11,16 +11,16 @@ d_material,d_nuclide,d_variable,score,mean,std. dev.
1,,temperature,flux,-4.4294257e-04,5.4687257e-04
3,,density,total,-1.5555916e+00,5.3353204e-01
3,,density,absorption,1.4925823e-01,2.3501173e-01
3,,density,scatter,-1.7048498e+00,3.3363896e-01
3,,density,fission,1.3210039e-01,1.6377610e-01
3,,density,scatter,-1.7048499e+00,3.3363896e-01
3,,density,fission,1.3210038e-01,1.6377610e-01
3,,density,nu-fission,3.1732288e-01,3.9893191e-01
3,,density,total,1.4744448e-01,2.0435075e-01
3,,density,absorption,1.6665433e-01,1.9696442e-01
3,,density,scatter,-1.9209851e-02,7.8974770e-03
3,,density,scatter,-1.9209851e-02,7.8974769e-03
3,,density,fission,1.4878594e-01,1.6616312e-01
3,,density,nu-fission,3.6225815e-01,4.0486140e-01
3,,density,total,1.2662462e+01,6.2596594e+00
3,,density,absorption,2.2864288e-01,1.3031728e-01
3,,density,absorption,2.2864287e-01,1.3031728e-01
3,,density,scatter,1.2433820e+01,6.1294912e+00
3,,density,fission,0.0000000e+00,0.0000000e+00
3,,density,nu-fission,0.0000000e+00,0.0000000e+00
@ -31,17 +31,17 @@ d_material,d_nuclide,d_variable,score,mean,std. dev.
3,,density,nu-fission,0.0000000e+00,0.0000000e+00
1,,density,total,2.9404312e-01,7.0116815e-02
1,,density,absorption,-1.1851195e-03,1.6943078e-03
1,,density,scatter,2.9522824e-01,6.8519873e-02
1,,density,fission,-4.4865588e-03,2.3660449e-03
1,,density,scatter,2.9522824e-01,6.8519874e-02
1,,density,fission,-4.4865589e-03,2.3660449e-03
1,,density,nu-fission,-1.0266898e-02,5.7956130e-03
1,,density,total,-3.6990351e-03,3.5138725e-03
1,,density,total,-3.6990352e-03,3.5138725e-03
1,,density,absorption,-7.0064347e-03,2.7205092e-03
1,,density,scatter,3.3073996e-03,7.9802045e-04
1,,density,fission,-6.3630708e-03,2.3832611e-03
1,,density,scatter,3.3073996e-03,7.9802046e-04
1,,density,fission,-6.3630709e-03,2.3832611e-03
1,,density,nu-fission,-1.5466339e-02,5.8086647e-03
1,,density,total,-5.5743331e-01,6.1625011e-02
1,,density,absorption,-9.1430498e-03,4.0831822e-03
1,,density,scatter,-5.4829026e-01,5.7756112e-02
1,,density,absorption,-9.1430499e-03,4.0831822e-03
1,,density,scatter,-5.4829026e-01,5.7756113e-02
1,,density,fission,0.0000000e+00,0.0000000e+00
1,,density,nu-fission,0.0000000e+00,0.0000000e+00
1,,density,total,0.0000000e+00,0.0000000e+00
@ -50,17 +50,17 @@ d_material,d_nuclide,d_variable,score,mean,std. dev.
1,,density,fission,0.0000000e+00,0.0000000e+00
1,,density,nu-fission,0.0000000e+00,0.0000000e+00
1,O16,nuclide_density,total,3.9360816e+01,6.1390337e+00
1,O16,nuclide_density,absorption,-6.8169613e-01,4.5302455e-01
1,O16,nuclide_density,absorption,-6.8169613e-01,4.5302456e-01
1,O16,nuclide_density,scatter,4.0042512e+01,6.4069240e+00
1,O16,nuclide_density,fission,-6.1275244e-01,2.5764187e-01
1,O16,nuclide_density,nu-fission,-1.5090099e+00,6.3048791e-01
1,O16,nuclide_density,total,-7.5872288e-01,3.4843447e-01
1,O16,nuclide_density,absorption,-6.7382098e-01,3.1002267e-01
1,O16,nuclide_density,absorption,-6.7382099e-01,3.1002267e-01
1,O16,nuclide_density,scatter,-8.4901894e-02,6.5286818e-02
1,O16,nuclide_density,fission,-5.5597011e-01,2.7085418e-01
1,O16,nuclide_density,nu-fission,-1.3555055e+00,6.6014209e-01
1,O16,nuclide_density,total,-1.5539605e+01,2.3345398e+01
1,O16,nuclide_density,absorption,-8.5880168e-02,5.0677339e-01
1,O16,nuclide_density,total,-1.5539606e+01,2.3345398e+01
1,O16,nuclide_density,absorption,-8.5880170e-02,5.0677339e-01
1,O16,nuclide_density,scatter,-1.5453725e+01,2.2838892e+01
1,O16,nuclide_density,fission,0.0000000e+00,0.0000000e+00
1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00
@ -78,10 +78,10 @@ d_material,d_nuclide,d_variable,score,mean,std. dev.
1,U235,nuclide_density,absorption,3.8860811e+02,3.5290173e+01
1,U235,nuclide_density,scatter,1.0782853e+02,1.9206965e+00
1,U235,nuclide_density,fission,3.0827647e+02,2.4266512e+01
1,U235,nuclide_density,nu-fission,7.5228268e+02,5.9109738e+01
1,U235,nuclide_density,nu-fission,7.5228267e+02,5.9109738e+01
1,U235,nuclide_density,total,-4.7231732e+03,7.5353357e+02
1,U235,nuclide_density,absorption,-1.1580370e+02,1.8531790e+01
1,U235,nuclide_density,scatter,-4.6073695e+03,7.3502263e+02
1,U235,nuclide_density,scatter,-4.6073695e+03,7.3502264e+02
1,U235,nuclide_density,fission,0.0000000e+00,0.0000000e+00
1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00
1,U235,nuclide_density,total,0.0000000e+00,0.0000000e+00
@ -109,11 +109,11 @@ d_material,d_nuclide,d_variable,score,mean,std. dev.
1,,temperature,scatter,0.0000000e+00,0.0000000e+00
1,,temperature,fission,0.0000000e+00,0.0000000e+00
1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00
3,,density,absorption,3.1512672e-02,2.4627803e-01
3,,density,absorption,3.1512670e-02,2.4627803e-01
3,,density,absorption,1.1452915e-01,1.5733776e-01
1,,density,absorption,-1.4010827e-03,5.7414887e-03
1,,density,absorption,-8.9116087e-03,7.6054344e-03
1,O16,nuclide_density,absorption,-1.0238428e+00,3.5596763e-01
1,O16,nuclide_density,absorption,-1.0238429e+00,3.5596764e-01
1,O16,nuclide_density,absorption,-5.4386638e-01,6.3275232e-01
1,U235,nuclide_density,absorption,1.9740455e+02,1.1770740e+02
1,U235,nuclide_density,absorption,-1.3873202e+02,3.0030411e+01
@ -139,7 +139,7 @@ d_material,d_nuclide,d_variable,score,mean,std. dev.
1,,density,scatter,-1.4155379e-02,7.8989014e-03
1,,density,nu-fission,0.0000000e+00,0.0000000e+00
1,,density,scatter,1.0449664e-03,5.7043392e-04
1,,density,nu-fission,-1.3723982e-02,1.5246898e-02
1,,density,nu-fission,-1.3723983e-02,1.5246898e-02
1,,density,scatter,3.0959958e-01,5.7651589e-02
1,,density,nu-fission,-1.9529210e-02,1.4804175e-02
1,,density,scatter,5.1063052e-04,1.7748731e-03
@ -153,7 +153,7 @@ d_material,d_nuclide,d_variable,score,mean,std. dev.
1,,density,scatter,0.0000000e+00,0.0000000e+00
1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00
1,O16,nuclide_density,scatter,1.4017611e-01,9.5507870e-02
1,O16,nuclide_density,nu-fission,-8.8199870e-01,1.6570982e+00
1,O16,nuclide_density,nu-fission,-8.8199871e-01,1.6570982e+00
1,O16,nuclide_density,scatter,-1.5442745e-01,1.3136597e-01
1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00
1,O16,nuclide_density,scatter,0.0000000e+00,0.0000000e+00

View file

@ -113,9 +113,6 @@ class DiffTallyTestHarness(PyAPITestHarness):
return df.to_csv(None, columns=cols, index=False, float_format='%.7e')
@pytest.mark.skipif('OPENMC_MULTIPOLE_LIBRARY' not in os.environ,
reason='OPENMC_MULTIPOLE_LIBRARY environment variable '
'must be set')
def test_diff_tally():
harness = DiffTallyTestHarness('statepoint.3.h5')
harness.main()

View file

@ -1 +1 @@
a1f6ccf0bef1075ffc12e7fa058a44c83360801ba6e2c76f00e1bd7e9543fe1832777b122321dcb1cfb5fc1165ce84f711a65ca83903dd57cd09652e003daf62
11755ecac8355b5e79384f5d72974e618b6f95500c0a5718c01bb340c5d1c8ceafc33de65b9e94b7e9d78f16ec209f8a0fdf6a531eab5430657688d0125db7ef

View file

@ -1 +1 @@
46950c046648faaa5ff3cb7b4fdd03667ae3c6da96a7ed8121761291de452cf88481f53e967ed52407d77d90109ae24839967a22ae216531a0e1491f5051ea72
cc306dfd3e3669827cb2f3bdc38005c0616f6faecb9277f3b0f869fdecf826ae662c65d67a402705956f100d2e13c7c11332364fa41ccc2e215ab100709b627f

View file

@ -1,2 +1,2 @@
k-combined:
2.546817E-01 1.509389E-02
2.562946E-01 1.530982E-02

View file

@ -1,2 +1,2 @@
k-combined:
1.006646E+00 1.477915E-02
9.877395E-01 1.744626E-02

View file

@ -13,7 +13,7 @@
material group in nuclide mean std. dev.
0 1 1 total 0.090649 0.00641
material group in nuclide mean std. dev.
0 1 1 total 7.137954e+06 507363.468222
0 1 1 total 7.137954e+06 507363.467231
material group in nuclide mean std. dev.
0 1 1 total 0.388721 0.01783
material group in nuclide mean std. dev.

View file

@ -12,8 +12,8 @@
0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13... 1 total 0.037577 0.001487
sum(distribcell) group in nuclide mean std. dev.
0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13... 1 total 0.092377 0.003628
sum(distribcell) group in nuclide mean std. dev.
0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13... 1 total 7.276706e+06 287579.24765
sum(distribcell) group in nuclide mean std. dev.
0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13... 1 total 7.276706e+06 287579.247699
sum(distribcell) group in nuclide mean std. dev.
0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13... 1 total 0.390797 0.008717
sum(distribcell) group in nuclide mean std. dev.

View file

@ -1,35 +1,35 @@
domain=1 type=total
[4.14825464e-01 6.60169863e-01]
[2.27929105e-02 4.75188999e-02]
[2.27929104e-02 4.75189000e-02]
domain=1 type=transport
[3.63092031e-01 6.44850709e-01]
[2.38384843e-02 4.76746408e-02]
[2.38384842e-02 4.76746410e-02]
domain=1 type=nu-transport
[3.63092031e-01 6.44850709e-01]
[2.38384843e-02 4.76746408e-02]
[2.38384842e-02 4.76746410e-02]
domain=1 type=absorption
[2.74078431e-02 2.64510714e-01]
[2.69249666e-03 2.33670618e-02]
domain=1 type=capture
[1.98445483e-02 7.17193458e-02]
[1.98445482e-02 7.17193458e-02]
[2.64330389e-03 2.52078411e-02]
domain=1 type=fission
[7.56329483e-03 1.92791369e-01]
[5.08483896e-04 1.71059103e-02]
[7.56329484e-03 1.92791369e-01]
[5.08483893e-04 1.71059103e-02]
domain=1 type=nu-fission
[1.94317397e-02 4.69774728e-01]
[1.32297611e-03 4.16819716e-02]
[1.32297610e-03 4.16819717e-02]
domain=1 type=kappa-fission
[1.47456979e+06 3.72868925e+07]
[9.92353629e+04 3.30837549e+06]
[9.92353624e+04 3.30837549e+06]
domain=1 type=scatter
[3.87417621e-01 3.95659148e-01]
[2.06257343e-02 2.51250447e-02]
[2.06257342e-02 2.51250448e-02]
domain=1 type=nu-scatter
[3.85188361e-01 4.12389370e-01]
[2.69456191e-02 1.54252759e-02]
domain=1 type=scatter matrix
[[[3.84199430e-01 5.18702806e-02 2.00688439e-02 9.47771503e-03]
[[[3.84199430e-01 5.18702806e-02 2.00688439e-02 9.47771502e-03]
[9.88930322e-04 -2.07234582e-04 -1.03366173e-04 2.34290606e-04]]
[[9.24639842e-04 -7.67704913e-04 4.93788836e-04 -1.71497217e-04]
@ -40,7 +40,7 @@ domain=1 type=scatter matrix
[[9.24883397e-04 7.67907131e-04 4.93918903e-04 1.71542390e-04]
[1.52449343e-02 4.50172764e-03 1.05507486e-02 1.04381870e-02]]]
domain=1 type=nu-scatter matrix
[[[3.84199430e-01 5.18702806e-02 2.00688439e-02 9.47771503e-03]
[[[3.84199430e-01 5.18702806e-02 2.00688439e-02 9.47771502e-03]
[9.88930322e-04 -2.07234582e-04 -1.03366173e-04 2.34290606e-04]]
[[9.24639842e-04 -7.67704913e-04 4.93788836e-04 -1.71497217e-04]
@ -59,7 +59,7 @@ domain=1 type=nu-fission matrix
[[2.01424221e-02 0.00000000e+00]
[4.54366342e-01 0.00000000e+00]]
[[3.14909051e-03 0.00000000e+00]
[2.74255162e-02 0.00000000e+00]]
[2.74255160e-02 0.00000000e+00]]
domain=1 type=scatter probability matrix
[[9.97432606e-01 2.56739409e-03]
[2.24215247e-03 9.97757848e-01]]
@ -71,52 +71,52 @@ domain=1 type=consistent scatter matrix
[[8.87128136e-04 -7.36559899e-04 4.73756321e-04 -1.64539748e-04]
[3.94772020e-01 1.58130798e-02 6.11300510e-03 -1.00731826e-02]]]
[[[3.66286904e-02 7.76748968e-03 3.13767806e-03 2.32683668e-03]
[4.89318749e-04 1.50458419e-04 1.85500930e-04 1.29783344e-04]]
[[[3.66286904e-02 7.76748967e-03 3.13767805e-03 2.32683668e-03]
[4.89318749e-04 1.50458419e-04 1.85500930e-04 1.29783343e-04]]
[[8.89289900e-04 7.38354757e-04 4.74910776e-04 1.64940700e-04]
[2.98710064e-02 4.44330993e-03 1.01307463e-02 1.00367467e-02]]]
[2.98710065e-02 4.44330993e-03 1.01307463e-02 1.00367467e-02]]]
domain=1 type=consistent nu-scatter matrix
[[[3.86422967e-01 5.21704775e-02 2.01849914e-02 9.53256688e-03]
[9.94653712e-04 -2.08433942e-04 -1.03964400e-04 2.35646553e-04]]
[[8.87128136e-04 -7.36559899e-04 4.73756321e-04 -1.64539748e-04]
[3.94772020e-01 1.58130798e-02 6.11300510e-03 -1.00731826e-02]]]
[[[4.75627021e-02 8.78140568e-03 3.51522200e-03 2.44425169e-03]
[[[4.75627021e-02 8.78140568e-03 3.51522199e-03 2.44425169e-03]
[8.40606499e-04 2.07733706e-04 1.98782933e-04 2.07523215e-04]]
[[1.53780011e-03 1.27679627e-03 8.21237084e-04 2.85222881e-04]
[3.39988352e-02 4.49065920e-03 1.01338659e-02 1.00452944e-02]]]
[3.39988353e-02 4.49065920e-03 1.01338659e-02 1.00452944e-02]]]
domain=1 type=chi
[1.00000000e+00 0.00000000e+00]
[4.60705493e-02 0.00000000e+00]
[4.60705491e-02 0.00000000e+00]
domain=1 type=chi-prompt
[1.00000000e+00 0.00000000e+00]
[5.14714845e-02 0.00000000e+00]
[5.14714842e-02 0.00000000e+00]
domain=1 type=inverse-velocity
[5.70932437e-08 2.85573948e-06]
[4.68793810e-09 2.44216368e-07]
[4.68793809e-09 2.44216369e-07]
domain=1 type=prompt-nu-fission
[1.92392209e-02 4.66718979e-01]
[1.30950644e-03 4.14108424e-02]
[1.30950644e-03 4.14108425e-02]
domain=1 type=prompt-nu-fission matrix
[[2.01424221e-02 0.00000000e+00]
[4.45819055e-01 0.00000000e+00]]
[4.45819054e-01 0.00000000e+00]]
[[3.14909051e-03 0.00000000e+00]
[2.86750878e-02 0.00000000e+00]]
[2.86750876e-02 0.00000000e+00]]
domain=1 type=delayed-nu-fission
[[4.31687649e-06 1.06974147e-04]
[2.69760050e-05 5.52167849e-04]
[2.84366794e-05 5.27147626e-04]
[7.42603126e-05 1.18190938e-03]
[4.14908415e-05 4.84567103e-04]
[1.70015984e-05 2.02983423e-04]]
[[2.89748553e-07 9.49155601e-06]
[1.85003751e-06 4.89925095e-05]
[1.97097930e-06 4.67725251e-05]
[5.22610330e-06 1.04867938e-04]
[2.99830756e-06 4.29944539e-05]
[1.22654681e-06 1.80102228e-05]]
[1.70015984e-05 2.02983424e-04]]
[[2.89748551e-07 9.49155602e-06]
[1.85003750e-06 4.89925096e-05]
[1.97097929e-06 4.67725252e-05]
[5.22610328e-06 1.04867938e-04]
[2.99830754e-06 4.29944540e-05]
[1.22654681e-06 1.80102229e-05]]
domain=1 type=chi-delayed
[[0.00000000e+00 0.00000000e+00]
[1.00000000e+00 0.00000000e+00]
@ -136,13 +136,13 @@ domain=1 type=beta
[1.46341397e-03 1.12212853e-03]
[3.82159878e-03 2.51590670e-03]
[2.13520982e-03 1.03148823e-03]
[8.74939593e-04 4.32086725e-04]]
[[1.80847602e-05 2.46946655e-05]
[8.74939592e-04 4.32086725e-04]]
[[1.80847601e-05 2.46946655e-05]
[1.14688936e-04 1.27466313e-04]
[1.21787672e-04 1.21690467e-04]
[3.21434953e-04 2.72840272e-04]
[1.82980531e-04 1.11860871e-04]
[7.48900067e-05 4.68581181e-05]]
[1.21787671e-04 1.21690467e-04]
[3.21434951e-04 2.72840272e-04]
[1.82980530e-04 1.11860871e-04]
[7.48900063e-05 4.68581181e-05]]
domain=1 type=decay-rate
[[1.34450193e-02 1.33360001e-02]
[3.20638663e-02 3.27389978e-02]
@ -150,12 +150,12 @@ domain=1 type=decay-rate
[3.15269336e-01 3.02780066e-01]
[8.89232587e-01 8.49490287e-01]
[2.98940409e+00 2.85300088e+00]]
[[1.08439456e-03 1.44623725e-03]
[2.65795039e-03 3.55041661e-03]
[1.02955037e-02 1.30981202e-02]
[2.71748572e-02 3.28353145e-02]
[7.93682892e-02 9.21238900e-02]
[2.66253284e-01 3.09396760e-01]]
[[1.08439455e-03 1.44623725e-03]
[2.65795038e-03 3.55041661e-03]
[1.02955036e-02 1.30981202e-02]
[2.71748571e-02 3.28353145e-02]
[7.93682889e-02 9.21238900e-02]
[2.66253283e-01 3.09396760e-01]]
domain=1 type=delayed-nu-fission matrix
[[[0.00000000e+00 0.00000000e+00]
[0.00000000e+00 0.00000000e+00]]
@ -178,7 +178,7 @@ domain=1 type=delayed-nu-fission matrix
[0.00000000e+00 0.00000000e+00]]
[[0.00000000e+00 0.00000000e+00]
[1.56094522e-03 0.00000000e+00]]
[1.56094521e-03 0.00000000e+00]]
[[0.00000000e+00 0.00000000e+00]
[1.18610370e-03 0.00000000e+00]]
@ -192,20 +192,20 @@ domain=1 type=delayed-nu-fission matrix
[[0.00000000e+00 0.00000000e+00]
[0.00000000e+00 0.00000000e+00]]]
domain=2 type=total
[3.13737666e-01 3.00821380e-01]
[1.55819223e-02 2.80524816e-02]
[3.13737667e-01 3.00821380e-01]
[1.55819228e-02 2.80524816e-02]
domain=2 type=transport
[2.75508079e-01 3.12035015e-01]
[1.77418855e-02 3.23843473e-02]
[1.77418859e-02 3.23843473e-02]
domain=2 type=nu-transport
[2.75508079e-01 3.12035015e-01]
[1.77418855e-02 3.23843473e-02]
[1.77418859e-02 3.23843473e-02]
domain=2 type=absorption
[1.57499139e-03 5.40037826e-03]
[3.22547919e-04 6.18139027e-04]
[1.57499139e-03 5.40037825e-03]
[3.22547917e-04 6.18139027e-04]
domain=2 type=capture
[1.57499139e-03 5.40037826e-03]
[3.22547919e-04 6.18139027e-04]
[1.57499139e-03 5.40037825e-03]
[3.22547917e-04 6.18139027e-04]
domain=2 type=fission
[0.00000000e+00 0.00000000e+00]
[0.00000000e+00 0.00000000e+00]
@ -217,7 +217,7 @@ domain=2 type=kappa-fission
[0.00000000e+00 0.00000000e+00]
domain=2 type=scatter
[3.12162675e-01 2.95421002e-01]
[1.53219430e-02 2.74455213e-02]
[1.53219435e-02 2.74455213e-02]
domain=2 type=nu-scatter
[3.10120713e-01 2.96264249e-01]
[3.37881037e-02 4.37922226e-02]
@ -264,7 +264,7 @@ domain=2 type=consistent scatter matrix
[[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]
[2.95421002e-01 -1.11817183e-02 8.81141444e-03 -3.26075959e-03]]]
[[[3.72534018e-02 8.74305413e-03 4.83468235e-03 3.77642682e-03]
[[[3.72534020e-02 8.74305414e-03 4.83468236e-03 3.77642683e-03]
[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]]
[[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]
@ -275,7 +275,7 @@ domain=2 type=consistent nu-scatter matrix
[[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]
[2.95421002e-01 -1.11817183e-02 8.81141444e-03 -3.26075959e-03]]]
[[[5.04070427e-02 9.69345877e-03 5.34169555e-03 3.87580585e-03]
[[[5.04070429e-02 9.69345878e-03 5.34169556e-03 3.87580585e-03]
[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]]
[[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]
@ -287,8 +287,8 @@ domain=2 type=chi-prompt
[0.00000000e+00 0.00000000e+00]
[0.00000000e+00 0.00000000e+00]
domain=2 type=inverse-velocity
[5.99597929e-08 2.98549016e-06]
[4.55308445e-09 3.41701982e-07]
[5.99597928e-08 2.98549016e-06]
[4.55308451e-09 3.41701982e-07]
domain=2 type=prompt-nu-fission
[0.00000000e+00 0.00000000e+00]
[0.00000000e+00 0.00000000e+00]
@ -385,8 +385,8 @@ domain=2 type=delayed-nu-fission matrix
[[0.00000000e+00 0.00000000e+00]
[0.00000000e+00 0.00000000e+00]]]
domain=3 type=total
[6.64572195e-01 2.05238389e+00]
[3.12147473e-02 2.24342891e-01]
[6.64572194e-01 2.05238389e+00]
[3.12147473e-02 2.24342890e-01]
domain=3 type=transport
[2.83322749e-01 1.49973953e+00]
[3.52061127e-02 2.30902118e-01]
@ -394,11 +394,11 @@ domain=3 type=nu-transport
[2.83322749e-01 1.49973953e+00]
[3.52061127e-02 2.30902118e-01]
domain=3 type=absorption
[6.90399495e-04 3.16872549e-02]
[4.41475663e-05 3.74655831e-03]
[6.90399488e-04 3.16872537e-02]
[4.41475703e-05 3.74655812e-03]
domain=3 type=capture
[6.90399495e-04 3.16872549e-02]
[4.41475663e-05 3.74655831e-03]
[6.90399488e-04 3.16872537e-02]
[4.41475703e-05 3.74655812e-03]
domain=3 type=fission
[0.00000000e+00 0.00000000e+00]
[0.00000000e+00 0.00000000e+00]
@ -418,24 +418,24 @@ domain=3 type=scatter matrix
[[[6.39901439e-01 3.81167422e-01 1.52391887e-01 9.14802163e-03]
[3.13677176e-02 8.75772258e-03 -2.56790088e-03 -3.78480261e-03]]
[[4.43343102e-04 3.99960386e-04 3.19562684e-04 2.13846954e-04]
[2.03494484e+00 5.09940477e-01 1.11174601e-01 2.49884339e-02]]]
[[[2.47091210e-02 1.62432638e-02 8.15627712e-03 3.88856186e-03]
[[4.43343102e-04 3.99960385e-04 3.19562684e-04 2.13846954e-04]
[2.03494484e+00 5.09940476e-01 1.11174601e-01 2.49884339e-02]]]
[[[2.47091210e-02 1.62432637e-02 8.15627711e-03 3.88856186e-03]
[1.72811278e-03 9.25670435e-04 1.01398468e-03 8.17075512e-04]]
[[4.44850361e-04 4.01320154e-04 3.20649120e-04 2.14573982e-04]
[2.57799870e-01 5.12359026e-02 1.30198161e-02 8.31235197e-03]]]
[2.57799870e-01 5.12359026e-02 1.30198161e-02 8.31235196e-03]]]
domain=3 type=nu-scatter matrix
[[[6.39901439e-01 3.81167422e-01 1.52391887e-01 9.14802163e-03]
[3.13677176e-02 8.75772258e-03 -2.56790088e-03 -3.78480261e-03]]
[[4.43343102e-04 3.99960386e-04 3.19562684e-04 2.13846954e-04]
[2.03494484e+00 5.09940477e-01 1.11174601e-01 2.49884339e-02]]]
[[[2.47091210e-02 1.62432638e-02 8.15627712e-03 3.88856186e-03]
[[4.43343102e-04 3.99960385e-04 3.19562684e-04 2.13846954e-04]
[2.03494484e+00 5.09940476e-01 1.11174601e-01 2.49884339e-02]]]
[[[2.47091210e-02 1.62432637e-02 8.15627711e-03 3.88856186e-03]
[1.72811278e-03 9.25670435e-04 1.01398468e-03 8.17075512e-04]]
[[4.44850361e-04 4.01320154e-04 3.20649120e-04 2.14573982e-04]
[2.57799870e-01 5.12359026e-02 1.30198161e-02 8.31235197e-03]]]
[2.57799870e-01 5.12359026e-02 1.30198161e-02 8.31235196e-03]]]
domain=3 type=multiplicity matrix
[[1.00000000e+00 1.00000000e+00]
[1.00000000e+00 1.00000000e+00]]
@ -469,7 +469,7 @@ domain=3 type=consistent nu-scatter matrix
[[4.40143026e-04 3.97073448e-04 3.17256062e-04 2.12303394e-04]
[2.02025649e+00 5.06259696e-01 1.10372136e-01 2.48080660e-02]]]
[[[4.52974133e-02 2.78247077e-02 1.21478698e-02 3.88422859e-03]
[3.06407542e-03 1.15855775e-03 1.02420876e-03 8.64382873e-04]]
[3.06407542e-03 1.15855774e-03 1.02420876e-03 8.64382873e-04]]
[[7.65033031e-04 6.90171798e-04 5.51437493e-04 3.69014387e-04]
[4.46600759e-01 1.04874946e-01 2.38091367e-02 9.39676938e-03]]]

View file

@ -42,10 +42,10 @@
3 2 2 1 1 total 0.020469 0.002617
mesh 1 group in nuclide mean std. dev.
x y z
0 1 1 1 1 total 2.177345e+06 589804.299388
2 1 2 1 1 total 1.404096e+06 236476.851953
1 2 1 1 1 total 1.413154e+06 347806.623417
3 2 2 1 1 total 1.608259e+06 206502.707865
0 1 1 1 1 total 2.177345e+06 589804.301157
2 1 2 1 1 total 1.404096e+06 236476.852674
1 2 1 1 1 total 1.413154e+06 347806.623478
3 2 2 1 1 total 1.608259e+06 206502.707123
mesh 1 group in nuclide mean std. dev.
x y z
0 1 1 1 1 total 0.735256 0.080216

View file

@ -130,7 +130,7 @@
0 1 2 2 total 0.000000 0.000000
material delayedgroup group in nuclide mean std. dev.
1 1 1 1 total 0.000004 2.897486e-07
3 1 2 1 total 0.000027 1.850038e-06
3 1 2 1 total 0.000027 1.850037e-06
5 1 3 1 total 0.000028 1.970979e-06
7 1 4 1 total 0.000074 5.226103e-06
9 1 5 1 total 0.000041 2.998308e-06
@ -325,7 +325,7 @@
1 2 1 total 0.0 0.0
0 2 2 total 0.0 0.0
material group in nuclide mean std. dev.
1 2 1 total 5.995979e-08 4.553084e-09
1 2 1 total 5.995979e-08 4.553085e-09
0 2 2 total 2.985490e-06 3.417020e-07
material group in nuclide mean std. dev.
1 2 1 total 0.0 0.0

View file

@ -1 +1 @@
0edd3036c0b5b1eebad90dc8fba25006f14745ceb51dd109e70d0c610d66071f32128facdbc6d4e5077534fe96fff9a8e0ddeefb4a18d6c578f8e805bab7aa22
185e6f1f7ba94b0cdfae5b2519865efec84055d341bd490b856f9786ef1c91a3cb007d6b22811ffa30d4665256aad8a2982548e6c96e8d8d9c5f569475e52cfe

View file

@ -74,9 +74,6 @@ class MultipoleTestHarness(PyAPITestHarness):
return outstr
@pytest.mark.skipif('OPENMC_MULTIPOLE_LIBRARY' not in os.environ,
reason='OPENMC_MULTIPOLE_LIBRARY environment variable '
'must be set')
def test_multipole():
model = make_model()
harness = MultipoleTestHarness('statepoint.5.h5', model)

View file

@ -1,2 +1,2 @@
k-combined:
1.040109E+00 6.527468E-02
1.040109E+00 6.527466E-02

View file

@ -1 +1 @@
8cf1936c565c6a09bffe2f7a0623ded1405bae37c1de8159551e64b86ca4f6bce82890a630b9428bcf8353f6de8e5cfc1f1a4263fd51a1c6b5cddb0a9c2ff368
aa7f79718620c122e3a13bfa0e200a41b642b09a5d10a6e43e1584181b0314fbeb73c165fe55ddd34c1e9546e381019dd8e3889ca7d99bfe1ab489631bec15d1

View file

@ -1 +1 @@
c8fb043c5321e698040544dbb0baa9ce82df0e189738fb6013b4f3ff7e05a989a7a59b9b55034b8c9de6bc604ba9f969dc08ad2752fc74da205c19ff5974c9a2
eac8fb56a8146b9e186ac9fb003753f4a0a18d4159d10e6fa51da4856baef66a10a0f5fb10c5727b51c6e44d81c147a8a7348ad9c9f7119a6ec33e0361082376

View file

@ -105,6 +105,9 @@ def test_material(capi_init):
m.volume = 10.0
assert m.volume == 10.0
with pytest.raises(exc.InvalidArgumentError):
m.set_density(1.0, 'goblins')
rho = 2.25e-2
m.set_density(rho)
assert sum(m.densities) == pytest.approx(rho)

View file

@ -1,25 +1,23 @@
import os
import pathlib
import numpy as np
import pytest
import openmc.data
pytestmark = pytest.mark.skipif(
'OPENMC_MULTIPOLE_LIBRARY' not in os.environ,
reason='OPENMC_MULTIPOLE_LIBRARY environment variable must be set')
@pytest.fixture(scope='module')
def u235():
directory = os.environ['OPENMC_MULTIPOLE_LIBRARY']
filename = os.path.join(directory, '092235.h5')
return openmc.data.WindowedMultipole.from_hdf5(filename)
directory = pathlib.Path(os.environ['OPENMC_CROSS_SECTIONS']).parent
u235 = directory / 'wmp' / '092235.h5'
return openmc.data.WindowedMultipole.from_hdf5(u235)
@pytest.fixture(scope='module')
def b10():
directory = os.environ['OPENMC_MULTIPOLE_LIBRARY']
filename = os.path.join(directory, '005010.h5')
return openmc.data.WindowedMultipole.from_hdf5(filename)
directory = pathlib.Path(os.environ['OPENMC_CROSS_SECTIONS']).parent
b10 = directory / 'wmp' / '005010.h5'
return openmc.data.WindowedMultipole.from_hdf5(b10)
def test_evaluate(u235):

View file

@ -154,7 +154,6 @@ def test_materials(run_in_tmpdir):
mats = openmc.Materials([m1, m2])
mats.cross_sections = '/some/fake/cross_sections.xml'
mats.multipole_library = '/some/awesome/mp_lib/'
mats.export_to_xml()
@ -200,7 +199,6 @@ def test_from_xml(run_in_tmpdir):
mats = openmc.Materials([m1, m2, m3])
mats.cross_sections = 'fake_path.xml'
mats.multipole_library = 'fake_multipole/'
mats.export_to_xml()
# Regenerate materials from XML

View file

@ -20,7 +20,6 @@ def test_export_to_xml(run_in_tmpdir):
s.statepoint = {'batches': [50, 150, 500, 1000]}
s.confidence_intervals = True
s.cross_sections = '/path/to/cross_sections.xml'
s.multipole_library = '/path/to/wmp/'
s.ptables = True
s.run_cmfd = False
s.seed = 17

View file

@ -1,9 +1,9 @@
#!/bin/bash
set -ex
# Download NNDC HDF5 data
# Download HDF5 data
if [[ ! -e $HOME/nndc_hdf5/cross_sections.xml ]]; then
wget -q -O - https://anl.box.com/shared/static/a0eflty17atnpd0pp7460exagr3nuhm7.xz | tar -C $HOME -xJ
wget -q -O - https://anl.box.com/shared/static/snrluuy79o2fffpvpng9bsuis5kl811d.xz | tar -C $HOME -xJ
fi
# Download ENDF/B-VII.1 distribution
@ -11,9 +11,3 @@ ENDF=$HOME/endf-b-vii.1/
if [[ ! -d $ENDF/neutrons || ! -d $ENDF/photoat || ! -d $ENDF/atomic_relax ]]; then
wget -q -O - https://anl.box.com/shared/static/4kd2gxnf4gtk4w1c8eua5fsua22kvgjb.xz | tar -C $HOME -xJ
fi
# Download multipole library
if [[ ! -e $HOME/WMP_Library/092235.h5 ]]; then
wget -q https://github.com/mit-crpg/WMP_Library/releases/download/v1.1/WMP_Library_v1.1.tar.gz
tar -C $HOME -xzf WMP_Library_v1.1.tar.gz
fi