summaryrefslogblamecommitdiff
path: root/var/spack/repos/builtin/packages/berkeleygw/package.py
blob: 2a89494d800928c0409ff163298b8fcb41ce6a84 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
                                                                         














                                                                                 

                                     




















































                                                                                             





                                                                   















































































































































                                                                                    
# Copyright 2013-2022 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 *


class Berkeleygw(MakefilePackage):
    """BerkeleyGW is a many-body perturbation theory code for excited states,
    using the GW method and the GW plus Bethe-Salpeter equation (GW-BSE) method
    to solve respectively for quasiparticle excitations and optical properties of
    materials."""

    homepage = "https://berkeleygw.org"

    maintainers = ['migueldiascosta']

    version('3.0.1',
            '7d8c2cc1ee679afb48efbdd676689d4d537226b50e13a049dbcb052aaaf3654f',
            url='https://berkeley.box.com/shared/static/m1dgnhiemo47lhxczrn6si71bwxoxor8.gz',
            expand=False)
    version('3.0',
            'ab411acead5e979fd42b8d298dbb0a12ce152e7be9eee0bb87e9e5a06a638e2a',
            url='https://berkeley.box.com/shared/static/lp6hj4kxr459l5a6t05qfuzl2ucyo03q.gz',
            expand=False)
    version('2.1',
            '31f3b643dd937350c3866338321d675d4a1b1f54c730b43ad74ae67e75a9e6f2',
            url='https://berkeley.box.com/shared/static/ze3azi5vlyw7hpwvl9i5f82kaiid6g0x.gz',
            expand=False)

    variant('mpi', default=True, description='Builds with MPI support')
    variant('elpa', default=True, description='Build with ELPA support')
    variant('python', default=False, description='Build with Python support')
    variant('openmp', default=True, description='Build with OpenMP support')
    variant('scalapack', default=True, description='Build with ScaLAPACK support')
    variant('hdf5', default=True, description='Builds with HDF5 support')
    variant('debug', default=False, description='Builds with DEBUG flag')
    variant('verbose', default=False, description='Builds with VERBOSE flag')

    depends_on('blas')
    depends_on('lapack')
    depends_on('scalapack')
    depends_on('mpi', when='+mpi')
    depends_on('hdf5+fortran+hl', when='+hdf5~mpi')
    depends_on('hdf5+fortran+hl+mpi', when='+hdf5+mpi')
    depends_on('scalapack', when='+scalapack+mpi')
    depends_on('elpa+openmp', when='+elpa+openmp')
    depends_on('elpa~openmp', when='+elpa~openmp')
    depends_on('fftw-api@3+openmp', when='+openmp')
    depends_on('fftw-api@3~openmp', when='~openmp')

    depends_on('python@:2', type=('build', 'run'), when='+python')
    depends_on('py-numpy@:1.16', type=('build', 'run'), when='+python')
    depends_on('py-setuptools@:44', type=('build', 'run'), when='+python')
    depends_on('py-h5py@:2', type=('build', 'run'), when='+hdf5+python')

    depends_on('perl', type='test')

    conflicts(
        '+scalapack',
        when='~mpi',
        msg='scalapack is a parallel library and needs MPI support'
    )

    conflicts(
        '+elpa',
        when='~mpi',
        msg='elpa is a parallel library and needs MPI support'
    )

    # Force openmp propagation on some providers of blas / fftw-api
    with when('+openmp'):
        depends_on('fftw+openmp', when='^fftw')
        depends_on('amdfftw+openmp', when='^amdfftw')
        depends_on('openblas threads=openmp', when='^openblas')
        depends_on('amdblis threads=openmp', when='^amdblis')

    parallel = False

    def edit(self, spec, prefix):
        # archive is a tar file, despite the .gz expension
        tar = which('tar')
        tar('-x', '-f', self.stage.archive_file, '--strip-components=1')

        # get generic arch.mk template
        copy(join_path(self.stage.source_path, 'config', 'generic.mpi.linux.mk'),
             'arch.mk')

        if self.version == Version('2.1'):
            # don't try to install missing file
            filter_file('install manual.html', '#install manual.html', 'Makefile')

        # don't rebuild in the install and test steps
        filter_file('install: all', 'install:', 'Makefile')
        filter_file('check: all', 'check:', 'Makefile')

        # use parallelization in tests
        filter_file(r'cd testsuite \&\& \$\(MAKE\) check$',
                    'cd testsuite && $(MAKE) check-parallel',
                    'Makefile')

        # remove stack ulimit in order to run openmp tests
        filter_file(r'function run_testsuite\(\) {',
                    'function run_testsuite() {\nulimit -s unlimited',
                    'testsuite/run_testsuite.sh')

    def setup_build_environment(self, env):
        if self.run_tests:
            env.set('OMP_NUM_THREADS', '2')
            env.set('BGW_TEST_MPI_NPROCS', '2')

    def build(self, spec, prefix):

        buildopts = []
        paraflags = []

        if '+mpi' in spec:
            paraflags.append('-DMPI')

        if '+openmp' in spec:
            paraflags.append('-DOMP')
            spec.compiler_flags['fflags'].append(self.compiler.openmp_flag)

        buildopts.append('C_PARAFLAG=-DPARA')
        buildopts.append('PARAFLAG=%s' % ' '.join(paraflags))

        debugflag = ""
        if '+debug' in spec:
            debugflag += "-DDEBUG "
        if '+verbose' in spec:
            debugflag += "-DVERBOSE "
        buildopts.append('DEBUGFLAG=%s' % debugflag)

        buildopts.append('LINK=%s' % spec['mpi'].mpifc)
        buildopts.append('C_LINK=%s' % spec['mpi'].mpicxx)

        buildopts.append('FOPTS=%s' % ' '.join(spec.compiler_flags['fflags']))
        buildopts.append('C_OPTS=%s' % ' '.join(spec.compiler_flags['cflags']))

        mathflags = []

        mathflags.append('-DUSEFFTW3')
        buildopts.append('FFTWINCLUDE=%s' % spec['fftw-api'].prefix.include)
        fftwspec = spec['fftw-api:openmp' if '+openmp' in spec else 'fftw-api']
        buildopts.append('FFTWLIB=%s' % fftwspec.libs.ld_flags)

        buildopts.append('LAPACKLIB=%s' % spec['lapack'].libs.ld_flags)

        if '+scalapack' in spec:
            mathflags.append('-DUSESCALAPACK')
            buildopts.append('SCALAPACKLIB=%s' % spec['scalapack'].libs.ld_flags)

        if spec.satisfies('%intel'):
            buildopts.append('COMPFLAG=-DINTEL')
            buildopts.append('MOD_OPT=-module ')
            buildopts.append('F90free=%s -free' % spec['mpi'].mpifc)
            buildopts.append('FCPP=cpp -C -P -ffreestanding')
            buildopts.append('C_COMP=%s' % spec['mpi'].mpicc)
            buildopts.append('CC_COMP=%s' % spec['mpi'].mpicxx)
            buildopts.append('BLACSDIR=%s' % spec['scalapack'].libs)
            buildopts.append('BLACS=%s' % spec['scalapack'].libs.ld_flags)
            buildopts.append('FOPTS=%s' % ' '.join(spec.compiler_flags['fflags']))
        elif spec.satisfies('%gcc'):
            c_flags = '-std=c99'
            cxx_flags = '-std=c++0x'
            f90_flags = "-ffree-form -ffree-line-length-none -fno-second-underscore"
            if spec.satisfies('%gcc@10:'):
                c_flags += ' -fcommon'
                cxx_flags += ' -fcommon'
                f90_flags += ' -fallow-argument-mismatch'
            buildopts.append('COMPFLAG=-DGNU')
            buildopts.append('MOD_OPT=-J ')
            buildopts.append('F90free=%s %s' % (spec['mpi'].mpifc, f90_flags))
            buildopts.append('FCPP=cpp -C -nostdinc')
            buildopts.append('C_COMP=%s %s' % (spec['mpi'].mpicc, c_flags))
            buildopts.append('CC_COMP=%s %s' % (spec['mpi'].mpicxx, cxx_flags))
            buildopts.append('FOPTS=%s' % ' '.join(spec.compiler_flags['fflags']))
        elif spec.satisfies('%fj'):
            c_flags = '-std=c99'
            cxx_flags = '-std=c++0x'
            f90_flags = "-Free"
            buildopts.append('COMPFLAG=')
            buildopts.append('MOD_OPT=-module ')
            buildopts.append('F90free=%s %s' % (spec['mpi'].mpifc, f90_flags))
            buildopts.append('FCPP=cpp -C -nostdinc')
            buildopts.append('C_COMP=%s %s' % (spec['mpi'].mpicc, c_flags))
            buildopts.append('CC_COMP=%s %s' % (spec['mpi'].mpicxx, cxx_flags))
            buildopts.append('FOPTS=-Kfast -Knotemparraystack %s' %
                             ' '.join(spec.compiler_flags['fflags']))
        else:
            raise InstallError("Spack does not yet have support for building "
                               "BerkeleyGW with compiler %s" % spec.compiler)

        if '+hdf5' in spec:
            mathflags.append('-DHDF5')
            buildopts.append('HDF5INCLUDE=%s' % spec['hdf5'].prefix.include)
            buildopts.append('HDF5LIB=%s' % spec['hdf5:hl,fortran'].libs.ld_flags)

        if '+elpa' in spec:
            mathflags.append('-DUSEELPA')
            elpa = spec['elpa']

            if '+openmp' in spec:
                elpa_suffix = '_openmp'
            else:
                elpa_suffix = ''

            elpa_incdir = elpa.headers.directories[0]
            elpa_libs = join_path(elpa.libs.directories[0],
                                  'libelpa%s.%s' % (elpa_suffix, dso_suffix))

            buildopts.append('ELPALIB=%s' % elpa_libs)
            buildopts.append('ELPAINCLUDE=%s' % join_path(elpa_incdir, 'modules'))

        buildopts.append('MATHFLAG=%s' % ' '.join(mathflags))

        make('all-flavors', *buildopts)

    def install(self, spec, prefix):
        make('install', 'INSTDIR=%s' % prefix)