312 lines
12 KiB
Python
312 lines
12 KiB
Python
# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
|
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
|
#
|
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
|
|
|
import os
|
|
import platform
|
|
import sys
|
|
|
|
import llnl.util.tty as tty
|
|
|
|
from spack.package import *
|
|
|
|
|
|
class Namd(MakefilePackage, CudaPackage):
|
|
"""NAMD is a parallel molecular dynamics code designed for
|
|
high-performance simulation of large biomolecular systems."""
|
|
|
|
homepage = "https://www.ks.uiuc.edu/Research/namd/"
|
|
url = "file://{0}/NAMD_2.12_Source.tar.gz".format(os.getcwd())
|
|
git = "https://charm.cs.illinois.edu/gerrit/namd.git"
|
|
manual_download = True
|
|
redistribute(source=False, binary=False)
|
|
|
|
maintainers("jcphill")
|
|
|
|
version("master", branch="master")
|
|
version("3.0b6", sha256="8b5fb1dc8d5b5666c6a45d20ee7e8c9d1f5c186578e2cf148b68ba421d43b850")
|
|
version("3.0b3", sha256="20c32b6161f9c376536e3cb97c3bfe5367e1baaaace3c716ff79831fc2eb8199")
|
|
version("2.15a2", sha256="8748cbaa93fc480f92fc263d9323e55bce6623fc693dbfd4a40f59b92669713e")
|
|
version("2.15a1", branch="master", tag="release-2-15-alpha-1")
|
|
# Same as above, but lets you use a local file instead of git
|
|
version(
|
|
"2.15a1.manual", sha256="474006e98e32dddae59616b3b75f13a2bb149deaf7a0d617ce7fb9fd5a56a33a"
|
|
)
|
|
version(
|
|
"2.14",
|
|
sha256="34044d85d9b4ae61650ccdba5cda4794088c3a9075932392dd0752ef8c049235",
|
|
preferred=True,
|
|
)
|
|
version("2.13", md5="9e3323ed856e36e34d5c17a7b0341e38")
|
|
version("2.12", md5="2a1191909b1ab03bf0205971ad4d8ee9")
|
|
|
|
variant(
|
|
"fftw",
|
|
default="3",
|
|
values=("none", "2", "3", "mkl", "amdfftw"),
|
|
description="Enable the use of FFTW/FFTW3/MKL FFT/AMDFFTW",
|
|
)
|
|
|
|
variant(
|
|
"interface",
|
|
default="tcl",
|
|
values=("none", "tcl", "python"),
|
|
description="Enables Tcl and/or python interface",
|
|
)
|
|
|
|
variant("avxtiles", when="target=x86_64_v4:", default=False, description="Enable avxtiles")
|
|
variant("single_node_gpu", default=False, description="Single node GPU")
|
|
|
|
# init_tcl_pointers() declaration and implementation are inconsistent
|
|
# "src/colvarproxy_namd.C", line 482: error: inherited member is not
|
|
# allowed
|
|
patch("inherited-member-2.13.patch", when="@2.13")
|
|
patch("inherited-member-2.14.patch", when="@2.14")
|
|
# Handle change in python-config for python@3.8:
|
|
patch("namd-python38.patch", when="interface=python ^python@3.8:")
|
|
|
|
depends_on("charmpp@7.0.0:", when="@3.0:")
|
|
depends_on("charmpp@6.10.1:6", when="@2.14:2")
|
|
depends_on("charmpp@6.8.2", when="@2.13")
|
|
depends_on("charmpp@6.7.1", when="@2.12")
|
|
|
|
depends_on("fftw@:2", when="fftw=2")
|
|
depends_on("fftw@3:", when="fftw=3")
|
|
|
|
depends_on("amdfftw", when="fftw=amdfftw")
|
|
|
|
depends_on("mkl", when="fftw=mkl")
|
|
|
|
depends_on("tcl", when="interface=tcl")
|
|
|
|
depends_on("tcl", when="interface=python")
|
|
depends_on("python", when="interface=python")
|
|
|
|
conflicts("+avxtiles", when="@:2.14,3:", msg="AVXTiles algorithm requires NAMD 2.15")
|
|
|
|
# https://www.ks.uiuc.edu/Research/namd/2.12/features.html
|
|
# https://www.ks.uiuc.edu/Research/namd/2.13/features.html
|
|
# https://www.ks.uiuc.edu/Research/namd/2.14/features.html
|
|
depends_on("cuda@6.5.14:7.5.18", when="@2.12 +cuda")
|
|
depends_on("cuda@8.0.61:", when="@2.13: +cuda")
|
|
|
|
def _copy_arch_file(self, lib):
|
|
config_filename = "arch/{0}.{1}".format(self.arch, lib)
|
|
if self.arch == "linux-aarch64":
|
|
copy("arch/Linux-ARM64.{0}".format(lib), config_filename)
|
|
else:
|
|
copy("arch/Linux-x86_64.{0}".format(lib), config_filename)
|
|
|
|
if lib == "tcl":
|
|
filter_file(
|
|
r"-ltcl8\.5", "-ltcl{0}".format(self.spec["tcl"].version.up_to(2)), config_filename
|
|
)
|
|
|
|
def _append_option(self, opts, lib):
|
|
if lib != "python":
|
|
self._copy_arch_file(lib)
|
|
spec = self.spec
|
|
lib_prefix = (
|
|
spec[lib].package.component_prefix
|
|
if spec[lib].name == "intel-oneapi-mkl"
|
|
else spec[lib].prefix
|
|
)
|
|
opts.extend(["--with-{0}".format(lib), "--{0}-prefix".format(lib), lib_prefix])
|
|
|
|
@property
|
|
def arch(self):
|
|
plat = sys.platform
|
|
if plat.startswith("linux"):
|
|
plat = "linux"
|
|
march = platform.machine()
|
|
return "{0}-{1}".format(plat, march)
|
|
|
|
@property
|
|
def build_directory(self):
|
|
return "{0}-spack".format(self.arch)
|
|
|
|
def _edit_arch_generic(self, spec, prefix):
|
|
"""Generic arch makefile generation"""
|
|
m64 = "-m64 " if not spec.satisfies("arch=aarch64:") else ""
|
|
with working_dir("arch"):
|
|
with open("{0}.arch".format(self.build_directory), "w") as fh:
|
|
# this options are take from the default provided
|
|
# configuration files
|
|
# https://github.com/UIUC-PPL/charm/pull/2778
|
|
archopt = spec.architecture.target.optimization_flags(spec.compiler)
|
|
|
|
if self.spec.satisfies("^charmpp@:6.10.1"):
|
|
optims_opts = {
|
|
"gcc": m64
|
|
+ "-O3 -fexpensive-optimizations \
|
|
-ffast-math -lpthread "
|
|
+ archopt,
|
|
"intel": "-O2 -ip -qopenmp-simd" + archopt,
|
|
"clang": m64 + "-O3 -ffast-math -fopenmp " + archopt,
|
|
"aocc": m64
|
|
+ "-O3 -ffp-contract=fast -ffast-math \
|
|
-fopenmp "
|
|
+ archopt,
|
|
}
|
|
else:
|
|
optims_opts = {
|
|
"gcc": m64
|
|
+ "-O3 -fexpensive-optimizations \
|
|
-ffast-math -lpthread "
|
|
+ archopt,
|
|
"intel": "-O2 -ip " + archopt,
|
|
"clang": m64 + "-O3 -ffast-math -fopenmp " + archopt,
|
|
"aocc": m64
|
|
+ "-O3 -ffp-contract=fast \
|
|
-ffast-math "
|
|
+ archopt,
|
|
}
|
|
|
|
if self.spec.satisfies("+avxtiles"):
|
|
optims_opts["aocc"] += " -DNAMD_AVXTILES"
|
|
optims_opts["clang"] += " -DNAMD_AVXTILES"
|
|
optims_opts["gcc"] += " -DNAMD_AVXTILES"
|
|
optims_opts["intel"] += " -DNAMD_AVXTILES"
|
|
|
|
optim_opts = (
|
|
optims_opts[self.compiler.name] if self.compiler.name in optims_opts else ""
|
|
)
|
|
|
|
fh.write(
|
|
"\n".join(
|
|
[
|
|
"NAMD_ARCH = {0}".format(self.arch),
|
|
"CHARMARCH = {0}".format(self.spec["charmpp"].charmarch),
|
|
"CXX = {0.cxx} {0.cxx11_flag}".format(self.compiler),
|
|
"CXXOPTS = {0}".format(optim_opts),
|
|
"CC = {0}".format(self.compiler.cc),
|
|
"COPTS = {0}".format(optim_opts),
|
|
"",
|
|
]
|
|
)
|
|
)
|
|
|
|
def _edit_arch_target_based(self, spec, prefix):
|
|
"""Try to use target base arch file return True if succeed"""
|
|
if spec.version < Version("2.14"):
|
|
return False
|
|
|
|
found_special_opt = False
|
|
with working_dir("arch"):
|
|
arch_filename = "{0}.arch".format(self.build_directory)
|
|
|
|
replace = [
|
|
[r"^CHARMARCH = .*$", "CHARMARCH = {0}".format(self.spec["charmpp"].charmarch)],
|
|
[r"^NAMD_ARCH = .*$", "NAMD_ARCH = {0}".format(self.arch)],
|
|
]
|
|
|
|
# Optimizations for skylake_avx512
|
|
if (
|
|
spec.platform == "linux"
|
|
and self.compiler.name == "intel"
|
|
and "avx512" in spec.target
|
|
and spec.target >= "skylake_avx512"
|
|
):
|
|
if spec.version >= Version("2.15") and os.path.exists("Linux-AVX512-icc.arch"):
|
|
tty.info("Building binaries with AVX512-tile optimization")
|
|
copy("Linux-AVX512-icc.arch", arch_filename)
|
|
elif spec.version >= Version("2.14") and os.path.exists("Linux-SKX-icc.arch"):
|
|
tty.info("Building binaries with Skylake-X" "AVX512 optimization")
|
|
copy("Linux-SKX-icc.arch", arch_filename)
|
|
else:
|
|
return False
|
|
|
|
replace.append([r"^CXX = icpc", "CXX = {0}".format(self.compiler.cxx)])
|
|
replace.append([r"^CC = icc", "CC = {0}".format(self.compiler.cc)])
|
|
found_special_opt = True
|
|
|
|
if found_special_opt:
|
|
for pattern, replacement in replace:
|
|
filter_file(pattern, replacement, arch_filename)
|
|
|
|
return found_special_opt
|
|
|
|
def _edit_arch(self, spec, prefix):
|
|
"""Try to use target base arch file, if not make generic"""
|
|
if not self._edit_arch_target_based(spec, prefix):
|
|
self._edit_arch_generic(spec, prefix)
|
|
|
|
def edit(self, spec, prefix):
|
|
self._edit_arch(spec, prefix)
|
|
|
|
self._copy_arch_file("base")
|
|
|
|
opts = ["--charm-base", spec["charmpp"].prefix]
|
|
fftw_version = spec.variants["fftw"].value
|
|
if fftw_version == "none":
|
|
opts.append("--without-fftw")
|
|
elif fftw_version == "mkl":
|
|
self._append_option(opts, "mkl")
|
|
elif fftw_version == "amdfftw":
|
|
self._copy_arch_file("fftw3")
|
|
opts.extend(["--with-fftw3", "--fftw-prefix", spec["amdfftw"].prefix])
|
|
else:
|
|
_fftw = "fftw{0}".format("" if fftw_version == "2" else "3")
|
|
|
|
self._copy_arch_file(_fftw)
|
|
opts.extend(["--with-{0}".format(_fftw), "--fftw-prefix", spec["fftw"].prefix])
|
|
|
|
interface_type = spec.variants["interface"].value
|
|
if interface_type != "none":
|
|
self._append_option(opts, "tcl")
|
|
|
|
if interface_type == "python":
|
|
self._append_option(opts, "python")
|
|
else:
|
|
opts.extend(["--without-tcl", "--without-python"])
|
|
|
|
if "+cuda" in spec:
|
|
self._append_option(opts, "cuda")
|
|
filter_file(
|
|
"^CUDADIR=.*$",
|
|
"CUDADIR={0}".format(spec["cuda"].prefix),
|
|
join_path("arch", self.arch + ".cuda"),
|
|
)
|
|
for cuda_arch in spec.variants["cuda_arch"].value:
|
|
opts.extend(["--cuda-gencode", f"arch=compute_{cuda_arch},code=sm_{cuda_arch}"])
|
|
|
|
if "+single_node_gpu" in spec:
|
|
opts.extend(["--with-single-node-cuda"])
|
|
|
|
config = Executable("./config")
|
|
|
|
config(self.build_directory, *opts)
|
|
|
|
# patch Make.config if needed
|
|
# spack install charmpp straight to prefix
|
|
# (not to $(CHARMBASE)/$(CHARMARCH))
|
|
if not os.path.exists(
|
|
join_path(self.spec["charmpp"].prefix, self.spec["charmpp"].charmarch)
|
|
):
|
|
filter_file(
|
|
r"^CHARM = \$\(CHARMBASE\)/\$\(CHARMARCH\)",
|
|
"CHARM = $(CHARMBASE)",
|
|
join_path(self.build_directory, "Make.config"),
|
|
)
|
|
|
|
@when("@3.0b3")
|
|
def build(self, spec, prefix):
|
|
# Disable parallel build
|
|
# https://github.com/spack/spack/pull/43215
|
|
with working_dir(self.build_directory):
|
|
make(parallel=False)
|
|
|
|
def install(self, spec, prefix):
|
|
with working_dir(self.build_directory):
|
|
mkdirp(prefix.bin)
|
|
if spec.version < Version("3"):
|
|
install("namd2", prefix.bin)
|
|
else:
|
|
install("namd3", prefix.bin)
|
|
install("psfgen", prefix.bin)
|
|
|
|
# I'm not sure this is a good idea or if an autoload of the charm
|
|
# module would not be better.
|
|
install("charmrun", prefix.bin)
|