Repository: easybuilders/easybuild-easyblocks

Issue:
Use of deprecated CMake options for Kokkos in LAMMPS easyblock
Recent versions of LAMMPS (at least version `2Jun20`) enforces camel casing for the Kokkos options (e.g., `-DKokkos_ENABLE_CUDA=yes`). Hopefully this naming was already supported in previous versions so we don't have to introduce version-related conditionals (which is tedious with LAMMPS versioning)


Discussion:
Perhaps we need to have a convert_lammps_version_to_sane_version function to apply in __init__ so we can use LooseVersion checks later on?

Resolving patch:
diff --git a/easybuild/easyblocks/l/lammps.py b/easybuild/easyblocks/l/lammps.py
--- a/easybuild/easyblocks/l/lammps.py
+++ b/easybuild/easyblocks/l/lammps.py
@@ -85,6 +85,7 @@
     '7.0': 'Volta70',  # NVIDIA Volta generation CC 7.0
     '7.2': 'Volta72',  # NVIDIA Volta generation CC 7.2
     '7.5': 'Turing75',  # NVIDIA Turing generation CC 7.5
+    '8.0': 'Ampere80',  # NVIDIA Ampere generation CC 8.0
 }
 
 PKG_PREFIX = 'PKG_'
@@ -96,6 +97,14 @@ class EB_LAMMPS(CMakeMake):
     Support for building and installing LAMMPS
     """
 
+    def __init__(self, *args, **kwargs):
+        """LAMMPS easyblock constructor: determine whether we should build with CUDA support enabled."""
+        super(EB_LAMMPS, self).__init__(*args, **kwargs)
+
+        cuda_dep = 'cuda' in [dep['name'].lower() for dep in self.cfg.dependencies()]
+        cuda_toolchain = hasattr(self.toolchain, 'COMPILER_CUDA_FAMILY')
+        self.cuda = cuda_dep or cuda_toolchain
+
     @staticmethod
     def extra_options(**kwargs):
         """Custom easyconfig parameters for LAMMPS"""
@@ -116,19 +125,21 @@ def prepare_step(self, *args, **kwargs):
         super(EB_LAMMPS, self).prepare_step(*args, **kwargs)
 
         # Unset LIBS when using both KOKKOS and CUDA - it will mix lib paths otherwise
-        if self.cfg['kokkos'] and get_software_root('CUDA'):
+        if self.cfg['kokkos'] and self.cuda:
             env.unset_env_vars(['LIBS'])
 
     def configure_step(self, **kwargs):
         """Custom configuration procedure for LAMMPS."""
 
-        cuda = get_software_root('CUDA')
         # list of CUDA compute capabilities to use can be specifed in two ways (where (2) overrules (1)):
         # (1) in the easyconfig file, via the custom cuda_compute_capabilities;
         # (2) in the EasyBuild configuration, via --cuda-compute-capabilities configuration option;
         ec_cuda_cc = self.cfg['cuda_compute_capabilities']
         cfg_cuda_cc = build_option('cuda_compute_capabilities')
-        cuda_cc = check_cuda_compute_capabilities(cfg_cuda_cc, ec_cuda_cc)
+        if cfg_cuda_cc and not isinstance(cfg_cuda_cc, list):
+            raise EasyBuildError("cuda_compute_capabilities in easyconfig should be provided as list of strings, " +
+                                 "(for example ['8.0', '7.5']). Got %s" % cfg_cuda_cc)
+        cuda_cc = check_cuda_compute_capabilities(cfg_cuda_cc, ec_cuda_cc, cuda=self.cuda)
 
         # cmake has its own folder
         self.cfg['srcdir'] = os.path.join(self.start_dir, 'cmake')
@@ -161,7 +172,7 @@ def configure_step(self, **kwargs):
         if '-DDOWNLOAD_EIGEN3=' not in self.cfg['configopts']:
             self.cfg.update('configopts', '-DDOWNLOAD_EIGEN3=no')
 
-        # Compiler complains about 'Eigen3_DIR' not beeing set, but acutally it needs 'EIGEN3_INCLUDE_DIR'.
+        # Compiler complains about 'Eigen3_DIR' not being set, but actually it needs 'EIGEN3_INCLUDE_DIR'.
         # see: https://github.com/lammps/lammps/issues/1110
         # Enable Eigen when its included as dependency dependency:
         eigen_root = get_software_root('Eigen')
@@ -216,20 +227,21 @@ def configure_step(self, **kwargs):
         if self.cfg['kokkos']:
 
             if self.toolchain.options.get('openmp', None):
-                self.cfg.update('configopts', '-DKOKKOS_ENABLE_OPENMP=yes')
+                self.cfg.update('configopts', '-DKokkos_ENABLE_OPENMP=yes')
 
-            self.cfg.update('configopts', '-D%sKOKKOS=on' % PKG_PREFIX)
-            self.cfg.update('configopts', '-DKOKKOS_ARCH="%s"' % get_kokkos_arch(cuda_cc, self.cfg['kokkos_arch']))
+            self.cfg.update('configopts', '-D%sKokkos=on' % PKG_PREFIX)
+            self.cfg.update('configopts', '-DKokkos_ARCH="%s"' % get_kokkos_arch(cuda_cc, self.cfg['kokkos_arch'],
+                                                                                 cuda=self.cuda))
 
             # if KOKKOS and CUDA
-            if cuda:
+            if self.cuda:
                 nvcc_wrapper_path = os.path.join(self.start_dir, "lib", "kokkos", "bin", "nvcc_wrapper")
-                self.cfg.update('configopts', '-DKOKKOS_ENABLE_CUDA=yes')
+                self.cfg.update('configopts', '-DKokkos_ENABLE_CUDA=yes')
                 self.cfg.update('configopts', '-DCMAKE_CXX_COMPILER="%s"' % nvcc_wrapper_path)
                 self.cfg.update('configopts', '-DCMAKE_CXX_FLAGS="-ccbin $CXX $CXXFLAGS"')
 
         # CUDA only
-        elif cuda:
+        elif self.cuda:
             self.cfg.update('configopts', '-D%sGPU=on' % PKG_PREFIX)
             self.cfg.update('configopts', '-DGPU_API=cuda')
             self.cfg.update('configopts', '-DGPU_ARCH=%s' % get_cuda_gpu_arch(cuda_cc))
@@ -303,13 +315,15 @@ def get_cuda_gpu_arch(cuda_cc):
     return 'sm_%s' % str(sorted(cuda_cc, reverse=True)[0]).replace(".", "")
 
 
-def get_kokkos_arch(cuda_cc, kokkos_arch):
+def get_kokkos_arch(cuda_cc, kokkos_arch, cuda=None):
     """
     Return KOKKOS ARCH in LAMMPS required format, which is either 'CPU_ARCH' or 'CPU_ARCH;GPU_ARCH'.
 
     see: https://lammps.sandia.gov/doc/Build_extras.html#kokkos
     """
-    cuda = get_software_root('CUDA')
+    if cuda is None or not isinstance(cuda, bool):
+        cuda = get_software_root('CUDA')
+
     processor_arch = None
 
     if kokkos_arch:
@@ -356,16 +370,19 @@ def get_kokkos_arch(cuda_cc, kokkos_arch):
     return kokkos_arch
 
 
-def check_cuda_compute_capabilities(cfg_cuda_cc, ec_cuda_cc):
+def check_cuda_compute_capabilities(cfg_cuda_cc, ec_cuda_cc, cuda=None):
     """
     Checks if cuda-compute-capabilities is set and prints warning if it gets declared on multiple places.
 
     :param cfg_cuda_cc: cuda-compute-capabilities from cli config
     :param ec_cuda_cc: cuda-compute-capabilities from easyconfig
+    :param cuda: boolean to check if cuda should be enabled or not
     :return: returns preferred cuda-compute-capabilities
     """
 
-    cuda = get_software_root('CUDA')
+    if cuda is None or not isinstance(cuda, bool):
+        cuda = get_software_root('CUDA')
+
     cuda_cc = cfg_cuda_cc or ec_cuda_cc or []
 
     if cuda:


Test patch: