diff --git a/easyblocks/a/aocl.py b/easyblocks/a/aocl.py
new file mode 100644
index 0000000000000000000000000000000000000000..53e0f4781a7aa98922317176b9247e62971fc6cd
--- /dev/null
+++ b/easyblocks/a/aocl.py
@@ -0,0 +1,93 @@
+##
+# Copyright 2009-2021 Ghent University
+#
+# This file is part of EasyBuild,
+# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
+# with support of Ghent University (http://ugent.be/hpc),
+# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
+# Flemish Research Foundation (FWO) (http://www.fwo.be/en)
+# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
+#
+# https://github.com/easybuilders/easybuild
+#
+# EasyBuild is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation v2.
+#
+# EasyBuild is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>.
+##
+"""
+EasyBuild support for AMD Core Math Library (AOCL), implemented as an easyblock
+
+@author: Lukas Krupcik (IT4Innovations)
+"""
+
+import os
+from distutils.version import LooseVersion
+
+from easybuild.framework.easyblock import EasyBlock
+from easybuild.framework.easyconfig import CUSTOM
+from easybuild.tools.run import run_cmd_qa
+from easybuild.tools.systemtools import get_shared_lib_ext
+
+
+class EB_AOCL(EasyBlock):
+
+ def __init__(self, *args, **kwargs):
+ """Constructor, adds extra class variables."""
+ super(EB_AOCL, self).__init__(*args, **kwargs)
+
+ self.basedir = '%s' % (self.version)
+
+ def configure_step(self):
+ """No custom configure step for AOCL."""
+ pass
+
+ def build_step(self):
+ """No custom build step for AOCL."""
+ pass
+
+ def install_step(self):
+ """Install by running install script."""
+
+ cmd = "./install.sh -t %s" % (self.installdir)
+
+ qa = {'The directory will be created if it does not already exist. >': self.installdir}
+
+ run_cmd_qa(cmd, qa, log_all=True, simple=True)
+
+ def make_module_extra(self):
+ """Add extra entries in module file (various paths)."""
+
+ txt = super(EB_AOCL, self).make_module_extra()
+
+ basepaths = ["%s" % (self.basedir)]
+
+ txt += self.module_generator.set_environment('AOCL_ROOT', "%s/%s" % (self.installdir, self.basedir))
+
+ for path in basepaths:
+ txt += self.module_generator.prepend_paths('PATH', os.path.join(path, 'amd-fftw/bin'))
+
+ for path in basepaths:
+ txt += self.module_generator.prepend_paths('CPATH', os.path.join(path, 'include'))
+
+ for key in ['LD_LIBRARY_PATH', 'LIBRARY_PATH']:
+ for path in basepaths:
+ txt += self.module_generator.prepend_paths(key, os.path.join(path, 'lib'))
+
+ return txt
+
+ def sanity_check_step(self):
+ """Custom sanity check for AOCL."""
+
+ custom_paths = {
+ 'files': [],
+ 'dirs': ['%s/aocc/include' % (self.version), '%s/aocc/lib' % (self.version), '%s/aocc/amd-fftw' % (self.version)]
+ }
+ super(EB_AOCL, self).sanity_check_step(custom_paths=custom_paths)
diff --git a/easyblocks/i/impi.py b/easyblocks/i/impi.py
new file mode 100644
index 0000000000000000000000000000000000000000..df0a804636509153fba451bcbb6c6a156c42784e
--- /dev/null
+++ b/easyblocks/i/impi.py
@@ -0,0 +1,377 @@
+# #
+# Copyright 2009-2023 Ghent University
+#
+# This file is part of EasyBuild,
+# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
+# with support of Ghent University (http://ugent.be/hpc),
+# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
+# Flemish Research Foundation (FWO) (http://www.fwo.be/en)
+# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
+#
+# https://github.com/easybuilders/easybuild
+#
+# EasyBuild is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation v2.
+#
+# EasyBuild is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>.
+# #
+"""
+EasyBuild support for installing the Intel MPI library, implemented as an easyblock
+
+@author: Stijn De Weirdt (Ghent University)
+@author: Dries Verdegem (Ghent University)
+@author: Kenneth Hoste (Ghent University)
+@author: Pieter De Baets (Ghent University)
+@author: Jens Timmerman (Ghent University)
+@author: Damian Alvarez (Forschungszentrum Juelich GmbH)
+@author: Alex Domingo (Vrije Universiteit Brussel)
+"""
+import os
+from distutils.version import LooseVersion
+
+import easybuild.tools.toolchain as toolchain
+from easybuild.easyblocks.generic.intelbase import IntelBase, ACTIVATION_NAME_2012, LICENSE_FILE_NAME_2012
+from easybuild.framework.easyconfig import CUSTOM
+from easybuild.tools.build_log import EasyBuildError
+from easybuild.tools.config import build_option
+from easybuild.tools.filetools import apply_regex_substitutions, change_dir, extract_file, mkdir, write_file
+from easybuild.tools.modules import get_software_root
+from easybuild.tools.run import run_cmd
+from easybuild.tools.systemtools import get_shared_lib_ext
+from easybuild.tools.toolchain.mpi import get_mpi_cmd_template
+
+
+class EB_impi(IntelBase):
+ """
+ Support for installing Intel MPI library
+ """
+ @staticmethod
+ def extra_options():
+ extra_vars = {
+ 'libfabric_configopts': ['', 'Configure options for the provided libfabric', CUSTOM],
+ 'libfabric_rebuild': [True, 'Try to rebuild internal libfabric instead of using provided binary', CUSTOM],
+ 'ofi_internal': [True, 'Use internal shipped libfabric instead of external libfabric', CUSTOM],
+ 'set_mpi_wrappers_compiler': [False, 'Override default compiler used by MPI wrapper commands', CUSTOM],
+ 'set_mpi_wrapper_aliases_gcc': [False, 'Set compiler for mpigcc/mpigxx via aliases', CUSTOM],
+ 'set_mpi_wrapper_aliases_intel': [False, 'Set compiler for mpiicc/mpiicpc/mpiifort via aliases', CUSTOM],
+ 'set_mpi_wrappers_all': [False, 'Set (default) compiler for all MPI wrapper commands', CUSTOM],
+ }
+ return IntelBase.extra_options(extra_vars)
+
+ def prepare_step(self, *args, **kwargs):
+ if LooseVersion(self.version) >= LooseVersion('2017.2.174'):
+ kwargs['requires_runtime_license'] = False
+ super(EB_impi, self).prepare_step(*args, **kwargs)
+ else:
+ super(EB_impi, self).prepare_step(*args, **kwargs)
+
+ def install_step(self):
+ """
+ Actual installation
+ - create silent cfg file
+ - execute command
+ """
+ impiver = LooseVersion(self.version)
+
+ if impiver >= LooseVersion('2021'):
+ super(EB_impi, self).install_step()
+
+ elif impiver >= LooseVersion('4.0.1'):
+ # impi starting from version 4.0.1.x uses standard installation procedure.
+
+ silent_cfg_names_map = {}
+
+ if impiver < LooseVersion('4.1.1'):
+ # since impi v4.1.1, silent.cfg has been slightly changed to be 'more standard'
+ silent_cfg_names_map.update({
+ 'activation_name': ACTIVATION_NAME_2012,
+ 'license_file_name': LICENSE_FILE_NAME_2012,
+ })
+
+ super(EB_impi, self).install_step(silent_cfg_names_map=silent_cfg_names_map)
+
+ # impi v4.1.1 and v5.0.1 installers create impi/<version> subdir, so stuff needs to be moved afterwards
+ if impiver == LooseVersion('4.1.1.036') or impiver >= LooseVersion('5.0.1.035'):
+ super(EB_impi, self).move_after_install()
+ else:
+ # impi up until version 4.0.0.x uses custom installation procedure.
+ silent = """[mpi]
+INSTALLDIR=%(ins)s
+LICENSEPATH=%(lic)s
+INSTALLMODE=NONRPM
+INSTALLUSER=NONROOT
+UPDATE_LD_SO_CONF=NO
+PROCEED_WITHOUT_PYTHON=yes
+AUTOMOUNTED_CLUSTER=yes
+EULA=accept
+[mpi-rt]
+INSTALLDIR=%(ins)s
+LICENSEPATH=%(lic)s
+INSTALLMODE=NONRPM
+INSTALLUSER=NONROOT
+UPDATE_LD_SO_CONF=NO
+PROCEED_WITHOUT_PYTHON=yes
+AUTOMOUNTED_CLUSTER=yes
+EULA=accept
+
+""" % {'lic': self.license_file, 'ins': self.installdir}
+
+ # already in correct directory
+ silentcfg = os.path.join(os.getcwd(), "silent.cfg")
+ write_file(silentcfg, silent)
+ self.log.debug("Contents of %s: %s", silentcfg, silent)
+
+ tmpdir = os.path.join(os.getcwd(), self.version, 'mytmpdir')
+ mkdir(tmpdir, parents=True)
+
+ cmd = "./install.sh --tmp-dir=%s --silent=%s" % (tmpdir, silentcfg)
+ run_cmd(cmd, log_all=True, simple=True)
+
+ # recompile libfabric (if requested)
+ # some Intel MPI versions (like 2019 update 6) no longer ship libfabric sources
+ libfabric_path = os.path.join(self.installdir, 'libfabric')
+ if impiver >= LooseVersion('2019') and self.cfg['libfabric_rebuild']:
+ if self.cfg['ofi_internal']:
+ libfabric_src_tgz_fn = 'src.tgz'
+ if os.path.exists(os.path.join(libfabric_path, libfabric_src_tgz_fn)):
+ change_dir(libfabric_path)
+ srcdir = extract_file(libfabric_src_tgz_fn, os.getcwd(), change_into_dir=False)
+ change_dir(srcdir)
+ libfabric_installpath = os.path.join(self.installdir, 'intel64', 'libfabric')
+
+ make = 'make'
+ if self.cfg['parallel']:
+ make += ' -j %d' % self.cfg['parallel']
+
+ cmds = [
+ './configure --prefix=%s %s' % (libfabric_installpath, self.cfg['libfabric_configopts']),
+ make,
+ 'make install'
+ ]
+ for cmd in cmds:
+ run_cmd(cmd, log_all=True, simple=True)
+ else:
+ self.log.info("Rebuild of libfabric is requested, but %s does not exist, so skipping...",
+ libfabric_src_tgz_fn)
+ else:
+ raise EasyBuildError("Rebuild of libfabric is requested, but ofi_internal is set to False.")
+
+ def post_install_step(self):
+ """Custom post install step for IMPI, fix broken env scripts after moving installed files."""
+ super(EB_impi, self).post_install_step()
+
+ impiver = LooseVersion(self.version)
+
+ if impiver >= LooseVersion('2021'):
+ self.log.info("No post-install action for impi v%s", self.version)
+
+ elif impiver == LooseVersion('4.1.1.036') or impiver >= LooseVersion('5.0.1.035'):
+ if impiver >= LooseVersion('2018.0.128'):
+ script_paths = [os.path.join('intel64', 'bin')]
+ else:
+ script_paths = [os.path.join('intel64', 'bin'), os.path.join('mic', 'bin')]
+ # fix broken env scripts after the move
+ regex_subs = [(r"^setenv I_MPI_ROOT.*", r"setenv I_MPI_ROOT %s" % self.installdir)]
+ for script in [os.path.join(script_path, 'mpivars.csh') for script_path in script_paths]:
+ apply_regex_substitutions(os.path.join(self.installdir, script), regex_subs)
+ regex_subs = [(r"^(\s*)I_MPI_ROOT=[^;\n]*", r"\1I_MPI_ROOT=%s" % self.installdir)]
+ for script in [os.path.join(script_path, 'mpivars.sh') for script_path in script_paths]:
+ apply_regex_substitutions(os.path.join(self.installdir, script), regex_subs)
+
+ # fix 'prefix=' in compiler wrapper scripts after moving installation (see install_step)
+ wrappers = ['mpif77', 'mpif90', 'mpigcc', 'mpigxx', 'mpiicc', 'mpiicpc', 'mpiifort']
+ regex_subs = [(r"^prefix=.*", r"prefix=%s" % self.installdir)]
+ for script_dir in script_paths:
+ for wrapper in wrappers:
+ wrapper_path = os.path.join(self.installdir, script_dir, wrapper)
+ if os.path.exists(wrapper_path):
+ apply_regex_substitutions(wrapper_path, regex_subs)
+
+ def sanity_check_step(self):
+ """Custom sanity check paths for IMPI."""
+
+ impi_ver = LooseVersion(self.version)
+
+ suff = '64'
+ if self.cfg['m32']:
+ suff = ''
+
+ mpi_mods = ['mpi.mod']
+ if impi_ver > LooseVersion('4.0'):
+ mpi_mods.extend(['mpi_base.mod', 'mpi_constants.mod', 'mpi_sizeofs.mod'])
+
+ if impi_ver >= LooseVersion('2021'):
+ mpi_subdir = os.path.join('mpi', self.version)
+ bin_dir = os.path.join(mpi_subdir, 'bin')
+ include_dir = os.path.join(mpi_subdir, 'include')
+ lib_dir = os.path.join(mpi_subdir, 'lib', 'release')
+
+ elif impi_ver >= LooseVersion('2019'):
+ bin_dir = os.path.join('intel64', 'bin')
+ include_dir = os.path.join('intel64', 'include')
+ lib_dir = os.path.join('intel64', 'lib', 'release')
+ else:
+ bin_dir = 'bin%s' % suff
+ include_dir = 'include%s' % suff
+ lib_dir = 'lib%s' % suff
+ mpi_mods.extend(['i_malloc.h'])
+
+ shlib_ext = get_shared_lib_ext()
+ custom_paths = {
+ 'files': [os.path.join(bin_dir, 'mpi%s' % x) for x in ['icc', 'icpc', 'ifort']] +
+ [os.path.join(include_dir, 'mpi%s.h' % x) for x in ['cxx', 'f', '', 'o', 'of']] +
+ [os.path.join(include_dir, x) for x in mpi_mods] +
+ [os.path.join(lib_dir, 'libmpi.%s' % shlib_ext)] +
+ [os.path.join(lib_dir, 'libmpi.a')],
+ 'dirs': [],
+ }
+
+ custom_commands = []
+
+ if build_option('mpi_tests'):
+ if impi_ver >= LooseVersion('2017'):
+ # Add minimal test program to sanity checks
+ if impi_ver >= LooseVersion('2021'):
+ impi_testsrc = os.path.join(self.installdir, 'mpi', self.version, 'test', 'test.c')
+ else:
+ impi_testsrc = os.path.join(self.installdir, 'test', 'test.c')
+
+ impi_testexe = os.path.join(self.builddir, 'mpi_test')
+ self.log.info("Adding minimal MPI test program to sanity checks: %s", impi_testsrc)
+
+ # Build test program with appropriate compiler from current toolchain
+ comp_fam = self.toolchain.comp_family()
+ if comp_fam == toolchain.INTELCOMP:
+ build_comp = 'mpiicc'
+ else:
+ build_comp = 'mpicc'
+ build_cmd = "%s %s -o %s" % (build_comp, impi_testsrc, impi_testexe)
+
+ # Execute test program with appropriate MPI executable for target toolchain
+ params = {'nr_ranks': self.cfg['parallel'], 'cmd': impi_testexe}
+ mpi_cmd_tmpl, params = get_mpi_cmd_template(toolchain.INTELMPI, params, mpi_version=self.version)
+
+ custom_commands.extend([
+ build_cmd, # build test program
+ #mpi_cmd_tmpl % params, # run test program
+ ])
+
+ super(EB_impi, self).sanity_check_step(custom_paths=custom_paths, custom_commands=custom_commands)
+
+ def make_module_req_guess(self):
+ """
+ A dictionary of possible directories to look for
+ """
+ guesses = super(EB_impi, self).make_module_req_guess()
+ if self.cfg['m32']:
+ lib_dirs = ['lib', 'lib/ia32', 'ia32/lib']
+ guesses.update({
+ 'PATH': ['bin', 'bin/ia32', 'ia32/bin'],
+ 'LD_LIBRARY_PATH': lib_dirs,
+ 'LIBRARY_PATH': lib_dirs,
+ 'MIC_LD_LIBRARY_PATH': ['mic/lib'],
+ })
+ else:
+ manpath = 'man'
+
+ impi_ver = LooseVersion(self.version)
+ if impi_ver >= LooseVersion('2021'):
+ mpi_subdir = os.path.join('mpi', self.version)
+ lib_dirs = [
+ os.path.join(mpi_subdir, 'lib'),
+ os.path.join(mpi_subdir, 'lib', 'release'),
+ os.path.join(mpi_subdir, 'libfabric', 'lib'),
+ ]
+ include_dirs = [os.path.join(mpi_subdir, 'include')]
+ path_dirs = [
+ os.path.join(mpi_subdir, 'bin'),
+ os.path.join(mpi_subdir, 'libfabric', 'bin'),
+ ]
+ manpath = os.path.join(mpi_subdir, 'man')
+
+ if self.cfg['ofi_internal']:
+ libfabric_dir = os.path.join('mpi', self.version, 'libfabric')
+ lib_dirs.append(os.path.join(libfabric_dir, 'lib'))
+ path_dirs.append(os.path.join(libfabric_dir, 'bin'))
+ guesses['FI_PROVIDER_PATH'] = [os.path.join(libfabric_dir, 'lib', 'prov')]
+
+ elif impi_ver >= LooseVersion('2019'):
+ # The "release" library is default in v2019. Give it precedence over intel64/lib.
+ # (remember paths are *prepended*, so the last path in the list has highest priority)
+ lib_dirs = [os.path.join('intel64', x) for x in ['lib', os.path.join('lib', 'release')]]
+ include_dirs = [os.path.join('intel64', 'include')]
+ path_dirs = [os.path.join('intel64', 'bin')]
+ if self.cfg['ofi_internal']:
+ lib_dirs.append(os.path.join('intel64', 'libfabric', 'lib'))
+ path_dirs.append(os.path.join('intel64', 'libfabric', 'bin'))
+ guesses['FI_PROVIDER_PATH'] = [os.path.join('intel64', 'libfabric', 'lib', 'prov')]
+ else:
+ lib_dirs = [os.path.join('lib', 'em64t'), 'lib64']
+ include_dirs = ['include64']
+ path_dirs = [os.path.join('bin', 'intel64'), 'bin64']
+ guesses['MIC_LD_LIBRARY_PATH'] = [os.path.join('mic', 'lib')]
+
+ guesses.update({
+ 'PATH': path_dirs,
+ 'LD_LIBRARY_PATH': lib_dirs,
+ 'LIBRARY_PATH': lib_dirs,
+ 'MANPATH': [manpath],
+ 'CPATH': include_dirs,
+ })
+
+ return guesses
+
+ def make_module_extra(self, *args, **kwargs):
+ """Overwritten from Application to add extra txt"""
+
+ if LooseVersion(self.version) >= LooseVersion('2021'):
+ mpiroot = os.path.join(self.installdir, 'mpi', self.version)
+ else:
+ mpiroot = self.installdir
+
+ txt = super(EB_impi, self).make_module_extra(*args, **kwargs)
+ txt += self.module_generator.set_environment('I_MPI_ROOT', mpiroot)
+ if self.cfg['set_mpi_wrappers_compiler'] or self.cfg['set_mpi_wrappers_all']:
+ for var in ['CC', 'CXX', 'F77', 'F90', 'FC']:
+ if var == 'FC':
+ # $FC isn't defined by EasyBuild framework, so use $F90 instead
+ src_var = 'F90'
+ else:
+ src_var = var
+
+ target_var = 'I_MPI_%s' % var
+
+ val = os.getenv(src_var)
+ if val:
+ txt += self.module_generator.set_environment(target_var, val)
+ else:
+ raise EasyBuildError("Environment variable $%s not set, can't define $%s", src_var, target_var)
+
+ if self.cfg['set_mpi_wrapper_aliases_gcc'] or self.cfg['set_mpi_wrappers_all']:
+ # force mpigcc/mpigxx to use GCC compilers, as would be expected based on their name
+ txt += self.module_generator.set_alias('mpigcc', 'mpigcc -cc=gcc')
+ txt += self.module_generator.set_alias('mpigxx', 'mpigxx -cxx=g++')
+
+ if self.cfg['set_mpi_wrapper_aliases_intel'] or self.cfg['set_mpi_wrappers_all']:
+ # do the same for mpiicc/mpiipc/mpiifort to be consistent, even if they may not exist
+ txt += self.module_generator.set_alias('mpiicc', 'mpiicc -cc=icc')
+ txt += self.module_generator.set_alias('mpiicpc', 'mpiicpc -cxx=icpc')
+ # -fc also works, but -f90 takes precedence
+ txt += self.module_generator.set_alias('mpiifort', 'mpiifort -f90=ifort')
+
+ # set environment variable UCX_TLS to 'all', this works in all hardware configurations
+ # needed with UCX regardless of the transports available (even without a Mellanox HCA)
+ # more information in easybuilders/easybuild-easyblocks#2253
+ if get_software_root('UCX'):
+ # do not overwrite settings in the easyconfig
+ if 'UCX_TLS' not in self.cfg['modextravars']:
+ txt += self.module_generator.set_environment('UCX_TLS', 'all')
+
+ return txt
diff --git a/easyblocks/o/openmpi.py b/easyblocks/o/openmpi.py
new file mode 100644
index 0000000000000000000000000000000000000000..11870c6730988e741dc365ab035072910ee66d5a
--- /dev/null
+++ b/easyblocks/o/openmpi.py
@@ -0,0 +1,243 @@
+##
+# Copyright 2019-2023 Ghent University
+#
+# This file is part of EasyBuild,
+# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
+# with support of Ghent University (http://ugent.be/hpc),
+# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
+# Flemish Research Foundation (FWO) (http://www.fwo.be/en)
+# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
+#
+# https://github.com/easybuilders/easybuild
+#
+# EasyBuild is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation v2.
+#
+# EasyBuild is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>.
+##
+"""
+EasyBuild support for OpenMPI, implemented as an easyblock
+
+@author: Kenneth Hoste (Ghent University)
+@author: Robert Mijakovic (LuxProvide)
+"""
+import os
+import re
+from easybuild.tools import LooseVersion
+
+import easybuild.tools.toolchain as toolchain
+from easybuild.easyblocks.generic.configuremake import ConfigureMake
+from easybuild.framework.easyconfig.constants import EASYCONFIG_CONSTANTS
+from easybuild.tools.build_log import EasyBuildError
+from easybuild.tools.config import build_option
+from easybuild.tools.modules import get_software_root
+from easybuild.tools.systemtools import check_os_dependency, get_shared_lib_ext
+from easybuild.tools.toolchain.mpi import get_mpi_cmd_template
+
+
+class EB_OpenMPI(ConfigureMake):
+ """OpenMPI easyblock."""
+
+ def configure_step(self):
+ """Custom configuration step for OpenMPI."""
+
+ def config_opt_used(key, enable_opt=False):
+ """Helper function to check whether a configure option is already specified in 'configopts'."""
+ if enable_opt:
+ regex = '--(disable|enable)-%s' % key
+ else:
+ regex = '--(with|without)-%s' % key
+
+ return bool(re.search(regex, self.cfg['configopts']))
+
+ config_opt_names = [
+ # suppress failure modes in relation to mpirun path
+ 'mpirun-prefix-by-default',
+ # build shared libraries
+ 'shared',
+ ]
+
+ for key in config_opt_names:
+ if not config_opt_used(key, enable_opt=True):
+ self.cfg.update('configopts', '--enable-%s' % key)
+
+ # List of EasyBuild dependencies for which OMPI has known options
+ known_dependencies = ('CUDA', 'hwloc', 'libevent', 'libfabric', 'PMIx', 'UCX', 'UCC')
+ # Value to use for `--with-<dep>=<value>` if the dependency is not specified in the easyconfig
+ # No entry is interpreted as no option added at all
+ # This is to make builds reproducible even when the system libraries are changed and avoids failures
+ # due to e.g. finding only PMIx but not libevent on the system
+ unused_dep_value = dict()
+ # Known options since version 3.0 (no earlier ones checked)
+ if LooseVersion(self.version) >= LooseVersion('3.0'):
+ # Default to disable the option with "no"
+ unused_dep_value = {dep: 'no' for dep in known_dependencies}
+ # For these the default is to use an internal copy and not using any is not supported
+ for dep in ('hwloc', 'libevent', 'PMIx'):
+ unused_dep_value[dep] = 'internal'
+
+ # handle dependencies
+ for dep in known_dependencies:
+ opt_name = dep.lower()
+ # If the option is already used, don't add it
+ if config_opt_used(opt_name):
+ continue
+
+ # libfabric option renamed in OpenMPI 3.1.0 to ofi
+ if dep == 'libfabric' and LooseVersion(self.version) >= LooseVersion('3.1'):
+ opt_name = 'ofi'
+ # Check new option name. They are synonyms since 3.1.0 for backward compatibility
+ if config_opt_used(opt_name):
+ continue
+
+ dep_root = get_software_root(dep)
+ # If the dependency is loaded, specify its path, else use the "unused" value, if any
+ if dep_root:
+ opt_value = dep_root
+ else:
+ opt_value = unused_dep_value.get(dep)
+ if opt_value is not None:
+ self.cfg.update('configopts', '--with-%s=%s' % (opt_name, opt_value))
+
+ if bool(get_software_root('PMIx')) != bool(get_software_root('libevent')):
+ raise EasyBuildError('You must either use both PMIx and libevent as dependencies or none of them. '
+ 'This is to enforce the same libevent is used for OpenMPI as for PMIx or '
+ 'the behavior may be unpredictable.')
+
+ # check whether VERBS support should be enabled
+ if not config_opt_used('verbs'):
+
+ # for OpenMPI v4.x, the openib BTL should be disabled when UCX is used;
+ # this is required to avoid "error initializing an OpenFabrics device" warnings,
+ # see also https://www.open-mpi.org/faq/?category=all#ofa-device-error
+ is_ucx_enabled = ('--with-ucx' in self.cfg['configopts'] and
+ '--with-ucx=no' not in self.cfg['configopts'])
+ if LooseVersion(self.version) >= LooseVersion('4.0.0') and is_ucx_enabled:
+ verbs = False
+ else:
+ # auto-detect based on available OS packages
+ os_packages = EASYCONFIG_CONSTANTS['OS_PKG_IBVERBS_DEV'][0]
+ verbs = any(check_os_dependency(osdep) for osdep in os_packages)
+ # for OpenMPI v5.x, the verbs support is removed, only UCX is available
+ # see https://github.com/open-mpi/ompi/pull/6270
+ if LooseVersion(self.version) <= LooseVersion('5.0.0'):
+ if verbs:
+ self.cfg.update('configopts', '--with-verbs')
+ else:
+ self.cfg.update('configopts', '--without-verbs')
+
+ super(EB_OpenMPI, self).configure_step()
+
+ def test_step(self):
+ """Test step for OpenMPI"""
+ # Default to `make check` if nothing is set. Disable with "runtest = False" in the EC
+ if self.cfg['runtest'] is None:
+ self.cfg['runtest'] = 'check'
+
+ super(EB_OpenMPI, self).test_step()
+
+ def load_module(self, *args, **kwargs):
+ """
+ Load (temporary) module file, after resetting to initial environment.
+
+ Also put RPATH wrappers back in place if needed, to ensure that sanity check commands work as expected.
+ """
+ super(EB_OpenMPI, self).load_module(*args, **kwargs)
+
+ # ensure RPATH wrappers are in place, otherwise compiling minimal test programs will fail
+ if build_option('rpath'):
+ if self.toolchain.options.get('rpath', True):
+ self.toolchain.prepare_rpath_wrappers(rpath_filter_dirs=self.rpath_filter_dirs,
+ rpath_include_dirs=self.rpath_include_dirs)
+
+ def sanity_check_step(self):
+ """Custom sanity check for OpenMPI."""
+
+ bin_names = ['mpicc', 'mpicxx', 'mpif90', 'mpifort', 'mpirun', 'ompi_info', 'opal_wrapper']
+ if LooseVersion(self.version) >= LooseVersion('5.0.0'):
+ bin_names.append('prterun')
+ else:
+ bin_names.append('orterun')
+ bin_files = [os.path.join('bin', x) for x in bin_names]
+
+ shlib_ext = get_shared_lib_ext()
+ lib_names = ['mpi_mpifh', 'mpi', 'open-pal']
+ if LooseVersion(self.version) >= LooseVersion('5.0.0'):
+ lib_names.append('prrte')
+ else:
+ lib_names.extend(['ompitrace', 'open-rte'])
+ lib_files = [os.path.join('lib', 'lib%s.%s' % (x, shlib_ext)) for x in lib_names]
+
+ inc_names = ['mpi-ext', 'mpif-config', 'mpif', 'mpi', 'mpi_portable_platform']
+ if LooseVersion(self.version) >= LooseVersion('5.0.0'):
+ inc_names.append('prte')
+ inc_files = [os.path.join('include', x + '.h') for x in inc_names]
+
+ custom_paths = {
+ 'files': bin_files + inc_files + lib_files,
+ 'dirs': [],
+ }
+
+ # make sure MPI compiler wrappers pick up correct compilers
+ expected = {
+ 'mpicc': os.getenv('CC', 'gcc'),
+ 'mpicxx': os.getenv('CXX', 'g++'),
+ 'mpifort': os.getenv('FC', 'gfortran'),
+ 'mpif90': os.getenv('F90', 'gfortran'),
+ }
+ # actual pattern for gfortran is "GNU Fortran"
+ for key in ['mpifort', 'mpif90']:
+ if expected[key] == 'gfortran':
+ expected[key] = "GNU Fortran"
+ # for PGI, correct pattern is "pgfortran" with mpif90
+ if expected['mpif90'] == 'pgf90':
+ expected['mpif90'] = 'pgfortran'
+ # for Clang the pattern is always clang
+ for key in ['mpicxx', 'mpifort', 'mpif90']:
+ if expected[key] in ['clang++', 'flang']:
+ expected[key] = 'clang'
+
+ custom_commands = ["%s --version | grep '%s'" % (key, expected[key]) for key in sorted(expected.keys())]
+
+ # Add minimal test program to sanity checks
+ # Run with correct MPI launcher
+ mpi_cmd_tmpl, params = get_mpi_cmd_template(toolchain.OPENMPI, dict(), mpi_version=self.version)
+ # Limit number of ranks to 8 to avoid it failing due to hyperthreading
+ ranks = min(8, self.cfg['parallel'])
+ for srcdir, src, compiler in (
+ ('examples', 'hello_c.c', 'mpicc'),
+ ('examples', 'hello_mpifh.f', 'mpifort'),
+ ('examples', 'hello_usempi.f90', 'mpif90'),
+ ('examples', 'ring_c.c', 'mpicc'),
+ ('examples', 'ring_mpifh.f', 'mpifort'),
+ #('examples', 'ring_usempi.f90', 'mpif90'),
+ ('test/simple', 'thread_init.c', 'mpicc'),
+ ('test/simple', 'intercomm1.c', 'mpicc'),
+ ('test/simple', 'mpi_barrier.c', 'mpicc'),
+ ):
+ src_path = os.path.join(self.cfg['start_dir'], srcdir, src)
+ if os.path.exists(src_path):
+ test_exe = os.path.join(self.builddir, 'mpi_test_' + os.path.splitext(src)[0])
+ self.log.info("Adding minimal MPI test program to sanity checks: %s", test_exe)
+
+ # Build test binary
+ custom_commands.append("%s %s -o %s" % (compiler, src_path, test_exe))
+
+ # Run the test if chosen
+ if build_option('mpi_tests'):
+ params.update({'nr_ranks': ranks, 'cmd': test_exe})
+ # Allow oversubscription for this test (in case of hyperthreading)
+ custom_commands.append("OMPI_MCA_rmaps_base_oversubscribe=1 " + mpi_cmd_tmpl % params)
+ # Run with 1 process which may trigger other bugs
+ # See https://github.com/easybuilders/easybuild-easyconfigs/issues/12978
+ params['nr_ranks'] = 1
+ custom_commands.append(mpi_cmd_tmpl % params)
+
+ super(EB_OpenMPI, self).sanity_check_step(custom_paths=custom_paths, custom_commands=custom_commands)
diff --git a/easyblocks/o/orca.py b/easyblocks/o/orca.py
new file mode 100644
index 0000000000000000000000000000000000000000..67b786e8d0be80ab2cedec1b53ed83db7c2cf1a3
--- /dev/null
+++ b/easyblocks/o/orca.py
@@ -0,0 +1,177 @@
+##
+# Copyright 2021-2024 Vrije Universiteit Brussel
+#
+# This file is part of EasyBuild,
+# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
+# with support of Ghent University (http://ugent.be/hpc),
+# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
+# Flemish Research Foundation (FWO) (http://www.fwo.be/en)
+# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
+#
+# https://github.com/easybuilders/easybuild
+#
+# EasyBuild is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation v2.
+#
+# EasyBuild is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>.
+##
+"""
+EasyBuild support for ORCA, implemented as an easyblock
+
+@author: Alex Domingo (Vrije Universiteit Brussel)
+"""
+import glob
+import os
+
+from easybuild.tools import LooseVersion
+from easybuild.easyblocks.generic.makecp import MakeCp
+from easybuild.easyblocks.generic.packedbinary import PackedBinary
+from easybuild.framework.easyconfig import CUSTOM
+from easybuild.tools.build_log import EasyBuildError
+from easybuild.tools.filetools import write_file
+from easybuild.tools.py2vs3 import string_type
+from easybuild.tools.systemtools import X86_64, get_cpu_architecture
+
+
+class EB_ORCA(PackedBinary, MakeCp):
+ """
+ ORCA installation files are extracted and placed in standard locations using 'files_to_copy' from MakeCp.
+ Sanity checks on files are automatically generated based on the contents of 'files_to_copy' by gathering
+ the target files in the build directory and checking their presence in the installation directory.
+ Sanity checks also include a quick test calculating the HF energy of a water molecule.
+ """
+
+ @staticmethod
+ def extra_options(extra_vars=None):
+ """Extra easyconfig parameters for ORCA."""
+ extra_vars = MakeCp.extra_options()
+ extra_vars.update(PackedBinary.extra_options())
+
+ # files_to_copy is not mandatory here, since we set it by default in install_step
+ extra_vars['files_to_copy'][2] = CUSTOM
+
+ return extra_vars
+
+ def __init__(self, *args, **kwargs):
+ """Init and validate easyconfig parameters and system architecture"""
+ super(EB_ORCA, self).__init__(*args, **kwargs)
+
+ # If user overwrites 'files_to_copy', custom 'sanity_check_paths' must be present
+ if self.cfg['files_to_copy'] and not self.cfg['sanity_check_paths']:
+ raise EasyBuildError("Found 'files_to_copy' option in easyconfig without 'sanity_check_paths'")
+
+ # Add orcaarch template for supported architectures
+ myarch = get_cpu_architecture()
+ if myarch == X86_64:
+ orcaarch = 'x86-64'
+ else:
+ raise EasyBuildError("Architecture %s is not supported by ORCA on EasyBuild", myarch)
+
+ self.cfg.template_values['orcaarch'] = orcaarch
+ self.cfg.generate_template_values()
+
+ def install_step(self):
+ """Install ORCA with MakeCp easyblock"""
+
+ if not self.cfg['files_to_copy']:
+ # Put installation files in standard locations
+ files_to_copy = [
+ (['auto*', 'orca*', 'otool*'], 'bin'),
+ (['*.pdf'], 'share'),
+ ]
+ # Version 5 extra files
+ if LooseVersion('5.0.0') <= LooseVersion(self.version) < LooseVersion('6.0.0'):
+ compoundmethods = (['ORCACompoundMethods'], 'bin')
+ files_to_copy.append(compoundmethods)
+ # Shared builds have additional libraries
+ libs_to_copy = (['liborca*'], 'lib')
+ if all([glob.glob(p) for p in libs_to_copy[0]]):
+ files_to_copy.append(libs_to_copy)
+
+ self.cfg['files_to_copy'] = files_to_copy
+
+ MakeCp.install_step(self)
+
+ def sanity_check_step(self):
+ """Custom sanity check for ORCA"""
+ custom_paths = None
+
+ if not self.cfg['sanity_check_paths']:
+ custom_paths = {'files': [], 'dirs': []}
+
+ if self.cfg['files_to_copy']:
+ # Convert 'files_to_copy' to list of files in build directory
+ for spec in self.cfg['files_to_copy']:
+ if isinstance(spec, tuple):
+ file_pattern = spec[0]
+ dest_dir = spec[1]
+ elif isinstance(spec, string_type):
+ file_pattern = spec
+ dest_dir = ''
+ else:
+ raise EasyBuildError(
+ "Found neither string nor tuple as file to copy: '%s' (type %s)", spec, type(spec)
+ )
+
+ if isinstance(file_pattern, string_type):
+ file_pattern = [file_pattern]
+
+ source_files = []
+ for pattern in file_pattern:
+ source_files.extend(glob.glob(pattern))
+
+ # Add files to custom sanity checks
+ for source in source_files:
+ if os.path.isfile(source):
+ custom_paths['files'].append(os.path.join(dest_dir, source))
+ else:
+ custom_paths['dirs'].append(os.path.join(dest_dir, source))
+ else:
+ # Minimal check of files (needed by --module-only)
+ custom_paths['files'] = ['bin/orca']
+
+# # Simple test: HF energy of water molecule
+# test_input_content = """
+#!HF DEF2-SVP
+#%%PAL NPROCS %(nprocs)s END
+#* xyz 0 1
+#O 0.0000 0.0000 0.0626
+#H -0.7920 0.0000 -0.4973
+#H 0.7920 0.0000 -0.4973
+#*
+#"""
+# nprocs = self.cfg.get('parallel', 1)
+# test_input_content = test_input_content % {'nprocs': nprocs}
+# test_input_path = os.path.join(self.builddir, 'eb_test_hf_water.inp')
+# write_file(test_input_path, test_input_content)
+#
+# # Reference total energy
+# test_output_energy = '-75.95934031'
+# test_output_regex = 'FINAL SINGLE POINT ENERGY[ \t]*%s' % test_output_energy
+#
+# # Instruct openmpi to treat hardware threads as slot
+# test_ompi_env = 'env OMPI_MCA_hwloc_base_use_hwthreads_as_cpus=1'
+#
+# # ORCA has to be executed using its full path to run in parallel
+# if os.path.isdir(os.path.join(self.installdir, 'bin')):
+# orca_bin = '$EBROOTORCA/bin/orca'
+# else:
+# orca_bin = '$(which orca)'
+#
+# test_orca_cmd = "%s %s %s" % (test_ompi_env, orca_bin, test_input_path)
+#
+# custom_commands = [
+# # Execute test in ORCA
+# test_orca_cmd,
+# # Repeat test and check total energy
+# "%s | grep -c '%s'" % (test_orca_cmd, test_output_regex),
+# ]
+#
+# super(EB_ORCA, self).sanity_check_step(custom_paths=custom_paths, custom_commands=custom_commands)
diff --git a/easyblocks/v/visit.py b/easyblocks/v/visit.py
index 47f1c18e435b8e578519249f0578a9415d70938d..0efa00e2fb6c1a108788699e8c1a92a38ab8e431 100644
--- a/easyblocks/v/visit.py
+++ b/easyblocks/v/visit.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-EasyBuild support for building and installing VisIt 3.1.0,
+EasyBuild support for building and installing VisIt 3.3.3,
implemented as an easyblock.
@author: Lukas Krupcik (IT4Innovations)
@@ -31,9 +31,11 @@ class EB_VisIt(EasyBlock):
"""Simply run installation script with configuration options"""
self.log.info("Changing VisIt installer permission")
os.chdir(self.cfg['start_dir'])
- chmod_cmd = "chmod 755 visit-install3_1_0"
+ #chmod_cmd = "chmod 755 visit-install3_3_3"
+ chmod_cmd = "chmod 755 visit-install2_13_3"
run_cmd(chmod_cmd, log_all=True)
- install_cmd = "./visit-install3_1_0 -c none 3.1.0 \
+ #install_cmd = "./visit-install3_3_3 -c none 3.3.3 \
+ install_cmd = "./visit-install2_13_3 -c none 2.13.3 \
linux-x86_64-rhel7 %s" % self.installdir
self.log.info("Running VisIt installer")
run_cmd(install_cmd, log_all=True)
diff --git a/w/wrf_sfire.py b/w/wrf_sfire.py
new file mode 100644
index 0000000000000000000000000000000000000000..29f2058d932444a00292655d49128a6d9f1b3cfd
--- /dev/null
+++ b/w/wrf_sfire.py
@@ -0,0 +1,233 @@
+##
+# Copyright 2009-2023 Ghent University
+#
+# This file is part of EasyBuild,
+# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
+# with support of Ghent University (http://ugent.be/hpc),
+# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
+# Flemish Research Foundation (FWO) (http://www.fwo.be/en)
+# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
+#
+# https://github.com/easybuilders/easybuild
+#
+# EasyBuild is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation v2.
+#
+# EasyBuild is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>.
+##
+"""
+EasyBuild support for building and installing WRF-Fire, implemented as an easyblock
+
+author: Kenneth Hoste (HPC-UGent)
+"""
+import os
+
+import easybuild.tools.environment as env
+import easybuild.tools.toolchain as toolchain
+from easybuild.framework.easyblock import EasyBlock
+from easybuild.framework.easyconfig import CUSTOM, MANDATORY
+from easybuild.tools.filetools import apply_regex_substitutions, change_dir, patch_perl_script_autoflush
+from easybuild.tools.modules import get_software_root
+from easybuild.tools.run import run_cmd, run_cmd_qa
+from easybuild.tools.build_log import EasyBuildError
+
+
+class EB_WRF_minus_Sfire(EasyBlock):
+ """Support for building/installing WRF-Sfire."""
+
+ @staticmethod
+ def extra_options():
+ """Custom easyconfig parameters for WRF-Sfire."""
+ extra_vars = {
+ 'buildtype': [None, "Specify the type of build (serial, smpar (OpenMP), "
+ "dmpar (MPI), dm+sm (hybrid OpenMP/MPI)).", MANDATORY],
+ 'runtest': [True, "Build and run WRF tests", CUSTOM],
+ }
+ return EasyBlock.extra_options(extra_vars)
+
+ def __init__(self, *args, **kwargs):
+ """Add extra config options specific to WRF."""
+ super(EB_WRF_minus_Sfire, self).__init__(*args, **kwargs)
+
+ self.build_in_installdir = True
+
+ def extract_step(self):
+ """Extract WRF-Sfire sources."""
+ self.cfg.update('unpack_options', '--strip-components=1')
+ super(EB_WRF_minus_Sfire, self).extract_step()
+
+ def configure_step(self):
+ """Custom configuration procedure for WRF-Sfire."""
+
+ comp_fam = self.toolchain.comp_family()
+
+ # define $NETCDF* for netCDF dependency
+ netcdf_fortran = get_software_root('netCDF-Fortran')
+ if netcdf_fortran:
+ env.setvar('NETCDF', netcdf_fortran)
+ else:
+ raise EasyBuildError("Required dependendy netCDF-Fortran is missing")
+
+ # define $PHDF5 for parallel HDF5 dependency
+ hdf5 = get_software_root('HDF5')
+ if hdf5 and os.path.exists(os.path.join(hdf5, 'bin', 'h5pcc')):
+ env.setvar('PHDF5', hdf5)
+
+ # first, configure WRF part
+ change_dir(os.path.join(self.cfg['start_dir'], 'WRFV3'))
+
+ # instruct WRF-Sfire to create netCDF v4 output files
+ env.setvar('WRFIO_NETCDF4_FILE_SUPPORT', '1')
+
+ # patch arch/Config_new.pl script, so that run_cmd_qa receives all output to answer questions
+ patch_perl_script_autoflush(os.path.join('arch', 'Config_new.pl'))
+
+ # determine build type option to look for
+ known_build_type_options = {
+ toolchain.INTELCOMP: "Linux x86_64 i486 i586 i686, ifort compiler with icc",
+ toolchain.GCC: "x86_64 Linux, gfortran compiler with gcc",
+ toolchain.PGI: "Linux x86_64, PGI compiler with pgcc",
+ }
+ build_type_option = known_build_type_options.get(comp_fam)
+ if build_type_option is None:
+ raise EasyBuildError("Don't know which WPS configure option to select for compiler family %s", comp_fam)
+
+ build_type_question = r"\s*(?P<nr>[0-9]+).\s*%s\s*\(%s\)" % (build_type_option, self.cfg['buildtype'])
+ qa = {
+ "Compile for nesting? (1=basic, 2=preset moves, 3=vortex following) [default 1]:": '1',
+ }
+ std_qa = {
+ # named group in match will be used to construct answer
+ r"%s.*\n(.*\n)*Enter selection\s*\[[0-9]+-[0-9]+\]\s*:" % build_type_question: '%(nr)s',
+ }
+ run_cmd_qa('./configure', qa, std_qa=std_qa, log_all=True, simple=True)
+
+ cpp_flag = None
+ if comp_fam == toolchain.INTELCOMP:
+ cpp_flag = '-fpp'
+ elif comp_fam == toolchain.GCC:
+ cpp_flag = '-cpp'
+ else:
+ raise EasyBuildError("Don't know which flag to use to specify that Fortran files were preprocessed")
+
+ # patch configure.wrf to get things right
+ comps = {
+ 'CFLAGS_LOCAL': os.getenv('CFLAGS'),
+ 'DM_FC': os.getenv('MPIF90'),
+ 'DM_CC': "%s -DMPI2_SUPPORT" % os.getenv('MPICC'),
+ 'FCOPTIM': os.getenv('FFLAGS'),
+ # specify that Fortran files have been preprocessed with cpp,
+ # see http://forum.wrfforum.com/viewtopic.php?f=5&t=6086
+ 'FORMAT_FIXED': "-FI %s" % cpp_flag,
+ 'FORMAT_FREE': "-FR %s" % cpp_flag,
+ }
+ regex_subs = [(r"^(%s\s*=\s*).*$" % k, r"\1 %s" % v) for (k, v) in comps.items()]
+ apply_regex_substitutions('configure.wrf', regex_subs)
+
+ # also configure WPS part
+ change_dir(os.path.join(self.cfg['start_dir'], 'WPS'))
+
+ # patch arch/Config_new.pl script, so that run_cmd_qa receives all output to answer questions
+ patch_perl_script_autoflush(os.path.join('arch', 'Config.pl'))
+
+ # determine build type option to look for
+ known_build_type_options = {
+ toolchain.INTELCOMP: "PC Linux x86_64, Intel compiler",
+ toolchain.GCC: "PC Linux x86_64, g95 compiler",
+ toolchain.PGI: "PC Linux x86_64 (IA64 and Opteron), PGI compiler 5.2 or higher",
+ }
+ build_type_option = known_build_type_options.get(comp_fam)
+ if build_type_option is None:
+ raise EasyBuildError("Don't know which WPS configure option to select for compiler family %s", comp_fam)
+
+ known_wps_build_types = {
+ 'dmpar': 'DM parallel',
+ 'smpar': 'serial',
+ }
+ wps_build_type = known_wps_build_types.get(self.cfg['buildtype'])
+ if wps_build_type is None:
+ raise EasyBuildError("Don't know which WPS build type to pick for '%s'", self.cfg['builddtype'])
+
+ build_type_question = r"\s*(?P<nr>[0-9]+).\s*%s.*%s(?!NO GRIB2)" % (build_type_option, wps_build_type)
+ std_qa = {
+ # named group in match will be used to construct answer
+ r"%s.*\n(.*\n)*Enter selection\s*\[[0-9]+-[0-9]+\]\s*:" % build_type_question: '%(nr)s',
+ }
+ run_cmd_qa('./configure', {}, std_qa=std_qa, log_all=True, simple=True)
+
+ # patch configure.wps to get things right
+ comps = {
+ 'CC': '%s %s' % (os.getenv('MPICC'), os.getenv('CFLAGS')),
+ 'FC': '%s %s' % (os.getenv('MPIF90'), os.getenv('F90FLAGS'))
+ }
+ regex_subs = [(r"^(%s\s*=\s*).*$" % k, r"\1 %s" % v) for (k, v) in comps.items()]
+ # specify that Fortran90 files have been preprocessed with cpp
+ regex_subs.extend([
+ (r"^(F77FLAGS\s*=\s*)", r"\1 %s " % cpp_flag),
+ (r"^(FFLAGS\s*=\s*)", r"\1 %s " % cpp_flag),
+ ])
+ apply_regex_substitutions('configure.wps', regex_subs)
+
+ def build_step(self):
+ """Custom build procedure for WRF-Sfire."""
+
+ cmd = './compile'
+ if self.cfg['parallel']:
+ cmd += " -j %d" % self.cfg['parallel']
+
+ # first, build WRF part
+ change_dir(os.path.join(self.cfg['start_dir'], 'WRFV3'))
+ (out, ec) = run_cmd(cmd + ' em_fire', log_all=True, simple=False, log_ok=True)
+
+ # next, build WPS part
+ change_dir(os.path.join(self.cfg['start_dir'], 'WPS'))
+ (out, ec) = run_cmd('./compile', log_all=True, simple=False, log_ok=True)
+
+ def test_step(self):
+ """Custom built-in test procedure for WRF-Sfire."""
+ if self.cfg['runtest']:
+ change_dir(os.path.join(self.cfg['start_dir'], 'WRFV3', 'test', 'em_fire', 'hill'))
+
+ if self.cfg['buildtype'] in ['dmpar', 'smpar', 'dm+sm']:
+ test_cmd = "ulimit -s unlimited && %s && %s" % (self.toolchain.mpi_cmd_for("./ideal.exe", 1),
+ self.toolchain.mpi_cmd_for("./wrf.exe", 2))
+ else:
+ test_cmd = "ulimit -s unlimited && ./ideal.exe && ./wrf.exe"
+ run_cmd(test_cmd, simple=True, log_all=True, log_ok=True)
+
+ # building/installing is done in build_step, so we can run tests
+ def install_step(self):
+ """Building was done in install dir, so nothing to do in install_step."""
+ pass
+
+ def sanity_check_step(self):
+ """Custom sanity check for WRF-Sfire."""
+ custom_paths = {
+ 'files': [os.path.join('WRFV3', 'main', f) for f in ['ideal.exe', 'libwrflib.a', 'wrf.exe']] +
+ [os.path.join('WPS', f) for f in ['geogrid.exe', 'metgrid.exe', 'ungrib.exe']],
+ 'dirs': [os.path.join('WRFV3', d) for d in ['main', 'run']],
+ }
+ super(EB_WRF_minus_Sfire, self).sanity_check_step(custom_paths=custom_paths)
+
+ def make_module_req_guess(self):
+ """Custom guesses for generated WRF-Sfire module file."""
+ wrf_maindir = os.path.join('WRFV3', 'main')
+ return {
+ 'LD_LIBRARY_PATH': [wrf_maindir],
+ 'PATH': [wrf_maindir, 'WPS'],
+ }
+
+ def make_module_extra(self):
+ """Add netCDF environment variables to module file."""
+ txt = super(EB_WRF_minus_Sfire, self).make_module_extra()
+ netcdf_fortran = get_software_root('netCDF-Fortran')
+ if netcdf_fortran:
+ txt += self.module_generator.set_environment('NETCDF', netcdf_fortran)
+ return txt