From 64ca0b752ffce91f9f36732ad603818884561e5c Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 14 Dec 2017 15:03:39 +0700 Subject: [PATCH 01/10] Try installing NJOY on Travis, separate things into scripts --- .travis.yml | 48 +++++++++++++------------------- tools/ci/travis-before-script.sh | 17 +++++++++++ tools/ci/travis-install-njoy.sh | 8 ++++++ tools/ci/travis-script.sh | 9 ++++++ 4 files changed, 54 insertions(+), 28 deletions(-) create mode 100755 tools/ci/travis-before-script.sh create mode 100755 tools/ci/travis-install-njoy.sh create mode 100755 tools/ci/travis-script.sh diff --git a/.travis.yml b/.travis.yml index 49b6ed2d12..7ff7a15982 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,18 +8,29 @@ 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$" + 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="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: @@ -32,37 +43,18 @@ before_install: 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 install: - if [[ $OPENMC_CONFIG != "check_source" ]]; then + ./tools/ci/travis-install-njoy.sh pip install numpy cython; pip install --upgrade pytest; pip install -e .[test]; fi 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 diff --git a/tools/ci/travis-before-script.sh b/tools/ci/travis-before-script.sh new file mode 100755 index 0000000000..6a56fcfe7c --- /dev/null +++ b/tools/ci/travis-before-script.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -ex +if [[ $OPENMC_CONFIG != "check_source" ]]; then + # 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 +fi diff --git a/tools/ci/travis-install-njoy.sh b/tools/ci/travis-install-njoy.sh new file mode 100755 index 0000000000..a338cbf4b7 --- /dev/null +++ b/tools/ci/travis-install-njoy.sh @@ -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 .. && make 2>/dev/null && sudo make install diff --git a/tools/ci/travis-script.sh b/tools/ci/travis-script.sh new file mode 100755 index 0000000000..71a3c6d746 --- /dev/null +++ b/tools/ci/travis-script.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -ex +cd tests +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 From f455ede48232e6490c4f9223fea950b84c54d6fd Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 14 Dec 2017 16:42:24 +0700 Subject: [PATCH 02/10] Remove check_source Travis configuration, make other simplifications --- .travis.yml | 22 ++++------------------ tools/ci/travis-before-script.sh | 25 ++++++++++++------------- tools/ci/travis-install.sh | 19 +++++++++++++++++++ tools/ci/travis-script.sh | 9 ++++----- 4 files changed, 39 insertions(+), 36 deletions(-) create mode 100755 tools/ci/travis-install.sh diff --git a/.travis.yml b/.travis.yml index 7ff7a15982..de8b7dcc73 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,32 +26,18 @@ env: - OPENMC_MULTIPOLE_LIBRARY=$HOME/multipole_lib - PATH=$PATH:$HOME/NJOY2016/build matrix: - - 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" - 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; - 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 - ./tools/ci/travis-install-njoy.sh - pip install numpy cython; - pip install --upgrade pytest; - pip install -e .[test]; - fi + - ./tools/ci/travis-install.sh before_script: - ./tools/ci/travis-before-script.sh diff --git a/tools/ci/travis-before-script.sh b/tools/ci/travis-before-script.sh index 6a56fcfe7c..bbf4980b0f 100755 --- a/tools/ci/travis-before-script.sh +++ b/tools/ci/travis-before-script.sh @@ -1,17 +1,16 @@ #!/bin/bash set -ex -if [[ $OPENMC_CONFIG != "check_source" ]]; then - # 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 +# 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 diff --git a/tools/ci/travis-install.sh b/tools/ci/travis-install.sh new file mode 100755 index 0000000000..354ae7f7f4 --- /dev/null +++ b/tools/ci/travis-install.sh @@ -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] diff --git a/tools/ci/travis-script.sh b/tools/ci/travis-script.sh index 71a3c6d746..978a2811c4 100755 --- a/tools/ci/travis-script.sh +++ b/tools/ci/travis-script.sh @@ -1,9 +1,8 @@ #!/bin/bash set -ex cd tests -if [[ $OPENMC_CONFIG == "check_source" ]]; then - ./check_source.py; -else - ./run_tests.py -C $OPENMC_CONFIG -j 2 - pytest --cov=../openmc -v unit_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/ From 4e9ee6c2e26772d74d8c5355a34b93819ac9ff5c Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 14 Dec 2017 22:04:42 +0700 Subject: [PATCH 03/10] Start adding unit tests for openmc.data --- openmc/data/neutron.py | 2 + tests/unit_tests/test_data_neutron.py | 121 ++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 tests/unit_tests/test_data_neutron.py diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 08d12106c2..b44c97afc2 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -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 = [] diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py new file mode 100644 index 0000000000..9c27a51522 --- /dev/null +++ b/tests/unit_tests/test_data_neutron.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python + +from collections import Mapping +import os + +import numpy as np +import pandas as pd +import pytest +import openmc.data + + +@pytest.fixture +def pu239(): + 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 +def gd154(): + directory = os.environ['OPENMC_ENDF_DATA'] + filename = os.path.join(directory, 'neutrons', 'n-064_Gd_154.endf') + return openmc.data.IncidentNeutron.from_endf(filename) + + +@pytest.fixture +def ace_file(): + directory = os.environ['OPENMC_ENDF_DATA'] + h1 = os.path.join(directory, 'neutrons', 'n-001_H_001.endf') + retcode = openmc.data.njoy.make_ace(h1, ace='h1.ace') + assert retcode == 0 + return os.path.join(os.getcwd(), 'h1.ace') + + +@pytest.fixture +def h1(ace_file): + return openmc.data.IncidentNeutron.from_ace(ace_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_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_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_get_reaction_components(h1): + assert h1.get_reaction_components(1) == [2, 102] + assert h1.get_reaction_components(101) == [102] + assert h1.get_reaction_components(102) == [102] + assert h1.get_reaction_components(51) == [] + + +def test_resonances(gd154): + res = gd154.resonances + assert isinstance(res, openmc.data.Resonances) + assert len(res.ranges) == 2 + resolved, unresolved = res.ranges + 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() + + +def test_reconstruct(gd154): + elastic = gd154.reactions[2].xs['0K'] + assert isinstance(elastic, openmc.data.ResonancesWithBackground) + assert elastic(0.0253) == pytest.approx(5.7228949796394524) From e94dd55b31424c02afc41c7dabb1846ab6247b93 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 16 Dec 2017 21:24:25 +0700 Subject: [PATCH 04/10] More unit tests for openmc.data and a few small fixes --- openmc/data/multipole.py | 3 +- openmc/data/neutron.py | 6 - tests/unit_tests/test_data_multipole.py | 41 +++++ tests/unit_tests/test_data_neutron.py | 204 +++++++++++++++++++++--- 4 files changed, 223 insertions(+), 31 deletions(-) create mode 100644 tests/unit_tests/test_data_multipole.py diff --git a/openmc/data/multipole.py b/openmc/data/multipole.py index 8e7f7e18dc..653ff08256 100644 --- a/openmc/data/multipole.py +++ b/openmc/data/multipole.py @@ -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 diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index b44c97afc2..7dcac5d6e6 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -529,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') diff --git a/tests/unit_tests/test_data_multipole.py b/tests/unit_tests/test_data_multipole.py new file mode 100644 index 0000000000..c485abb4fc --- /dev/null +++ b/tests/unit_tests/test_data_multipole.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +from collections import Callable +import os + +import numpy as np +import pandas as pd +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) diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py index 9c27a51522..4809c56386 100644 --- a/tests/unit_tests/test_data_neutron.py +++ b/tests/unit_tests/test_data_neutron.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -from collections import Mapping +from collections import Mapping, Callable import os import numpy as np @@ -9,32 +9,79 @@ import pytest import openmc.data -@pytest.fixture +_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 -def gd154(): - directory = os.environ['OPENMC_ENDF_DATA'] - filename = os.path.join(directory, 'neutrons', 'n-064_Gd_154.endf') +@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 -def ace_file(): - directory = os.environ['OPENMC_ENDF_DATA'] - h1 = os.path.join(directory, 'neutrons', 'n-001_H_001.endf') - retcode = openmc.data.njoy.make_ace(h1, ace='h1.ace') - assert retcode == 0 - return os.path.join(os.getcwd(), 'h1.ace') +@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 -def h1(ace_file): - return openmc.data.IncidentNeutron.from_ace(ace_file) +@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 h2(): + endf_file = os.path.join(_ENDF_DATA, 'neutrons', 'n-001_H_002.endf') + return openmc.data.IncidentNeutron.from_njoy( + endf_file, temperatures=_TEMPERATURES) def test_attributes(pu239): @@ -45,6 +92,16 @@ def test_attributes(pu239): 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_energy_grid(pu239): assert isinstance(pu239.energy, Mapping) for temp, grid in pu239.energy.items(): @@ -52,6 +109,13 @@ def test_energy_grid(pu239): 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 @@ -91,18 +155,72 @@ def test_fission(pu239): assert photon.particle == 'photon' -def test_get_reaction_components(h1): - assert h1.get_reaction_components(1) == [2, 102] - assert h1.get_reaction_components(101) == [102] - assert h1.get_reaction_components(102) == [102] - assert h1.get_reaction_components(51) == [] +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_resonances(gd154): +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) @@ -114,8 +232,46 @@ def test_resonances(gd154): assert (resolved.parameters['J'] <= 0.5).all() assert (resolved.parameters['fissionWidthA'] == 0.0).all() - -def test_reconstruct(gd154): 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) From 2e5bfecdaf050ab129771da4744ddb11581f99e5 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 18 Dec 2017 13:40:30 +0700 Subject: [PATCH 05/10] Add tests for openmc.data.thermal --- openmc/data/thermal.py | 25 +++--- tests/unit_tests/test_data_multipole.py | 2 - tests/unit_tests/test_data_thermal.py | 100 ++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 16 deletions(-) create mode 100644 tests/unit_tests/test_data_thermal.py diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index 99e4b5a537..fefb71518b 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -408,30 +408,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 diff --git a/tests/unit_tests/test_data_multipole.py b/tests/unit_tests/test_data_multipole.py index c485abb4fc..dc30677e80 100644 --- a/tests/unit_tests/test_data_multipole.py +++ b/tests/unit_tests/test_data_multipole.py @@ -1,10 +1,8 @@ #!/usr/bin/env python -from collections import Callable import os import numpy as np -import pandas as pd import pytest import openmc.data diff --git a/tests/unit_tests/test_data_thermal.py b/tests/unit_tests/test_data_thermal.py new file mode 100644 index 0000000000..4af815c884 --- /dev/null +++ b/tests/unit_tests/test_data_thermal.py @@ -0,0 +1,100 @@ +#!/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' + + # Names that don't remotely match anything + assert f('boogie_monster') == 'c_boogie_monster' From 6996bbde5c9cd46642c4239f600d785727c32be4 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 18 Dec 2017 17:06:25 +0700 Subject: [PATCH 06/10] Improve coverage of openmc.data (decay, neutron, miscellaneous) --- openmc/data/grid.py | 3 + tests/unit_tests/test_data_decay.py | 82 +++++++++++++++++++++++++ tests/unit_tests/test_data_misc.py | 50 +++++++++++++++ tests/unit_tests/test_data_neutron.py | 88 +++++++++++++++++++++++++++ 4 files changed, 223 insertions(+) create mode 100644 tests/unit_tests/test_data_decay.py create mode 100644 tests/unit_tests/test_data_misc.py diff --git a/openmc/data/grid.py b/openmc/data/grid.py index f08bac9990..e63919ac29 100644 --- a/openmc/data/grid.py +++ b/openmc/data/grid.py @@ -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 = [] diff --git a/tests/unit_tests/test_data_decay.py b/tests/unit_tests/test_data_decay.py new file mode 100644 index 0000000000..be8ad7d64e --- /dev/null +++ b/tests/unit_tests/test_data_decay.py @@ -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)) diff --git a/tests/unit_tests/test_data_misc.py b/tests/unit_tests/test_data_misc.py new file mode 100644 index 0000000000..aeeb04c0fb --- /dev/null +++ b/tests/unit_tests/test_data_misc.py @@ -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) diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py index 4809c56386..502442f5b7 100644 --- a/tests/unit_tests/test_data_neutron.py +++ b/tests/unit_tests/test_data_neutron.py @@ -77,6 +77,13 @@ def na22(): 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') @@ -84,6 +91,12 @@ def h2(): 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 @@ -102,6 +115,15 @@ def test_fission_energy(pu239): 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(): @@ -155,6 +177,13 @@ def test_fission(pu239): 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') @@ -275,3 +304,62 @@ 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')) + retcode = openmc.data.njoy.make_ace(filename, ace=ace_ascii) + assert retcode == 0 + + # 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) From 530f33907b82fc8c8f1373146e27fd832cc41501 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 18 Dec 2017 20:20:22 +0700 Subject: [PATCH 07/10] Raise CalledProcessError when NJOY fails. Py2 fix in laboratory.py --- openmc/data/laboratory.py | 2 +- openmc/data/njoy.py | 86 +++++++++++++++++++-------------------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/openmc/data/laboratory.py b/openmc/data/laboratory.py index 0a89083622..3c240b88d1 100644 --- a/openmc/data/laboratory.py +++ b/openmc/data/laboratory.py @@ -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 diff --git a/openmc/data/njoy.py b/openmc/data/njoy.py index ac98af7fb6..b08b3bdfb3 100644 --- a/openmc/data/njoy.py +++ b/openmc/data/njoy.py @@ -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)) From 39f3ea9327ca080cc5e3e80f801adb868a71369f Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 18 Dec 2017 20:58:31 +0700 Subject: [PATCH 08/10] Build NJOY without shared library --- tools/ci/travis-install-njoy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/travis-install-njoy.sh b/tools/ci/travis-install-njoy.sh index a338cbf4b7..788cfc7a7f 100755 --- a/tools/ci/travis-install-njoy.sh +++ b/tools/ci/travis-install-njoy.sh @@ -5,4 +5,4 @@ git clone https://github.com/njoy/NJOY2016 cd NJOY2016 sed -i -e 's/5\.1/4.8/' CMakeLists.txt mkdir build && cd build -cmake .. && make 2>/dev/null && sudo make install +cmake -Dstatic=on .. && make 2>/dev/null && sudo make install From 9f7e5e85e777f942a48645403c94067d4a2eb6ea Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 19 Dec 2017 14:08:26 +0700 Subject: [PATCH 09/10] Improve guessing in openmc.data.get_thermal_name --- openmc/data/thermal.py | 94 +++++++++++++++------------ tests/unit_tests/test_data_neutron.py | 3 +- tests/unit_tests/test_data_thermal.py | 1 + 3 files changed, 55 insertions(+), 43 deletions(-) diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index fefb71518b..cc549c80ea 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -23,40 +23,40 @@ from openmc.stats import Discrete, Tabular _THERMAL_NAMES = { - 'c_Al27': ('al', 'al27'), - 'c_Be': ('be', 'be-metal'), - '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_D_in_D2O': ('dd2o', 'hwtr', 'hw'), - 'c_Fe56': ('fe', 'fe56'), - 'c_Graphite': ('graph', 'grph', 'gr'), - '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_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_UO2': ('ouo2', 'o2-u', 'o2/u'), - 'c_ortho_D': ('orthod', 'dortho'), - 'c_ortho_H': ('orthoh', 'hortho'), - '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_Zr_in_ZrH': ('zrzrh', 'zr-h', 'zr/h') + 'c_Al27': ['al', 'al27'], + 'c_Be': ['be', 'be-metal'], + '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_D_in_D2O': ['dd2o', 'hwtr', 'hw'], + 'c_Fe56': ['fe', 'fe56'], + 'c_Graphite': ['graph', 'grph', 'gr'], + '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_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_UO2': ['ouo2', 'o2-u', 'o2/u'], + 'c_ortho_D': ['orthod', 'dortho'], + 'c_ortho_H': ['orthoh', 'hortho'], + '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_Zr_in_ZrH': ['zrzrh', 'zr-h', 'zr/h'] } @@ -84,13 +84,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 = sum(_THERMAL_NAMES.values(), []) + all_names += _THERMAL_NAMES.keys() + + 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. ' diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py index 502442f5b7..e314d32a42 100644 --- a/tests/unit_tests/test_data_neutron.py +++ b/tests/unit_tests/test_data_neutron.py @@ -348,8 +348,7 @@ 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')) - retcode = openmc.data.njoy.make_ace(filename, ace=ace_ascii) - assert retcode == 0 + openmc.data.njoy.make_ace(filename, ace=ace_ascii) # Convert to binary openmc.data.ace.ascii_to_binary(ace_ascii, ace_binary) diff --git a/tests/unit_tests/test_data_thermal.py b/tests/unit_tests/test_data_thermal.py index 4af815c884..9def78b38d 100644 --- a/tests/unit_tests/test_data_thermal.py +++ b/tests/unit_tests/test_data_thermal.py @@ -95,6 +95,7 @@ def test_get_thermal_name(): # 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' From 4d3da2e5b1420e352523f473a6003b9dec37a7e9 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 11 Jan 2018 06:22:07 -0600 Subject: [PATCH 10/10] Use itertools.chain in get_thermal_name --- openmc/data/thermal.py | 73 +++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index cc549c80ea..68192de039 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -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 @@ -23,40 +24,40 @@ from openmc.stats import Discrete, Tabular _THERMAL_NAMES = { - 'c_Al27': ['al', 'al27'], - 'c_Be': ['be', 'be-metal'], - '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_D_in_D2O': ['dd2o', 'hwtr', 'hw'], - 'c_Fe56': ['fe', 'fe56'], - 'c_Graphite': ['graph', 'grph', 'gr'], - '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_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_UO2': ['ouo2', 'o2-u', 'o2/u'], - 'c_ortho_D': ['orthod', 'dortho'], - 'c_ortho_H': ['orthoh', 'hortho'], - '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_Zr_in_ZrH': ['zrzrh', 'zr-h', 'zr/h'] + 'c_Al27': ('al', 'al27'), + 'c_Be': ('be', 'be-metal'), + '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_D_in_D2O': ('dd2o', 'hwtr', 'hw'), + 'c_Fe56': ('fe', 'fe56'), + 'c_Graphite': ('graph', 'grph', 'gr'), + '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_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_UO2': ('ouo2', 'o2-u', 'o2/u'), + 'c_ortho_D': ('orthod', 'dortho'), + 'c_ortho_H': ('orthoh', 'hortho'), + '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_Zr_in_ZrH': ('zrzrh', 'zr-h', 'zr/h') } @@ -87,8 +88,8 @@ def get_thermal_name(name): # First, construct a list of all the values/keys in the names # dictionary - all_names = sum(_THERMAL_NAMES.values(), []) - all_names += _THERMAL_NAMES.keys() + all_names = itertools.chain(_THERMAL_NAMES.keys(), + *_THERMAL_NAMES.values()) matches = get_close_matches(name, all_names, cutoff=0.5) if len(matches) > 0: