-
Notifications
You must be signed in to change notification settings - Fork 301
Update LAMMPS easyblock: v2025 fix + extra tests #3894
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
811ecb0
57204fb
294d28e
3e28f44
217e21d
a947538
e164235
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -46,7 +46,7 @@ | |||||||||||||||
from easybuild.tools.filetools import copy_dir, copy_file, mkdir, read_file | ||||||||||||||||
from easybuild.tools.modules import get_software_root, get_software_version | ||||||||||||||||
from easybuild.tools.run import run_shell_cmd | ||||||||||||||||
from easybuild.tools.systemtools import AARCH64, get_cpu_architecture, get_shared_lib_ext | ||||||||||||||||
from easybuild.tools.systemtools import AARCH64, get_cpu_architecture, get_shared_lib_ext, get_avail_core_count | ||||||||||||||||
from easybuild.tools.toolchain.compiler import OPTARCH_GENERIC | ||||||||||||||||
|
||||||||||||||||
from easybuild.easyblocks.generic.cmakemake import CMakeMake | ||||||||||||||||
|
@@ -359,7 +359,7 @@ def prepare_step(self, *args, **kwargs): | |||||||||||||||
# version 1.3.2 is used in the test suite to check easyblock can be initialised | ||||||||||||||||
if self.version != '1.3.2': | ||||||||||||||||
# take into account that build directory may not be available (in case of --module-only) | ||||||||||||||||
if os.path.exists(self.start_dir) and os.listdir(self.start_dir): | ||||||||||||||||
if self.start_dir and os.path.exists(self.start_dir) and os.listdir(self.start_dir): | ||||||||||||||||
self.cur_version = translate_lammps_version(self.version, path=self.start_dir) | ||||||||||||||||
else: | ||||||||||||||||
self.cur_version = translate_lammps_version(self.version, path=self.installdir) | ||||||||||||||||
|
@@ -471,30 +471,19 @@ def configure_step(self, **kwargs): | |||||||||||||||
# https://docs.lammps.org/Build_basics.html | ||||||||||||||||
# https://docs.lammps.org/Build_settings.html | ||||||||||||||||
# https://docs.lammps.org/Build_package.html | ||||||||||||||||
# https://docs.lammps.org/Build_extras.html | ||||||||||||||||
if self.cfg['general_packages']: | ||||||||||||||||
for package in self.cfg['general_packages']: | ||||||||||||||||
self.cfg.update('configopts', '-D%s%s=on' % (self.pkg_prefix, package)) | ||||||||||||||||
|
||||||||||||||||
if self.cfg['user_packages']: | ||||||||||||||||
for package in self.cfg['user_packages']: | ||||||||||||||||
self.cfg.update('configopts', '-D%s%s=on' % (self.pkg_user_prefix, package)) | ||||||||||||||||
|
||||||||||||||||
# Optimization settings | ||||||||||||||||
# OPT package | ||||||||||||||||
pkg_opt = '-D%sOPT=' % self.pkg_prefix | ||||||||||||||||
if pkg_opt not in self.cfg['configopts']: | ||||||||||||||||
self.cfg.update('configopts', pkg_opt + 'on') | ||||||||||||||||
|
||||||||||||||||
# grab the architecture so we can check if we have Intel hardware (also used for Kokkos below) | ||||||||||||||||
processor_arch, gpu_arch = self.get_kokkos_arch(cuda_cc, self.cfg['kokkos_arch']) | ||||||||||||||||
|
||||||||||||||||
if processor_arch in INTEL_PACKAGE_ARCH_LIST or \ | ||||||||||||||||
(processor_arch == 'NATIVE' and self.kokkos_cpu_mapping.get(get_cpu_arch()) in INTEL_PACKAGE_ARCH_LIST): | ||||||||||||||||
# USER-INTEL enables optimizations on Intel processors. GCC has also partial support for some of them. | ||||||||||||||||
pkg_user_intel = '-D%sINTEL=' % self.pkg_user_prefix | ||||||||||||||||
if pkg_user_intel not in self.cfg['configopts']: | ||||||||||||||||
if self.toolchain.comp_family() in [toolchain.GCC, toolchain.INTELCOMP]: | ||||||||||||||||
self.cfg.update('configopts', pkg_user_intel + 'on') | ||||||||||||||||
|
||||||||||||||||
# MPI/OpenMP | ||||||||||||||||
if self.toolchain.options.get('usempi', None): | ||||||||||||||||
self.cfg.update('configopts', '-DBUILD_MPI=yes') | ||||||||||||||||
|
@@ -517,11 +506,27 @@ def configure_step(self, **kwargs): | |||||||||||||||
if '-DFFT_PACK=' not in self.cfg['configopts']: | ||||||||||||||||
self.cfg.update('configopts', '-DFFT_PACK=array') | ||||||||||||||||
|
||||||||||||||||
# https://lammps.sandia.gov/doc/Build_extras.html | ||||||||||||||||
# KOKKOS | ||||||||||||||||
# detect the CPU and GPU architecture (used for Intel and Kokkos packages belos) | ||||||||||||||||
processor_arch, gpu_arch = self.get_kokkos_arch(cuda_cc, self.cfg['kokkos_arch']) | ||||||||||||||||
|
||||||||||||||||
# INTEL package | ||||||||||||||||
self.pkg_intel = False | ||||||||||||||||
if processor_arch in INTEL_PACKAGE_ARCH_LIST or \ | ||||||||||||||||
(processor_arch == 'NATIVE' and self.kokkos_cpu_mapping.get(get_cpu_arch()) in INTEL_PACKAGE_ARCH_LIST): | ||||||||||||||||
# USER-INTEL enables optimizations on Intel processors. GCC has also partial support for some of them. | ||||||||||||||||
pkg_user_intel = '-D%sINTEL=' % self.pkg_user_prefix | ||||||||||||||||
if pkg_user_intel not in self.cfg['configopts']: | ||||||||||||||||
if self.toolchain.comp_family() in [toolchain.GCC, toolchain.INTELCOMP]: | ||||||||||||||||
self.cfg.update('configopts', pkg_user_intel + 'on') | ||||||||||||||||
self.pkg_intel = True | ||||||||||||||||
else: | ||||||||||||||||
self.pkg_intel = True | ||||||||||||||||
|
||||||||||||||||
# KOKKOS package | ||||||||||||||||
if self.cfg['kokkos']: | ||||||||||||||||
print_msg("Using Kokkos package with arch: CPU - %s, GPU - %s" % (processor_arch, gpu_arch)) | ||||||||||||||||
self.cfg.update('configopts', '-D%sKOKKOS=on' % self.pkg_prefix) | ||||||||||||||||
self.cfg.update('configopts', '-D%s_ENABLE_SERIAL=yes' % self.kokkos_prefix) | ||||||||||||||||
|
||||||||||||||||
if self.toolchain.options.get('openmp', None): | ||||||||||||||||
self.cfg.update('configopts', '-D%s_ENABLE_OPENMP=yes' % self.kokkos_prefix) | ||||||||||||||||
|
@@ -557,7 +562,7 @@ def configure_step(self, **kwargs): | |||||||||||||||
elif get_software_root("FFTW"): | ||||||||||||||||
self.cfg.update('configopts', '-DFFT_KOKKOS=FFTW3') | ||||||||||||||||
|
||||||||||||||||
# CUDA only | ||||||||||||||||
# GPU package (cannot be built with KOKKOS+CUDA) | ||||||||||||||||
elif self.cuda: | ||||||||||||||||
print_msg("Using GPU package (not Kokkos) with arch: CPU - %s, GPU - %s" % (processor_arch, gpu_arch)) | ||||||||||||||||
self.cfg.update('configopts', '-D%sGPU=on' % self.pkg_prefix) | ||||||||||||||||
|
@@ -568,6 +573,7 @@ def configure_step(self, **kwargs): | |||||||||||||||
# to lib64) | ||||||||||||||||
self.cfg.update('configopts', '-DCMAKE_INSTALL_LIBDIR=lib') | ||||||||||||||||
|
||||||||||||||||
# Python interface | ||||||||||||||||
# avoid that pip (ab)uses $HOME/.cache/pip | ||||||||||||||||
# cfr. https://pip.pypa.io/en/stable/reference/pip_install/#caching | ||||||||||||||||
env.setvar('XDG_CACHE_HOME', tempfile.gettempdir()) | ||||||||||||||||
|
@@ -602,6 +608,23 @@ def configure_step(self, **kwargs): | |||||||||||||||
else: | ||||||||||||||||
raise EasyBuildError("Expected to find a Python dependency as sanity check commands rely on it!") | ||||||||||||||||
|
||||||||||||||||
# Testing (PyYAML must be installed) | ||||||||||||||||
if self.cfg['runtest'] is None or self.cfg['runtest']: | ||||||||||||||||
if LooseVersion(self.cur_version) >= LooseVersion(translate_lammps_version('29Aug2024')): | ||||||||||||||||
# Testing of KOKKOS+CUDA builds does not work for version < 22Jul2025 | ||||||||||||||||
# See: https://github.com/lammps/lammps/issues/405 | ||||||||||||||||
if LooseVersion(self.cur_version) < LooseVersion(translate_lammps_version('22Jul2025')) \ | ||||||||||||||||
and self.cfg['kokkos'] and self.cuda: | ||||||||||||||||
print_warning("Skipping tests: KOKKOS+CUDA builds have broken testing in LAMMPS < 22Jul2025.") | ||||||||||||||||
self.cfg['runtest'] = False | ||||||||||||||||
else: | ||||||||||||||||
self.cfg['runtest'] = True | ||||||||||||||||
if 'PyYAML' not in (dep['name'] for dep in self.cfg.builddependencies()): | ||||||||||||||||
raise EasyBuildError("PyYAML not included as build dependency: cannot run tests.") | ||||||||||||||||
self.cfg.update('configopts', '-DENABLE_TESTING=on') | ||||||||||||||||
else: | ||||||||||||||||
self.cfg['runtest'] = False | ||||||||||||||||
|
||||||||||||||||
return super().configure_step() | ||||||||||||||||
|
||||||||||||||||
def install_step(self): | ||||||||||||||||
|
@@ -648,13 +671,27 @@ def install_step(self): | |||||||||||||||
|
||||||||||||||||
run_shell_cmd(cmd) | ||||||||||||||||
|
||||||||||||||||
def test_step(self): | ||||||||||||||||
"""Filter the ctests that should be run""" | ||||||||||||||||
# add flags to test_cmd to ignore some tests | ||||||||||||||||
if self.cfg.get('runtest') is True and not self.cfg.get('test_cmd'): | ||||||||||||||||
test_cmd = 'ctest' | ||||||||||||||||
if LooseVersion(self.cmake_version) >= '3.17.0': | ||||||||||||||||
test_cmd += ' --no-tests=error' | ||||||||||||||||
test_cmd += ' -LE unstable -E "TestMliapPyUnified|AtomicPairStyle:meam_spline|KSpaceStyle:scafacos.*"' | ||||||||||||||||
self.log.debug(f"Running tests using test_cmd = '{test_cmd}' as test_cmd") | ||||||||||||||||
self.cfg['test_cmd'] = test_cmd | ||||||||||||||||
|
||||||||||||||||
super().test_step() | ||||||||||||||||
|
||||||||||||||||
def sanity_check_step(self, *args, **kwargs): | ||||||||||||||||
"""Run custom sanity checks for LAMMPS files, dirs and commands.""" | ||||||||||||||||
|
||||||||||||||||
# Set cur_version when running --sanity-check-only | ||||||||||||||||
if self.cur_version is None: | ||||||||||||||||
self.cur_version = translate_lammps_version(self.version, path=self.installdir) | ||||||||||||||||
|
||||||||||||||||
# Test some LAMMPS examples | ||||||||||||||||
# Output files need to go somewhere (and has to work for --module-only as well) | ||||||||||||||||
execution_dir = tempfile.mkdtemp() | ||||||||||||||||
|
||||||||||||||||
|
@@ -676,15 +713,53 @@ def sanity_check_step(self, *args, **kwargs): | |||||||||||||||
for check_file in sanity_check_test_inputs | ||||||||||||||||
] | ||||||||||||||||
|
||||||||||||||||
# add accelerator-specific tests | ||||||||||||||||
if self.pkg_intel: # INTEL package | ||||||||||||||||
custom_commands.append( | ||||||||||||||||
'from lammps import lammps; l=lammps(cmdargs=["-sf", "intel"]); l.file("%s")' % | ||||||||||||||||
os.path.join(self.installdir, "examples", "msst", "in.msst") | ||||||||||||||||
) | ||||||||||||||||
if self.cfg['kokkos']: # KOKKOS package | ||||||||||||||||
if self.cuda: # NOTE: requires a GPU to run | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a difficult requirement to meet, we should be able to support a cross-compilation. In EESSI, for example, this is going to cause problems as we must cross-compile for a lot of architectures. You could make it conditional on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See for example easybuild-easyblocks/easybuild/easyblocks/t/tensorflow.py Lines 1048 to 1054 in 6a0f356
|
||||||||||||||||
custom_commands.append( | ||||||||||||||||
'from lammps import lammps; l=lammps(cmdargs=["-sf", "kk", "-k", "on", "g", "1"]); l.file("%s")' % | ||||||||||||||||
os.path.join(self.installdir, "examples", "msst", "in.msst") | ||||||||||||||||
) | ||||||||||||||||
else: | ||||||||||||||||
custom_commands.append( | ||||||||||||||||
'from lammps import lammps; l=lammps(cmdargs=["-sf", "kk", "-k", "on"]); l.file("%s")' % | ||||||||||||||||
os.path.join(self.installdir, "examples", "msst", "in.msst") | ||||||||||||||||
) | ||||||||||||||||
elif self.cuda: # GPU package | ||||||||||||||||
custom_commands.append( | ||||||||||||||||
'from lammps import lammps; l=lammps(cmdargs=["-sf", "gpu", "-pk", "gpu", "1"]); l.file("%s")' % | ||||||||||||||||
os.path.join(self.installdir, "examples", "msst", "in.msst") | ||||||||||||||||
) | ||||||||||||||||
if self.toolchain.options.get('openmp', None): # OPENMP package | ||||||||||||||||
custom_commands.append( | ||||||||||||||||
'from lammps import lammps; l=lammps(cmdargs=["-sf", "omp", "-pk", "omp", "2"]); l.file("%s")' % | ||||||||||||||||
os.path.join(self.installdir, "examples", "msst", "in.msst") | ||||||||||||||||
) | ||||||||||||||||
# OPT package | ||||||||||||||||
custom_commands.append( | ||||||||||||||||
'from lammps import lammps; l=lammps(cmdargs=["-sf", "opt"]); l.file("%s")' % | ||||||||||||||||
os.path.join(self.installdir, "examples", "msst", "in.msst") | ||||||||||||||||
) | ||||||||||||||||
|
||||||||||||||||
# mpirun command needs an l.finalize() in the sanity check from LAMMPS 29Sep2021 | ||||||||||||||||
if LooseVersion(self.cur_version) >= LooseVersion(translate_lammps_version('29Sep2021')): | ||||||||||||||||
# This is actually not needed if mpi4py is installed, and can cause a crash in version 2025+ | ||||||||||||||||
if LooseVersion(self.cur_version) >= LooseVersion(translate_lammps_version('29Sep2021')) and \ | ||||||||||||||||
LooseVersion(self.cur_version) < LooseVersion(translate_lammps_version('22Jul2025')): | ||||||||||||||||
custom_commands = [cmd + '; l.finalize()' for cmd in custom_commands] | ||||||||||||||||
|
||||||||||||||||
custom_commands = ["""python -c '%s'""" % cmd for cmd in custom_commands] | ||||||||||||||||
|
||||||||||||||||
# Execute sanity check commands within an initialized MPI in MPI enabled toolchains | ||||||||||||||||
if self.toolchain.options.get('usempi', None): | ||||||||||||||||
custom_commands = [self.toolchain.mpi_cmd_for(cmd, 1) for cmd in custom_commands] | ||||||||||||||||
# use up to 4 cores, to speed up tests | ||||||||||||||||
test_core_cnt = min(self.cfg.parallel, get_avail_core_count(), 4) | ||||||||||||||||
self.log.info("Using %s cores for the MPI tests" % test_core_cnt) | ||||||||||||||||
custom_commands = [self.toolchain.mpi_cmd_for(cmd, test_core_cnt) for cmd in custom_commands] | ||||||||||||||||
|
||||||||||||||||
custom_commands = ["cd %s && " % execution_dir + cmd for cmd in custom_commands] | ||||||||||||||||
|
||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.