diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000..cc25c05 --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,157 @@ +name: CI + +on: + push: + branches: + - "master" + pull_request: + branches: + - "master" + schedule: + # Nightly tests run on master by default: + # Scheduled workflows run on the latest commit on the default or base branch. + # (from https://help.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events-schedule) + - cron: "0 0 * * *" + + +jobs: + unix: + runs-on: ${{ matrix.os }} + name: ${{ matrix.name }} + strategy: + fail-fast: false + matrix: + include: + - name: Linux CPU CUDA 11.0 Python 3.6 + python-version: "3.6" + os: ubuntu-latest + gcc-version: "9" + cuda-version: "11.0" + cdt-name: cos7 # CentOS sysroot: cuda 10.x needs cos6, 11+ needs cos7 + CMAKE_FLAGS: | + -DPLUMED_BUILD_CUDA_LIB=ON \ + -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda \ + -DEXTRA_COMPILE_FLAGS="-L/usr/local/cuda/lib64/stubs -Wl,-rpath,/usr/local/cuda/lib64/stubs -Wl,-rpath-link,/usr/local/cuda/lib64/stubs" + + - name: MacOS Intel CPU OpenCL Python 3.9 + python-version: "3.9" + os: macos-latest + cuda-version: "" + CMAKE_FLAGS: "" + + steps: + - uses: actions/checkout@v2 + + - name: "Patch conda env (if needed)" + if: startsWith(matrix.os, 'ubuntu') + run: | + sed -i -e "s/@CDT_NAME@/${{ matrix.cdt-name }}/g" \ + -e "s/@GCC_VERSION@/${{ matrix.gcc-version }}.*/g" \ + -e "s/@CUDATOOLKIT_VERSION@/${{ matrix.cuda-version }}.*/g" \ + devtools/conda-envs/build-${{ matrix.os }}.yml + + - uses: conda-incubator/setup-miniconda@v2 + name: "Prepare base dependencies" + with: + python-version: ${{ matrix.python-version }} + activate-environment: build + environment-file: devtools/conda-envs/build-${{ matrix.os }}.yml + auto-activate-base: false + channels: conda-forge + + - name: "Install CUDA on Ubuntu (if needed)" + if: matrix.cuda-version != '' + env: + CUDA_VERSION: ${{ matrix.cuda-version }} + run: source devtools/scripts/install_cuda.sh + + - name: "Set SDK on MacOS (if needed)" + if: startsWith(matrix.os, 'macos') + run: source devtools/scripts/install_macos_sdk.sh + + - name: "Conda info" + shell: bash -l {0} + run: | + conda info -a + conda list + + - name: Patch Plumed's Lepton location + shell: bash -l {0} + run: | + test -d ${CONDA_PREFIX}/include/plumed/lepton && mv ${CONDA_PREFIX}/include/plumed/lepton ${CONDA_PREFIX}/include/plumed/lepton.bak + + - name: "Configure build with CMake" + shell: bash -l {0} + run: | + mkdir build + cd build + + SHLIB_EXT=".so" + if [[ ${{ matrix.os }} == macos-* ]]; then + SHLIB_EXT=".dylib" + fi + + cmake .. \ + -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} \ + -DCMAKE_PREFIX_PATH=${CONDA_PREFIX} \ + -DCMAKE_BUILD_TYPE=Release \ + -DOPENMM_DIR=${CONDA_PREFIX} \ + -DPLUMED_INCLUDE_DIR=${CONDA_PREFIX}/include/plumed \ + -DPLUMED_LIBRARY_DIR=${CONDA_PREFIX}/lib \ + -DPLUMED_BUILD_OPENCL_LIB=ON \ + -DOPENCL_INCLUDE_DIR=${CONDA_PREFIX}/include \ + -DOPENCL_LIBRARY=${CONDA_PREFIX}/lib/libOpenCL${SHLIB_EXT} \ + ${{ matrix.CMAKE_FLAGS }} + + - name: "Build" + shell: bash -l {0} + run: | + cd build + make -j2 install + make -j2 PythonInstall + + - name: "Plugin information" + shell: bash -l {0} + run: | + python -c "import simtk.openmm as mm; print('---Loaded---', *mm.pluginLoadedLibNames, '---Failed---', *mm.Platform.getPluginLoadFailures(), sep='\n')" + + - name: "Test C++" + shell: bash -l {0} + run: | + set +e + cd build + if [[ ${{ matrix.os }} == ubuntu-* ]]; then + test_files=$(find . -name "Test*" -executable -type f) + else + test_files=$(find . -name "Test*" -perm +0111 -type f) + fi + summary="" + exitcode=0 + for f in $test_files; do + fn=$(basename $f) + echo "::group::$fn" + summary+="\n${fn}: " + if [[ $fn == *Cuda* ]]; then + echo "Skipping $fn..." + summary+="Skipped" + echo "::endgroup::" + continue + fi + echo "Running $fn..." + ./${f} + thisexitcode=$? + if [[ $thisexitcode == 0 ]]; then summary+="OK"; else summary+="FAILED"; fi + ((exitcode+=$thisexitcode)) + echo "::endgroup::" + done + echo "-------" + echo "Summary" + echo "-------" + echo -e "${summary}" + exit $exitcode + + - name: "Test Python" + shell: bash -l {0} + run: | + cd python/tests + pytest -v Test* diff --git a/README.md b/README.md index d7b13bd..8dce629 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +[![GH Actions Status](https://github.com/openmm/openmm-plumed/workflows/CI/badge.svg)](https://github.com/openmm/openmm-plumed/actions?query=branch%3Amaster+workflow%3ACI) +[![Conda](https://img.shields.io/conda/v/conda-forge/openmm-plumed.svg)](https://anaconda.org/conda-forge/openmm-plumed) +[![Anaconda Cloud Badge](https://anaconda.org/conda-forge/openmm-plumed/badges/downloads.svg)](https://anaconda.org/conda-forge/openmm-plumed) + OpenMM PLUMED Plugin ===================== diff --git a/devtools/conda-envs/build-macos-latest.yml b/devtools/conda-envs/build-macos-latest.yml new file mode 100644 index 0000000..4e9818e --- /dev/null +++ b/devtools/conda-envs/build-macos-latest.yml @@ -0,0 +1,18 @@ +name: build +channels: +- conda-forge +dependencies: +# build +- cmake +- make +- compilers +# host +- python +- pip +- swig +- openmm +- plumed >=2.7 +- khronos-opencl-icd-loader +- pocl +# test +- pytest diff --git a/devtools/conda-envs/build-ubuntu-latest.yml b/devtools/conda-envs/build-ubuntu-latest.yml new file mode 100644 index 0000000..d9431c9 --- /dev/null +++ b/devtools/conda-envs/build-ubuntu-latest.yml @@ -0,0 +1,25 @@ +name: build +channels: +- conda-forge +dependencies: +# build +- cmake +- make +- gcc_linux-64 @GCC_VERSION@ +- gxx_linux-64 @GCC_VERSION@ +- libx11-common-@CDT_NAME@-x86_64 +- libx11-@CDT_NAME@-x86_64 +- mesa-dri-drivers-@CDT_NAME@-x86_64 +- mesa-libgl-@CDT_NAME@-x86_64 +- mesa-libgl-devel-@CDT_NAME@-x86_64 +# host +- python +- pip +- swig +- openmm +- plumed >=2.7 +- ocl-icd +- cudatoolkit @CUDATOOLKIT_VERSION@ +- pocl +# test +- pytest diff --git a/devtools/scripts/install_cuda.sh b/devtools/scripts/install_cuda.sh new file mode 100644 index 0000000..bab49f5 --- /dev/null +++ b/devtools/scripts/install_cuda.sh @@ -0,0 +1,47 @@ +# This script install CUDA on Ubuntu-based systemws +# It uses the Nvidia repos for Ubuntu 18.04, which as of Dec 2020 +# includes packages for CUDA 10.0, 10.1, 10.2, 11.0, 11.1, 11.2 +# Future versions might require an updated repo (maybe Ubuntu 20) +# It expects a $CUDA_VERSION environment variable set to major.minor (e.g. 10.0) + +set -euxo pipefail + +# Enable retrying +echo 'APT::Acquire::Retries "5";' | sudo tee /etc/apt/apt.conf.d/80-retries + +sudo wget --retry-connrefused --waitretry=1 --read-timeout=20 --timeout=15 --tries 5 \ + -O /etc/apt/preferences.d/cuda-repository-pin-600 \ + https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-ubuntu1804.pin +sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub +sudo add-apt-repository "deb http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/ /" +sudo apt-get update -qq + +CUDA_APT=${CUDA_VERSION/./-} +## cufft changed package names in CUDA 11 +if [[ ${CUDA_VERSION} == 10.* ]]; then CUFFT="cuda-cufft"; else CUFFT="libcufft"; fi +sudo apt-get install -y \ + libgl1-mesa-dev cuda-compiler-${CUDA_APT} \ + cuda-drivers cuda-driver-dev-${CUDA_APT} \ + cuda-cudart-${CUDA_APT} cuda-cudart-dev-${CUDA_APT} \ + ${CUFFT}-${CUDA_APT} ${CUFFT}-dev-${CUDA_APT} \ + cuda-nvprof-${CUDA_APT} tree +sudo apt-get clean + +if [[ ! -d /usr/local/cuda ]]; then + sudo ln -s /usr/local/cuda-${CUDA_VERSION} /usr/local/cuda +fi + +if [[ -f /usr/local/cuda-${CUDA_VERSION}/lib64/stubs/libcuda.so ]]; then + sudo ln -s /usr/local/cuda-${CUDA_VERSION}/lib64/stubs/libcuda.so /usr/local/cuda-${CUDA_VERSION}/lib64/stubs/libcuda.so.1 +fi + +# Remove Nvidia's OpenCL +sudo rm -rf /usr/local/cuda-${CUDA_VERSION}/lib64/libOpenCL.* /usr/local/cuda-${CUDA_VERSION}/include/CL /etc/OpenCL/vendors/nvidia.icd + +export CUDA_HOME="/usr/local/cuda" +export CUDA_PATH="/usr/local/cuda" +export PATH="${CUDA_HOME}/bin:${PATH}" + +echo "CUDA_HOME=${CUDA_HOME}" >> ${GITHUB_ENV} +echo "CUDA_PATH=${CUDA_PATH}" >> ${GITHUB_ENV} +echo "PATH=${PATH}" >> ${GITHUB_ENV} diff --git a/devtools/scripts/install_macos_sdk.sh b/devtools/scripts/install_macos_sdk.sh new file mode 100644 index 0000000..85b1616 --- /dev/null +++ b/devtools/scripts/install_macos_sdk.sh @@ -0,0 +1,31 @@ +# Install an older MacOS SDK +# This should guarantee OpenMM builds with extended compatibility across MacOS versions +# Adapted from conda-forge-ci-setup scripts: +# * https://github.com/conda-forge/conda-forge-ci-setup-feedstock/blob/dde296e/recipe/run_conda_forge_build_setup_osx +# * https://github.com/conda-forge/conda-forge-ci-setup-feedstock/blob/dde296e/recipe/download_osx_sdk.sh +# +# Some possible updates might involve upgrading the download link to future MacOS releases (10.15 to something else), +# depending on the version provided by the CI + +OSX_SDK_DIR="$(xcode-select -p)/Platforms/MacOSX.platform/Developer/SDKs" +export MACOSX_DEPLOYMENT_TARGET=10.9 +export MACOSX_SDK_VERSION=10.9 + +export CMAKE_OSX_SYSROOT="${OSX_SDK_DIR}/MacOSX${MACOSX_SDK_VERSION}.sdk" + +if [[ ! -d ${CMAKE_OSX_SYSROOT}} ]]; then + echo "Downloading ${MACOSX_SDK_VERSION} sdk" + curl -L -O --connect-timeout 5 --max-time 10 --retry 5 --retry-delay 0 --retry-max-time 40 --retry-connrefused --retry-all-errors \ + https://github.com/phracker/MacOSX-SDKs/releases/download/10.15/MacOSX${MACOSX_SDK_VERSION}.sdk.tar.xz + tar -xf MacOSX${MACOSX_SDK_VERSION}.sdk.tar.xz -C "$(dirname ${CMAKE_OSX_SYSROOT})" +fi + +if [[ "$MACOSX_DEPLOYMENT_TARGET" == 10.* ]]; then +# set minimum sdk version to our target +plutil -replace MinimumSDKVersion -string ${MACOSX_SDK_VERSION} $(xcode-select -p)/Platforms/MacOSX.platform/Info.plist +plutil -replace DTSDKName -string macosx${MACOSX_SDK_VERSION}internal $(xcode-select -p)/Platforms/MacOSX.platform/Info.plist +fi + +echo "MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET}" >> ${GITHUB_ENV} +echo "CMAKE_OSX_SYSROOT=${MACOSX_DEPLOYMENT_TARGET}" >> ${GITHUB_ENV} +echo "CMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT}" >> ${GITHUB_ENV} \ No newline at end of file