diff --git a/.gitignore b/.gitignore index a0cfd5c7ff..35f45e747b 100644 --- a/.gitignore +++ b/.gitignore @@ -97,3 +97,7 @@ examples/jupyter/plots *.c *.html *.so + +.cache/ +.tox/ +.python-version diff --git a/.travis.yml b/.travis.yml index 64fbdc9df2..b4462ed0e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,21 +28,7 @@ matrix: env: OPENMC_CONFIG="check_source" before_install: - # ============== Handle Python third-party packages ============== - - if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then - wget https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh; - else - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; - fi - - bash miniconda.sh -b -p $HOME/miniconda - - export PATH="$HOME/miniconda/bin:$PATH" - - hash -r - - conda config --set always_yes yes --set changeps1 no - - conda update -q conda - - conda info -a - if [[ $OPENMC_CONFIG != "check_source" ]]; then - conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION six numpy scipy h5py=2.5 pandas; - source activate test-environment; 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; @@ -52,7 +38,11 @@ before_install: export HDF5_DIR=/usr; fi -install: true +install: + - if [[ $OPENMC_CONFIG != "check_source" ]]; then + pip install numpy cython; + pip install -e .[test]; + fi before_script: - if [[ $OPENMC_CONFIG != "check_source" ]]; then @@ -72,5 +62,6 @@ script: ./check_source.py; else ./run_tests.py -C $OPENMC_CONFIG -j 2; + pytest --cov=../openmc unit_tests/; fi - cd .. diff --git a/CMakeLists.txt b/CMakeLists.txt index 905555a050..0b0bef14ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -468,6 +468,11 @@ file(GLOB_RECURSE TESTS ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_*.py) # Loop through all the tests foreach(test ${TESTS}) + # Remove unit tests + if(test MATCHES ".*unit_tests.*") + continue() + endif() + # Get test information get_filename_component(TEST_NAME ${test} NAME) get_filename_component(TEST_PATH ${test} PATH) diff --git a/CTestConfig.cmake b/CTestConfig.cmake deleted file mode 100644 index e127a8ddf2..0000000000 --- a/CTestConfig.cmake +++ /dev/null @@ -1,25 +0,0 @@ -## This file should be placed in the root directory of your project. -## Then modify the CMakeLists.txt file in the root directory of your -## project to incorporate the testing dashboard. -## # The following are required to uses Dart and the Cdash dashboard -## ENABLE_TESTING() -## INCLUDE(CTest) - -# Generic information about CDASH site -set(CTEST_PROJECT_NAME "OpenMC") -set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC") -set(CTEST_DROP_METHOD "http") -set(CTEST_DROP_SITE "openmc.mit.edu") -set(CTEST_DROP_LOCATION "/cdash/submit.php?project=OpenMC") -set(CTEST_DROP_SITE_CDASH TRUE) - -# Set file size larger to see more output -set(CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE "20000") -set(CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE "20000") - -# User/password to CDASH site -# Please contact Nick Horelik or -# Bryan Herman if you want to push -# test suite information to our CDASH site. -set(CTEST_DROP_SITE_USER "") -set(CTEST_DROP_SITE_PASSWORD "") diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000000..04348222fa --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,35 @@ +include CMakeLists.txt +include LICENSE +include schemas.xml +include openmc/data/reconstruct.pyx +include docs/source/_templates/layout.html +include docs/sphinxext/LICENSE +recursive-include . *.rst +recursive-include cmake *.cmake +recursive-include docs *.css +recursive-include docs *.dia +recursive-include docs *.png +recursive-include docs *.py +recursive-include docs *.svg +recursive-include docs *.tex +recursive-include docs *.txt +recursive-include docs Makefile +recursive-include examples *.h5 +recursive-include examples *.ipynb +recursive-include examples *.png +recursive-include examples *.py +recursive-include examples *.xml +recursive-include man *.1 +recursive-include src *.F90 +recursive-include src *.c +recursive-include src *.cc +recursive-include src *.cpp +recursive-include src *.h +recursive-include src *.hpp +recursive-include src *.rnc +recursive-include src *.rng +recursive-include tests *.dat +recursive-include tests *.h5 +recursive-include tests *.py +recursive-include tests *.xml +prune docs/build diff --git a/Makefile b/Makefile deleted file mode 100644 index 990f22d9d3..0000000000 --- a/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -all: - mkdir -p build - cmake -H. -Bbuild - make -s -C build -clean: - make -s -C build clean -distclean: - rm -fr build -test: - make -s -C build test -install: - make -s -C build install - -.PHONY: all clean distclean test install diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 497e09b4d5..09fc4520c0 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -414,16 +414,19 @@ distributions. various HDF5 files, h5py is needed to provide access to data within these files from Python. -.. admonition:: Optional - :class: note - `Matplotlib `_ Matplotlib is used to providing plotting functionality in the API like the :meth:`Universe.plot` method and the :func:`openmc.plot_xs` function. `uncertainties `_ - Uncertainties are optionally used for decay data in the :mod:`openmc.data` - module. + Uncertainties are used for decay data in the :mod:`openmc.data` module. + + `lxml `_ + lxml is used for the :ref:`scripts_validate` script and various other + parts of the Python API. + +.. admonition:: Optional + :class: note `Cython `_ Cython is used for resonance reconstruction for ENDF data converted to @@ -437,8 +440,8 @@ distributions. The silomesh package is needed to convert voxel and track files to SILO format. - `lxml `_ - lxml is used for the :ref:`scripts_validate` script. + `pytest `_ + The pytest framework is used for unit testing the Python API. .. _usersguide_nxml: diff --git a/readme.rst b/readme.rst index 34d2a5d099..75e4a1438f 100644 --- a/readme.rst +++ b/readme.rst @@ -2,8 +2,7 @@ OpenMC Monte Carlo Particle Transport Code ========================================== -.. image:: https://travis-ci.org/mit-crpg/openmc.svg?branch=develop - :target: https://travis-ci.org/mit-crpg/openmc +|licensebadge| |travisbadge| The OpenMC project aims to provide a fully-featured Monte Carlo particle transport code based on modern methods. It is a constructive solid geometry, @@ -55,3 +54,11 @@ OpenMC is distributed under the MIT/X license_. .. _Troubleshooting section: http://openmc.readthedocs.io/en/stable/usersguide/troubleshoot.html .. _Issues: https://github.com/mit-crpg/openmc/issues .. _license: http://openmc.readthedocs.io/en/stable/license.html + +.. |licensebadge| image:: https://img.shields.io/github/license/mit-crpg/openmc.svg + :target: http://openmc.readthedocs.io/en/latest/license.html + :alt: License + +.. |travisbadge| image:: https://travis-ci.org/mit-crpg/openmc.svg?branch=develop + :target: https://travis-ci.org/mit-crpg/openmc + :alt: Travis CI build status (Linux) diff --git a/setup.py b/setup.py index 7ca824ab01..271fac0f00 100755 --- a/setup.py +++ b/setup.py @@ -3,13 +3,8 @@ import glob import sys import numpy as np -try: - from setuptools import setup - have_setuptools = True -except ImportError: - from distutils.core import setup - have_setuptools = False +from setuptools import setup, find_packages try: from Cython.Build import cythonize have_cython = True @@ -28,47 +23,53 @@ else: with open('openmc/__init__.py', 'r') as f: version = f.readlines()[-1].split()[-1].strip("'") -kwargs = {'name': 'openmc', - 'version': version, - 'packages': ['openmc', 'openmc.capi', 'openmc.data', 'openmc.mgxs', - 'openmc.model', 'openmc.stats'], - 'scripts': glob.glob('scripts/openmc-*'), +kwargs = { + 'name': 'openmc', + 'version': version, + 'packages': find_packages(), + 'scripts': glob.glob('scripts/openmc-*'), - # Data files and librarries - 'package_data': { - 'openmc.capi': ['libopenmc.{}'.format(suffix)], - 'openmc.data': ['mass.mas12', 'fission_Q_data_endfb71.h5'] - }, + # Data files and librarries + 'package_data': { + 'openmc.capi': ['libopenmc.{}'.format(suffix)], + 'openmc.data': ['mass.mas12', 'fission_Q_data_endfb71.h5'] + }, - # Metadata - 'author': 'Will Boyd', - 'author_email': 'wbinventor@gmail.com', - 'description': 'OpenMC Python API', - 'url': 'https://github.com/mit-crpg/openmc', - 'classifiers': [ - 'Intended Audience :: Developers', - 'Intended Audience :: End Users/Desktop', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: MIT License', - 'Natural Language :: English', - 'Programming Language :: Python', - 'Topic :: Scientific/Engineering' - ]} + # Metadata + 'author': 'The OpenMC Development Team', + 'author_email': 'openmc-dev@googlegroups.com', + 'description': 'OpenMC', + 'url': 'https://github.com/mit-crpg/openmc', + 'classifiers': [ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Intended Audience :: End Users/Desktop', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: MIT License', + 'Natural Language :: English', + 'Topic :: Scientific/Engineering' + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + ], -if have_setuptools: - kwargs.update({ - # Required dependencies - 'install_requires': ['six', 'numpy>=1.9', 'h5py', 'scipy', 'pandas>=0.17.0'], + # Required dependencies + 'install_requires': [ + 'six', 'numpy>=1.9', 'h5py', 'scipy', 'ipython', 'matplotlib', + 'pandas>=0.17.0', 'lxml', 'uncertainties' + ], - # Optional dependencies - 'extras_require': { - 'decay': ['uncertainties'], - 'plot': ['matplotlib', 'ipython'], - 'vtk': ['vtk', 'silomesh'], - 'validate': ['lxml'] - }, - - }) + # Optional dependencies + 'extras_require': { + 'test': ['pytest', 'pytest-cov'], + 'vtk': ['vtk', 'silomesh'], + }, +} # If Cython is present, add resonance reconstruction capability if have_cython: diff --git a/tests/run_tests.py b/tests/run_tests.py index 50e9313df3..6e6b886a50 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -10,43 +10,43 @@ import glob import socket from subprocess import call, check_output from collections import OrderedDict -from optparse import OptionParser +from argparse import ArgumentParser # Command line parsing -parser = OptionParser() -parser.add_option('-j', '--parallel', dest='n_procs', default='1', - help="Number of parallel jobs.") -parser.add_option('-R', '--tests-regex', dest='regex_tests', - help="Run tests matching regular expression. \ - Test names are the directories present in tests folder.\ - This uses standard regex syntax to select tests.") -parser.add_option('-C', '--build-config', dest='build_config', - help="Build configurations matching regular expression. \ - Specific build configurations can be printed out with \ - optional argument -p, --print. This uses standard \ - regex syntax to select build configurations.") -parser.add_option('-l', '--list', action="store_true", - dest="list_build_configs", default=False, - help="List out build configurations.") -parser.add_option("-p", "--project", dest="project", default="", - help="project name for build") -parser.add_option("-D", "--dashboard", dest="dash", - help="Dash name -- Experimental, Nightly, Continuous") -parser.add_option("-u", "--update", action="store_true", dest="update", - help="Allow CTest to update repo. (WARNING: may overwrite\ - changes that were not pushed.") -parser.add_option("-s", "--script", action="store_true", dest="script", - help="Activate CTest scripting mode for coverage, valgrind\ - and dashboard capability.") -(options, args) = parser.parse_args() +parser = ArgumentParser() +parser.add_argument('-j', '--parallel', dest='n_procs', default='1', + help="Number of parallel jobs.") +parser.add_argument('-R', '--tests-regex', dest='regex_tests', + help="Run tests matching regular expression. \ + Test names are the directories present in tests folder.\ + This uses standard regex syntax to select tests.") +parser.add_argument('-C', '--build-config', dest='build_config', + help="Build configurations matching regular expression. \ + Specific build configurations can be printed out with \ + optional argument -p, --print. This uses standard \ + regex syntax to select build configurations.") +parser.add_argument('-l', '--list', action="store_true", + dest="list_build_configs", default=False, + help="List out build configurations.") +parser.add_argument("-p", "--project", dest="project", default="", + help="project name for build") +parser.add_argument("-D", "--dashboard", dest="dash", + help="Dash name -- Experimental, Nightly, Continuous") +parser.add_argument("-u", "--update", action="store_true", dest="update", + help="Allow CTest to update repo. (WARNING: may overwrite\ + changes that were not pushed.") +parser.add_argument("-s", "--script", action="store_true", dest="script", + help="Activate CTest scripting mode for coverage, valgrind\ + and dashboard capability.") +args = parser.parse_args() # Default compiler paths -FC='gfortran' -CC='gcc' -CXX='g++' -MPI_DIR='/opt/mpich/3.2-gnu' -HDF5_DIR='/opt/hdf5/1.8.16-gnu' -PHDF5_DIR='/opt/phdf5/1.8.16-gnu' +FC = 'gfortran' +CC = 'gcc' +CXX = 'g++' +MPI_DIR = '/opt/mpich/3.2-gnu' +HDF5_DIR = '/opt/hdf5/1.8.16-gnu' +PHDF5_DIR = '/opt/phdf5/1.8.16-gnu' # Script mode for extra capability script_mode = False @@ -115,6 +115,7 @@ endif() # Define test data structure tests = OrderedDict() + def cleanup(path): """Remove generated output files.""" for dirpath, dirnames, filenames in os.walk(path): @@ -173,7 +174,7 @@ class Test(object): # Sets the build name that will show up on the CDash def get_build_name(self): - self.build_name = options.project + '_' + self.name + self.build_name = args.project + '_' + self.name return self.build_name # Sets up build options for various tests. It is used both @@ -211,7 +212,7 @@ class Test(object): os.environ['HDF5_ROOT'] = PHDF5_DIR else: os.environ['HDF5_ROOT'] = HDF5_DIR - rc = call(['ctest', '-S', 'ctestscript.run','-V']) + rc = call(['ctest', '-S', 'ctestscript.run', '-V']) if rc != 0: self.success = False self.msg = 'Failed on ctest script.' @@ -243,12 +244,12 @@ class Test(object): return # Default make string - make_list = ['make','-s'] + make_list = ['make', '-s'] # Check for parallel - if options.n_procs is not None: + if args.n_procs is not None: make_list.append('-j') - make_list.append(options.n_procs) + make_list.append(args.n_procs) # Run make rc = call(make_list) @@ -265,14 +266,14 @@ class Test(object): ctest_list = ['ctest'] # Check for parallel - if options.n_procs is not None: + if args.n_procs is not None: ctest_list.append('-j') - ctest_list.append(options.n_procs) + ctest_list.append(args.n_procs) # Check for subset of tests - if options.regex_tests is not None: + if args.regex_tests is not None: ctest_list.append('-R') - ctest_list.append(options.regex_tests) + ctest_list.append(args.regex_tests) # Run ctests rc = call(ctest_list) @@ -282,7 +283,7 @@ class Test(object): # Simple function to add a test to the global tests dictionary -def add_test(name, debug=False, optimize=False, mpi=False, openmp=False,\ +def add_test(name, debug=False, optimize=False, mpi=False, openmp=False, phdf5=False, valgrind=False, coverage=False): tests.update({name: Test(name, debug, optimize, mpi, openmp, phdf5, valgrind, coverage)}) @@ -308,7 +309,7 @@ add_test('hdf5-debug_valgrind', debug=True, valgrind=True) add_test('hdf5-debug_coverage', debug=True, coverage=True) # Check to see if we should just print build configuration information to user -if options.list_build_configs: +if args.list_build_configs: for key in tests: print('Configuration Name: {0}'.format(key)) print(' Debug Flags:..........{0}'.format(tests[key].debug)) @@ -320,10 +321,10 @@ if options.list_build_configs: exit() # Delete items of dictionary that don't match regular expression -if options.build_config is not None: +if args.build_config is not None: to_delete = [] for key in tests: - if not re.search(options.build_config, key): + if not re.search(args.build_config, key): to_delete.append(key) for key in to_delete: del tests[key] @@ -333,27 +334,21 @@ if options.build_config is not None: # Experimental, Nightly, Continuous. On the CDash end, these can be # reorganized into groups when a hostname, dashboard and build name # are matched. -if options.dash is None: +if args.dash is None: dash = 'Experimental' submit = '' else: - dash = options.dash + dash = args.dash submit = 'ctest_submit()' # Check for update command, which will run git fetch/merge and will delete # any changes to repo that were not pushed to remote origin -if options.update: - update = 'ctest_update()' -else: - update = '' +update = 'ctest_update()' if args.update else '' # Check for CTest scipts mode # Sets up whether we should use just the basic ctest command or use # CTest scripting to perform tests. -if not options.dash is None or options.script: - script_mode = True -else: - script_mode = False +script_mode = (args.dash is not None or args.script) # Setup CTest script vars. Not used in non-script mode pwd = os.getcwd() @@ -364,17 +359,17 @@ ctest_vars = { 'dashboard': dash, 'submit': submit, 'update': update, - 'n_procs': options.n_procs + 'n_procs': args.n_procs } # Check project name -subprop = """set_property(GLOBAL PROPERTY SubProject {0})""" -if options.project == "" : - ctest_vars.update({'subproject':''}) -elif options.project == 'develop': - ctest_vars.update({'subproject':''}) +subprop = "set_property(GLOBAL PROPERTY SubProject {0})" +if args.project == "": + ctest_vars.update({'subproject': ''}) +elif args.project == 'develop': + ctest_vars.update({'subproject': ''}) else: - ctest_vars.update({'subproject':subprop.format(options.project)}) + ctest_vars.update({'subproject': subprop.format(args.project)}) # Set up default valgrind tests (subset of all tests) # Currently takes too long to run all the tests with valgrind @@ -396,8 +391,8 @@ if not script_mode: for key in to_delete: del tests[key] -# Check if tests empty -if len(list(tests.keys())) == 0: +# Check if tests is empty +if not tests: print('No tests to run.') exit() @@ -447,16 +442,16 @@ for key in iter(tests): # Check for user custom tests # INCLUDE is a CTest command that allows for a subset # of tests to be executed. Only used in script mode. - if options.regex_tests is None: - ctest_vars.update({'tests' : ''}) + if args.regex_tests is None: + ctest_vars.update({'tests': ''}) # No user tests, use default valgrind tests if test.valgrind: - ctest_vars.update({'tests' : 'INCLUDE {0}'. + ctest_vars.update({'tests': 'INCLUDE {0}'. format(valgrind_default_tests)}) else: - ctest_vars.update({'tests' : 'INCLUDE {0}'. - format(options.regex_tests)}) + ctest_vars.update({'tests': 'INCLUDE {0}'. + format(args.regex_tests)}) # Main part of code that does the ctest execution. # It is broken up by two modes, script and non-script diff --git a/tests/test_element_wo/test_element_wo.py b/tests/unit_tests/test_element_wo.py similarity index 92% rename from tests/test_element_wo/test_element_wo.py rename to tests/unit_tests/test_element_wo.py index e2a5726f19..7b9487f73d 100644 --- a/tests/test_element_wo/test_element_wo.py +++ b/tests/unit_tests/test_element_wo.py @@ -5,13 +5,11 @@ import sys import numpy as np -sys.path.insert(0, os.pardir) -sys.path.insert(0, os.path.join(os.pardir, os.pardir)) from openmc import Material from openmc.data import NATURAL_ABUNDANCE, atomic_mass -if __name__ == '__main__': +def test_element_wo(): # This test doesn't require an OpenMC run. We just need to make sure the # element.expand() method expands elements with the proper nuclide # compositions.