From e9101ab57f9fb4ab076ff9eb2a3b5e85aaafc21b Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Fri, 19 Jul 2024 01:25:36 +0100 Subject: [PATCH 01/76] draft scikit build core wheel --- CMakeLists.txt | 10 ++++++++++ openmc/__init__.py | 1 + openmc/openmc_exec.py | 22 ++++++++++++++++++++++ pyproject.toml | 9 ++++++++- setup.py | 11 +++++++++-- 5 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 openmc/openmc_exec.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f4cc1b527b..d7fa6cb2a2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,11 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # Set module path set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) +# Conditionally find Python if building with scikit-build-core +if(SKBUILD) + find_package(Python COMPONENTS Interpreter Development.Module REQUIRED) +endif() + # Enable correct usage of CXX_EXTENSIONS if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.22) cmake_policy(SET CMP0128 NEW) @@ -614,3 +619,8 @@ install(FILES man/man1/openmc.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) install(FILES LICENSE DESTINATION "${CMAKE_INSTALL_DOCDIR}" RENAME copyright) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(FILES "${CMAKE_BINARY_DIR}/include/openmc/version.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/openmc) + +if(SKBUILD) + install(TARGETS openmc RUNTIME DESTINATION openmc/bin) + install(TARGETS libopenmc LIBRARY DESTINATION openmc/lib) +endif() diff --git a/openmc/__init__.py b/openmc/__init__.py index 566d287068f..32320365d58 100644 --- a/openmc/__init__.py +++ b/openmc/__init__.py @@ -34,6 +34,7 @@ from openmc.polynomial import * from openmc.tracks import * from .config import * +from .openmc_exec import main # Import a few names from the model module from openmc.model import Model diff --git a/openmc/openmc_exec.py b/openmc/openmc_exec.py new file mode 100644 index 00000000000..72cd283beff --- /dev/null +++ b/openmc/openmc_exec.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +# helper script that launches the openmc binary + +import os +import sys +import sysconfig +from pathlib import Path + + +def main(): + lib_path = sysconfig.get_path("platlib") + "openmc/lib/openmc" + os.environ["LD_LIBRARY_PATH"] = ( + lib_path + ":" + os.environ.get("LD_LIBRARY_PATH", "") + ) + os.execv( + Path(sysconfig.get_path("platlib")) / "openmc" / "bin" / "openmc", sys.argv + ) + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml index d1b2c335cd7..08bc9ad1313 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,6 @@ [build-system] -requires = ["setuptools", "wheel", "numpy", "cython"] +requires = ["setuptools", "wheel", "numpy", "cython", "scikit-build-core"] +build-backend = "scikit_build_core.build" [project] name = "openmc" @@ -72,3 +73,9 @@ openmc-track-to-vtk = "scripts.openmc_track_to_vtk:main" openmc-update-inputs = "scripts.openmc_update_inputs:main" openmc-update-mgxs = "scripts.openmc_update_mgxs:main" openmc-voxel-to-vtk = "scripts.openmc_voxel_to_vtk:main" +openmc-exec = "openmc.openmc_exec:main" + +[tool.scikit-build] +cmake.verbose = true +# cmake args can be passed in here or in the command line via exports or inline with the pip install +cmake.args = ["-DCMAKE_BUILD_TYPE=RELEASE"] \ No newline at end of file diff --git a/setup.py b/setup.py index 4e24f48a123..32cf2483ce0 100755 --- a/setup.py +++ b/setup.py @@ -1,13 +1,20 @@ #!/usr/bin/env python +import os import numpy as np -from setuptools import setup +from setuptools import setup, Extension from Cython.Build import cythonize +class OpenMCExtension(Extension): + def __init__(self, name, cmake_lists_dir=".", sources=[], **kwa): + Extension.__init__(self, name, sources=sources, **kwa) + self.cmake_lists_dir = os.path.abspath(cmake_lists_dir) + + kwargs = { # Cython is used to add resonance reconstruction and fast float_endf - 'ext_modules': cythonize('openmc/data/*.pyx'), + 'ext_modules': cythonize('openmc/data/*.pyx') + [OpenMCExtension('libopenmc')], 'include_dirs': [np.get_include()] } From e857f4529cd8833c475ee1cecbf6af7e48a61493 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Fri, 19 Jul 2024 01:31:11 +0100 Subject: [PATCH 02/76] renamed executable --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 08bc9ad1313..69090111b33 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,7 +73,7 @@ openmc-track-to-vtk = "scripts.openmc_track_to_vtk:main" openmc-update-inputs = "scripts.openmc_update_inputs:main" openmc-update-mgxs = "scripts.openmc_update_mgxs:main" openmc-voxel-to-vtk = "scripts.openmc_voxel_to_vtk:main" -openmc-exec = "openmc.openmc_exec:main" +openmc = "openmc.openmc_exec:main" [tool.scikit-build] cmake.verbose = true From 61b7035681230cb0c94e8b819584ee104873faed Mon Sep 17 00:00:00 2001 From: Jon Shimwell Date: Fri, 19 Jul 2024 10:02:52 +0100 Subject: [PATCH 03/76] linking libopenmc with openmc in cmakelists --- CMakeLists.txt | 7 ++++++- openmc/openmc_exec.py | 4 ---- pyproject.toml | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d7fa6cb2a2f..7c86c391521 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -332,6 +332,11 @@ if("${isSystemDir}" STREQUAL "-1") set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}") endif() +if(SKBUILD) + set(CMAKE_INSTALL_RPATH "$ORIGIN") + set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) +endif() + #=============================================================================== # libopenmc #=============================================================================== @@ -622,5 +627,5 @@ install(FILES "${CMAKE_BINARY_DIR}/include/openmc/version.h" DESTINATION ${CMAKE if(SKBUILD) install(TARGETS openmc RUNTIME DESTINATION openmc/bin) - install(TARGETS libopenmc LIBRARY DESTINATION openmc/lib) + install(TARGETS libopenmc LIBRARY DESTINATION openmc/bin) endif() diff --git a/openmc/openmc_exec.py b/openmc/openmc_exec.py index 72cd283beff..579eeced24f 100644 --- a/openmc/openmc_exec.py +++ b/openmc/openmc_exec.py @@ -9,10 +9,6 @@ def main(): - lib_path = sysconfig.get_path("platlib") + "openmc/lib/openmc" - os.environ["LD_LIBRARY_PATH"] = ( - lib_path + ":" + os.environ.get("LD_LIBRARY_PATH", "") - ) os.execv( Path(sysconfig.get_path("platlib")) / "openmc" / "bin" / "openmc", sys.argv ) diff --git a/pyproject.toml b/pyproject.toml index 08bc9ad1313..c236b968035 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,9 +73,9 @@ openmc-track-to-vtk = "scripts.openmc_track_to_vtk:main" openmc-update-inputs = "scripts.openmc_update_inputs:main" openmc-update-mgxs = "scripts.openmc_update_mgxs:main" openmc-voxel-to-vtk = "scripts.openmc_voxel_to_vtk:main" -openmc-exec = "openmc.openmc_exec:main" +openmc = "openmc.openmc_exec:main" [tool.scikit-build] cmake.verbose = true # cmake args can be passed in here or in the command line via exports or inline with the pip install -cmake.args = ["-DCMAKE_BUILD_TYPE=RELEASE"] \ No newline at end of file +cmake.args = ["-DCMAKE_BUILD_TYPE=RELEASE"] From 2541d50e557653ba6dc17e70c47db8431edc72a4 Mon Sep 17 00:00:00 2001 From: Jon Shimwell Date: Sat, 20 Jul 2024 00:08:42 +0100 Subject: [PATCH 04/76] updated docs for pip install that compiles --- docs/source/quickinstall.rst | 25 ++++++------------ docs/source/usersguide/install.rst | 42 +++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/docs/source/quickinstall.rst b/docs/source/quickinstall.rst index 7f222f77cb8..3e0778a9eca 100644 --- a/docs/source/quickinstall.rst +++ b/docs/source/quickinstall.rst @@ -160,28 +160,19 @@ download and install OpenMC by entering the following commands in a terminal: git clone --recurse-submodules https://github.com/openmc-dev/openmc.git cd openmc - mkdir build && cd build - cmake .. - make - sudo make install + python -m pip install . -This will build an executable named ``openmc`` and install it (by default in -/usr/local/bin). If you do not have administrator privileges, the cmake command -should specify an installation directory where you have write access, e.g. +The easiest way to install it is using `pip `_. +This `pip` command will install the `openmc` Python package and compile an executable named ``openmc`` +and install it (by default in the bin folder of the Python package directory). .. code-block:: sh - cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local .. - -The :mod:`openmc` Python package must be installed separately. The easiest way -to install it is using `pip `_. -From the root directory of the OpenMC repository, run: + python -m pip install . --global-option="build_ext" --global-option="--" --global-option="-DOPENMC_USE_MPI=ON" -.. code-block:: sh - - python -m pip install . +The compilion of the ``openmc`` can be customised by specifying CMake arguments. By default, OpenMC will be built with multithreading support. To build -distributed-memory parallel versions of OpenMC using MPI or to configure other -options, directions can be found in the :ref:`detailed installation instructions +distributed-memory parallel versions of OpenMC using MPI the above command can be run. +There are other options that can be set, more details can be found in the :ref:`detailed installation instructions `. diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 130e96c0ae6..203ec879430 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -175,9 +175,9 @@ feature can be used to access the installed packages. .. _install_source: ----------------------- -Installing from Source ----------------------- +-------------------------------- +Compiling from Source with CMake +-------------------------------- .. _prerequisites: @@ -367,6 +367,8 @@ Note that first a build directory is created as a subdirectory of the source directory. The Makefile in the top-level directory will automatically perform an out-of-source build with default options. +.. _cmake_arguemnts: + CMakeLists.txt Options ++++++++++++++++++++++ @@ -505,15 +507,15 @@ To run the test suite, you will first need to download a pre-generated cross section library along with windowed multipole data. Please refer to our :ref:`devguide_tests` documentation for further details. ---------------------- -Installing Python API ---------------------- +----------------------------------------------- +Installing Python API and compiling from source +----------------------------------------------- If you installed OpenMC using :ref:`Conda `, no further steps are necessary in order to use OpenMC's :ref:`Python API `. However, if -you are :ref:`installing from source `, the Python API is not -installed by default when ``make install`` is run because in many situations it -doesn't make sense to install a Python package in the same location as the +you are :ref:`Compiling from Source with CMake `, the Python API +is not installed by default when ``make install`` is run because in many situations +it doesn't make sense to install a Python package in the same location as the ``openmc`` executable (for example, if you are installing the package into a `virtual environment `_). The easiest way to install the :mod:`openmc` Python package is to use pip_, which is @@ -527,7 +529,27 @@ distribution/repository, run: pip will first check that all :ref:`required third-party packages ` have been installed, and if they are not present, they will be installed by downloading the appropriate packages from the Python -Package Index (`PyPI `_). +Package Index (`PyPI `_). The pip command will also compile +an executable named ``openmc`` and install it (by default in the bin folder of +the Python package directory). + +Passing CMake Options to via pip +-------------------------------- + +If you need to pass CMake options to the build process, you can do so by +running pip install with some additional options. All the CMake arguments +covered in the :ref:`CMakeLists.txt Options` are supported. +For example, to build OpenMC with MPI support, you can run: + +.. code-block:: sh + + python -m pip install . --global-option="build_ext" --global-option="--" --global-option="-DOPENMC_USE_MPI=ON" + +To build OpenMC with DAGMC support two CMake arguments are needed, you can run: + +.. code-block:: sh + + python -m pip install . --global-option="build_ext" --global-option="--" --global-option="-DOPENMC_USE_DAGMC=ON" --global-option="-DDAGMC_ROOT=/path/to/dagmc/installation" Installing in "Development" Mode -------------------------------- From f15e80f00537660919b2d8ff9d8b66f65562953b Mon Sep 17 00:00:00 2001 From: Jon Shimwell Date: Tue, 23 Jul 2024 19:04:34 +0100 Subject: [PATCH 05/76] pip install with cmake args in ci --- tools/ci/gha-install.py | 33 ++++++++++++++++----------------- tools/ci/gha-install.sh | 3 --- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/tools/ci/gha-install.py b/tools/ci/gha-install.py index f4b2fbb3187..5cf46baa24c 100644 --- a/tools/ci/gha-install.py +++ b/tools/ci/gha-install.py @@ -26,48 +26,47 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrys os.chdir('build') # Build in debug mode by default with support for MCPL - cmake_cmd = ['cmake', '-DCMAKE_BUILD_TYPE=Debug', '-DOPENMC_USE_MCPL=on'] + pip_command = ['pip' 'install' '.[test,vtk]'] + pip_suffix = ['--config-settings=cmake.args=-DCMAKE_BUILD_TYPE=ON;-DOPENMC_USE_MCPL=ON'] # Turn off OpenMP if specified if not omp: - cmake_cmd.append('-DOPENMC_USE_OPENMP=off') + pip_suffix.append('-DOPENMC_USE_OPENMP=off') # Use MPI wrappers when building in parallel if mpi: - cmake_cmd.append('-DOPENMC_USE_MPI=on') + pip_suffix.append('-DOPENMC_USE_MPI=on') # Tell CMake to prefer parallel HDF5 if specified if phdf5: if not mpi: raise ValueError('Parallel HDF5 must be used in ' 'conjunction with MPI.') - cmake_cmd.append('-DHDF5_PREFER_PARALLEL=ON') + pip_suffix.append('-DHDF5_PREFER_PARALLEL=ON') else: - cmake_cmd.append('-DHDF5_PREFER_PARALLEL=OFF') + pip_suffix.append('-DHDF5_PREFER_PARALLEL=OFF') if dagmc: - cmake_cmd.append('-DOPENMC_USE_DAGMC=ON') - cmake_cmd.append('-DCMAKE_PREFIX_PATH=~/DAGMC') + pip_suffix.append('-DOPENMC_USE_DAGMC=ON') + pip_suffix.append('-DCMAKE_PREFIX_PATH=~/DAGMC') if libmesh: - cmake_cmd.append('-DOPENMC_USE_LIBMESH=ON') + pip_suffix.append('-DOPENMC_USE_LIBMESH=ON') libmesh_path = os.environ.get('HOME') + '/LIBMESH' - cmake_cmd.append('-DCMAKE_PREFIX_PATH=' + libmesh_path) + pip_suffix.append('-DCMAKE_PREFIX_PATH=' + libmesh_path) if ncrystal: - cmake_cmd.append('-DOPENMC_USE_NCRYSTAL=ON') + pip_suffix.append('-DOPENMC_USE_NCRYSTAL=ON') ncrystal_cmake_path = os.environ.get('HOME') + '/ncrystal_inst/lib/cmake' - cmake_cmd.append(f'-DCMAKE_PREFIX_PATH={ncrystal_cmake_path}') + pip_suffix.append(f'-DCMAKE_PREFIX_PATH={ncrystal_cmake_path}') # Build in coverage mode for coverage testing - cmake_cmd.append('-DOPENMC_ENABLE_COVERAGE=on') + pip_suffix.append('-DOPENMC_ENABLE_COVERAGE=on') + pip_command.append(';'.join(pip_suffix)) # Build and install - cmake_cmd.append('..') - print(' '.join(cmake_cmd)) - subprocess.check_call(cmake_cmd) - subprocess.check_call(['make', '-j4']) - subprocess.check_call(['sudo', 'make', 'install']) + print(' '.join(pip_command)) + subprocess.check_call(pip_command) def main(): # Convert Travis matrix environment variables into arguments for install() diff --git a/tools/ci/gha-install.sh b/tools/ci/gha-install.sh index 2cef974d346..1673edd4ada 100755 --- a/tools/ci/gha-install.sh +++ b/tools/ci/gha-install.sh @@ -47,9 +47,6 @@ fi # Build and install OpenMC executable python tools/ci/gha-install.py -# Install Python API in editable mode -pip install -e .[test,vtk] - # For coverage testing of the C++ source files pip install cpp-coveralls From 3c98d8a8346746d1c0cd90dd60ed33c4799d5b39 Mon Sep 17 00:00:00 2001 From: Jon Shimwell Date: Tue, 23 Jul 2024 19:59:07 +0100 Subject: [PATCH 06/76] added missing , --- tools/ci/gha-install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/gha-install.py b/tools/ci/gha-install.py index 5cf46baa24c..f8c9ebe7e53 100644 --- a/tools/ci/gha-install.py +++ b/tools/ci/gha-install.py @@ -26,7 +26,7 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrys os.chdir('build') # Build in debug mode by default with support for MCPL - pip_command = ['pip' 'install' '.[test,vtk]'] + pip_command = ['pip', 'install', '.[test,vtk]'] pip_suffix = ['--config-settings=cmake.args=-DCMAKE_BUILD_TYPE=ON;-DOPENMC_USE_MCPL=ON'] # Turn off OpenMP if specified From 0aafd44dda9cdaffca73e83fd42c201eec0fbae5 Mon Sep 17 00:00:00 2001 From: Jon Shimwell Date: Tue, 23 Jul 2024 20:02:44 +0100 Subject: [PATCH 07/76] no need for manual creation of build dir --- tools/ci/gha-install.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/ci/gha-install.py b/tools/ci/gha-install.py index f8c9ebe7e53..536df1f9377 100644 --- a/tools/ci/gha-install.py +++ b/tools/ci/gha-install.py @@ -1,5 +1,4 @@ import os -import shutil import subprocess def which(program): @@ -20,10 +19,6 @@ def is_exe(fpath): def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrystal=False): - # Create build directory and change to it - shutil.rmtree('build', ignore_errors=True) - os.mkdir('build') - os.chdir('build') # Build in debug mode by default with support for MCPL pip_command = ['pip', 'install', '.[test,vtk]'] From 9ef3beb1603bd286467dccbfa13eca87f29c9bf2 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Fri, 26 Jul 2024 13:05:41 +0100 Subject: [PATCH 08/76] [skip ci] adding apt packages for read the docs --- .readthedocs.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index b7b69f9fe59..fb49db819e5 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -4,6 +4,11 @@ build: os: "ubuntu-20.04" tools: python: "3.10" + apt_package: + - g++ + - cmake + - libhdf5-dev + - libpng-dev sphinx: configuration: docs/source/conf.py From 40ceaadea68b02e6758b4ef0a66194371095456c Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Fri, 26 Jul 2024 13:17:20 +0100 Subject: [PATCH 09/76] [skip ci] trying ubuntu 22.04 --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index fb49db819e5..e5d69973b34 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,7 +1,7 @@ version: 2 build: - os: "ubuntu-20.04" + os: "ubuntu-22.04" tools: python: "3.10" apt_package: From 2c8cf714a716d77bcf9363d4e93abd73bb93defa Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Fri, 26 Jul 2024 13:18:08 +0100 Subject: [PATCH 10/76] [skip ci] added missing s --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index e5d69973b34..bcbea55994e 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -4,7 +4,7 @@ build: os: "ubuntu-22.04" tools: python: "3.10" - apt_package: + apt_packages: - g++ - cmake - libhdf5-dev From 4c0075f0f3fdb7562beff590a71de2da7ad0f9d7 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Fri, 26 Jul 2024 17:52:37 +0100 Subject: [PATCH 11/76] adding gha actions --- .github/workflows/ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9293e319b42..1415074ad71 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -145,9 +145,7 @@ jobs: - name: test shell: bash - run: | - CTEST_OUTPUT_ON_FAILURE=1 make test -C $GITHUB_WORKSPACE/build/ - $GITHUB_WORKSPACE/tools/ci/gha-script.sh + run: $GITHUB_WORKSPACE/tools/ci/gha-script.sh - name: after_success shell: bash From 4de0d948f0feceaa5c3fa1e4c1119f6db2224697 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Fri, 26 Jul 2024 23:30:11 +0100 Subject: [PATCH 12/76] upper case ON for cmake args --- tools/ci/gha-install.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ci/gha-install.py b/tools/ci/gha-install.py index cb1b23b2433..a03c89712b1 100644 --- a/tools/ci/gha-install.py +++ b/tools/ci/gha-install.py @@ -14,7 +14,7 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrys # Use MPI wrappers when building in parallel if mpi: - pip_suffix.append('-DOPENMC_USE_MPI=on') + pip_suffix.append('-DOPENMC_USE_MPI=ON') # Tell CMake to prefer parallel HDF5 if specified if phdf5: @@ -40,7 +40,7 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrys pip_suffix.append(f'-DCMAKE_PREFIX_PATH={ncrystal_cmake_path}') # Build in coverage mode for coverage testing - pip_suffix.append('-DOPENMC_ENABLE_COVERAGE=on') + pip_suffix.append('-DOPENMC_ENABLE_COVERAGE=ON') pip_command.append(';'.join(pip_suffix)) # Build and install From 688d6882d59e56da6b3f2e191986b788fadf7982 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Sat, 27 Jul 2024 00:09:17 +0100 Subject: [PATCH 13/76] added quotes to cmake args --- tools/ci/gha-pip-install.py | 63 +++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 tools/ci/gha-pip-install.py diff --git a/tools/ci/gha-pip-install.py b/tools/ci/gha-pip-install.py new file mode 100644 index 00000000000..dde7535e0d6 --- /dev/null +++ b/tools/ci/gha-pip-install.py @@ -0,0 +1,63 @@ +import os +import subprocess + + +def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrystal=False): + + # Build in debug mode by default with support for MCPL + pip_command = ['pip', 'install', '.[test,vtk]'] + pip_suffix = ['--config-settings=cmake.args="-DCMAKE_BUILD_TYPE=ON;-DOPENMC_USE_MCPL=ON'] + + # Turn off OpenMP if specified + if not omp: + pip_suffix.append('-DOPENMC_USE_OPENMP=off') + + # Use MPI wrappers when building in parallel + if mpi: + pip_suffix.append('-DOPENMC_USE_MPI=ON') + + # Tell CMake to prefer parallel HDF5 if specified + if phdf5: + if not mpi: + raise ValueError('Parallel HDF5 must be used in ' + 'conjunction with MPI.') + pip_suffix.append('-DHDF5_PREFER_PARALLEL=ON') + else: + pip_suffix.append('-DHDF5_PREFER_PARALLEL=OFF') + + if dagmc: + pip_suffix.append('-DOPENMC_USE_DAGMC=ON') + pip_suffix.append('-DCMAKE_PREFIX_PATH=~/DAGMC') + + if libmesh: + pip_suffix.append('-DOPENMC_USE_LIBMESH=ON') + libmesh_path = os.environ.get('HOME') + '/LIBMESH' + pip_suffix.append('-DCMAKE_PREFIX_PATH=' + libmesh_path) + + if ncrystal: + pip_suffix.append('-DOPENMC_USE_NCRYSTAL=ON') + ncrystal_cmake_path = os.environ.get('HOME') + '/ncrystal_inst/lib/cmake' + pip_suffix.append(f'-DCMAKE_PREFIX_PATH={ncrystal_cmake_path}') + + # Build in coverage mode for coverage testing + pip_suffix.append('-DOPENMC_ENABLE_COVERAGE=ON"') + + pip_command.append(';'.join(pip_suffix)) + # Build and install + print(' '.join(pip_command)) + subprocess.check_call(pip_command) + +def main(): + # Convert Travis matrix environment variables into arguments for install() + omp = (os.environ.get('OMP') == 'y') + mpi = (os.environ.get('MPI') == 'y') + phdf5 = (os.environ.get('PHDF5') == 'y') + dagmc = (os.environ.get('DAGMC') == 'y') + ncrystal = (os.environ.get('NCRYSTAL') == 'y') + libmesh = (os.environ.get('LIBMESH') == 'y') + + # Build and install + install(omp, mpi, phdf5, dagmc, libmesh, ncrystal) + +if __name__ == '__main__': + main() From 07a4dcd473fc048aeb4baf22bceb22fb203aa9a0 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Sat, 27 Jul 2024 00:26:08 +0100 Subject: [PATCH 14/76] keeping same filename --- .github/workflows/ci.yml | 4 ++- tools/ci/gha-install.py | 4 +-- tools/ci/gha-pip-install.py | 63 ------------------------------------- 3 files changed, 5 insertions(+), 66 deletions(-) delete mode 100644 tools/ci/gha-pip-install.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1415074ad71..9293e319b42 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -145,7 +145,9 @@ jobs: - name: test shell: bash - run: $GITHUB_WORKSPACE/tools/ci/gha-script.sh + run: | + CTEST_OUTPUT_ON_FAILURE=1 make test -C $GITHUB_WORKSPACE/build/ + $GITHUB_WORKSPACE/tools/ci/gha-script.sh - name: after_success shell: bash diff --git a/tools/ci/gha-install.py b/tools/ci/gha-install.py index a03c89712b1..dde7535e0d6 100644 --- a/tools/ci/gha-install.py +++ b/tools/ci/gha-install.py @@ -6,7 +6,7 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrys # Build in debug mode by default with support for MCPL pip_command = ['pip', 'install', '.[test,vtk]'] - pip_suffix = ['--config-settings=cmake.args=-DCMAKE_BUILD_TYPE=ON;-DOPENMC_USE_MCPL=ON'] + pip_suffix = ['--config-settings=cmake.args="-DCMAKE_BUILD_TYPE=ON;-DOPENMC_USE_MCPL=ON'] # Turn off OpenMP if specified if not omp: @@ -40,7 +40,7 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrys pip_suffix.append(f'-DCMAKE_PREFIX_PATH={ncrystal_cmake_path}') # Build in coverage mode for coverage testing - pip_suffix.append('-DOPENMC_ENABLE_COVERAGE=ON') + pip_suffix.append('-DOPENMC_ENABLE_COVERAGE=ON"') pip_command.append(';'.join(pip_suffix)) # Build and install diff --git a/tools/ci/gha-pip-install.py b/tools/ci/gha-pip-install.py deleted file mode 100644 index dde7535e0d6..00000000000 --- a/tools/ci/gha-pip-install.py +++ /dev/null @@ -1,63 +0,0 @@ -import os -import subprocess - - -def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrystal=False): - - # Build in debug mode by default with support for MCPL - pip_command = ['pip', 'install', '.[test,vtk]'] - pip_suffix = ['--config-settings=cmake.args="-DCMAKE_BUILD_TYPE=ON;-DOPENMC_USE_MCPL=ON'] - - # Turn off OpenMP if specified - if not omp: - pip_suffix.append('-DOPENMC_USE_OPENMP=off') - - # Use MPI wrappers when building in parallel - if mpi: - pip_suffix.append('-DOPENMC_USE_MPI=ON') - - # Tell CMake to prefer parallel HDF5 if specified - if phdf5: - if not mpi: - raise ValueError('Parallel HDF5 must be used in ' - 'conjunction with MPI.') - pip_suffix.append('-DHDF5_PREFER_PARALLEL=ON') - else: - pip_suffix.append('-DHDF5_PREFER_PARALLEL=OFF') - - if dagmc: - pip_suffix.append('-DOPENMC_USE_DAGMC=ON') - pip_suffix.append('-DCMAKE_PREFIX_PATH=~/DAGMC') - - if libmesh: - pip_suffix.append('-DOPENMC_USE_LIBMESH=ON') - libmesh_path = os.environ.get('HOME') + '/LIBMESH' - pip_suffix.append('-DCMAKE_PREFIX_PATH=' + libmesh_path) - - if ncrystal: - pip_suffix.append('-DOPENMC_USE_NCRYSTAL=ON') - ncrystal_cmake_path = os.environ.get('HOME') + '/ncrystal_inst/lib/cmake' - pip_suffix.append(f'-DCMAKE_PREFIX_PATH={ncrystal_cmake_path}') - - # Build in coverage mode for coverage testing - pip_suffix.append('-DOPENMC_ENABLE_COVERAGE=ON"') - - pip_command.append(';'.join(pip_suffix)) - # Build and install - print(' '.join(pip_command)) - subprocess.check_call(pip_command) - -def main(): - # Convert Travis matrix environment variables into arguments for install() - omp = (os.environ.get('OMP') == 'y') - mpi = (os.environ.get('MPI') == 'y') - phdf5 = (os.environ.get('PHDF5') == 'y') - dagmc = (os.environ.get('DAGMC') == 'y') - ncrystal = (os.environ.get('NCRYSTAL') == 'y') - libmesh = (os.environ.get('LIBMESH') == 'y') - - # Build and install - install(omp, mpi, phdf5, dagmc, libmesh, ncrystal) - -if __name__ == '__main__': - main() From 9253977ac3df5a29b2b021fb6112c509b7794c54 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Sat, 27 Jul 2024 00:37:54 +0100 Subject: [PATCH 15/76] running just pytest --- .github/workflows/ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9293e319b42..1415074ad71 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -145,9 +145,7 @@ jobs: - name: test shell: bash - run: | - CTEST_OUTPUT_ON_FAILURE=1 make test -C $GITHUB_WORKSPACE/build/ - $GITHUB_WORKSPACE/tools/ci/gha-script.sh + run: $GITHUB_WORKSPACE/tools/ci/gha-script.sh - name: after_success shell: bash From 1f016940ee9e6c0c6e2eba5bf71912729ee2bf63 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Sat, 27 Jul 2024 00:39:43 +0100 Subject: [PATCH 16/76] [skip ci] corrected cmake arg passing example --- docs/source/usersguide/install.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 203ec879430..c0ad2fdcd48 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -176,7 +176,7 @@ feature can be used to access the installed packages. .. _install_source: -------------------------------- -Compiling from Source with CMake +Compiling from source with CMake -------------------------------- .. _prerequisites: @@ -533,7 +533,7 @@ Package Index (`PyPI `_). The pip command will also compile an executable named ``openmc`` and install it (by default in the bin folder of the Python package directory). -Passing CMake Options to via pip +Passing CMake arguments via pip -------------------------------- If you need to pass CMake options to the build process, you can do so by @@ -543,13 +543,13 @@ For example, to build OpenMC with MPI support, you can run: .. code-block:: sh - python -m pip install . --global-option="build_ext" --global-option="--" --global-option="-DOPENMC_USE_MPI=ON" + python -m pip install . --config-settings=cmake.args=-DOPENMC_USE_MPI=ON To build OpenMC with DAGMC support two CMake arguments are needed, you can run: .. code-block:: sh - python -m pip install . --global-option="build_ext" --global-option="--" --global-option="-DOPENMC_USE_DAGMC=ON" --global-option="-DDAGMC_ROOT=/path/to/dagmc/installation" + python -m pip install . --config-settings=cmake.args="-DOPENMC_USE_DAGMC=ON;DDAGMC_ROOT=/path/to/dagmc/installation" Installing in "Development" Mode -------------------------------- From 6850217ad5dffdcc1874c052b809c154166dfc84 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Sat, 27 Jul 2024 01:02:49 +0100 Subject: [PATCH 17/76] added diagnosis prints --- CMakeLists.txt | 11 +++++++++++ tools/ci/gha-install.py | 1 + 2 files changed, 12 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c86c391521..928f72c245f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,17 @@ option(OPENMC_USE_MCPL "Enable MCPL" option(OPENMC_USE_NCRYSTAL "Enable support for NCrystal scattering" OFF) option(OPENMC_USE_UWUW "Enable UWUW" OFF) +message(STATUS "OPENMC_USE_OPENMP ${OPENMC_USE_OPENMP}") +message(STATUS "OPENMC_BUILD_TESTS ${OPENMC_BUILD_TESTS}") +message(STATUS "OPENMC_ENABLE_PROFILE ${OPENMC_ENABLE_PROFILE}") +message(STATUS "OPENMC_ENABLE_COVERAGE ${OPENMC_ENABLE_COVERAGE}") +message(STATUS "OPENMC_USE_DAGMC ${OPENMC_USE_DAGMC}") +message(STATUS "OPENMC_USE_LIBMESH ${OPENMC_USE_LIBMESH}") +message(STATUS "OPENMC_USE_MPI ${OPENMC_USE_MPI}") +message(STATUS "OPENMC_USE_MCPL ${OPENMC_USE_MCPL}") +message(STATUS "OPENMC_USE_NCRYSTAL ${OPENMC_USE_NCRYSTAL}") +message(STATUS "OPENMC_USE_UWUW ${OPENMC_USE_UWUW}") + # Warnings for deprecated options foreach(OLD_OPT IN ITEMS "openmp" "profile" "coverage" "dagmc" "libmesh") if(DEFINED ${OLD_OPT}) diff --git a/tools/ci/gha-install.py b/tools/ci/gha-install.py index dde7535e0d6..4ef2e780d3f 100644 --- a/tools/ci/gha-install.py +++ b/tools/ci/gha-install.py @@ -43,6 +43,7 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrys pip_suffix.append('-DOPENMC_ENABLE_COVERAGE=ON"') pip_command.append(';'.join(pip_suffix)) + pip_command.append('--verbose') # Build and install print(' '.join(pip_command)) subprocess.check_call(pip_command) From 97a3f22bdf532315f5381310ce540a374272f7cc Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Sat, 27 Jul 2024 01:15:36 +0100 Subject: [PATCH 18/76] removed 2nd pip install which was overwritting --- tools/ci/gha-install.py | 2 +- tools/ci/gha-install.sh | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/tools/ci/gha-install.py b/tools/ci/gha-install.py index 4ef2e780d3f..da94df1bc2b 100644 --- a/tools/ci/gha-install.py +++ b/tools/ci/gha-install.py @@ -5,7 +5,7 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrystal=False): # Build in debug mode by default with support for MCPL - pip_command = ['pip', 'install', '.[test,vtk]'] + pip_command = ['pip', 'install', '.[test,vtk,ci]'] pip_suffix = ['--config-settings=cmake.args="-DCMAKE_BUILD_TYPE=ON;-DOPENMC_USE_MCPL=ON'] # Turn off OpenMP if specified diff --git a/tools/ci/gha-install.sh b/tools/ci/gha-install.sh index 87952fda9cb..e69aaaa13fb 100755 --- a/tools/ci/gha-install.sh +++ b/tools/ci/gha-install.sh @@ -46,6 +46,3 @@ fi # Build and install OpenMC executable python tools/ci/gha-install.py - -# Install Python API in editable mode -pip install -e .[test,vtk,ci] From 021339254c29b65875f7f0c7b02351e6b9a497b8 Mon Sep 17 00:00:00 2001 From: Jon Shimwell Date: Wed, 14 Aug 2024 21:37:22 +0100 Subject: [PATCH 19/76] matching simulation results from ci --- tests/regression_tests/triso/results_true.dat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression_tests/triso/results_true.dat b/tests/regression_tests/triso/results_true.dat index fa1842e547d..a24354045e2 100644 --- a/tests/regression_tests/triso/results_true.dat +++ b/tests/regression_tests/triso/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.716873E+00 5.266107E-02 +1.716873E+00 5.266094E-02 From 6e3e47e11de207419b91114fe07fc6fb0cd4c224 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Thu, 12 Sep 2024 14:36:43 +0100 Subject: [PATCH 20/76] using debug instead of on for DCMAKE_BUILD_TYPE --- tools/ci/gha-install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/gha-install.py b/tools/ci/gha-install.py index da94df1bc2b..004ce589300 100644 --- a/tools/ci/gha-install.py +++ b/tools/ci/gha-install.py @@ -6,7 +6,7 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrys # Build in debug mode by default with support for MCPL pip_command = ['pip', 'install', '.[test,vtk,ci]'] - pip_suffix = ['--config-settings=cmake.args="-DCMAKE_BUILD_TYPE=ON;-DOPENMC_USE_MCPL=ON'] + pip_suffix = ['--config-settings=cmake.args="-DCMAKE_BUILD_TYPE=DEBUG;-DOPENMC_USE_MCPL=ON'] # Turn off OpenMP if specified if not omp: From b4b4e3a14280932ef210179052eb3d444a42607c Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Tue, 17 Sep 2024 08:22:24 +0600 Subject: [PATCH 21/76] scikit-build-core added --- CMakeLists.txt | 2 +- MANIFEST.in | 48 ------------------------------------------------ pyproject.toml | 25 +++++++++++++------------ 3 files changed, 14 insertions(+), 61 deletions(-) delete mode 100644 MANIFEST.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f4cc1b527b..bd3d011b66f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.16 FATAL_ERROR) +cmake_minimum_required(VERSION 3.18 FATAL_ERROR) project(openmc C CXX) # Set version numbers diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index b73218af0dc..00000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,48 +0,0 @@ -include CMakeLists.txt -include LICENSE -include CODE_OF_CONDUCT.md -include CODEOWNERS -include CONTRIBUTING.md -include Dockerfile -include schemas.xml -include pyproject.toml -include pytest.ini -include docs/source/_templates/layout.html -global-include *.cmake -global-include *.cmake.in -global-include *.rst -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 *.cpp -recursive-include examples *.py -recursive-include examples *.xml -recursive-include include *.h -recursive-include include *.h.in -recursive-include include *.hh -recursive-include man *.1 -recursive-include src *.cc -recursive-include src *.cpp -recursive-include src *.rnc -recursive-include src *.rng -recursive-include tests *.dat -recursive-include tests *.h5 -recursive-include tests *.h5m -recursive-include tests *.py -recursive-include tests *.xml -recursive-include vendor CMakeLists.txt -recursive-include vendor *.cc -recursive-include vendor *.cpp -recursive-include vendor *.h -recursive-include vendor *.hh -recursive-include vendor *.hpp -recursive-include vendor *.pc.in -recursive-include vendor *.natvis -include vendor/gsl-lite/include/gsl/gsl -prune docs/build -prune docs/source/pythonapi/generated/ diff --git a/pyproject.toml b/pyproject.toml index 39aa261c1b4..6700f5d8f43 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,15 @@ [build-system] -requires = ["setuptools", "wheel"] -build-backend = "setuptools.build_meta" +requires = ["scikit-build-core"] +build-backend = "scikit_build_core.build" [project] name = "openmc" +version = "0.15.1-dev" authors = [ {name = "The OpenMC Development Team", email = "openmc@anl.gov"}, ] -description = "OpenMC" -version = "0.15.1-dev" -requires-python = ">=3.10" +description = "OpenMC is a community-developed Monte Carlo neutron and photon transport code." +readme = "README.md" license = {file = "LICENSE"} classifiers = [ "Development Status :: 4 - Beta", @@ -25,6 +25,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", ] +requires-python = ">=3.10" dependencies = [ "numpy", "h5py", @@ -58,14 +59,14 @@ Documentation = "https://docs.openmc.org" Repository = "https://github.com/openmc-dev/openmc" Issues = "https://github.com/openmc-dev/openmc/issues" -[tool.setuptools.packages.find] -include = ['openmc*', 'scripts*'] -exclude = ['tests*'] +# Scikit-Build Configuration +[tool.scikit-build] +cmake.verbose = true +logging.level = "INFO" +wheel.install-dir = "pyne/core" +wheel.packages = ["pyne"] +wheel.exclude = ["CMakeLists.txt"] -[tool.setuptools.package-data] -"openmc.data.effective_dose" = ["*.txt"] -"openmc.data" = ["*.txt", "*.DAT", "*.json", "*.h5"] -"openmc.lib" = ["libopenmc.dylib", "libopenmc.so"] [project.scripts] openmc-ace-to-hdf5 = "scripts.openmc_ace_to_hdf5:main" From 79ae016b1a5b7d92d127dae74cfc6c8191c0626d Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Fri, 20 Sep 2024 23:47:34 +0600 Subject: [PATCH 22/76] Add rpath --- CMakeLists.txt | 91 +++++++++++++++++++++++++++++++++++++++----------- pyproject.toml | 16 ++------- 2 files changed, 74 insertions(+), 33 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd3d011b66f..0570d30ac0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -310,23 +310,52 @@ include(GNUInstallDirs) # installed one in CMAKE_INSTALL_PREFIX. Ref: # https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/RPATH-handling -# use, i.e. don't skip the full RPATH for the build tree -set(CMAKE_SKIP_BUILD_RPATH FALSE) -# when building, don't use the install RPATH already -# (but later on when installing) -set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) +if(SKBUILD) + # Scikit-build installs OpenMC to ${SKBUILD_PLATLIB_DIR}/openmc + # So, set bin directory to root environment (install prefix/bin) + set(CMAKE_INSTALL_BINDIR ${SKBUILD_SCRIPTS_DIR}) + # Unfortunately, OpenMC has lib directory in the openmc/lib subdirectory + set(CMAKE_INSTALL_LIBDIR lib) + set(SKBUILD_LIB_DIR openmc/${CMAKE_INSTALL_LIBDIR}) + + # Auditwheel and Delocate need this when repairing the wheel + # Since OpenMC libs are installed in the openmc/core subdirectory + # Auditwheel and Delocate need this to find the OpenMC libs for openmc.data + # It's a bit of a hack, but it works + set(SKBUILD_REPAIR_WHEEL_PATCH ../../openmc/${CMAKE_INSTALL_LIBDIR}) + if(APPLE) + set(CMAKE_MACOSX_RPATH ON) + set(OPENMC_LIBRARY_RPATH "@loader_path") + set(OPENMC_PYTHON_MODULE_RPATH "@loader_path/${CMAKE_INSTALL_LIBDIR}") + set(OPENMC_BINARY_RPATH "@loader_path/../${SKBUILD_LIB_DIR};@loader_path/../../${SKBUILD_LIB_DIR}") + elseif(UNIX) + set(OPENMC_LIBRARY_RPATH "$ORIGIN") + set(OPENMC_PYTHON_MODULE_RPATH "$ORIGIN/${CMAKE_INSTALL_LIBDIR}") + set(OPENMC_BINARY_RPATH "$ORIGIN/../${SKBUILD_LIB_DIR};$ORIGIN/../../${SKBUILD_LIB_DIR}") + else() + set(OPENMC_LIBRARY_RPATH OFF) + set(OPENMC_PYTHON_MODULE_RPATH OFF) + set(OPENMC_BINARY_RPATH OFF) + endif() +else() + # use, i.e. don't skip the full RPATH for the build tree + set(CMAKE_SKIP_BUILD_RPATH FALSE) -# add the automatically determined parts of the RPATH -# which point to directories outside the build tree to the install RPATH -set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + # when building, don't use the install RPATH already + # (but later on when installing) + set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) -# the RPATH to be used when installing, but only if it's not a system directory -list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_FULL_LIBDIR}" isSystemDir) -if("${isSystemDir}" STREQUAL "-1") - set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}") -endif() + # add the automatically determined parts of the RPATH + # which point to directories outside the build tree to the install RPATH + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + # the RPATH to be used when installing, but only if it's not a system directory + list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_FULL_LIBDIR}" isSystemDir) + if("${isSystemDir}" STREQUAL "-1") + set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}") + endif() +endif() #=============================================================================== # libopenmc #=============================================================================== @@ -472,6 +501,14 @@ target_include_directories(libopenmc # Set compile flags target_compile_options(libopenmc PRIVATE ${cxxflags}) +if(SKBUILD) + set_target_properties( + libopenmc + PROPERTIES + INSTALL_RPATH "${OPENMC_LIBRARY_RPATH}" + ) +endif() + # Add include directory for configured version file target_include_directories(libopenmc PUBLIC $) @@ -577,16 +614,24 @@ target_compile_features(openmc PUBLIC cxx_std_17) target_compile_features(libopenmc PUBLIC cxx_std_17) set_target_properties(openmc libopenmc PROPERTIES CXX_EXTENSIONS OFF) +if(SKBUILD) + set_target_properties( + openmc + PROPERTIES + INSTALL_RPATH "${OPENMC_BINARY_RPATH}" + ) +endif() + #=============================================================================== # Python package #=============================================================================== - -add_custom_command(TARGET libopenmc POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - $ - ${CMAKE_CURRENT_SOURCE_DIR}/openmc/lib/$ - COMMENT "Copying libopenmc to Python module directory") - +if(NOT SKBUILD) + add_custom_command(TARGET libopenmc POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + $ + ${CMAKE_CURRENT_SOURCE_DIR}/openmc/lib/$ + COMMENT "Copying libopenmc to Python module directory") +endif() #=============================================================================== # Install executable, scripts, manpage, license #=============================================================================== @@ -606,6 +651,12 @@ install(EXPORT openmc-targets NAMESPACE OpenMC:: DESTINATION ${INSTALL_CONFIGDIR}) +# Collect scripts +file(GLOB SCRIPTS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/*") + +# Install scripts to bin directory +install(PROGRAMS ${SCRIPTS} DESTINATION ${CMAKE_INSTALL_BINDIR}) + install(FILES "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfig.cmake" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfigVersion.cmake" diff --git a/pyproject.toml b/pyproject.toml index 6700f5d8f43..16d16106798 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,18 +61,8 @@ Issues = "https://github.com/openmc-dev/openmc/issues" # Scikit-Build Configuration [tool.scikit-build] -cmake.verbose = true +build.verbose = true logging.level = "INFO" -wheel.install-dir = "pyne/core" -wheel.packages = ["pyne"] +wheel.install-dir = "openmc" +wheel.packages = ["openmc"] wheel.exclude = ["CMakeLists.txt"] - - -[project.scripts] -openmc-ace-to-hdf5 = "scripts.openmc_ace_to_hdf5:main" -openmc-plot-mesh-tally = "scripts.openmc_plot_mesh_tally:main" -openmc-track-combine = "scripts.openmc_track_combine:main" -openmc-track-to-vtk = "scripts.openmc_track_to_vtk:main" -openmc-update-inputs = "scripts.openmc_update_inputs:main" -openmc-update-mgxs = "scripts.openmc_update_mgxs:main" -openmc-voxel-to-vtk = "scripts.openmc_voxel_to_vtk:main" From 394b0f97fe39524b00ea729358f97f22c9e9ca25 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Tue, 24 Sep 2024 08:05:06 +0600 Subject: [PATCH 23/76] Install by scikit-build-core --- Dockerfile | 45 ++++++++++----------------------- tools/ci/gha-install.py | 56 +++++++++++++++++++++++------------------ tools/ci/gha-install.sh | 4 +-- 3 files changed, 46 insertions(+), 59 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4a94e3c0b11..f4c011310c8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -195,40 +195,21 @@ ENV LIBMESH_INSTALL_DIR=$HOME/LIBMESH # clone and install openmc RUN mkdir -p ${HOME}/OpenMC && cd ${HOME}/OpenMC \ && git clone --shallow-submodules --recurse-submodules --single-branch -b ${openmc_branch} --depth=1 ${OPENMC_REPO} \ - && mkdir build && cd build ; \ - if [ ${build_dagmc} = "on" ] && [ ${build_libmesh} = "on" ]; then \ - cmake ../openmc \ - -DCMAKE_CXX_COMPILER=mpicxx \ - -DOPENMC_USE_MPI=on \ - -DHDF5_PREFER_PARALLEL=on \ - -DOPENMC_USE_DAGMC=on \ - -DOPENMC_USE_LIBMESH=on \ - -DCMAKE_PREFIX_PATH="${DAGMC_INSTALL_DIR};${LIBMESH_INSTALL_DIR}" ; \ + && cd openmc ; \ + export SKBUILD_CMAKE_ARGS="-DCMAKE_CXX_COMPILER=mpicxx; \ + -DOPENMC_USE_MPI=on; \ + -DHDF5_PREFER_PARALLEL=on" \ + if [ ${build_dagmc} = "on" ]; then \ + SKBUILD_CMAKE_ARGS="${SKBUILD_CMAKE_ARGS}; \ + -DOPENMC_USE_DAGMC=on; \ + -DCMAKE_PREFIX_PATH=${DAGMC_INSTALL_DIR}" ; \ fi ; \ - if [ ${build_dagmc} = "on" ] && [ ${build_libmesh} = "off" ]; then \ - cmake ../openmc \ - -DCMAKE_CXX_COMPILER=mpicxx \ - -DOPENMC_USE_MPI=on \ - -DHDF5_PREFER_PARALLEL=on \ - -DOPENMC_USE_DAGMC=ON \ - -DCMAKE_PREFIX_PATH=${DAGMC_INSTALL_DIR} ; \ + if [ ${build_libmesh} = "on" ]; then \ + SKBUILD_CMAKE_ARGS="${SKBUILD_CMAKE_ARGS}; \ + -DOPENMC_USE_LIBMESH=on; \ + -DCMAKE_PREFIX_PATH=${LIBMESH_INSTALL_DIR}" ; \ fi ; \ - if [ ${build_dagmc} = "off" ] && [ ${build_libmesh} = "on" ]; then \ - cmake ../openmc \ - -DCMAKE_CXX_COMPILER=mpicxx \ - -DOPENMC_USE_MPI=on \ - -DHDF5_PREFER_PARALLEL=on \ - -DOPENMC_USE_LIBMESH=on \ - -DCMAKE_PREFIX_PATH=${LIBMESH_INSTALL_DIR} ; \ - fi ; \ - if [ ${build_dagmc} = "off" ] && [ ${build_libmesh} = "off" ]; then \ - cmake ../openmc \ - -DCMAKE_CXX_COMPILER=mpicxx \ - -DOPENMC_USE_MPI=on \ - -DHDF5_PREFER_PARALLEL=on ; \ - fi ; \ - make 2>/dev/null -j${compile_cores} install \ - && cd ../openmc && pip install .[test,depletion-mpi] \ + pip -v install .[test,depletion-mpi] \ && python -c "import openmc" FROM build AS release diff --git a/tools/ci/gha-install.py b/tools/ci/gha-install.py index f046e863470..9a72c32e1c7 100644 --- a/tools/ci/gha-install.py +++ b/tools/ci/gha-install.py @@ -1,56 +1,64 @@ import os -import shutil import subprocess +import shutil def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrystal=False): - # Create build directory and change to it - shutil.rmtree('build', ignore_errors=True) - os.mkdir('build') - os.chdir('build') - - # Build in debug mode by default with support for MCPL - cmake_cmd = ['cmake', '-DCMAKE_BUILD_TYPE=Debug', '-DOPENMC_USE_MCPL=on'] + # List to store the CMake arguments + cmake_args = ['-DCMAKE_BUILD_TYPE=Debug', '-DOPENMC_USE_MCPL=on'] # Turn off OpenMP if specified if not omp: - cmake_cmd.append('-DOPENMC_USE_OPENMP=off') + cmake_args.append('-DOPENMC_USE_OPENMP=off') # Use MPI wrappers when building in parallel if mpi: - cmake_cmd.append('-DOPENMC_USE_MPI=on') + cmake_args.append('-DOPENMC_USE_MPI=on') # Tell CMake to prefer parallel HDF5 if specified if phdf5: if not mpi: - raise ValueError('Parallel HDF5 must be used in ' - 'conjunction with MPI.') - cmake_cmd.append('-DHDF5_PREFER_PARALLEL=ON') + raise ValueError('Parallel HDF5 must be used in conjunction with MPI.') + cmake_args.append('-DHDF5_PREFER_PARALLEL=ON') else: - cmake_cmd.append('-DHDF5_PREFER_PARALLEL=OFF') + cmake_args.append('-DHDF5_PREFER_PARALLEL=OFF') if dagmc: - cmake_cmd.append('-DOPENMC_USE_DAGMC=ON') - cmake_cmd.append('-DCMAKE_PREFIX_PATH=~/DAGMC') + cmake_args.append('-DOPENMC_USE_DAGMC=ON') + cmake_args.append('-DCMAKE_PREFIX_PATH=~/DAGMC') if libmesh: - cmake_cmd.append('-DOPENMC_USE_LIBMESH=ON') + cmake_args.append('-DOPENMC_USE_LIBMESH=ON') libmesh_path = os.environ.get('HOME') + '/LIBMESH' - cmake_cmd.append('-DCMAKE_PREFIX_PATH=' + libmesh_path) + cmake_args.append('-DCMAKE_PREFIX_PATH=' + libmesh_path) if ncrystal: - cmake_cmd.append('-DOPENMC_USE_NCRYSTAL=ON') + cmake_args.append('-DOPENMC_USE_NCRYSTAL=ON') ncrystal_cmake_path = os.environ.get('HOME') + '/ncrystal_inst/lib/cmake' - cmake_cmd.append(f'-DCMAKE_PREFIX_PATH={ncrystal_cmake_path}') + cmake_args.append(f'-DCMAKE_PREFIX_PATH={ncrystal_cmake_path}') # Build in coverage mode for coverage testing - cmake_cmd.append('-DOPENMC_ENABLE_COVERAGE=on') + cmake_args.append('-DOPENMC_ENABLE_COVERAGE=on') - # Build and install - cmake_cmd.append('..') + # Set environment variable for SKBUILD + os.environ['SKBUILD_CMAKE_ARGS'] = ';'.join(cmake_args) + + # Run pip to build and install + subprocess.check_call(['pip', '-v', 'install', '.[test,vtk,ci]']) + + # Using standard CMake method + # Create build directory and change to it + shutil.rmtree('build', ignore_errors=True) + os.mkdir('build') + os.chdir('build') + + # Add CMake arguments for standard method + cmake_cmd = ['cmake', '..'] + cmake_args print(' '.join(cmake_cmd)) + + # Run CMake and build subprocess.check_call(cmake_cmd) - subprocess.check_call(['make', '-j4']) + subprocess.check_call(['make', '-j$(nproc)']) subprocess.check_call(['sudo', 'make', 'install']) def main(): diff --git a/tools/ci/gha-install.sh b/tools/ci/gha-install.sh index cff7dc834f5..9a302c23f0b 100755 --- a/tools/ci/gha-install.sh +++ b/tools/ci/gha-install.sh @@ -43,8 +43,6 @@ if [[ $MPI == 'y' ]]; then pip install --no-binary=h5py h5py fi -# Build and install OpenMC executable +# Build and install OpenMC python tools/ci/gha-install.py -# Install Python API in editable mode -pip install -e .[test,vtk,ci] From 12aec226081e64b22e76d5957af592a125999ac4 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Tue, 24 Sep 2024 11:21:12 +0600 Subject: [PATCH 24/76] update python install doc --- docs/source/devguide/workflow.rst | 17 +++++------ docs/source/quickinstall.rst | 49 +++++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/docs/source/devguide/workflow.rst b/docs/source/devguide/workflow.rst index d6a3c6ba4f4..136b97c313f 100644 --- a/docs/source/devguide/workflow.rst +++ b/docs/source/devguide/workflow.rst @@ -116,15 +116,14 @@ pip_. From the root directory of the OpenMC repository, run: .. code-block:: sh - python -m pip install -e .[test] - -This installs the OpenMC Python package in `"editable" mode -`_ so that 1) -it can be imported from a Python interpreter and 2) any changes made are -immediately reflected in the installed version (that is, you don't need to keep -reinstalling it). While the same effect can be achieved using the -:envvar:`PYTHONPATH` environment variable, this is generally discouraged as it -can interfere with virtual environments. +python -m pip install --no-build-isolation \ + -Ceditable.rebuild=true \ + -Ccmake.build-type=Debug \ + -Cbuild-dir=build \ + -ve ".[test]" + +This feature allows for rebuilding on initial import, providing +flexibility for iterative development or testing changes to the codebase. .. _git: http://git-scm.com/ .. _GitHub: https://github.com/ diff --git a/docs/source/quickinstall.rst b/docs/source/quickinstall.rst index 7f222f77cb8..05f4f0a1805 100644 --- a/docs/source/quickinstall.rst +++ b/docs/source/quickinstall.rst @@ -150,13 +150,20 @@ source below. Building Source on Linux or macOS --------------------------------- -All OpenMC source code is hosted on `GitHub -`_. If you have `git -`_, a modern C++ compiler, `CMake `_, -and `HDF5 `_ installed, you can -download and install OpenMC by entering the following commands in a terminal: +All OpenMC source code is hosted on GitHub (`OpenMC GitHub `_). +Depending on your needs, you can either: -.. code-block:: sh +- Build only the OpenMC executable (using CMake). +- Build both the OpenMC executable and Python package (using pip). + +1. Building the OpenMC Executable Only (CMake) +============================================== + +If you only need the OpenMC executable without Python bindings, you can build it using +the following steps. You will need `git `_, a modern C++ compiler, +`CMake `_, and `HDF5 `_ installed: + +.. code-block:: bash git clone --recurse-submodules https://github.com/openmc-dev/openmc.git cd openmc @@ -172,15 +179,39 @@ should specify an installation directory where you have write access, e.g. .. code-block:: sh cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local .. + make + make install + +2. Building the OpenMC Executable with Python Support (pip) +=========================================================== -The :mod:`openmc` Python package must be installed separately. The easiest way -to install it is using `pip `_. -From the root directory of the OpenMC repository, run: +If you also want to install the OpenMC Python package,you can use +`pip `_ to build both the executable and +the Python package at the same time. This requires a Python environment +and pip installed. From the root directory of the OpenMC repository, run: .. code-block:: sh python -m pip install . +This will build the ``openmc`` executable and install it along with the Python bindings. +There is no need to manually run ``cmake`` or ``make``, as the pip command handles +both the C++ and Python build processes. + +Custom Build Options +~~~~~~~~~~~~~~~~~~~~ + +If you need to customize the build options (e.g., enabling MPI, DAGMC, or LibMesh), +you can pass CMake arguments using the ``SKBUILD_CMAKE_ARGS`` environment variable +before running pip. For example: + +.. code-block:: bash + + export SKBUILD_CMAKE_ARGS="-DOPENMC_USE_MPI=on;-DOPENMC_USE_DAGMC=on" + python -m pip install ".[test,depletion-mpi]" + +This allows you to configure your build just like you would with CMake. + By default, OpenMC will be built with multithreading support. To build distributed-memory parallel versions of OpenMC using MPI or to configure other options, directions can be found in the :ref:`detailed installation instructions From 564cb5fa3b5173049e6756046e50f63980e8a821 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Tue, 24 Sep 2024 11:21:31 +0600 Subject: [PATCH 25/76] add support for dev mode --- CMakeLists.txt | 19 ++++++++---- docs/source/usersguide/install.rst | 48 +++++++++++++++++++++++------- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0570d30ac0c..0edf8108f28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -312,27 +312,33 @@ include(GNUInstallDirs) if(SKBUILD) + # Find necessary packages + find_package( + Python + COMPONENTS Interpreter + REQUIRED + ) # Scikit-build installs OpenMC to ${SKBUILD_PLATLIB_DIR}/openmc # So, set bin directory to root environment (install prefix/bin) set(CMAKE_INSTALL_BINDIR ${SKBUILD_SCRIPTS_DIR}) # Unfortunately, OpenMC has lib directory in the openmc/lib subdirectory set(CMAKE_INSTALL_LIBDIR lib) - set(SKBUILD_LIB_DIR openmc/${CMAKE_INSTALL_LIBDIR}) + set(SKBUILD_LIB_DIR ${CMAKE_INSTALL_LIBDIR}/python${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}/site-packages/openmc/${CMAKE_INSTALL_LIBDIR}) # Auditwheel and Delocate need this when repairing the wheel # Since OpenMC libs are installed in the openmc/core subdirectory # Auditwheel and Delocate need this to find the OpenMC libs for openmc.data # It's a bit of a hack, but it works - set(SKBUILD_REPAIR_WHEEL_PATCH ../../openmc/${CMAKE_INSTALL_LIBDIR}) + set(SKBUILD_REPAIR_WHEEL_PATCH openmc/${CMAKE_INSTALL_LIBDIR}) if(APPLE) set(CMAKE_MACOSX_RPATH ON) set(OPENMC_LIBRARY_RPATH "@loader_path") set(OPENMC_PYTHON_MODULE_RPATH "@loader_path/${CMAKE_INSTALL_LIBDIR}") - set(OPENMC_BINARY_RPATH "@loader_path/../${SKBUILD_LIB_DIR};@loader_path/../../${SKBUILD_LIB_DIR}") + set(OPENMC_BINARY_RPATH "@loader_path/../${SKBUILD_LIB_DIR};@loader_path/../${SKBUILD_REPAIR_WHEEL_PATCH};@loader_path/../../${SKBUILD_REPAIR_WHEEL_PATCH}") elseif(UNIX) set(OPENMC_LIBRARY_RPATH "$ORIGIN") set(OPENMC_PYTHON_MODULE_RPATH "$ORIGIN/${CMAKE_INSTALL_LIBDIR}") - set(OPENMC_BINARY_RPATH "$ORIGIN/../${SKBUILD_LIB_DIR};$ORIGIN/../../${SKBUILD_LIB_DIR}") + set(OPENMC_BINARY_RPATH "$ORIGIN/../${SKBUILD_LIB_DIR};$ORIGIN/../${SKBUILD_REPAIR_WHEEL_PATCH};$ORIGIN/../../${SKBUILD_REPAIR_WHEEL_PATCH}") else() set(OPENMC_LIBRARY_RPATH OFF) set(OPENMC_PYTHON_MODULE_RPATH OFF) @@ -623,9 +629,10 @@ if(SKBUILD) endif() #=============================================================================== -# Python package +# Copy libopenmc to Python module directory for development #=============================================================================== -if(NOT SKBUILD) +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) add_custom_command(TARGET libopenmc POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 1c0b7fa5b32..07398bcb20b 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -510,19 +510,45 @@ Installing Python API --------------------- If you installed OpenMC using :ref:`Conda `, no further steps are -necessary in order to use OpenMC's :ref:`Python API `. However, if -you are :ref:`installing from source `, the Python API is not -installed by default when ``make install`` is run because in many situations it -doesn't make sense to install a Python package in the same location as the -``openmc`` executable (for example, if you are installing the package into a -`virtual environment `_). The -easiest way to install the :mod:`openmc` Python package is to use pip_, which is -included by default in Python 3.4+. From the root directory of the OpenMC -distribution/repository, run: +necessary to use OpenMC's :ref:`Python API `. However, if you are +:ref:`installing from source `, the Python API is not installed +by default when building OpenMC because, in many cases, it doesn't make sense to +install a Python package in the same location as the OpenMC executable (for example, +if you are using a virtual environment `virtualenv `_). -.. code-block:: sh +To install OpenMC and its Python API, the recommended method is to use pip, +which includes both the Python package and the OpenMC executable. +From the root directory of the OpenMC repository, run: + +.. code-block:: bash + + python -m pip install ".[test,depletion-mpi]" + +This command installs both the OpenMC executable and the Python API together. +There's no need to manually run ``cmake`` or ``make install`` as pip automatically +handles the build process, including any CMake configuration. + +Custom Build Options +==================== + +If you need to customize the build (for example, to enable MPI, DAGMC, or LibMesh), +you can pass the necessary CMake arguments through the ``SKBUILD_CMAKE_ARGS`` +environment variable before running pip install: + +.. code-block:: bash + + export SKBUILD_CMAKE_ARGS="-DOPENMC_USE_MPI=on;-DOPENMC_USE_DAGMC=on" + python -m pip install ".[test,depletion-mpi]" + +Alternatively, pip provides additional ways to configure the build using +``--config-settings``: + +.. code-block:: bash - python -m pip install . + python -m pip install . -v --config-settings=build.verbose=true \ + --config-settings=logging.level=INFO \ + --config-settings=cmake.define.SOME_DEFINE=ON \ + --config-settings=cmake.args="-DSOME_DEFINE=ON;-DOTHER=OFF" pip will first check that all :ref:`required third-party packages ` have been installed, and if they are not present, From 1f1faca345085b42e350141a16f059fc617a40c6 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Tue, 24 Sep 2024 11:24:28 +0600 Subject: [PATCH 26/76] update dev doc with skbuild support --- docs/source/devguide/workflow.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/source/devguide/workflow.rst b/docs/source/devguide/workflow.rst index 136b97c313f..3b8cb2044b1 100644 --- a/docs/source/devguide/workflow.rst +++ b/docs/source/devguide/workflow.rst @@ -63,9 +63,9 @@ features and bug fixes. The general steps for contributing are as follows: .. code-block:: sh - git clone --recurse-submodules git@github.com:yourusername/openmc.git - cd openmc - git checkout -b newbranch develop + git clone --recurse-submodules git@github.com:yourusername/openmc.git + cd openmc + git checkout -b newbranch develop 3. Run ``tools/dev/install-commit-hooks.sh`` to install a post-commit hook that runs clang-format on C++ files to apply :ref:`automatic code formatting @@ -116,11 +116,11 @@ pip_. From the root directory of the OpenMC repository, run: .. code-block:: sh -python -m pip install --no-build-isolation \ - -Ceditable.rebuild=true \ - -Ccmake.build-type=Debug \ - -Cbuild-dir=build \ - -ve ".[test]" + python -m pip install --no-build-isolation \ + -Ceditable.rebuild=true \ + -Ccmake.build-type=Debug \ + -Cbuild-dir=build \ + -ve ".[test]" This feature allows for rebuilding on initial import, providing flexibility for iterative development or testing changes to the codebase. From f1142657d888e5340d6f46a6c4a477ee0012b184 Mon Sep 17 00:00:00 2001 From: Jon Shimwell Date: Wed, 25 Sep 2024 09:39:30 +0200 Subject: [PATCH 27/76] back to -j4 for make --- tools/ci/gha-install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/gha-install.py b/tools/ci/gha-install.py index 9a72c32e1c7..9fe64d3aafa 100644 --- a/tools/ci/gha-install.py +++ b/tools/ci/gha-install.py @@ -58,7 +58,7 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrys # Run CMake and build subprocess.check_call(cmake_cmd) - subprocess.check_call(['make', '-j$(nproc)']) + subprocess.check_call(['make', '-j4']) subprocess.check_call(['sudo', 'make', 'install']) def main(): From c577d509b4f0845857d13f3d37dd19a8098dceac Mon Sep 17 00:00:00 2001 From: Jon Shimwell Date: Wed, 25 Sep 2024 11:25:39 +0200 Subject: [PATCH 28/76] adding cmake args to pip install command --- tools/ci/gha-install.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/ci/gha-install.py b/tools/ci/gha-install.py index 9fe64d3aafa..4ed863f304f 100644 --- a/tools/ci/gha-install.py +++ b/tools/ci/gha-install.py @@ -44,7 +44,8 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrys os.environ['SKBUILD_CMAKE_ARGS'] = ';'.join(cmake_args) # Run pip to build and install - subprocess.check_call(['pip', '-v', 'install', '.[test,vtk,ci]']) + pip_suffix = '--config-settings=cmake.args="' + ';'.join(cmake_args) + '"' + subprocess.check_call(['pip', '-v', 'install', '.[test,vtk,ci]', pip_suffix]) # Using standard CMake method # Create build directory and change to it From ec7e11f75bf974a3ec6982a7821d109de43f0c0d Mon Sep 17 00:00:00 2001 From: Jon Shimwell Date: Wed, 25 Sep 2024 11:31:22 +0200 Subject: [PATCH 29/76] [skip ci] cmake args actual openmc options --- docs/source/usersguide/install.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 60fb99104c4..f9cbfa6f4dd 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -547,9 +547,7 @@ Alternatively, pip provides additional ways to configure the build using .. code-block:: bash - python -m pip install . -v --config-settings=build.verbose=true \ - --config-settings=cmake.define.SOME_DEFINE=ON \ - --config-settings=cmake.args="-DSOME_DEFINE=ON;-DOTHER=OFF" + python -m pip install . --config-settings=cmake.args="-OPENMC_USE_MPI=ON;-OPENMC_USE_MCPL=ON" pip will first check that all :ref:`required third-party packages ` have been installed, and if they are not present, From 03a6744679f8cc4d15ac9e08055c583e10d21201 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Mon, 30 Sep 2024 19:30:30 +0600 Subject: [PATCH 30/76] add manylinux docker --- tools/ci/manylinux.dockerfile | 378 ++++++++++++++++++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100644 tools/ci/manylinux.dockerfile diff --git a/tools/ci/manylinux.dockerfile b/tools/ci/manylinux.dockerfile new file mode 100644 index 00000000000..20669e766ae --- /dev/null +++ b/tools/ci/manylinux.dockerfile @@ -0,0 +1,378 @@ +# Configure base image +ARG MANYLINUX_IMAGE=manylinux_2_28_x86_64 +ARG Python_ABI="cp312-cp312" + +# Configure dependencies tags +ARG NJOY2016_TAG="2016.76" +ARG HDF5_TAG="hdf5_1.14.4.3" +ARG NETCDF_TAG="v4.9.2" +ARG MOAB_TAG="master" +ARG EMBREE_TAG="v4.3.3" +ARG DD_TAG="v1.1.0" +ARG DAGMC_TAG="v3.2.3" +ARG NCrystal_TAG="v3.9.7" +ARG PYBIND_TAG="v2.13.6" +ARG XTL_TAG="0.7.7" +ARG XTENSOR_TAG="0.25.0" +ARG XTENSOR_PYTHON_TAG="0.27.0" +ARG XTENSOR_BLAS_TAG="0.21.0" +ARG VECTFIT_TAG="master" +ARG LIBMESH_TAG="v1.7.2" +ARG MCPL_TAG="v1.6.2" + + +# Build base stage +FROM quay.io/pypa/${MANYLINUX_IMAGE} AS base + +ARG Python_ABI + +# Set timezone +ENV TZ=America/Chicago +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +# Set Home directory +ENV HOME /root +WORKDIR $HOME + +# Setup Epel +RUN yum install -y epel-release && \ + yum config-manager --enable epel + +# Install basic dependencies +RUN yum install -y \ + wget \ + git \ + gcc \ + gcc-c++ \ + gcc-gfortran \ + make \ + python3.12-devel \ + zlib-devel \ + curl-devel \ + eigen3-devel \ + lapack-devel \ + libpng-devel \ + openmpi-devel && \ + yum clean all + +# Use Python from manylinux as the default Python +ENV PATH="/opt/python/${Python_ABI}/bin:${PATH}" +RUN ln -sf /opt/python/${Python_ABI}/bin/python3 /usr/bin/python + +# Set up general library environment variables +ENV LD_LIBRARY_PATH=/usr/lib64:$LD_LIBRARY_PATH + +# Set up OpenMPI environment variables +ENV PATH=/usr/lib64/openmpi/bin:$PATH +ENV LD_LIBRARY_PATH=/usr/lib64/openmpi/lib:$LD_LIBRARY_PATH + +# Install necessary Python packages +RUN python -m pip install --upgrade \ + scikit-build-core \ + setuptools \ + numpy \ + cmake \ + ninja \ + h5py \ + scipy \ + ipython \ + matplotlib \ + pandas \ + lxml \ + uncertainties \ + endf \ + vtk \ + mpi4py \ + packaging \ + pytest \ + pytest-cov \ + colorama \ + openpyxl + + +# Set up NJOY2016 +ARG NJOY2016_TAG + +# Build and install NJOY2016 +RUN git clone --depth 1 -b ${NJOY2016_TAG} https://github.com/njoy/njoy2016.git njoy && \ + cd njoy && \ + mkdir build && cd build && \ + cmake .. \ + -Dstatic=ON && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf njoy + + +# Set up HDF5 +ARG HDF5_TAG + +# Build and install HDF5 +RUN git clone --depth 1 -b ${HDF5_TAG} https://github.com/HDFGroup/hdf5.git hdf5 && \ + cd hdf5 && \ + mkdir build && cd build && \ + cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ + -DMPI_C_COMPILER=mpicc \ + -DMPI_CXX_COMPILER=mpicxx \ + -DMPI_Fortran_COMPILER=mpif90 \ + -DHDF5_ENABLE_PARALLEL=ON \ + -DHDF5_BUILD_HL_LIB=ON \ + -DBUILD_SHARED_LIBS=ON \ + -DBUILD_EXAMPLES=OFF && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf hdf5 + + +# Set up NetCDF +ARG NETCDF_TAG + +# Build and install NetCDF +RUN git clone --depth 1 -b ${NETCDF_TAG} https://github.com/Unidata/netcdf-c.git netcdf && \ + cd netcdf && \ + mkdir build && cd build && \ + cmake .. \ + -DCMAKE_C_COMPILER=mpicc \ + -DCMAKE_CXX_COMPILER=mpicxx \ + -DCMAKE_Fortran_COMPILER=mpif90 \ + -DBUILD_SHARED_LIBS=ON \ + -DENABLE_DAP=ON \ + -DENABLE_TESTS=OFF && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf netcdf + + +# Set up MOAB +ARG MOAB_TAG + +# Build and install MOAB +RUN git clone --depth 1 -b ${MOAB_TAG} https://bitbucket.org/fathomteam/moab.git moab && \ + cd moab && \ + mkdir build && cd build && \ + cmake .. \ + -DCMAKE_C_COMPILER=mpicc \ + -DCMAKE_CXX_COMPILER=mpicxx \ + -DCMAKE_Fortran_COMPILER=mpif90 \ + -DENABLE_MPI=ON \ + -DENABLE_HDF5=ON \ + -DHDF5_ROOT=/usr/local \ + -DENABLE_NETCDF=ON \ + -DNETCDF_ROOT=/usr/local \ + -DBUILD_SHARED_LIBS=ON \ + -DENABLE_BLASLAPACK=OFF && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf moab + +# Set up EMBREE +ARG EMBREE_TAG + +# Build and install EMBREE +RUN git clone --depth 1 -b ${EMBREE_TAG} https://github.com/embree/embree.git embree && \ + cd embree && \ + mkdir build && cd build && \ + cmake .. \ + -DEMBREE_TASKING_SYSTEM=INTERNAL \ + -DEMBREE_ISPC_SUPPORT=OFF \ + -DEMBREE_TUTORIALS=OFF && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf embree + +# Set up Double Down +ARG DD_TAG + +# Build and install Double Down +RUN git clone --depth 1 -b ${DD_TAG} https://github.com/pshriwise/double-down.git dd && \ + cd dd && \ + mkdir build && cd build && \ + cmake .. && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf dd + +# Set up DAGMC +ARG DAGMC_TAG + +# Build and install DAGMC +RUN git clone --depth 1 -b ${DAGMC_TAG} https://github.com/svalinn/DAGMC.git dagmc && \ + cd dagmc && \ + mkdir build && cd build && \ + cmake .. \ + -DCMAKE_C_COMPILER=mpicc \ + -DCMAKE_CXX_COMPILER=mpicxx \ + -DMOAB_DIR=/usr/local \ + -Ddd_ROOT=/usr/local \ + -DBUILD_TALLY=ON \ + -DBUILD_UWUW=ON \ + -DDOUBLE_DOWN=ON \ + -DBUILD_STATIC_LIBS=OFF \ + -DBUILD_RPATH=OFF && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf dagmc + +# Set up NCrystal +ARG NCrystal_TAG + +# Build and install NCrystal +RUN git clone --depth 1 -b ${NCrystal_TAG} https://github.com/mctools/ncrystal.git ncrystal && \ + cd ncrystal && \ + mkdir build && cd build && \ + cmake .. \ + -DBUILD_SHARED_LIBS=ON \ + -DNCRYSTAL_NOTOUCH_CMAKE_BUILD_TYPE=ON \ + -DNCRYSTAL_MODIFY_RPATH=OFF \ + -DCMAKE_BUILD_TYPE=Release \ + -DNCRYSTAL_ENABLE_EXAMPLES=OFF \ + -DNCRYSTAL_ENABLE_SETUPSH=OFF \ + -DNCRYSTAL_ENABLE_DATA=EMBED \ + -DPython3_EXECUTABLE=$(which python) && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + ncrystal-config --setup && \ + rm -rf ncrystal + +# Set up pybind +ARG PYBIND_TAG + +# Build and install pybind +RUN git clone --depth 1 -b ${PYBIND_TAG} https://github.com/pybind/pybind11.git pybind11 && \ + cd pybind11 && \ + mkdir build && cd build && \ + cmake .. && \ + make -j$(nproc) && make install && \ + cd .. && \ + python -m pip install . && \ + cd .. && \ + rm -rf pybind11 + +# Set up xtl +ARG XTL_TAG + +# Build and install xtl +RUN git clone --depth 1 -b ${XTL_TAG} https://github.com/xtensor-stack/xtl.git xtl && \ + cd xtl && \ + mkdir build && cd build && \ + cmake .. && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf xtl + +# Set up xtensor +ARG XTENSOR_TAG + +# Build and install xtensor +RUN git clone --depth 1 -b ${XTENSOR_TAG} https://github.com/xtensor-stack/xtensor.git xtensor && \ + cd xtensor && \ + mkdir build && cd build && \ + cmake .. && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf xtensor + +# Set up xtensor-python +ARG XTENSOR_PYTHON_TAG + +# Build and install xtensor-python +RUN git clone --depth 1 -b ${XTENSOR_PYTHON_TAG} https://github.com/xtensor-stack/xtensor-python.git xtensor-python && \ + cd xtensor-python && \ + mkdir build && cd build && \ + cmake .. \ + -DNUMPY_INCLUDE_DIRS=$(python -c "import numpy; print(numpy.get_include())") && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf xtensor-python + +# Set up xtensor-blas +ARG XTENSOR_BLAS_TAG + +# Build and install xtensor-blas +RUN git clone --depth 1 -b ${XTENSOR_BLAS_TAG} https://github.com/xtensor-stack/xtensor-blas.git xtensor-blas && \ + cd xtensor-blas && \ + mkdir build && cd build && \ + cmake .. && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf xtensor-blas + +# Set up vectfit +ARG VECTFIT_TAG + +# Build and install vectfit +RUN git clone --depth 1 -b ${VECTFIT_TAG} https://github.com/liangjg/vectfit.git vectfit && \ + cd vectfit && \ + python -m pip install . && \ + cd .. && \ + rm -rf vectfit + +# Set up libMesh +ARG LIBMESH_TAG + +# Build and install libMesh +RUN git clone --depth 1 -b ${LIBMESH_TAG} https://github.com/libMesh/libmesh.git libmesh && \ + cd libmesh && \ + git submodule update --init --recursive && \ + mkdir build && cd build && \ + export METHODS="opt" && \ + ../configure \ + CXX=mpicxx CC=mpicc FC=mpifort F77=mpif77 \ + --enable-exodus \ + --disable-netcdf-4 \ + --disable-eigen \ + --disable-lapack && \ + make -j$(nproc) && make install && \ + cd .. && \ + rm -rf libmesh + +# Set up MCPL +ARG MCPL_TAG + +# Build and install MCPL +RUN git clone --depth 1 --single-branch -b ${MCPL_TAG} https://github.com/mctools/mcpl.git mcpl && \ + cd mcpl && \ + mkdir build && cd build && \ + cmake .. && \ + make -j$(nproc) && make install && \ + cd .. && \ + rm -rf mcpl + + +# Download and extract HDF5 data +RUN wget -q -O - https://anl.box.com/shared/static/teaup95cqv8s9nn56hfn7ku8mmelr95p.xz | tar -C $HOME -xJ + +# Download and extract ENDF/B-VII.1 distribution +RUN wget -q -O - https://anl.box.com/shared/static/4kd2gxnf4gtk4w1c8eua5fsua22kvgjb.xz | tar -C $HOME -xJ + + +FROM base AS build + +# Copy OpenMC source +COPY . $HOME/openmc + +# Configure SKBUILD CMake arguments +ENV SKBUILD_CMAKE_ARGS "-DOPENMC_USE_OPENMP=ON; \ + -DOPENMC_USE_DAGMC=ON; \ + -DOPENMC_USE_LIBMESH=ON; \ + -DOPENMC_USE_MPI=ON; \ + -DOPENMC_USE_MCPL=ON; \ + -DOPENMC_USE_NCRYSTAL=ON;" + +# Build OpenMC wheel +RUN cd $HOME/openmc && python -m build . -w + +# Repair wheel +RUN auditwheel repair $HOME/openmc/dist/openmc-*.whl -w $HOME/openmc/dist + +# Install OpenMC wheel +RUN python -m pip install $HOME/openmc/dist/*manylinux**.whl + + +FROM build AS test + +# Test OpenMC +RUN cd $HOME/openmc && \ + nctool --test && \ + pytest --cov=openmc -v --mpi --event tests From 556adbb18224ffb27ff128bd29d7c7b4ac9ed62f Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Mon, 30 Sep 2024 19:50:30 +0600 Subject: [PATCH 31/76] add gcc and mpi build --- tools/ci/manylinux.dockerfile | 57 +++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/tools/ci/manylinux.dockerfile b/tools/ci/manylinux.dockerfile index 20669e766ae..450d7cb65fc 100644 --- a/tools/ci/manylinux.dockerfile +++ b/tools/ci/manylinux.dockerfile @@ -2,6 +2,9 @@ ARG MANYLINUX_IMAGE=manylinux_2_28_x86_64 ARG Python_ABI="cp312-cp312" +# Configure Compiler to use (gcc or openmpi) +ARG COMPILER="gcc" + # Configure dependencies tags ARG NJOY2016_TAG="2016.76" ARG HDF5_TAG="hdf5_1.14.4.3" @@ -62,10 +65,6 @@ RUN ln -sf /opt/python/${Python_ABI}/bin/python3 /usr/bin/python # Set up general library environment variables ENV LD_LIBRARY_PATH=/usr/lib64:$LD_LIBRARY_PATH -# Set up OpenMPI environment variables -ENV PATH=/usr/lib64/openmpi/bin:$PATH -ENV LD_LIBRARY_PATH=/usr/lib64/openmpi/lib:$LD_LIBRARY_PATH - # Install necessary Python packages RUN python -m pip install --upgrade \ scikit-build-core \ @@ -89,6 +88,28 @@ RUN python -m pip install --upgrade \ colorama \ openpyxl +FROM base AS compiler-gcc + +ENV CC=gcc +ENV CXX=g++ +ENV FC=gfortran +ENV F77=gfortran + +FROM base AS compiler-openmpi + +ENV CC=mpicc +ENV CXX=mpicxx +ENV FC=mpif90 +ENV F77=mpif77 + +# Set up OpenMPI environment variables +ENV PATH=/usr/lib64/openmpi/bin:$PATH +ENV LD_LIBRARY_PATH=/usr/lib64/openmpi/lib:$LD_LIBRARY_PATH + + +FROM compiler-${COMPILER} AS dependencies + +ARG COMPILER # Set up NJOY2016 ARG NJOY2016_TAG @@ -113,10 +134,7 @@ RUN git clone --depth 1 -b ${HDF5_TAG} https://github.com/HDFGroup/hdf5.git hdf5 mkdir build && cd build && \ cmake .. \ -DCMAKE_INSTALL_PREFIX=/usr/local \ - -DMPI_C_COMPILER=mpicc \ - -DMPI_CXX_COMPILER=mpicxx \ - -DMPI_Fortran_COMPILER=mpif90 \ - -DHDF5_ENABLE_PARALLEL=ON \ + -DHDF5_ENABLE_PARALLEL=$([ ${COMPILER} == "openmpi" ] && echo "ON" || echo "OFF") \ -DHDF5_BUILD_HL_LIB=ON \ -DBUILD_SHARED_LIBS=ON \ -DBUILD_EXAMPLES=OFF && \ @@ -133,9 +151,6 @@ RUN git clone --depth 1 -b ${NETCDF_TAG} https://github.com/Unidata/netcdf-c.git cd netcdf && \ mkdir build && cd build && \ cmake .. \ - -DCMAKE_C_COMPILER=mpicc \ - -DCMAKE_CXX_COMPILER=mpicxx \ - -DCMAKE_Fortran_COMPILER=mpif90 \ -DBUILD_SHARED_LIBS=ON \ -DENABLE_DAP=ON \ -DENABLE_TESTS=OFF && \ @@ -152,10 +167,7 @@ RUN git clone --depth 1 -b ${MOAB_TAG} https://bitbucket.org/fathomteam/moab.git cd moab && \ mkdir build && cd build && \ cmake .. \ - -DCMAKE_C_COMPILER=mpicc \ - -DCMAKE_CXX_COMPILER=mpicxx \ - -DCMAKE_Fortran_COMPILER=mpif90 \ - -DENABLE_MPI=ON \ + -DENABLE_MPI=$([ ${COMPILER} == "openmpi" ] && echo "ON" || echo "OFF") \ -DENABLE_HDF5=ON \ -DHDF5_ROOT=/usr/local \ -DENABLE_NETCDF=ON \ @@ -201,8 +213,6 @@ RUN git clone --depth 1 -b ${DAGMC_TAG} https://github.com/svalinn/DAGMC.git dag cd dagmc && \ mkdir build && cd build && \ cmake .. \ - -DCMAKE_C_COMPILER=mpicc \ - -DCMAKE_CXX_COMPILER=mpicxx \ -DMOAB_DIR=/usr/local \ -Ddd_ROOT=/usr/local \ -DBUILD_TALLY=ON \ @@ -318,7 +328,6 @@ RUN git clone --depth 1 -b ${LIBMESH_TAG} https://github.com/libMesh/libmesh.git mkdir build && cd build && \ export METHODS="opt" && \ ../configure \ - CXX=mpicxx CC=mpicc FC=mpifort F77=mpif77 \ --enable-exodus \ --disable-netcdf-4 \ --disable-eigen \ @@ -347,7 +356,9 @@ RUN wget -q -O - https://anl.box.com/shared/static/teaup95cqv8s9nn56hfn7ku8mmelr RUN wget -q -O - https://anl.box.com/shared/static/4kd2gxnf4gtk4w1c8eua5fsua22kvgjb.xz | tar -C $HOME -xJ -FROM base AS build +FROM dependencies AS openmc + +ARG COMPILER # Copy OpenMC source COPY . $HOME/openmc @@ -356,7 +367,7 @@ COPY . $HOME/openmc ENV SKBUILD_CMAKE_ARGS "-DOPENMC_USE_OPENMP=ON; \ -DOPENMC_USE_DAGMC=ON; \ -DOPENMC_USE_LIBMESH=ON; \ - -DOPENMC_USE_MPI=ON; \ + -DOPENMC_USE_MPI=$([ ${COMPILER} = 'openmpi' ] && echo 'ON' || echo 'OFF'); \ -DOPENMC_USE_MCPL=ON; \ -DOPENMC_USE_NCRYSTAL=ON;" @@ -370,9 +381,11 @@ RUN auditwheel repair $HOME/openmc/dist/openmc-*.whl -w $HOME/openmc/dist RUN python -m pip install $HOME/openmc/dist/*manylinux**.whl -FROM build AS test +FROM openmc AS openmc-test + +ARG COMPILER # Test OpenMC RUN cd $HOME/openmc && \ nctool --test && \ - pytest --cov=openmc -v --mpi --event tests + pytest --cov=openmc -v $([ ${COMPILER} = 'openmpi' ] && echo '--mpi') --event tests From ef1ca2f36c8cdd051bad772f751df78534d00abd Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Mon, 30 Sep 2024 20:26:15 +0600 Subject: [PATCH 32/76] Add openmc options and add more docs --- tools/ci/manylinux.dockerfile | 144 +++++++++++++++++++++------------- 1 file changed, 89 insertions(+), 55 deletions(-) diff --git a/tools/ci/manylinux.dockerfile b/tools/ci/manylinux.dockerfile index 450d7cb65fc..3599f5194ce 100644 --- a/tools/ci/manylinux.dockerfile +++ b/tools/ci/manylinux.dockerfile @@ -1,9 +1,45 @@ +# ---------------------------------------------------------------------------- +# Dockerfile for building the OpenMC project with support for various dependencies +# and configurations. This Dockerfile allows you to build OpenMC with support +# for GCC or OpenMPI compilers, along with several libraries like NJOY2016, HDF5, +# NetCDF, MOAB, EMBREE, Double Down, DAGMC, NCrystal, PyBind11, Xtensor, Vectfit, +# libMesh, and MCPL. Each of these dependencies is installed from their respective +# repositories and tags. + +# The build process is split into stages: +# 1. Base Stage: Sets up a Manylinux base image and installs necessary dependencies. +# 2. Compiler Configuration: Defines the compilers (GCC or OpenMPI) to be used. +# 3. Dependencies Stage: Downloads and builds all external dependencies. +# 4. OpenMC Stage: Copies OpenMC source code, builds it using CMake with specific +# flags and installs it in the container. +# 5. Test Stage: Runs OpenMC's unit tests. + +# Arguments and environment variables can be customized for different compiler and +# dependency versions. +# +# To build the Docker image, use the following command from the repository's root: +# docker build -t openmc -f tools/ci/manylinux.dockerfile . +# +# For more information about each step, refer to the inline comments. +# ---------------------------------------------------------------------------- + # Configure base image ARG MANYLINUX_IMAGE=manylinux_2_28_x86_64 ARG Python_ABI="cp312-cp312" # Configure Compiler to use (gcc or openmpi) -ARG COMPILER="gcc" +ARG COMPILER="openmpi" + +# OpenMC options +ARG OPENMC_USE_OPENMP="ON" +ARG OPENMC_BUILD_TESTS="ON" +ARG OPENMC_ENABLE_PROFILE="OFF" +ARG OPENMC_ENABLE_COVERAGE="OFF" +ARG OPENMC_USE_DAGMC="ON" +ARG OPENMC_USE_LIBMESH="ON" +ARG OPENMC_USE_MCPL="ON" +ARG OPENMC_USE_NCRYSTAL="ON" +ARG OPENMC_USE_UWUW="OFF" # Configure dependencies tags ARG NJOY2016_TAG="2016.76" @@ -24,7 +60,7 @@ ARG LIBMESH_TAG="v1.7.2" ARG MCPL_TAG="v1.6.2" -# Build base stage +# Base stage FROM quay.io/pypa/${MANYLINUX_IMAGE} AS base ARG Python_ABI @@ -37,12 +73,10 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone ENV HOME /root WORKDIR $HOME -# Setup Epel +# Setup Epel repository and install build dependencies RUN yum install -y epel-release && \ - yum config-manager --enable epel - -# Install basic dependencies -RUN yum install -y \ + yum config-manager --enable epel && \ + yum install -y \ wget \ git \ gcc \ @@ -62,7 +96,7 @@ RUN yum install -y \ ENV PATH="/opt/python/${Python_ABI}/bin:${PATH}" RUN ln -sf /opt/python/${Python_ABI}/bin/python3 /usr/bin/python -# Set up general library environment variables +# Set up environment variables for shared libraries ENV LD_LIBRARY_PATH=/usr/lib64:$LD_LIBRARY_PATH # Install necessary Python packages @@ -88,6 +122,8 @@ RUN python -m pip install --upgrade \ colorama \ openpyxl + +# Compiler configuration stage: gcc FROM base AS compiler-gcc ENV CC=gcc @@ -95,6 +131,8 @@ ENV CXX=g++ ENV FC=gfortran ENV F77=gfortran + +# Compiler configuration stage: openmpi FROM base AS compiler-openmpi ENV CC=mpicc @@ -107,14 +145,13 @@ ENV PATH=/usr/lib64/openmpi/bin:$PATH ENV LD_LIBRARY_PATH=/usr/lib64/openmpi/lib:$LD_LIBRARY_PATH +# Dependencies stage FROM compiler-${COMPILER} AS dependencies ARG COMPILER -# Set up NJOY2016 -ARG NJOY2016_TAG - # Build and install NJOY2016 +ARG NJOY2016_TAG RUN git clone --depth 1 -b ${NJOY2016_TAG} https://github.com/njoy/njoy2016.git njoy && \ cd njoy && \ mkdir build && cd build && \ @@ -125,10 +162,8 @@ RUN git clone --depth 1 -b ${NJOY2016_TAG} https://github.com/njoy/njoy2016.git rm -rf njoy -# Set up HDF5 -ARG HDF5_TAG - # Build and install HDF5 +ARG HDF5_TAG RUN git clone --depth 1 -b ${HDF5_TAG} https://github.com/HDFGroup/hdf5.git hdf5 && \ cd hdf5 && \ mkdir build && cd build && \ @@ -143,10 +178,8 @@ RUN git clone --depth 1 -b ${HDF5_TAG} https://github.com/HDFGroup/hdf5.git hdf5 rm -rf hdf5 -# Set up NetCDF -ARG NETCDF_TAG - # Build and install NetCDF +ARG NETCDF_TAG RUN git clone --depth 1 -b ${NETCDF_TAG} https://github.com/Unidata/netcdf-c.git netcdf && \ cd netcdf && \ mkdir build && cd build && \ @@ -159,10 +192,8 @@ RUN git clone --depth 1 -b ${NETCDF_TAG} https://github.com/Unidata/netcdf-c.git rm -rf netcdf -# Set up MOAB -ARG MOAB_TAG - # Build and install MOAB +ARG MOAB_TAG RUN git clone --depth 1 -b ${MOAB_TAG} https://bitbucket.org/fathomteam/moab.git moab && \ cd moab && \ mkdir build && cd build && \ @@ -178,10 +209,9 @@ RUN git clone --depth 1 -b ${MOAB_TAG} https://bitbucket.org/fathomteam/moab.git cd ../.. && \ rm -rf moab -# Set up EMBREE -ARG EMBREE_TAG -# Build and install EMBREE +# Build and install Embree +ARG EMBREE_TAG RUN git clone --depth 1 -b ${EMBREE_TAG} https://github.com/embree/embree.git embree && \ cd embree && \ mkdir build && cd build && \ @@ -193,10 +223,9 @@ RUN git clone --depth 1 -b ${EMBREE_TAG} https://github.com/embree/embree.git em cd ../.. && \ rm -rf embree -# Set up Double Down -ARG DD_TAG # Build and install Double Down +ARG DD_TAG RUN git clone --depth 1 -b ${DD_TAG} https://github.com/pshriwise/double-down.git dd && \ cd dd && \ mkdir build && cd build && \ @@ -205,10 +234,9 @@ RUN git clone --depth 1 -b ${DD_TAG} https://github.com/pshriwise/double-down.gi cd ../.. && \ rm -rf dd -# Set up DAGMC -ARG DAGMC_TAG # Build and install DAGMC +ARG DAGMC_TAG RUN git clone --depth 1 -b ${DAGMC_TAG} https://github.com/svalinn/DAGMC.git dagmc && \ cd dagmc && \ mkdir build && cd build && \ @@ -224,10 +252,9 @@ RUN git clone --depth 1 -b ${DAGMC_TAG} https://github.com/svalinn/DAGMC.git dag cd ../.. && \ rm -rf dagmc -# Set up NCrystal -ARG NCrystal_TAG # Build and install NCrystal +ARG NCrystal_TAG RUN git clone --depth 1 -b ${NCrystal_TAG} https://github.com/mctools/ncrystal.git ncrystal && \ cd ncrystal && \ mkdir build && cd build && \ @@ -245,10 +272,9 @@ RUN git clone --depth 1 -b ${NCrystal_TAG} https://github.com/mctools/ncrystal.g ncrystal-config --setup && \ rm -rf ncrystal -# Set up pybind -ARG PYBIND_TAG # Build and install pybind +ARG PYBIND_TAG RUN git clone --depth 1 -b ${PYBIND_TAG} https://github.com/pybind/pybind11.git pybind11 && \ cd pybind11 && \ mkdir build && cd build && \ @@ -259,10 +285,9 @@ RUN git clone --depth 1 -b ${PYBIND_TAG} https://github.com/pybind/pybind11.git cd .. && \ rm -rf pybind11 -# Set up xtl -ARG XTL_TAG # Build and install xtl +ARG XTL_TAG RUN git clone --depth 1 -b ${XTL_TAG} https://github.com/xtensor-stack/xtl.git xtl && \ cd xtl && \ mkdir build && cd build && \ @@ -271,10 +296,9 @@ RUN git clone --depth 1 -b ${XTL_TAG} https://github.com/xtensor-stack/xtl.git x cd ../.. && \ rm -rf xtl -# Set up xtensor -ARG XTENSOR_TAG # Build and install xtensor +ARG XTENSOR_TAG RUN git clone --depth 1 -b ${XTENSOR_TAG} https://github.com/xtensor-stack/xtensor.git xtensor && \ cd xtensor && \ mkdir build && cd build && \ @@ -283,10 +307,9 @@ RUN git clone --depth 1 -b ${XTENSOR_TAG} https://github.com/xtensor-stack/xtens cd ../.. && \ rm -rf xtensor -# Set up xtensor-python -ARG XTENSOR_PYTHON_TAG # Build and install xtensor-python +ARG XTENSOR_PYTHON_TAG RUN git clone --depth 1 -b ${XTENSOR_PYTHON_TAG} https://github.com/xtensor-stack/xtensor-python.git xtensor-python && \ cd xtensor-python && \ mkdir build && cd build && \ @@ -296,10 +319,9 @@ RUN git clone --depth 1 -b ${XTENSOR_PYTHON_TAG} https://github.com/xtensor-stac cd ../.. && \ rm -rf xtensor-python -# Set up xtensor-blas -ARG XTENSOR_BLAS_TAG # Build and install xtensor-blas +ARG XTENSOR_BLAS_TAG RUN git clone --depth 1 -b ${XTENSOR_BLAS_TAG} https://github.com/xtensor-stack/xtensor-blas.git xtensor-blas && \ cd xtensor-blas && \ mkdir build && cd build && \ @@ -308,26 +330,25 @@ RUN git clone --depth 1 -b ${XTENSOR_BLAS_TAG} https://github.com/xtensor-stack/ cd ../.. && \ rm -rf xtensor-blas -# Set up vectfit -ARG VECTFIT_TAG # Build and install vectfit +ARG VECTFIT_TAG RUN git clone --depth 1 -b ${VECTFIT_TAG} https://github.com/liangjg/vectfit.git vectfit && \ cd vectfit && \ python -m pip install . && \ cd .. && \ rm -rf vectfit -# Set up libMesh -ARG LIBMESH_TAG # Build and install libMesh +ARG LIBMESH_TAG RUN git clone --depth 1 -b ${LIBMESH_TAG} https://github.com/libMesh/libmesh.git libmesh && \ cd libmesh && \ git submodule update --init --recursive && \ mkdir build && cd build && \ export METHODS="opt" && \ ../configure \ + $([ ${COMPILER} = 'openmpi' ] && echo '--enable-mpi' || echo '--disable-mpi') \ --enable-exodus \ --disable-netcdf-4 \ --disable-eigen \ @@ -336,11 +357,10 @@ RUN git clone --depth 1 -b ${LIBMESH_TAG} https://github.com/libMesh/libmesh.git cd .. && \ rm -rf libmesh -# Set up MCPL -ARG MCPL_TAG # Build and install MCPL -RUN git clone --depth 1 --single-branch -b ${MCPL_TAG} https://github.com/mctools/mcpl.git mcpl && \ +ARG MCPL_TAG +RUN git clone --depth 1 -b ${MCPL_TAG} https://github.com/mctools/mcpl.git mcpl && \ cd mcpl && \ mkdir build && cd build && \ cmake .. && \ @@ -356,20 +376,34 @@ RUN wget -q -O - https://anl.box.com/shared/static/teaup95cqv8s9nn56hfn7ku8mmelr RUN wget -q -O - https://anl.box.com/shared/static/4kd2gxnf4gtk4w1c8eua5fsua22kvgjb.xz | tar -C $HOME -xJ +# Build and install OpenMC stage FROM dependencies AS openmc ARG COMPILER - -# Copy OpenMC source +ARG OPENMC_USE_OPENMP +ARG OPENMC_BUILD_TESTS +ARG OPENMC_ENABLE_PROFILE +ARG OPENMC_ENABLE_COVERAGE +ARG OPENMC_USE_DAGMC +ARG OPENMC_USE_LIBMESH +ARG OPENMC_USE_MCPL +ARG OPENMC_USE_NCRYSTAL +ARG OPENMC_USE_UWUW + +# Copy OpenMC source to docker image COPY . $HOME/openmc # Configure SKBUILD CMake arguments -ENV SKBUILD_CMAKE_ARGS "-DOPENMC_USE_OPENMP=ON; \ - -DOPENMC_USE_DAGMC=ON; \ - -DOPENMC_USE_LIBMESH=ON; \ - -DOPENMC_USE_MPI=$([ ${COMPILER} = 'openmpi' ] && echo 'ON' || echo 'OFF'); \ - -DOPENMC_USE_MCPL=ON; \ - -DOPENMC_USE_NCRYSTAL=ON;" +ENV SKBUILD_CMAKE_ARGS "-DOPENMC_USE_MPI=$([ ${COMPILER} = 'openmpi' ] && echo 'ON' || echo 'OFF'); \ + -DOPENMC_USE_OPENMP=${OPENMC_USE_OPENMP}; \ + -DOPENMC_BUILD_TESTS=${OPENMC_BUILD_TESTS}; \ + -DOPENMC_ENABLE_PROFILE=${OPENMC_ENABLE_PROFILE}; \ + -DOPENMC_ENABLE_COVERAGE=${OPENMC_ENABLE_COVERAGE}; \ + -DOPENMC_USE_DAGMC=${OPENMC_USE_DAGMC}; \ + -DOPENMC_USE_LIBMESH=${OPENMC_USE_LIBMESH}; \ + -DOPENMC_USE_MCPL=${OPENMC_USE_MCPL}; \ + -DOPENMC_USE_NCRYSTAL=${OPENMC_USE_NCRYSTAL}; \ + -DOPENMC_USE_UWUW=${OPENMC_USE_UWUW}" # Build OpenMC wheel RUN cd $HOME/openmc && python -m build . -w @@ -380,7 +414,7 @@ RUN auditwheel repair $HOME/openmc/dist/openmc-*.whl -w $HOME/openmc/dist # Install OpenMC wheel RUN python -m pip install $HOME/openmc/dist/*manylinux**.whl - +# Test OpenMC stage FROM openmc AS openmc-test ARG COMPILER From ead096dc85058dfd27506eaa17ec141111667491 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Mon, 30 Sep 2024 21:27:47 +0600 Subject: [PATCH 33/76] install openmpi on openmpi stage --- tools/ci/manylinux.dockerfile | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/ci/manylinux.dockerfile b/tools/ci/manylinux.dockerfile index 3599f5194ce..a8eed4890af 100644 --- a/tools/ci/manylinux.dockerfile +++ b/tools/ci/manylinux.dockerfile @@ -28,7 +28,7 @@ ARG MANYLINUX_IMAGE=manylinux_2_28_x86_64 ARG Python_ABI="cp312-cp312" # Configure Compiler to use (gcc or openmpi) -ARG COMPILER="openmpi" +ARG COMPILER="gcc" # OpenMC options ARG OPENMC_USE_OPENMP="ON" @@ -88,8 +88,7 @@ RUN yum install -y epel-release && \ curl-devel \ eigen3-devel \ lapack-devel \ - libpng-devel \ - openmpi-devel && \ + libpng-devel && \ yum clean all # Use Python from manylinux as the default Python @@ -115,7 +114,6 @@ RUN python -m pip install --upgrade \ uncertainties \ endf \ vtk \ - mpi4py \ packaging \ pytest \ pytest-cov \ @@ -135,6 +133,13 @@ ENV F77=gfortran # Compiler configuration stage: openmpi FROM base AS compiler-openmpi +# Install OpenMPI +RUN yum install -y \ + openmpi-devel && \ + yum clean all && \ + python -m pip install --upgrade \ + mpi4py + ENV CC=mpicc ENV CXX=mpicxx ENV FC=mpif90 From 8a7362e0e12777dfb80ed075f676ef826a95da49 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Mon, 30 Sep 2024 23:19:14 +0600 Subject: [PATCH 34/76] add /usr/local/lib64 to path --- tools/ci/manylinux.dockerfile | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/tools/ci/manylinux.dockerfile b/tools/ci/manylinux.dockerfile index a8eed4890af..85dea9d028e 100644 --- a/tools/ci/manylinux.dockerfile +++ b/tools/ci/manylinux.dockerfile @@ -96,7 +96,7 @@ ENV PATH="/opt/python/${Python_ABI}/bin:${PATH}" RUN ln -sf /opt/python/${Python_ABI}/bin/python3 /usr/bin/python # Set up environment variables for shared libraries -ENV LD_LIBRARY_PATH=/usr/lib64:$LD_LIBRARY_PATH +ENV LD_LIBRARY_PATH=/usr/lib64:/usr/local/lib64:$LD_LIBRARY_PATH # Install necessary Python packages RUN python -m pip install --upgrade \ @@ -133,6 +133,10 @@ ENV F77=gfortran # Compiler configuration stage: openmpi FROM base AS compiler-openmpi +# Set up OpenMPI environment variables +ENV PATH=/usr/lib64/openmpi/bin:$PATH +ENV LD_LIBRARY_PATH=/usr/lib64/openmpi/lib:$LD_LIBRARY_PATH + # Install OpenMPI RUN yum install -y \ openmpi-devel && \ @@ -145,10 +149,6 @@ ENV CXX=mpicxx ENV FC=mpif90 ENV F77=mpif77 -# Set up OpenMPI environment variables -ENV PATH=/usr/lib64/openmpi/bin:$PATH -ENV LD_LIBRARY_PATH=/usr/lib64/openmpi/lib:$LD_LIBRARY_PATH - # Dependencies stage FROM compiler-${COMPILER} AS dependencies @@ -399,7 +399,7 @@ ARG OPENMC_USE_UWUW COPY . $HOME/openmc # Configure SKBUILD CMake arguments -ENV SKBUILD_CMAKE_ARGS "-DOPENMC_USE_MPI=$([ ${COMPILER} = 'openmpi' ] && echo 'ON' || echo 'OFF'); \ +RUN export SKBUILD_CMAKE_ARGS="-DOPENMC_USE_MPI=$([ ${COMPILER} == 'openmpi' ] && echo 'ON' || echo 'OFF'); \ -DOPENMC_USE_OPENMP=${OPENMC_USE_OPENMP}; \ -DOPENMC_BUILD_TESTS=${OPENMC_BUILD_TESTS}; \ -DOPENMC_ENABLE_PROFILE=${OPENMC_ENABLE_PROFILE}; \ @@ -408,10 +408,9 @@ ENV SKBUILD_CMAKE_ARGS "-DOPENMC_USE_MPI=$([ ${COMPILER} = 'openmpi' ] && echo ' -DOPENMC_USE_LIBMESH=${OPENMC_USE_LIBMESH}; \ -DOPENMC_USE_MCPL=${OPENMC_USE_MCPL}; \ -DOPENMC_USE_NCRYSTAL=${OPENMC_USE_NCRYSTAL}; \ - -DOPENMC_USE_UWUW=${OPENMC_USE_UWUW}" - -# Build OpenMC wheel -RUN cd $HOME/openmc && python -m build . -w + -DOPENMC_USE_UWUW=${OPENMC_USE_UWUW}" && \ + cd $HOME/openmc && \ + python -m build . -w # Repair wheel RUN auditwheel repair $HOME/openmc/dist/openmc-*.whl -w $HOME/openmc/dist @@ -427,4 +426,4 @@ ARG COMPILER # Test OpenMC RUN cd $HOME/openmc && \ nctool --test && \ - pytest --cov=openmc -v $([ ${COMPILER} = 'openmpi' ] && echo '--mpi') --event tests + pytest --cov=openmc -v $([ ${COMPILER} == 'openmpi' ] && echo '--mpi') --event tests From 9985fab03729a0f56092700e9fa5cab8ce4b74b6 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Mon, 30 Sep 2024 23:19:27 +0600 Subject: [PATCH 35/76] add workflow --- .../workflows/docker-publish-manylinux.yml | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 .github/workflows/docker-publish-manylinux.yml diff --git a/.github/workflows/docker-publish-manylinux.yml b/.github/workflows/docker-publish-manylinux.yml new file mode 100644 index 00000000000..1bc1edfe757 --- /dev/null +++ b/.github/workflows/docker-publish-manylinux.yml @@ -0,0 +1,120 @@ +name: Build & Publish Manylinux Images + +on: + # allows us to run workflows manually + workflow_dispatch: + push: + paths: + - "tools/ci/manylinux.dockerfile" + - ".github/workflows/docker-publish-manylinux.yml" + +jobs: + build-dependency-and-test-img: + runs-on: ubuntu-latest + + strategy: + matrix: + manylinux_image: [ + manylinux_2_28_x86_64 + ] + compiler: [ + gcc, + openmpi + ] + python: [ + cp312-cp312 + ] + + name: Installing Dependencies, Building OpenMC and running tests + steps: + - name: default environment + run: | + echo "tag-latest-on-default=false" >> "$GITHUB_ENV" + + - name: condition on trigger parameters + if: ${{ github.repository_owner == 'openmc-dev' && github.ref == 'refs/heads/develop' }} + run: | + echo "tag-latest-on-default=true" >> "$GITHUB_ENV" + + - name: Log in to the Container registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Configure docker image tag + run: | + image_base_tag=ghcr.io/${{ github.repository_owner }}/ + image_base_tag+=openmc-ci-${{ matrix.manylinux_image }} + image_base_tag+=-${{ matrix.compiler}} + image_base_tag+=-${{ matrix.python }} + echo "image_base_tag=${image_base_tag}" >> "$GITHUB_ENV" + + - name: Installing Dependencies in Docker image + uses: firehed/multistage-docker-build-action@v1 + with: + repository: ${{ env.image_base_tag }} + stages: base, dependencies, openmc + server-stage: openmc-test + quiet: false + parallel: true + tag-latest-on-default: ${{ env.tag-latest-on-default }} + dockerfile: CI/Dockerfile + build-args: > + MANYLINUX_IMAGE=${{ matrix.manylinux_image }}, + COMPILER=${{ matrix.compiler }}, + Python_ABI=${{ matrix.python }} + + push_stable_ci_img: + needs: [build-dependency-and-test-img] + runs-on: ubuntu-latest + + strategy: + matrix: + manylinux_image: [ + manylinux_2_28_x86_64 + ] + compiler: [ + gcc, + openmpi + ] + python: [ + cp312-cp312 + ] + + name: Pushing final images + steps: + - name: Log in to the Container registry + if: ${{ github.repository_owner == 'svalinn' }} + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Configure docker image tag + if: ${{ github.repository_owner == 'openmc-dev' }} + run: | + image_base_tag=ghcr.io/${{ github.repository_owner }}/ + image_base_tag+=openmc-ci-${{ matrix.manylinux_image }} + image_base_tag+=-${{ matrix.compiler}} + image_base_tag+=-${{ matrix.python }} + echo "image_base_tag=${image_base_tag}" >> "$GITHUB_ENV" + + - name: Push Image as latest img + if: ${{ github.repository_owner == 'openmc-dev' && github.ref == 'refs/heads/develop' }} + uses: akhilerm/tag-push-action@v2.1.0 + with: + src: ${{ env.image_base_tag }}/openmc:latest + dst: ${{ env.image_base_tag }}:latest + + - name: Push Image as latest img + if: ${{ github.repository_owner == 'openmc-dev' && github.ref == 'refs/heads/develop' }} + uses: akhilerm/tag-push-action@v2.1.0 + with: + src: ${{ env.image_base_tag }}:latest + dst: ${{ env.image_base_tag }}:stable From 65ae22c16543fe8e63286e089b1dcdc5d6217091 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Mon, 30 Sep 2024 23:55:51 +0600 Subject: [PATCH 36/76] remove setup.py --- setup.py | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100755 setup.py diff --git a/setup.py b/setup.py deleted file mode 100755 index f26b3138274..00000000000 --- a/setup.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python - -import os -import numpy as np -from setuptools import setup, Extension - - -class OpenMCExtension(Extension): - def __init__(self, name, cmake_lists_dir=".", sources=[], **kwa): - Extension.__init__(self, name, sources=sources, **kwa) - self.cmake_lists_dir = os.path.abspath(cmake_lists_dir) - - -kwargs = { - 'ext_modules': [OpenMCExtension('libopenmc')], - 'include_dirs': [np.get_include()] -} - -setup(**kwargs) From ac5648cea049d25e04ccf2cab79940d5a892154c Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Tue, 1 Oct 2024 08:40:51 +0600 Subject: [PATCH 37/76] remove test stage --- .github/workflows/docker-publish-manylinux.yml | 6 +++--- tools/ci/manylinux.dockerfile | 12 +++--------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/.github/workflows/docker-publish-manylinux.yml b/.github/workflows/docker-publish-manylinux.yml index 1bc1edfe757..6a4c8d50ae0 100644 --- a/.github/workflows/docker-publish-manylinux.yml +++ b/.github/workflows/docker-publish-manylinux.yml @@ -58,8 +58,8 @@ jobs: uses: firehed/multistage-docker-build-action@v1 with: repository: ${{ env.image_base_tag }} - stages: base, dependencies, openmc - server-stage: openmc-test + stages: base, dependencies + server-stage: openmc quiet: false parallel: true tag-latest-on-default: ${{ env.tag-latest-on-default }} @@ -89,7 +89,7 @@ jobs: name: Pushing final images steps: - name: Log in to the Container registry - if: ${{ github.repository_owner == 'svalinn' }} + if: ${{ github.repository_owner == 'openmc-dev' }} uses: docker/login-action@v2 with: registry: ghcr.io diff --git a/tools/ci/manylinux.dockerfile b/tools/ci/manylinux.dockerfile index 85dea9d028e..00464450c17 100644 --- a/tools/ci/manylinux.dockerfile +++ b/tools/ci/manylinux.dockerfile @@ -11,8 +11,7 @@ # 2. Compiler Configuration: Defines the compilers (GCC or OpenMPI) to be used. # 3. Dependencies Stage: Downloads and builds all external dependencies. # 4. OpenMC Stage: Copies OpenMC source code, builds it using CMake with specific -# flags and installs it in the container. -# 5. Test Stage: Runs OpenMC's unit tests. +# flags and installs it in the container. After the build, OpenMC is tested. # Arguments and environment variables can be customized for different compiler and # dependency versions. @@ -359,7 +358,7 @@ RUN git clone --depth 1 -b ${LIBMESH_TAG} https://github.com/libMesh/libmesh.git --disable-eigen \ --disable-lapack && \ make -j$(nproc) && make install && \ - cd .. && \ + cd ../.. && \ rm -rf libmesh @@ -370,7 +369,7 @@ RUN git clone --depth 1 -b ${MCPL_TAG} https://github.com/mctools/mcpl.git mcpl mkdir build && cd build && \ cmake .. && \ make -j$(nproc) && make install && \ - cd .. && \ + cd ../.. && \ rm -rf mcpl @@ -418,11 +417,6 @@ RUN auditwheel repair $HOME/openmc/dist/openmc-*.whl -w $HOME/openmc/dist # Install OpenMC wheel RUN python -m pip install $HOME/openmc/dist/*manylinux**.whl -# Test OpenMC stage -FROM openmc AS openmc-test - -ARG COMPILER - # Test OpenMC RUN cd $HOME/openmc && \ nctool --test && \ From db8265f5558cc44316ed9585448fbf9cf0db1af6 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Tue, 1 Oct 2024 09:30:19 +0600 Subject: [PATCH 38/76] add pypi --- .../workflows/docker-publish-manylinux.yml | 4 +- .github/workflows/pypi.yml | 57 +++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/pypi.yml diff --git a/.github/workflows/docker-publish-manylinux.yml b/.github/workflows/docker-publish-manylinux.yml index 6a4c8d50ae0..a9aae2b0f4e 100644 --- a/.github/workflows/docker-publish-manylinux.yml +++ b/.github/workflows/docker-publish-manylinux.yml @@ -49,7 +49,7 @@ jobs: - name: Configure docker image tag run: | image_base_tag=ghcr.io/${{ github.repository_owner }}/ - image_base_tag+=openmc-ci-${{ matrix.manylinux_image }} + image_base_tag+=openmc-${{ matrix.manylinux_image }} image_base_tag+=-${{ matrix.compiler}} image_base_tag+=-${{ matrix.python }} echo "image_base_tag=${image_base_tag}" >> "$GITHUB_ENV" @@ -100,7 +100,7 @@ jobs: if: ${{ github.repository_owner == 'openmc-dev' }} run: | image_base_tag=ghcr.io/${{ github.repository_owner }}/ - image_base_tag+=openmc-ci-${{ matrix.manylinux_image }} + image_base_tag+=openmc-${{ matrix.manylinux_image }} image_base_tag+=-${{ matrix.compiler}} image_base_tag+=-${{ matrix.python }} echo "image_base_tag=${image_base_tag}" >> "$GITHUB_ENV" diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml new file mode 100644 index 00000000000..7b7aa690d54 --- /dev/null +++ b/.github/workflows/pypi.yml @@ -0,0 +1,57 @@ +name: Publish wheels to PyPI + +on: + # allows running workflows manually + workflow_dispatch: + + release: + types: [published] + +jobs: + main: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + arch: manylinux_x86_64 + - os: macos-13 + arch: macosx_x86_64 + - os: macos-14 + arch: macosx_arm64 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Build wheels + uses: pypa/cibuildwheel@v2.18.0 + env: + CIBW_BUILD: "cp*-${{ matrix.arch }}" + CIBW_ARCHS_LINUX: "x86_64" + CIBW_MANYLINUX_X86_64_IMAGE: ghcr.io/${{ github.repository_owner }}/openmc-manylinux_2_28_x86_64-gcc-cp312-cp312/openmc:latest + CIBW_ARCHS_MACOS: "native" + CIBW_BEFORE_BUILD_MACOS: | + brew install llvm cmake xtensor hdf5 python libomp libpng + CIBW_ENVIRONMENT_MACOS: > + MACOSX_DEPLOYMENT_TARGET=${{ matrix.os == 'macos-14' && '14.0' || '13.0' }} + DYLD_LIBRARY_PATH=/usr/local/opt/gcc/lib/gcc/current/:$DYLD_LIBRARY_PATH + CXX=$(brew --prefix llvm)/bin/clang++ + HDF5_ROOT=$(brew --prefix hdf5) + CIBW_BUILD_FRONTEND: "build" + with: + package-dir: openmc + output-dir: wheelhouse + config-file: "{package}/pyproject.toml" + + - name: Publish package to PyPI + if: success() + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} + run: | + twine upload wheelhouse/*.whl \ No newline at end of file From a205ef762f7eb7c847bd2510429bc001b7918883 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Tue, 1 Oct 2024 15:31:05 +0600 Subject: [PATCH 39/76] move python deps to last --- tools/ci/manylinux.dockerfile | 212 +++++++++++++++------------------- 1 file changed, 93 insertions(+), 119 deletions(-) diff --git a/tools/ci/manylinux.dockerfile b/tools/ci/manylinux.dockerfile index 00464450c17..cbf487f7288 100644 --- a/tools/ci/manylinux.dockerfile +++ b/tools/ci/manylinux.dockerfile @@ -11,7 +11,8 @@ # 2. Compiler Configuration: Defines the compilers (GCC or OpenMPI) to be used. # 3. Dependencies Stage: Downloads and builds all external dependencies. # 4. OpenMC Stage: Copies OpenMC source code, builds it using CMake with specific -# flags and installs it in the container. After the build, OpenMC is tested. +# flags and installs it in the container. +# 5. Test Stage: Runs OpenMC unit tests. # Arguments and environment variables can be customized for different compiler and # dependency versions. @@ -24,11 +25,13 @@ # Configure base image ARG MANYLINUX_IMAGE=manylinux_2_28_x86_64 -ARG Python_ABI="cp312-cp312" # Configure Compiler to use (gcc or openmpi) ARG COMPILER="gcc" +# Configure Python ABI to use +ARG Python_ABI="cp312-cp312" + # OpenMC options ARG OPENMC_USE_OPENMP="ON" ARG OPENMC_BUILD_TESTS="ON" @@ -44,7 +47,7 @@ ARG OPENMC_USE_UWUW="OFF" ARG NJOY2016_TAG="2016.76" ARG HDF5_TAG="hdf5_1.14.4.3" ARG NETCDF_TAG="v4.9.2" -ARG MOAB_TAG="master" +ARG MOAB_TAG="5.5.1" ARG EMBREE_TAG="v4.3.3" ARG DD_TAG="v1.1.0" ARG DAGMC_TAG="v3.2.3" @@ -62,8 +65,6 @@ ARG MCPL_TAG="v1.6.2" # Base stage FROM quay.io/pypa/${MANYLINUX_IMAGE} AS base -ARG Python_ABI - # Set timezone ENV TZ=America/Chicago RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone @@ -90,35 +91,9 @@ RUN yum install -y epel-release && \ libpng-devel && \ yum clean all -# Use Python from manylinux as the default Python -ENV PATH="/opt/python/${Python_ABI}/bin:${PATH}" -RUN ln -sf /opt/python/${Python_ABI}/bin/python3 /usr/bin/python - # Set up environment variables for shared libraries ENV LD_LIBRARY_PATH=/usr/lib64:/usr/local/lib64:$LD_LIBRARY_PATH -# Install necessary Python packages -RUN python -m pip install --upgrade \ - scikit-build-core \ - setuptools \ - numpy \ - cmake \ - ninja \ - h5py \ - scipy \ - ipython \ - matplotlib \ - pandas \ - lxml \ - uncertainties \ - endf \ - vtk \ - packaging \ - pytest \ - pytest-cov \ - colorama \ - openpyxl - # Compiler configuration stage: gcc FROM base AS compiler-gcc @@ -132,22 +107,20 @@ ENV F77=gfortran # Compiler configuration stage: openmpi FROM base AS compiler-openmpi -# Set up OpenMPI environment variables -ENV PATH=/usr/lib64/openmpi/bin:$PATH -ENV LD_LIBRARY_PATH=/usr/lib64/openmpi/lib:$LD_LIBRARY_PATH - # Install OpenMPI RUN yum install -y \ openmpi-devel && \ - yum clean all && \ - python -m pip install --upgrade \ - mpi4py + yum clean all ENV CC=mpicc ENV CXX=mpicxx ENV FC=mpif90 ENV F77=mpif77 +# Set up OpenMPI environment variables +ENV PATH=/usr/lib64/openmpi/bin:$PATH +ENV LD_LIBRARY_PATH=/usr/lib64/openmpi/lib:$LD_LIBRARY_PATH + # Dependencies stage FROM compiler-${COMPILER} AS dependencies @@ -165,7 +138,6 @@ RUN git clone --depth 1 -b ${NJOY2016_TAG} https://github.com/njoy/njoy2016.git cd ../.. && \ rm -rf njoy - # Build and install HDF5 ARG HDF5_TAG RUN git clone --depth 1 -b ${HDF5_TAG} https://github.com/HDFGroup/hdf5.git hdf5 && \ @@ -181,7 +153,6 @@ RUN git clone --depth 1 -b ${HDF5_TAG} https://github.com/HDFGroup/hdf5.git hdf5 cd ../.. && \ rm -rf hdf5 - # Build and install NetCDF ARG NETCDF_TAG RUN git clone --depth 1 -b ${NETCDF_TAG} https://github.com/Unidata/netcdf-c.git netcdf && \ @@ -195,7 +166,6 @@ RUN git clone --depth 1 -b ${NETCDF_TAG} https://github.com/Unidata/netcdf-c.git cd ../.. && \ rm -rf netcdf - # Build and install MOAB ARG MOAB_TAG RUN git clone --depth 1 -b ${MOAB_TAG} https://bitbucket.org/fathomteam/moab.git moab && \ @@ -208,12 +178,12 @@ RUN git clone --depth 1 -b ${MOAB_TAG} https://bitbucket.org/fathomteam/moab.git -DENABLE_NETCDF=ON \ -DNETCDF_ROOT=/usr/local \ -DBUILD_SHARED_LIBS=ON \ - -DENABLE_BLASLAPACK=OFF && \ + -DENABLE_BLASLAPACK=OFF \ + -DENABLE_PYMOAB=OFF && \ make -j$(nproc) && make install && \ cd ../.. && \ rm -rf moab - # Build and install Embree ARG EMBREE_TAG RUN git clone --depth 1 -b ${EMBREE_TAG} https://github.com/embree/embree.git embree && \ @@ -227,18 +197,17 @@ RUN git clone --depth 1 -b ${EMBREE_TAG} https://github.com/embree/embree.git em cd ../.. && \ rm -rf embree - # Build and install Double Down ARG DD_TAG RUN git clone --depth 1 -b ${DD_TAG} https://github.com/pshriwise/double-down.git dd && \ cd dd && \ mkdir build && cd build && \ - cmake .. && \ + cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr/local && \ make -j$(nproc) && make install && \ cd ../.. && \ rm -rf dd - # Build and install DAGMC ARG DAGMC_TAG RUN git clone --depth 1 -b ${DAGMC_TAG} https://github.com/svalinn/DAGMC.git dagmc && \ @@ -256,7 +225,6 @@ RUN git clone --depth 1 -b ${DAGMC_TAG} https://github.com/svalinn/DAGMC.git dag cd ../.. && \ rm -rf dagmc - # Build and install NCrystal ARG NCrystal_TAG RUN git clone --depth 1 -b ${NCrystal_TAG} https://github.com/mctools/ncrystal.git ncrystal && \ @@ -276,74 +244,6 @@ RUN git clone --depth 1 -b ${NCrystal_TAG} https://github.com/mctools/ncrystal.g ncrystal-config --setup && \ rm -rf ncrystal - -# Build and install pybind -ARG PYBIND_TAG -RUN git clone --depth 1 -b ${PYBIND_TAG} https://github.com/pybind/pybind11.git pybind11 && \ - cd pybind11 && \ - mkdir build && cd build && \ - cmake .. && \ - make -j$(nproc) && make install && \ - cd .. && \ - python -m pip install . && \ - cd .. && \ - rm -rf pybind11 - - -# Build and install xtl -ARG XTL_TAG -RUN git clone --depth 1 -b ${XTL_TAG} https://github.com/xtensor-stack/xtl.git xtl && \ - cd xtl && \ - mkdir build && cd build && \ - cmake .. && \ - make -j$(nproc) && make install && \ - cd ../.. && \ - rm -rf xtl - - -# Build and install xtensor -ARG XTENSOR_TAG -RUN git clone --depth 1 -b ${XTENSOR_TAG} https://github.com/xtensor-stack/xtensor.git xtensor && \ - cd xtensor && \ - mkdir build && cd build && \ - cmake .. && \ - make -j$(nproc) && make install && \ - cd ../.. && \ - rm -rf xtensor - - -# Build and install xtensor-python -ARG XTENSOR_PYTHON_TAG -RUN git clone --depth 1 -b ${XTENSOR_PYTHON_TAG} https://github.com/xtensor-stack/xtensor-python.git xtensor-python && \ - cd xtensor-python && \ - mkdir build && cd build && \ - cmake .. \ - -DNUMPY_INCLUDE_DIRS=$(python -c "import numpy; print(numpy.get_include())") && \ - make -j$(nproc) && make install && \ - cd ../.. && \ - rm -rf xtensor-python - - -# Build and install xtensor-blas -ARG XTENSOR_BLAS_TAG -RUN git clone --depth 1 -b ${XTENSOR_BLAS_TAG} https://github.com/xtensor-stack/xtensor-blas.git xtensor-blas && \ - cd xtensor-blas && \ - mkdir build && cd build && \ - cmake .. && \ - make -j$(nproc) && make install && \ - cd ../.. && \ - rm -rf xtensor-blas - - -# Build and install vectfit -ARG VECTFIT_TAG -RUN git clone --depth 1 -b ${VECTFIT_TAG} https://github.com/liangjg/vectfit.git vectfit && \ - cd vectfit && \ - python -m pip install . && \ - cd .. && \ - rm -rf vectfit - - # Build and install libMesh ARG LIBMESH_TAG RUN git clone --depth 1 -b ${LIBMESH_TAG} https://github.com/libMesh/libmesh.git libmesh && \ @@ -361,7 +261,6 @@ RUN git clone --depth 1 -b ${LIBMESH_TAG} https://github.com/libMesh/libmesh.git cd ../.. && \ rm -rf libmesh - # Build and install MCPL ARG MCPL_TAG RUN git clone --depth 1 -b ${MCPL_TAG} https://github.com/mctools/mcpl.git mcpl && \ @@ -372,7 +271,6 @@ RUN git clone --depth 1 -b ${MCPL_TAG} https://github.com/mctools/mcpl.git mcpl cd ../.. && \ rm -rf mcpl - # Download and extract HDF5 data RUN wget -q -O - https://anl.box.com/shared/static/teaup95cqv8s9nn56hfn7ku8mmelr95p.xz | tar -C $HOME -xJ @@ -384,6 +282,7 @@ RUN wget -q -O - https://anl.box.com/shared/static/4kd2gxnf4gtk4w1c8eua5fsua22kv FROM dependencies AS openmc ARG COMPILER +ARG Python_ABI ARG OPENMC_USE_OPENMP ARG OPENMC_BUILD_TESTS ARG OPENMC_ENABLE_PROFILE @@ -394,6 +293,10 @@ ARG OPENMC_USE_MCPL ARG OPENMC_USE_NCRYSTAL ARG OPENMC_USE_UWUW +# Use Python from manylinux as the default Python +ENV PATH="/opt/python/${Python_ABI}/bin:${PATH}" +RUN ln -sf /opt/python/${Python_ABI}/bin/python3 /usr/bin/python + # Copy OpenMC source to docker image COPY . $HOME/openmc @@ -412,10 +315,81 @@ RUN export SKBUILD_CMAKE_ARGS="-DOPENMC_USE_MPI=$([ ${COMPILER} == 'openmpi' ] & python -m build . -w # Repair wheel -RUN auditwheel repair $HOME/openmc/dist/openmc-*.whl -w $HOME/openmc/dist +RUN auditwheel repair $HOME/openmc/dist/openmc-*.whl -w $HOME/openmc/dist/ # Install OpenMC wheel -RUN python -m pip install $HOME/openmc/dist/*manylinux**.whl +RUN python -m pip install \ + "$(echo $HOME/openmc/dist/*manylinux**.whl)[$([ ${COMPILER} == 'openmpi' ] && echo 'depletion-mpi,')test,ci,vtk]" + + +# Test OpenMC stage +FROM openmc AS test + +ARG COMPILER + +# Build and install pybind +ARG PYBIND_TAG +RUN git clone --depth 1 -b ${PYBIND_TAG} https://github.com/pybind/pybind11.git pybind11 && \ + cd pybind11 && \ + mkdir build && cd build && \ + cmake .. && \ + make -j$(nproc) && make install && \ + cd .. && \ + python -m pip install . && \ + cd .. && \ + rm -rf pybind11 + +# Build and install xtl +ARG XTL_TAG +RUN git clone --depth 1 -b ${XTL_TAG} https://github.com/xtensor-stack/xtl.git xtl && \ + cd xtl && \ + mkdir build && cd build && \ + cmake .. && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf xtl + +# Build and install xtensor +ARG XTENSOR_TAG +RUN git clone --depth 1 -b ${XTENSOR_TAG} https://github.com/xtensor-stack/xtensor.git xtensor && \ + cd xtensor && \ + mkdir build && cd build && \ + cmake .. && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf xtensor + +# Build and install xtensor-python +ARG XTENSOR_PYTHON_TAG +RUN git clone --depth 1 -b ${XTENSOR_PYTHON_TAG} https://github.com/xtensor-stack/xtensor-python.git xtensor-python && \ + cd xtensor-python && \ + mkdir build && cd build && \ + cmake .. \ + -DNUMPY_INCLUDE_DIRS=$(python -c "import numpy; print(numpy.get_include())") && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf xtensor-python + +# Build and install xtensor-blas +ARG XTENSOR_BLAS_TAG +RUN git clone --depth 1 -b ${XTENSOR_BLAS_TAG} https://github.com/xtensor-stack/xtensor-blas.git xtensor-blas && \ + cd xtensor-blas && \ + mkdir build && cd build && \ + cmake .. && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf xtensor-blas + +# Build and install vectfit +ARG VECTFIT_TAG +RUN git clone --depth 1 -b ${VECTFIT_TAG} https://github.com/liangjg/vectfit.git vectfit && \ + cd vectfit && \ + python -m pip install . && \ + cd .. && \ + rm -rf vectfit + +RUN yum install -y \ + sqlite-devel # Test OpenMC RUN cd $HOME/openmc && \ From 7036ec6422e6121dc098362469d76d7076ff8eb6 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Wed, 2 Oct 2024 13:16:34 +0600 Subject: [PATCH 40/76] fix pytest-cov issue --- tools/ci/manylinux.dockerfile | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/ci/manylinux.dockerfile b/tools/ci/manylinux.dockerfile index cbf487f7288..cdd63212133 100644 --- a/tools/ci/manylinux.dockerfile +++ b/tools/ci/manylinux.dockerfile @@ -92,7 +92,7 @@ RUN yum install -y epel-release && \ yum clean all # Set up environment variables for shared libraries -ENV LD_LIBRARY_PATH=/usr/lib64:/usr/local/lib64:$LD_LIBRARY_PATH +ENV LD_LIBRARY_PATH=/usr/local/lib64:$LD_LIBRARY_PATH # Compiler configuration stage: gcc @@ -133,6 +133,7 @@ RUN git clone --depth 1 -b ${NJOY2016_TAG} https://github.com/njoy/njoy2016.git cd njoy && \ mkdir build && cd build && \ cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ -Dstatic=ON && \ make -j$(nproc) && make install && \ cd ../.. && \ @@ -159,6 +160,7 @@ RUN git clone --depth 1 -b ${NETCDF_TAG} https://github.com/Unidata/netcdf-c.git cd netcdf && \ mkdir build && cd build && \ cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ -DBUILD_SHARED_LIBS=ON \ -DENABLE_DAP=ON \ -DENABLE_TESTS=OFF && \ @@ -172,6 +174,7 @@ RUN git clone --depth 1 -b ${MOAB_TAG} https://bitbucket.org/fathomteam/moab.git cd moab && \ mkdir build && cd build && \ cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ -DENABLE_MPI=$([ ${COMPILER} == "openmpi" ] && echo "ON" || echo "OFF") \ -DENABLE_HDF5=ON \ -DHDF5_ROOT=/usr/local \ @@ -190,6 +193,7 @@ RUN git clone --depth 1 -b ${EMBREE_TAG} https://github.com/embree/embree.git em cd embree && \ mkdir build && cd build && \ cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ -DEMBREE_TASKING_SYSTEM=INTERNAL \ -DEMBREE_ISPC_SUPPORT=OFF \ -DEMBREE_TUTORIALS=OFF && \ @@ -231,6 +235,7 @@ RUN git clone --depth 1 -b ${NCrystal_TAG} https://github.com/mctools/ncrystal.g cd ncrystal && \ mkdir build && cd build && \ cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ -DBUILD_SHARED_LIBS=ON \ -DNCRYSTAL_NOTOUCH_CMAKE_BUILD_TYPE=ON \ -DNCRYSTAL_MODIFY_RPATH=OFF \ @@ -253,6 +258,7 @@ RUN git clone --depth 1 -b ${LIBMESH_TAG} https://github.com/libMesh/libmesh.git export METHODS="opt" && \ ../configure \ $([ ${COMPILER} = 'openmpi' ] && echo '--enable-mpi' || echo '--disable-mpi') \ + --prefix=/usr/local \ --enable-exodus \ --disable-netcdf-4 \ --disable-eigen \ @@ -266,7 +272,8 @@ ARG MCPL_TAG RUN git clone --depth 1 -b ${MCPL_TAG} https://github.com/mctools/mcpl.git mcpl && \ cd mcpl && \ mkdir build && cd build && \ - cmake .. && \ + cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr/local && \ make -j$(nproc) && make install && \ cd ../.. && \ rm -rf mcpl @@ -388,9 +395,6 @@ RUN git clone --depth 1 -b ${VECTFIT_TAG} https://github.com/liangjg/vectfit.git cd .. && \ rm -rf vectfit -RUN yum install -y \ - sqlite-devel - # Test OpenMC RUN cd $HOME/openmc && \ nctool --test && \ From 1d8e951a2c04bc665ff37930965b0480f3c1c4e1 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Wed, 2 Oct 2024 13:19:28 +0600 Subject: [PATCH 41/76] fix pytest-cov issue --- tools/ci/manylinux.dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ci/manylinux.dockerfile b/tools/ci/manylinux.dockerfile index cdd63212133..7b5e949a280 100644 --- a/tools/ci/manylinux.dockerfile +++ b/tools/ci/manylinux.dockerfile @@ -218,6 +218,7 @@ RUN git clone --depth 1 -b ${DAGMC_TAG} https://github.com/svalinn/DAGMC.git dag cd dagmc && \ mkdir build && cd build && \ cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ -DMOAB_DIR=/usr/local \ -Ddd_ROOT=/usr/local \ -DBUILD_TALLY=ON \ From 0043634d9b0b5c4dd816def0c4ee33f2d403f04f Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Wed, 2 Oct 2024 15:06:49 +0600 Subject: [PATCH 42/76] no need abi --- .github/workflows/docker-publish-manylinux.yml | 16 +++------------- .github/workflows/pypi.yml | 2 +- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/.github/workflows/docker-publish-manylinux.yml b/.github/workflows/docker-publish-manylinux.yml index a9aae2b0f4e..da60b82d6ca 100644 --- a/.github/workflows/docker-publish-manylinux.yml +++ b/.github/workflows/docker-publish-manylinux.yml @@ -21,9 +21,6 @@ jobs: gcc, openmpi ] - python: [ - cp312-cp312 - ] name: Installing Dependencies, Building OpenMC and running tests steps: @@ -51,24 +48,21 @@ jobs: image_base_tag=ghcr.io/${{ github.repository_owner }}/ image_base_tag+=openmc-${{ matrix.manylinux_image }} image_base_tag+=-${{ matrix.compiler}} - image_base_tag+=-${{ matrix.python }} echo "image_base_tag=${image_base_tag}" >> "$GITHUB_ENV" - name: Installing Dependencies in Docker image uses: firehed/multistage-docker-build-action@v1 with: repository: ${{ env.image_base_tag }} - stages: base, dependencies - server-stage: openmc + stages: base, dependencies, openmc + server-stage: test quiet: false parallel: true tag-latest-on-default: ${{ env.tag-latest-on-default }} dockerfile: CI/Dockerfile build-args: > MANYLINUX_IMAGE=${{ matrix.manylinux_image }}, - COMPILER=${{ matrix.compiler }}, - Python_ABI=${{ matrix.python }} - + COMPILER=${{ matrix.compiler }} push_stable_ci_img: needs: [build-dependency-and-test-img] runs-on: ubuntu-latest @@ -82,9 +76,6 @@ jobs: gcc, openmpi ] - python: [ - cp312-cp312 - ] name: Pushing final images steps: @@ -102,7 +93,6 @@ jobs: image_base_tag=ghcr.io/${{ github.repository_owner }}/ image_base_tag+=openmc-${{ matrix.manylinux_image }} image_base_tag+=-${{ matrix.compiler}} - image_base_tag+=-${{ matrix.python }} echo "image_base_tag=${image_base_tag}" >> "$GITHUB_ENV" - name: Push Image as latest img diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 7b7aa690d54..0b324d3b7c1 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -33,7 +33,7 @@ jobs: env: CIBW_BUILD: "cp*-${{ matrix.arch }}" CIBW_ARCHS_LINUX: "x86_64" - CIBW_MANYLINUX_X86_64_IMAGE: ghcr.io/${{ github.repository_owner }}/openmc-manylinux_2_28_x86_64-gcc-cp312-cp312/openmc:latest + CIBW_MANYLINUX_X86_64_IMAGE: ghcr.io/${{ github.repository_owner }}/openmc-manylinux_2_28_x86_64-gcc/openmc:latest CIBW_ARCHS_MACOS: "native" CIBW_BEFORE_BUILD_MACOS: | brew install llvm cmake xtensor hdf5 python libomp libpng From 9e65e4ab1577ab5a8383c18c4a825c4cdd00d9be Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Wed, 2 Oct 2024 20:19:09 +0600 Subject: [PATCH 43/76] fix path --- .github/workflows/docker-publish-manylinux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-publish-manylinux.yml b/.github/workflows/docker-publish-manylinux.yml index da60b82d6ca..5fc49d8900c 100644 --- a/.github/workflows/docker-publish-manylinux.yml +++ b/.github/workflows/docker-publish-manylinux.yml @@ -59,7 +59,7 @@ jobs: quiet: false parallel: true tag-latest-on-default: ${{ env.tag-latest-on-default }} - dockerfile: CI/Dockerfile + dockerfile: tools/ci/manylinux.dockerfile build-args: > MANYLINUX_IMAGE=${{ matrix.manylinux_image }}, COMPILER=${{ matrix.compiler }} From 1985003b0c2f7871b3ad4d47aaa872d06d6da99b Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Thu, 3 Oct 2024 21:06:56 +0600 Subject: [PATCH 44/76] move openmc to src --- openmc/data/compton_profiles.h5 | Bin 598888 -> 0 bytes openmc/data/density_effect.h5 | Bin 206264 -> 0 bytes pyproject.toml | 2 +- {openmc => src/openmc}/__init__.py | 0 {openmc => src/openmc}/_xml.py | 0 {openmc => src/openmc}/arithmetic.py | 0 {openmc => src/openmc}/bounding_box.py | 0 {openmc => src/openmc}/cell.py | 0 {openmc => src/openmc}/checkvalue.py | 0 {openmc => src/openmc}/cmfd.py | 0 {openmc => src/openmc}/config.py | 0 {openmc => src/openmc}/data/BREMX.DAT | 0 {openmc => src/openmc}/data/__init__.py | 0 {openmc => src/openmc}/data/ace.py | 0 .../openmc}/data/angle_distribution.py | 0 {openmc => src/openmc}/data/angle_energy.py | 0 {openmc => src/openmc}/data/correlated.py | 0 {openmc => src/openmc}/data/data.py | 0 {openmc => src/openmc}/data/decay.py | 0 .../openmc}/data/effective_dose/__init__.py | 0 .../openmc}/data/effective_dose/dose.py | 0 .../openmc}/data/effective_dose/electrons.txt | 0 .../data/effective_dose/helium_ions.txt | 0 .../data/effective_dose/negative_muons.txt | 0 .../data/effective_dose/negative_pions.txt | 0 .../openmc}/data/effective_dose/neutrons.txt | 0 .../openmc}/data/effective_dose/photons.txt | 0 .../data/effective_dose/photons_kerma.txt | 0 .../data/effective_dose/positive_muons.txt | 0 .../data/effective_dose/positive_pions.txt | 0 .../openmc}/data/effective_dose/positrons.txt | 0 .../openmc}/data/effective_dose/protons.txt | 0 {openmc => src/openmc}/data/endf.py | 0 .../openmc}/data/energy_distribution.py | 0 {openmc => src/openmc}/data/fission_energy.py | 0 {openmc => src/openmc}/data/function.py | 0 {openmc => src/openmc}/data/grid.py | 0 {openmc => src/openmc}/data/half_life.json | 0 {openmc => src/openmc}/data/kalbach_mann.py | 0 {openmc => src/openmc}/data/laboratory.py | 0 {openmc => src/openmc}/data/library.py | 0 {openmc => src/openmc}/data/mass_1.mas20.txt | 0 {openmc => src/openmc}/data/multipole.py | 0 {openmc => src/openmc}/data/nbody.py | 0 {openmc => src/openmc}/data/neutron.py | 0 {openmc => src/openmc}/data/njoy.py | 0 {openmc => src/openmc}/data/photon.py | 0 {openmc => src/openmc}/data/product.py | 0 {openmc => src/openmc}/data/reaction.py | 0 {openmc => src/openmc}/data/resonance.py | 0 .../openmc}/data/resonance_covariance.py | 0 {openmc => src/openmc}/data/thermal.py | 0 .../openmc}/data/thermal_angle_energy.py | 0 {openmc => src/openmc}/data/uncorrelated.py | 0 {openmc => src/openmc}/data/urr.py | 0 {openmc => src/openmc}/deplete/__init__.py | 0 .../openmc}/deplete/_matrix_funcs.py | 0 {openmc => src/openmc}/deplete/abc.py | 0 {openmc => src/openmc}/deplete/atom_number.py | 0 {openmc => src/openmc}/deplete/chain.py | 0 .../openmc}/deplete/coupled_operator.py | 0 {openmc => src/openmc}/deplete/cram.py | 0 {openmc => src/openmc}/deplete/helpers.py | 0 .../openmc}/deplete/independent_operator.py | 0 {openmc => src/openmc}/deplete/integrators.py | 0 {openmc => src/openmc}/deplete/microxs.py | 0 {openmc => src/openmc}/deplete/nuclide.py | 0 .../openmc}/deplete/openmc_operator.py | 0 {openmc => src/openmc}/deplete/pool.py | 0 .../openmc}/deplete/reaction_rates.py | 0 {openmc => src/openmc}/deplete/results.py | 0 {openmc => src/openmc}/deplete/stepresult.py | 0 .../openmc}/deplete/transfer_rates.py | 0 {openmc => src/openmc}/dummy_comm.py | 0 {openmc => src/openmc}/element.py | 0 {openmc => src/openmc}/examples.py | 0 {openmc => src/openmc}/exceptions.py | 0 {openmc => src/openmc}/executor.py | 0 {openmc => src/openmc}/filter.py | 0 {openmc => src/openmc}/filter_expansion.py | 0 {openmc => src/openmc}/geometry.py | 0 {openmc => src/openmc}/lattice.py | 0 {openmc => src/openmc}/lib/__init__.py | 0 {openmc => src/openmc}/lib/cell.py | 0 {openmc => src/openmc}/lib/core.py | 0 {openmc => src/openmc}/lib/error.py | 0 {openmc => src/openmc}/lib/filter.py | 0 {openmc => src/openmc}/lib/material.py | 0 {openmc => src/openmc}/lib/math.py | 0 {openmc => src/openmc}/lib/mesh.py | 0 {openmc => src/openmc}/lib/nuclide.py | 0 {openmc => src/openmc}/lib/plot.py | 0 {openmc => src/openmc}/lib/settings.py | 0 {openmc => src/openmc}/lib/tally.py | 0 {openmc => src/openmc}/lib/weight_windows.py | 0 {openmc => src/openmc}/macroscopic.py | 0 {openmc => src/openmc}/material.py | 0 {openmc => src/openmc}/mesh.py | 0 {openmc => src/openmc}/mgxs/__init__.py | 0 {openmc => src/openmc}/mgxs/groups.py | 0 {openmc => src/openmc}/mgxs/library.py | 0 {openmc => src/openmc}/mgxs/mdgxs.py | 0 {openmc => src/openmc}/mgxs/mgxs.py | 0 {openmc => src/openmc}/mgxs_library.py | 0 {openmc => src/openmc}/mixin.py | 0 {openmc => src/openmc}/model/__init__.py | 0 {openmc => src/openmc}/model/funcs.py | 0 {openmc => src/openmc}/model/model.py | 0 .../openmc}/model/surface_composite.py | 0 {openmc => src/openmc}/model/triso.py | 0 {openmc => src/openmc}/mpi.py | 0 {openmc => src/openmc}/nuclide.py | 0 {openmc => src/openmc}/openmc_exec.py | 0 {openmc => src/openmc}/openmoc_compatible.py | 0 {openmc => src/openmc}/particle_restart.py | 0 {openmc => src/openmc}/plots.py | 0 {openmc => src/openmc}/plotter.py | 0 {openmc => src/openmc}/polynomial.py | 0 {openmc => src/openmc}/region.py | 0 {openmc => src/openmc}/search.py | 0 {openmc => src/openmc}/settings.py | 0 {openmc => src/openmc}/source.py | 0 {openmc => src/openmc}/statepoint.py | 0 {openmc => src/openmc}/stats/__init__.py | 0 {openmc => src/openmc}/stats/multivariate.py | 0 {openmc => src/openmc}/stats/univariate.py | 0 {openmc => src/openmc}/summary.py | 0 {openmc => src/openmc}/surface.py | 0 {openmc => src/openmc}/tallies.py | 0 {openmc => src/openmc}/tally_derivative.py | 0 {openmc => src/openmc}/tracks.py | 0 {openmc => src/openmc}/trigger.py | 0 {openmc => src/openmc}/universe.py | 0 {openmc => src/openmc}/utility_funcs.py | 0 {openmc => src/openmc}/volume.py | 0 {openmc => src/openmc}/weight_windows.py | 0 136 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 openmc/data/compton_profiles.h5 delete mode 100644 openmc/data/density_effect.h5 rename {openmc => src/openmc}/__init__.py (100%) rename {openmc => src/openmc}/_xml.py (100%) rename {openmc => src/openmc}/arithmetic.py (100%) rename {openmc => src/openmc}/bounding_box.py (100%) rename {openmc => src/openmc}/cell.py (100%) rename {openmc => src/openmc}/checkvalue.py (100%) rename {openmc => src/openmc}/cmfd.py (100%) rename {openmc => src/openmc}/config.py (100%) rename {openmc => src/openmc}/data/BREMX.DAT (100%) rename {openmc => src/openmc}/data/__init__.py (100%) rename {openmc => src/openmc}/data/ace.py (100%) rename {openmc => src/openmc}/data/angle_distribution.py (100%) rename {openmc => src/openmc}/data/angle_energy.py (100%) rename {openmc => src/openmc}/data/correlated.py (100%) rename {openmc => src/openmc}/data/data.py (100%) rename {openmc => src/openmc}/data/decay.py (100%) rename {openmc => src/openmc}/data/effective_dose/__init__.py (100%) rename {openmc => src/openmc}/data/effective_dose/dose.py (100%) rename {openmc => src/openmc}/data/effective_dose/electrons.txt (100%) rename {openmc => src/openmc}/data/effective_dose/helium_ions.txt (100%) rename {openmc => src/openmc}/data/effective_dose/negative_muons.txt (100%) rename {openmc => src/openmc}/data/effective_dose/negative_pions.txt (100%) rename {openmc => src/openmc}/data/effective_dose/neutrons.txt (100%) rename {openmc => src/openmc}/data/effective_dose/photons.txt (100%) rename {openmc => src/openmc}/data/effective_dose/photons_kerma.txt (100%) rename {openmc => src/openmc}/data/effective_dose/positive_muons.txt (100%) rename {openmc => src/openmc}/data/effective_dose/positive_pions.txt (100%) rename {openmc => src/openmc}/data/effective_dose/positrons.txt (100%) rename {openmc => src/openmc}/data/effective_dose/protons.txt (100%) rename {openmc => src/openmc}/data/endf.py (100%) rename {openmc => src/openmc}/data/energy_distribution.py (100%) rename {openmc => src/openmc}/data/fission_energy.py (100%) rename {openmc => src/openmc}/data/function.py (100%) rename {openmc => src/openmc}/data/grid.py (100%) rename {openmc => src/openmc}/data/half_life.json (100%) rename {openmc => src/openmc}/data/kalbach_mann.py (100%) rename {openmc => src/openmc}/data/laboratory.py (100%) rename {openmc => src/openmc}/data/library.py (100%) rename {openmc => src/openmc}/data/mass_1.mas20.txt (100%) rename {openmc => src/openmc}/data/multipole.py (100%) rename {openmc => src/openmc}/data/nbody.py (100%) rename {openmc => src/openmc}/data/neutron.py (100%) rename {openmc => src/openmc}/data/njoy.py (100%) rename {openmc => src/openmc}/data/photon.py (100%) rename {openmc => src/openmc}/data/product.py (100%) rename {openmc => src/openmc}/data/reaction.py (100%) rename {openmc => src/openmc}/data/resonance.py (100%) rename {openmc => src/openmc}/data/resonance_covariance.py (100%) rename {openmc => src/openmc}/data/thermal.py (100%) rename {openmc => src/openmc}/data/thermal_angle_energy.py (100%) rename {openmc => src/openmc}/data/uncorrelated.py (100%) rename {openmc => src/openmc}/data/urr.py (100%) rename {openmc => src/openmc}/deplete/__init__.py (100%) rename {openmc => src/openmc}/deplete/_matrix_funcs.py (100%) rename {openmc => src/openmc}/deplete/abc.py (100%) rename {openmc => src/openmc}/deplete/atom_number.py (100%) rename {openmc => src/openmc}/deplete/chain.py (100%) rename {openmc => src/openmc}/deplete/coupled_operator.py (100%) rename {openmc => src/openmc}/deplete/cram.py (100%) rename {openmc => src/openmc}/deplete/helpers.py (100%) rename {openmc => src/openmc}/deplete/independent_operator.py (100%) rename {openmc => src/openmc}/deplete/integrators.py (100%) rename {openmc => src/openmc}/deplete/microxs.py (100%) rename {openmc => src/openmc}/deplete/nuclide.py (100%) rename {openmc => src/openmc}/deplete/openmc_operator.py (100%) rename {openmc => src/openmc}/deplete/pool.py (100%) rename {openmc => src/openmc}/deplete/reaction_rates.py (100%) rename {openmc => src/openmc}/deplete/results.py (100%) rename {openmc => src/openmc}/deplete/stepresult.py (100%) rename {openmc => src/openmc}/deplete/transfer_rates.py (100%) rename {openmc => src/openmc}/dummy_comm.py (100%) rename {openmc => src/openmc}/element.py (100%) rename {openmc => src/openmc}/examples.py (100%) rename {openmc => src/openmc}/exceptions.py (100%) rename {openmc => src/openmc}/executor.py (100%) rename {openmc => src/openmc}/filter.py (100%) rename {openmc => src/openmc}/filter_expansion.py (100%) rename {openmc => src/openmc}/geometry.py (100%) rename {openmc => src/openmc}/lattice.py (100%) rename {openmc => src/openmc}/lib/__init__.py (100%) rename {openmc => src/openmc}/lib/cell.py (100%) rename {openmc => src/openmc}/lib/core.py (100%) rename {openmc => src/openmc}/lib/error.py (100%) rename {openmc => src/openmc}/lib/filter.py (100%) rename {openmc => src/openmc}/lib/material.py (100%) rename {openmc => src/openmc}/lib/math.py (100%) rename {openmc => src/openmc}/lib/mesh.py (100%) rename {openmc => src/openmc}/lib/nuclide.py (100%) rename {openmc => src/openmc}/lib/plot.py (100%) rename {openmc => src/openmc}/lib/settings.py (100%) rename {openmc => src/openmc}/lib/tally.py (100%) rename {openmc => src/openmc}/lib/weight_windows.py (100%) rename {openmc => src/openmc}/macroscopic.py (100%) rename {openmc => src/openmc}/material.py (100%) rename {openmc => src/openmc}/mesh.py (100%) rename {openmc => src/openmc}/mgxs/__init__.py (100%) rename {openmc => src/openmc}/mgxs/groups.py (100%) rename {openmc => src/openmc}/mgxs/library.py (100%) rename {openmc => src/openmc}/mgxs/mdgxs.py (100%) rename {openmc => src/openmc}/mgxs/mgxs.py (100%) rename {openmc => src/openmc}/mgxs_library.py (100%) rename {openmc => src/openmc}/mixin.py (100%) rename {openmc => src/openmc}/model/__init__.py (100%) rename {openmc => src/openmc}/model/funcs.py (100%) rename {openmc => src/openmc}/model/model.py (100%) rename {openmc => src/openmc}/model/surface_composite.py (100%) rename {openmc => src/openmc}/model/triso.py (100%) rename {openmc => src/openmc}/mpi.py (100%) rename {openmc => src/openmc}/nuclide.py (100%) rename {openmc => src/openmc}/openmc_exec.py (100%) rename {openmc => src/openmc}/openmoc_compatible.py (100%) rename {openmc => src/openmc}/particle_restart.py (100%) rename {openmc => src/openmc}/plots.py (100%) rename {openmc => src/openmc}/plotter.py (100%) rename {openmc => src/openmc}/polynomial.py (100%) rename {openmc => src/openmc}/region.py (100%) rename {openmc => src/openmc}/search.py (100%) rename {openmc => src/openmc}/settings.py (100%) rename {openmc => src/openmc}/source.py (100%) rename {openmc => src/openmc}/statepoint.py (100%) rename {openmc => src/openmc}/stats/__init__.py (100%) rename {openmc => src/openmc}/stats/multivariate.py (100%) rename {openmc => src/openmc}/stats/univariate.py (100%) rename {openmc => src/openmc}/summary.py (100%) rename {openmc => src/openmc}/surface.py (100%) rename {openmc => src/openmc}/tallies.py (100%) rename {openmc => src/openmc}/tally_derivative.py (100%) rename {openmc => src/openmc}/tracks.py (100%) rename {openmc => src/openmc}/trigger.py (100%) rename {openmc => src/openmc}/universe.py (100%) rename {openmc => src/openmc}/utility_funcs.py (100%) rename {openmc => src/openmc}/volume.py (100%) rename {openmc => src/openmc}/weight_windows.py (100%) diff --git a/openmc/data/compton_profiles.h5 b/openmc/data/compton_profiles.h5 deleted file mode 100644 index 298ed0340e6eaf3a0788d86edc5faa011931cdf6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 598888 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≈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

}U12r=Nc;3o?hkbPBt9lvcZCodG)-bNQ9@w2JCF zJm6NiP8LFcvD0Q;*N z*8io(|NP~B@R2@RPvLQwDJ~a$3%DN6H@B3&;R;emc&!~fb$DTI$F&+bnvWHkqu3yI zg@lpoo*R_jA-JXvU5vz6fb=Q*Q<`s#J0Bm#vB6&u?>Vj;Tn}`LkZ%XK20td|_kAh3 zL~wc`EARX6Z{jQK)LQX@(|wrWqlx*P$BVPfV?BiTC@Q@9W2ql_X|pTM?f-6hc@26o z$tCi8t3L-WQ?Hf!r_S|2ZxGjw`3>(kcqZsF4XgR^U5AS+H27|DU;8maWbWb^?XwCR zHNf?l%&W%;JkOtf9CV$Y-<^yz^�W9Te_#zw#>q*Ms%XINR@@x>@w)Le+cBKlf_I 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 diff --git a/openmc/data/density_effect.h5 b/openmc/data/density_effect.h5 deleted file mode 100644 index 77d973517c244f6083b558e9569a5082174169eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 206264 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 diff --git a/pyproject.toml b/pyproject.toml index 16d16106798..847b97bded6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,5 +64,5 @@ Issues = "https://github.com/openmc-dev/openmc/issues" build.verbose = true logging.level = "INFO" wheel.install-dir = "openmc" -wheel.packages = ["openmc"] +wheel.packages = ["src/openmc"] wheel.exclude = ["CMakeLists.txt"] diff --git a/openmc/__init__.py b/src/openmc/__init__.py similarity index 100% rename from openmc/__init__.py rename to src/openmc/__init__.py diff --git a/openmc/_xml.py b/src/openmc/_xml.py similarity index 100% rename from openmc/_xml.py rename to src/openmc/_xml.py diff --git a/openmc/arithmetic.py b/src/openmc/arithmetic.py similarity index 100% rename from openmc/arithmetic.py rename to src/openmc/arithmetic.py diff --git a/openmc/bounding_box.py b/src/openmc/bounding_box.py similarity index 100% rename from openmc/bounding_box.py rename to src/openmc/bounding_box.py diff --git a/openmc/cell.py b/src/openmc/cell.py similarity index 100% rename from openmc/cell.py rename to src/openmc/cell.py diff --git a/openmc/checkvalue.py b/src/openmc/checkvalue.py similarity index 100% rename from openmc/checkvalue.py rename to src/openmc/checkvalue.py diff --git a/openmc/cmfd.py b/src/openmc/cmfd.py similarity index 100% rename from openmc/cmfd.py rename to src/openmc/cmfd.py diff --git a/openmc/config.py b/src/openmc/config.py similarity index 100% rename from openmc/config.py rename to src/openmc/config.py diff --git a/openmc/data/BREMX.DAT b/src/openmc/data/BREMX.DAT similarity index 100% rename from openmc/data/BREMX.DAT rename to src/openmc/data/BREMX.DAT diff --git a/openmc/data/__init__.py b/src/openmc/data/__init__.py similarity index 100% rename from openmc/data/__init__.py rename to src/openmc/data/__init__.py diff --git a/openmc/data/ace.py b/src/openmc/data/ace.py similarity index 100% rename from openmc/data/ace.py rename to src/openmc/data/ace.py diff --git a/openmc/data/angle_distribution.py b/src/openmc/data/angle_distribution.py similarity index 100% rename from openmc/data/angle_distribution.py rename to src/openmc/data/angle_distribution.py diff --git a/openmc/data/angle_energy.py b/src/openmc/data/angle_energy.py similarity index 100% rename from openmc/data/angle_energy.py rename to src/openmc/data/angle_energy.py diff --git a/openmc/data/correlated.py b/src/openmc/data/correlated.py similarity index 100% rename from openmc/data/correlated.py rename to src/openmc/data/correlated.py diff --git a/openmc/data/data.py b/src/openmc/data/data.py similarity index 100% rename from openmc/data/data.py rename to src/openmc/data/data.py diff --git a/openmc/data/decay.py b/src/openmc/data/decay.py similarity index 100% rename from openmc/data/decay.py rename to src/openmc/data/decay.py diff --git a/openmc/data/effective_dose/__init__.py b/src/openmc/data/effective_dose/__init__.py similarity index 100% rename from openmc/data/effective_dose/__init__.py rename to src/openmc/data/effective_dose/__init__.py diff --git a/openmc/data/effective_dose/dose.py b/src/openmc/data/effective_dose/dose.py similarity index 100% rename from openmc/data/effective_dose/dose.py rename to src/openmc/data/effective_dose/dose.py diff --git a/openmc/data/effective_dose/electrons.txt b/src/openmc/data/effective_dose/electrons.txt similarity index 100% rename from openmc/data/effective_dose/electrons.txt rename to src/openmc/data/effective_dose/electrons.txt diff --git a/openmc/data/effective_dose/helium_ions.txt b/src/openmc/data/effective_dose/helium_ions.txt similarity index 100% rename from openmc/data/effective_dose/helium_ions.txt rename to src/openmc/data/effective_dose/helium_ions.txt diff --git a/openmc/data/effective_dose/negative_muons.txt b/src/openmc/data/effective_dose/negative_muons.txt similarity index 100% rename from openmc/data/effective_dose/negative_muons.txt rename to src/openmc/data/effective_dose/negative_muons.txt diff --git a/openmc/data/effective_dose/negative_pions.txt b/src/openmc/data/effective_dose/negative_pions.txt similarity index 100% rename from openmc/data/effective_dose/negative_pions.txt rename to src/openmc/data/effective_dose/negative_pions.txt diff --git a/openmc/data/effective_dose/neutrons.txt b/src/openmc/data/effective_dose/neutrons.txt similarity index 100% rename from openmc/data/effective_dose/neutrons.txt rename to src/openmc/data/effective_dose/neutrons.txt diff --git a/openmc/data/effective_dose/photons.txt b/src/openmc/data/effective_dose/photons.txt similarity index 100% rename from openmc/data/effective_dose/photons.txt rename to src/openmc/data/effective_dose/photons.txt diff --git a/openmc/data/effective_dose/photons_kerma.txt b/src/openmc/data/effective_dose/photons_kerma.txt similarity index 100% rename from openmc/data/effective_dose/photons_kerma.txt rename to src/openmc/data/effective_dose/photons_kerma.txt diff --git a/openmc/data/effective_dose/positive_muons.txt b/src/openmc/data/effective_dose/positive_muons.txt similarity index 100% rename from openmc/data/effective_dose/positive_muons.txt rename to src/openmc/data/effective_dose/positive_muons.txt diff --git a/openmc/data/effective_dose/positive_pions.txt b/src/openmc/data/effective_dose/positive_pions.txt similarity index 100% rename from openmc/data/effective_dose/positive_pions.txt rename to src/openmc/data/effective_dose/positive_pions.txt diff --git a/openmc/data/effective_dose/positrons.txt b/src/openmc/data/effective_dose/positrons.txt similarity index 100% rename from openmc/data/effective_dose/positrons.txt rename to src/openmc/data/effective_dose/positrons.txt diff --git a/openmc/data/effective_dose/protons.txt b/src/openmc/data/effective_dose/protons.txt similarity index 100% rename from openmc/data/effective_dose/protons.txt rename to src/openmc/data/effective_dose/protons.txt diff --git a/openmc/data/endf.py b/src/openmc/data/endf.py similarity index 100% rename from openmc/data/endf.py rename to src/openmc/data/endf.py diff --git a/openmc/data/energy_distribution.py b/src/openmc/data/energy_distribution.py similarity index 100% rename from openmc/data/energy_distribution.py rename to src/openmc/data/energy_distribution.py diff --git a/openmc/data/fission_energy.py b/src/openmc/data/fission_energy.py similarity index 100% rename from openmc/data/fission_energy.py rename to src/openmc/data/fission_energy.py diff --git a/openmc/data/function.py b/src/openmc/data/function.py similarity index 100% rename from openmc/data/function.py rename to src/openmc/data/function.py diff --git a/openmc/data/grid.py b/src/openmc/data/grid.py similarity index 100% rename from openmc/data/grid.py rename to src/openmc/data/grid.py diff --git a/openmc/data/half_life.json b/src/openmc/data/half_life.json similarity index 100% rename from openmc/data/half_life.json rename to src/openmc/data/half_life.json diff --git a/openmc/data/kalbach_mann.py b/src/openmc/data/kalbach_mann.py similarity index 100% rename from openmc/data/kalbach_mann.py rename to src/openmc/data/kalbach_mann.py diff --git a/openmc/data/laboratory.py b/src/openmc/data/laboratory.py similarity index 100% rename from openmc/data/laboratory.py rename to src/openmc/data/laboratory.py diff --git a/openmc/data/library.py b/src/openmc/data/library.py similarity index 100% rename from openmc/data/library.py rename to src/openmc/data/library.py diff --git a/openmc/data/mass_1.mas20.txt b/src/openmc/data/mass_1.mas20.txt similarity index 100% rename from openmc/data/mass_1.mas20.txt rename to src/openmc/data/mass_1.mas20.txt diff --git a/openmc/data/multipole.py b/src/openmc/data/multipole.py similarity index 100% rename from openmc/data/multipole.py rename to src/openmc/data/multipole.py diff --git a/openmc/data/nbody.py b/src/openmc/data/nbody.py similarity index 100% rename from openmc/data/nbody.py rename to src/openmc/data/nbody.py diff --git a/openmc/data/neutron.py b/src/openmc/data/neutron.py similarity index 100% rename from openmc/data/neutron.py rename to src/openmc/data/neutron.py diff --git a/openmc/data/njoy.py b/src/openmc/data/njoy.py similarity index 100% rename from openmc/data/njoy.py rename to src/openmc/data/njoy.py diff --git a/openmc/data/photon.py b/src/openmc/data/photon.py similarity index 100% rename from openmc/data/photon.py rename to src/openmc/data/photon.py diff --git a/openmc/data/product.py b/src/openmc/data/product.py similarity index 100% rename from openmc/data/product.py rename to src/openmc/data/product.py diff --git a/openmc/data/reaction.py b/src/openmc/data/reaction.py similarity index 100% rename from openmc/data/reaction.py rename to src/openmc/data/reaction.py diff --git a/openmc/data/resonance.py b/src/openmc/data/resonance.py similarity index 100% rename from openmc/data/resonance.py rename to src/openmc/data/resonance.py diff --git a/openmc/data/resonance_covariance.py b/src/openmc/data/resonance_covariance.py similarity index 100% rename from openmc/data/resonance_covariance.py rename to src/openmc/data/resonance_covariance.py diff --git a/openmc/data/thermal.py b/src/openmc/data/thermal.py similarity index 100% rename from openmc/data/thermal.py rename to src/openmc/data/thermal.py diff --git a/openmc/data/thermal_angle_energy.py b/src/openmc/data/thermal_angle_energy.py similarity index 100% rename from openmc/data/thermal_angle_energy.py rename to src/openmc/data/thermal_angle_energy.py diff --git a/openmc/data/uncorrelated.py b/src/openmc/data/uncorrelated.py similarity index 100% rename from openmc/data/uncorrelated.py rename to src/openmc/data/uncorrelated.py diff --git a/openmc/data/urr.py b/src/openmc/data/urr.py similarity index 100% rename from openmc/data/urr.py rename to src/openmc/data/urr.py diff --git a/openmc/deplete/__init__.py b/src/openmc/deplete/__init__.py similarity index 100% rename from openmc/deplete/__init__.py rename to src/openmc/deplete/__init__.py diff --git a/openmc/deplete/_matrix_funcs.py b/src/openmc/deplete/_matrix_funcs.py similarity index 100% rename from openmc/deplete/_matrix_funcs.py rename to src/openmc/deplete/_matrix_funcs.py diff --git a/openmc/deplete/abc.py b/src/openmc/deplete/abc.py similarity index 100% rename from openmc/deplete/abc.py rename to src/openmc/deplete/abc.py diff --git a/openmc/deplete/atom_number.py b/src/openmc/deplete/atom_number.py similarity index 100% rename from openmc/deplete/atom_number.py rename to src/openmc/deplete/atom_number.py diff --git a/openmc/deplete/chain.py b/src/openmc/deplete/chain.py similarity index 100% rename from openmc/deplete/chain.py rename to src/openmc/deplete/chain.py diff --git a/openmc/deplete/coupled_operator.py b/src/openmc/deplete/coupled_operator.py similarity index 100% rename from openmc/deplete/coupled_operator.py rename to src/openmc/deplete/coupled_operator.py diff --git a/openmc/deplete/cram.py b/src/openmc/deplete/cram.py similarity index 100% rename from openmc/deplete/cram.py rename to src/openmc/deplete/cram.py diff --git a/openmc/deplete/helpers.py b/src/openmc/deplete/helpers.py similarity index 100% rename from openmc/deplete/helpers.py rename to src/openmc/deplete/helpers.py diff --git a/openmc/deplete/independent_operator.py b/src/openmc/deplete/independent_operator.py similarity index 100% rename from openmc/deplete/independent_operator.py rename to src/openmc/deplete/independent_operator.py diff --git a/openmc/deplete/integrators.py b/src/openmc/deplete/integrators.py similarity index 100% rename from openmc/deplete/integrators.py rename to src/openmc/deplete/integrators.py diff --git a/openmc/deplete/microxs.py b/src/openmc/deplete/microxs.py similarity index 100% rename from openmc/deplete/microxs.py rename to src/openmc/deplete/microxs.py diff --git a/openmc/deplete/nuclide.py b/src/openmc/deplete/nuclide.py similarity index 100% rename from openmc/deplete/nuclide.py rename to src/openmc/deplete/nuclide.py diff --git a/openmc/deplete/openmc_operator.py b/src/openmc/deplete/openmc_operator.py similarity index 100% rename from openmc/deplete/openmc_operator.py rename to src/openmc/deplete/openmc_operator.py diff --git a/openmc/deplete/pool.py b/src/openmc/deplete/pool.py similarity index 100% rename from openmc/deplete/pool.py rename to src/openmc/deplete/pool.py diff --git a/openmc/deplete/reaction_rates.py b/src/openmc/deplete/reaction_rates.py similarity index 100% rename from openmc/deplete/reaction_rates.py rename to src/openmc/deplete/reaction_rates.py diff --git a/openmc/deplete/results.py b/src/openmc/deplete/results.py similarity index 100% rename from openmc/deplete/results.py rename to src/openmc/deplete/results.py diff --git a/openmc/deplete/stepresult.py b/src/openmc/deplete/stepresult.py similarity index 100% rename from openmc/deplete/stepresult.py rename to src/openmc/deplete/stepresult.py diff --git a/openmc/deplete/transfer_rates.py b/src/openmc/deplete/transfer_rates.py similarity index 100% rename from openmc/deplete/transfer_rates.py rename to src/openmc/deplete/transfer_rates.py diff --git a/openmc/dummy_comm.py b/src/openmc/dummy_comm.py similarity index 100% rename from openmc/dummy_comm.py rename to src/openmc/dummy_comm.py diff --git a/openmc/element.py b/src/openmc/element.py similarity index 100% rename from openmc/element.py rename to src/openmc/element.py diff --git a/openmc/examples.py b/src/openmc/examples.py similarity index 100% rename from openmc/examples.py rename to src/openmc/examples.py diff --git a/openmc/exceptions.py b/src/openmc/exceptions.py similarity index 100% rename from openmc/exceptions.py rename to src/openmc/exceptions.py diff --git a/openmc/executor.py b/src/openmc/executor.py similarity index 100% rename from openmc/executor.py rename to src/openmc/executor.py diff --git a/openmc/filter.py b/src/openmc/filter.py similarity index 100% rename from openmc/filter.py rename to src/openmc/filter.py diff --git a/openmc/filter_expansion.py b/src/openmc/filter_expansion.py similarity index 100% rename from openmc/filter_expansion.py rename to src/openmc/filter_expansion.py diff --git a/openmc/geometry.py b/src/openmc/geometry.py similarity index 100% rename from openmc/geometry.py rename to src/openmc/geometry.py diff --git a/openmc/lattice.py b/src/openmc/lattice.py similarity index 100% rename from openmc/lattice.py rename to src/openmc/lattice.py diff --git a/openmc/lib/__init__.py b/src/openmc/lib/__init__.py similarity index 100% rename from openmc/lib/__init__.py rename to src/openmc/lib/__init__.py diff --git a/openmc/lib/cell.py b/src/openmc/lib/cell.py similarity index 100% rename from openmc/lib/cell.py rename to src/openmc/lib/cell.py diff --git a/openmc/lib/core.py b/src/openmc/lib/core.py similarity index 100% rename from openmc/lib/core.py rename to src/openmc/lib/core.py diff --git a/openmc/lib/error.py b/src/openmc/lib/error.py similarity index 100% rename from openmc/lib/error.py rename to src/openmc/lib/error.py diff --git a/openmc/lib/filter.py b/src/openmc/lib/filter.py similarity index 100% rename from openmc/lib/filter.py rename to src/openmc/lib/filter.py diff --git a/openmc/lib/material.py b/src/openmc/lib/material.py similarity index 100% rename from openmc/lib/material.py rename to src/openmc/lib/material.py diff --git a/openmc/lib/math.py b/src/openmc/lib/math.py similarity index 100% rename from openmc/lib/math.py rename to src/openmc/lib/math.py diff --git a/openmc/lib/mesh.py b/src/openmc/lib/mesh.py similarity index 100% rename from openmc/lib/mesh.py rename to src/openmc/lib/mesh.py diff --git a/openmc/lib/nuclide.py b/src/openmc/lib/nuclide.py similarity index 100% rename from openmc/lib/nuclide.py rename to src/openmc/lib/nuclide.py diff --git a/openmc/lib/plot.py b/src/openmc/lib/plot.py similarity index 100% rename from openmc/lib/plot.py rename to src/openmc/lib/plot.py diff --git a/openmc/lib/settings.py b/src/openmc/lib/settings.py similarity index 100% rename from openmc/lib/settings.py rename to src/openmc/lib/settings.py diff --git a/openmc/lib/tally.py b/src/openmc/lib/tally.py similarity index 100% rename from openmc/lib/tally.py rename to src/openmc/lib/tally.py diff --git a/openmc/lib/weight_windows.py b/src/openmc/lib/weight_windows.py similarity index 100% rename from openmc/lib/weight_windows.py rename to src/openmc/lib/weight_windows.py diff --git a/openmc/macroscopic.py b/src/openmc/macroscopic.py similarity index 100% rename from openmc/macroscopic.py rename to src/openmc/macroscopic.py diff --git a/openmc/material.py b/src/openmc/material.py similarity index 100% rename from openmc/material.py rename to src/openmc/material.py diff --git a/openmc/mesh.py b/src/openmc/mesh.py similarity index 100% rename from openmc/mesh.py rename to src/openmc/mesh.py diff --git a/openmc/mgxs/__init__.py b/src/openmc/mgxs/__init__.py similarity index 100% rename from openmc/mgxs/__init__.py rename to src/openmc/mgxs/__init__.py diff --git a/openmc/mgxs/groups.py b/src/openmc/mgxs/groups.py similarity index 100% rename from openmc/mgxs/groups.py rename to src/openmc/mgxs/groups.py diff --git a/openmc/mgxs/library.py b/src/openmc/mgxs/library.py similarity index 100% rename from openmc/mgxs/library.py rename to src/openmc/mgxs/library.py diff --git a/openmc/mgxs/mdgxs.py b/src/openmc/mgxs/mdgxs.py similarity index 100% rename from openmc/mgxs/mdgxs.py rename to src/openmc/mgxs/mdgxs.py diff --git a/openmc/mgxs/mgxs.py b/src/openmc/mgxs/mgxs.py similarity index 100% rename from openmc/mgxs/mgxs.py rename to src/openmc/mgxs/mgxs.py diff --git a/openmc/mgxs_library.py b/src/openmc/mgxs_library.py similarity index 100% rename from openmc/mgxs_library.py rename to src/openmc/mgxs_library.py diff --git a/openmc/mixin.py b/src/openmc/mixin.py similarity index 100% rename from openmc/mixin.py rename to src/openmc/mixin.py diff --git a/openmc/model/__init__.py b/src/openmc/model/__init__.py similarity index 100% rename from openmc/model/__init__.py rename to src/openmc/model/__init__.py diff --git a/openmc/model/funcs.py b/src/openmc/model/funcs.py similarity index 100% rename from openmc/model/funcs.py rename to src/openmc/model/funcs.py diff --git a/openmc/model/model.py b/src/openmc/model/model.py similarity index 100% rename from openmc/model/model.py rename to src/openmc/model/model.py diff --git a/openmc/model/surface_composite.py b/src/openmc/model/surface_composite.py similarity index 100% rename from openmc/model/surface_composite.py rename to src/openmc/model/surface_composite.py diff --git a/openmc/model/triso.py b/src/openmc/model/triso.py similarity index 100% rename from openmc/model/triso.py rename to src/openmc/model/triso.py diff --git a/openmc/mpi.py b/src/openmc/mpi.py similarity index 100% rename from openmc/mpi.py rename to src/openmc/mpi.py diff --git a/openmc/nuclide.py b/src/openmc/nuclide.py similarity index 100% rename from openmc/nuclide.py rename to src/openmc/nuclide.py diff --git a/openmc/openmc_exec.py b/src/openmc/openmc_exec.py similarity index 100% rename from openmc/openmc_exec.py rename to src/openmc/openmc_exec.py diff --git a/openmc/openmoc_compatible.py b/src/openmc/openmoc_compatible.py similarity index 100% rename from openmc/openmoc_compatible.py rename to src/openmc/openmoc_compatible.py diff --git a/openmc/particle_restart.py b/src/openmc/particle_restart.py similarity index 100% rename from openmc/particle_restart.py rename to src/openmc/particle_restart.py diff --git a/openmc/plots.py b/src/openmc/plots.py similarity index 100% rename from openmc/plots.py rename to src/openmc/plots.py diff --git a/openmc/plotter.py b/src/openmc/plotter.py similarity index 100% rename from openmc/plotter.py rename to src/openmc/plotter.py diff --git a/openmc/polynomial.py b/src/openmc/polynomial.py similarity index 100% rename from openmc/polynomial.py rename to src/openmc/polynomial.py diff --git a/openmc/region.py b/src/openmc/region.py similarity index 100% rename from openmc/region.py rename to src/openmc/region.py diff --git a/openmc/search.py b/src/openmc/search.py similarity index 100% rename from openmc/search.py rename to src/openmc/search.py diff --git a/openmc/settings.py b/src/openmc/settings.py similarity index 100% rename from openmc/settings.py rename to src/openmc/settings.py diff --git a/openmc/source.py b/src/openmc/source.py similarity index 100% rename from openmc/source.py rename to src/openmc/source.py diff --git a/openmc/statepoint.py b/src/openmc/statepoint.py similarity index 100% rename from openmc/statepoint.py rename to src/openmc/statepoint.py diff --git a/openmc/stats/__init__.py b/src/openmc/stats/__init__.py similarity index 100% rename from openmc/stats/__init__.py rename to src/openmc/stats/__init__.py diff --git a/openmc/stats/multivariate.py b/src/openmc/stats/multivariate.py similarity index 100% rename from openmc/stats/multivariate.py rename to src/openmc/stats/multivariate.py diff --git a/openmc/stats/univariate.py b/src/openmc/stats/univariate.py similarity index 100% rename from openmc/stats/univariate.py rename to src/openmc/stats/univariate.py diff --git a/openmc/summary.py b/src/openmc/summary.py similarity index 100% rename from openmc/summary.py rename to src/openmc/summary.py diff --git a/openmc/surface.py b/src/openmc/surface.py similarity index 100% rename from openmc/surface.py rename to src/openmc/surface.py diff --git a/openmc/tallies.py b/src/openmc/tallies.py similarity index 100% rename from openmc/tallies.py rename to src/openmc/tallies.py diff --git a/openmc/tally_derivative.py b/src/openmc/tally_derivative.py similarity index 100% rename from openmc/tally_derivative.py rename to src/openmc/tally_derivative.py diff --git a/openmc/tracks.py b/src/openmc/tracks.py similarity index 100% rename from openmc/tracks.py rename to src/openmc/tracks.py diff --git a/openmc/trigger.py b/src/openmc/trigger.py similarity index 100% rename from openmc/trigger.py rename to src/openmc/trigger.py diff --git a/openmc/universe.py b/src/openmc/universe.py similarity index 100% rename from openmc/universe.py rename to src/openmc/universe.py diff --git a/openmc/utility_funcs.py b/src/openmc/utility_funcs.py similarity index 100% rename from openmc/utility_funcs.py rename to src/openmc/utility_funcs.py diff --git a/openmc/volume.py b/src/openmc/volume.py similarity index 100% rename from openmc/volume.py rename to src/openmc/volume.py diff --git a/openmc/weight_windows.py b/src/openmc/weight_windows.py similarity index 100% rename from openmc/weight_windows.py rename to src/openmc/weight_windows.py From 303f5963a5737900a53753eb5bccd48331115c64 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Thu, 3 Oct 2024 21:09:51 +0600 Subject: [PATCH 45/76] no need to copy lib to openmc --- CMakeLists.txt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2742111cdf3..34c0753303a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -644,17 +644,6 @@ if(SKBUILD) ) endif() -#=============================================================================== -# Copy libopenmc to Python module directory for development -#=============================================================================== -if(CMAKE_BUILD_TYPE STREQUAL "Debug") - set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) - add_custom_command(TARGET libopenmc POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - $ - ${CMAKE_CURRENT_SOURCE_DIR}/openmc/lib/$ - COMMENT "Copying libopenmc to Python module directory") -endif() #=============================================================================== # Install executable, scripts, manpage, license #=============================================================================== From 1813d6e5fcd1a4f7242606ad2c401388a3f14884 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Thu, 3 Oct 2024 21:41:38 +0600 Subject: [PATCH 46/76] remove BUILD_EXAMPLES --- tools/ci/manylinux.dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/ci/manylinux.dockerfile b/tools/ci/manylinux.dockerfile index 7b5e949a280..783834a577e 100644 --- a/tools/ci/manylinux.dockerfile +++ b/tools/ci/manylinux.dockerfile @@ -148,8 +148,7 @@ RUN git clone --depth 1 -b ${HDF5_TAG} https://github.com/HDFGroup/hdf5.git hdf5 -DCMAKE_INSTALL_PREFIX=/usr/local \ -DHDF5_ENABLE_PARALLEL=$([ ${COMPILER} == "openmpi" ] && echo "ON" || echo "OFF") \ -DHDF5_BUILD_HL_LIB=ON \ - -DBUILD_SHARED_LIBS=ON \ - -DBUILD_EXAMPLES=OFF && \ + -DBUILD_SHARED_LIBS=ON && \ make -j$(nproc) && make install && \ cd ../.. && \ rm -rf hdf5 From 2cbce3b7db3602878f1dfe8dc43a7b2da21aa671 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Thu, 3 Oct 2024 22:10:05 +0600 Subject: [PATCH 47/76] python deps stage --- .../workflows/docker-publish-manylinux.yml | 4 +- .github/workflows/pypi.yml | 2 +- tools/ci/manylinux.dockerfile | 130 +++++++++--------- 3 files changed, 69 insertions(+), 67 deletions(-) diff --git a/.github/workflows/docker-publish-manylinux.yml b/.github/workflows/docker-publish-manylinux.yml index 5fc49d8900c..e6860457e5b 100644 --- a/.github/workflows/docker-publish-manylinux.yml +++ b/.github/workflows/docker-publish-manylinux.yml @@ -54,8 +54,8 @@ jobs: uses: firehed/multistage-docker-build-action@v1 with: repository: ${{ env.image_base_tag }} - stages: base, dependencies, openmc - server-stage: test + stages: base, dependencies, python-dependencies + server-stage: openmc quiet: false parallel: true tag-latest-on-default: ${{ env.tag-latest-on-default }} diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 0b324d3b7c1..bd9efb69646 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -33,7 +33,7 @@ jobs: env: CIBW_BUILD: "cp*-${{ matrix.arch }}" CIBW_ARCHS_LINUX: "x86_64" - CIBW_MANYLINUX_X86_64_IMAGE: ghcr.io/${{ github.repository_owner }}/openmc-manylinux_2_28_x86_64-gcc/openmc:latest + CIBW_MANYLINUX_X86_64_IMAGE: ghcr.io/${{ github.repository_owner }}/openmc-manylinux_2_28_x86_64-gcc/python-dependencies:latest CIBW_ARCHS_MACOS: "native" CIBW_BEFORE_BUILD_MACOS: | brew install llvm cmake xtensor hdf5 python libomp libpng diff --git a/tools/ci/manylinux.dockerfile b/tools/ci/manylinux.dockerfile index 783834a577e..89798082218 100644 --- a/tools/ci/manylinux.dockerfile +++ b/tools/ci/manylinux.dockerfile @@ -10,9 +10,9 @@ # 1. Base Stage: Sets up a Manylinux base image and installs necessary dependencies. # 2. Compiler Configuration: Defines the compilers (GCC or OpenMPI) to be used. # 3. Dependencies Stage: Downloads and builds all external dependencies. -# 4. OpenMC Stage: Copies OpenMC source code, builds it using CMake with specific -# flags and installs it in the container. -# 5. Test Stage: Runs OpenMC unit tests. +# 4. Python Dependencies Stage: Downloads and installs Python dependencies. +# 5. OpenMC Stage: Copies OpenMC source code, build wheel with specific +# flags and installs it in the container. Then, runs tests. # Arguments and environment variables can be customized for different compiler and # dependency versions. @@ -229,26 +229,6 @@ RUN git clone --depth 1 -b ${DAGMC_TAG} https://github.com/svalinn/DAGMC.git dag cd ../.. && \ rm -rf dagmc -# Build and install NCrystal -ARG NCrystal_TAG -RUN git clone --depth 1 -b ${NCrystal_TAG} https://github.com/mctools/ncrystal.git ncrystal && \ - cd ncrystal && \ - mkdir build && cd build && \ - cmake .. \ - -DCMAKE_INSTALL_PREFIX=/usr/local \ - -DBUILD_SHARED_LIBS=ON \ - -DNCRYSTAL_NOTOUCH_CMAKE_BUILD_TYPE=ON \ - -DNCRYSTAL_MODIFY_RPATH=OFF \ - -DCMAKE_BUILD_TYPE=Release \ - -DNCRYSTAL_ENABLE_EXAMPLES=OFF \ - -DNCRYSTAL_ENABLE_SETUPSH=OFF \ - -DNCRYSTAL_ENABLE_DATA=EMBED \ - -DPython3_EXECUTABLE=$(which python) && \ - make -j$(nproc) && make install && \ - cd ../.. && \ - ncrystal-config --setup && \ - rm -rf ncrystal - # Build and install libMesh ARG LIBMESH_TAG RUN git clone --depth 1 -b ${LIBMESH_TAG} https://github.com/libMesh/libmesh.git libmesh && \ @@ -280,59 +260,41 @@ RUN git clone --depth 1 -b ${MCPL_TAG} https://github.com/mctools/mcpl.git mcpl # Download and extract HDF5 data RUN wget -q -O - https://anl.box.com/shared/static/teaup95cqv8s9nn56hfn7ku8mmelr95p.xz | tar -C $HOME -xJ +ENV OPENMC_CROSS_SECTIONS=$HOME/nndc_hdf5/cross_sections.xml # Download and extract ENDF/B-VII.1 distribution RUN wget -q -O - https://anl.box.com/shared/static/4kd2gxnf4gtk4w1c8eua5fsua22kvgjb.xz | tar -C $HOME -xJ +ENV OPENMC_ENDF_DATA=$HOME/endf-b-vii.1 -# Build and install OpenMC stage -FROM dependencies AS openmc +# Python dependencies stage +FROM dependencies AS python-dependencies -ARG COMPILER ARG Python_ABI -ARG OPENMC_USE_OPENMP -ARG OPENMC_BUILD_TESTS -ARG OPENMC_ENABLE_PROFILE -ARG OPENMC_ENABLE_COVERAGE -ARG OPENMC_USE_DAGMC -ARG OPENMC_USE_LIBMESH -ARG OPENMC_USE_MCPL -ARG OPENMC_USE_NCRYSTAL -ARG OPENMC_USE_UWUW # Use Python from manylinux as the default Python ENV PATH="/opt/python/${Python_ABI}/bin:${PATH}" RUN ln -sf /opt/python/${Python_ABI}/bin/python3 /usr/bin/python -# Copy OpenMC source to docker image -COPY . $HOME/openmc - -# Configure SKBUILD CMake arguments -RUN export SKBUILD_CMAKE_ARGS="-DOPENMC_USE_MPI=$([ ${COMPILER} == 'openmpi' ] && echo 'ON' || echo 'OFF'); \ - -DOPENMC_USE_OPENMP=${OPENMC_USE_OPENMP}; \ - -DOPENMC_BUILD_TESTS=${OPENMC_BUILD_TESTS}; \ - -DOPENMC_ENABLE_PROFILE=${OPENMC_ENABLE_PROFILE}; \ - -DOPENMC_ENABLE_COVERAGE=${OPENMC_ENABLE_COVERAGE}; \ - -DOPENMC_USE_DAGMC=${OPENMC_USE_DAGMC}; \ - -DOPENMC_USE_LIBMESH=${OPENMC_USE_LIBMESH}; \ - -DOPENMC_USE_MCPL=${OPENMC_USE_MCPL}; \ - -DOPENMC_USE_NCRYSTAL=${OPENMC_USE_NCRYSTAL}; \ - -DOPENMC_USE_UWUW=${OPENMC_USE_UWUW}" && \ - cd $HOME/openmc && \ - python -m build . -w - -# Repair wheel -RUN auditwheel repair $HOME/openmc/dist/openmc-*.whl -w $HOME/openmc/dist/ - -# Install OpenMC wheel -RUN python -m pip install \ - "$(echo $HOME/openmc/dist/*manylinux**.whl)[$([ ${COMPILER} == 'openmpi' ] && echo 'depletion-mpi,')test,ci,vtk]" - - -# Test OpenMC stage -FROM openmc AS test - -ARG COMPILER +# Build and install NCrystal +ARG NCrystal_TAG +RUN git clone --depth 1 -b ${NCrystal_TAG} https://github.com/mctools/ncrystal.git ncrystal && \ + cd ncrystal && \ + mkdir build && cd build && \ + cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ + -DBUILD_SHARED_LIBS=ON \ + -DNCRYSTAL_NOTOUCH_CMAKE_BUILD_TYPE=ON \ + -DNCRYSTAL_MODIFY_RPATH=OFF \ + -DCMAKE_BUILD_TYPE=Release \ + -DNCRYSTAL_ENABLE_EXAMPLES=OFF \ + -DNCRYSTAL_ENABLE_SETUPSH=OFF \ + -DNCRYSTAL_ENABLE_DATA=EMBED \ + -DPython3_EXECUTABLE=$(which python) && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + ncrystal-config --setup && \ + rm -rf ncrystal # Build and install pybind ARG PYBIND_TAG @@ -395,6 +357,46 @@ RUN git clone --depth 1 -b ${VECTFIT_TAG} https://github.com/liangjg/vectfit.git cd .. && \ rm -rf vectfit + +# OpenMC stage +FROM python-dependencies AS openmc + +ARG COMPILER +ARG Python_ABI +ARG OPENMC_USE_OPENMP +ARG OPENMC_BUILD_TESTS +ARG OPENMC_ENABLE_PROFILE +ARG OPENMC_ENABLE_COVERAGE +ARG OPENMC_USE_DAGMC +ARG OPENMC_USE_LIBMESH +ARG OPENMC_USE_MCPL +ARG OPENMC_USE_NCRYSTAL +ARG OPENMC_USE_UWUW + +# Copy OpenMC source to docker image +COPY . $HOME/openmc + +# Configure SKBUILD CMake arguments +RUN export SKBUILD_CMAKE_ARGS="-DOPENMC_USE_MPI=$([ ${COMPILER} == 'openmpi' ] && echo 'ON' || echo 'OFF'); \ + -DOPENMC_USE_OPENMP=${OPENMC_USE_OPENMP}; \ + -DOPENMC_BUILD_TESTS=${OPENMC_BUILD_TESTS}; \ + -DOPENMC_ENABLE_PROFILE=${OPENMC_ENABLE_PROFILE}; \ + -DOPENMC_ENABLE_COVERAGE=${OPENMC_ENABLE_COVERAGE}; \ + -DOPENMC_USE_DAGMC=${OPENMC_USE_DAGMC}; \ + -DOPENMC_USE_LIBMESH=${OPENMC_USE_LIBMESH}; \ + -DOPENMC_USE_MCPL=${OPENMC_USE_MCPL}; \ + -DOPENMC_USE_NCRYSTAL=${OPENMC_USE_NCRYSTAL}; \ + -DOPENMC_USE_UWUW=${OPENMC_USE_UWUW}" && \ + cd $HOME/openmc && \ + python -m build . -w + +# Repair wheel +RUN auditwheel repair $HOME/openmc/dist/openmc-*.whl -w $HOME/openmc/dist/ + +# Install OpenMC wheel +RUN python -m pip install \ + "$(echo $HOME/openmc/dist/*manylinux**.whl)[$([ ${COMPILER} == 'openmpi' ] && echo 'depletion-mpi,')test,ci,vtk]" + # Test OpenMC RUN cd $HOME/openmc && \ nctool --test && \ From d58867078be9712ccec94833ba5b5a4674b9521b Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Thu, 3 Oct 2024 22:47:38 +0600 Subject: [PATCH 48/76] pip install numpy --- tools/ci/manylinux.dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ci/manylinux.dockerfile b/tools/ci/manylinux.dockerfile index 89798082218..97e91194236 100644 --- a/tools/ci/manylinux.dockerfile +++ b/tools/ci/manylinux.dockerfile @@ -333,6 +333,7 @@ ARG XTENSOR_PYTHON_TAG RUN git clone --depth 1 -b ${XTENSOR_PYTHON_TAG} https://github.com/xtensor-stack/xtensor-python.git xtensor-python && \ cd xtensor-python && \ mkdir build && cd build && \ + python -m pip install numpy && \ cmake .. \ -DNUMPY_INCLUDE_DIRS=$(python -c "import numpy; print(numpy.get_include())") && \ make -j$(nproc) && make install && \ From 4b08da7b5eec0557d0f5fd347730ddf990fd92d0 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Thu, 3 Oct 2024 23:19:07 +0600 Subject: [PATCH 49/76] fail-fast: false --- .github/workflows/docker-publish-manylinux.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/docker-publish-manylinux.yml b/.github/workflows/docker-publish-manylinux.yml index e6860457e5b..073b9db5074 100644 --- a/.github/workflows/docker-publish-manylinux.yml +++ b/.github/workflows/docker-publish-manylinux.yml @@ -13,6 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: manylinux_image: [ manylinux_2_28_x86_64 From db2bb3f0d1062b89a79759dd2479a9a148aa99fa Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Fri, 4 Oct 2024 00:14:14 +0600 Subject: [PATCH 50/76] sdist.include = ["src/openmc/**"] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 847b97bded6..0f5cfb9d659 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,4 +65,4 @@ build.verbose = true logging.level = "INFO" wheel.install-dir = "openmc" wheel.packages = ["src/openmc"] -wheel.exclude = ["CMakeLists.txt"] +sdist.include = ["src/openmc/**"] From 63e1b26d5b90a9b9c1abc1af16ae72fa2fef1d8c Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Fri, 4 Oct 2024 19:18:54 +0600 Subject: [PATCH 51/76] set DATAROOTDIR --- CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 34c0753303a..ce9f00f915f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -339,6 +339,8 @@ if(SKBUILD) set(CMAKE_INSTALL_BINDIR ${SKBUILD_SCRIPTS_DIR}) # Unfortunately, OpenMC has lib directory in the openmc/lib subdirectory set(CMAKE_INSTALL_LIBDIR lib) + set(CMAKE_INSTALL_INCLUDEDIR ${SKBUILD_HEADERS_DIR}) + set(CMAKE_INSTALL_DATAROOTDIR ${SKBUILD_DATA_DIR}) set(SKBUILD_LIB_DIR ${CMAKE_INSTALL_LIBDIR}/python${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}/site-packages/openmc/${CMAKE_INSTALL_LIBDIR}) # Auditwheel and Delocate need this when repairing the wheel @@ -651,7 +653,12 @@ endif() configure_file(cmake/OpenMCConfig.cmake.in "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfig.cmake" @ONLY) configure_file(cmake/OpenMCConfigVersion.cmake.in "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfigVersion.cmake" @ONLY) -set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/OpenMC) +if(SKBUILD) + set(INSTALL_CONFIGDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_LIBDIR}/cmake/OpenMC) +else() + set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/OpenMC) +endif() + install(TARGETS openmc libopenmc EXPORT openmc-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} From cbca8378f8730f32aee5f1e519324a44d7fabf75 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Fri, 4 Oct 2024 20:02:01 +0600 Subject: [PATCH 52/76] add vendor packages --- tools/ci/manylinux.dockerfile | 102 ++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 36 deletions(-) diff --git a/tools/ci/manylinux.dockerfile b/tools/ci/manylinux.dockerfile index 97e91194236..f6f5ec801d7 100644 --- a/tools/ci/manylinux.dockerfile +++ b/tools/ci/manylinux.dockerfile @@ -44,6 +44,11 @@ ARG OPENMC_USE_NCRYSTAL="ON" ARG OPENMC_USE_UWUW="OFF" # Configure dependencies tags +ARG GSL_LITE_TAG="v0.41.0" +ARG XTL_TAG="0.7.7" +ARG XTENSOR_TAG="0.25.0" +ARG XTENSOR_BLAS_TAG="0.21.0" +ARG CATCH2_TAG="v3.7.1" ARG NJOY2016_TAG="2016.76" ARG HDF5_TAG="hdf5_1.14.4.3" ARG NETCDF_TAG="v4.9.2" @@ -53,10 +58,7 @@ ARG DD_TAG="v1.1.0" ARG DAGMC_TAG="v3.2.3" ARG NCrystal_TAG="v3.9.7" ARG PYBIND_TAG="v2.13.6" -ARG XTL_TAG="0.7.7" -ARG XTENSOR_TAG="0.25.0" ARG XTENSOR_PYTHON_TAG="0.27.0" -ARG XTENSOR_BLAS_TAG="0.21.0" ARG VECTFIT_TAG="master" ARG LIBMESH_TAG="v1.7.2" ARG MCPL_TAG="v1.6.2" @@ -88,7 +90,9 @@ RUN yum install -y epel-release && \ curl-devel \ eigen3-devel \ lapack-devel \ - libpng-devel && \ + libpng-devel \ + pugixml-devel \ + fmt-devel && \ yum clean all # Set up environment variables for shared libraries @@ -127,6 +131,60 @@ FROM compiler-${COMPILER} AS dependencies ARG COMPILER +# Build and install gsl-lite +ARG GSL_LITE_TAG +RUN git clone --depth 1 -b ${GSL_LITE_TAG} https://github.com/gsl-lite/gsl-lite.git gsl-lite && \ + cd gsl-lite && \ + mkdir build && cd build && \ + cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr/local && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf gsl-lite + +# Build and install xtl +ARG XTL_TAG +RUN git clone --depth 1 -b ${XTL_TAG} https://github.com/xtensor-stack/xtl.git xtl && \ + cd xtl && \ + mkdir build && cd build && \ + cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr/local && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf xtl + +# Build and install xtensor +ARG XTENSOR_TAG +RUN git clone --depth 1 -b ${XTENSOR_TAG} https://github.com/xtensor-stack/xtensor.git xtensor && \ + cd xtensor && \ + mkdir build && cd build && \ + cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr/local && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf xtensor + +# Build and install xtensor-blas +ARG XTENSOR_BLAS_TAG +RUN git clone --depth 1 -b ${XTENSOR_BLAS_TAG} https://github.com/xtensor-stack/xtensor-blas.git xtensor-blas && \ + cd xtensor-blas && \ + mkdir build && cd build && \ + cmake .. && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf xtensor-blas + +# Build and install Catch2 +ARG CATCH2_TAG +RUN git clone --depth 1 -b ${CATCH2_TAG} https://github.com/catchorg/Catch2.git catch2 && \ + cd catch2 && \ + mkdir build && cd build && \ + cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr/local && \ + make -j$(nproc) && make install && \ + cd ../.. && \ + rm -rf catch2 + # Build and install NJOY2016 ARG NJOY2016_TAG RUN git clone --depth 1 -b ${NJOY2016_TAG} https://github.com/njoy/njoy2016.git njoy && \ @@ -301,33 +359,14 @@ ARG PYBIND_TAG RUN git clone --depth 1 -b ${PYBIND_TAG} https://github.com/pybind/pybind11.git pybind11 && \ cd pybind11 && \ mkdir build && cd build && \ - cmake .. && \ + cmake .. \ + -DCMAKE_INSTALL_PREFIX=/usr/local && \ make -j$(nproc) && make install && \ cd .. && \ python -m pip install . && \ cd .. && \ rm -rf pybind11 -# Build and install xtl -ARG XTL_TAG -RUN git clone --depth 1 -b ${XTL_TAG} https://github.com/xtensor-stack/xtl.git xtl && \ - cd xtl && \ - mkdir build && cd build && \ - cmake .. && \ - make -j$(nproc) && make install && \ - cd ../.. && \ - rm -rf xtl - -# Build and install xtensor -ARG XTENSOR_TAG -RUN git clone --depth 1 -b ${XTENSOR_TAG} https://github.com/xtensor-stack/xtensor.git xtensor && \ - cd xtensor && \ - mkdir build && cd build && \ - cmake .. && \ - make -j$(nproc) && make install && \ - cd ../.. && \ - rm -rf xtensor - # Build and install xtensor-python ARG XTENSOR_PYTHON_TAG RUN git clone --depth 1 -b ${XTENSOR_PYTHON_TAG} https://github.com/xtensor-stack/xtensor-python.git xtensor-python && \ @@ -335,21 +374,12 @@ RUN git clone --depth 1 -b ${XTENSOR_PYTHON_TAG} https://github.com/xtensor-stac mkdir build && cd build && \ python -m pip install numpy && \ cmake .. \ - -DNUMPY_INCLUDE_DIRS=$(python -c "import numpy; print(numpy.get_include())") && \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ + -DNUMPY_INCLUDE_DIRS=$(python -c "import numpy; print(numpy.get_include())") && \ make -j$(nproc) && make install && \ cd ../.. && \ rm -rf xtensor-python -# Build and install xtensor-blas -ARG XTENSOR_BLAS_TAG -RUN git clone --depth 1 -b ${XTENSOR_BLAS_TAG} https://github.com/xtensor-stack/xtensor-blas.git xtensor-blas && \ - cd xtensor-blas && \ - mkdir build && cd build && \ - cmake .. && \ - make -j$(nproc) && make install && \ - cd ../.. && \ - rm -rf xtensor-blas - # Build and install vectfit ARG VECTFIT_TAG RUN git clone --depth 1 -b ${VECTFIT_TAG} https://github.com/liangjg/vectfit.git vectfit && \ From 995c840bafc42907df5b722cc190d28f902b527a Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sat, 5 Oct 2024 00:01:22 +0600 Subject: [PATCH 53/76] add more dirs --- CMakeLists.txt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ce9f00f915f..dae56dfe3da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -341,10 +341,17 @@ if(SKBUILD) set(CMAKE_INSTALL_LIBDIR lib) set(CMAKE_INSTALL_INCLUDEDIR ${SKBUILD_HEADERS_DIR}) set(CMAKE_INSTALL_DATAROOTDIR ${SKBUILD_DATA_DIR}) + set(CMAKE_INSTALL_DATADIR ${SKBUILD_DATA_DIR}) + set(CMAKE_INSTALL_DOCDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_DOCDIR}) + set(CMAKE_INSTALL_INFODIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_INFODIR}) + set(CMAKE_INSTALL_MANDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_MANDIR}) + set(CMAKE_INSTALL_LOCALEDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_LOCALEDIR}) + set(CMAKE_INSTALL_LOCALSTATEDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_LOCALSTATEDIR}) + set(CMAKE_INSTALL_RUNSTATEDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_RUNSTATEDIR}) set(SKBUILD_LIB_DIR ${CMAKE_INSTALL_LIBDIR}/python${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}/site-packages/openmc/${CMAKE_INSTALL_LIBDIR}) # Auditwheel and Delocate need this when repairing the wheel - # Since OpenMC libs are installed in the openmc/core subdirectory + # Since OpenMC libs are installed in the openmc subdirectory # Auditwheel and Delocate need this to find the OpenMC libs for openmc.data # It's a bit of a hack, but it works set(SKBUILD_REPAIR_WHEEL_PATCH openmc/${CMAKE_INSTALL_LIBDIR}) @@ -352,7 +359,7 @@ if(SKBUILD) set(CMAKE_MACOSX_RPATH ON) set(OPENMC_LIBRARY_RPATH "@loader_path") set(OPENMC_PYTHON_MODULE_RPATH "@loader_path/${CMAKE_INSTALL_LIBDIR}") - set(OPENMC_BINARY_RPATH "@loader_path/../${SKBUILD_LIB_DIR};@loader_path/../${SKBUILD_REPAIR_WHEEL_PATCH};@loader_path/../../${SKBUILD_REPAIR_WHEEL_PATCH}") + set(OPENMC_BINARY_RPATH "@loader_path/../${SKBUILD_LIB_DIR};@loader_path/../../${SKBUILD_REPAIR_WHEEL_PATCH}") elseif(UNIX) set(OPENMC_LIBRARY_RPATH "$ORIGIN") set(OPENMC_PYTHON_MODULE_RPATH "$ORIGIN/${CMAKE_INSTALL_LIBDIR}") From d68bac590e0eb1ca95011ca51fee933d55edf0d6 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sat, 5 Oct 2024 01:45:41 +0600 Subject: [PATCH 54/76] CMAKE_INSTALL_DATADIR --- CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dae56dfe3da..03cbb89bf50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -340,8 +340,7 @@ if(SKBUILD) # Unfortunately, OpenMC has lib directory in the openmc/lib subdirectory set(CMAKE_INSTALL_LIBDIR lib) set(CMAKE_INSTALL_INCLUDEDIR ${SKBUILD_HEADERS_DIR}) - set(CMAKE_INSTALL_DATAROOTDIR ${SKBUILD_DATA_DIR}) - set(CMAKE_INSTALL_DATADIR ${SKBUILD_DATA_DIR}) + set(CMAKE_INSTALL_DATADIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_DATADIR}) set(CMAKE_INSTALL_DOCDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_DOCDIR}) set(CMAKE_INSTALL_INFODIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_INFODIR}) set(CMAKE_INSTALL_MANDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_MANDIR}) From 07126a0871b54518d241fb2a54226aa5c893b820 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sat, 5 Oct 2024 16:21:04 +0600 Subject: [PATCH 55/76] no need OpenMCTargets for skbuild --- CMakeLists.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 03cbb89bf50..ba18af20892 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -671,10 +671,14 @@ install(TARGETS openmc libopenmc LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) -install(EXPORT openmc-targets - FILE OpenMCTargets.cmake - NAMESPACE OpenMC:: - DESTINATION ${INSTALL_CONFIGDIR}) + +if(NOT SKBUILD) + install(EXPORT openmc-targets + FILE OpenMCTargets.cmake + NAMESPACE OpenMC:: + DESTINATION ${INSTALL_CONFIGDIR} + ) +endif() # Collect scripts file(GLOB SCRIPTS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/*") From bf0f40038063923fa9ae7fa85ec41eb5bd867c43 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sat, 5 Oct 2024 16:22:57 +0600 Subject: [PATCH 56/76] install rpath if var is defined --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba18af20892..8e395ad363c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -531,7 +531,7 @@ target_include_directories(libopenmc # Set compile flags target_compile_options(libopenmc PRIVATE ${cxxflags}) -if(SKBUILD) +if(OPENMC_LIBRARY_RPATH) set_target_properties( libopenmc PROPERTIES @@ -644,7 +644,7 @@ target_compile_features(openmc PUBLIC cxx_std_17) target_compile_features(libopenmc PUBLIC cxx_std_17) set_target_properties(openmc libopenmc PROPERTIES CXX_EXTENSIONS OFF) -if(SKBUILD) +if(OPENMC_BINARY_RPATH) set_target_properties( openmc PROPERTIES From 12acf73ab5d2a4117ce7861ec7fab13a49ec5f9d Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sat, 5 Oct 2024 22:02:03 +0600 Subject: [PATCH 57/76] eval $(ncrystal-config --setup) --- tools/ci/manylinux.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/manylinux.dockerfile b/tools/ci/manylinux.dockerfile index f6f5ec801d7..ea60b38175c 100644 --- a/tools/ci/manylinux.dockerfile +++ b/tools/ci/manylinux.dockerfile @@ -351,7 +351,6 @@ RUN git clone --depth 1 -b ${NCrystal_TAG} https://github.com/mctools/ncrystal.g -DPython3_EXECUTABLE=$(which python) && \ make -j$(nproc) && make install && \ cd ../.. && \ - ncrystal-config --setup && \ rm -rf ncrystal # Build and install pybind @@ -430,5 +429,6 @@ RUN python -m pip install \ # Test OpenMC RUN cd $HOME/openmc && \ + eval $(ncrystal-config --setup) && \ nctool --test && \ pytest --cov=openmc -v $([ ${COMPILER} == 'openmpi' ] && echo '--mpi') --event tests From bf334ce9e2c2c6ee8a8e9093767396babee275d0 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Tue, 8 Oct 2024 23:44:12 +0600 Subject: [PATCH 58/76] sdist include *.h5 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 0f5cfb9d659..5d1837bec4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,4 +65,4 @@ build.verbose = true logging.level = "INFO" wheel.install-dir = "openmc" wheel.packages = ["src/openmc"] -sdist.include = ["src/openmc/**"] +sdist.include = ["*.h5"] From 4e6939799c16c7712293bcdfc9cc8c612a9e3f2f Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Thu, 17 Oct 2024 20:21:57 +0600 Subject: [PATCH 59/76] setup openmc lib for skbuild --- cmake/OpenMCConfig.cmake.in | 67 +++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/cmake/OpenMCConfig.cmake.in b/cmake/OpenMCConfig.cmake.in index 44a5e0d5a3f..4aa5f92d9ba 100644 --- a/cmake/OpenMCConfig.cmake.in +++ b/cmake/OpenMCConfig.cmake.in @@ -23,7 +23,70 @@ endif() find_package(PNG) -if(NOT TARGET OpenMC::libopenmc) +if(@SKBUILD@) + # Find the Python interpreter and ensure it's available. + find_package(Python COMPONENTS Interpreter REQUIRED) + + # Function to run Python commands and validate their execution. + function(run_python_command output_var command) + execute_process( + COMMAND ${Python_EXECUTABLE} -c "${command}" + OUTPUT_VARIABLE ${output_var} + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE result + ) + # Check if the command was successful + if(NOT result EQUAL 0) + message(FATAL_ERROR "Failed to run Python command: ${command}") + else() + # Add the output variable to the parent scope + set(${output_var} "${${output_var}}" PARENT_SCOPE) + endif() + endfunction() + + # Extract MOAB include paths, library paths, and extra libraries + run_python_command(OpenMC_INCLUDE_DIRS "import openmc; print(openmc.include_path)") + run_python_command(OpenMC_LIBRARY_DIRS "import openmc; print(openmc.lib_path)") + run_python_command(OpenMC_EXTRA_LIBRARIES "import openmc; print(' '.join(openmc.extra_lib))") + + # Check if the wheel was repaired using auditwheel or delocate + if(OpenMC_EXTRA_LIBRARIES) + message(FATAL_ERROR + "This build of OpenMC is not supported. " + "It appears that the wheel was repaired using tools like auditwheel or delocate, " + "that modifies the shared libraries, which may cause problems.\n" + "OpenMC_EXTRA_LIBRARIES is not empty: ${OpenMC_EXTRA_LIBRARIES}.\n" + "To resolve this, please build OpenMC from scratch. " + "For more information, visit: https://docs.openmc.org/" + ) + endif() + + # Find the core library + find_library(OpenMC_LIBRARY + NAMES openmc + HINTS ${OpenMC_LIBRARY_DIRS} + NO_DEFAULT_PATH + ) + + # Add the core library as an imported target + add_library(OpenMC::libopenmc UNKNOWN IMPORTED) + set_target_properties(OpenMC::libopenmc PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${OpenMC_INCLUDE_DIRS}" + IMPORTED_LOCATION "${OpenMC_LIBRARY}" + ) + + # Add the core library to the list of libraries + set(OpenMC_LIBRARIES ${OpenMC_LIBRARY}) + + # Include standard argument handling for finding packages + include(FindPackageHandleStandardArgs) + + # Validates that the necessary variables are set + find_package_handle_standard_args(MOAB + REQUIRED_VARS OpenMC_LIBRARIES OpenMC_INCLUDE_DIRS + VERSION_VAR @OPENMC_VERSION@ + ) +elseif(NOT TARGET OpenMC::libopenmc) include("${OpenMC_CMAKE_DIR}/OpenMCTargets.cmake") endif() @@ -41,4 +104,4 @@ endif() if(@OPENMC_USE_UWUW@) find_package(UWUW REQUIRED) -endif() +endif() \ No newline at end of file From 4a69b09ba71796cfdfe672b9eada5ac9863ed6fd Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Thu, 17 Oct 2024 20:23:18 +0600 Subject: [PATCH 60/76] prepare for merge --- {src/openmc => openmc}/__init__.py | 0 {src/openmc => openmc}/_xml.py | 0 {src/openmc => openmc}/arithmetic.py | 0 {src/openmc => openmc}/bounding_box.py | 0 {src/openmc => openmc}/cell.py | 0 {src/openmc => openmc}/checkvalue.py | 0 {src/openmc => openmc}/cmfd.py | 0 {src/openmc => openmc}/config.py | 0 {src/openmc => openmc}/data/BREMX.DAT | 0 {src/openmc => openmc}/data/__init__.py | 0 {src/openmc => openmc}/data/ace.py | 0 {src/openmc => openmc}/data/angle_distribution.py | 0 {src/openmc => openmc}/data/angle_energy.py | 0 {src/openmc => openmc}/data/correlated.py | 0 {src/openmc => openmc}/data/data.py | 0 {src/openmc => openmc}/data/decay.py | 0 {src/openmc => openmc}/data/effective_dose/__init__.py | 0 {src/openmc => openmc}/data/effective_dose/dose.py | 0 {src/openmc => openmc}/data/effective_dose/electrons.txt | 0 {src/openmc => openmc}/data/effective_dose/helium_ions.txt | 0 {src/openmc => openmc}/data/effective_dose/negative_muons.txt | 0 {src/openmc => openmc}/data/effective_dose/negative_pions.txt | 0 {src/openmc => openmc}/data/effective_dose/neutrons.txt | 0 {src/openmc => openmc}/data/effective_dose/photons.txt | 0 {src/openmc => openmc}/data/effective_dose/photons_kerma.txt | 0 {src/openmc => openmc}/data/effective_dose/positive_muons.txt | 0 {src/openmc => openmc}/data/effective_dose/positive_pions.txt | 0 {src/openmc => openmc}/data/effective_dose/positrons.txt | 0 {src/openmc => openmc}/data/effective_dose/protons.txt | 0 {src/openmc => openmc}/data/endf.py | 0 {src/openmc => openmc}/data/energy_distribution.py | 0 {src/openmc => openmc}/data/fission_energy.py | 0 {src/openmc => openmc}/data/function.py | 0 {src/openmc => openmc}/data/grid.py | 0 {src/openmc => openmc}/data/half_life.json | 0 {src/openmc => openmc}/data/kalbach_mann.py | 0 {src/openmc => openmc}/data/laboratory.py | 0 {src/openmc => openmc}/data/library.py | 0 {src/openmc => openmc}/data/mass_1.mas20.txt | 0 {src/openmc => openmc}/data/multipole.py | 0 {src/openmc => openmc}/data/nbody.py | 0 {src/openmc => openmc}/data/neutron.py | 0 {src/openmc => openmc}/data/njoy.py | 0 {src/openmc => openmc}/data/photon.py | 0 {src/openmc => openmc}/data/product.py | 0 {src/openmc => openmc}/data/reaction.py | 0 {src/openmc => openmc}/data/resonance.py | 0 {src/openmc => openmc}/data/resonance_covariance.py | 0 {src/openmc => openmc}/data/thermal.py | 0 {src/openmc => openmc}/data/thermal_angle_energy.py | 0 {src/openmc => openmc}/data/uncorrelated.py | 0 {src/openmc => openmc}/data/urr.py | 0 {src/openmc => openmc}/deplete/__init__.py | 0 {src/openmc => openmc}/deplete/_matrix_funcs.py | 0 {src/openmc => openmc}/deplete/abc.py | 0 {src/openmc => openmc}/deplete/atom_number.py | 0 {src/openmc => openmc}/deplete/chain.py | 0 {src/openmc => openmc}/deplete/coupled_operator.py | 0 {src/openmc => openmc}/deplete/cram.py | 0 {src/openmc => openmc}/deplete/helpers.py | 0 {src/openmc => openmc}/deplete/independent_operator.py | 0 {src/openmc => openmc}/deplete/integrators.py | 0 {src/openmc => openmc}/deplete/microxs.py | 0 {src/openmc => openmc}/deplete/nuclide.py | 0 {src/openmc => openmc}/deplete/openmc_operator.py | 0 {src/openmc => openmc}/deplete/pool.py | 0 {src/openmc => openmc}/deplete/reaction_rates.py | 0 {src/openmc => openmc}/deplete/results.py | 0 {src/openmc => openmc}/deplete/stepresult.py | 0 {src/openmc => openmc}/deplete/transfer_rates.py | 0 {src/openmc => openmc}/dummy_comm.py | 0 {src/openmc => openmc}/element.py | 0 {src/openmc => openmc}/examples.py | 0 {src/openmc => openmc}/exceptions.py | 0 {src/openmc => openmc}/executor.py | 0 {src/openmc => openmc}/filter.py | 0 {src/openmc => openmc}/filter_expansion.py | 0 {src/openmc => openmc}/geometry.py | 0 {src/openmc => openmc}/lattice.py | 0 {src/openmc => openmc}/lib/__init__.py | 0 {src/openmc => openmc}/lib/cell.py | 0 {src/openmc => openmc}/lib/core.py | 0 {src/openmc => openmc}/lib/error.py | 0 {src/openmc => openmc}/lib/filter.py | 0 {src/openmc => openmc}/lib/material.py | 0 {src/openmc => openmc}/lib/math.py | 0 {src/openmc => openmc}/lib/mesh.py | 0 {src/openmc => openmc}/lib/nuclide.py | 0 {src/openmc => openmc}/lib/plot.py | 0 {src/openmc => openmc}/lib/settings.py | 0 {src/openmc => openmc}/lib/tally.py | 0 {src/openmc => openmc}/lib/weight_windows.py | 0 {src/openmc => openmc}/macroscopic.py | 0 {src/openmc => openmc}/material.py | 0 {src/openmc => openmc}/mesh.py | 0 {src/openmc => openmc}/mgxs/__init__.py | 0 {src/openmc => openmc}/mgxs/groups.py | 0 {src/openmc => openmc}/mgxs/library.py | 0 {src/openmc => openmc}/mgxs/mdgxs.py | 0 {src/openmc => openmc}/mgxs/mgxs.py | 0 {src/openmc => openmc}/mgxs_library.py | 0 {src/openmc => openmc}/mixin.py | 0 {src/openmc => openmc}/model/__init__.py | 0 {src/openmc => openmc}/model/funcs.py | 0 {src/openmc => openmc}/model/model.py | 0 {src/openmc => openmc}/model/surface_composite.py | 0 {src/openmc => openmc}/model/triso.py | 0 {src/openmc => openmc}/mpi.py | 0 {src/openmc => openmc}/nuclide.py | 0 {src/openmc => openmc}/openmc_exec.py | 0 {src/openmc => openmc}/openmoc_compatible.py | 0 {src/openmc => openmc}/particle_restart.py | 0 {src/openmc => openmc}/plots.py | 0 {src/openmc => openmc}/plotter.py | 0 {src/openmc => openmc}/polynomial.py | 0 {src/openmc => openmc}/region.py | 0 {src/openmc => openmc}/search.py | 0 {src/openmc => openmc}/settings.py | 0 {src/openmc => openmc}/source.py | 0 {src/openmc => openmc}/statepoint.py | 0 {src/openmc => openmc}/stats/__init__.py | 0 {src/openmc => openmc}/stats/multivariate.py | 0 {src/openmc => openmc}/stats/univariate.py | 0 {src/openmc => openmc}/summary.py | 0 {src/openmc => openmc}/surface.py | 0 {src/openmc => openmc}/tallies.py | 0 {src/openmc => openmc}/tally_derivative.py | 0 {src/openmc => openmc}/tracks.py | 0 {src/openmc => openmc}/trigger.py | 0 {src/openmc => openmc}/universe.py | 0 {src/openmc => openmc}/utility_funcs.py | 0 {src/openmc => openmc}/volume.py | 0 {src/openmc => openmc}/weight_windows.py | 0 133 files changed, 0 insertions(+), 0 deletions(-) rename {src/openmc => openmc}/__init__.py (100%) rename {src/openmc => openmc}/_xml.py (100%) rename {src/openmc => openmc}/arithmetic.py (100%) rename {src/openmc => openmc}/bounding_box.py (100%) rename {src/openmc => openmc}/cell.py (100%) rename {src/openmc => openmc}/checkvalue.py (100%) rename {src/openmc => openmc}/cmfd.py (100%) rename {src/openmc => openmc}/config.py (100%) rename {src/openmc => openmc}/data/BREMX.DAT (100%) rename {src/openmc => openmc}/data/__init__.py (100%) rename {src/openmc => openmc}/data/ace.py (100%) rename {src/openmc => openmc}/data/angle_distribution.py (100%) rename {src/openmc => openmc}/data/angle_energy.py (100%) rename {src/openmc => openmc}/data/correlated.py (100%) rename {src/openmc => openmc}/data/data.py (100%) rename {src/openmc => openmc}/data/decay.py (100%) rename {src/openmc => openmc}/data/effective_dose/__init__.py (100%) rename {src/openmc => openmc}/data/effective_dose/dose.py (100%) rename {src/openmc => openmc}/data/effective_dose/electrons.txt (100%) rename {src/openmc => openmc}/data/effective_dose/helium_ions.txt (100%) rename {src/openmc => openmc}/data/effective_dose/negative_muons.txt (100%) rename {src/openmc => openmc}/data/effective_dose/negative_pions.txt (100%) rename {src/openmc => openmc}/data/effective_dose/neutrons.txt (100%) rename {src/openmc => openmc}/data/effective_dose/photons.txt (100%) rename {src/openmc => openmc}/data/effective_dose/photons_kerma.txt (100%) rename {src/openmc => openmc}/data/effective_dose/positive_muons.txt (100%) rename {src/openmc => openmc}/data/effective_dose/positive_pions.txt (100%) rename {src/openmc => openmc}/data/effective_dose/positrons.txt (100%) rename {src/openmc => openmc}/data/effective_dose/protons.txt (100%) rename {src/openmc => openmc}/data/endf.py (100%) rename {src/openmc => openmc}/data/energy_distribution.py (100%) rename {src/openmc => openmc}/data/fission_energy.py (100%) rename {src/openmc => openmc}/data/function.py (100%) rename {src/openmc => openmc}/data/grid.py (100%) rename {src/openmc => openmc}/data/half_life.json (100%) rename {src/openmc => openmc}/data/kalbach_mann.py (100%) rename {src/openmc => openmc}/data/laboratory.py (100%) rename {src/openmc => openmc}/data/library.py (100%) rename {src/openmc => openmc}/data/mass_1.mas20.txt (100%) rename {src/openmc => openmc}/data/multipole.py (100%) rename {src/openmc => openmc}/data/nbody.py (100%) rename {src/openmc => openmc}/data/neutron.py (100%) rename {src/openmc => openmc}/data/njoy.py (100%) rename {src/openmc => openmc}/data/photon.py (100%) rename {src/openmc => openmc}/data/product.py (100%) rename {src/openmc => openmc}/data/reaction.py (100%) rename {src/openmc => openmc}/data/resonance.py (100%) rename {src/openmc => openmc}/data/resonance_covariance.py (100%) rename {src/openmc => openmc}/data/thermal.py (100%) rename {src/openmc => openmc}/data/thermal_angle_energy.py (100%) rename {src/openmc => openmc}/data/uncorrelated.py (100%) rename {src/openmc => openmc}/data/urr.py (100%) rename {src/openmc => openmc}/deplete/__init__.py (100%) rename {src/openmc => openmc}/deplete/_matrix_funcs.py (100%) rename {src/openmc => openmc}/deplete/abc.py (100%) rename {src/openmc => openmc}/deplete/atom_number.py (100%) rename {src/openmc => openmc}/deplete/chain.py (100%) rename {src/openmc => openmc}/deplete/coupled_operator.py (100%) rename {src/openmc => openmc}/deplete/cram.py (100%) rename {src/openmc => openmc}/deplete/helpers.py (100%) rename {src/openmc => openmc}/deplete/independent_operator.py (100%) rename {src/openmc => openmc}/deplete/integrators.py (100%) rename {src/openmc => openmc}/deplete/microxs.py (100%) rename {src/openmc => openmc}/deplete/nuclide.py (100%) rename {src/openmc => openmc}/deplete/openmc_operator.py (100%) rename {src/openmc => openmc}/deplete/pool.py (100%) rename {src/openmc => openmc}/deplete/reaction_rates.py (100%) rename {src/openmc => openmc}/deplete/results.py (100%) rename {src/openmc => openmc}/deplete/stepresult.py (100%) rename {src/openmc => openmc}/deplete/transfer_rates.py (100%) rename {src/openmc => openmc}/dummy_comm.py (100%) rename {src/openmc => openmc}/element.py (100%) rename {src/openmc => openmc}/examples.py (100%) rename {src/openmc => openmc}/exceptions.py (100%) rename {src/openmc => openmc}/executor.py (100%) rename {src/openmc => openmc}/filter.py (100%) rename {src/openmc => openmc}/filter_expansion.py (100%) rename {src/openmc => openmc}/geometry.py (100%) rename {src/openmc => openmc}/lattice.py (100%) rename {src/openmc => openmc}/lib/__init__.py (100%) rename {src/openmc => openmc}/lib/cell.py (100%) rename {src/openmc => openmc}/lib/core.py (100%) rename {src/openmc => openmc}/lib/error.py (100%) rename {src/openmc => openmc}/lib/filter.py (100%) rename {src/openmc => openmc}/lib/material.py (100%) rename {src/openmc => openmc}/lib/math.py (100%) rename {src/openmc => openmc}/lib/mesh.py (100%) rename {src/openmc => openmc}/lib/nuclide.py (100%) rename {src/openmc => openmc}/lib/plot.py (100%) rename {src/openmc => openmc}/lib/settings.py (100%) rename {src/openmc => openmc}/lib/tally.py (100%) rename {src/openmc => openmc}/lib/weight_windows.py (100%) rename {src/openmc => openmc}/macroscopic.py (100%) rename {src/openmc => openmc}/material.py (100%) rename {src/openmc => openmc}/mesh.py (100%) rename {src/openmc => openmc}/mgxs/__init__.py (100%) rename {src/openmc => openmc}/mgxs/groups.py (100%) rename {src/openmc => openmc}/mgxs/library.py (100%) rename {src/openmc => openmc}/mgxs/mdgxs.py (100%) rename {src/openmc => openmc}/mgxs/mgxs.py (100%) rename {src/openmc => openmc}/mgxs_library.py (100%) rename {src/openmc => openmc}/mixin.py (100%) rename {src/openmc => openmc}/model/__init__.py (100%) rename {src/openmc => openmc}/model/funcs.py (100%) rename {src/openmc => openmc}/model/model.py (100%) rename {src/openmc => openmc}/model/surface_composite.py (100%) rename {src/openmc => openmc}/model/triso.py (100%) rename {src/openmc => openmc}/mpi.py (100%) rename {src/openmc => openmc}/nuclide.py (100%) rename {src/openmc => openmc}/openmc_exec.py (100%) rename {src/openmc => openmc}/openmoc_compatible.py (100%) rename {src/openmc => openmc}/particle_restart.py (100%) rename {src/openmc => openmc}/plots.py (100%) rename {src/openmc => openmc}/plotter.py (100%) rename {src/openmc => openmc}/polynomial.py (100%) rename {src/openmc => openmc}/region.py (100%) rename {src/openmc => openmc}/search.py (100%) rename {src/openmc => openmc}/settings.py (100%) rename {src/openmc => openmc}/source.py (100%) rename {src/openmc => openmc}/statepoint.py (100%) rename {src/openmc => openmc}/stats/__init__.py (100%) rename {src/openmc => openmc}/stats/multivariate.py (100%) rename {src/openmc => openmc}/stats/univariate.py (100%) rename {src/openmc => openmc}/summary.py (100%) rename {src/openmc => openmc}/surface.py (100%) rename {src/openmc => openmc}/tallies.py (100%) rename {src/openmc => openmc}/tally_derivative.py (100%) rename {src/openmc => openmc}/tracks.py (100%) rename {src/openmc => openmc}/trigger.py (100%) rename {src/openmc => openmc}/universe.py (100%) rename {src/openmc => openmc}/utility_funcs.py (100%) rename {src/openmc => openmc}/volume.py (100%) rename {src/openmc => openmc}/weight_windows.py (100%) diff --git a/src/openmc/__init__.py b/openmc/__init__.py similarity index 100% rename from src/openmc/__init__.py rename to openmc/__init__.py diff --git a/src/openmc/_xml.py b/openmc/_xml.py similarity index 100% rename from src/openmc/_xml.py rename to openmc/_xml.py diff --git a/src/openmc/arithmetic.py b/openmc/arithmetic.py similarity index 100% rename from src/openmc/arithmetic.py rename to openmc/arithmetic.py diff --git a/src/openmc/bounding_box.py b/openmc/bounding_box.py similarity index 100% rename from src/openmc/bounding_box.py rename to openmc/bounding_box.py diff --git a/src/openmc/cell.py b/openmc/cell.py similarity index 100% rename from src/openmc/cell.py rename to openmc/cell.py diff --git a/src/openmc/checkvalue.py b/openmc/checkvalue.py similarity index 100% rename from src/openmc/checkvalue.py rename to openmc/checkvalue.py diff --git a/src/openmc/cmfd.py b/openmc/cmfd.py similarity index 100% rename from src/openmc/cmfd.py rename to openmc/cmfd.py diff --git a/src/openmc/config.py b/openmc/config.py similarity index 100% rename from src/openmc/config.py rename to openmc/config.py diff --git a/src/openmc/data/BREMX.DAT b/openmc/data/BREMX.DAT similarity index 100% rename from src/openmc/data/BREMX.DAT rename to openmc/data/BREMX.DAT diff --git a/src/openmc/data/__init__.py b/openmc/data/__init__.py similarity index 100% rename from src/openmc/data/__init__.py rename to openmc/data/__init__.py diff --git a/src/openmc/data/ace.py b/openmc/data/ace.py similarity index 100% rename from src/openmc/data/ace.py rename to openmc/data/ace.py diff --git a/src/openmc/data/angle_distribution.py b/openmc/data/angle_distribution.py similarity index 100% rename from src/openmc/data/angle_distribution.py rename to openmc/data/angle_distribution.py diff --git a/src/openmc/data/angle_energy.py b/openmc/data/angle_energy.py similarity index 100% rename from src/openmc/data/angle_energy.py rename to openmc/data/angle_energy.py diff --git a/src/openmc/data/correlated.py b/openmc/data/correlated.py similarity index 100% rename from src/openmc/data/correlated.py rename to openmc/data/correlated.py diff --git a/src/openmc/data/data.py b/openmc/data/data.py similarity index 100% rename from src/openmc/data/data.py rename to openmc/data/data.py diff --git a/src/openmc/data/decay.py b/openmc/data/decay.py similarity index 100% rename from src/openmc/data/decay.py rename to openmc/data/decay.py diff --git a/src/openmc/data/effective_dose/__init__.py b/openmc/data/effective_dose/__init__.py similarity index 100% rename from src/openmc/data/effective_dose/__init__.py rename to openmc/data/effective_dose/__init__.py diff --git a/src/openmc/data/effective_dose/dose.py b/openmc/data/effective_dose/dose.py similarity index 100% rename from src/openmc/data/effective_dose/dose.py rename to openmc/data/effective_dose/dose.py diff --git a/src/openmc/data/effective_dose/electrons.txt b/openmc/data/effective_dose/electrons.txt similarity index 100% rename from src/openmc/data/effective_dose/electrons.txt rename to openmc/data/effective_dose/electrons.txt diff --git a/src/openmc/data/effective_dose/helium_ions.txt b/openmc/data/effective_dose/helium_ions.txt similarity index 100% rename from src/openmc/data/effective_dose/helium_ions.txt rename to openmc/data/effective_dose/helium_ions.txt diff --git a/src/openmc/data/effective_dose/negative_muons.txt b/openmc/data/effective_dose/negative_muons.txt similarity index 100% rename from src/openmc/data/effective_dose/negative_muons.txt rename to openmc/data/effective_dose/negative_muons.txt diff --git a/src/openmc/data/effective_dose/negative_pions.txt b/openmc/data/effective_dose/negative_pions.txt similarity index 100% rename from src/openmc/data/effective_dose/negative_pions.txt rename to openmc/data/effective_dose/negative_pions.txt diff --git a/src/openmc/data/effective_dose/neutrons.txt b/openmc/data/effective_dose/neutrons.txt similarity index 100% rename from src/openmc/data/effective_dose/neutrons.txt rename to openmc/data/effective_dose/neutrons.txt diff --git a/src/openmc/data/effective_dose/photons.txt b/openmc/data/effective_dose/photons.txt similarity index 100% rename from src/openmc/data/effective_dose/photons.txt rename to openmc/data/effective_dose/photons.txt diff --git a/src/openmc/data/effective_dose/photons_kerma.txt b/openmc/data/effective_dose/photons_kerma.txt similarity index 100% rename from src/openmc/data/effective_dose/photons_kerma.txt rename to openmc/data/effective_dose/photons_kerma.txt diff --git a/src/openmc/data/effective_dose/positive_muons.txt b/openmc/data/effective_dose/positive_muons.txt similarity index 100% rename from src/openmc/data/effective_dose/positive_muons.txt rename to openmc/data/effective_dose/positive_muons.txt diff --git a/src/openmc/data/effective_dose/positive_pions.txt b/openmc/data/effective_dose/positive_pions.txt similarity index 100% rename from src/openmc/data/effective_dose/positive_pions.txt rename to openmc/data/effective_dose/positive_pions.txt diff --git a/src/openmc/data/effective_dose/positrons.txt b/openmc/data/effective_dose/positrons.txt similarity index 100% rename from src/openmc/data/effective_dose/positrons.txt rename to openmc/data/effective_dose/positrons.txt diff --git a/src/openmc/data/effective_dose/protons.txt b/openmc/data/effective_dose/protons.txt similarity index 100% rename from src/openmc/data/effective_dose/protons.txt rename to openmc/data/effective_dose/protons.txt diff --git a/src/openmc/data/endf.py b/openmc/data/endf.py similarity index 100% rename from src/openmc/data/endf.py rename to openmc/data/endf.py diff --git a/src/openmc/data/energy_distribution.py b/openmc/data/energy_distribution.py similarity index 100% rename from src/openmc/data/energy_distribution.py rename to openmc/data/energy_distribution.py diff --git a/src/openmc/data/fission_energy.py b/openmc/data/fission_energy.py similarity index 100% rename from src/openmc/data/fission_energy.py rename to openmc/data/fission_energy.py diff --git a/src/openmc/data/function.py b/openmc/data/function.py similarity index 100% rename from src/openmc/data/function.py rename to openmc/data/function.py diff --git a/src/openmc/data/grid.py b/openmc/data/grid.py similarity index 100% rename from src/openmc/data/grid.py rename to openmc/data/grid.py diff --git a/src/openmc/data/half_life.json b/openmc/data/half_life.json similarity index 100% rename from src/openmc/data/half_life.json rename to openmc/data/half_life.json diff --git a/src/openmc/data/kalbach_mann.py b/openmc/data/kalbach_mann.py similarity index 100% rename from src/openmc/data/kalbach_mann.py rename to openmc/data/kalbach_mann.py diff --git a/src/openmc/data/laboratory.py b/openmc/data/laboratory.py similarity index 100% rename from src/openmc/data/laboratory.py rename to openmc/data/laboratory.py diff --git a/src/openmc/data/library.py b/openmc/data/library.py similarity index 100% rename from src/openmc/data/library.py rename to openmc/data/library.py diff --git a/src/openmc/data/mass_1.mas20.txt b/openmc/data/mass_1.mas20.txt similarity index 100% rename from src/openmc/data/mass_1.mas20.txt rename to openmc/data/mass_1.mas20.txt diff --git a/src/openmc/data/multipole.py b/openmc/data/multipole.py similarity index 100% rename from src/openmc/data/multipole.py rename to openmc/data/multipole.py diff --git a/src/openmc/data/nbody.py b/openmc/data/nbody.py similarity index 100% rename from src/openmc/data/nbody.py rename to openmc/data/nbody.py diff --git a/src/openmc/data/neutron.py b/openmc/data/neutron.py similarity index 100% rename from src/openmc/data/neutron.py rename to openmc/data/neutron.py diff --git a/src/openmc/data/njoy.py b/openmc/data/njoy.py similarity index 100% rename from src/openmc/data/njoy.py rename to openmc/data/njoy.py diff --git a/src/openmc/data/photon.py b/openmc/data/photon.py similarity index 100% rename from src/openmc/data/photon.py rename to openmc/data/photon.py diff --git a/src/openmc/data/product.py b/openmc/data/product.py similarity index 100% rename from src/openmc/data/product.py rename to openmc/data/product.py diff --git a/src/openmc/data/reaction.py b/openmc/data/reaction.py similarity index 100% rename from src/openmc/data/reaction.py rename to openmc/data/reaction.py diff --git a/src/openmc/data/resonance.py b/openmc/data/resonance.py similarity index 100% rename from src/openmc/data/resonance.py rename to openmc/data/resonance.py diff --git a/src/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py similarity index 100% rename from src/openmc/data/resonance_covariance.py rename to openmc/data/resonance_covariance.py diff --git a/src/openmc/data/thermal.py b/openmc/data/thermal.py similarity index 100% rename from src/openmc/data/thermal.py rename to openmc/data/thermal.py diff --git a/src/openmc/data/thermal_angle_energy.py b/openmc/data/thermal_angle_energy.py similarity index 100% rename from src/openmc/data/thermal_angle_energy.py rename to openmc/data/thermal_angle_energy.py diff --git a/src/openmc/data/uncorrelated.py b/openmc/data/uncorrelated.py similarity index 100% rename from src/openmc/data/uncorrelated.py rename to openmc/data/uncorrelated.py diff --git a/src/openmc/data/urr.py b/openmc/data/urr.py similarity index 100% rename from src/openmc/data/urr.py rename to openmc/data/urr.py diff --git a/src/openmc/deplete/__init__.py b/openmc/deplete/__init__.py similarity index 100% rename from src/openmc/deplete/__init__.py rename to openmc/deplete/__init__.py diff --git a/src/openmc/deplete/_matrix_funcs.py b/openmc/deplete/_matrix_funcs.py similarity index 100% rename from src/openmc/deplete/_matrix_funcs.py rename to openmc/deplete/_matrix_funcs.py diff --git a/src/openmc/deplete/abc.py b/openmc/deplete/abc.py similarity index 100% rename from src/openmc/deplete/abc.py rename to openmc/deplete/abc.py diff --git a/src/openmc/deplete/atom_number.py b/openmc/deplete/atom_number.py similarity index 100% rename from src/openmc/deplete/atom_number.py rename to openmc/deplete/atom_number.py diff --git a/src/openmc/deplete/chain.py b/openmc/deplete/chain.py similarity index 100% rename from src/openmc/deplete/chain.py rename to openmc/deplete/chain.py diff --git a/src/openmc/deplete/coupled_operator.py b/openmc/deplete/coupled_operator.py similarity index 100% rename from src/openmc/deplete/coupled_operator.py rename to openmc/deplete/coupled_operator.py diff --git a/src/openmc/deplete/cram.py b/openmc/deplete/cram.py similarity index 100% rename from src/openmc/deplete/cram.py rename to openmc/deplete/cram.py diff --git a/src/openmc/deplete/helpers.py b/openmc/deplete/helpers.py similarity index 100% rename from src/openmc/deplete/helpers.py rename to openmc/deplete/helpers.py diff --git a/src/openmc/deplete/independent_operator.py b/openmc/deplete/independent_operator.py similarity index 100% rename from src/openmc/deplete/independent_operator.py rename to openmc/deplete/independent_operator.py diff --git a/src/openmc/deplete/integrators.py b/openmc/deplete/integrators.py similarity index 100% rename from src/openmc/deplete/integrators.py rename to openmc/deplete/integrators.py diff --git a/src/openmc/deplete/microxs.py b/openmc/deplete/microxs.py similarity index 100% rename from src/openmc/deplete/microxs.py rename to openmc/deplete/microxs.py diff --git a/src/openmc/deplete/nuclide.py b/openmc/deplete/nuclide.py similarity index 100% rename from src/openmc/deplete/nuclide.py rename to openmc/deplete/nuclide.py diff --git a/src/openmc/deplete/openmc_operator.py b/openmc/deplete/openmc_operator.py similarity index 100% rename from src/openmc/deplete/openmc_operator.py rename to openmc/deplete/openmc_operator.py diff --git a/src/openmc/deplete/pool.py b/openmc/deplete/pool.py similarity index 100% rename from src/openmc/deplete/pool.py rename to openmc/deplete/pool.py diff --git a/src/openmc/deplete/reaction_rates.py b/openmc/deplete/reaction_rates.py similarity index 100% rename from src/openmc/deplete/reaction_rates.py rename to openmc/deplete/reaction_rates.py diff --git a/src/openmc/deplete/results.py b/openmc/deplete/results.py similarity index 100% rename from src/openmc/deplete/results.py rename to openmc/deplete/results.py diff --git a/src/openmc/deplete/stepresult.py b/openmc/deplete/stepresult.py similarity index 100% rename from src/openmc/deplete/stepresult.py rename to openmc/deplete/stepresult.py diff --git a/src/openmc/deplete/transfer_rates.py b/openmc/deplete/transfer_rates.py similarity index 100% rename from src/openmc/deplete/transfer_rates.py rename to openmc/deplete/transfer_rates.py diff --git a/src/openmc/dummy_comm.py b/openmc/dummy_comm.py similarity index 100% rename from src/openmc/dummy_comm.py rename to openmc/dummy_comm.py diff --git a/src/openmc/element.py b/openmc/element.py similarity index 100% rename from src/openmc/element.py rename to openmc/element.py diff --git a/src/openmc/examples.py b/openmc/examples.py similarity index 100% rename from src/openmc/examples.py rename to openmc/examples.py diff --git a/src/openmc/exceptions.py b/openmc/exceptions.py similarity index 100% rename from src/openmc/exceptions.py rename to openmc/exceptions.py diff --git a/src/openmc/executor.py b/openmc/executor.py similarity index 100% rename from src/openmc/executor.py rename to openmc/executor.py diff --git a/src/openmc/filter.py b/openmc/filter.py similarity index 100% rename from src/openmc/filter.py rename to openmc/filter.py diff --git a/src/openmc/filter_expansion.py b/openmc/filter_expansion.py similarity index 100% rename from src/openmc/filter_expansion.py rename to openmc/filter_expansion.py diff --git a/src/openmc/geometry.py b/openmc/geometry.py similarity index 100% rename from src/openmc/geometry.py rename to openmc/geometry.py diff --git a/src/openmc/lattice.py b/openmc/lattice.py similarity index 100% rename from src/openmc/lattice.py rename to openmc/lattice.py diff --git a/src/openmc/lib/__init__.py b/openmc/lib/__init__.py similarity index 100% rename from src/openmc/lib/__init__.py rename to openmc/lib/__init__.py diff --git a/src/openmc/lib/cell.py b/openmc/lib/cell.py similarity index 100% rename from src/openmc/lib/cell.py rename to openmc/lib/cell.py diff --git a/src/openmc/lib/core.py b/openmc/lib/core.py similarity index 100% rename from src/openmc/lib/core.py rename to openmc/lib/core.py diff --git a/src/openmc/lib/error.py b/openmc/lib/error.py similarity index 100% rename from src/openmc/lib/error.py rename to openmc/lib/error.py diff --git a/src/openmc/lib/filter.py b/openmc/lib/filter.py similarity index 100% rename from src/openmc/lib/filter.py rename to openmc/lib/filter.py diff --git a/src/openmc/lib/material.py b/openmc/lib/material.py similarity index 100% rename from src/openmc/lib/material.py rename to openmc/lib/material.py diff --git a/src/openmc/lib/math.py b/openmc/lib/math.py similarity index 100% rename from src/openmc/lib/math.py rename to openmc/lib/math.py diff --git a/src/openmc/lib/mesh.py b/openmc/lib/mesh.py similarity index 100% rename from src/openmc/lib/mesh.py rename to openmc/lib/mesh.py diff --git a/src/openmc/lib/nuclide.py b/openmc/lib/nuclide.py similarity index 100% rename from src/openmc/lib/nuclide.py rename to openmc/lib/nuclide.py diff --git a/src/openmc/lib/plot.py b/openmc/lib/plot.py similarity index 100% rename from src/openmc/lib/plot.py rename to openmc/lib/plot.py diff --git a/src/openmc/lib/settings.py b/openmc/lib/settings.py similarity index 100% rename from src/openmc/lib/settings.py rename to openmc/lib/settings.py diff --git a/src/openmc/lib/tally.py b/openmc/lib/tally.py similarity index 100% rename from src/openmc/lib/tally.py rename to openmc/lib/tally.py diff --git a/src/openmc/lib/weight_windows.py b/openmc/lib/weight_windows.py similarity index 100% rename from src/openmc/lib/weight_windows.py rename to openmc/lib/weight_windows.py diff --git a/src/openmc/macroscopic.py b/openmc/macroscopic.py similarity index 100% rename from src/openmc/macroscopic.py rename to openmc/macroscopic.py diff --git a/src/openmc/material.py b/openmc/material.py similarity index 100% rename from src/openmc/material.py rename to openmc/material.py diff --git a/src/openmc/mesh.py b/openmc/mesh.py similarity index 100% rename from src/openmc/mesh.py rename to openmc/mesh.py diff --git a/src/openmc/mgxs/__init__.py b/openmc/mgxs/__init__.py similarity index 100% rename from src/openmc/mgxs/__init__.py rename to openmc/mgxs/__init__.py diff --git a/src/openmc/mgxs/groups.py b/openmc/mgxs/groups.py similarity index 100% rename from src/openmc/mgxs/groups.py rename to openmc/mgxs/groups.py diff --git a/src/openmc/mgxs/library.py b/openmc/mgxs/library.py similarity index 100% rename from src/openmc/mgxs/library.py rename to openmc/mgxs/library.py diff --git a/src/openmc/mgxs/mdgxs.py b/openmc/mgxs/mdgxs.py similarity index 100% rename from src/openmc/mgxs/mdgxs.py rename to openmc/mgxs/mdgxs.py diff --git a/src/openmc/mgxs/mgxs.py b/openmc/mgxs/mgxs.py similarity index 100% rename from src/openmc/mgxs/mgxs.py rename to openmc/mgxs/mgxs.py diff --git a/src/openmc/mgxs_library.py b/openmc/mgxs_library.py similarity index 100% rename from src/openmc/mgxs_library.py rename to openmc/mgxs_library.py diff --git a/src/openmc/mixin.py b/openmc/mixin.py similarity index 100% rename from src/openmc/mixin.py rename to openmc/mixin.py diff --git a/src/openmc/model/__init__.py b/openmc/model/__init__.py similarity index 100% rename from src/openmc/model/__init__.py rename to openmc/model/__init__.py diff --git a/src/openmc/model/funcs.py b/openmc/model/funcs.py similarity index 100% rename from src/openmc/model/funcs.py rename to openmc/model/funcs.py diff --git a/src/openmc/model/model.py b/openmc/model/model.py similarity index 100% rename from src/openmc/model/model.py rename to openmc/model/model.py diff --git a/src/openmc/model/surface_composite.py b/openmc/model/surface_composite.py similarity index 100% rename from src/openmc/model/surface_composite.py rename to openmc/model/surface_composite.py diff --git a/src/openmc/model/triso.py b/openmc/model/triso.py similarity index 100% rename from src/openmc/model/triso.py rename to openmc/model/triso.py diff --git a/src/openmc/mpi.py b/openmc/mpi.py similarity index 100% rename from src/openmc/mpi.py rename to openmc/mpi.py diff --git a/src/openmc/nuclide.py b/openmc/nuclide.py similarity index 100% rename from src/openmc/nuclide.py rename to openmc/nuclide.py diff --git a/src/openmc/openmc_exec.py b/openmc/openmc_exec.py similarity index 100% rename from src/openmc/openmc_exec.py rename to openmc/openmc_exec.py diff --git a/src/openmc/openmoc_compatible.py b/openmc/openmoc_compatible.py similarity index 100% rename from src/openmc/openmoc_compatible.py rename to openmc/openmoc_compatible.py diff --git a/src/openmc/particle_restart.py b/openmc/particle_restart.py similarity index 100% rename from src/openmc/particle_restart.py rename to openmc/particle_restart.py diff --git a/src/openmc/plots.py b/openmc/plots.py similarity index 100% rename from src/openmc/plots.py rename to openmc/plots.py diff --git a/src/openmc/plotter.py b/openmc/plotter.py similarity index 100% rename from src/openmc/plotter.py rename to openmc/plotter.py diff --git a/src/openmc/polynomial.py b/openmc/polynomial.py similarity index 100% rename from src/openmc/polynomial.py rename to openmc/polynomial.py diff --git a/src/openmc/region.py b/openmc/region.py similarity index 100% rename from src/openmc/region.py rename to openmc/region.py diff --git a/src/openmc/search.py b/openmc/search.py similarity index 100% rename from src/openmc/search.py rename to openmc/search.py diff --git a/src/openmc/settings.py b/openmc/settings.py similarity index 100% rename from src/openmc/settings.py rename to openmc/settings.py diff --git a/src/openmc/source.py b/openmc/source.py similarity index 100% rename from src/openmc/source.py rename to openmc/source.py diff --git a/src/openmc/statepoint.py b/openmc/statepoint.py similarity index 100% rename from src/openmc/statepoint.py rename to openmc/statepoint.py diff --git a/src/openmc/stats/__init__.py b/openmc/stats/__init__.py similarity index 100% rename from src/openmc/stats/__init__.py rename to openmc/stats/__init__.py diff --git a/src/openmc/stats/multivariate.py b/openmc/stats/multivariate.py similarity index 100% rename from src/openmc/stats/multivariate.py rename to openmc/stats/multivariate.py diff --git a/src/openmc/stats/univariate.py b/openmc/stats/univariate.py similarity index 100% rename from src/openmc/stats/univariate.py rename to openmc/stats/univariate.py diff --git a/src/openmc/summary.py b/openmc/summary.py similarity index 100% rename from src/openmc/summary.py rename to openmc/summary.py diff --git a/src/openmc/surface.py b/openmc/surface.py similarity index 100% rename from src/openmc/surface.py rename to openmc/surface.py diff --git a/src/openmc/tallies.py b/openmc/tallies.py similarity index 100% rename from src/openmc/tallies.py rename to openmc/tallies.py diff --git a/src/openmc/tally_derivative.py b/openmc/tally_derivative.py similarity index 100% rename from src/openmc/tally_derivative.py rename to openmc/tally_derivative.py diff --git a/src/openmc/tracks.py b/openmc/tracks.py similarity index 100% rename from src/openmc/tracks.py rename to openmc/tracks.py diff --git a/src/openmc/trigger.py b/openmc/trigger.py similarity index 100% rename from src/openmc/trigger.py rename to openmc/trigger.py diff --git a/src/openmc/universe.py b/openmc/universe.py similarity index 100% rename from src/openmc/universe.py rename to openmc/universe.py diff --git a/src/openmc/utility_funcs.py b/openmc/utility_funcs.py similarity index 100% rename from src/openmc/utility_funcs.py rename to openmc/utility_funcs.py diff --git a/src/openmc/volume.py b/openmc/volume.py similarity index 100% rename from src/openmc/volume.py rename to openmc/volume.py diff --git a/src/openmc/weight_windows.py b/openmc/weight_windows.py similarity index 100% rename from src/openmc/weight_windows.py rename to openmc/weight_windows.py From d0740ce41710f2b9456f5fb2cd8b025fad3a3626 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Thu, 17 Oct 2024 20:26:48 +0600 Subject: [PATCH 61/76] move openmc to src again --- {openmc => src/openmc}/__init__.py | 0 {openmc => src/openmc}/_xml.py | 0 {openmc => src/openmc}/arithmetic.py | 0 {openmc => src/openmc}/bounding_box.py | 0 {openmc => src/openmc}/cell.py | 0 {openmc => src/openmc}/checkvalue.py | 0 {openmc => src/openmc}/cmfd.py | 0 {openmc => src/openmc}/config.py | 0 {openmc => src/openmc}/data/BREMX.DAT | 0 {openmc => src/openmc}/data/__init__.py | 0 {openmc => src/openmc}/data/ace.py | 0 {openmc => src/openmc}/data/angle_distribution.py | 0 {openmc => src/openmc}/data/angle_energy.py | 0 {openmc => src/openmc}/data/correlated.py | 0 {openmc => src/openmc}/data/data.py | 0 {openmc => src/openmc}/data/decay.py | 0 {openmc => src/openmc}/data/effective_dose/__init__.py | 0 {openmc => src/openmc}/data/effective_dose/dose.py | 0 {openmc => src/openmc}/data/effective_dose/icrp116/electrons.txt | 0 .../openmc}/data/effective_dose/icrp116/helium_ions.txt | 0 .../openmc}/data/effective_dose/icrp116/negative_muons.txt | 0 .../openmc}/data/effective_dose/icrp116/negative_pions.txt | 0 {openmc => src/openmc}/data/effective_dose/icrp116/neutrons.txt | 0 {openmc => src/openmc}/data/effective_dose/icrp116/photons.txt | 0 .../openmc}/data/effective_dose/icrp116/photons_kerma.txt | 0 .../openmc}/data/effective_dose/icrp116/positive_muons.txt | 0 .../openmc}/data/effective_dose/icrp116/positive_pions.txt | 0 {openmc => src/openmc}/data/effective_dose/icrp116/positrons.txt | 0 {openmc => src/openmc}/data/effective_dose/icrp116/protons.txt | 0 .../data/effective_dose/icrp74/generate_photon_effective_dose.py | 0 {openmc => src/openmc}/data/effective_dose/icrp74/neutrons.txt | 0 {openmc => src/openmc}/data/effective_dose/icrp74/photons.txt | 0 {openmc => src/openmc}/data/endf.py | 0 {openmc => src/openmc}/data/energy_distribution.py | 0 {openmc => src/openmc}/data/fission_energy.py | 0 {openmc => src/openmc}/data/function.py | 0 {openmc => src/openmc}/data/grid.py | 0 {openmc => src/openmc}/data/half_life.json | 0 {openmc => src/openmc}/data/kalbach_mann.py | 0 {openmc => src/openmc}/data/laboratory.py | 0 {openmc => src/openmc}/data/library.py | 0 {openmc => src/openmc}/data/mass_1.mas20.txt | 0 {openmc => src/openmc}/data/multipole.py | 0 {openmc => src/openmc}/data/nbody.py | 0 {openmc => src/openmc}/data/neutron.py | 0 {openmc => src/openmc}/data/njoy.py | 0 {openmc => src/openmc}/data/photon.py | 0 {openmc => src/openmc}/data/product.py | 0 {openmc => src/openmc}/data/reaction.py | 0 {openmc => src/openmc}/data/resonance.py | 0 {openmc => src/openmc}/data/resonance_covariance.py | 0 {openmc => src/openmc}/data/thermal.py | 0 {openmc => src/openmc}/data/thermal_angle_energy.py | 0 {openmc => src/openmc}/data/uncorrelated.py | 0 {openmc => src/openmc}/data/urr.py | 0 {openmc => src/openmc}/deplete/__init__.py | 0 {openmc => src/openmc}/deplete/_matrix_funcs.py | 0 {openmc => src/openmc}/deplete/abc.py | 0 {openmc => src/openmc}/deplete/atom_number.py | 0 {openmc => src/openmc}/deplete/chain.py | 0 {openmc => src/openmc}/deplete/coupled_operator.py | 0 {openmc => src/openmc}/deplete/cram.py | 0 {openmc => src/openmc}/deplete/helpers.py | 0 {openmc => src/openmc}/deplete/independent_operator.py | 0 {openmc => src/openmc}/deplete/integrators.py | 0 {openmc => src/openmc}/deplete/microxs.py | 0 {openmc => src/openmc}/deplete/nuclide.py | 0 {openmc => src/openmc}/deplete/openmc_operator.py | 0 {openmc => src/openmc}/deplete/pool.py | 0 {openmc => src/openmc}/deplete/reaction_rates.py | 0 {openmc => src/openmc}/deplete/results.py | 0 {openmc => src/openmc}/deplete/stepresult.py | 0 {openmc => src/openmc}/deplete/transfer_rates.py | 0 {openmc => src/openmc}/dummy_comm.py | 0 {openmc => src/openmc}/element.py | 0 {openmc => src/openmc}/examples.py | 0 {openmc => src/openmc}/exceptions.py | 0 {openmc => src/openmc}/executor.py | 0 {openmc => src/openmc}/filter.py | 0 {openmc => src/openmc}/filter_expansion.py | 0 {openmc => src/openmc}/geometry.py | 0 {openmc => src/openmc}/lattice.py | 0 {openmc => src/openmc}/lib/__init__.py | 0 {openmc => src/openmc}/lib/cell.py | 0 {openmc => src/openmc}/lib/core.py | 0 {openmc => src/openmc}/lib/error.py | 0 {openmc => src/openmc}/lib/filter.py | 0 {openmc => src/openmc}/lib/material.py | 0 {openmc => src/openmc}/lib/math.py | 0 {openmc => src/openmc}/lib/mesh.py | 0 {openmc => src/openmc}/lib/nuclide.py | 0 {openmc => src/openmc}/lib/plot.py | 0 {openmc => src/openmc}/lib/settings.py | 0 {openmc => src/openmc}/lib/tally.py | 0 {openmc => src/openmc}/lib/weight_windows.py | 0 {openmc => src/openmc}/macroscopic.py | 0 {openmc => src/openmc}/material.py | 0 {openmc => src/openmc}/mesh.py | 0 {openmc => src/openmc}/mgxs/__init__.py | 0 {openmc => src/openmc}/mgxs/groups.py | 0 {openmc => src/openmc}/mgxs/library.py | 0 {openmc => src/openmc}/mgxs/mdgxs.py | 0 {openmc => src/openmc}/mgxs/mgxs.py | 0 {openmc => src/openmc}/mgxs_library.py | 0 {openmc => src/openmc}/mixin.py | 0 {openmc => src/openmc}/model/__init__.py | 0 {openmc => src/openmc}/model/funcs.py | 0 {openmc => src/openmc}/model/model.py | 0 {openmc => src/openmc}/model/surface_composite.py | 0 {openmc => src/openmc}/model/triso.py | 0 {openmc => src/openmc}/mpi.py | 0 {openmc => src/openmc}/nuclide.py | 0 {openmc => src/openmc}/openmc_exec.py | 0 {openmc => src/openmc}/openmoc_compatible.py | 0 {openmc => src/openmc}/particle_restart.py | 0 {openmc => src/openmc}/plots.py | 0 {openmc => src/openmc}/plotter.py | 0 {openmc => src/openmc}/polynomial.py | 0 {openmc => src/openmc}/region.py | 0 {openmc => src/openmc}/search.py | 0 {openmc => src/openmc}/settings.py | 0 {openmc => src/openmc}/source.py | 0 {openmc => src/openmc}/statepoint.py | 0 {openmc => src/openmc}/stats/__init__.py | 0 {openmc => src/openmc}/stats/multivariate.py | 0 {openmc => src/openmc}/stats/univariate.py | 0 {openmc => src/openmc}/summary.py | 0 {openmc => src/openmc}/surface.py | 0 {openmc => src/openmc}/tallies.py | 0 {openmc => src/openmc}/tally_derivative.py | 0 {openmc => src/openmc}/tracks.py | 0 {openmc => src/openmc}/trigger.py | 0 {openmc => src/openmc}/universe.py | 0 {openmc => src/openmc}/utility_funcs.py | 0 {openmc => src/openmc}/volume.py | 0 {openmc => src/openmc}/weight_windows.py | 0 136 files changed, 0 insertions(+), 0 deletions(-) rename {openmc => src/openmc}/__init__.py (100%) rename {openmc => src/openmc}/_xml.py (100%) rename {openmc => src/openmc}/arithmetic.py (100%) rename {openmc => src/openmc}/bounding_box.py (100%) rename {openmc => src/openmc}/cell.py (100%) rename {openmc => src/openmc}/checkvalue.py (100%) rename {openmc => src/openmc}/cmfd.py (100%) rename {openmc => src/openmc}/config.py (100%) rename {openmc => src/openmc}/data/BREMX.DAT (100%) rename {openmc => src/openmc}/data/__init__.py (100%) rename {openmc => src/openmc}/data/ace.py (100%) rename {openmc => src/openmc}/data/angle_distribution.py (100%) rename {openmc => src/openmc}/data/angle_energy.py (100%) rename {openmc => src/openmc}/data/correlated.py (100%) rename {openmc => src/openmc}/data/data.py (100%) rename {openmc => src/openmc}/data/decay.py (100%) rename {openmc => src/openmc}/data/effective_dose/__init__.py (100%) rename {openmc => src/openmc}/data/effective_dose/dose.py (100%) rename {openmc => src/openmc}/data/effective_dose/icrp116/electrons.txt (100%) rename {openmc => src/openmc}/data/effective_dose/icrp116/helium_ions.txt (100%) rename {openmc => src/openmc}/data/effective_dose/icrp116/negative_muons.txt (100%) rename {openmc => src/openmc}/data/effective_dose/icrp116/negative_pions.txt (100%) rename {openmc => src/openmc}/data/effective_dose/icrp116/neutrons.txt (100%) rename {openmc => src/openmc}/data/effective_dose/icrp116/photons.txt (100%) rename {openmc => src/openmc}/data/effective_dose/icrp116/photons_kerma.txt (100%) rename {openmc => src/openmc}/data/effective_dose/icrp116/positive_muons.txt (100%) rename {openmc => src/openmc}/data/effective_dose/icrp116/positive_pions.txt (100%) rename {openmc => src/openmc}/data/effective_dose/icrp116/positrons.txt (100%) rename {openmc => src/openmc}/data/effective_dose/icrp116/protons.txt (100%) rename {openmc => src/openmc}/data/effective_dose/icrp74/generate_photon_effective_dose.py (100%) rename {openmc => src/openmc}/data/effective_dose/icrp74/neutrons.txt (100%) rename {openmc => src/openmc}/data/effective_dose/icrp74/photons.txt (100%) rename {openmc => src/openmc}/data/endf.py (100%) rename {openmc => src/openmc}/data/energy_distribution.py (100%) rename {openmc => src/openmc}/data/fission_energy.py (100%) rename {openmc => src/openmc}/data/function.py (100%) rename {openmc => src/openmc}/data/grid.py (100%) rename {openmc => src/openmc}/data/half_life.json (100%) rename {openmc => src/openmc}/data/kalbach_mann.py (100%) rename {openmc => src/openmc}/data/laboratory.py (100%) rename {openmc => src/openmc}/data/library.py (100%) rename {openmc => src/openmc}/data/mass_1.mas20.txt (100%) rename {openmc => src/openmc}/data/multipole.py (100%) rename {openmc => src/openmc}/data/nbody.py (100%) rename {openmc => src/openmc}/data/neutron.py (100%) rename {openmc => src/openmc}/data/njoy.py (100%) rename {openmc => src/openmc}/data/photon.py (100%) rename {openmc => src/openmc}/data/product.py (100%) rename {openmc => src/openmc}/data/reaction.py (100%) rename {openmc => src/openmc}/data/resonance.py (100%) rename {openmc => src/openmc}/data/resonance_covariance.py (100%) rename {openmc => src/openmc}/data/thermal.py (100%) rename {openmc => src/openmc}/data/thermal_angle_energy.py (100%) rename {openmc => src/openmc}/data/uncorrelated.py (100%) rename {openmc => src/openmc}/data/urr.py (100%) rename {openmc => src/openmc}/deplete/__init__.py (100%) rename {openmc => src/openmc}/deplete/_matrix_funcs.py (100%) rename {openmc => src/openmc}/deplete/abc.py (100%) rename {openmc => src/openmc}/deplete/atom_number.py (100%) rename {openmc => src/openmc}/deplete/chain.py (100%) rename {openmc => src/openmc}/deplete/coupled_operator.py (100%) rename {openmc => src/openmc}/deplete/cram.py (100%) rename {openmc => src/openmc}/deplete/helpers.py (100%) rename {openmc => src/openmc}/deplete/independent_operator.py (100%) rename {openmc => src/openmc}/deplete/integrators.py (100%) rename {openmc => src/openmc}/deplete/microxs.py (100%) rename {openmc => src/openmc}/deplete/nuclide.py (100%) rename {openmc => src/openmc}/deplete/openmc_operator.py (100%) rename {openmc => src/openmc}/deplete/pool.py (100%) rename {openmc => src/openmc}/deplete/reaction_rates.py (100%) rename {openmc => src/openmc}/deplete/results.py (100%) rename {openmc => src/openmc}/deplete/stepresult.py (100%) rename {openmc => src/openmc}/deplete/transfer_rates.py (100%) rename {openmc => src/openmc}/dummy_comm.py (100%) rename {openmc => src/openmc}/element.py (100%) rename {openmc => src/openmc}/examples.py (100%) rename {openmc => src/openmc}/exceptions.py (100%) rename {openmc => src/openmc}/executor.py (100%) rename {openmc => src/openmc}/filter.py (100%) rename {openmc => src/openmc}/filter_expansion.py (100%) rename {openmc => src/openmc}/geometry.py (100%) rename {openmc => src/openmc}/lattice.py (100%) rename {openmc => src/openmc}/lib/__init__.py (100%) rename {openmc => src/openmc}/lib/cell.py (100%) rename {openmc => src/openmc}/lib/core.py (100%) rename {openmc => src/openmc}/lib/error.py (100%) rename {openmc => src/openmc}/lib/filter.py (100%) rename {openmc => src/openmc}/lib/material.py (100%) rename {openmc => src/openmc}/lib/math.py (100%) rename {openmc => src/openmc}/lib/mesh.py (100%) rename {openmc => src/openmc}/lib/nuclide.py (100%) rename {openmc => src/openmc}/lib/plot.py (100%) rename {openmc => src/openmc}/lib/settings.py (100%) rename {openmc => src/openmc}/lib/tally.py (100%) rename {openmc => src/openmc}/lib/weight_windows.py (100%) rename {openmc => src/openmc}/macroscopic.py (100%) rename {openmc => src/openmc}/material.py (100%) rename {openmc => src/openmc}/mesh.py (100%) rename {openmc => src/openmc}/mgxs/__init__.py (100%) rename {openmc => src/openmc}/mgxs/groups.py (100%) rename {openmc => src/openmc}/mgxs/library.py (100%) rename {openmc => src/openmc}/mgxs/mdgxs.py (100%) rename {openmc => src/openmc}/mgxs/mgxs.py (100%) rename {openmc => src/openmc}/mgxs_library.py (100%) rename {openmc => src/openmc}/mixin.py (100%) rename {openmc => src/openmc}/model/__init__.py (100%) rename {openmc => src/openmc}/model/funcs.py (100%) rename {openmc => src/openmc}/model/model.py (100%) rename {openmc => src/openmc}/model/surface_composite.py (100%) rename {openmc => src/openmc}/model/triso.py (100%) rename {openmc => src/openmc}/mpi.py (100%) rename {openmc => src/openmc}/nuclide.py (100%) rename {openmc => src/openmc}/openmc_exec.py (100%) rename {openmc => src/openmc}/openmoc_compatible.py (100%) rename {openmc => src/openmc}/particle_restart.py (100%) rename {openmc => src/openmc}/plots.py (100%) rename {openmc => src/openmc}/plotter.py (100%) rename {openmc => src/openmc}/polynomial.py (100%) rename {openmc => src/openmc}/region.py (100%) rename {openmc => src/openmc}/search.py (100%) rename {openmc => src/openmc}/settings.py (100%) rename {openmc => src/openmc}/source.py (100%) rename {openmc => src/openmc}/statepoint.py (100%) rename {openmc => src/openmc}/stats/__init__.py (100%) rename {openmc => src/openmc}/stats/multivariate.py (100%) rename {openmc => src/openmc}/stats/univariate.py (100%) rename {openmc => src/openmc}/summary.py (100%) rename {openmc => src/openmc}/surface.py (100%) rename {openmc => src/openmc}/tallies.py (100%) rename {openmc => src/openmc}/tally_derivative.py (100%) rename {openmc => src/openmc}/tracks.py (100%) rename {openmc => src/openmc}/trigger.py (100%) rename {openmc => src/openmc}/universe.py (100%) rename {openmc => src/openmc}/utility_funcs.py (100%) rename {openmc => src/openmc}/volume.py (100%) rename {openmc => src/openmc}/weight_windows.py (100%) diff --git a/openmc/__init__.py b/src/openmc/__init__.py similarity index 100% rename from openmc/__init__.py rename to src/openmc/__init__.py diff --git a/openmc/_xml.py b/src/openmc/_xml.py similarity index 100% rename from openmc/_xml.py rename to src/openmc/_xml.py diff --git a/openmc/arithmetic.py b/src/openmc/arithmetic.py similarity index 100% rename from openmc/arithmetic.py rename to src/openmc/arithmetic.py diff --git a/openmc/bounding_box.py b/src/openmc/bounding_box.py similarity index 100% rename from openmc/bounding_box.py rename to src/openmc/bounding_box.py diff --git a/openmc/cell.py b/src/openmc/cell.py similarity index 100% rename from openmc/cell.py rename to src/openmc/cell.py diff --git a/openmc/checkvalue.py b/src/openmc/checkvalue.py similarity index 100% rename from openmc/checkvalue.py rename to src/openmc/checkvalue.py diff --git a/openmc/cmfd.py b/src/openmc/cmfd.py similarity index 100% rename from openmc/cmfd.py rename to src/openmc/cmfd.py diff --git a/openmc/config.py b/src/openmc/config.py similarity index 100% rename from openmc/config.py rename to src/openmc/config.py diff --git a/openmc/data/BREMX.DAT b/src/openmc/data/BREMX.DAT similarity index 100% rename from openmc/data/BREMX.DAT rename to src/openmc/data/BREMX.DAT diff --git a/openmc/data/__init__.py b/src/openmc/data/__init__.py similarity index 100% rename from openmc/data/__init__.py rename to src/openmc/data/__init__.py diff --git a/openmc/data/ace.py b/src/openmc/data/ace.py similarity index 100% rename from openmc/data/ace.py rename to src/openmc/data/ace.py diff --git a/openmc/data/angle_distribution.py b/src/openmc/data/angle_distribution.py similarity index 100% rename from openmc/data/angle_distribution.py rename to src/openmc/data/angle_distribution.py diff --git a/openmc/data/angle_energy.py b/src/openmc/data/angle_energy.py similarity index 100% rename from openmc/data/angle_energy.py rename to src/openmc/data/angle_energy.py diff --git a/openmc/data/correlated.py b/src/openmc/data/correlated.py similarity index 100% rename from openmc/data/correlated.py rename to src/openmc/data/correlated.py diff --git a/openmc/data/data.py b/src/openmc/data/data.py similarity index 100% rename from openmc/data/data.py rename to src/openmc/data/data.py diff --git a/openmc/data/decay.py b/src/openmc/data/decay.py similarity index 100% rename from openmc/data/decay.py rename to src/openmc/data/decay.py diff --git a/openmc/data/effective_dose/__init__.py b/src/openmc/data/effective_dose/__init__.py similarity index 100% rename from openmc/data/effective_dose/__init__.py rename to src/openmc/data/effective_dose/__init__.py diff --git a/openmc/data/effective_dose/dose.py b/src/openmc/data/effective_dose/dose.py similarity index 100% rename from openmc/data/effective_dose/dose.py rename to src/openmc/data/effective_dose/dose.py diff --git a/openmc/data/effective_dose/icrp116/electrons.txt b/src/openmc/data/effective_dose/icrp116/electrons.txt similarity index 100% rename from openmc/data/effective_dose/icrp116/electrons.txt rename to src/openmc/data/effective_dose/icrp116/electrons.txt diff --git a/openmc/data/effective_dose/icrp116/helium_ions.txt b/src/openmc/data/effective_dose/icrp116/helium_ions.txt similarity index 100% rename from openmc/data/effective_dose/icrp116/helium_ions.txt rename to src/openmc/data/effective_dose/icrp116/helium_ions.txt diff --git a/openmc/data/effective_dose/icrp116/negative_muons.txt b/src/openmc/data/effective_dose/icrp116/negative_muons.txt similarity index 100% rename from openmc/data/effective_dose/icrp116/negative_muons.txt rename to src/openmc/data/effective_dose/icrp116/negative_muons.txt diff --git a/openmc/data/effective_dose/icrp116/negative_pions.txt b/src/openmc/data/effective_dose/icrp116/negative_pions.txt similarity index 100% rename from openmc/data/effective_dose/icrp116/negative_pions.txt rename to src/openmc/data/effective_dose/icrp116/negative_pions.txt diff --git a/openmc/data/effective_dose/icrp116/neutrons.txt b/src/openmc/data/effective_dose/icrp116/neutrons.txt similarity index 100% rename from openmc/data/effective_dose/icrp116/neutrons.txt rename to src/openmc/data/effective_dose/icrp116/neutrons.txt diff --git a/openmc/data/effective_dose/icrp116/photons.txt b/src/openmc/data/effective_dose/icrp116/photons.txt similarity index 100% rename from openmc/data/effective_dose/icrp116/photons.txt rename to src/openmc/data/effective_dose/icrp116/photons.txt diff --git a/openmc/data/effective_dose/icrp116/photons_kerma.txt b/src/openmc/data/effective_dose/icrp116/photons_kerma.txt similarity index 100% rename from openmc/data/effective_dose/icrp116/photons_kerma.txt rename to src/openmc/data/effective_dose/icrp116/photons_kerma.txt diff --git a/openmc/data/effective_dose/icrp116/positive_muons.txt b/src/openmc/data/effective_dose/icrp116/positive_muons.txt similarity index 100% rename from openmc/data/effective_dose/icrp116/positive_muons.txt rename to src/openmc/data/effective_dose/icrp116/positive_muons.txt diff --git a/openmc/data/effective_dose/icrp116/positive_pions.txt b/src/openmc/data/effective_dose/icrp116/positive_pions.txt similarity index 100% rename from openmc/data/effective_dose/icrp116/positive_pions.txt rename to src/openmc/data/effective_dose/icrp116/positive_pions.txt diff --git a/openmc/data/effective_dose/icrp116/positrons.txt b/src/openmc/data/effective_dose/icrp116/positrons.txt similarity index 100% rename from openmc/data/effective_dose/icrp116/positrons.txt rename to src/openmc/data/effective_dose/icrp116/positrons.txt diff --git a/openmc/data/effective_dose/icrp116/protons.txt b/src/openmc/data/effective_dose/icrp116/protons.txt similarity index 100% rename from openmc/data/effective_dose/icrp116/protons.txt rename to src/openmc/data/effective_dose/icrp116/protons.txt diff --git a/openmc/data/effective_dose/icrp74/generate_photon_effective_dose.py b/src/openmc/data/effective_dose/icrp74/generate_photon_effective_dose.py similarity index 100% rename from openmc/data/effective_dose/icrp74/generate_photon_effective_dose.py rename to src/openmc/data/effective_dose/icrp74/generate_photon_effective_dose.py diff --git a/openmc/data/effective_dose/icrp74/neutrons.txt b/src/openmc/data/effective_dose/icrp74/neutrons.txt similarity index 100% rename from openmc/data/effective_dose/icrp74/neutrons.txt rename to src/openmc/data/effective_dose/icrp74/neutrons.txt diff --git a/openmc/data/effective_dose/icrp74/photons.txt b/src/openmc/data/effective_dose/icrp74/photons.txt similarity index 100% rename from openmc/data/effective_dose/icrp74/photons.txt rename to src/openmc/data/effective_dose/icrp74/photons.txt diff --git a/openmc/data/endf.py b/src/openmc/data/endf.py similarity index 100% rename from openmc/data/endf.py rename to src/openmc/data/endf.py diff --git a/openmc/data/energy_distribution.py b/src/openmc/data/energy_distribution.py similarity index 100% rename from openmc/data/energy_distribution.py rename to src/openmc/data/energy_distribution.py diff --git a/openmc/data/fission_energy.py b/src/openmc/data/fission_energy.py similarity index 100% rename from openmc/data/fission_energy.py rename to src/openmc/data/fission_energy.py diff --git a/openmc/data/function.py b/src/openmc/data/function.py similarity index 100% rename from openmc/data/function.py rename to src/openmc/data/function.py diff --git a/openmc/data/grid.py b/src/openmc/data/grid.py similarity index 100% rename from openmc/data/grid.py rename to src/openmc/data/grid.py diff --git a/openmc/data/half_life.json b/src/openmc/data/half_life.json similarity index 100% rename from openmc/data/half_life.json rename to src/openmc/data/half_life.json diff --git a/openmc/data/kalbach_mann.py b/src/openmc/data/kalbach_mann.py similarity index 100% rename from openmc/data/kalbach_mann.py rename to src/openmc/data/kalbach_mann.py diff --git a/openmc/data/laboratory.py b/src/openmc/data/laboratory.py similarity index 100% rename from openmc/data/laboratory.py rename to src/openmc/data/laboratory.py diff --git a/openmc/data/library.py b/src/openmc/data/library.py similarity index 100% rename from openmc/data/library.py rename to src/openmc/data/library.py diff --git a/openmc/data/mass_1.mas20.txt b/src/openmc/data/mass_1.mas20.txt similarity index 100% rename from openmc/data/mass_1.mas20.txt rename to src/openmc/data/mass_1.mas20.txt diff --git a/openmc/data/multipole.py b/src/openmc/data/multipole.py similarity index 100% rename from openmc/data/multipole.py rename to src/openmc/data/multipole.py diff --git a/openmc/data/nbody.py b/src/openmc/data/nbody.py similarity index 100% rename from openmc/data/nbody.py rename to src/openmc/data/nbody.py diff --git a/openmc/data/neutron.py b/src/openmc/data/neutron.py similarity index 100% rename from openmc/data/neutron.py rename to src/openmc/data/neutron.py diff --git a/openmc/data/njoy.py b/src/openmc/data/njoy.py similarity index 100% rename from openmc/data/njoy.py rename to src/openmc/data/njoy.py diff --git a/openmc/data/photon.py b/src/openmc/data/photon.py similarity index 100% rename from openmc/data/photon.py rename to src/openmc/data/photon.py diff --git a/openmc/data/product.py b/src/openmc/data/product.py similarity index 100% rename from openmc/data/product.py rename to src/openmc/data/product.py diff --git a/openmc/data/reaction.py b/src/openmc/data/reaction.py similarity index 100% rename from openmc/data/reaction.py rename to src/openmc/data/reaction.py diff --git a/openmc/data/resonance.py b/src/openmc/data/resonance.py similarity index 100% rename from openmc/data/resonance.py rename to src/openmc/data/resonance.py diff --git a/openmc/data/resonance_covariance.py b/src/openmc/data/resonance_covariance.py similarity index 100% rename from openmc/data/resonance_covariance.py rename to src/openmc/data/resonance_covariance.py diff --git a/openmc/data/thermal.py b/src/openmc/data/thermal.py similarity index 100% rename from openmc/data/thermal.py rename to src/openmc/data/thermal.py diff --git a/openmc/data/thermal_angle_energy.py b/src/openmc/data/thermal_angle_energy.py similarity index 100% rename from openmc/data/thermal_angle_energy.py rename to src/openmc/data/thermal_angle_energy.py diff --git a/openmc/data/uncorrelated.py b/src/openmc/data/uncorrelated.py similarity index 100% rename from openmc/data/uncorrelated.py rename to src/openmc/data/uncorrelated.py diff --git a/openmc/data/urr.py b/src/openmc/data/urr.py similarity index 100% rename from openmc/data/urr.py rename to src/openmc/data/urr.py diff --git a/openmc/deplete/__init__.py b/src/openmc/deplete/__init__.py similarity index 100% rename from openmc/deplete/__init__.py rename to src/openmc/deplete/__init__.py diff --git a/openmc/deplete/_matrix_funcs.py b/src/openmc/deplete/_matrix_funcs.py similarity index 100% rename from openmc/deplete/_matrix_funcs.py rename to src/openmc/deplete/_matrix_funcs.py diff --git a/openmc/deplete/abc.py b/src/openmc/deplete/abc.py similarity index 100% rename from openmc/deplete/abc.py rename to src/openmc/deplete/abc.py diff --git a/openmc/deplete/atom_number.py b/src/openmc/deplete/atom_number.py similarity index 100% rename from openmc/deplete/atom_number.py rename to src/openmc/deplete/atom_number.py diff --git a/openmc/deplete/chain.py b/src/openmc/deplete/chain.py similarity index 100% rename from openmc/deplete/chain.py rename to src/openmc/deplete/chain.py diff --git a/openmc/deplete/coupled_operator.py b/src/openmc/deplete/coupled_operator.py similarity index 100% rename from openmc/deplete/coupled_operator.py rename to src/openmc/deplete/coupled_operator.py diff --git a/openmc/deplete/cram.py b/src/openmc/deplete/cram.py similarity index 100% rename from openmc/deplete/cram.py rename to src/openmc/deplete/cram.py diff --git a/openmc/deplete/helpers.py b/src/openmc/deplete/helpers.py similarity index 100% rename from openmc/deplete/helpers.py rename to src/openmc/deplete/helpers.py diff --git a/openmc/deplete/independent_operator.py b/src/openmc/deplete/independent_operator.py similarity index 100% rename from openmc/deplete/independent_operator.py rename to src/openmc/deplete/independent_operator.py diff --git a/openmc/deplete/integrators.py b/src/openmc/deplete/integrators.py similarity index 100% rename from openmc/deplete/integrators.py rename to src/openmc/deplete/integrators.py diff --git a/openmc/deplete/microxs.py b/src/openmc/deplete/microxs.py similarity index 100% rename from openmc/deplete/microxs.py rename to src/openmc/deplete/microxs.py diff --git a/openmc/deplete/nuclide.py b/src/openmc/deplete/nuclide.py similarity index 100% rename from openmc/deplete/nuclide.py rename to src/openmc/deplete/nuclide.py diff --git a/openmc/deplete/openmc_operator.py b/src/openmc/deplete/openmc_operator.py similarity index 100% rename from openmc/deplete/openmc_operator.py rename to src/openmc/deplete/openmc_operator.py diff --git a/openmc/deplete/pool.py b/src/openmc/deplete/pool.py similarity index 100% rename from openmc/deplete/pool.py rename to src/openmc/deplete/pool.py diff --git a/openmc/deplete/reaction_rates.py b/src/openmc/deplete/reaction_rates.py similarity index 100% rename from openmc/deplete/reaction_rates.py rename to src/openmc/deplete/reaction_rates.py diff --git a/openmc/deplete/results.py b/src/openmc/deplete/results.py similarity index 100% rename from openmc/deplete/results.py rename to src/openmc/deplete/results.py diff --git a/openmc/deplete/stepresult.py b/src/openmc/deplete/stepresult.py similarity index 100% rename from openmc/deplete/stepresult.py rename to src/openmc/deplete/stepresult.py diff --git a/openmc/deplete/transfer_rates.py b/src/openmc/deplete/transfer_rates.py similarity index 100% rename from openmc/deplete/transfer_rates.py rename to src/openmc/deplete/transfer_rates.py diff --git a/openmc/dummy_comm.py b/src/openmc/dummy_comm.py similarity index 100% rename from openmc/dummy_comm.py rename to src/openmc/dummy_comm.py diff --git a/openmc/element.py b/src/openmc/element.py similarity index 100% rename from openmc/element.py rename to src/openmc/element.py diff --git a/openmc/examples.py b/src/openmc/examples.py similarity index 100% rename from openmc/examples.py rename to src/openmc/examples.py diff --git a/openmc/exceptions.py b/src/openmc/exceptions.py similarity index 100% rename from openmc/exceptions.py rename to src/openmc/exceptions.py diff --git a/openmc/executor.py b/src/openmc/executor.py similarity index 100% rename from openmc/executor.py rename to src/openmc/executor.py diff --git a/openmc/filter.py b/src/openmc/filter.py similarity index 100% rename from openmc/filter.py rename to src/openmc/filter.py diff --git a/openmc/filter_expansion.py b/src/openmc/filter_expansion.py similarity index 100% rename from openmc/filter_expansion.py rename to src/openmc/filter_expansion.py diff --git a/openmc/geometry.py b/src/openmc/geometry.py similarity index 100% rename from openmc/geometry.py rename to src/openmc/geometry.py diff --git a/openmc/lattice.py b/src/openmc/lattice.py similarity index 100% rename from openmc/lattice.py rename to src/openmc/lattice.py diff --git a/openmc/lib/__init__.py b/src/openmc/lib/__init__.py similarity index 100% rename from openmc/lib/__init__.py rename to src/openmc/lib/__init__.py diff --git a/openmc/lib/cell.py b/src/openmc/lib/cell.py similarity index 100% rename from openmc/lib/cell.py rename to src/openmc/lib/cell.py diff --git a/openmc/lib/core.py b/src/openmc/lib/core.py similarity index 100% rename from openmc/lib/core.py rename to src/openmc/lib/core.py diff --git a/openmc/lib/error.py b/src/openmc/lib/error.py similarity index 100% rename from openmc/lib/error.py rename to src/openmc/lib/error.py diff --git a/openmc/lib/filter.py b/src/openmc/lib/filter.py similarity index 100% rename from openmc/lib/filter.py rename to src/openmc/lib/filter.py diff --git a/openmc/lib/material.py b/src/openmc/lib/material.py similarity index 100% rename from openmc/lib/material.py rename to src/openmc/lib/material.py diff --git a/openmc/lib/math.py b/src/openmc/lib/math.py similarity index 100% rename from openmc/lib/math.py rename to src/openmc/lib/math.py diff --git a/openmc/lib/mesh.py b/src/openmc/lib/mesh.py similarity index 100% rename from openmc/lib/mesh.py rename to src/openmc/lib/mesh.py diff --git a/openmc/lib/nuclide.py b/src/openmc/lib/nuclide.py similarity index 100% rename from openmc/lib/nuclide.py rename to src/openmc/lib/nuclide.py diff --git a/openmc/lib/plot.py b/src/openmc/lib/plot.py similarity index 100% rename from openmc/lib/plot.py rename to src/openmc/lib/plot.py diff --git a/openmc/lib/settings.py b/src/openmc/lib/settings.py similarity index 100% rename from openmc/lib/settings.py rename to src/openmc/lib/settings.py diff --git a/openmc/lib/tally.py b/src/openmc/lib/tally.py similarity index 100% rename from openmc/lib/tally.py rename to src/openmc/lib/tally.py diff --git a/openmc/lib/weight_windows.py b/src/openmc/lib/weight_windows.py similarity index 100% rename from openmc/lib/weight_windows.py rename to src/openmc/lib/weight_windows.py diff --git a/openmc/macroscopic.py b/src/openmc/macroscopic.py similarity index 100% rename from openmc/macroscopic.py rename to src/openmc/macroscopic.py diff --git a/openmc/material.py b/src/openmc/material.py similarity index 100% rename from openmc/material.py rename to src/openmc/material.py diff --git a/openmc/mesh.py b/src/openmc/mesh.py similarity index 100% rename from openmc/mesh.py rename to src/openmc/mesh.py diff --git a/openmc/mgxs/__init__.py b/src/openmc/mgxs/__init__.py similarity index 100% rename from openmc/mgxs/__init__.py rename to src/openmc/mgxs/__init__.py diff --git a/openmc/mgxs/groups.py b/src/openmc/mgxs/groups.py similarity index 100% rename from openmc/mgxs/groups.py rename to src/openmc/mgxs/groups.py diff --git a/openmc/mgxs/library.py b/src/openmc/mgxs/library.py similarity index 100% rename from openmc/mgxs/library.py rename to src/openmc/mgxs/library.py diff --git a/openmc/mgxs/mdgxs.py b/src/openmc/mgxs/mdgxs.py similarity index 100% rename from openmc/mgxs/mdgxs.py rename to src/openmc/mgxs/mdgxs.py diff --git a/openmc/mgxs/mgxs.py b/src/openmc/mgxs/mgxs.py similarity index 100% rename from openmc/mgxs/mgxs.py rename to src/openmc/mgxs/mgxs.py diff --git a/openmc/mgxs_library.py b/src/openmc/mgxs_library.py similarity index 100% rename from openmc/mgxs_library.py rename to src/openmc/mgxs_library.py diff --git a/openmc/mixin.py b/src/openmc/mixin.py similarity index 100% rename from openmc/mixin.py rename to src/openmc/mixin.py diff --git a/openmc/model/__init__.py b/src/openmc/model/__init__.py similarity index 100% rename from openmc/model/__init__.py rename to src/openmc/model/__init__.py diff --git a/openmc/model/funcs.py b/src/openmc/model/funcs.py similarity index 100% rename from openmc/model/funcs.py rename to src/openmc/model/funcs.py diff --git a/openmc/model/model.py b/src/openmc/model/model.py similarity index 100% rename from openmc/model/model.py rename to src/openmc/model/model.py diff --git a/openmc/model/surface_composite.py b/src/openmc/model/surface_composite.py similarity index 100% rename from openmc/model/surface_composite.py rename to src/openmc/model/surface_composite.py diff --git a/openmc/model/triso.py b/src/openmc/model/triso.py similarity index 100% rename from openmc/model/triso.py rename to src/openmc/model/triso.py diff --git a/openmc/mpi.py b/src/openmc/mpi.py similarity index 100% rename from openmc/mpi.py rename to src/openmc/mpi.py diff --git a/openmc/nuclide.py b/src/openmc/nuclide.py similarity index 100% rename from openmc/nuclide.py rename to src/openmc/nuclide.py diff --git a/openmc/openmc_exec.py b/src/openmc/openmc_exec.py similarity index 100% rename from openmc/openmc_exec.py rename to src/openmc/openmc_exec.py diff --git a/openmc/openmoc_compatible.py b/src/openmc/openmoc_compatible.py similarity index 100% rename from openmc/openmoc_compatible.py rename to src/openmc/openmoc_compatible.py diff --git a/openmc/particle_restart.py b/src/openmc/particle_restart.py similarity index 100% rename from openmc/particle_restart.py rename to src/openmc/particle_restart.py diff --git a/openmc/plots.py b/src/openmc/plots.py similarity index 100% rename from openmc/plots.py rename to src/openmc/plots.py diff --git a/openmc/plotter.py b/src/openmc/plotter.py similarity index 100% rename from openmc/plotter.py rename to src/openmc/plotter.py diff --git a/openmc/polynomial.py b/src/openmc/polynomial.py similarity index 100% rename from openmc/polynomial.py rename to src/openmc/polynomial.py diff --git a/openmc/region.py b/src/openmc/region.py similarity index 100% rename from openmc/region.py rename to src/openmc/region.py diff --git a/openmc/search.py b/src/openmc/search.py similarity index 100% rename from openmc/search.py rename to src/openmc/search.py diff --git a/openmc/settings.py b/src/openmc/settings.py similarity index 100% rename from openmc/settings.py rename to src/openmc/settings.py diff --git a/openmc/source.py b/src/openmc/source.py similarity index 100% rename from openmc/source.py rename to src/openmc/source.py diff --git a/openmc/statepoint.py b/src/openmc/statepoint.py similarity index 100% rename from openmc/statepoint.py rename to src/openmc/statepoint.py diff --git a/openmc/stats/__init__.py b/src/openmc/stats/__init__.py similarity index 100% rename from openmc/stats/__init__.py rename to src/openmc/stats/__init__.py diff --git a/openmc/stats/multivariate.py b/src/openmc/stats/multivariate.py similarity index 100% rename from openmc/stats/multivariate.py rename to src/openmc/stats/multivariate.py diff --git a/openmc/stats/univariate.py b/src/openmc/stats/univariate.py similarity index 100% rename from openmc/stats/univariate.py rename to src/openmc/stats/univariate.py diff --git a/openmc/summary.py b/src/openmc/summary.py similarity index 100% rename from openmc/summary.py rename to src/openmc/summary.py diff --git a/openmc/surface.py b/src/openmc/surface.py similarity index 100% rename from openmc/surface.py rename to src/openmc/surface.py diff --git a/openmc/tallies.py b/src/openmc/tallies.py similarity index 100% rename from openmc/tallies.py rename to src/openmc/tallies.py diff --git a/openmc/tally_derivative.py b/src/openmc/tally_derivative.py similarity index 100% rename from openmc/tally_derivative.py rename to src/openmc/tally_derivative.py diff --git a/openmc/tracks.py b/src/openmc/tracks.py similarity index 100% rename from openmc/tracks.py rename to src/openmc/tracks.py diff --git a/openmc/trigger.py b/src/openmc/trigger.py similarity index 100% rename from openmc/trigger.py rename to src/openmc/trigger.py diff --git a/openmc/universe.py b/src/openmc/universe.py similarity index 100% rename from openmc/universe.py rename to src/openmc/universe.py diff --git a/openmc/utility_funcs.py b/src/openmc/utility_funcs.py similarity index 100% rename from openmc/utility_funcs.py rename to src/openmc/utility_funcs.py diff --git a/openmc/volume.py b/src/openmc/volume.py similarity index 100% rename from openmc/volume.py rename to src/openmc/volume.py diff --git a/openmc/weight_windows.py b/src/openmc/weight_windows.py similarity index 100% rename from openmc/weight_windows.py rename to src/openmc/weight_windows.py From fbda53058e92c22ce7fd307cad98a30c7e5685e8 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Fri, 18 Oct 2024 00:50:00 +0600 Subject: [PATCH 62/76] update lib paths --- CMakeLists.txt | 21 +++++++-------------- cmake/OpenMCConfig.cmake.in | 2 +- src/openmc/__init__.py | 30 ++++++++++++++++++++++++++++++ src/openmc/lib/__init__.py | 12 ++---------- 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a8ec7ab23db..1df0b882208 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -337,9 +337,7 @@ if(SKBUILD) # Scikit-build installs OpenMC to ${SKBUILD_PLATLIB_DIR}/openmc # So, set bin directory to root environment (install prefix/bin) set(CMAKE_INSTALL_BINDIR ${SKBUILD_SCRIPTS_DIR}) - # Unfortunately, OpenMC has lib directory in the openmc/lib subdirectory - set(CMAKE_INSTALL_LIBDIR lib) - set(CMAKE_INSTALL_INCLUDEDIR ${SKBUILD_HEADERS_DIR}) + set(CMAKE_INSTALL_INCLUDEDIR ${SKBUILD_SUBDIR}/${CMAKE_INSTALL_INCLUDEDIR}) set(CMAKE_INSTALL_DATADIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_DATADIR}) set(CMAKE_INSTALL_DOCDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_DOCDIR}) set(CMAKE_INSTALL_INFODIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_INFODIR}) @@ -347,26 +345,21 @@ if(SKBUILD) set(CMAKE_INSTALL_LOCALEDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_LOCALEDIR}) set(CMAKE_INSTALL_LOCALSTATEDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_LOCALSTATEDIR}) set(CMAKE_INSTALL_RUNSTATEDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_RUNSTATEDIR}) - set(SKBUILD_LIB_DIR ${CMAKE_INSTALL_LIBDIR}/python${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}/site-packages/openmc/${CMAKE_INSTALL_LIBDIR}) + set(SKBUILD_SUBDIR core/) + set(SKBUILD_LIB_DIR ${CMAKE_INSTALL_LIBDIR}/python${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}/site-packages/openmc/${SKBUILD_SUBDIR}${CMAKE_INSTALL_LIBDIR}) # Auditwheel and Delocate need this when repairing the wheel # Since OpenMC libs are installed in the openmc subdirectory # Auditwheel and Delocate need this to find the OpenMC libs for openmc.data # It's a bit of a hack, but it works - set(SKBUILD_REPAIR_WHEEL_PATCH openmc/${CMAKE_INSTALL_LIBDIR}) + set(SKBUILD_REPAIR_WHEEL_PATCH openmc/${SKBUILD_SUBDIR}${CMAKE_INSTALL_LIBDIR}) if(APPLE) set(CMAKE_MACOSX_RPATH ON) set(OPENMC_LIBRARY_RPATH "@loader_path") - set(OPENMC_PYTHON_MODULE_RPATH "@loader_path/${CMAKE_INSTALL_LIBDIR}") set(OPENMC_BINARY_RPATH "@loader_path/../${SKBUILD_LIB_DIR};@loader_path/../../${SKBUILD_REPAIR_WHEEL_PATCH}") elseif(UNIX) set(OPENMC_LIBRARY_RPATH "$ORIGIN") - set(OPENMC_PYTHON_MODULE_RPATH "$ORIGIN/${CMAKE_INSTALL_LIBDIR}") set(OPENMC_BINARY_RPATH "$ORIGIN/../${SKBUILD_LIB_DIR};$ORIGIN/../${SKBUILD_REPAIR_WHEEL_PATCH};$ORIGIN/../../${SKBUILD_REPAIR_WHEEL_PATCH}") - else() - set(OPENMC_LIBRARY_RPATH OFF) - set(OPENMC_PYTHON_MODULE_RPATH OFF) - set(OPENMC_BINARY_RPATH OFF) endif() else() # use, i.e. don't skip the full RPATH for the build tree @@ -672,7 +665,7 @@ endif() install(TARGETS openmc libopenmc EXPORT openmc-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${SKBUILD_SUBDIR}${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) @@ -696,5 +689,5 @@ install(FILES DESTINATION ${INSTALL_CONFIGDIR}) install(FILES man/man1/openmc.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) install(FILES LICENSE DESTINATION "${CMAKE_INSTALL_DOCDIR}" RENAME copyright) -install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) -install(FILES "${CMAKE_BINARY_DIR}/include/openmc/version.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/openmc) +install(DIRECTORY include/ DESTINATION ${SKBUILD_SUBDIR}${CMAKE_INSTALL_INCLUDEDIR}) +install(FILES "${CMAKE_BINARY_DIR}/include/openmc/version.h" DESTINATION ${SKBUILD_SUBDIR}${CMAKE_INSTALL_INCLUDEDIR}/openmc) diff --git a/cmake/OpenMCConfig.cmake.in b/cmake/OpenMCConfig.cmake.in index 5323495d077..ece6f1bd342 100644 --- a/cmake/OpenMCConfig.cmake.in +++ b/cmake/OpenMCConfig.cmake.in @@ -46,7 +46,7 @@ if(@SKBUILD@) # Extract MOAB include paths, library paths, and extra libraries run_python_command(OpenMC_INCLUDE_DIRS "import openmc; print(openmc.include_path)") - run_python_command(OpenMC_LIBRARY_DIRS "import openmc; print(openmc.lib_path)") + run_python_command(OpenMC_LIBRARY_DIRS "import openmc; print(' '.join(openmc.lib_path))") run_python_command(OpenMC_EXTRA_LIBRARIES "import openmc; print(' '.join(openmc.extra_lib))") # Check if the wheel was repaired using auditwheel or delocate diff --git a/src/openmc/__init__.py b/src/openmc/__init__.py index 32320365d58..db070fd6a45 100644 --- a/src/openmc/__init__.py +++ b/src/openmc/__init__.py @@ -1,3 +1,5 @@ +import os +import glob import importlib.metadata from openmc.arithmetic import * from openmc.bounding_box import * @@ -43,3 +45,31 @@ __version__ = importlib.metadata.version("openmc") + +def get_path(subdir, pattern=""): + """Helper function to return paths that match a given pattern within a subdirectory.""" + path = os.path.join(__path__[0], "core", subdir) + return glob.glob(os.path.join(path, pattern)) if os.path.exists(path) else [] + +def get_include_path(): + """Return the include directory path for OpenMC headers.""" + return get_path("include") + +def get_core_libraries(): + """Return library paths and library directory paths.""" + lib_paths = [libs for lib in ["lib", "lib64"] for libs in get_path(lib)] + lib = [libs for lib in ["lib", "lib64"] for libs in get_path(lib, pattern="*openmc*")] + return lib, lib_paths + +def get_extra_libraries(): + """List all the extra libraries of OpenMC.""" + libs_path = os.path.join(__path__[0], ".dylibs") if sys.platform == "darwin" else os.path.join(__path__[0], "..", "pyne.libs") + return (glob.glob(os.path.join(libs_path, "*")), libs_path) if os.path.exists(libs_path) else ([], []) + +# Setup variables +include_path = get_include_path() +lib, lib_path = get_core_libraries() +extra_lib, extra_lib_path = get_extra_libraries() + +# Export variables for easy access +__all__ = ["include_path", "lib", "lib_path", "extra_lib", "extra_lib_path"] diff --git a/src/openmc/lib/__init__.py b/src/openmc/lib/__init__.py index 9bb2efb38af..cd49665a5f3 100644 --- a/src/openmc/lib/__init__.py +++ b/src/openmc/lib/__init__.py @@ -13,20 +13,12 @@ """ from ctypes import CDLL, c_bool, c_int -import importlib.resources import os -import sys - - -# Determine shared-library suffix -if sys.platform == 'darwin': - _suffix = 'dylib' -else: - _suffix = 'so' if os.environ.get('READTHEDOCS', None) != 'True': # Open shared library - _filename = importlib.resources.files(__name__) / f'libopenmc.{_suffix}' + import openmc + _filename = openmc.lib[0] _dll = CDLL(str(_filename)) # TODO: Remove str() when Python 3.12+ else: # For documentation builds, we don't actually have the shared library From 0d3f6f20f632214841c23111b39a317b761eb0ec Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Fri, 18 Oct 2024 20:53:02 +0600 Subject: [PATCH 63/76] add include --- cmake/OpenMCConfig.cmake.in | 2 +- src/openmc/__init__.py | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/cmake/OpenMCConfig.cmake.in b/cmake/OpenMCConfig.cmake.in index ece6f1bd342..e62849c78e6 100644 --- a/cmake/OpenMCConfig.cmake.in +++ b/cmake/OpenMCConfig.cmake.in @@ -45,7 +45,7 @@ if(@SKBUILD@) endfunction() # Extract MOAB include paths, library paths, and extra libraries - run_python_command(OpenMC_INCLUDE_DIRS "import openmc; print(openmc.include_path)") + run_python_command(OpenMC_INCLUDE_DIRS "import openmc; print(' '.join(openmc.include_path))") run_python_command(OpenMC_LIBRARY_DIRS "import openmc; print(' '.join(openmc.lib_path))") run_python_command(OpenMC_EXTRA_LIBRARIES "import openmc; print(' '.join(openmc.extra_lib))") diff --git a/src/openmc/__init__.py b/src/openmc/__init__.py index db070fd6a45..4b14ce53452 100644 --- a/src/openmc/__init__.py +++ b/src/openmc/__init__.py @@ -46,30 +46,32 @@ __version__ = importlib.metadata.version("openmc") -def get_path(subdir, pattern=""): +def get_core_path(subdir, pattern="*"): """Helper function to return paths that match a given pattern within a subdirectory.""" path = os.path.join(__path__[0], "core", subdir) return glob.glob(os.path.join(path, pattern)) if os.path.exists(path) else [] def get_include_path(): """Return the include directory path for OpenMC headers.""" - return get_path("include") + include = get_core_path("include") + include_path = get_core_path("include", "") + return include, include_path def get_core_libraries(): """Return library paths and library directory paths.""" - lib_paths = [libs for lib in ["lib", "lib64"] for libs in get_path(lib)] - lib = [libs for lib in ["lib", "lib64"] for libs in get_path(lib, pattern="*openmc*")] + lib = [libs for lib in ["lib", "lib64"] for libs in get_core_path(lib)] + lib_paths = [libs for lib in ["lib", "lib64"] for libs in get_core_path(lib, "")] return lib, lib_paths def get_extra_libraries(): - """List all the extra libraries of OpenMC.""" - libs_path = os.path.join(__path__[0], ".dylibs") if sys.platform == "darwin" else os.path.join(__path__[0], "..", "pyne.libs") + """List all the extra libraries.""" + libs_path = os.path.join(__path__[0], ".dylibs") if sys.platform == "darwin" else os.path.join(__path__[0], "..", "openmc.libs") return (glob.glob(os.path.join(libs_path, "*")), libs_path) if os.path.exists(libs_path) else ([], []) # Setup variables -include_path = get_include_path() +include, include_path = get_include_path() lib, lib_path = get_core_libraries() extra_lib, extra_lib_path = get_extra_libraries() # Export variables for easy access -__all__ = ["include_path", "lib", "lib_path", "extra_lib", "extra_lib_path"] +__all__ = ["include", "include_path", "lib", "lib_path", "extra_lib", "extra_lib_path"] From af0f1d5ccf70a84373f53215a0c7416713abf11e Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sun, 20 Oct 2024 02:27:34 +0600 Subject: [PATCH 64/76] add openmc.in --- CMakeLists.txt | 54 +++++++++++++++++++++++++------------------------ cmake/openmc.in | 12 +++++++++++ 2 files changed, 40 insertions(+), 26 deletions(-) create mode 100644 cmake/openmc.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 1df0b882208..e83b654f01a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -334,10 +334,11 @@ if(SKBUILD) COMPONENTS Interpreter REQUIRED ) - # Scikit-build installs OpenMC to ${SKBUILD_PLATLIB_DIR}/openmc - # So, set bin directory to root environment (install prefix/bin) - set(CMAKE_INSTALL_BINDIR ${SKBUILD_SCRIPTS_DIR}) - set(CMAKE_INSTALL_INCLUDEDIR ${SKBUILD_SUBDIR}/${CMAKE_INSTALL_INCLUDEDIR}) + # By default, scikit-build will install everything to ${SKBUILD_PLATLIB_DIR}/openmc + # Install include and bin directories to ${SKBUILD_PLATLIB_DIR}/openmc/SKBUILD_SUBDIR + set(SKBUILD_SUBDIR core/) + set(CMAKE_INSTALL_BINDIR ${SKBUILD_SUBDIR}${CMAKE_INSTALL_BINDIR}) + set(CMAKE_INSTALL_INCLUDEDIR ${SKBUILD_SUBDIR}${CMAKE_INSTALL_INCLUDEDIR}) set(CMAKE_INSTALL_DATADIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_DATADIR}) set(CMAKE_INSTALL_DOCDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_DOCDIR}) set(CMAKE_INSTALL_INFODIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_INFODIR}) @@ -345,21 +346,13 @@ if(SKBUILD) set(CMAKE_INSTALL_LOCALEDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_LOCALEDIR}) set(CMAKE_INSTALL_LOCALSTATEDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_LOCALSTATEDIR}) set(CMAKE_INSTALL_RUNSTATEDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_RUNSTATEDIR}) - set(SKBUILD_SUBDIR core/) - set(SKBUILD_LIB_DIR ${CMAKE_INSTALL_LIBDIR}/python${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}/site-packages/openmc/${SKBUILD_SUBDIR}${CMAKE_INSTALL_LIBDIR}) - - # Auditwheel and Delocate need this when repairing the wheel - # Since OpenMC libs are installed in the openmc subdirectory - # Auditwheel and Delocate need this to find the OpenMC libs for openmc.data - # It's a bit of a hack, but it works - set(SKBUILD_REPAIR_WHEEL_PATCH openmc/${SKBUILD_SUBDIR}${CMAKE_INSTALL_LIBDIR}) if(APPLE) set(CMAKE_MACOSX_RPATH ON) set(OPENMC_LIBRARY_RPATH "@loader_path") - set(OPENMC_BINARY_RPATH "@loader_path/../${SKBUILD_LIB_DIR};@loader_path/../../${SKBUILD_REPAIR_WHEEL_PATCH}") + set(OPENMC_BINARY_RPATH "@loader_path/../${CMAKE_INSTALL_LIBDIR}") elseif(UNIX) set(OPENMC_LIBRARY_RPATH "$ORIGIN") - set(OPENMC_BINARY_RPATH "$ORIGIN/../${SKBUILD_LIB_DIR};$ORIGIN/../${SKBUILD_REPAIR_WHEEL_PATCH};$ORIGIN/../../${SKBUILD_REPAIR_WHEEL_PATCH}") + set(OPENMC_BINARY_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}") endif() else() # use, i.e. don't skip the full RPATH for the build tree @@ -517,7 +510,7 @@ endif() target_include_directories(libopenmc PUBLIC - $ + $ $ ${HDF5_INCLUDE_DIRS} ) @@ -666,22 +659,31 @@ install(TARGETS openmc libopenmc EXPORT openmc-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${SKBUILD_SUBDIR}${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${SKBUILD_SUBDIR}${CMAKE_INSTALL_LIBDIR} ) -if(NOT SKBUILD) - install(EXPORT openmc-targets - FILE OpenMCTargets.cmake - NAMESPACE OpenMC:: - DESTINATION ${INSTALL_CONFIGDIR} - ) -endif() +set(INSTALL_TARGETDIR ${SKBUILD_SUBDIR}${CMAKE_INSTALL_LIBDIR}/cmake/OpenMC) +install(EXPORT openmc-targets + FILE OpenMCTargets.cmake + NAMESPACE OpenMC:: + DESTINATION ${INSTALL_TARGETDIR} +) # Collect scripts file(GLOB SCRIPTS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/*") # Install scripts to bin directory -install(PROGRAMS ${SCRIPTS} DESTINATION ${CMAKE_INSTALL_BINDIR}) +if(SKBUILD) + install(PROGRAMS ${SCRIPTS} DESTINATION ${SKBUILD_SCRIPTS_DIR}) +else() + install(PROGRAMS ${SCRIPTS} DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif() + +# Install openmc script +if(SKBUILD) + configure_file(cmake/openmc.in "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/openmc" @ONLY) + install(PROGRAMS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/openmc" DESTINATION ${SKBUILD_SCRIPTS_DIR}) +endif() install(FILES "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfig.cmake" @@ -689,5 +691,5 @@ install(FILES DESTINATION ${INSTALL_CONFIGDIR}) install(FILES man/man1/openmc.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) install(FILES LICENSE DESTINATION "${CMAKE_INSTALL_DOCDIR}" RENAME copyright) -install(DIRECTORY include/ DESTINATION ${SKBUILD_SUBDIR}${CMAKE_INSTALL_INCLUDEDIR}) -install(FILES "${CMAKE_BINARY_DIR}/include/openmc/version.h" DESTINATION ${SKBUILD_SUBDIR}${CMAKE_INSTALL_INCLUDEDIR}/openmc) +install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +install(FILES "${CMAKE_BINARY_DIR}/include/openmc/version.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/openmc) diff --git a/cmake/openmc.in b/cmake/openmc.in new file mode 100644 index 00000000000..e0cffe9950a --- /dev/null +++ b/cmake/openmc.in @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 + +import os +import sys +import sysconfig + + +if __name__ == "__main__": + os.execv( + os.path.join(sysconfig.get_path("platlib"), 'openmc', '@CMAKE_INSTALL_BINDIR@', 'openmc'), + sys.argv, + ) \ No newline at end of file From e2802f34b352489688eff913011af0ae3c207e9b Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sun, 20 Oct 2024 02:31:01 +0600 Subject: [PATCH 65/76] use OpenMC targets --- cmake/OpenMCConfig.cmake.in | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/cmake/OpenMCConfig.cmake.in b/cmake/OpenMCConfig.cmake.in index e62849c78e6..aa276bb7eab 100644 --- a/cmake/OpenMCConfig.cmake.in +++ b/cmake/OpenMCConfig.cmake.in @@ -5,6 +5,9 @@ find_package(gsl-lite REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../gsl-lite) find_package(pugixml REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../pugixml) find_package(xtl REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../xtl) find_package(xtensor REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../xtensor) + +find_package(HDF5 REQUIRED COMPONENTS C HL) + if(@OPENMC_USE_DAGMC@) find_package(DAGMC REQUIRED HINTS @DAGMC_DIR@) endif() @@ -60,32 +63,10 @@ if(@SKBUILD@) "For more information, visit: https://docs.openmc.org/" ) endif() - - # Find the core library - find_library(OpenMC_LIBRARY - NAMES openmc - HINTS ${OpenMC_LIBRARY_DIRS} - NO_DEFAULT_PATH - ) - - # Add the core library as an imported target - add_library(OpenMC::libopenmc UNKNOWN IMPORTED) - set_target_properties(OpenMC::libopenmc PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${OpenMC_INCLUDE_DIRS}" - IMPORTED_LOCATION "${OpenMC_LIBRARY}" - ) - - # Add the core library to the list of libraries - set(OpenMC_LIBRARIES ${OpenMC_LIBRARY}) - - # Include standard argument handling for finding packages - include(FindPackageHandleStandardArgs) - - # Validates that the necessary variables are set - find_package_handle_standard_args(MOAB - REQUIRED_VARS OpenMC_LIBRARIES OpenMC_INCLUDE_DIRS - VERSION_VAR @OPENMC_VERSION@ - ) + + # Add OpenMC targets + file(TO_CMAKE_PATH "${OpenMC_LIBRARY_DIRS}/cmake/OpenMC/OpenMCTargets.cmake" OpenMC_TARGETS_FILE) + include(${OpenMC_TARGETS_FILE}) elseif(NOT TARGET OpenMC::libopenmc) include("${OpenMC_CMAKE_DIR}/OpenMCTargets.cmake") endif() From db1d8d1cbc5cabc8f9b6e3cdacbc5a723f6d58fb Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sun, 20 Oct 2024 02:53:18 +0600 Subject: [PATCH 66/76] install source version --- tools/ci/manylinux.dockerfile | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tools/ci/manylinux.dockerfile b/tools/ci/manylinux.dockerfile index ea60b38175c..e9a3521a9d5 100644 --- a/tools/ci/manylinux.dockerfile +++ b/tools/ci/manylinux.dockerfile @@ -96,8 +96,7 @@ RUN yum install -y epel-release && \ yum clean all # Set up environment variables for shared libraries -ENV LD_LIBRARY_PATH=/usr/local/lib64:$LD_LIBRARY_PATH - +ENV LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64:$LD_LIBRARY_PATH # Compiler configuration stage: gcc FROM base AS compiler-gcc @@ -331,8 +330,8 @@ FROM dependencies AS python-dependencies ARG Python_ABI # Use Python from manylinux as the default Python +ENV PYTHONHOME="/opt/python/${Python_ABI}" ENV PATH="/opt/python/${Python_ABI}/bin:${PATH}" -RUN ln -sf /opt/python/${Python_ABI}/bin/python3 /usr/bin/python # Build and install NCrystal ARG NCrystal_TAG @@ -420,15 +419,20 @@ RUN export SKBUILD_CMAKE_ARGS="-DOPENMC_USE_MPI=$([ ${COMPILER} == 'openmpi' ] & cd $HOME/openmc && \ python -m build . -w -# Repair wheel -RUN auditwheel repair $HOME/openmc/dist/openmc-*.whl -w $HOME/openmc/dist/ - # Install OpenMC wheel RUN python -m pip install \ - "$(echo $HOME/openmc/dist/*manylinux**.whl)[$([ ${COMPILER} == 'openmpi' ] && echo 'depletion-mpi,')test,ci,vtk]" + "$(echo $HOME/openmc/dist/*.whl)[$([ ${COMPILER} == 'openmpi' ] && echo 'depletion-mpi,')test,ci,vtk]" # Test OpenMC RUN cd $HOME/openmc && \ eval $(ncrystal-config --setup) && \ nctool --test && \ pytest --cov=openmc -v $([ ${COMPILER} == 'openmpi' ] && echo '--mpi') --event tests + +# Repair wheel +RUN auditwheel repair $HOME/openmc/dist/openmc-*.whl -w $HOME/openmc/dist/ + +# Test repaired wheel +RUN python -m pip uninstall openmc -y && \ + python -m pip install $HOME/openmc/dist/*manylinux**.whl && \ + openmc --version \ No newline at end of file From 7a0a56d12750806d39ce9b9c37c66027b910f336 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sun, 20 Oct 2024 11:44:43 +0600 Subject: [PATCH 67/76] add SKBUILDScripts.cmake --- CMakeLists.txt | 25 +++++++++++-------------- cmake/SKBUILDScripts.cmake | 24 ++++++++++++++++++++++++ cmake/openmc.in | 12 ------------ 3 files changed, 35 insertions(+), 26 deletions(-) create mode 100644 cmake/SKBUILDScripts.cmake delete mode 100644 cmake/openmc.in diff --git a/CMakeLists.txt b/CMakeLists.txt index e83b654f01a..c611e5a55fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,11 +16,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # Set module path set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) -# Conditionally find Python if building with scikit-build-core -if(SKBUILD) - find_package(Python COMPONENTS Interpreter Development.Module REQUIRED) -endif() - # Enable correct usage of CXX_EXTENSIONS if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.22) cmake_policy(SET CMP0128 NEW) @@ -328,12 +323,6 @@ include(GNUInstallDirs) if(SKBUILD) - # Find necessary packages - find_package( - Python - COMPONENTS Interpreter - REQUIRED - ) # By default, scikit-build will install everything to ${SKBUILD_PLATLIB_DIR}/openmc # Install include and bin directories to ${SKBUILD_PLATLIB_DIR}/openmc/SKBUILD_SUBDIR set(SKBUILD_SUBDIR core/) @@ -346,6 +335,11 @@ if(SKBUILD) set(CMAKE_INSTALL_LOCALEDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_LOCALEDIR}) set(CMAKE_INSTALL_LOCALSTATEDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_LOCALSTATEDIR}) set(CMAKE_INSTALL_RUNSTATEDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_RUNSTATEDIR}) + + # Include the SKBUILDScripts.cmake file + include(cmake/SKBUILDScripts.cmake) + + # Set RPATH if(APPLE) set(CMAKE_MACOSX_RPATH ON) set(OPENMC_LIBRARY_RPATH "@loader_path") @@ -634,6 +628,10 @@ target_compile_features(openmc PUBLIC cxx_std_17) target_compile_features(libopenmc PUBLIC cxx_std_17) set_target_properties(openmc libopenmc PROPERTIES CXX_EXTENSIONS OFF) +# Add openmc executable to SKBUILD_SCRIPT_LIST +list(APPEND SKBUILD_SCRIPT_LIST openmc) + +# Set rpath for openmc executable if(OPENMC_BINARY_RPATH) set_target_properties( openmc @@ -679,10 +677,9 @@ else() install(PROGRAMS ${SCRIPTS} DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() -# Install openmc script +# Generate and install the SKBUILD scripts if(SKBUILD) - configure_file(cmake/openmc.in "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/openmc" @ONLY) - install(PROGRAMS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/openmc" DESTINATION ${SKBUILD_SCRIPTS_DIR}) + generate_and_install_scripts(${SKBUILD_SCRIPT_LIST}) endif() install(FILES diff --git a/cmake/SKBUILDScripts.cmake b/cmake/SKBUILDScripts.cmake new file mode 100644 index 00000000000..da86ee801f1 --- /dev/null +++ b/cmake/SKBUILDScripts.cmake @@ -0,0 +1,24 @@ +# Function to create and install the binary scripts +function(generate_and_install_scripts SCRIPT_LIST) + foreach(SCRIPT_NAME ${SCRIPT_LIST}) + # Define the output path for each generated script + set(GENERATED_SCRIPT "${CMAKE_BINARY_DIR}/${SCRIPT_NAME}") + + # Generate the script content directly + file(WRITE "${GENERATED_SCRIPT}" "#!/usr/bin/env python3\n\n") + file(APPEND "${GENERATED_SCRIPT}" "import os\n") + file(APPEND "${GENERATED_SCRIPT}" "import sys\n") + file(APPEND "${GENERATED_SCRIPT}" "import sysconfig\n\n") + file(APPEND "${GENERATED_SCRIPT}" "if __name__ == '__main__':\n") + file(APPEND "${GENERATED_SCRIPT}" " os.execv(\n") + file(APPEND "${GENERATED_SCRIPT}" " os.path.join(sysconfig.get_path('platlib'), '${SKBUILD_PROJECT_NAME}', '${CMAKE_INSTALL_BINDIR}', '${SCRIPT_NAME}'),\n") + file(APPEND "${GENERATED_SCRIPT}" " sys.argv,\n") + file(APPEND "${GENERATED_SCRIPT}" " )\n") + + # Install the generated script + install( + PROGRAMS "${GENERATED_SCRIPT}" + DESTINATION "${SKBUILD_SCRIPTS_DIR}" + ) + endforeach() +endfunction() diff --git a/cmake/openmc.in b/cmake/openmc.in deleted file mode 100644 index e0cffe9950a..00000000000 --- a/cmake/openmc.in +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -import sysconfig - - -if __name__ == "__main__": - os.execv( - os.path.join(sysconfig.get_path("platlib"), 'openmc', '@CMAKE_INSTALL_BINDIR@', 'openmc'), - sys.argv, - ) \ No newline at end of file From 8dabae4d49d85710b553ef4319565d37f59e9876 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sun, 20 Oct 2024 12:16:38 +0600 Subject: [PATCH 68/76] update get_core_path --- src/openmc/__init__.py | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/openmc/__init__.py b/src/openmc/__init__.py index 4b14ce53452..7f6dedadc9d 100644 --- a/src/openmc/__init__.py +++ b/src/openmc/__init__.py @@ -46,26 +46,37 @@ __version__ = importlib.metadata.version("openmc") -def get_core_path(subdir, pattern="*"): - """Helper function to return paths that match a given pattern within a subdirectory.""" +def get_core_path(subdir, pattern="*", recursive=False): + """ + Helper function to return paths that match a given pattern within a subdirectory. + + Args: + subdir (str): The subdirectory within the 'core' directory. + pattern (str): The pattern to match files or directories. + recursive (bool): Whether to search recursively in subdirectories. + + Returns: + list: A list of matched paths. + """ path = os.path.join(__path__[0], "core", subdir) - return glob.glob(os.path.join(path, pattern)) if os.path.exists(path) else [] + search_pattern = os.path.join(path, "**", pattern) if recursive else os.path.join(path, pattern) + return glob.glob(search_pattern, recursive=recursive) if os.path.exists(path) else [] def get_include_path(): - """Return the include directory path for OpenMC headers.""" - include = get_core_path("include") - include_path = get_core_path("include", "") + """Return includes and include path for OpenMC headers.""" + include = get_core_path("include", "*", recursive=True) + include_path = get_core_path("include", "", recursive=False) return include, include_path def get_core_libraries(): - """Return library paths and library directory paths.""" - lib = [libs for lib in ["lib", "lib64"] for libs in get_core_path(lib)] - lib_paths = [libs for lib in ["lib", "lib64"] for libs in get_core_path(lib, "")] - return lib, lib_paths + """Return libraries and library paths for OpenMC.""" + lib = [lib_file for lib in ["lib", "lib64"] for lib_file in get_core_path(lib, "libopenmc*", recursive=True)] + lib_path = [lib_file for lib in ["lib", "lib64"] for lib_file in get_core_path(lib, "", recursive=False)] + return lib, lib_path def get_extra_libraries(): - """List all the extra libraries.""" - libs_path = os.path.join(__path__[0], ".dylibs") if sys.platform == "darwin" else os.path.join(__path__[0], "..", "openmc.libs") + """Return the extra libraries installed by auditwheel or delocate.""" + libs_path = os.path.join(__path__[0], ".dylibs") if sys.platform == "darwin" else os.path.normpath(os.path.join(__path__[0], "..", "openmc.libs")) return (glob.glob(os.path.join(libs_path, "*")), libs_path) if os.path.exists(libs_path) else ([], []) # Setup variables @@ -74,4 +85,4 @@ def get_extra_libraries(): extra_lib, extra_lib_path = get_extra_libraries() # Export variables for easy access -__all__ = ["include", "include_path", "lib", "lib_path", "extra_lib", "extra_lib_path"] +__all__ = ["include", "include_path", "lib", "lib_path", "extra_lib", "extra_lib_path"] \ No newline at end of file From b8f634c1af52a4eefae54aa97208480113736f30 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sun, 20 Oct 2024 12:22:08 +0600 Subject: [PATCH 69/76] add /usr/local/lib/ to lib path --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c201b003c6..5214aed9901 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -98,6 +98,7 @@ jobs: run: | echo "OPENMC_CROSS_SECTIONS=$HOME/nndc_hdf5/cross_sections.xml" >> $GITHUB_ENV echo "OPENMC_ENDF_DATA=$HOME/endf-b-vii.1" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH" >> $GITHUB_ENV - name: Apt dependencies shell: bash From 73cd2669a9148770bbb1348930b221d56c78f600 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sun, 20 Oct 2024 12:23:07 +0600 Subject: [PATCH 70/76] remove file openmc_exec --- src/openmc/openmc_exec.py | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 src/openmc/openmc_exec.py diff --git a/src/openmc/openmc_exec.py b/src/openmc/openmc_exec.py deleted file mode 100644 index 579eeced24f..00000000000 --- a/src/openmc/openmc_exec.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python3 - -# helper script that launches the openmc binary - -import os -import sys -import sysconfig -from pathlib import Path - - -def main(): - os.execv( - Path(sysconfig.get_path("platlib")) / "openmc" / "bin" / "openmc", sys.argv - ) - - -if __name__ == "__main__": - main() From ea6fab9789ff003fedef7f8cd12fa26479fc947a Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sun, 20 Oct 2024 13:29:34 +0600 Subject: [PATCH 71/76] remove openmc_exec --- src/openmc/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/openmc/__init__.py b/src/openmc/__init__.py index 7f6dedadc9d..9c95c4f0ea2 100644 --- a/src/openmc/__init__.py +++ b/src/openmc/__init__.py @@ -36,7 +36,6 @@ from openmc.polynomial import * from openmc.tracks import * from .config import * -from .openmc_exec import main # Import a few names from the model module from openmc.model import Model From e51918979cf7f74f31002341644f71014a3a768f Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sun, 20 Oct 2024 14:39:52 +0600 Subject: [PATCH 72/76] Allow CMAKE_INSTALL_RPATH_USE_LINK_PATH --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c611e5a55fb..57253f61cdb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -356,16 +356,16 @@ else() # (but later on when installing) set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) - # add the automatically determined parts of the RPATH - # which point to directories outside the build tree to the install RPATH - set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) - # the RPATH to be used when installing, but only if it's not a system directory list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_FULL_LIBDIR}" isSystemDir) if("${isSystemDir}" STREQUAL "-1") set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}") endif() endif() + +# add the automatically determined parts of the RPATH +# which point to directories outside the build tree to the install RPATH +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) #=============================================================================== # libopenmc #=============================================================================== From 32d96e2d4cdfab80e90dd316265b360a32e61cd4 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sun, 20 Oct 2024 18:07:35 +0600 Subject: [PATCH 73/76] renamed to GenerateScript.cmake --- CMakeLists.txt | 11 ++++----- ...UILDScripts.cmake => GenerateScript.cmake} | 23 +++++++++++++------ 2 files changed, 20 insertions(+), 14 deletions(-) rename cmake/{SKBUILDScripts.cmake => GenerateScript.cmake} (55%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 57253f61cdb..31bc71fa0ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,9 @@ foreach(OLD_BLD in ITEMS "debug" "optimize") endif() endforeach() +# Include the GenerateScript.cmake file +include(cmake/GenerateScript.cmake) + #=============================================================================== # Set a default build configuration if not explicitly specified #=============================================================================== @@ -628,8 +631,7 @@ target_compile_features(openmc PUBLIC cxx_std_17) target_compile_features(libopenmc PUBLIC cxx_std_17) set_target_properties(openmc libopenmc PROPERTIES CXX_EXTENSIONS OFF) -# Add openmc executable to SKBUILD_SCRIPT_LIST -list(APPEND SKBUILD_SCRIPT_LIST openmc) +generate_and_install_python_script(openmc) # Set rpath for openmc executable if(OPENMC_BINARY_RPATH) @@ -677,11 +679,6 @@ else() install(PROGRAMS ${SCRIPTS} DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() -# Generate and install the SKBUILD scripts -if(SKBUILD) - generate_and_install_scripts(${SKBUILD_SCRIPT_LIST}) -endif() - install(FILES "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfig.cmake" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfigVersion.cmake" diff --git a/cmake/SKBUILDScripts.cmake b/cmake/GenerateScript.cmake similarity index 55% rename from cmake/SKBUILDScripts.cmake rename to cmake/GenerateScript.cmake index da86ee801f1..553c3dc1627 100644 --- a/cmake/SKBUILDScripts.cmake +++ b/cmake/GenerateScript.cmake @@ -1,8 +1,17 @@ -# Function to create and install the binary scripts -function(generate_and_install_scripts SCRIPT_LIST) - foreach(SCRIPT_NAME ${SCRIPT_LIST}) - # Define the output path for each generated script - set(GENERATED_SCRIPT "${CMAKE_BINARY_DIR}/${SCRIPT_NAME}") +# Function to generate and install a Python script +# This function creates a Python script with a specified name, writes content to it, +# and installs it to a specified location. +# +# Arguments: +# SCRIPT_NAME - The name of the script to be generated (e.g., 'my_script'). +# +function(generate_and_install_python_script SCRIPT_NAME) + if(SKBUILD) + # Strip any leading/trailing whitespace from the script name + string(STRIP "${SCRIPT_NAME}" CLEAN_SCRIPT_NAME) + + # Define the output path for the generated script using the cleaned name + set(GENERATED_SCRIPT "${CMAKE_BINARY_DIR}/${CLEAN_SCRIPT_NAME}") # Generate the script content directly file(WRITE "${GENERATED_SCRIPT}" "#!/usr/bin/env python3\n\n") @@ -11,7 +20,7 @@ function(generate_and_install_scripts SCRIPT_LIST) file(APPEND "${GENERATED_SCRIPT}" "import sysconfig\n\n") file(APPEND "${GENERATED_SCRIPT}" "if __name__ == '__main__':\n") file(APPEND "${GENERATED_SCRIPT}" " os.execv(\n") - file(APPEND "${GENERATED_SCRIPT}" " os.path.join(sysconfig.get_path('platlib'), '${SKBUILD_PROJECT_NAME}', '${CMAKE_INSTALL_BINDIR}', '${SCRIPT_NAME}'),\n") + file(APPEND "${GENERATED_SCRIPT}" " os.path.join(sysconfig.get_path('platlib'), '${SKBUILD_PROJECT_NAME}', '${CMAKE_INSTALL_BINDIR}', '${CLEAN_SCRIPT_NAME}'),\n") file(APPEND "${GENERATED_SCRIPT}" " sys.argv,\n") file(APPEND "${GENERATED_SCRIPT}" " )\n") @@ -20,5 +29,5 @@ function(generate_and_install_scripts SCRIPT_LIST) PROGRAMS "${GENERATED_SCRIPT}" DESTINATION "${SKBUILD_SCRIPTS_DIR}" ) - endforeach() + endif() endfunction() From f52ff64e17003e1c39493ed126b90097e62b7460 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Sun, 20 Oct 2024 18:16:23 +0600 Subject: [PATCH 74/76] remove SKBUILDScripts --- CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 31bc71fa0ae..36fb0fada6c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -338,9 +338,6 @@ if(SKBUILD) set(CMAKE_INSTALL_LOCALEDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_LOCALEDIR}) set(CMAKE_INSTALL_LOCALSTATEDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_LOCALSTATEDIR}) set(CMAKE_INSTALL_RUNSTATEDIR ${SKBUILD_DATA_DIR}/${CMAKE_INSTALL_RUNSTATEDIR}) - - # Include the SKBUILDScripts.cmake file - include(cmake/SKBUILDScripts.cmake) # Set RPATH if(APPLE) From d1f8ae338ecd218123489306c595f8ddce4d1154 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Tue, 22 Oct 2024 09:40:24 +0600 Subject: [PATCH 75/76] revert --- tests/regression_tests/triso/results_true.dat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression_tests/triso/results_true.dat b/tests/regression_tests/triso/results_true.dat index a24354045e2..fa1842e547d 100644 --- a/tests/regression_tests/triso/results_true.dat +++ b/tests/regression_tests/triso/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.716873E+00 5.266094E-02 +1.716873E+00 5.266107E-02 From ddb6c96ef1339d45759e4d1f7d83ff7391e0aff4 Mon Sep 17 00:00:00 2001 From: Ahnaf Tahmid Chowdhury Date: Tue, 22 Oct 2024 09:58:54 +0600 Subject: [PATCH 76/76] update to 1.8 --- .github/workflows/docker-publish-manylinux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-publish-manylinux.yml b/.github/workflows/docker-publish-manylinux.yml index 073b9db5074..8dacdd556b6 100644 --- a/.github/workflows/docker-publish-manylinux.yml +++ b/.github/workflows/docker-publish-manylinux.yml @@ -52,7 +52,7 @@ jobs: echo "image_base_tag=${image_base_tag}" >> "$GITHUB_ENV" - name: Installing Dependencies in Docker image - uses: firehed/multistage-docker-build-action@v1 + uses: firehed/multistage-docker-build-action@v1.8 with: repository: ${{ env.image_base_tag }} stages: base, dependencies, python-dependencies