diff --git a/config.yaml b/config.yaml index 547591dbc..604c00f97 100644 --- a/config.yaml +++ b/config.yaml @@ -102,17 +102,21 @@ uenvs: a100: 2023/a100 gh200: 2023/gh200-mpi deploy: - # deploy to both the production and test clusters eiger: [zen2] "2024": recipes: zen2: 2024/mc gh200: 2024/gh200-mpi deploy: - # deploy to both the production and test clusters santis: [gh200] daint: [gh200] eiger: [zen2] + "2025": + recipes: + gh200: 2025/gh200-mpi + deploy: + santis: [gh200] + daint: [gh200] cp2k: "2024.1": recipes: diff --git a/recipes/gromacs/2025/gh200-mpi-pytorch/compilers.yaml b/recipes/gromacs/2025/gh200-mpi-pytorch/compilers.yaml new file mode 100644 index 000000000..3a2d2fc46 --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi-pytorch/compilers.yaml @@ -0,0 +1,2 @@ +gcc: + version: "13" diff --git a/recipes/gromacs/2025/gh200-mpi-pytorch/config.yaml b/recipes/gromacs/2025/gh200-mpi-pytorch/config.yaml new file mode 100644 index 000000000..cb6bebf8f --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi-pytorch/config.yaml @@ -0,0 +1,11 @@ +name: gromacs-gh200-pytorch +store: /user-environment +description: GPU-optimised GROMACS with PLUMED and PyTorch, and the toolchain to build your own GROMACS. +spack: + repo: https://github.com/spack/spack.git + commit: releases/v1.0 + packages: + repo: https://github.com/spack/spack-packages.git + commit: f5e96586306f35c10c473b9fc2f33e561f711373 +modules: false +version: 2 diff --git a/recipes/gromacs/2025/gh200-mpi-pytorch/environments.yaml b/recipes/gromacs/2025/gh200-mpi-pytorch/environments.yaml new file mode 100644 index 000000000..ae08e5db4 --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi-pytorch/environments.yaml @@ -0,0 +1,35 @@ +gromacs-pytorch: + compiler: [gcc] + network: + mpi: cray-mpich@8.1.32 +cuda + unify: when_possible + specs: + - cmake + - cuda@12.9 + - blas + - lapack + - hwloc + - fftw + - python@3.12 + - py-torch@2.8.0 ~nccl ~distributed + - plumed@2.10 +pytorch +mpi + - gromacs@2025.0 +cuda +plumed +mpi +hwloc + packages: + - perl + variants: + - +mpi + - +cuda + - cuda_arch=90a + views: + develop: + exclude: ['gromacs'] + uenv: + add_compilers: true + prefix_paths: + LD_LIBRARY_PATH: [lib, lib64] + gromacs: + link: run + uenv: + add_compilers: true + prefix_paths: + LD_LIBRARY_PATH: [lib, lib64] \ No newline at end of file diff --git a/recipes/gromacs/2025/gh200-mpi-pytorch/extra/reframe.yaml b/recipes/gromacs/2025/gh200-mpi-pytorch/extra/reframe.yaml new file mode 100644 index 000000000..f6224e3d0 --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi-pytorch/extra/reframe.yaml @@ -0,0 +1,19 @@ +run: + features: + - gromacs + - cuda + - mpi + cc: gcc + cxx: g++ + views: + - gromacs + +build: + features: + - gromacs-dev + - cuda + - mpi + cc: gcc + cxx: g++ + views: + - develop \ No newline at end of file diff --git a/recipes/gromacs/2025/gh200-mpi-pytorch/repo/packages/gromacs/gmxDetectCpu-cmake-3.14.patch b/recipes/gromacs/2025/gh200-mpi-pytorch/repo/packages/gromacs/gmxDetectCpu-cmake-3.14.patch new file mode 100644 index 000000000..2f94a6a99 --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi-pytorch/repo/packages/gromacs/gmxDetectCpu-cmake-3.14.patch @@ -0,0 +1,12 @@ +--- a/cmake/gmxDetectCpu.cmake ++++ b/cmake/gmxDetectCpu.cmake +@@ -83,7 +83,7 @@ function(gmx_run_cpu_detection TYPE) + set(GCC_INLINE_ASM_DEFINE "-DGMX_X86_GCC_INLINE_ASM=0") + endif() + +- set(_compile_definitions "${GCC_INLINE_ASM_DEFINE} -I${PROJECT_SOURCE_DIR}/src -DGMX_CPUINFO_STANDALONE ${GMX_STDLIB_CXX_FLAGS} -DGMX_TARGET_X86=${GMX_TARGET_X86_VALUE}") ++ set(_compile_definitions ${GCC_INLINE_ASM_DEFINE} -I${PROJECT_SOURCE_DIR}/src -DGMX_CPUINFO_STANDALONE ${GMX_STDLIB_CXX_FLAGS} -DGMX_TARGET_X86=${GMX_TARGET_X86_VALUE}) + set(LINK_LIBRARIES "${GMX_STDLIB_LIBRARIES}") + try_compile(CPU_DETECTION_COMPILED + "${PROJECT_BINARY_DIR}" + diff --git a/recipes/gromacs/2025/gh200-mpi-pytorch/repo/packages/gromacs/gmxDetectSimd-cmake-3.14.patch b/recipes/gromacs/2025/gh200-mpi-pytorch/repo/packages/gromacs/gmxDetectSimd-cmake-3.14.patch new file mode 100644 index 000000000..f30ec78a7 --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi-pytorch/repo/packages/gromacs/gmxDetectSimd-cmake-3.14.patch @@ -0,0 +1,11 @@ +--- a/cmake/gmxDetectSimd.cmake ++++ b/cmake/gmxDetectSimd.cmake +@@ -77,7 +77,7 @@ function(gmx_suggest_simd _suggested_simd) + else() + set(GMX_TARGET_X86_VALUE 0) + endif() +- set(_compile_definitions "${GCC_INLINE_ASM_DEFINE} -I${CMAKE_SOURCE_DIR}/src -DGMX_CPUINFO_STANDALONE ${GMX_STDLIB_CXX_FLAGS} -DGMX_TARGET_X86=${GMX_TARGET_X86_VALUE}") ++ set(_compile_definitions ${GCC_INLINE_ASM_DEFINE} -I${CMAKE_SOURCE_DIR}/src -DGMX_CPUINFO_STANDALONE ${GMX_STDLIB_CXX_FLAGS} -DGMX_TARGET_X86=${GMX_TARGET_X86_VALUE}) + + # Prepare a default suggestion + set(OUTPUT_SIMD "None") diff --git a/recipes/gromacs/2025/gh200-mpi-pytorch/repo/packages/gromacs/package.py b/recipes/gromacs/2025/gh200-mpi-pytorch/repo/packages/gromacs/package.py new file mode 100644 index 000000000..1273bcd54 --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi-pytorch/repo/packages/gromacs/package.py @@ -0,0 +1,834 @@ +# Copyright Spack Project Developers. See COPYRIGHT file for details. +# +# SPDX-License-Identifier: (Apache-2.0 OR MIT) + +import os + +from spack_repo.builtin.build_systems import cmake +from spack_repo.builtin.build_systems.cmake import CMakePackage +from spack_repo.builtin.build_systems.cuda import CudaPackage + +from spack.package import * + + +class Gromacs(CMakePackage, CudaPackage): + """GROMACS is a molecular dynamics package primarily designed for simulations + of proteins, lipids and nucleic acids. It was originally developed in + the Biophysical Chemistry department of University of Groningen, and is now + maintained by contributors in universities and research centers across the world. + + GROMACS is one of the fastest and most popular software packages + available and can run on CPUs as well as GPUs. It is free, open source + released under the GNU Lesser General Public License. Before the version 4.6, + GROMACS was released under the GNU General Public License. + """ + + homepage = "https://www.gromacs.org" + url = "https://ftp.gromacs.org/gromacs/gromacs-2022.2.tar.gz" + list_url = "https://ftp.gromacs.org/gromacs" + git = "https://gitlab.com/gromacs/gromacs.git" + + maintainers("mabraham", "eirrgang", "junghans") + + license("GPL-2.0-or-later", when="@:4.5") + license("LGPL-2.1-or-later", when="@4.6:") + + # Deprecation policy: + # + # GROMACS makes an annual major release and supports it with fixes + # in minor updates for about two years. Each such annual release + # series is supported in spack for those two years, then marked as + # deprecated in Spack. Deprecated versions can be removed after + # the next major release of GROMACS is supported in Spack. Users + # needing such an old version can either do a manual installation + # or get an older version of Spack. + # + # Exception: Version 2019.6 is the last version capable of tabulated + # interactions used in the so-called "group scheme." It will be marked + # as deprecated only after equivalent functionality is available in + # a major release of GROMACS, then removed as above. + # + # Exception: Otherwise, versions before 2022 will be removed when + # 2025 is supported. + version("main", branch="main") + version("master", branch="main", deprecated=True) + version("2025.2", sha256="0df09f9d45a99ef00e66b9baa9493a27e906813763a3b6c7672217c66b43ea11") + version("2025.1", sha256="0adf621a80fd8043f8defec84ce02811c0cdf42a052232890932d81f25c4d28a") + version("2025.0", sha256="a27ad35a646295bbec129abe684d9d03d1e2e0bd76b0d625e9055746aaefae82") + version("2024.5", sha256="fecf06b186cddb942cfb42ee8da5f3eb2b9993e6acc0a2f18d14ac0b014424f3") + version("2024.4", sha256="ac618ece2e58afa86b536c5a2c4fcb937f0760318f12d18f10346b6bdebd86a8") + version("2024.3", sha256="bbda056ee59390be7d58d84c13a9ec0d4e3635617adf2eb747034922cba1f029") + version("2024.2", sha256="802a7e335f2e895770f57b159e4ec368ebb0ff2ce6daccf706c6e8025c36852b") + version("2024.1", sha256="937d8f12a36fffbf2af7add71adbb5aa5c5537892d46c9a76afbecab1aa0aac7") + version("2024", sha256="04d226d52066a8bc3a42e00d6213de737b4ec292e26703065924ff01956801e2") + version( + "2023.5", + sha256="9cc491d3601a5fe0ec0de727e4432c34877f596fe8a463d4cf0f0f53fb34d08b", + ) + version( + "2023.4", + sha256="e5d6c4d9e7ccacfaccb0888619bd21b5ea8911f82b410e68d6db5d40f695f231", + deprecated=True, + ) + version( + "2023.3", + sha256="4ec8f8d0c7af76b13f8fd16db8e2c120e749de439ae9554d9f653f812d78d1cb", + deprecated=True, + ) + version( + "2023.2", + sha256="bce1480727e4b2bb900413b75d99a3266f3507877da4f5b2d491df798f9fcdae", + deprecated=True, + ) + version( + "2023.1", + sha256="eef2bb4a6cb6314cf9da47f26df2a0d27af4bf7b3099723d43601073ab0a42f4", + ) + version( + "2023", + sha256="ac92c6da72fbbcca414fd8a8d979e56ecf17c4c1cdabed2da5cfb4e7277b7ba8", + ) + version( + "2022.6", + sha256="75d277138475679dd3e334e384a71516570cde767310476687f2a5b72333ea41", + deprecated=True, + ) + version( + "2022.5", + sha256="083cc3c424bb93ffe86c12f952e3e5b4e6c9f6520de5338761f24b75e018c223", + ) + version( + "2022.4", + sha256="c511be602ff29402065b50906841def98752639b92a95f1b0a1060d9b5e27297", + deprecated=True, + ) + version( + "2022.3", + sha256="14cfb130ddaf8f759a3af643c04f5a0d0d32b09bc3448b16afa5b617f5e35dae", + deprecated=True, + ) + version( + "2022.2", + sha256="656404f884d2fa2244c97d2a5b92af148d0dbea94ad13004724b3fcbf45e01bf", + deprecated=True, + ) + version( + "2022.1", + sha256="85ddab5197d79524a702c4959c2c43be875e0fc471df3a35224939dce8512450", + deprecated=True, + ) + version( + "2022", + sha256="fad60d606c02e6164018692c6c9f2c159a9130c2bf32e8c5f4f1b6ba2dda2b68", + deprecated=True, + ) + # See exception documented above + version("2019.6", sha256="bebe396dc0db11a9d4cc205abc13b50d88225617642508168a2195324f06a358") + + depends_on("c", type="build") + depends_on("cxx", type="build") + depends_on("fortran", type="build", when="@:4.5.5") # No core Fortran code since 4.6 + depends_on("fortran", type="build", when="+cp2k") # Need Fortan compiler for CP2K + + variant( + "mpi", default=True, description="Activate MPI support (disable for Thread-MPI support)" + ) + variant("shared", default=True, description="Enables the build of shared libraries") + variant( + "double", + default=False, + description="Produces a double precision version of the executables", + ) + variant( + "cufftmp", + default=False, + when="@2022: +cuda+mpi", + description="Enable multi-GPU FFT support with cuFFTMp", + ) + variant( + "heffte", + default=False, + when="@2021: +mpi", + description="Enable multi-GPU FFT support with HeFFTe", + ) + depends_on("heffte +cuda", when="+heffte +cuda") + depends_on("heffte +sycl", when="+heffte +sycl") + variant("opencl", default=False, description="Enable OpenCL support") + variant("sycl", default=False, when="@2021:", description="Enable SYCL support") + requires( + "^intel-oneapi-runtime", + "^hipsycl %clang", + policy="one_of", + when="+sycl", + msg="GROMACS SYCL support comes either from intel-oneapi-runtime or a " + + "package that provides the virtual package `sycl`, such as AdaptiveCpp " + + "plus a clang compiler.", + ) + variant( + "intel-data-center-gpu-max", + default=False, + when="@2022: +sycl", + description="Enable support for Intel Data Center GPU Max", + ) + variant("nosuffix", default=False, description="Disable default suffixes") + variant( + "build_type", + default="Release", + description="The build type to build", + values=( + "Debug", + "Release", + "RelWithDebInfo", + "MinSizeRel", + "Reference", + "RelWithAssert", + "Profile", + ), + ) + variant( + "nblib", + default=True, + when="@2021:", + description="Build and install the NB-LIB C++ API for GROMACS", + ) + variant( + "gmxapi", + default=True, + when="@2019:", + description="Build and install the gmxlib python API for GROMACS", + ) + variant( + "mdrun_only", + default=False, + description="Enables the build of a cut-down version" + " of libgromacs and/or the mdrun program", + ) + conflicts( + "+mdrun_only", when="@2021:", msg="mdrun-only build option was removed for GROMACS 2021." + ) + variant( + "nvshmem", + default=False, + when="@2024:+mpi+cuda", + description="Enable NVSHMEM support for Nvidia GPUs", + ) + conflicts( + "+nvshmem", + when="+cufftmp", + msg=( + "The GROMACS support for NVSHMEM does not work with the GROMACS support " + "for cuFFTMp (even though cuFFTMp uses NVSHMEM in its implementation)" + ), + ) + + variant("openmp", default=True, description="Enables OpenMP at configure time") + conflicts( + "+openmp", when="%apple-clang", msg="OpenMP not available for the Apple clang compiler" + ) + variant("openmp_max_threads", default="none", description="Max number of OpenMP threads") + conflicts( + "+openmp_max_threads", when="~openmp", msg="OpenMP is off but OpenMP Max threads is set" + ) + variant( + "sve", + default=True, + description="Enable SVE on aarch64 if available", + when="target=neoverse_v1:,neoverse_v2:,neoverse_n2:", + ) + variant( + "sve", default=True, description="Enable SVE on aarch64 if available", when="target=a64fx" + ) + variant( + "relaxed_double_precision", + default=False, + description="GMX_RELAXED_DOUBLE_PRECISION, use only for Fujitsu PRIMEHPC", + ) + conflicts( + "+relaxed_double_precision", + when="@2021:", + msg="GMX_RELAXED_DOUBLE_PRECISION option removed for GROMACS 2021.", + ) + variant("hwloc", default=True, description="Use the hwloc portable hardware locality library") + variant("cycle_subcounters", default=False, description="Enables cycle subcounters") + + variant("cp2k", default=False, description="CP2K QM/MM interface integration") + conflicts( + "+cp2k", when="@:2021", msg="CP2K QM/MM support have been introduced in GROMACS 2022" + ) + conflicts("+shared", when="+cp2k", msg="Enabling CP2K requires static build") + conflicts("%intel", when="@2022:", msg="GROMACS %intel support was removed in version 2022") + conflicts("%gcc@:8", when="@2023:", msg="GROMACS requires GCC 9 or later since version 2023") + conflicts( + "^intel-oneapi-mkl@:2021.2", + when="@2023:", + msg="GROMACS requires oneMKL 2021.3 or later since version 2023", + ) + + depends_on("mpi", when="+mpi") + + # Plumed 2.9.0 needs Gromacs 2023, 2022.5, 2021.7, 2020.7 + # Plumed 2.8.3 needs Gromacs 2022.5, 2021.7, 2020.7, 2019.6 + # Plumed 2.8.2 needs Gromacs 2022.5, 2021.7, 2020.7, 2019.6 + # Plumed 2.8.1 needs Gromacs 2022.3, 2021.6, 2020.7, 2019.6 + # Plumed 2.8.0 needs Gromacs 2021.4, 2020.6, 2019.6 + # Plumed 2.7.6 needs Gromacs 2021.5, 2020.6, 2019.6 + # Plumed 2.7.5 needs Gromacs 2021.5, 2020.6, 2019.6 + # Plumed 2.7.4 needs Gromacs 2021.4, 2020.6, 2019.6 + # Plumed 2.7.3 needs Gromacs 2021.4, 2020.6, 2019.6 + # Plumed 2.7.2 needs Gromacs 2021, 2020.6, 2019.6 + # Plumed 2.7.1 needs Gromacs 2021, 2020.5, 2019.6 + # Plumed 2.7.0 needs Gromacs 2020.4, 2019.6 + # Plumed 2.6.6 needs Gromacs 2020.4, 2019.6, 2018.8 + # Plumed 2.6.5 needs Gromacs 2020.4, 2019.6, 2018.8 + # Plumed 2.6.4 needs Gromacs 2020.4, 2019.6, 2018.8 + # Plumed 2.6.3 needs Gromacs 2020.4, 2019.6, 2018.8 + # Plumed 2.6.2 needs Gromacs 2020.4, 2019.6, 2018.8 + # Plumed 2.6.1 needs Gromacs 2020.2, 2019.6, 2018.8 + # Plumed 2.6.0 needs Gromacs 2019.4, 2018.8 + # Plumed 2.5.7 needs Gromacs 2019.4, 2018.8, 2016.6 + # Plumed 2.5.6 needs Gromacs 2019.4, 2018.8, 2016.6 + # Plumed 2.5.5 needs Gromacs 2019.4, 2018.8, 2016.6 + # Plumed 2.5.4 needs Gromacs 2019.4, 2018.8, 2016.6 + # Plumed 2.5.3 needs Gromacs 2019.4, 2018.8, 2016.6 + # Plumed 2.5.2 needs Gromacs 2019.2, 2018.6, 2016.6 + # Plumed 2.5.1 needs Gromacs 2018.6, 2016.6 + # Plumed 2.5.0 needs Gromacs 2018.4, 2016.5 + + # Above dependencies can be verified, and new versions added, by going to + # https://github.com/plumed/plumed2/tree/v2.9.0/patches + # and switching tags. + + # Versions without minor release number, such as `2023` and `2021`, + # require exact specification using `@=`, starting from Spack v0.20.0, + # see https://github.com/spack/spack/releases/tag/v0.20.0 + + plumed_patches = { + "=2025.0": "2.10.0", + "=2023": "2.9.1", + "2022.5": "2.8.2:2.9.1", + "2022.3": "2.8.1", + "2021.7": "2.8.2:2.9.1", + "2021.6": "2.8.1", + "2021.5": "2.7.5:2.7.6", + "2021.4": "2.7.3:2.8.0", + "=2021": "2.7.1:2.7.2", + "2020.7": "2.8.1:2.9.1", + "2020.6": "2.7.2:2.8.0", + "2020.5": "2.7.1", + "2020.4": "2.6.2:2.7.0", + "2020.2": "2.6.1", + "2019.6": "2.6.1:2.8.3", + "2019.4": "2.5.3:2.6.0", + "2019.2": "2.5.2", + "2018.8": "2.5.3:2.6", + "2018.6": "2.5.1:2.5.2", + "2018.4": "2.5.0", + "2016.6": "2.5.1:2.5", + "2016.5": "2.5.0", + } + + variant( + "plumed", + default=False, + description="Enable PLUMED support", + when="@{0}".format(",".join(plumed_patches.keys())), + ) + with when("+plumed"): + depends_on("plumed+mpi", when="+mpi") + depends_on("plumed~mpi", when="~mpi") + for gmx_ver, plumed_vers in plumed_patches.items(): + depends_on("plumed@{0}".format(plumed_vers), when="@{0}+plumed".format(gmx_ver)) + + variant( + "intel_provided_gcc", + default=False, + description="Use this if Intel compiler is installed through spack. " + + "The g++ location is written to icp{c,x}.cfg", + ) + + variant( + "itt", + default=False, + when="@2024:", + description="Enable Instrumentation and Tracing Technology (ITT)" + + " profiling API (from Intel)", + ) + depends_on("intel-oneapi-vtune", "+itt") + + depends_on("fftw-api@3") + depends_on("cmake@2.8.8:3", type="build") + depends_on("cmake@3.4.3:3", type="build", when="@2018:") + depends_on("cmake@3.9.6:3", type="build", when="@2020") + depends_on("cmake@3.13.0:3", type="build", when="@2021") + depends_on("cmake@3.16.3:3", type="build", when="@2022:") + depends_on("cmake@3.18.4:3", type="build", when="@main") + depends_on("cmake@3.16.0:3", type="build", when="%fj") + depends_on("pkgconfig", type="build") + + depends_on("cuda", when="+cuda") + depends_on("sycl", when="+sycl") + depends_on("lapack") + depends_on("blas") + depends_on("gcc", when="~intel_provided_gcc %intel") + # TODO this can be expanded to all clang-based compilers once + # the principle is demonstrated to work + with when("~intel_provided_gcc %oneapi"): + depends_on("gcc-runtime@5:", when="@2020") + depends_on("gcc-runtime@7:", when="@2021:2022") + depends_on("gcc-runtime@9:", when="@2023:2024") + depends_on("gcc-runtime@11:", when="@2025:") + + depends_on("hwloc@1.0:1", when="+hwloc@2016:2018") + depends_on("hwloc", when="+hwloc@2019:") + + depends_on("cp2k@8.1:", when="+cp2k") + + depends_on("nvhpc", when="+cufftmp") + depends_on("nvhpc", when="+nvshmem") + depends_on("heffte", when="+heffte") + + requires( + "%intel", + "%oneapi", + policy="one_of", + when="+intel_provided_gcc", + msg="Only attempt to find gcc libs for Intel compiler if Intel compiler is used.", + ) + + # If the Intel suite is used for Lapack, it must be used for fftw and vice-versa + requires("^[virtuals=fftw-api] intel-oneapi-mkl", when="^[virtuals=lapack] intel-oneapi-mkl") + requires("^[virtuals=lapack] intel-oneapi-mkl", when="^[virtuals=fftw-api] intel-oneapi-mkl") + + patch("gmxDetectCpu-cmake-3.14.patch", when="@2018:2019.3^cmake@3.14.0:") + patch("gmxDetectSimd-cmake-3.14.patch", when="@5.0:2017^cmake@3.14.0:") + # 2021.2 will always try to build tests (see https://gromacs.bioexcel.eu/t/compilation-failure-for-gromacs-2021-1-and-2021-2-with-cmake-3-20-2/2129) + patch( + "https://gitlab.com/gromacs/gromacs/-/commit/10262892e11a87fda0f59e633c89ed5ab1100509.diff", + sha256="2c30d00404b76421c13866cc42afa5e63276f7926c862838751b158df8727b1b", + when="@2021.1:2021.2", + ) + + filter_compiler_wrappers( + "*.cmake", relative_root=os.path.join("share", "cmake", "gromacs_mpi") + ) + filter_compiler_wrappers("*.cmake", relative_root=os.path.join("share", "cmake", "gromacs")) + + def patch(self): + # Otherwise build fails with GCC 11 (11.2) + if self.spec.satisfies("@2018:2020.6"): + filter_file( + "#include ", + "#include \n#include ", + "src/gromacs/awh/biasparams.h", + ) + if self.spec.satisfies("@2018:2018.8"): + filter_file( + "#include ", + "#include \n#include ", + "src/gromacs/mdlib/minimize.cpp", + ) + if self.spec.satisfies("@2019:2019.6,2020:2020.6"): + filter_file( + "#include ", + "#include \n#include ", + "src/gromacs/mdrun/minimize.cpp", + ) + if self.spec.satisfies("@2020:2020.6"): + filter_file( + "#include ", + "#include \n#include ", + "src/gromacs/modularsimulator/modularsimulator.h", + ) + # Ref: https://gitlab.com/gromacs/gromacs/-/merge_requests/3504 + if self.spec.satisfies("@2023"): + filter_file( + " if (std::filesystem::equivalent(searchPath, buildBinPath))", + " if (std::error_code c; std::filesystem::equivalent(searchPath," + " buildBinPath, c))", + "src/gromacs/commandline/cmdlineprogramcontext.cpp", + string=True, + ) + + if self.spec.satisfies("+plumed"): + self["plumed"].apply_patch(self) + + if self.spec.satisfies("%nvhpc"): + # Disable obsolete workaround + filter_file("ifdef __PGI", "if 0", "src/gromacs/fileio/xdrf.h") + + if self.spec.satisfies("+cuda"): + # Upstream supports building of last two major versions of Gromacs. + # Older versions of Gromacs need to be patched to build with more recent + # versions of CUDA library. + + # Hardware version 3.0 is supported up to CUDA 10.2 (Gromacs 4.6-2020.3 + # needs to be patched, 2020.4 is handling it correctly) + + if self.spec.satisfies("@4.6:2020.3^cuda@11:"): + filter_file( + r"-gencode;arch=compute_30,code=sm_30;?", "", "cmake/gmxManageNvccConfig.cmake" + ) + filter_file( + r"-gencode;arch=compute_30,code=compute_30;?", + "", + "cmake/gmxManageNvccConfig.cmake", + ) + + # Hardware version 2.0 is supported up to CUDA 8 (Gromacs 4.6-2016.3 + # needs to be patched, 2016.4 is handling it correctly, removed in 2019) + + if self.spec.satisfies("@4.6:2016.3^cuda@9:"): + filter_file( + r"-gencode;arch=compute_20,code=sm_20;?", "", "cmake/gmxManageNvccConfig.cmake" + ) + filter_file( + r"-gencode;arch=compute_20,code=compute_20;?", + "", + "cmake/gmxManageNvccConfig.cmake", + ) + + if self.spec.satisfies("@4.6:5.0^cuda@9:"): + filter_file( + r"-gencode;arch=compute_20,code=sm_21;?", "", "cmake/gmxManageNvccConfig.cmake" + ) + + def setup_run_environment(self, env: EnvironmentModifications) -> None: + if self.spec.satisfies("+cufftmp"): + env.append_path( + "LD_LIBRARY_PATH", + join_path( + self.spec["nvhpc"].prefix, + f"Linux_{self.spec.target.family}", + self.spec["nvhpc"].version, + "comm_libs", + "nvshmem", + "lib", + ), + ) + + +class CMakeBuilder(cmake.CMakeBuilder): + @run_after("build") + def build_test_binaries(self): + """Build the test binaries. + + GROMACS usually excludes tests from the default build target, but building + the tests during spack's ``check`` phase takes a long time while producing + no visible output, even with ``--verbose``. + + Here, we make sure the test binaries are built during the build phase + (as would normally be expected when configured with BUILD_TESTING) + when the ``--test`` flag is used. + + Note: the GMX_DEVELOPER_BUILD option disables the EXCLUDE_FROM_ALL on the + test binaries, but the option incurs additional side effects that may + not be intended with ``--test``. + """ + if self.pkg.run_tests: + with working_dir(self.build_directory): + make("tests") + + def check(self): + """Run the ``check`` target (skipping the ``test`` target). + + Override the standard CMakeBuilder behavior. GROMACS has both `test` + and `check` targets, but we are only interested in the latter. + """ + with working_dir(self.build_directory): + if self.generator == "Unix Makefiles": + make("check") + elif self.generator == "Ninja": + ninja("check") + + def cmake_args(self): + options = [] + # Warning: Use `define_from_variant()` with caution. + # GROMACS may use unexpected conventions for CMake variable values. + # For example: variables that accept boolean values like "OFF" + # may actually be STRING type, and undefined variables may trigger + # different defaults for dependent options than explicitly defined variables. + # `-DGMX_VAR=OFF` may not have the same meaning as `-DGMX_VAR=`. + # In other words, the mapping between package variants and the + # GMX CMake variables is often non-trivial. + + if self.spec.satisfies("+mpi"): + options.append("-DGMX_MPI:BOOL=ON") + if self.pkg.version < Version("2020"): + # Ensures gmxapi builds properly + options.extend( + [ + "-DCMAKE_C_COMPILER=%s" % self.spec["mpi"].mpicc, + "-DCMAKE_CXX_COMPILER=%s" % self.spec["mpi"].mpicxx, + "-DCMAKE_Fortran_COMPILER=%s" % self.spec["mpi"].mpifc, + ] + ) + elif self.pkg.version == Version("2021"): + # Work around https://gitlab.com/gromacs/gromacs/-/issues/3896 + # Ensures gmxapi builds properly + options.extend( + [ + "-DCMAKE_C_COMPILER=%s" % self.spec["mpi"].mpicc, + "-DCMAKE_CXX_COMPILER=%s" % self.spec["mpi"].mpicxx, + ] + ) + else: + options.extend( + [ + "-DCMAKE_C_COMPILER=%s" % spack_cc, + "-DCMAKE_CXX_COMPILER=%s" % spack_cxx, + "-DMPI_C_COMPILER=%s" % self.spec["mpi"].mpicc, + "-DMPI_CXX_COMPILER=%s" % self.spec["mpi"].mpicxx, + ] + ) + else: + options.extend( + [ + "-DCMAKE_C_COMPILER=%s" % spack_cc, + "-DCMAKE_CXX_COMPILER=%s" % spack_cxx, + "-DGMX_MPI:BOOL=OFF", + "-DGMX_THREAD_MPI:BOOL=ON", + ] + ) + + if self.spec.satisfies("%aocc"): + options.append("-DCMAKE_CXX_FLAGS=--stdlib=libc++") + + if self.spec.satisfies("@2020:"): + options.append("-DGMX_INSTALL_LEGACY_API=ON") + + if self.spec.satisfies("%oneapi") or self.spec.satisfies("%intel"): + # If intel-oneapi-compilers was installed through spack the gcc is added to the + # configuration file. + if self.spec.satisfies("+intel_provided_gcc") and os.path.exists( + ".".join([os.environ["SPACK_CXX"], "cfg"]) + ): + with open(".".join([os.environ["SPACK_CXX"], "cfg"]), "r") as f: + options.append("-DCMAKE_CXX_FLAGS={}".format(f.read())) + elif self.spec["cxx"].name == "gcc": + options.append("-DGMX_GPLUSPLUS_PATH=%s/g++" % self.spec["gcc"].prefix.bin) + + if self.spec.satisfies("+double"): + options.append("-DGMX_DOUBLE:BOOL=ON") + + if self.spec.satisfies("+nosuffix"): + options.append("-DGMX_DEFAULT_SUFFIX:BOOL=OFF") + + if self.spec.satisfies("~shared"): + options.append("-DBUILD_SHARED_LIBS:BOOL=OFF") + options.append("-DGMXAPI:BOOL=OFF") + + if self.spec.satisfies("+hwloc"): + options.append("-DGMX_HWLOC:BOOL=ON") + else: + options.append("-DGMX_HWLOC:BOOL=OFF") + + if self.pkg.version >= Version("2021"): + if self.spec.satisfies("+cuda"): + options.append("-DGMX_GPU:STRING=CUDA") + elif self.spec.satisfies("+opencl"): + options.append("-DGMX_GPU:STRING=OpenCL") + elif self.spec.satisfies("+sycl"): + options.append("-DGMX_GPU:STRING=SYCL") + else: + options.append("-DGMX_GPU:STRING=OFF") + else: + if self.spec.satisfies("+cuda") or self.spec.satisfies("+opencl"): + options.append("-DGMX_GPU:BOOL=ON") + if self.spec.satisfies("+opencl"): + options.append("-DGMX_USE_OPENCL=ON") + else: + options.append("-DGMX_GPU:BOOL=OFF") + + if self.spec.satisfies("+cuda"): + options.append("-DCUDA_TOOLKIT_ROOT_DIR:STRING=" + self.spec["cuda"].prefix) + if not self.spec.satisfies("cuda_arch=none"): + cuda_arch = self.spec.variants["cuda_arch"].value + options.append(f"-DGMX_CUDA_TARGET_SM:STRING={';'.join(cuda_arch)}") + + options.append("-DGMX_EXTERNAL_LAPACK:BOOL=ON") + if self.spec["lapack"].libs: + options.append("-DGMX_LAPACK_USER={0}".format(self.spec["lapack"].libs.joined(";"))) + + options.append("-DGMX_EXTERNAL_BLAS:BOOL=ON") + if self.spec["blas"].libs: + options.append("-DGMX_BLAS_USER={0}".format(self.spec["blas"].libs.joined(";"))) + + if self.spec.satisfies("+cp2k"): + options.append("-DGMX_CP2K:BOOL=ON") + options.append("-DCP2K_DIR:STRING={0}".format(self.spec["cp2k"].prefix)) + + if self.spec.satisfies("+cufftmp"): + options.append("-DGMX_USE_CUFFTMP=ON") + options.append( + f'-DcuFFTMp_ROOT={self.spec["nvhpc"].prefix}/Linux_{self.spec.target.family}' + + f'/{self.spec["nvhpc"].version}/math_libs' + ) + + if self.spec.satisfies("+heffte"): + options.append("-DGMX_USE_HEFFTE=on") + options.append(f'-DHeffte_ROOT={self.spec["heffte"].prefix}') + + if self.spec.satisfies("+intel-data-center-gpu-max"): + options.append("-DGMX_GPU_NB_CLUSTER_SIZE=8") + options.append("-DGMX_GPU_NB_NUM_CLUSTER_PER_CELL_X=1") + + if "+itt" in self.spec: + options.append("-DGMX_USE_ITT=on") + options.append( + "-DITTNOTIFY_INCLUDE_DIR=%s" + % self.spec["intel-oneapi-vtune"].package.headers.directories[0] + ) + + if self.spec.satisfies("~nblib"): + options.append("-DGMX_INSTALL_NBLIB_API=OFF") + if self.spec.satisfies("~gmxapi"): + options.append("-DGMXAPI=OFF") + + # Activate SIMD based on properties of the target + target = self.spec.target + if target >= "zen4": + # AMD Family 17h (EPYC Genoa) + options.append("-DGMX_SIMD=AVX_512") + elif target >= "zen2": + # AMD Family 17h (EPYC Rome) + options.append("-DGMX_SIMD=AVX2_256") + elif target >= "zen": + # AMD Family 17h (EPYC Naples) + options.append("-DGMX_SIMD=AVX2_128") + elif target >= "bulldozer": + # AMD Family 15h + options.append("-DGMX_SIMD=AVX_128_FMA") + elif "vsx" in target: + # IBM Power 7 and beyond + if self.spec.satisfies("%nvhpc"): + options.append("-DGMX_SIMD=None") + else: + options.append("-DGMX_SIMD=IBM_VSX") + elif target.family == "aarch64": + # ARMv8 + if self.spec.satisfies("%nvhpc"): + options.append("-DGMX_SIMD=None") + elif "sve" in target.features and "+sve" in self.spec: + options.append("-DGMX_SIMD=ARM_SVE") + else: + options.append("-DGMX_SIMD=ARM_NEON_ASIMD") + elif target == "mic_knl": + # Intel KNL + options.append("-DGMX_SIMD=AVX_512_KNL") + else: + # Other architectures + simd_features = [ + ("sse2", "SSE2"), + ("sse4_1", "SSE4.1"), + ("avx", "AVX_256"), + ("axv128", "AVX2_128"), + ("avx2", "AVX2_256"), + ("avx512", "AVX_512"), + ] + + # Workaround NVIDIA compiler bug when avx512 is enabled + if self.spec.satisfies("%nvhpc") and ("avx512", "AVX_512") in simd_features: + simd_features.remove(("avx512", "AVX_512")) + + feature_set = False + for feature, flag in reversed(simd_features): + if feature in target: + options.append("-DGMX_SIMD:STRING={0}".format(flag)) + feature_set = True + break + + # Fall back + if not feature_set: + options.append("-DGMX_SIMD:STRING=None") + + # Use the 'rtdscp' assembly instruction only on + # appropriate architectures + options.append(self.define("GMX_USE_RDTSCP", str(target.family) in ("x86_64", "x86"))) + + if self.spec.satisfies("@:2020"): + options.append(self.define_from_variant("GMX_BUILD_MDRUN_ONLY", "mdrun_only")) + + options.append(self.define_from_variant("GMX_OPENMP", "openmp")) + + if self.spec.satisfies("@:2020"): + options.append( + self.define_from_variant( + "GMX_RELAXED_DOUBLE_PRECISION", "relaxed_double_precision" + ) + ) + + if self.spec.satisfies("+cycle_subcounters"): + options.append("-DGMX_CYCLE_SUBCOUNTERS:BOOL=ON") + else: + options.append("-DGMX_CYCLE_SUBCOUNTERS:BOOL=OFF") + + if "+openmp" in self.spec and self.spec.variants["openmp_max_threads"].value != "none": + options.append( + "-DGMX_OPENMP_MAX_THREADS=%s" % self.spec.variants["openmp_max_threads"].value + ) + if self.spec.satisfies("+nvshmem"): + options.append("-DGMX_NVSHMEM:BOOL=ON") + nvshmem_root = join_path( + self.spec["nvhpc"].prefix, + f"Linux_{self.spec.target.family}", + self.spec["nvhpc"].version, + "comm_libs", + "nvshmem", + ) + options.append(f"-DNVSHMEM_ROOT={nvshmem_root}") + + if self.spec.satisfies("^[virtuals=lapack] intel-oneapi-mkl"): + # fftw-api@3 is provided by intel-oneapi-mkl + options.append("-DGMX_FFT_LIBRARY=mkl") + if self.spec.satisfies("@:2022"): + options.append( + "-DMKL_INCLUDE_DIR={0}".format(self.spec["mkl"].headers.directories[0]) + ) + # The 'blas' property provides a minimal set of libraries + # that is sufficient for fft. Using full mkl fails the cmake test + options.append("-DMKL_LIBRARIES={0}".format(self.spec["blas"].libs.joined(";"))) + else: + # we rely on the fftw-api@3 + options.append("-DGMX_FFT_LIBRARY=fftw3") + if self.spec.satisfies("^[virtuals=fftw-api] amdfftw"): + options.append("-DGMX_FFT_LIBRARY=fftw3") + options.append( + "-DFFTWF_INCLUDE_DIRS={0}".format(self.spec["amdfftw"].headers.directories[0]) + ) + options.append( + "-DFFTWF_LIBRARIES={0}".format(self.spec["amdfftw"].libs.joined(";")) + ) + elif self.spec.satisfies("^armpl-gcc"): + options.append( + "-DFFTWF_INCLUDE_DIR={0}".format(self.spec["armpl-gcc"].headers.directories[0]) + ) + options.append( + "-DFFTWF_LIBRARY={0}".format(self.spec["armpl-gcc"].libs.joined(";")) + ) + elif self.spec.satisfies("^acfl"): + options.append( + "-DFFTWF_INCLUDE_DIR={0}".format(self.spec["acfl"].headers.directories[0]) + ) + options.append("-DFFTWF_LIBRARY={0}".format(self.spec["acfl"].libs.joined(";"))) + + # Ensure that the GROMACS log files report how the code was patched + # during the build, so that any problems are easier to diagnose. + if self.spec.satisfies("+plumed"): + options.append("-DGMX_VERSION_STRING_OF_FORK=PLUMED-spack") + else: + options.append("-DGMX_VERSION_STRING_OF_FORK=spack") + return options + + def setup_build_environment(self, env: EnvironmentModifications) -> None: + if self.spec.satisfies("+cufftmp"): + env.append_path( + "LD_LIBRARY_PATH", + join_path( + self.spec["nvhpc"].prefix, + f"Linux_{self.spec.target.family}", + self.spec["nvhpc"].version, + "comm_libs", + "nvshmem", + "lib", + ), + ) diff --git a/recipes/gromacs/2025/gh200-mpi-pytorch/repo/packages/plumed/package.py b/recipes/gromacs/2025/gh200-mpi-pytorch/repo/packages/plumed/package.py new file mode 100644 index 000000000..b6ab12006 --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi-pytorch/repo/packages/plumed/package.py @@ -0,0 +1,345 @@ +# Copyright Spack Project Developers. See COPYRIGHT file for details. +# +# SPDX-License-Identifier: (Apache-2.0 OR MIT) + +import collections +import os +from pathlib import Path + +from spack_repo.builtin.build_systems.autotools import AutotoolsPackage + +from spack.package import * + + +class Plumed(AutotoolsPackage): + """PLUMED is an open source library for free energy calculations in + molecular systems which works together with some of the most popular + molecular dynamics engines. + + Free energy calculations can be performed as a function of many order + parameters with a particular focus on biological problems, using state + of the art methods such as metadynamics, umbrella sampling and + Jarzynski-equation based steered MD. + + The software, written in C++, can be easily interfaced with both fortran + and C/C++ codes. + """ + + homepage = "https://www.plumed.org/" + url = "https://github.com/plumed/plumed2/archive/v2.7.4.tar.gz" + git = "https://github.com/plumed/plumed2.git" + maintainers("marcodelapierre") + + tags = ["e4s"] + + license("LGPL-3.0-or-later") + + version("master", branch="master") + + version("2.10.0", sha256="ca6410d47e91b4e0f953e1a8933f15b05c4681167611ab3b096ab121155f6879") + version("2.9.2", sha256="301fbc958374f81d9b8c7a1eac73095f6dded52cce73ce33d64bdbebf51ac63d") + version("2.9.1", sha256="e24563ad1eb657611918e0c978d9c5212340f128b4f1aa5efbd439a0b2e91b58") + version("2.9.0", sha256="612d2387416b5f82dd8545709921440370e144fd46cef633654cf0ee43bac5f8") + + version("2.8.3", sha256="e98da486e252cdf290b0b5b2f3f021409ea0d2d775ab609a6ad68fc1ab143a3b") + version("2.8.2", sha256="a2064bacba1dde36b05aaf351ba4b7e6d30a165b332b0a83b7a6db04b477be9f") + version("2.8.1", sha256="f56bc9266c8a47241385c595717c2734a9b67148a7f4122b808bc0733710173e") + version("2.8.0", sha256="8357eca6f280125037ad4e7c427f96f2af2f60ddfedce1a2e36e1e1cc3bff32b") + + version("2.7.6", sha256="9ca7b1e84bf2343a09a5b604222dd04aa0fc8b62a7cb82d1d68b795b6b189c06") + version("2.7.5", sha256="39cb01108706df7ef71c7c315ddfc4306137f62ac72222b8582ab892221f7972") + version("2.7.4", sha256="6f5dc16a753c71ed719f17f9cbb61642ab8e716fb7f77e22960dfa145c3b8211") + version("2.7.3", sha256="aa1f6200c2ed351e40ce4391a9590f171532474b30f384feddfab10e36d7e08e") + version("2.7.2", sha256="c9a31e68d6440828cf186ca43c9e11a5e5c7ad1c96b2b66ed5a5a141fc954373") + version("2.7.1", sha256="cb8b5735d8dd61980fa6441f3dde3f33544240ae4177da0f529fb5abb355cd4a") + version("2.7.0", sha256="14450ea566c25ac9bf71fd77bb9c0c95e9038462b5739c73a515be82e2011cd6") + + version("2.6.6", sha256="43a7bb410280141c020363671c685a759d4497b3db3eb3c04899264b51a26859") + version("2.6.5", sha256="3b72587ba6fe72def46bcc7d917974123279879de7f8335acf542bba57865eed") + version("2.6.4", sha256="53e49c0db6cc769d238834bea884e856f4e7bb8f71c9929e5584bd977113f03b") + version("2.6.3", sha256="d05b9e4a4c1329fc932d5bdd04f20419be230f98159bdc012a91716461ab4a2f") + version("2.6.2", sha256="bbc2ef0cb08d404513b8b737c72333b6656389e15effd6a0f9ace2a5758c9a4a") + version("2.6.1", sha256="c1b3c397b2d971140aa240dde50e48a04ce78e3dedb02b6dca80fa53f8026e4e") + version("2.6.0", sha256="3d57ae460607a49547ef38a52c4ac93493a3966857c352280a9c05f5dcdb1820") + + version("2.5.7", sha256="aa10d2879c3edeaef9d5a530fe8b05f67ecfbec2e9423e0f95701d0bc54826c7") + version("2.5.6", sha256="1bc29b0274196fb553cdf7ba8ecb7a93a91d60a920d99863edbcd536d618ce8c") + version("2.5.5", sha256="70faa9ff1938e286dc388cb793b39840953e5646855b684f48df1bc864b737e8") + version("2.5.4", sha256="a1647e598191f261e75d06351e607475d395af481315052a4c28563ac9989a7f") + version("2.5.3", sha256="543288be667dc4201fc461ecd2dd4878ddfbeac682d0c021c99ea8e501c7c9dc") + version("2.5.2", sha256="85d10cc46e2e37c7719cf51c0931278f56c2c8f8a9d86188b2bf97c2535a2ab4") + version("2.5.1", sha256="de309980dcfd6f6e0e70e138856f4bd9eb4d8a513906a5e6389f18a5af7f2eba") + version("2.5.0", sha256="53e08187ec9f8af2326fa84407e34644a7c51d2af93034309fb70675eee5e4f7") + + # Variants. PLUMED by default builds a number of optional modules. + # The ones listed here are not built by default for various reasons, + # such as stability, lack of testing, or lack of demand. + # + # From 'configure --help' @2.3: + # all/none/reset or : separated list such as + # +crystallization:-bias default: reset + # + # Optional modules can be provided in two ways, via the `optional_modules` variant: + # 1. Use a reference set of optional modules via `optional_modules` (recommended). + # Allowed values are: `all`[default], `reset`. + # 2. Pick any combination of specific optional modules (advanced). + # Only the requested optional modules will be activated. + # See list in variable `single_optional_modules` below. + # This list comes from the Plumed manual, eg for 2.8: + # https://www.plumed.org/doc-v2.8/user-doc/html/mymodules.html + # These are implemented using multi-valued variants (`disjoint_sets`), + # and the `conditional` option to handle version conflicts. + single_optional_modules = ( + "adjmat", + "analysis", + conditional("annfunc", when="@2.6:"), + "bias", + "cltools", + "colvar", + "crystallization", + "dimred", + "drr", + "eds", + conditional("fisst", when="@2.7:"), + "function", + conditional("funnel", when="@2.7:"), + "generic", + "isdb", + "logmfd", + "manyrestraints", + "mapping", + conditional("maze", when="@2.6:"), + "molfile", + "multicolvar", + conditional("opes", when="@2.7:"), + conditional("pamm", when="optional_modules=adjmat"), + "piv", + conditional("s2cm", when="@2.8:"), + conditional("sasa", when="@2.8:"), + "secondarystructure", + "setup", + "vatom", + "ves", + conditional("xdrfile", when="@2.8:"), + ) + + variant( + "optional_modules", + values=disjoint_sets(("all",), ("reset",), single_optional_modules) + .prohibit_empty_set() + .with_default("all"), + description="Activates optional modules: all, reset, or custom list (advanced)", + ) + + variant("shared", default=True, description="Builds shared libraries") + variant("mpi", default=True, description="Activates MPI support") + variant("gsl", default=True, description="Activates GSL support") + variant( + "arrayfire", + default="none", + values=("none", "cpu", "cuda", "opencl"), + description="Activates FireArray support", + ) + variant("pytorch", default=False, description="Activates PyTorch support", when="@2.9:") + variant("metatomic", default=False, description="Activates metatomic support", when="@2.10:") + + depends_on("c", type="build") # generated + depends_on("cxx", type="build") # generated + depends_on("fortran", type="build") # generated + + # Dependencies. LAPACK and BLAS are recommended but not essential. + depends_on("zlib-api") + depends_on("blas") + depends_on("lapack") + depends_on("arrayfire", when="arrayfire=cpu") + depends_on("arrayfire+cuda", when="arrayfire=cuda") + depends_on("arrayfire+opencl", when="arrayfire=opencl") + + depends_on("mpi", when="+mpi") + depends_on("gsl", when="+gsl") + + depends_on("autoconf", type="build") + depends_on("automake", type="build") + depends_on("libtool", type="build") + depends_on("m4", type="build") + depends_on("py-cython", type="build") + + depends_on("py-torch", when="+pytorch") + conflicts("+metatomic ~pytorch", msg="metatomic support requires PyTorch") + depends_on("libmetatomic-torch", when="+metatomic") + + # https://github.com/plumed/plumed2/issues/1256 + conflicts("^py-cython@3.1:", when="@:2.9.3") + + force_autoreconf = True + + parallel = True + + def apply_patch(self, other): + # The name of MD engines differ slightly from the ones used in Spack + format_strings = collections.defaultdict(lambda: "{0.name}-{0.version}") + format_strings["espresso"] = "q{0.name}-{0.version}" + format_strings["amber"] = "{0.name}{0.version}" + + get_md = lambda x: format_strings[x.name].format(x) + + # Get available patches + plumed_patch = Executable(os.path.join(self.spec.prefix.bin, "plumed-patch")) + + out = plumed_patch("-q", "-l", output=str) + available = out.split(":")[-1].split() + + # Check that `other` is among the patchable applications + if get_md(other) not in available: + msg = "{0.name}@{0.version} is not among the MD engine" + msg += " that can be patched by {1.name}@{1.version}.\n" + msg += "Supported engines are:\n" + for x in available: + msg += x + "\n" + raise RuntimeError(msg.format(other, self.spec)) + + # Call plumed-patch to patch executables + target = format_strings[other.name].format(other) + plumed_patch("-p", "-e", target) + + def setup_dependent_package(self, module, dependent_spec): + # Make plumed visible from dependent packages + module.plumed = self.command + + @property + def plumed_inc(self): + return os.path.join(self.prefix.lib, "plumed", "src", "lib", "Plumed.inc") + + @run_before("autoreconf") + def filter_gslcblas(self): + # This part is needed to avoid linking with gsl cblas + # interface which will mask the cblas interface + # provided by optimized libraries due to linking order + filter_file("-lgslcblas", "", "configure.ac") + + def patch(self): + # Ensure Spack's wrappers are used to compile the Python interface + env = ( + 'CC="{0}" LDSHARED="{0} -pthread -shared" ' + 'CXX="{1}" LDCXXSHARED="{1} -pthread -shared"'.format(spack_cc, spack_cxx) + ) + filter_file( + "plumed_program_name=plumed", + "{0} plumed_program_name=plumed".format(env), + "src/lib/Makefile", + "python/Makefile", + ) + + def configure_args(self): + spec = self.spec + + # From plumed docs : + # Also consider that this is different with respect to what some other + # configure script does in that variables such as MPICXX are + # completely ignored here. In case you work on a machine where CXX is + # set to a serial compiler and MPICXX to a MPI compiler, to compile + # with MPI you should use: + # + # > ./configure CXX="$MPICXX" + + # The configure.ac script may detect the wrong linker for + # LD_RO which causes issues at link time. Here we work around + # the issue saying we have no LD_RO executable. + configure_opts = ["--disable-ld-r"] + + configure_opts.append("--disable-doc") + + # If using MPI then ensure the correct compiler wrapper is used. + if "+mpi" in spec: + configure_opts.extend(["--enable-mpi", "CXX={0}".format(spec["mpi"].mpicxx)]) + + # If the MPI dependency is provided by the intel-oneapi-mpi package then the following + # additional argument is required to allow it to build. + if spec.satisfies("^[virtuals=mpi] intel-oneapi-mpi"): + configure_opts.extend(["STATIC_LIBS=-mt_mpi"]) + + enable_libmetatomic = self.spec.satisfies("+metatomic") + enable_libtorch = self.spec.satisfies("+pytorch") or self.spec.satisfies("+metatomic") + + extra_ldflags = [] + extra_libs = [] + extra_cppflags = [] + # Set flags to help find gsl + if "+gsl" in spec: + gsl_libs = spec["gsl"].libs + blas_libs = spec["blas"].libs + extra_ldflags.append((gsl_libs + blas_libs).search_flags) + extra_libs.append((gsl_libs + blas_libs).link_flags) + extra_cppflags.extend( + [spec["gsl"].headers.include_flags, spec["blas"].headers.include_flags] + ) + # Set flags to help with ArrayFire + if "arrayfire=none" not in spec: + libaf = "arrayfire:{0}".format(spec.variants["arrayfire"].value) + extra_ldflags.append(spec[libaf].libs.search_flags) + extra_libs.append(spec[libaf].libs.link_flags) + extra_cppflags.append(spec[libaf].headers.include_flags) + # Set flags to help with PyTorch + if enable_libtorch: + pytorch_path = Path(spec["py-torch"].package.cmake_prefix_paths[0]).parent.parent + extra_ldflags.append(spec["py-torch"].libs.search_flags) + extra_libs.append(spec["py-torch"].libs.link_flags) + # Add include paths manually + # Spack HeaderList.cpp_flags does not support include paths within include paths + extra_cppflags.extend( + [ + f"-I{pytorch_path / 'include'}", + f"-I{pytorch_path / 'include' / 'torch' / 'csrc' / 'api' / 'include'}", + ] + ) + if enable_libmetatomic: + for libname in ["libmetatensor", "libmetatensor-torch", "libmetatomic-torch"]: + extra_ldflags.append(spec[libname].libs.search_flags) + extra_libs.append(spec[libname].libs.link_flags) + extra_cppflags.append(spec[libnamd].headers.include_flags) + + if extra_ldflags: + configure_opts.append("LDFLAGS={0}".format(" ".join(extra_ldflags))) + + if extra_libs: + configure_opts.append("LIBS={0}".format(" ".join(extra_libs))) + + if extra_cppflags: + configure_opts.append("CPPFLAGS={0}".format(" ".join(extra_cppflags))) + + # Additional arguments + configure_opts.extend( + [ + "--enable-shared={0}".format("yes" if "+shared" in spec else "no"), + "--enable-gsl={0}".format("yes" if "+gsl" in spec else "no"), + "--enable-af_cpu={0}".format("yes" if "arrayfire=cpu" in spec else "no"), + "--enable-af_cuda={0}".format("yes" if "arrayfire=cuda" in spec else "no"), + "--enable-af_ocl={0}".format("yes" if "arrayfire=ocl" in spec else "no"), + "--enable-libtorch={0}".format("yes" if enable_libtorch else "no"), + "--enable-libmetatomic={0}".format("yes" if enable_libmetatomic else "no"), + ] + ) + + # Construct list of optional modules + optional_modules = spec.variants["optional_modules"].value + + # Predefined set of modules + if "all" in optional_modules: + selected_modules = "all" + elif "reset" in optional_modules: + selected_modules = "reset" + # Custom set of modules + else: + # Ensure modules from variants + if spec.satisfies("+pytorch") or sepec.satisfies("+metatomic"): + optional_modules += ("pytorch",) + if spec.satisfies("+libmetatomic"): + optional_modules += ("metatomic",) + + selected_modules = "none" + for mod in optional_modules: + selected_modules += ":+{0}".format(mod) + + configure_opts.append("--enable-modules={0}".format(selected_modules)) + + return configure_opts diff --git a/recipes/gromacs/2025/gh200-mpi/compilers.yaml b/recipes/gromacs/2025/gh200-mpi/compilers.yaml new file mode 100644 index 000000000..840d9974d --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi/compilers.yaml @@ -0,0 +1,2 @@ +gcc: + version: "14.2" diff --git a/recipes/gromacs/2025/gh200-mpi/config.yaml b/recipes/gromacs/2025/gh200-mpi/config.yaml new file mode 100644 index 000000000..8ec9c302e --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi/config.yaml @@ -0,0 +1,11 @@ +name: gromacs-gh200 +store: /user-environment +description: GPU-optimised GROMACS with and without PLUMED, and the toolchain to build your own GROMACS. +spack: + repo: https://github.com/spack/spack.git + commit: releases/v1.0 + packages: + repo: https://github.com/spack/spack-packages.git + commit: releases/v2025.07 +modules: false +version: 2 diff --git a/recipes/gromacs/2025/gh200-mpi/environments.yaml b/recipes/gromacs/2025/gh200-mpi/environments.yaml new file mode 100644 index 000000000..c50d8d2ef --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi/environments.yaml @@ -0,0 +1,25 @@ +gromacs: + compiler: [gcc] + network: + mpi: cray-mpich@8.1.32 +cuda + unify: when_possible + specs: + - cmake + - cuda@12.9 + - blas + - lapack + - hwloc + - fftw + - python@3.12 + - gromacs@2025.0 +cuda +plumed +mpi +hwloc + variants: + - +mpi + - +cuda + - cuda_arch=90a + views: + develop: + exclude: ['gromacs'] + gromacs: + link: run + packages: + - perl \ No newline at end of file diff --git a/recipes/gromacs/2025/gh200-mpi/extra/reframe.yaml b/recipes/gromacs/2025/gh200-mpi/extra/reframe.yaml new file mode 100644 index 000000000..f6224e3d0 --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi/extra/reframe.yaml @@ -0,0 +1,19 @@ +run: + features: + - gromacs + - cuda + - mpi + cc: gcc + cxx: g++ + views: + - gromacs + +build: + features: + - gromacs-dev + - cuda + - mpi + cc: gcc + cxx: g++ + views: + - develop \ No newline at end of file diff --git a/recipes/gromacs/2025/gh200-mpi/repo/packages/gromacs/gmxDetectCpu-cmake-3.14.patch b/recipes/gromacs/2025/gh200-mpi/repo/packages/gromacs/gmxDetectCpu-cmake-3.14.patch new file mode 100644 index 000000000..2f94a6a99 --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi/repo/packages/gromacs/gmxDetectCpu-cmake-3.14.patch @@ -0,0 +1,12 @@ +--- a/cmake/gmxDetectCpu.cmake ++++ b/cmake/gmxDetectCpu.cmake +@@ -83,7 +83,7 @@ function(gmx_run_cpu_detection TYPE) + set(GCC_INLINE_ASM_DEFINE "-DGMX_X86_GCC_INLINE_ASM=0") + endif() + +- set(_compile_definitions "${GCC_INLINE_ASM_DEFINE} -I${PROJECT_SOURCE_DIR}/src -DGMX_CPUINFO_STANDALONE ${GMX_STDLIB_CXX_FLAGS} -DGMX_TARGET_X86=${GMX_TARGET_X86_VALUE}") ++ set(_compile_definitions ${GCC_INLINE_ASM_DEFINE} -I${PROJECT_SOURCE_DIR}/src -DGMX_CPUINFO_STANDALONE ${GMX_STDLIB_CXX_FLAGS} -DGMX_TARGET_X86=${GMX_TARGET_X86_VALUE}) + set(LINK_LIBRARIES "${GMX_STDLIB_LIBRARIES}") + try_compile(CPU_DETECTION_COMPILED + "${PROJECT_BINARY_DIR}" + diff --git a/recipes/gromacs/2025/gh200-mpi/repo/packages/gromacs/gmxDetectSimd-cmake-3.14.patch b/recipes/gromacs/2025/gh200-mpi/repo/packages/gromacs/gmxDetectSimd-cmake-3.14.patch new file mode 100644 index 000000000..f30ec78a7 --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi/repo/packages/gromacs/gmxDetectSimd-cmake-3.14.patch @@ -0,0 +1,11 @@ +--- a/cmake/gmxDetectSimd.cmake ++++ b/cmake/gmxDetectSimd.cmake +@@ -77,7 +77,7 @@ function(gmx_suggest_simd _suggested_simd) + else() + set(GMX_TARGET_X86_VALUE 0) + endif() +- set(_compile_definitions "${GCC_INLINE_ASM_DEFINE} -I${CMAKE_SOURCE_DIR}/src -DGMX_CPUINFO_STANDALONE ${GMX_STDLIB_CXX_FLAGS} -DGMX_TARGET_X86=${GMX_TARGET_X86_VALUE}") ++ set(_compile_definitions ${GCC_INLINE_ASM_DEFINE} -I${CMAKE_SOURCE_DIR}/src -DGMX_CPUINFO_STANDALONE ${GMX_STDLIB_CXX_FLAGS} -DGMX_TARGET_X86=${GMX_TARGET_X86_VALUE}) + + # Prepare a default suggestion + set(OUTPUT_SIMD "None") diff --git a/recipes/gromacs/2025/gh200-mpi/repo/packages/gromacs/package.py b/recipes/gromacs/2025/gh200-mpi/repo/packages/gromacs/package.py new file mode 100644 index 000000000..1273bcd54 --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi/repo/packages/gromacs/package.py @@ -0,0 +1,834 @@ +# Copyright Spack Project Developers. See COPYRIGHT file for details. +# +# SPDX-License-Identifier: (Apache-2.0 OR MIT) + +import os + +from spack_repo.builtin.build_systems import cmake +from spack_repo.builtin.build_systems.cmake import CMakePackage +from spack_repo.builtin.build_systems.cuda import CudaPackage + +from spack.package import * + + +class Gromacs(CMakePackage, CudaPackage): + """GROMACS is a molecular dynamics package primarily designed for simulations + of proteins, lipids and nucleic acids. It was originally developed in + the Biophysical Chemistry department of University of Groningen, and is now + maintained by contributors in universities and research centers across the world. + + GROMACS is one of the fastest and most popular software packages + available and can run on CPUs as well as GPUs. It is free, open source + released under the GNU Lesser General Public License. Before the version 4.6, + GROMACS was released under the GNU General Public License. + """ + + homepage = "https://www.gromacs.org" + url = "https://ftp.gromacs.org/gromacs/gromacs-2022.2.tar.gz" + list_url = "https://ftp.gromacs.org/gromacs" + git = "https://gitlab.com/gromacs/gromacs.git" + + maintainers("mabraham", "eirrgang", "junghans") + + license("GPL-2.0-or-later", when="@:4.5") + license("LGPL-2.1-or-later", when="@4.6:") + + # Deprecation policy: + # + # GROMACS makes an annual major release and supports it with fixes + # in minor updates for about two years. Each such annual release + # series is supported in spack for those two years, then marked as + # deprecated in Spack. Deprecated versions can be removed after + # the next major release of GROMACS is supported in Spack. Users + # needing such an old version can either do a manual installation + # or get an older version of Spack. + # + # Exception: Version 2019.6 is the last version capable of tabulated + # interactions used in the so-called "group scheme." It will be marked + # as deprecated only after equivalent functionality is available in + # a major release of GROMACS, then removed as above. + # + # Exception: Otherwise, versions before 2022 will be removed when + # 2025 is supported. + version("main", branch="main") + version("master", branch="main", deprecated=True) + version("2025.2", sha256="0df09f9d45a99ef00e66b9baa9493a27e906813763a3b6c7672217c66b43ea11") + version("2025.1", sha256="0adf621a80fd8043f8defec84ce02811c0cdf42a052232890932d81f25c4d28a") + version("2025.0", sha256="a27ad35a646295bbec129abe684d9d03d1e2e0bd76b0d625e9055746aaefae82") + version("2024.5", sha256="fecf06b186cddb942cfb42ee8da5f3eb2b9993e6acc0a2f18d14ac0b014424f3") + version("2024.4", sha256="ac618ece2e58afa86b536c5a2c4fcb937f0760318f12d18f10346b6bdebd86a8") + version("2024.3", sha256="bbda056ee59390be7d58d84c13a9ec0d4e3635617adf2eb747034922cba1f029") + version("2024.2", sha256="802a7e335f2e895770f57b159e4ec368ebb0ff2ce6daccf706c6e8025c36852b") + version("2024.1", sha256="937d8f12a36fffbf2af7add71adbb5aa5c5537892d46c9a76afbecab1aa0aac7") + version("2024", sha256="04d226d52066a8bc3a42e00d6213de737b4ec292e26703065924ff01956801e2") + version( + "2023.5", + sha256="9cc491d3601a5fe0ec0de727e4432c34877f596fe8a463d4cf0f0f53fb34d08b", + ) + version( + "2023.4", + sha256="e5d6c4d9e7ccacfaccb0888619bd21b5ea8911f82b410e68d6db5d40f695f231", + deprecated=True, + ) + version( + "2023.3", + sha256="4ec8f8d0c7af76b13f8fd16db8e2c120e749de439ae9554d9f653f812d78d1cb", + deprecated=True, + ) + version( + "2023.2", + sha256="bce1480727e4b2bb900413b75d99a3266f3507877da4f5b2d491df798f9fcdae", + deprecated=True, + ) + version( + "2023.1", + sha256="eef2bb4a6cb6314cf9da47f26df2a0d27af4bf7b3099723d43601073ab0a42f4", + ) + version( + "2023", + sha256="ac92c6da72fbbcca414fd8a8d979e56ecf17c4c1cdabed2da5cfb4e7277b7ba8", + ) + version( + "2022.6", + sha256="75d277138475679dd3e334e384a71516570cde767310476687f2a5b72333ea41", + deprecated=True, + ) + version( + "2022.5", + sha256="083cc3c424bb93ffe86c12f952e3e5b4e6c9f6520de5338761f24b75e018c223", + ) + version( + "2022.4", + sha256="c511be602ff29402065b50906841def98752639b92a95f1b0a1060d9b5e27297", + deprecated=True, + ) + version( + "2022.3", + sha256="14cfb130ddaf8f759a3af643c04f5a0d0d32b09bc3448b16afa5b617f5e35dae", + deprecated=True, + ) + version( + "2022.2", + sha256="656404f884d2fa2244c97d2a5b92af148d0dbea94ad13004724b3fcbf45e01bf", + deprecated=True, + ) + version( + "2022.1", + sha256="85ddab5197d79524a702c4959c2c43be875e0fc471df3a35224939dce8512450", + deprecated=True, + ) + version( + "2022", + sha256="fad60d606c02e6164018692c6c9f2c159a9130c2bf32e8c5f4f1b6ba2dda2b68", + deprecated=True, + ) + # See exception documented above + version("2019.6", sha256="bebe396dc0db11a9d4cc205abc13b50d88225617642508168a2195324f06a358") + + depends_on("c", type="build") + depends_on("cxx", type="build") + depends_on("fortran", type="build", when="@:4.5.5") # No core Fortran code since 4.6 + depends_on("fortran", type="build", when="+cp2k") # Need Fortan compiler for CP2K + + variant( + "mpi", default=True, description="Activate MPI support (disable for Thread-MPI support)" + ) + variant("shared", default=True, description="Enables the build of shared libraries") + variant( + "double", + default=False, + description="Produces a double precision version of the executables", + ) + variant( + "cufftmp", + default=False, + when="@2022: +cuda+mpi", + description="Enable multi-GPU FFT support with cuFFTMp", + ) + variant( + "heffte", + default=False, + when="@2021: +mpi", + description="Enable multi-GPU FFT support with HeFFTe", + ) + depends_on("heffte +cuda", when="+heffte +cuda") + depends_on("heffte +sycl", when="+heffte +sycl") + variant("opencl", default=False, description="Enable OpenCL support") + variant("sycl", default=False, when="@2021:", description="Enable SYCL support") + requires( + "^intel-oneapi-runtime", + "^hipsycl %clang", + policy="one_of", + when="+sycl", + msg="GROMACS SYCL support comes either from intel-oneapi-runtime or a " + + "package that provides the virtual package `sycl`, such as AdaptiveCpp " + + "plus a clang compiler.", + ) + variant( + "intel-data-center-gpu-max", + default=False, + when="@2022: +sycl", + description="Enable support for Intel Data Center GPU Max", + ) + variant("nosuffix", default=False, description="Disable default suffixes") + variant( + "build_type", + default="Release", + description="The build type to build", + values=( + "Debug", + "Release", + "RelWithDebInfo", + "MinSizeRel", + "Reference", + "RelWithAssert", + "Profile", + ), + ) + variant( + "nblib", + default=True, + when="@2021:", + description="Build and install the NB-LIB C++ API for GROMACS", + ) + variant( + "gmxapi", + default=True, + when="@2019:", + description="Build and install the gmxlib python API for GROMACS", + ) + variant( + "mdrun_only", + default=False, + description="Enables the build of a cut-down version" + " of libgromacs and/or the mdrun program", + ) + conflicts( + "+mdrun_only", when="@2021:", msg="mdrun-only build option was removed for GROMACS 2021." + ) + variant( + "nvshmem", + default=False, + when="@2024:+mpi+cuda", + description="Enable NVSHMEM support for Nvidia GPUs", + ) + conflicts( + "+nvshmem", + when="+cufftmp", + msg=( + "The GROMACS support for NVSHMEM does not work with the GROMACS support " + "for cuFFTMp (even though cuFFTMp uses NVSHMEM in its implementation)" + ), + ) + + variant("openmp", default=True, description="Enables OpenMP at configure time") + conflicts( + "+openmp", when="%apple-clang", msg="OpenMP not available for the Apple clang compiler" + ) + variant("openmp_max_threads", default="none", description="Max number of OpenMP threads") + conflicts( + "+openmp_max_threads", when="~openmp", msg="OpenMP is off but OpenMP Max threads is set" + ) + variant( + "sve", + default=True, + description="Enable SVE on aarch64 if available", + when="target=neoverse_v1:,neoverse_v2:,neoverse_n2:", + ) + variant( + "sve", default=True, description="Enable SVE on aarch64 if available", when="target=a64fx" + ) + variant( + "relaxed_double_precision", + default=False, + description="GMX_RELAXED_DOUBLE_PRECISION, use only for Fujitsu PRIMEHPC", + ) + conflicts( + "+relaxed_double_precision", + when="@2021:", + msg="GMX_RELAXED_DOUBLE_PRECISION option removed for GROMACS 2021.", + ) + variant("hwloc", default=True, description="Use the hwloc portable hardware locality library") + variant("cycle_subcounters", default=False, description="Enables cycle subcounters") + + variant("cp2k", default=False, description="CP2K QM/MM interface integration") + conflicts( + "+cp2k", when="@:2021", msg="CP2K QM/MM support have been introduced in GROMACS 2022" + ) + conflicts("+shared", when="+cp2k", msg="Enabling CP2K requires static build") + conflicts("%intel", when="@2022:", msg="GROMACS %intel support was removed in version 2022") + conflicts("%gcc@:8", when="@2023:", msg="GROMACS requires GCC 9 or later since version 2023") + conflicts( + "^intel-oneapi-mkl@:2021.2", + when="@2023:", + msg="GROMACS requires oneMKL 2021.3 or later since version 2023", + ) + + depends_on("mpi", when="+mpi") + + # Plumed 2.9.0 needs Gromacs 2023, 2022.5, 2021.7, 2020.7 + # Plumed 2.8.3 needs Gromacs 2022.5, 2021.7, 2020.7, 2019.6 + # Plumed 2.8.2 needs Gromacs 2022.5, 2021.7, 2020.7, 2019.6 + # Plumed 2.8.1 needs Gromacs 2022.3, 2021.6, 2020.7, 2019.6 + # Plumed 2.8.0 needs Gromacs 2021.4, 2020.6, 2019.6 + # Plumed 2.7.6 needs Gromacs 2021.5, 2020.6, 2019.6 + # Plumed 2.7.5 needs Gromacs 2021.5, 2020.6, 2019.6 + # Plumed 2.7.4 needs Gromacs 2021.4, 2020.6, 2019.6 + # Plumed 2.7.3 needs Gromacs 2021.4, 2020.6, 2019.6 + # Plumed 2.7.2 needs Gromacs 2021, 2020.6, 2019.6 + # Plumed 2.7.1 needs Gromacs 2021, 2020.5, 2019.6 + # Plumed 2.7.0 needs Gromacs 2020.4, 2019.6 + # Plumed 2.6.6 needs Gromacs 2020.4, 2019.6, 2018.8 + # Plumed 2.6.5 needs Gromacs 2020.4, 2019.6, 2018.8 + # Plumed 2.6.4 needs Gromacs 2020.4, 2019.6, 2018.8 + # Plumed 2.6.3 needs Gromacs 2020.4, 2019.6, 2018.8 + # Plumed 2.6.2 needs Gromacs 2020.4, 2019.6, 2018.8 + # Plumed 2.6.1 needs Gromacs 2020.2, 2019.6, 2018.8 + # Plumed 2.6.0 needs Gromacs 2019.4, 2018.8 + # Plumed 2.5.7 needs Gromacs 2019.4, 2018.8, 2016.6 + # Plumed 2.5.6 needs Gromacs 2019.4, 2018.8, 2016.6 + # Plumed 2.5.5 needs Gromacs 2019.4, 2018.8, 2016.6 + # Plumed 2.5.4 needs Gromacs 2019.4, 2018.8, 2016.6 + # Plumed 2.5.3 needs Gromacs 2019.4, 2018.8, 2016.6 + # Plumed 2.5.2 needs Gromacs 2019.2, 2018.6, 2016.6 + # Plumed 2.5.1 needs Gromacs 2018.6, 2016.6 + # Plumed 2.5.0 needs Gromacs 2018.4, 2016.5 + + # Above dependencies can be verified, and new versions added, by going to + # https://github.com/plumed/plumed2/tree/v2.9.0/patches + # and switching tags. + + # Versions without minor release number, such as `2023` and `2021`, + # require exact specification using `@=`, starting from Spack v0.20.0, + # see https://github.com/spack/spack/releases/tag/v0.20.0 + + plumed_patches = { + "=2025.0": "2.10.0", + "=2023": "2.9.1", + "2022.5": "2.8.2:2.9.1", + "2022.3": "2.8.1", + "2021.7": "2.8.2:2.9.1", + "2021.6": "2.8.1", + "2021.5": "2.7.5:2.7.6", + "2021.4": "2.7.3:2.8.0", + "=2021": "2.7.1:2.7.2", + "2020.7": "2.8.1:2.9.1", + "2020.6": "2.7.2:2.8.0", + "2020.5": "2.7.1", + "2020.4": "2.6.2:2.7.0", + "2020.2": "2.6.1", + "2019.6": "2.6.1:2.8.3", + "2019.4": "2.5.3:2.6.0", + "2019.2": "2.5.2", + "2018.8": "2.5.3:2.6", + "2018.6": "2.5.1:2.5.2", + "2018.4": "2.5.0", + "2016.6": "2.5.1:2.5", + "2016.5": "2.5.0", + } + + variant( + "plumed", + default=False, + description="Enable PLUMED support", + when="@{0}".format(",".join(plumed_patches.keys())), + ) + with when("+plumed"): + depends_on("plumed+mpi", when="+mpi") + depends_on("plumed~mpi", when="~mpi") + for gmx_ver, plumed_vers in plumed_patches.items(): + depends_on("plumed@{0}".format(plumed_vers), when="@{0}+plumed".format(gmx_ver)) + + variant( + "intel_provided_gcc", + default=False, + description="Use this if Intel compiler is installed through spack. " + + "The g++ location is written to icp{c,x}.cfg", + ) + + variant( + "itt", + default=False, + when="@2024:", + description="Enable Instrumentation and Tracing Technology (ITT)" + + " profiling API (from Intel)", + ) + depends_on("intel-oneapi-vtune", "+itt") + + depends_on("fftw-api@3") + depends_on("cmake@2.8.8:3", type="build") + depends_on("cmake@3.4.3:3", type="build", when="@2018:") + depends_on("cmake@3.9.6:3", type="build", when="@2020") + depends_on("cmake@3.13.0:3", type="build", when="@2021") + depends_on("cmake@3.16.3:3", type="build", when="@2022:") + depends_on("cmake@3.18.4:3", type="build", when="@main") + depends_on("cmake@3.16.0:3", type="build", when="%fj") + depends_on("pkgconfig", type="build") + + depends_on("cuda", when="+cuda") + depends_on("sycl", when="+sycl") + depends_on("lapack") + depends_on("blas") + depends_on("gcc", when="~intel_provided_gcc %intel") + # TODO this can be expanded to all clang-based compilers once + # the principle is demonstrated to work + with when("~intel_provided_gcc %oneapi"): + depends_on("gcc-runtime@5:", when="@2020") + depends_on("gcc-runtime@7:", when="@2021:2022") + depends_on("gcc-runtime@9:", when="@2023:2024") + depends_on("gcc-runtime@11:", when="@2025:") + + depends_on("hwloc@1.0:1", when="+hwloc@2016:2018") + depends_on("hwloc", when="+hwloc@2019:") + + depends_on("cp2k@8.1:", when="+cp2k") + + depends_on("nvhpc", when="+cufftmp") + depends_on("nvhpc", when="+nvshmem") + depends_on("heffte", when="+heffte") + + requires( + "%intel", + "%oneapi", + policy="one_of", + when="+intel_provided_gcc", + msg="Only attempt to find gcc libs for Intel compiler if Intel compiler is used.", + ) + + # If the Intel suite is used for Lapack, it must be used for fftw and vice-versa + requires("^[virtuals=fftw-api] intel-oneapi-mkl", when="^[virtuals=lapack] intel-oneapi-mkl") + requires("^[virtuals=lapack] intel-oneapi-mkl", when="^[virtuals=fftw-api] intel-oneapi-mkl") + + patch("gmxDetectCpu-cmake-3.14.patch", when="@2018:2019.3^cmake@3.14.0:") + patch("gmxDetectSimd-cmake-3.14.patch", when="@5.0:2017^cmake@3.14.0:") + # 2021.2 will always try to build tests (see https://gromacs.bioexcel.eu/t/compilation-failure-for-gromacs-2021-1-and-2021-2-with-cmake-3-20-2/2129) + patch( + "https://gitlab.com/gromacs/gromacs/-/commit/10262892e11a87fda0f59e633c89ed5ab1100509.diff", + sha256="2c30d00404b76421c13866cc42afa5e63276f7926c862838751b158df8727b1b", + when="@2021.1:2021.2", + ) + + filter_compiler_wrappers( + "*.cmake", relative_root=os.path.join("share", "cmake", "gromacs_mpi") + ) + filter_compiler_wrappers("*.cmake", relative_root=os.path.join("share", "cmake", "gromacs")) + + def patch(self): + # Otherwise build fails with GCC 11 (11.2) + if self.spec.satisfies("@2018:2020.6"): + filter_file( + "#include ", + "#include \n#include ", + "src/gromacs/awh/biasparams.h", + ) + if self.spec.satisfies("@2018:2018.8"): + filter_file( + "#include ", + "#include \n#include ", + "src/gromacs/mdlib/minimize.cpp", + ) + if self.spec.satisfies("@2019:2019.6,2020:2020.6"): + filter_file( + "#include ", + "#include \n#include ", + "src/gromacs/mdrun/minimize.cpp", + ) + if self.spec.satisfies("@2020:2020.6"): + filter_file( + "#include ", + "#include \n#include ", + "src/gromacs/modularsimulator/modularsimulator.h", + ) + # Ref: https://gitlab.com/gromacs/gromacs/-/merge_requests/3504 + if self.spec.satisfies("@2023"): + filter_file( + " if (std::filesystem::equivalent(searchPath, buildBinPath))", + " if (std::error_code c; std::filesystem::equivalent(searchPath," + " buildBinPath, c))", + "src/gromacs/commandline/cmdlineprogramcontext.cpp", + string=True, + ) + + if self.spec.satisfies("+plumed"): + self["plumed"].apply_patch(self) + + if self.spec.satisfies("%nvhpc"): + # Disable obsolete workaround + filter_file("ifdef __PGI", "if 0", "src/gromacs/fileio/xdrf.h") + + if self.spec.satisfies("+cuda"): + # Upstream supports building of last two major versions of Gromacs. + # Older versions of Gromacs need to be patched to build with more recent + # versions of CUDA library. + + # Hardware version 3.0 is supported up to CUDA 10.2 (Gromacs 4.6-2020.3 + # needs to be patched, 2020.4 is handling it correctly) + + if self.spec.satisfies("@4.6:2020.3^cuda@11:"): + filter_file( + r"-gencode;arch=compute_30,code=sm_30;?", "", "cmake/gmxManageNvccConfig.cmake" + ) + filter_file( + r"-gencode;arch=compute_30,code=compute_30;?", + "", + "cmake/gmxManageNvccConfig.cmake", + ) + + # Hardware version 2.0 is supported up to CUDA 8 (Gromacs 4.6-2016.3 + # needs to be patched, 2016.4 is handling it correctly, removed in 2019) + + if self.spec.satisfies("@4.6:2016.3^cuda@9:"): + filter_file( + r"-gencode;arch=compute_20,code=sm_20;?", "", "cmake/gmxManageNvccConfig.cmake" + ) + filter_file( + r"-gencode;arch=compute_20,code=compute_20;?", + "", + "cmake/gmxManageNvccConfig.cmake", + ) + + if self.spec.satisfies("@4.6:5.0^cuda@9:"): + filter_file( + r"-gencode;arch=compute_20,code=sm_21;?", "", "cmake/gmxManageNvccConfig.cmake" + ) + + def setup_run_environment(self, env: EnvironmentModifications) -> None: + if self.spec.satisfies("+cufftmp"): + env.append_path( + "LD_LIBRARY_PATH", + join_path( + self.spec["nvhpc"].prefix, + f"Linux_{self.spec.target.family}", + self.spec["nvhpc"].version, + "comm_libs", + "nvshmem", + "lib", + ), + ) + + +class CMakeBuilder(cmake.CMakeBuilder): + @run_after("build") + def build_test_binaries(self): + """Build the test binaries. + + GROMACS usually excludes tests from the default build target, but building + the tests during spack's ``check`` phase takes a long time while producing + no visible output, even with ``--verbose``. + + Here, we make sure the test binaries are built during the build phase + (as would normally be expected when configured with BUILD_TESTING) + when the ``--test`` flag is used. + + Note: the GMX_DEVELOPER_BUILD option disables the EXCLUDE_FROM_ALL on the + test binaries, but the option incurs additional side effects that may + not be intended with ``--test``. + """ + if self.pkg.run_tests: + with working_dir(self.build_directory): + make("tests") + + def check(self): + """Run the ``check`` target (skipping the ``test`` target). + + Override the standard CMakeBuilder behavior. GROMACS has both `test` + and `check` targets, but we are only interested in the latter. + """ + with working_dir(self.build_directory): + if self.generator == "Unix Makefiles": + make("check") + elif self.generator == "Ninja": + ninja("check") + + def cmake_args(self): + options = [] + # Warning: Use `define_from_variant()` with caution. + # GROMACS may use unexpected conventions for CMake variable values. + # For example: variables that accept boolean values like "OFF" + # may actually be STRING type, and undefined variables may trigger + # different defaults for dependent options than explicitly defined variables. + # `-DGMX_VAR=OFF` may not have the same meaning as `-DGMX_VAR=`. + # In other words, the mapping between package variants and the + # GMX CMake variables is often non-trivial. + + if self.spec.satisfies("+mpi"): + options.append("-DGMX_MPI:BOOL=ON") + if self.pkg.version < Version("2020"): + # Ensures gmxapi builds properly + options.extend( + [ + "-DCMAKE_C_COMPILER=%s" % self.spec["mpi"].mpicc, + "-DCMAKE_CXX_COMPILER=%s" % self.spec["mpi"].mpicxx, + "-DCMAKE_Fortran_COMPILER=%s" % self.spec["mpi"].mpifc, + ] + ) + elif self.pkg.version == Version("2021"): + # Work around https://gitlab.com/gromacs/gromacs/-/issues/3896 + # Ensures gmxapi builds properly + options.extend( + [ + "-DCMAKE_C_COMPILER=%s" % self.spec["mpi"].mpicc, + "-DCMAKE_CXX_COMPILER=%s" % self.spec["mpi"].mpicxx, + ] + ) + else: + options.extend( + [ + "-DCMAKE_C_COMPILER=%s" % spack_cc, + "-DCMAKE_CXX_COMPILER=%s" % spack_cxx, + "-DMPI_C_COMPILER=%s" % self.spec["mpi"].mpicc, + "-DMPI_CXX_COMPILER=%s" % self.spec["mpi"].mpicxx, + ] + ) + else: + options.extend( + [ + "-DCMAKE_C_COMPILER=%s" % spack_cc, + "-DCMAKE_CXX_COMPILER=%s" % spack_cxx, + "-DGMX_MPI:BOOL=OFF", + "-DGMX_THREAD_MPI:BOOL=ON", + ] + ) + + if self.spec.satisfies("%aocc"): + options.append("-DCMAKE_CXX_FLAGS=--stdlib=libc++") + + if self.spec.satisfies("@2020:"): + options.append("-DGMX_INSTALL_LEGACY_API=ON") + + if self.spec.satisfies("%oneapi") or self.spec.satisfies("%intel"): + # If intel-oneapi-compilers was installed through spack the gcc is added to the + # configuration file. + if self.spec.satisfies("+intel_provided_gcc") and os.path.exists( + ".".join([os.environ["SPACK_CXX"], "cfg"]) + ): + with open(".".join([os.environ["SPACK_CXX"], "cfg"]), "r") as f: + options.append("-DCMAKE_CXX_FLAGS={}".format(f.read())) + elif self.spec["cxx"].name == "gcc": + options.append("-DGMX_GPLUSPLUS_PATH=%s/g++" % self.spec["gcc"].prefix.bin) + + if self.spec.satisfies("+double"): + options.append("-DGMX_DOUBLE:BOOL=ON") + + if self.spec.satisfies("+nosuffix"): + options.append("-DGMX_DEFAULT_SUFFIX:BOOL=OFF") + + if self.spec.satisfies("~shared"): + options.append("-DBUILD_SHARED_LIBS:BOOL=OFF") + options.append("-DGMXAPI:BOOL=OFF") + + if self.spec.satisfies("+hwloc"): + options.append("-DGMX_HWLOC:BOOL=ON") + else: + options.append("-DGMX_HWLOC:BOOL=OFF") + + if self.pkg.version >= Version("2021"): + if self.spec.satisfies("+cuda"): + options.append("-DGMX_GPU:STRING=CUDA") + elif self.spec.satisfies("+opencl"): + options.append("-DGMX_GPU:STRING=OpenCL") + elif self.spec.satisfies("+sycl"): + options.append("-DGMX_GPU:STRING=SYCL") + else: + options.append("-DGMX_GPU:STRING=OFF") + else: + if self.spec.satisfies("+cuda") or self.spec.satisfies("+opencl"): + options.append("-DGMX_GPU:BOOL=ON") + if self.spec.satisfies("+opencl"): + options.append("-DGMX_USE_OPENCL=ON") + else: + options.append("-DGMX_GPU:BOOL=OFF") + + if self.spec.satisfies("+cuda"): + options.append("-DCUDA_TOOLKIT_ROOT_DIR:STRING=" + self.spec["cuda"].prefix) + if not self.spec.satisfies("cuda_arch=none"): + cuda_arch = self.spec.variants["cuda_arch"].value + options.append(f"-DGMX_CUDA_TARGET_SM:STRING={';'.join(cuda_arch)}") + + options.append("-DGMX_EXTERNAL_LAPACK:BOOL=ON") + if self.spec["lapack"].libs: + options.append("-DGMX_LAPACK_USER={0}".format(self.spec["lapack"].libs.joined(";"))) + + options.append("-DGMX_EXTERNAL_BLAS:BOOL=ON") + if self.spec["blas"].libs: + options.append("-DGMX_BLAS_USER={0}".format(self.spec["blas"].libs.joined(";"))) + + if self.spec.satisfies("+cp2k"): + options.append("-DGMX_CP2K:BOOL=ON") + options.append("-DCP2K_DIR:STRING={0}".format(self.spec["cp2k"].prefix)) + + if self.spec.satisfies("+cufftmp"): + options.append("-DGMX_USE_CUFFTMP=ON") + options.append( + f'-DcuFFTMp_ROOT={self.spec["nvhpc"].prefix}/Linux_{self.spec.target.family}' + + f'/{self.spec["nvhpc"].version}/math_libs' + ) + + if self.spec.satisfies("+heffte"): + options.append("-DGMX_USE_HEFFTE=on") + options.append(f'-DHeffte_ROOT={self.spec["heffte"].prefix}') + + if self.spec.satisfies("+intel-data-center-gpu-max"): + options.append("-DGMX_GPU_NB_CLUSTER_SIZE=8") + options.append("-DGMX_GPU_NB_NUM_CLUSTER_PER_CELL_X=1") + + if "+itt" in self.spec: + options.append("-DGMX_USE_ITT=on") + options.append( + "-DITTNOTIFY_INCLUDE_DIR=%s" + % self.spec["intel-oneapi-vtune"].package.headers.directories[0] + ) + + if self.spec.satisfies("~nblib"): + options.append("-DGMX_INSTALL_NBLIB_API=OFF") + if self.spec.satisfies("~gmxapi"): + options.append("-DGMXAPI=OFF") + + # Activate SIMD based on properties of the target + target = self.spec.target + if target >= "zen4": + # AMD Family 17h (EPYC Genoa) + options.append("-DGMX_SIMD=AVX_512") + elif target >= "zen2": + # AMD Family 17h (EPYC Rome) + options.append("-DGMX_SIMD=AVX2_256") + elif target >= "zen": + # AMD Family 17h (EPYC Naples) + options.append("-DGMX_SIMD=AVX2_128") + elif target >= "bulldozer": + # AMD Family 15h + options.append("-DGMX_SIMD=AVX_128_FMA") + elif "vsx" in target: + # IBM Power 7 and beyond + if self.spec.satisfies("%nvhpc"): + options.append("-DGMX_SIMD=None") + else: + options.append("-DGMX_SIMD=IBM_VSX") + elif target.family == "aarch64": + # ARMv8 + if self.spec.satisfies("%nvhpc"): + options.append("-DGMX_SIMD=None") + elif "sve" in target.features and "+sve" in self.spec: + options.append("-DGMX_SIMD=ARM_SVE") + else: + options.append("-DGMX_SIMD=ARM_NEON_ASIMD") + elif target == "mic_knl": + # Intel KNL + options.append("-DGMX_SIMD=AVX_512_KNL") + else: + # Other architectures + simd_features = [ + ("sse2", "SSE2"), + ("sse4_1", "SSE4.1"), + ("avx", "AVX_256"), + ("axv128", "AVX2_128"), + ("avx2", "AVX2_256"), + ("avx512", "AVX_512"), + ] + + # Workaround NVIDIA compiler bug when avx512 is enabled + if self.spec.satisfies("%nvhpc") and ("avx512", "AVX_512") in simd_features: + simd_features.remove(("avx512", "AVX_512")) + + feature_set = False + for feature, flag in reversed(simd_features): + if feature in target: + options.append("-DGMX_SIMD:STRING={0}".format(flag)) + feature_set = True + break + + # Fall back + if not feature_set: + options.append("-DGMX_SIMD:STRING=None") + + # Use the 'rtdscp' assembly instruction only on + # appropriate architectures + options.append(self.define("GMX_USE_RDTSCP", str(target.family) in ("x86_64", "x86"))) + + if self.spec.satisfies("@:2020"): + options.append(self.define_from_variant("GMX_BUILD_MDRUN_ONLY", "mdrun_only")) + + options.append(self.define_from_variant("GMX_OPENMP", "openmp")) + + if self.spec.satisfies("@:2020"): + options.append( + self.define_from_variant( + "GMX_RELAXED_DOUBLE_PRECISION", "relaxed_double_precision" + ) + ) + + if self.spec.satisfies("+cycle_subcounters"): + options.append("-DGMX_CYCLE_SUBCOUNTERS:BOOL=ON") + else: + options.append("-DGMX_CYCLE_SUBCOUNTERS:BOOL=OFF") + + if "+openmp" in self.spec and self.spec.variants["openmp_max_threads"].value != "none": + options.append( + "-DGMX_OPENMP_MAX_THREADS=%s" % self.spec.variants["openmp_max_threads"].value + ) + if self.spec.satisfies("+nvshmem"): + options.append("-DGMX_NVSHMEM:BOOL=ON") + nvshmem_root = join_path( + self.spec["nvhpc"].prefix, + f"Linux_{self.spec.target.family}", + self.spec["nvhpc"].version, + "comm_libs", + "nvshmem", + ) + options.append(f"-DNVSHMEM_ROOT={nvshmem_root}") + + if self.spec.satisfies("^[virtuals=lapack] intel-oneapi-mkl"): + # fftw-api@3 is provided by intel-oneapi-mkl + options.append("-DGMX_FFT_LIBRARY=mkl") + if self.spec.satisfies("@:2022"): + options.append( + "-DMKL_INCLUDE_DIR={0}".format(self.spec["mkl"].headers.directories[0]) + ) + # The 'blas' property provides a minimal set of libraries + # that is sufficient for fft. Using full mkl fails the cmake test + options.append("-DMKL_LIBRARIES={0}".format(self.spec["blas"].libs.joined(";"))) + else: + # we rely on the fftw-api@3 + options.append("-DGMX_FFT_LIBRARY=fftw3") + if self.spec.satisfies("^[virtuals=fftw-api] amdfftw"): + options.append("-DGMX_FFT_LIBRARY=fftw3") + options.append( + "-DFFTWF_INCLUDE_DIRS={0}".format(self.spec["amdfftw"].headers.directories[0]) + ) + options.append( + "-DFFTWF_LIBRARIES={0}".format(self.spec["amdfftw"].libs.joined(";")) + ) + elif self.spec.satisfies("^armpl-gcc"): + options.append( + "-DFFTWF_INCLUDE_DIR={0}".format(self.spec["armpl-gcc"].headers.directories[0]) + ) + options.append( + "-DFFTWF_LIBRARY={0}".format(self.spec["armpl-gcc"].libs.joined(";")) + ) + elif self.spec.satisfies("^acfl"): + options.append( + "-DFFTWF_INCLUDE_DIR={0}".format(self.spec["acfl"].headers.directories[0]) + ) + options.append("-DFFTWF_LIBRARY={0}".format(self.spec["acfl"].libs.joined(";"))) + + # Ensure that the GROMACS log files report how the code was patched + # during the build, so that any problems are easier to diagnose. + if self.spec.satisfies("+plumed"): + options.append("-DGMX_VERSION_STRING_OF_FORK=PLUMED-spack") + else: + options.append("-DGMX_VERSION_STRING_OF_FORK=spack") + return options + + def setup_build_environment(self, env: EnvironmentModifications) -> None: + if self.spec.satisfies("+cufftmp"): + env.append_path( + "LD_LIBRARY_PATH", + join_path( + self.spec["nvhpc"].prefix, + f"Linux_{self.spec.target.family}", + self.spec["nvhpc"].version, + "comm_libs", + "nvshmem", + "lib", + ), + ) diff --git a/recipes/gromacs/2025/gh200-mpi/repo/packages/plumed/package.py b/recipes/gromacs/2025/gh200-mpi/repo/packages/plumed/package.py new file mode 100644 index 000000000..b6ab12006 --- /dev/null +++ b/recipes/gromacs/2025/gh200-mpi/repo/packages/plumed/package.py @@ -0,0 +1,345 @@ +# Copyright Spack Project Developers. See COPYRIGHT file for details. +# +# SPDX-License-Identifier: (Apache-2.0 OR MIT) + +import collections +import os +from pathlib import Path + +from spack_repo.builtin.build_systems.autotools import AutotoolsPackage + +from spack.package import * + + +class Plumed(AutotoolsPackage): + """PLUMED is an open source library for free energy calculations in + molecular systems which works together with some of the most popular + molecular dynamics engines. + + Free energy calculations can be performed as a function of many order + parameters with a particular focus on biological problems, using state + of the art methods such as metadynamics, umbrella sampling and + Jarzynski-equation based steered MD. + + The software, written in C++, can be easily interfaced with both fortran + and C/C++ codes. + """ + + homepage = "https://www.plumed.org/" + url = "https://github.com/plumed/plumed2/archive/v2.7.4.tar.gz" + git = "https://github.com/plumed/plumed2.git" + maintainers("marcodelapierre") + + tags = ["e4s"] + + license("LGPL-3.0-or-later") + + version("master", branch="master") + + version("2.10.0", sha256="ca6410d47e91b4e0f953e1a8933f15b05c4681167611ab3b096ab121155f6879") + version("2.9.2", sha256="301fbc958374f81d9b8c7a1eac73095f6dded52cce73ce33d64bdbebf51ac63d") + version("2.9.1", sha256="e24563ad1eb657611918e0c978d9c5212340f128b4f1aa5efbd439a0b2e91b58") + version("2.9.0", sha256="612d2387416b5f82dd8545709921440370e144fd46cef633654cf0ee43bac5f8") + + version("2.8.3", sha256="e98da486e252cdf290b0b5b2f3f021409ea0d2d775ab609a6ad68fc1ab143a3b") + version("2.8.2", sha256="a2064bacba1dde36b05aaf351ba4b7e6d30a165b332b0a83b7a6db04b477be9f") + version("2.8.1", sha256="f56bc9266c8a47241385c595717c2734a9b67148a7f4122b808bc0733710173e") + version("2.8.0", sha256="8357eca6f280125037ad4e7c427f96f2af2f60ddfedce1a2e36e1e1cc3bff32b") + + version("2.7.6", sha256="9ca7b1e84bf2343a09a5b604222dd04aa0fc8b62a7cb82d1d68b795b6b189c06") + version("2.7.5", sha256="39cb01108706df7ef71c7c315ddfc4306137f62ac72222b8582ab892221f7972") + version("2.7.4", sha256="6f5dc16a753c71ed719f17f9cbb61642ab8e716fb7f77e22960dfa145c3b8211") + version("2.7.3", sha256="aa1f6200c2ed351e40ce4391a9590f171532474b30f384feddfab10e36d7e08e") + version("2.7.2", sha256="c9a31e68d6440828cf186ca43c9e11a5e5c7ad1c96b2b66ed5a5a141fc954373") + version("2.7.1", sha256="cb8b5735d8dd61980fa6441f3dde3f33544240ae4177da0f529fb5abb355cd4a") + version("2.7.0", sha256="14450ea566c25ac9bf71fd77bb9c0c95e9038462b5739c73a515be82e2011cd6") + + version("2.6.6", sha256="43a7bb410280141c020363671c685a759d4497b3db3eb3c04899264b51a26859") + version("2.6.5", sha256="3b72587ba6fe72def46bcc7d917974123279879de7f8335acf542bba57865eed") + version("2.6.4", sha256="53e49c0db6cc769d238834bea884e856f4e7bb8f71c9929e5584bd977113f03b") + version("2.6.3", sha256="d05b9e4a4c1329fc932d5bdd04f20419be230f98159bdc012a91716461ab4a2f") + version("2.6.2", sha256="bbc2ef0cb08d404513b8b737c72333b6656389e15effd6a0f9ace2a5758c9a4a") + version("2.6.1", sha256="c1b3c397b2d971140aa240dde50e48a04ce78e3dedb02b6dca80fa53f8026e4e") + version("2.6.0", sha256="3d57ae460607a49547ef38a52c4ac93493a3966857c352280a9c05f5dcdb1820") + + version("2.5.7", sha256="aa10d2879c3edeaef9d5a530fe8b05f67ecfbec2e9423e0f95701d0bc54826c7") + version("2.5.6", sha256="1bc29b0274196fb553cdf7ba8ecb7a93a91d60a920d99863edbcd536d618ce8c") + version("2.5.5", sha256="70faa9ff1938e286dc388cb793b39840953e5646855b684f48df1bc864b737e8") + version("2.5.4", sha256="a1647e598191f261e75d06351e607475d395af481315052a4c28563ac9989a7f") + version("2.5.3", sha256="543288be667dc4201fc461ecd2dd4878ddfbeac682d0c021c99ea8e501c7c9dc") + version("2.5.2", sha256="85d10cc46e2e37c7719cf51c0931278f56c2c8f8a9d86188b2bf97c2535a2ab4") + version("2.5.1", sha256="de309980dcfd6f6e0e70e138856f4bd9eb4d8a513906a5e6389f18a5af7f2eba") + version("2.5.0", sha256="53e08187ec9f8af2326fa84407e34644a7c51d2af93034309fb70675eee5e4f7") + + # Variants. PLUMED by default builds a number of optional modules. + # The ones listed here are not built by default for various reasons, + # such as stability, lack of testing, or lack of demand. + # + # From 'configure --help' @2.3: + # all/none/reset or : separated list such as + # +crystallization:-bias default: reset + # + # Optional modules can be provided in two ways, via the `optional_modules` variant: + # 1. Use a reference set of optional modules via `optional_modules` (recommended). + # Allowed values are: `all`[default], `reset`. + # 2. Pick any combination of specific optional modules (advanced). + # Only the requested optional modules will be activated. + # See list in variable `single_optional_modules` below. + # This list comes from the Plumed manual, eg for 2.8: + # https://www.plumed.org/doc-v2.8/user-doc/html/mymodules.html + # These are implemented using multi-valued variants (`disjoint_sets`), + # and the `conditional` option to handle version conflicts. + single_optional_modules = ( + "adjmat", + "analysis", + conditional("annfunc", when="@2.6:"), + "bias", + "cltools", + "colvar", + "crystallization", + "dimred", + "drr", + "eds", + conditional("fisst", when="@2.7:"), + "function", + conditional("funnel", when="@2.7:"), + "generic", + "isdb", + "logmfd", + "manyrestraints", + "mapping", + conditional("maze", when="@2.6:"), + "molfile", + "multicolvar", + conditional("opes", when="@2.7:"), + conditional("pamm", when="optional_modules=adjmat"), + "piv", + conditional("s2cm", when="@2.8:"), + conditional("sasa", when="@2.8:"), + "secondarystructure", + "setup", + "vatom", + "ves", + conditional("xdrfile", when="@2.8:"), + ) + + variant( + "optional_modules", + values=disjoint_sets(("all",), ("reset",), single_optional_modules) + .prohibit_empty_set() + .with_default("all"), + description="Activates optional modules: all, reset, or custom list (advanced)", + ) + + variant("shared", default=True, description="Builds shared libraries") + variant("mpi", default=True, description="Activates MPI support") + variant("gsl", default=True, description="Activates GSL support") + variant( + "arrayfire", + default="none", + values=("none", "cpu", "cuda", "opencl"), + description="Activates FireArray support", + ) + variant("pytorch", default=False, description="Activates PyTorch support", when="@2.9:") + variant("metatomic", default=False, description="Activates metatomic support", when="@2.10:") + + depends_on("c", type="build") # generated + depends_on("cxx", type="build") # generated + depends_on("fortran", type="build") # generated + + # Dependencies. LAPACK and BLAS are recommended but not essential. + depends_on("zlib-api") + depends_on("blas") + depends_on("lapack") + depends_on("arrayfire", when="arrayfire=cpu") + depends_on("arrayfire+cuda", when="arrayfire=cuda") + depends_on("arrayfire+opencl", when="arrayfire=opencl") + + depends_on("mpi", when="+mpi") + depends_on("gsl", when="+gsl") + + depends_on("autoconf", type="build") + depends_on("automake", type="build") + depends_on("libtool", type="build") + depends_on("m4", type="build") + depends_on("py-cython", type="build") + + depends_on("py-torch", when="+pytorch") + conflicts("+metatomic ~pytorch", msg="metatomic support requires PyTorch") + depends_on("libmetatomic-torch", when="+metatomic") + + # https://github.com/plumed/plumed2/issues/1256 + conflicts("^py-cython@3.1:", when="@:2.9.3") + + force_autoreconf = True + + parallel = True + + def apply_patch(self, other): + # The name of MD engines differ slightly from the ones used in Spack + format_strings = collections.defaultdict(lambda: "{0.name}-{0.version}") + format_strings["espresso"] = "q{0.name}-{0.version}" + format_strings["amber"] = "{0.name}{0.version}" + + get_md = lambda x: format_strings[x.name].format(x) + + # Get available patches + plumed_patch = Executable(os.path.join(self.spec.prefix.bin, "plumed-patch")) + + out = plumed_patch("-q", "-l", output=str) + available = out.split(":")[-1].split() + + # Check that `other` is among the patchable applications + if get_md(other) not in available: + msg = "{0.name}@{0.version} is not among the MD engine" + msg += " that can be patched by {1.name}@{1.version}.\n" + msg += "Supported engines are:\n" + for x in available: + msg += x + "\n" + raise RuntimeError(msg.format(other, self.spec)) + + # Call plumed-patch to patch executables + target = format_strings[other.name].format(other) + plumed_patch("-p", "-e", target) + + def setup_dependent_package(self, module, dependent_spec): + # Make plumed visible from dependent packages + module.plumed = self.command + + @property + def plumed_inc(self): + return os.path.join(self.prefix.lib, "plumed", "src", "lib", "Plumed.inc") + + @run_before("autoreconf") + def filter_gslcblas(self): + # This part is needed to avoid linking with gsl cblas + # interface which will mask the cblas interface + # provided by optimized libraries due to linking order + filter_file("-lgslcblas", "", "configure.ac") + + def patch(self): + # Ensure Spack's wrappers are used to compile the Python interface + env = ( + 'CC="{0}" LDSHARED="{0} -pthread -shared" ' + 'CXX="{1}" LDCXXSHARED="{1} -pthread -shared"'.format(spack_cc, spack_cxx) + ) + filter_file( + "plumed_program_name=plumed", + "{0} plumed_program_name=plumed".format(env), + "src/lib/Makefile", + "python/Makefile", + ) + + def configure_args(self): + spec = self.spec + + # From plumed docs : + # Also consider that this is different with respect to what some other + # configure script does in that variables such as MPICXX are + # completely ignored here. In case you work on a machine where CXX is + # set to a serial compiler and MPICXX to a MPI compiler, to compile + # with MPI you should use: + # + # > ./configure CXX="$MPICXX" + + # The configure.ac script may detect the wrong linker for + # LD_RO which causes issues at link time. Here we work around + # the issue saying we have no LD_RO executable. + configure_opts = ["--disable-ld-r"] + + configure_opts.append("--disable-doc") + + # If using MPI then ensure the correct compiler wrapper is used. + if "+mpi" in spec: + configure_opts.extend(["--enable-mpi", "CXX={0}".format(spec["mpi"].mpicxx)]) + + # If the MPI dependency is provided by the intel-oneapi-mpi package then the following + # additional argument is required to allow it to build. + if spec.satisfies("^[virtuals=mpi] intel-oneapi-mpi"): + configure_opts.extend(["STATIC_LIBS=-mt_mpi"]) + + enable_libmetatomic = self.spec.satisfies("+metatomic") + enable_libtorch = self.spec.satisfies("+pytorch") or self.spec.satisfies("+metatomic") + + extra_ldflags = [] + extra_libs = [] + extra_cppflags = [] + # Set flags to help find gsl + if "+gsl" in spec: + gsl_libs = spec["gsl"].libs + blas_libs = spec["blas"].libs + extra_ldflags.append((gsl_libs + blas_libs).search_flags) + extra_libs.append((gsl_libs + blas_libs).link_flags) + extra_cppflags.extend( + [spec["gsl"].headers.include_flags, spec["blas"].headers.include_flags] + ) + # Set flags to help with ArrayFire + if "arrayfire=none" not in spec: + libaf = "arrayfire:{0}".format(spec.variants["arrayfire"].value) + extra_ldflags.append(spec[libaf].libs.search_flags) + extra_libs.append(spec[libaf].libs.link_flags) + extra_cppflags.append(spec[libaf].headers.include_flags) + # Set flags to help with PyTorch + if enable_libtorch: + pytorch_path = Path(spec["py-torch"].package.cmake_prefix_paths[0]).parent.parent + extra_ldflags.append(spec["py-torch"].libs.search_flags) + extra_libs.append(spec["py-torch"].libs.link_flags) + # Add include paths manually + # Spack HeaderList.cpp_flags does not support include paths within include paths + extra_cppflags.extend( + [ + f"-I{pytorch_path / 'include'}", + f"-I{pytorch_path / 'include' / 'torch' / 'csrc' / 'api' / 'include'}", + ] + ) + if enable_libmetatomic: + for libname in ["libmetatensor", "libmetatensor-torch", "libmetatomic-torch"]: + extra_ldflags.append(spec[libname].libs.search_flags) + extra_libs.append(spec[libname].libs.link_flags) + extra_cppflags.append(spec[libnamd].headers.include_flags) + + if extra_ldflags: + configure_opts.append("LDFLAGS={0}".format(" ".join(extra_ldflags))) + + if extra_libs: + configure_opts.append("LIBS={0}".format(" ".join(extra_libs))) + + if extra_cppflags: + configure_opts.append("CPPFLAGS={0}".format(" ".join(extra_cppflags))) + + # Additional arguments + configure_opts.extend( + [ + "--enable-shared={0}".format("yes" if "+shared" in spec else "no"), + "--enable-gsl={0}".format("yes" if "+gsl" in spec else "no"), + "--enable-af_cpu={0}".format("yes" if "arrayfire=cpu" in spec else "no"), + "--enable-af_cuda={0}".format("yes" if "arrayfire=cuda" in spec else "no"), + "--enable-af_ocl={0}".format("yes" if "arrayfire=ocl" in spec else "no"), + "--enable-libtorch={0}".format("yes" if enable_libtorch else "no"), + "--enable-libmetatomic={0}".format("yes" if enable_libmetatomic else "no"), + ] + ) + + # Construct list of optional modules + optional_modules = spec.variants["optional_modules"].value + + # Predefined set of modules + if "all" in optional_modules: + selected_modules = "all" + elif "reset" in optional_modules: + selected_modules = "reset" + # Custom set of modules + else: + # Ensure modules from variants + if spec.satisfies("+pytorch") or sepec.satisfies("+metatomic"): + optional_modules += ("pytorch",) + if spec.satisfies("+libmetatomic"): + optional_modules += ("metatomic",) + + selected_modules = "none" + for mod in optional_modules: + selected_modules += ":+{0}".format(mod) + + configure_opts.append("--enable-modules={0}".format(selected_modules)) + + return configure_opts