Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 13 additions & 114 deletions easybuild/easyblocks/g/gromacs.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,8 @@ def extra_options():
'mpisuffix': ['_mpi', "Suffix to append to MPI-enabled executables (only for GROMACS < 4.6)", CUSTOM],
'mpiexec': ['mpirun', "MPI executable to use when running tests", CUSTOM],
'mpiexec_numproc_flag': ['-np', "Flag to introduce the number of MPI tasks when running tests", CUSTOM],
'mpi_only': [False, "Only build for MPI and skip nompi.", CUSTOM],
'mpi_numprocs': [0, "Number of MPI tasks to use when running tests", CUSTOM],
'ignore_plumed_version_check': [False, "Ignore the version compatibility check for PLUMED", CUSTOM],
'cp2k': [None, "Build with CP2K QM/MM. None is auto-detect. True or False forces behaviour.", CUSTOM],
'plumed': [None, "Try to apply PLUMED patches. None (default) is auto-detect. " +
"True or False forces behaviour.", CUSTOM],
})
Expand Down Expand Up @@ -119,21 +117,9 @@ def get_gromacs_arch(self):
# http://manual.gromacs.org/documentation/2018/install-guide/index.html#simd-support
if 'MIC-AVX512' in optarch and LooseVersion(self.version) >= LooseVersion('2016'):
res = 'AVX_512_KNL'
elif (('AVX512' in optarch or 'MARCH=X86-64-V4' in optarch) and
LooseVersion(self.version) >= LooseVersion('2016')):
if (LooseVersion(self.version) >= LooseVersion('2019') and
LooseVersion(self.version) < LooseVersion('2023') and
comp_fam == toolchain.GCC and get_software_root('imkl') and
re.search(r'GMX_DOUBLE=(1|ON|YES|TRUE)\b', self.cfg['configopts'].upper())):
# Workaround to DOUBLE precision builds being broken for AVX512 in GROMACS 2019.x
# and 2020.x when using toolchains with GCC and MKL.
# With GROMACS 2023.3 under StdEnv/2023 the issue is fixed.
# TODO: test with GROMACS 2021, 2022 under StdEnv/2020 & 2023 to narrow down further.
res = 'AVX2_256'
self.log.info("Falling back to AVX2_256 for GROMACS >= 2019 with GMX_DOUBLE=ON.")
else:
res = 'AVX_512'
elif ('AVX2' in optarch or 'MARCH=X86-64-V3' in optarch) and LooseVersion(self.version) >= LooseVersion('5.0'):
elif 'AVX512' in optarch and LooseVersion(self.version) >= LooseVersion('2016'):
res = 'AVX_512'
elif 'AVX2' in optarch and LooseVersion(self.version) >= LooseVersion('5.0'):
res = 'AVX2_256'
elif 'AVX' in optarch:
res = 'AVX_256'
Expand Down Expand Up @@ -228,65 +214,6 @@ def configure_step(self):
# to avoid that GROMACS finds and uses a system-wide CUDA compiler
self.cfg.update('configopts', "-DGMX_GPU=OFF")

# CP2K detection
# enable CP2K support if CP2K is listed as a dependency
# and CP2K support is either explicitly enabled (cp2k = True) or unspecified ('cp2k' not defined)
cp2k_root = get_software_root('CP2K')
if self.cfg['cp2k'] and not cp2k_root:
msg = "CP2K support has been requested but CP2K is not listed as a dependency."
raise EasyBuildError(msg)
elif cp2k_root and self.cfg['cp2k'] is False:
self.log.info('CP2K was found, but compilation without CP2K has been requested.')
cp2k_root = None

if cp2k_root:
if gromacs_version < LooseVersion('2022'):
msg = 'CP2K support is only available for GROMACS 2022 and newer.'
raise EasyBuildError(msg)
elif LooseVersion(get_software_version('CP2K')) < LooseVersion('8.1'):
msg = 'CP2K support in GROMACS requires CP2K version 8.1 or higher.'
raise EasyBuildError(msg)

if not self.cfg['mpi_only']:
msg = "GROMACS with CP2K support needs to be built with 'mpi_only = True'"
raise EasyBuildError(msg)

if not os.path.exists(os.path.join(cp2k_root, 'lib', 'libcp2k.a')):
msg = 'CP2K needs to be compiled with "library = True".'
raise EasyBuildError(msg)
if not os.path.exists(os.path.join(cp2k_root, 'lib', 'pkgconfig', 'libcp2k.pc')):
msg = "pkg-config is required as a build-dependency for CP2K"
raise EasyBuildError(msg)
if not get_software_root('pkg-config'):
msg = "pkg-config is required as a build-dependency for building GROMACS-CP2K"
raise EasyBuildError(msg)

