203 lines
9.0 KiB
Python
203 lines
9.0 KiB
Python
# Copyright 2013-2021 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)
|
|
|
|
from spack import *
|
|
from spack.util.environment import set_env
|
|
from spack.util.executable import which
|
|
|
|
|
|
class Strumpack(CMakePackage, CudaPackage, ROCmPackage):
|
|
"""STRUMPACK -- STRUctured Matrix PACKage - provides linear solvers
|
|
for sparse matrices and for dense rank-structured matrices, i.e.,
|
|
matrices that exhibit some kind of low-rank property. It provides a
|
|
distributed memory fully algebraic sparse solver and
|
|
preconditioner. The preconditioner is mostly aimed at large sparse
|
|
linear systems which result from the discretization of a partial
|
|
differential equation, but is not limited to any particular type of
|
|
problem. STRUMPACK also provides preconditioned GMRES and BiCGStab
|
|
iterative solvers."""
|
|
|
|
homepage = "http://portal.nersc.gov/project/sparse/strumpack"
|
|
url = "https://github.com/pghysels/STRUMPACK/archive/v5.1.0.tar.gz"
|
|
git = "https://github.com/pghysels/STRUMPACK.git"
|
|
|
|
maintainers = ['pghysels']
|
|
|
|
test_requires_compiler = True
|
|
|
|
version('master', branch='master')
|
|
version('5.1.1', sha256='6cf4eaae5beb9bd377f2abce9e4da9fd3e95bf086ae2f04554fad6dd561c28b9')
|
|
version('5.0.0', sha256='bdfd1620ff7158d96055059be04ee49466ebaca8213a2fdab33e2d4571019a49')
|
|
version('4.0.0', sha256='a3629f1f139865c74916f8f69318f53af6319e7f8ec54e85c16466fd7d256938')
|
|
version('3.3.0', sha256='499fd3b58656b4b6495496920e5372895861ebf15328be8a7a9354e06c734bc7')
|
|
version('3.2.0', sha256='34d93e1b2a3b8908ef89804b7e08c5a884cbbc0b2c9f139061627c0d2de282c1')
|
|
version('3.1.1', sha256='c1c3446ee023f7b24baa97b24907735e89ce4ae9f5ef516645dfe390165d1778')
|
|
|
|
variant('shared', default=False, description='Build shared libraries')
|
|
variant('mpi', default=True, description='Use MPI')
|
|
variant('openmp', default=True,
|
|
description='Enable thread parallellism via tasking with OpenMP')
|
|
variant('parmetis', default=True,
|
|
description='Enable use of ParMetis')
|
|
variant('scotch', default=False,
|
|
description='Enable use of Scotch')
|
|
variant('butterflypack', default=True,
|
|
description='Enable use of ButterflyPACK')
|
|
variant('zfp', default=True,
|
|
description='Build with support for compression using ZFP')
|
|
variant('c_interface', default=True,
|
|
description='Enable C interface')
|
|
variant('count_flops', default=False,
|
|
description='Build with flop counters')
|
|
variant('task_timers', default=False,
|
|
description='Build with timers for internal routines')
|
|
variant('build_dev_tests', default=False,
|
|
description='Build developer test routines')
|
|
variant('build_tests', default=False,
|
|
description='Build test routines')
|
|
variant('slate', default=True,
|
|
description="Build with SLATE support")
|
|
|
|
depends_on('cmake@3.11:', type='build')
|
|
depends_on('mpi', when='+mpi')
|
|
depends_on('blas')
|
|
depends_on('lapack')
|
|
depends_on('scalapack', when='+mpi')
|
|
depends_on('metis')
|
|
depends_on('parmetis', when='+parmetis')
|
|
depends_on('scotch~metis', when='+scotch')
|
|
depends_on('scotch~metis+mpi', when='+scotch+mpi')
|
|
depends_on('butterflypack@1.1.0', when='@3.3.0:3.9.999 +butterflypack+mpi')
|
|
depends_on('butterflypack@1.2.0:', when='@4.0.0: +butterflypack+mpi')
|
|
depends_on('cuda', when='@4.0.0: +cuda')
|
|
depends_on('zfp', when='+zfp')
|
|
depends_on('hipblas', when='+rocm')
|
|
depends_on('rocsolver', when='+rocm')
|
|
depends_on('slate', when='+slate')
|
|
depends_on('slate+cuda', when='+cuda+slate')
|
|
|
|
conflicts('+parmetis', when='~mpi')
|
|
conflicts('+butterflypack', when='~mpi')
|
|
conflicts('+butterflypack', when='@:3.2.0')
|
|
conflicts('+zfp', when='@:3.9.999')
|
|
conflicts('+cuda', when='@:3.9.999')
|
|
conflicts('+rocm', when='@:5.0.999')
|
|
conflicts('+rocm', when='+cuda')
|
|
conflicts('+slate', when='@:5.1.1')
|
|
conflicts('+slate', when='~mpi')
|
|
conflicts('^openblas@0.3.6: threads=none', when='+openmp',
|
|
msg='STRUMPACK requires openblas with OpenMP threading support')
|
|
conflicts('^openblas@0.3.6: threads=pthreads', when='+openmp',
|
|
msg='STRUMPACK requires openblas with OpenMP threading support')
|
|
|
|
patch('intel-19-compile.patch', when='@3.1.1')
|
|
|
|
def cmake_args(self):
|
|
spec = self.spec
|
|
|
|
def on_off(varstr):
|
|
return 'ON' if varstr in spec else 'OFF'
|
|
|
|
args = [
|
|
'-DSTRUMPACK_USE_MPI=%s' % on_off('+mpi'),
|
|
'-DSTRUMPACK_USE_OPENMP=%s' % on_off('+openmp'),
|
|
'-DSTRUMPACK_USE_CUDA=%s' % on_off('+cuda'),
|
|
'-DSTRUMPACK_USE_HIP=%s' % on_off('+rocm'),
|
|
'-DTPL_ENABLE_PARMETIS=%s' % on_off('+parmetis'),
|
|
'-DTPL_ENABLE_SCOTCH=%s' % on_off('+scotch'),
|
|
'-DTPL_ENABLE_BPACK=%s' % on_off('+butterflypack'),
|
|
'-DSTRUMPACK_COUNT_FLOPS=%s' % on_off('+count_flops'),
|
|
'-DSTRUMPACK_TASK_TIMERS=%s' % on_off('+task_timers'),
|
|
'-DSTRUMPACK_DEV_TESTING=%s' % on_off('+build_dev_tests'),
|
|
'-DSTRUMPACK_BUILD_TESTS=%s' % on_off('+build_tests'),
|
|
'-DTPL_BLAS_LIBRARIES=%s' % spec['blas'].libs.joined(";"),
|
|
'-DTPL_LAPACK_LIBRARIES=%s' % spec['lapack'].libs.joined(";"),
|
|
'-DBUILD_SHARED_LIBS=%s' % on_off('+shared')
|
|
]
|
|
|
|
if '+mpi' in spec:
|
|
args.append(
|
|
'-DTPL_SCALAPACK_LIBRARIES=%s' % spec['scalapack'].
|
|
libs.joined(";"))
|
|
|
|
if spec.satisfies('@:3.9.999'):
|
|
if '+mpi' in spec:
|
|
args.extend([
|
|
'-DCMAKE_C_COMPILER=%s' % spec['mpi'].mpicc,
|
|
'-DCMAKE_CXX_COMPILER=%s' % spec['mpi'].mpicxx,
|
|
'-DCMAKE_Fortran_COMPILER=%s' % spec['mpi'].mpifc
|
|
])
|
|
args.extend([
|
|
'-DSTRUMPACK_C_INTERFACE=%s' % on_off('+c_interface'),
|
|
])
|
|
|
|
if '+cuda' in spec:
|
|
args.extend([
|
|
'-DCUDA_TOOLKIT_ROOT_DIR={0}'.format(spec['cuda'].prefix),
|
|
'-DCMAKE_CUDA_HOST_COMPILER={0}'.format(env["SPACK_CXX"])])
|
|
cuda_archs = spec.variants['cuda_arch'].value
|
|
if 'none' not in cuda_archs:
|
|
args.append('-DCUDA_NVCC_FLAGS={0}'.
|
|
format(' '.join(self.cuda_flags(cuda_archs))))
|
|
|
|
if '+rocm' in spec:
|
|
args.append(
|
|
'-DHIP_ROOT_DIR={0}'.format(spec['hip'].prefix))
|
|
rocm_archs = spec.variants['amdgpu_target'].value
|
|
if 'none' not in rocm_archs:
|
|
args.append('-DHIP_HIPCC_FLAGS=--amdgpu-target={0}'.
|
|
format(",".join(rocm_archs)))
|
|
|
|
return args
|
|
|
|
test_data_dir = 'examples/data'
|
|
test_src_dir = 'test'
|
|
|
|
@run_after('install')
|
|
def cache_test_sources(self):
|
|
"""Copy the example source files after the package is installed to an
|
|
install test subdirectory for use during `spack test run`."""
|
|
self.cache_extra_test_sources([self.test_data_dir, self.test_src_dir])
|
|
|
|
def _test_example(self, test_prog, test_dir, test_cmd, test_args):
|
|
tmpbld_dir = '{0}/_BUILD'.format(test_dir)
|
|
with working_dir(tmpbld_dir, create=True):
|
|
with open('{0}/CMakeLists.txt'.format(tmpbld_dir), 'w') as mkfile:
|
|
mkfile.write('cmake_minimum_required(VERSION 3.13)\n')
|
|
mkfile.write('project(StrumpackSmokeTest LANGUAGES CXX)\n')
|
|
mkfile.write('find_package(STRUMPACK REQUIRED)\n')
|
|
mkfile.write('add_executable({0} ../{0}.cpp)\n'.
|
|
format(test_prog))
|
|
mkfile.write('target_link_libraries({0} '.format(test_prog) +
|
|
'PRIVATE STRUMPACK::strumpack)\n')
|
|
|
|
opts = self.std_cmake_args
|
|
opts += self.cmake_args()
|
|
opts += ['.']
|
|
self.run_test('cmake', opts, [], installed=False, work_dir='.')
|
|
self.run_test('make')
|
|
with set_env(OMP_NUM_THREADS='4'):
|
|
self.run_test(test_cmd, test_args, installed=False,
|
|
purpose='test: strumpack smoke test',
|
|
skip_missing=False, work_dir='.')
|
|
self.run_test('rm', ['-fR', tmpbld_dir])
|
|
|
|
def test(self):
|
|
test_dir = join_path(self.install_test_root, self.test_src_dir)
|
|
test_exe = 'test_sparse_seq'
|
|
test_exe_mpi = 'test_sparse_mpi'
|
|
exe_arg = ['../../examples/data/pde900.mtx']
|
|
if '+mpi' in self.spec:
|
|
test_args = ['-n', '4', test_exe_mpi]
|
|
test_args.extend(exe_arg)
|
|
mpiexe_list = ['mpirun', 'mpiexec', 'srun']
|
|
for mpiexe in mpiexe_list:
|
|
if which(mpiexe) is not None:
|
|
self._test_example(test_exe_mpi, test_dir,
|
|
mpiexe, test_args)
|
|
break
|
|
else:
|
|
self._test_example(test_exe, test_dir, test_exe, exe_arg)
|