Merge pull request #953 from paulromano/test-data

Add unit tests for openmc.data Python package
This commit is contained in:
Sterling Harper 2018-01-11 13:02:37 -05:00 committed by GitHub
commit 3236f0de15
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 799 additions and 124 deletions

View file

@ -8,61 +8,39 @@ addons:
apt:
packages:
- gfortran
- g++
- mpich
- libmpich-dev
cache:
directories:
- $HOME/nndc_hdf5
- $HOME/endf-b-vii.1
env:
- OPENMC_CONFIG="check_source"
- OPENMC_CONFIG="^hdf5-debug$"
- OPENMC_CONFIG="^omp-hdf5-debug$"
- OPENMC_CONFIG="^mpi-hdf5-debug$"
- OPENMC_CONFIG="^phdf5-debug$"
# We aren't testing the check_source script so just run it with Python 3.
matrix:
exclude:
- python: "2.7"
env: OPENMC_CONFIG="check_source"
global:
- FC=gfortran
- MPI_DIR=/usr
- PHDF5_DIR=/usr
- HDF5_DIR=/usr
- 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/multipole_lib
- PATH=$PATH:$HOME/NJOY2016/build
matrix:
- OPENMC_CONFIG="^hdf5-debug$"
- OPENMC_CONFIG="^omp-hdf5-debug$"
- OPENMC_CONFIG="^mpi-hdf5-debug$"
- OPENMC_CONFIG="^phdf5-debug$"
before_install:
- if [[ $OPENMC_CONFIG != "check_source" ]]; then
sudo add-apt-repository ppa:nschloe/hdf5-backports -y;
sudo apt-get update -q;
sudo apt-get install libhdf5-serial-dev libhdf5-mpich-dev -y;
export FC=gfortran;
export MPI_DIR=/usr;
export PHDF5_DIR=/usr;
export HDF5_DIR=/usr;
fi
- sudo add-apt-repository ppa:nschloe/hdf5-backports -y
- sudo apt-get update -q
- sudo apt-get install libhdf5-serial-dev libhdf5-mpich-dev -y
install:
- if [[ $OPENMC_CONFIG != "check_source" ]]; then
pip install numpy cython;
pip install --upgrade pytest;
pip install -e .[test];
fi
- ./tools/ci/travis-install.sh
before_script:
- if [[ $OPENMC_CONFIG != "check_source" ]]; then
if [[ ! -e $HOME/nndc_hdf5/cross_sections.xml ]]; then
wget https://anl.box.com/shared/static/a6sw2cep34wlz6b9i9jwiotaqoayxcxt.xz -O - | tar -C $HOME -xvJ;
fi;
export OPENMC_CROSS_SECTIONS=$HOME/nndc_hdf5/cross_sections.xml;
git clone --branch=master git://github.com/smharper/windowed_multipole_library.git wmp_lib;
tar xzvf wmp_lib/multipole_lib.tar.gz;
export OPENMC_MULTIPOLE_LIBRARY=$PWD/multipole_lib;
fi
- ./tools/ci/travis-before-script.sh
script:
- cd tests
- export OMP_NUM_THREADS=2
- if [[ $OPENMC_CONFIG == "check_source" ]]; then
./check_source.py;
else
./run_tests.py -C $OPENMC_CONFIG -j 2 &&
pytest --cov=../openmc -v unit_tests/;
fi
- cd ..
- ./tools/ci/travis-script.sh

View file

@ -21,6 +21,9 @@ def linearize(x, f, tolerance=0.001):
Tabulated values of the dependent variable
"""
# Make sure x is a numpy array
x = np.asarray(x)
# Initialize output arrays
x_out = []
y_out = []

View file

@ -44,7 +44,7 @@ class LaboratoryAngleEnergy(AngleEnergy):
"""
def __init__(self, breakpoints, interpolation, energy, mu, energy_out):
super(LaboratoryAngleEnergy).__init__()
super(LaboratoryAngleEnergy, self).__init__()
self.breakpoints = breakpoints
self.interpolation = interpolation
self.energy = energy

View file

@ -531,7 +531,8 @@ class WindowedMultipole(EqualityMixin):
sqrtkT = sqrt(K_BOLTZMANN * T)
sqrtE = sqrt(E)
invE = 1.0 / E
dopp = self.sqrtAWR / sqrtkT
if sqrtkT > 0.0:
dopp = self.sqrtAWR / sqrtkT
# Locate us. The i_window calc omits a + 1 present in F90 because of
# the 1-based vs. 0-based indexing. Similarly startw needs to be

View file

@ -465,6 +465,8 @@ class IncidentNeutron(EqualityMixin):
return [mt]
elif mt in SUM_RULES:
mts = SUM_RULES[mt]
else:
return []
complete = False
while not complete:
new_mts = []
@ -527,12 +529,6 @@ class IncidentNeutron(EqualityMixin):
rx_group = rxs_group.create_group('reaction_{:03}'.format(rx.mt))
rx.to_hdf5(rx_group)
# Write 0K elastic scattering if needed
if '0K' in rx.xs and '0K' not in rx_group:
group = rx_group.create_group('0K')
dset = group.create_dataset('xs', data=rx.xs['0K'].y)
dset.attrs['threshold_idx'] = 1
# Write total nu data if available
if len(rx.derived_products) > 0 and 'total_nu' not in g:
tgroup = g.create_group('total_nu')