self.log.info('CP2K support has been enabled.')
# Building with CP2K requires static build w/o gmxapi.
# https://manual.gromacs.org/documentation/2022/install-guide/index.html#building-with-cp2k-qm-mm-support
self.log.info("Building with CP2K QM/MM.")
self.cfg['build_shared_libs'] = False
self.libext = 'a'
cp2k_version = get_software_version('CP2K')
self.cfg.update('configopts', "-DGMX_INSTALL_NBLIB_API=OFF")
self.cfg.update('configopts', "-DGMXAPI=OFF")
self.cfg.update('configopts', "-DGMX_CP2K=ON")
# Ensure that the GROMACS log files report that CP2K was enabled and which version was used.
self.cfg.update('configopts', "-DGMX_VERSION_STRING_OF_FORK=CP2K-{:}".format(cp2k_version))
self.cfg.update('configopts', "-DCP2K_DIR=%s/lib64" % cp2k_root)
cp2k_linker_flags = [
# Need MPI linker flags b/c libcp2k.a is compiled with mpifort.
# These are for OpenMPI (mpifort --showme).
"-lmpi_usempif08 -lmpi_usempi_ignore_tkr -lmpi_mpifh",
"-L%s/lib/exts/dbcsr" % cp2k_root,
# get depenencies for libcp2k.a:
"$(pkg-config --libs-only-l libcp2k)"
]
if get_software_root('Libint'):
# for some reason libint2 is not discovered by pkg-config:
cp2k_linker_flags.append('-lint2')
self.cfg.update('configopts', '-DCP2K_LINKER_FLAGS="%s"' % " ".join(cp2k_linker_flags))

# PLUMED detection
# enable PLUMED support if PLUMED is listed as a dependency
# and PLUMED support is either explicitly enabled (plumed = True) or unspecified ('plumed' not defined)
Expand Down Expand Up @@ -395,7 +322,7 @@ def configure_step(self):
mpiexec_path, self.cfg.get('mpiexec_numproc_flag'),
mpi_numprocs)

elif gromacs_version >= '2019' and self.cfg['build_shared_libs']:
if gromacs_version >= '2019':
# Building the gmxapi interface requires shared libraries,
# this is handled in the class initialisation so --module-only works
self.cfg.update('configopts', "-DGMXAPI=ON")
Expand Down Expand Up @@ -576,10 +503,8 @@ def test_step(self):
copy_dir('lib', libdir)

orig_runtest = self.cfg['runtest']

if LooseVersion(self.version) < LooseVersion('2019'):
# make very sure OMP_NUM_THREADS is set to 1, to avoid hanging GROMACS regression test
env.setvar('OMP_NUM_THREADS', '1')
# make very sure OMP_NUM_THREADS is set to 1, to avoid hanging GROMACS regression test
env.setvar('OMP_NUM_THREADS', '1')

if self.cfg['runtest'] is None or isinstance(self.cfg['runtest'], bool):
self.cfg['runtest'] = 'check'
Expand Down Expand Up @@ -667,14 +592,6 @@ def get_lib_subdirs(self):
subdir = lib_relpath.split(os.sep)[0:-1]
lib_subdirs.append(os.path.join(*subdir))

if not self.cfg['build_shared_libs'] and len(lib_subdirs) == 0:
for libdir in ['lib', 'lib64']:
if os.path.exists(os.path.join(self.installdir, libdir)):
msg = "Found lib subdirectory: %s but it doesn't contain: %s.\n"
msg += "As building shared libs was disabled, this is probably okay."
lib_subdirs = [libdir]
self.log.info(msg, libdir, libname)

if len(lib_subdirs) == 0:
raise EasyBuildError(f"Failed to determine sub-directory with {libname} in {self.installdir}")

Expand Down Expand Up @@ -738,12 +655,8 @@ def sanity_check_step(self):
else:
mpisuff = '_mpi'

if self.cfg['mpi_only']:
mpi_bins = [binary + mpisuff for binary in mpi_bins]
mpi_libnames = [libname + mpisuff for libname in mpi_libnames]
else:
mpi_bins.extend([binary + mpisuff for binary in mpi_bins])
mpi_libnames.extend([libname + mpisuff for libname in mpi_libnames])
mpi_bins.extend([binary + mpisuff for binary in mpi_bins])
mpi_libnames.extend([libname + mpisuff for libname in mpi_libnames])

suffixes = ['']

Expand Down Expand Up @@ -773,21 +686,10 @@ def sanity_check_step(self):
dirs.extend([os.path.join(ld, 'pkgconfig') for ld in self.lib_subdirs])

custom_paths = {
'files': [os.path.join('bin', b) for b in bin_files],
'files': [os.path.join('bin', b) for b in bin_files] +
[os.path.join(libdir, lib) for libdir in self.lib_subdirs for lib in lib_files],
'dirs': dirs,
}

if self.cfg['build_shared_libs'] or LooseVersion(self.version) <= LooseVersion('2022'):
# only if any libs are actually built
if not self.lib_subdir:
self.lib_subdir = self.get_lib_subdir()

# pkgconfig dir not available for earlier versions, exact version to use here is unclear
if LooseVersion(self.version) >= LooseVersion('4.6'):
custom_paths['dirs'].append(os.path.join(self.lib_subdir, 'pkgconfig'))

custom_paths['files'] = custom_paths['files'] + [os.path.join(self.lib_subdir, lib) for lib in lib_files]

super().sanity_check_step(custom_paths=custom_paths)

def run_all_steps(self, *args, **kwargs):
Expand Down Expand Up @@ -867,12 +769,9 @@ def run_all_steps(self, *args, **kwargs):
if precisions == []:
raise EasyBuildError("No precision selected. At least one of single/double_precision must be unset or True")

if self.cfg['mpi_only']:
mpitypes = ['mpi']
else:
mpitypes = ['nompi']
if self.toolchain.options.get('usempi', None):
mpitypes.append('mpi')
mpitypes = ['nompi']
if self.toolchain.options.get('usempi', None):
mpitypes.append('mpi')

# We need to count the number of variations to build.
versions_built = []
Expand Down