View file

@ -4,7 +4,7 @@ from collections import namedtuple
from io import StringIO
import os
import shutil
from subprocess import Popen, PIPE, STDOUT
from subprocess import Popen, PIPE, STDOUT, CalledProcessError
import sys
import tempfile
@ -139,10 +139,10 @@ def run(commands, tapein, tapeout, input_filename=None, stdout=False,
njoy_exec : str, optional
Path to NJOY executable
Returns
-------
int
Return code of NJOY process
Raises
------
subprocess.CalledProcessError
If the NJOY process returns with a non-zero status
"""
@ -165,16 +165,23 @@ def run(commands, tapein, tapeout, input_filename=None, stdout=False,
njoy.stdin.write(commands)
njoy.stdin.flush()
lines = []
while True:
# If process is finished, break loop
line = njoy.stdout.readline()
if not line and njoy.poll() is not None:
break
lines.append(line)
if stdout:
# If user requested output, print to screen
print(line, end='')
# Check for error
if njoy.returncode != 0:
raise CalledProcessError(njoy.returncode, njoy_exec,
''.join(lines))
# Copy output files back to original directory
for tape_num, filename in tapeout.items():
tmpfilename = os.path.join(tmpdir, 'tape{}'.format(tape_num))
@ -183,8 +190,6 @@ def run(commands, tapein, tapeout, input_filename=None, stdout=False,
finally:
shutil.rmtree(tmpdir)
return njoy.returncode
def make_pendf(filename, pendf='pendf', error=0.001, stdout=False):
"""Generate ACE file from an ENDF file
@ -200,15 +205,15 @@ def make_pendf(filename, pendf='pendf', error=0.001, stdout=False):
stdout : bool
Whether to display NJOY standard output
Returns
-------
int
Return code of NJOY process
Raises
------
subprocess.CalledProcessError
If the NJOY process returns with a non-zero status
"""
return make_ace(filename, pendf=pendf, error=error, broadr=False,
heatr=False, purr=False, acer=False, stdout=stdout)
make_ace(filename, pendf=pendf, error=error, broadr=False,
heatr=False, purr=False, acer=False, stdout=stdout)
def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None,
@ -238,14 +243,14 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None,
purr : bool, optional
Indicating whether to add probability table when running NJOY
acer : bool, optional
Indicating whether to generate ACE file when running NJOY
Indicating whether to generate ACE file when running NJOY
**kwargs
Keyword arguments passed to :func:`openmc.data.njoy.run`
Returns
-------
int
Return code of NJOY process
Raises
------
subprocess.CalledProcessError
If the NJOY process returns with a non-zero status
"""
ev = endf.Evaluation(filename)
@ -285,7 +290,7 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None,
nheatr = nheatr_in + 1
commands += _TEMPLATE_HEATR
nlast = nheatr
# purr
if purr:
npurr_in = nlast
@ -310,9 +315,9 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None,
tapeout[nace] = fname.format(ace, temperature)
tapeout[ndir] = fname.format(xsdir, temperature)
commands += 'stop\n'
retcode = run(commands, tapein, tapeout, **kwargs)
run(commands, tapein, tapeout, **kwargs)
if acer and retcode == 0:
if acer:
with open(ace, 'w') as ace_file, open(xsdir, 'w') as xsdir_file:
for temperature in temperatures:
# Get contents of ACE file
@ -337,10 +342,8 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None,
os.remove(fname.format(ace, temperature))
os.remove(fname.format(xsdir, temperature))
return retcode
def make_ace_thermal(filename, filename_thermal, temperatures=None,
def make_ace_thermal(filename, filename_thermal, temperatures=None,
ace='ace', xsdir='xsdir', error=0.001, **kwargs):
"""Generate thermal scattering ACE file from ENDF files
@ -362,10 +365,10 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None,
**kwargs
Keyword arguments passed to :func:`openmc.data.njoy.run`
Returns
-------
int
Return code of NJOY process
Raises
------
subprocess.CalledProcessError
If the NJOY process returns with a non-zero status
"""
ev = endf.Evaluation(filename)
@ -461,21 +464,18 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None,
tapeout[nace] = fname.format(ace, temperature)
tapeout[ndir] = fname.format(xsdir, temperature)
commands += 'stop\n'
retcode = run(commands, tapein, tapeout, **kwargs)
run(commands, tapein, tapeout, **kwargs)
if retcode == 0:
with open(ace, 'w') as ace_file, open(xsdir, 'w') as xsdir_file:
# Concatenate ACE and xsdir files together
for temperature in temperatures:
text = open(fname.format(ace, temperature), 'r').read()
ace_file.write(text)
text = open(fname.format(xsdir, temperature), 'r').read()
xsdir_file.write(text)
# Remove ACE/xsdir files for each temperature
with open(ace, 'w') as ace_file, open(xsdir, 'w') as xsdir_file:
# Concatenate ACE and xsdir files together
for temperature in temperatures:
os.remove(fname.format(ace, temperature))
os.remove(fname.format(xsdir, temperature))
text = open(fname.format(ace, temperature), 'r').read()
ace_file.write(text)
return retcode
text = open(fname.format(xsdir, temperature), 'r').read()
xsdir_file.write(text)
# Remove ACE/xsdir files for each temperature
for temperature in temperatures:
os.remove(fname.format(ace, temperature))
os.remove(fname.format(xsdir, temperature))

View file

@ -1,6 +1,7 @@
from collections import Iterable
from difflib import get_close_matches
from numbers import Real
import itertools
import os
import re
import shutil
@ -25,37 +26,37 @@ from openmc.stats import Discrete, Tabular
_THERMAL_NAMES = {
'c_Al27': ('al', 'al27'),
'c_Be': ('be', 'be-metal'),
'c_BeO': ('beo',),
'c_BeO': ('beo'),
'c_Be_in_BeO': ('bebeo', 'be-o', 'be/o'),
'c_C6H6': ('benz', 'c6h6'),
'c_C_in_SiC': ('csic',),
'c_Ca_in_CaH2': ('cah',),
'c_Ca_in_CaH2': ('cah'),
'c_D_in_D2O': ('dd2o', 'hwtr', 'hw'),
'c_Fe56': ('fe', 'fe56'),
'c_Graphite': ('graph', 'grph', 'gr'),
'c_H_in_CaH2': ('hcah2',),
'c_H_in_CaH2': ('hcah2'),
'c_H_in_CH2': ('hch2', 'poly', 'pol'),
'c_H_in_CH4_liquid': ('lch4', 'lmeth'),
'c_H_in_CH4_solid': ('sch4', 'smeth'),
'c_H_in_H2O': ('hh2o', 'lwtr', 'lw'),
'c_H_in_H2O_solid': ('hice',),
'c_H_in_C5O2H8': ('lucite', 'c5o2h8'),
'c_H_in_YH2': ('hyh2',),
'c_H_in_YH2': ('hyh2'),
'c_H_in_ZrH': ('hzrh', 'h-zr', 'h/zr', 'hzr'),
'c_Mg24': ('mg', 'mg24'),
'c_O_in_BeO': ('obeo', 'o-be', 'o/be'),
'c_O_in_D2O': ('od2o',),
'c_O_in_H2O_ice': ('oice',),
'c_O_in_D2O': ('od2o'),
'c_O_in_H2O_ice': ('oice'),
'c_O_in_UO2': ('ouo2', 'o2-u', 'o2/u'),
'c_ortho_D': ('orthod', 'dortho'),
'c_ortho_H': ('orthoh', 'hortho'),
'c_Si_in_SiC': ('sisic',),
'c_Si_in_SiC': ('sisic'),
'c_SiO2_alpha': ('sio2', 'sio2a'),
'c_SiO2_beta': ('sio2b'),
'c_para_D': ('parad', 'dpara'),
'c_para_H': ('parah', 'hpara'),
'c_U_in_UO2': ('uuo2', 'u-o2', 'u/o2'),
'c_Y_in_YH2': ('yyh2',),
'c_Y_in_YH2': ('yyh2'),
'c_Zr_in_ZrH': ('zrzrh', 'zr-h', 'zr/h')
}
@ -84,13 +85,25 @@ def get_thermal_name(name):
# Make an educated guess?? This actually works well for
# JEFF-3.2 which stupidly uses names like lw00.32t,
# lw01.32t, etc. for different temperatures
for proper_name, names in _THERMAL_NAMES.items():
matches = get_close_matches(
name.lower(), names, cutoff=0.5)
if len(matches) > 0:
warn('Thermal scattering material "{}" is not recognized. '
'Assigning a name of {}.'.format(name, proper_name))
return proper_name
# First, construct a list of all the values/keys in the names
# dictionary
all_names = itertools.chain(_THERMAL_NAMES.keys(),
*_THERMAL_NAMES.values())
matches = get_close_matches(name, all_names, cutoff=0.5)
if len(matches) > 0:
# Figure out the key for the corresponding match
match = matches[0]
if match not in _THERMAL_NAMES:
for key, value_list in _THERMAL_NAMES.items():
if match in value_list:
match = key
break
warn('Thermal scattering material "{}" is not recognized. '
'Assigning a name of {}.'.format(name, match))
return match
else:
# OK, we give up. Just use the ACE name.
warn('Thermal scattering material "{0}" is not recognized. '
@ -408,30 +421,27 @@ class ThermalScattering(EqualityMixin):
# Cross section
elastic_xs_type = elastic_group['xs'].attrs['type'].decode()
if elastic_xs_type == 'Tabulated1D':
table.elastic_xs[T] = \
Tabulated1D.from_hdf5(elastic_group['xs'])
table.elastic_xs[T] = Tabulated1D.from_hdf5(
elastic_group['xs'])
elif elastic_xs_type == 'bragg':
table.elastic_xs[T] = \
CoherentElastic.from_hdf5(elastic_group['xs'])
table.elastic_xs[T] = CoherentElastic.from_hdf5(
elastic_group['xs'])
# Angular distribution
if 'mu_out' in elastic_group:
table.elastic_mu_out[T] = \
elastic_group['mu_out'].value
table.elastic_mu_out[T] = elastic_group['mu_out'].value
# Read thermal inelastic scattering
if 'inelastic' in Tgroup:
inelastic_group = Tgroup['inelastic']
table.inelastic_xs[T] = \
Tabulated1D.from_hdf5(inelastic_group['xs'])
table.inelastic_xs[T] = Tabulated1D.from_hdf5(
inelastic_group['xs'])
if table.secondary_mode in ('equal', 'skewed'):
table.inelastic_e_out[T] = \
inelastic_group['energy_out']
table.inelastic_mu_out[T] = \
inelastic_group['mu_out']
table.inelastic_e_out[T] = inelastic_group['energy_out'].value
table.inelastic_mu_out[T] = inelastic_group['mu_out'].value
elif table.secondary_mode == 'continuous':
table.inelastic_dist[T] = \
AngleEnergy.from_hdf5(inelastic_group)
table.inelastic_dist[T] = AngleEnergy.from_hdf5(
inelastic_group)
return table

View file

@ -0,0 +1,82 @@
#!/usr/bin/env python
from collections import Mapping
import os
from math import log
import numpy as np
import pytest
from uncertainties import ufloat
import openmc.data
_ENDF_DATA = os.environ['OPENMC_ENDF_DATA']
def ufloat_close(a, b):
assert a.nominal_value == pytest.approx(b.nominal_value)
assert a.std_dev == pytest.approx(b.std_dev)
@pytest.fixture(scope='module')
def nb90():
"""Nb90 decay data."""
filename = os.path.join(_ENDF_DATA, 'decay', 'dec-041_Nb_090.endf')
return openmc.data.Decay.from_endf(filename)
@pytest.fixture(scope='module')
def u235_yields():
"""U235 fission product yield data."""
filename = os.path.join(_ENDF_DATA, 'nfy', 'nfy-092_U_235.endf')
return openmc.data.FissionProductYields.from_endf(filename)
def test_nb90_halflife(nb90):
ufloat_close(nb90.half_life, ufloat(52560.0, 180.0))
ufloat_close(nb90.decay_constant, log(2.)/nb90.half_life)
def test_nb90_nuclide(nb90):
assert nb90.nuclide['atomic_number'] == 41
assert nb90.nuclide['mass_number'] == 90
assert nb90.nuclide['isomeric_state'] == 0
assert nb90.nuclide['parity'] == 1.0
assert nb90.nuclide['spin'] == 8.0
assert not nb90.nuclide['stable']
assert nb90.nuclide['mass'] == pytest.approx(89.13888)
def test_nb90_modes(nb90):
assert len(nb90.modes) == 2
ec = nb90.modes[0]
assert ec.modes == ['ec/beta+']
assert ec.parent == 'Nb90'
assert ec.daughter == 'Zr90'
assert 'Nb90 -> Zr90' in str(ec)
ufloat_close(ec.branching_ratio, ufloat(0.0147633, 0.0003386195))
ufloat_close(ec.energy, ufloat(6111000., 4000.))
# Make sure branching ratios sum to 1
total = sum(m.branching_ratio for m in nb90.modes)
assert total.nominal_value == pytest.approx(1.0)
def test_nb90_spectra(nb90):
assert sorted(nb90.spectra.keys()) == ['e-', 'ec/beta+', 'gamma', 'xray']
def test_fpy(u235_yields):
assert u235_yields.nuclide['atomic_number'] == 92
assert u235_yields.nuclide['mass_number'] == 235
assert u235_yields.nuclide['isomeric_state'] == 0
assert u235_yields.nuclide['name'] == 'U235'
assert u235_yields.energies == pytest.approx([0.0253, 500.e3, 1.4e7])
assert len(u235_yields.cumulative) == 3
thermal = u235_yields.cumulative[0]
ufloat_close(thermal['I135'], ufloat(0.0628187, 0.000879461))
assert len(u235_yields.independent) == 3
thermal = u235_yields.independent[0]
ufloat_close(thermal['I135'], ufloat(0.0292737, 0.000819663))

View file

@ -0,0 +1,50 @@
#!/usr/bin/env python
from collections import Mapping
import os
import numpy as np
import pytest
import openmc.data
def test_data_library(tmpdir):
lib = openmc.data.DataLibrary.from_xml()
for f in lib.libraries:
assert sorted(f.keys()) == ['materials', 'path', 'type']
f = lib.get_by_material('U235')
assert f['type'] == 'neutron'
assert 'U235' in f['materials']
f = lib.get_by_material('c_H_in_H2O')
assert f['type'] == 'thermal'
assert 'c_H_in_H2O' in f['materials']
filename = str(tmpdir.join('test.xml'))
lib.export_to_xml(filename)
assert os.path.exists(filename)
new_lib = openmc.data.DataLibrary()
directory = os.path.dirname(os.environ['OPENMC_CROSS_SECTIONS'])
new_lib.register_file(os.path.join(directory, 'H1.h5'))
assert new_lib.libraries[-1]['type'] == 'neutron'
new_lib.register_file(os.path.join(directory, 'c_Zr_in_ZrH.h5'))
assert new_lib.libraries[-1]['type'] == 'thermal'
def test_linearize():
"""Test linearization of a continuous function."""
x, y = openmc.data.linearize([-1., 1.], lambda x: 1 - x*x)
f = openmc.data.Tabulated1D(x, y)
assert f(-0.5) == pytest.approx(1 - 0.5*0.5, 0.001)
assert f(0.32) == pytest.approx(1 - 0.32*0.32, 0.001)
def test_thin():
"""Test thinning of a tabulated function."""
x = np.linspace(0., 2*np.pi, 1000)
y = np.sin(x)
x_thin, y_thin = openmc.data.thin(x, y)
f = openmc.data.Tabulated1D(x_thin, y_thin)
assert f(1.0) == pytest.approx(np.sin(1.0), 0.001)

View file

@ -0,0 +1,39 @@
#!/usr/bin/env python
import os
import numpy as np
import pytest
import openmc.data
@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)
@pytest.fixture(scope='module')
def fe56():
directory = os.environ['OPENMC_MULTIPOLE_LIBRARY']
filename = os.path.join(directory, '026056.h5')
return openmc.data.WindowedMultipole.from_hdf5(filename)
def test_evaluate(u235):
"""Make sure multipole object can be called."""
energies = [1e-3, 1.0, 10.0, 50.]
total, absorption, fission = u235(energies, 0.0)
assert total[1] == pytest.approx(90.64895383)
total, absorption, fission = u235(energies, 300.0)
assert total[1] == pytest.approx(91.12534964)
def test_high_l(fe56):
"""Test a nuclide (Fe56) with a high l-value (4)."""
energies = [1e-3, 1.0, 10.0, 1e3, 1e5]
total, absorption, fission = fe56(energies, 0.0)
assert total[0] == pytest.approx(25.072619556789267)
total, absorption, fission = fe56(energies, 300.0)
assert total[0] == pytest.approx(27.85535792368082)

View file

@ -0,0 +1,364 @@
#!/usr/bin/env python
from collections import Mapping, Callable
import os
import numpy as np
import pandas as pd
import pytest
import openmc.data
_TEMPERATURES = [300., 600., 900.]
_ENDF_DATA = os.environ['OPENMC_ENDF_DATA']
@pytest.fixture(scope='module')
def pu239():
"""Pu239 HDF5 data."""
directory = os.path.dirname(os.environ['OPENMC_CROSS_SECTIONS'])
filename = os.path.join(directory, 'Pu239.h5')
return openmc.data.IncidentNeutron.from_hdf5(filename)
@pytest.fixture(scope='module')
def xe135():
"""Xe135 ENDF data (contains SLBW resonance range)"""
filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-054_Xe_135.endf')
return openmc.data.IncidentNeutron.from_endf(filename)
@pytest.fixture(scope='module')
def sm150():
"""Sm150 ENDF data (contains MLBW resonance range)"""
filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-062_Sm_150.endf')
return openmc.data.IncidentNeutron.from_endf(filename)
@pytest.fixture(scope='module')
def gd154():
"""Gd154 ENDF data (contains Reich Moore resonance range)"""
filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-064_Gd_154.endf')
return openmc.data.IncidentNeutron.from_endf(filename)
@pytest.fixture(scope='module')
def cl35():
"""Cl35 ENDF data (contains RML resonance range)"""
filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-017_Cl_035.endf')
return openmc.data.IncidentNeutron.from_endf(filename)
@pytest.fixture(scope='module')
def am241():
"""Am241 ENDF data (contains Madland-Nix fission energy distribution)."""
filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-095_Am_241.endf')
return openmc.data.IncidentNeutron.from_endf(filename)
@pytest.fixture(scope='module')
def u233():
"""U233 ENDF data (contains Watt fission energy distribution)."""
filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-092_U_233.endf')
return openmc.data.IncidentNeutron.from_endf(filename)
@pytest.fixture(scope='module')
def u236():
"""U236 ENDF data (contains Watt fission energy distribution)."""
filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-092_U_236.endf')
return openmc.data.IncidentNeutron.from_endf(filename)
@pytest.fixture(scope='module')
def na22():
"""Na22 ENDF data (contains evaporation spectrum)."""
filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-011_Na_022.endf')
return openmc.data.IncidentNeutron.from_endf(filename)
@pytest.fixture(scope='module')
def be9():
"""Be9 ENDF data (contains laboratory angle-energy distribution)."""
filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-004_Be_009.endf')
return openmc.data.IncidentNeutron.from_endf(filename)
@pytest.fixture(scope='module')
def h2():
endf_file = os.path.join(_ENDF_DATA, 'neutrons', 'n-001_H_002.endf')
return openmc.data.IncidentNeutron.from_njoy(
endf_file, temperatures=_TEMPERATURES)
@pytest.fixture(scope='module')
def am244():
endf_file = os.path.join(_ENDF_DATA, 'neutrons', 'n-095_Am_244.endf')
return openmc.data.IncidentNeutron.from_njoy(endf_file)
def test_attributes(pu239):
assert pu239.name == 'Pu239'
assert pu239.mass_number == 239
assert pu239.metastable == 0
assert pu239.atomic_symbol == 'Pu'
assert pu239.atomic_weight_ratio == pytest.approx(236.9986)
def test_fission_energy(pu239):
fer = pu239.fission_energy
assert isinstance(fer, openmc.data.FissionEnergyRelease)
components = ['betas', 'delayed_neutrons', 'delayed_photons', 'fragments',
'neutrinos', 'prompt_neutrons', 'prompt_photons', 'recoverable',
'total', 'q_prompt', 'q_recoverable', 'q_total']
for c in components:
assert isinstance(getattr(fer, c), Callable)
def test_compact_fission_energy(tmpdir):
files = [os.path.join(_ENDF_DATA, 'neutrons', 'n-090_Th_232.endf'),
os.path.join(_ENDF_DATA, 'neutrons', 'n-094_Pu_240.endf'),
os.path.join(_ENDF_DATA, 'neutrons', 'n-094_Pu_241.endf')]
output = str(tmpdir.join('compact_lib.h5'))
openmc.data.write_compact_458_library(files, output)
assert os.path.exists(output)
def test_energy_grid(pu239):
assert isinstance(pu239.energy, Mapping)
for temp, grid in pu239.energy.items():
assert temp.endswith('K')
assert np.all(np.diff(grid) >= 0.0)
def test_reactions(pu239):
assert 2 in pu239.reactions
assert isinstance(pu239.reactions[2], openmc.data.Reaction)
with pytest.raises(KeyError):
pu239.reactions[14]
def test_elastic(pu239):
elastic = pu239.reactions[2]
assert elastic.center_of_mass
assert elastic.q_value == 0.0
assert elastic.mt == 2
assert '0K' in elastic.xs
assert '294K' in elastic.xs
assert len(elastic.products) == 1
p = elastic.products[0]
assert isinstance(p, openmc.data.Product)
assert p.particle == 'neutron'
assert p.emission_mode == 'prompt'
assert len(p.distribution) == 1
d = p.distribution[0]
assert isinstance(d, openmc.data.UncorrelatedAngleEnergy)
assert isinstance(d.angle, openmc.data.AngleDistribution)
assert d.energy is None
assert p.yield_(0.0) == 1.0
def test_fission(pu239):
fission = pu239.reactions[18]
assert not fission.center_of_mass
assert fission.q_value == pytest.approx(198902000.0)
assert fission.mt == 18
assert '294K' in fission.xs
assert len(fission.products) == 8
prompt = fission.products[0]
assert prompt.particle == 'neutron'
assert prompt.yield_(1.0e-5) == pytest.approx(2.874262)
delayed = [p for p in fission.products if p.emission_mode == 'delayed']
assert len(delayed) == 6
assert all(d.particle == 'neutron' for d in delayed)
assert sum(d.decay_rate for d in delayed) == pytest.approx(4.037212)
assert sum(d.yield_(1.0) for d in delayed) == pytest.approx(0.00645)
photon = fission.products[-1]
assert photon.particle == 'photon'
def test_derived_products(am244):
fission = am244.reactions[18]
total_neutron = fission.derived_products[0]
assert total_neutron.emission_mode == 'total'
assert total_neutron.yield_(6e6) == pytest.approx(4.2558)
def test_urr(pu239):
for T, ptable in pu239.urr.items():
assert T.endswith('K')
assert isinstance(ptable, openmc.data.ProbabilityTables)
ptable = pu239.urr['294K']
assert ptable.absorption_flag == -1
assert ptable.energy[0] == pytest.approx(2500.001)
assert ptable.energy[-1] == pytest.approx(29999.99)
assert ptable.inelastic_flag == 51
assert ptable.interpolation == 2
assert not ptable.multiply_smooth
assert ptable.table.shape == (70, 6, 20)
assert ptable.table.shape[0] == ptable.energy.size
def test_get_reaction_components(h2):
assert h2.get_reaction_components(1) == [2, 16, 102]
assert h2.get_reaction_components(101) == [102]
assert h2.get_reaction_components(16) == [16]
assert h2.get_reaction_components(51) == []
def test_export_to_hdf5(tmpdir, pu239, gd154):
filename = str(tmpdir.join('pu239.h5'))
pu239.export_to_hdf5(filename)
assert os.path.exists(filename)
with pytest.raises(NotImplementedError):
gd154.export_to_hdf5('gd154.h5')
def test_slbw(xe135):
res = xe135.resonances
assert isinstance(res, openmc.data.Resonances)
assert len(res.ranges) == 2
resolved = res.resolved
assert isinstance(resolved, openmc.data.SingleLevelBreitWigner)
assert resolved.energy_min == pytest.approx(1e-5)
assert resolved.energy_max == pytest.approx(190.)
assert resolved.target_spin == pytest.approx(1.5)
assert isinstance(resolved.parameters, pd.DataFrame)
s = resolved.parameters.iloc[0]
assert s['energy'] == pytest.approx(0.084)
xs = resolved.reconstruct([10., 30., 100.])
assert sorted(xs.keys()) == [2, 18, 102]
assert np.all(xs[18] == 0.0)
def test_mlbw(sm150):
resolved = sm150.resonances.resolved
assert isinstance(resolved, openmc.data.MultiLevelBreitWigner)
assert resolved.energy_min == pytest.approx(1e-5)
assert resolved.energy_max == pytest.approx(1570.)
assert resolved.target_spin == 0.0
xs = resolved.reconstruct([10., 100., 1000.])
assert sorted(xs.keys()) == [2, 18, 102]
assert np.all(xs[18] == 0.0)
def test_reichmoore(gd154):
res = gd154.resonances
assert isinstance(res, openmc.data.Resonances)
assert len(res.ranges) == 2
resolved, unresolved = res.ranges
assert resolved is res.resolved
assert unresolved is res.unresolved
assert isinstance(resolved, openmc.data.ReichMoore)
assert isinstance(unresolved, openmc.data.Unresolved)
assert resolved.energy_min == pytest.approx(1e-5)
assert resolved.energy_max == pytest.approx(2760.)
assert resolved.target_spin == 0.0
assert resolved.channel_radius[0](1.0) == pytest.approx(0.74)
assert isinstance(resolved.parameters, pd.DataFrame)
assert (resolved.parameters['L'] == 0).all()
assert (resolved.parameters['J'] <= 0.5).all()
assert (resolved.parameters['fissionWidthA'] == 0.0).all()
elastic = gd154.reactions[2].xs['0K']
assert isinstance(elastic, openmc.data.ResonancesWithBackground)
assert elastic(0.0253) == pytest.approx(5.7228949796394524)
def test_rml(cl35):
resolved = cl35.resonances.resolved
assert isinstance(resolved, openmc.data.RMatrixLimited)
assert resolved.energy_min == pytest.approx(1e-5)
assert resolved.energy_max == pytest.approx(1.2e6)
assert resolved.target_spin == 0.0
for group in resolved.spin_groups:
assert isinstance(group, openmc.data.SpinGroup)
def test_madland_nix(am241):
fission = am241.reactions[18]
prompt_neutron = fission.products[0]
dist = prompt_neutron.distribution[0].energy
assert isinstance(dist, openmc.data.MadlandNix)
assert dist.efl == pytest.approx(1029979.0)
assert dist.efh == pytest.approx(546729.7)
assert isinstance(dist.tm, Callable)
def test_watt(u233):
fission = u233.reactions[18]
prompt_neutron = fission.products[0]
dist = prompt_neutron.distribution[0].energy
assert isinstance(dist, openmc.data.WattEnergy)
def test_maxwell(u236):
fission = u236.reactions[18]
prompt_neutron = fission.products[0]
dist = prompt_neutron.distribution[0].energy
assert isinstance(dist, openmc.data.MaxwellEnergy)
def test_evaporation(na22):
n2n = na22.reactions[16]
dist = n2n.products[0].distribution[0].energy
assert isinstance(dist, openmc.data.Evaporation)
def test_laboratory(be9):
n2n = be9.reactions[16]
dist = n2n.products[0].distribution[0]
assert isinstance(dist, openmc.data.LaboratoryAngleEnergy)
assert list(dist.breakpoints) == [18]
assert list(dist.interpolation) == [2]
assert dist.energy[0] == pytest.approx(1748830.)
assert dist.energy[-1] == pytest.approx(20.e6)
assert len(dist.energy) == len(dist.energy_out) == len(dist.mu)
for eout, mu in zip(dist.energy_out, dist.mu):
assert len(eout) == len(mu)
assert np.all((-1. <= mu.x) & (mu.x <= 1.))
def test_correlated(tmpdir):
endf_file = os.path.join(_ENDF_DATA, 'neutrons', 'n-014_Si_030.endf')
si30 = openmc.data.IncidentNeutron.from_njoy(endf_file, heatr=False)
# Convert to HDF5 and read back
filename = str(tmpdir.join('si30.h5'))
si30.export_to_hdf5(filename)
si30_copy = openmc.data.IncidentNeutron.from_hdf5(filename)
def test_nbody(tmpdir, h2):
# Convert to HDF5 and read back
filename = str(tmpdir.join('h2.h5'))
h2.export_to_hdf5(filename)
h2_copy = openmc.data.IncidentNeutron.from_hdf5(filename)
# Compare distributions
nbody1 = h2[16].products[0].distribution[0]
nbody2 = h2_copy[16].products[0].distribution[0]
assert nbody1.total_mass == nbody2.total_mass
assert nbody1.n_particles == nbody2.n_particles
assert nbody1.q_value == nbody2.q_value
def test_ace_convert(tmpdir):
filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-001_H_001.endf')
ace_ascii = str(tmpdir.join('ace_ascii'))
ace_binary = str(tmpdir.join('ace_binary'))
openmc.data.njoy.make_ace(filename, ace=ace_ascii)
# Convert to binary
openmc.data.ace.ascii_to_binary(ace_ascii, ace_binary)
# Make sure conversion worked
lib_ascii = openmc.data.ace.Library(ace_ascii)
lib_binary = openmc.data.ace.Library(ace_binary)
for tab_a, tab_b in zip(lib_ascii.tables, lib_binary.tables):
assert tab_a.name == tab_b.name
assert tab_a.atomic_weight_ratio == pytest.approx(tab_b.atomic_weight_ratio)
assert tab_a.temperature == pytest.approx(tab_b.temperature)
assert np.all(tab_a.nxs == tab_b.nxs)
assert np.all(tab_a.jxs == tab_b.jxs)

View file

@ -0,0 +1,101 @@
#!/usr/bin/env python
from collections import Callable
import os
import numpy as np
import pytest
import openmc.data
_ENDF_DATA = os.environ['OPENMC_ENDF_DATA']
@pytest.fixture(scope='module')
def h2o():
"""H in H2O thermal scattering data."""
directory = os.path.dirname(os.environ['OPENMC_CROSS_SECTIONS'])
filename = os.path.join(directory, 'c_H_in_H2O.h5')
return openmc.data.ThermalScattering.from_hdf5(filename)
@pytest.fixture(scope='module')
def graphite():
"""Graphite thermal scattering data."""
directory = os.path.dirname(os.environ['OPENMC_CROSS_SECTIONS'])
filename = os.path.join(directory, 'c_Graphite.h5')
return openmc.data.ThermalScattering.from_hdf5(filename)
@pytest.fixture(scope='module')
def h2o_njoy():
path_h1 = os.path.join(_ENDF_DATA, 'neutrons', 'n-001_H_001.endf')
path_h2o = os.path.join(_ENDF_DATA, 'thermal_scatt', 'tsl-HinH2O.endf')
return openmc.data.ThermalScattering.from_njoy(
path_h1, path_h2o, temperatures=[293.6, 500.0])
def test_h2o_attributes(h2o):
assert h2o.name == 'c_H_in_H2O'
assert h2o.nuclides == ['H1']
assert h2o.secondary_mode == 'skewed'
assert h2o.temperatures == ['294K']
assert h2o.atomic_weight_ratio == pytest.approx(0.999167)
def test_h2o_xs(h2o):
assert not h2o.elastic_xs
for temperature, func in h2o.inelastic_xs.items():
assert temperature.endswith('K')
assert isinstance(func, Callable)
def test_graphite_attributes(graphite):
assert graphite.name == 'c_Graphite'
assert graphite.nuclides == ['C0', 'C12', 'C13']
assert graphite.secondary_mode == 'skewed'
assert graphite.temperatures == ['296K']
assert graphite.atomic_weight_ratio == pytest.approx(11.898)
def test_graphite_xs(graphite):
for temperature, func in graphite.elastic_xs.items():
assert temperature.endswith('K')
assert isinstance(func, openmc.data.CoherentElastic)
for temperature, func in graphite.inelastic_xs.items():
assert temperature.endswith('K')
assert isinstance(func, Callable)
elastic = graphite.elastic_xs['296K']
assert elastic([1e-3, 1.0]) == pytest.approx([13.47464936, 0.62590156])
def test_export_to_hdf5(tmpdir, h2o_njoy, graphite):
filename = str(tmpdir.join('water.h5'))
h2o_njoy.export_to_hdf5(filename)
assert os.path.exists(filename)
filename = str(tmpdir.join('graphite.h5'))
graphite.export_to_hdf5(filename)
assert os.path.exists(filename)
def test_continuous_dist(h2o_njoy):
for temperature, dist in h2o_njoy.inelastic_dist.items():
assert temperature.endswith('K')
assert isinstance(dist, openmc.data.CorrelatedAngleEnergy)
def test_get_thermal_name():
f = openmc.data.get_thermal_name
# Names which are recognized
assert f('lwtr') == 'c_H_in_H2O'
assert f('hh2o') == 'c_H_in_H2O'
with pytest.warns(UserWarning, match='is not recognized'):
# Names which can be guessed
assert f('lw00') == 'c_H_in_H2O'
assert f('graphite') == 'c_Graphite'
assert f('D_in_D2O') == 'c_D_in_D2O'
# Names that don't remotely match anything
assert f('boogie_monster') == 'c_boogie_monster'

View file

@ -0,0 +1,16 @@
#!/bin/bash
set -ex
# Download NNDC HDF5 data
if [[ ! -e $HOME/nndc_hdf5/cross_sections.xml ]]; then
wget https://anl.box.com/shared/static/a6sw2cep34wlz6b9i9jwiotaqoayxcxt.xz -O - | tar -C $HOME -xvJ
fi
# Download ENDF/B-VII.1 distribution
if [[ ! -d $HOME/endf-b-vii.1/neutrons ]]; then
wget https://anl.box.com/shared/static/4kd2gxnf4gtk4w1c8eua5fsua22kvgjb.xz -O - | tar -C $HOME -xvJ
fi
# Download multipole library
git clone --branch=master git://github.com/smharper/windowed_multipole_library.git wmp_lib
tar -C $HOME -xzvf wmp_lib/multipole_lib.tar.gz

View file

@ -0,0 +1,8 @@
#!/bin/bash
set -ex
cd $HOME
git clone https://github.com/njoy/NJOY2016
cd NJOY2016
sed -i -e 's/5\.1/4.8/' CMakeLists.txt
mkdir build && cd build
cmake -Dstatic=on .. && make 2>/dev/null && sudo make install

19
tools/ci/travis-install.sh Executable file
View file

@ -0,0 +1,19 @@
#!/bin/bash
set -ex
# Install NJOY 2016
./tools/ci/travis-install-njoy.sh
# Running OpenMC's setup.py requires numpy/cython already
pip install numpy cython
# pytest installed by default -- make sure we get latest
pip install --upgrade pytest
# Pandas stopped supporting Python 3.4 with version 0.21
if [[ "$TRAVIS_PYTHON_VERSION" == "3.4" ]]; then
pip install pandas==0.20.3
fi
# Install OpenMC in editable mode
pip install -e .[test]

8
tools/ci/travis-script.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/bash
set -ex
cd tests
if [[ $TRAVIS_PYTHON_VERSION == "3.4" && $OPENMC_CONFIG == '^hdf5-debug$' ]]; then
./check_source.py
fi
./run_tests.py -C $OPENMC_CONFIG -j 2
pytest --cov=../openmc -v unit_tests/