summaryrefslogtreecommitdiff
path: root/var/spack/repos/builtin/packages/molgw/package.py
blob: 6031b6dd008dc3fbabc04e438423e777fe9e85d7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# Copyright 2013-2023 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 os import getenv
from subprocess import PIPE, run

from spack.package import *


class Molgw(MakefilePackage):
    """MOLGW is a quantum chemistry code that implements the many-body perturbation theory (MBPT)
    to describe the excited electronic states in finite systems (atoms, molecules, clusters).
    MOLGW implements the GW approximation for the self-energy (ionization and affinity)
    and the Bethe-Salpeter equation for the optical excitations.
    MOLGW also applies the real-time time-dependent density-functional theory (RT-TDDFT).
    MOLGW employs standard Gaussian basis set.
    """

    homepage = "https://github.com/bruneval/molgw"
    url = "https://github.com/bruneval/molgw/archive/v3.2.tar.gz"
    git = "https://github.com/bruneval/molgw.git"

    maintainers("bruneval")

    license("GPL-3.0-only")

    version("3.2", sha256="a3f9a99db52d95ce03bc3636b5999e6d92b503ec2f4afca33d030480c3e10242")

    variant("openmp", default=False, description="Build with OpenMP support")
    variant("scalapack", default=False, description="Build with ScaLAPACK support")

    depends_on("blas")
    depends_on("lapack")
    depends_on("libxc@5:")
    depends_on("libcint+pypzpx+coulomb_erf")

    depends_on("scalapack", when="+scalapack")
    depends_on("mpi", when="+scalapack")

    # enforce scalapack-capable mkl when asking +scalapack (and using intel-oneapi-mkl)
    depends_on("intel-oneapi-mkl+cluster", when="+scalapack ^intel-oneapi-mkl")
    # enforce threaded mkl when asking +openmp (and using intel-oneapi-mkl)
    depends_on("intel-oneapi-mkl threads=openmp", when="+openmp ^intel-oneapi-mkl")
    # enforce threaded openblas when asking +openmp (and using openblas)
    depends_on("openblas threads=openmp", when="+openmp ^openblas")

    def _get_mkl_ld_flags(self, spec):
        mklroot = str(getenv("MKLROOT"))
        command = [mklroot + "/bin/intel64/mkl_link_tool", "-libs", "--quiet"]

        if "+openmp" not in spec:
            command.extend(["--parallel=no"])
        else:
            command.extend(["--parallel=yes"])

            if "%intel" in spec or "%oneapi" in spec:
                command.extend(["-c", "intel_f"])
                if "+openmp" in spec:
                    command.extend(["-o", "iomp5"])
            elif "%gcc" in spec:
                command.extend(["-c", "gnu_f"])
                if "+openmp" in spec:
                    command.extend(["-o", "gomp"])

        if "+scalapack" in spec:
            command.extend(["--cluster_library=scalapack"])
            if "openmpi" in spec:
                command.extend(["-m", "openmpi"])
            elif "mpich" in spec:
                command.extend(["-m", "mpich2"])
            elif "intelmpi" in spec:
                command.extend(["-m", "intelmpi"])
        result = run(command, stdout=PIPE)
        return result.stdout.decode(encoding="utf-8").strip()

    def edit(self, spec, prefix):
        flags = {}
        flags["PREFIX"] = prefix

        # Set LAPACK and SCALAPACK
        if spec["lapack"].name not in INTEL_MATH_LIBRARIES:
            flags["LAPACK"] = self._get_mkl_ld_flags(spec)
        else:
            flags["LAPACK"] = spec["lapack"].libs.ld_flags + " " + spec["blas"].libs.ld_flags
            if "+scalapack" in spec:
                flags["SCALAPACK"] = spec["scalapack"].libs.ld_flags

        # Set FC
        if "+scalapack" in spec:
            flags["FC"] = "{0}".format(spec["mpi"].mpifc)
        else:
            flags["FC"] = self.compiler.fc_names[0]

        # Set FCFLAGS
        if self.compiler.flags.get("fflags") is not None:
            flags["FCFLAGS"] = " ".join(self.compiler.flags.get("fflags")) + " "
        if "+openmp" in spec:
            flags["FCFLAGS"] = flags.get("FCFLAGS", "") + " {0} ".format(self.compiler.openmp_flag)
        if "%intel" in spec or "%oneapi" in spec:
            flags["FCFLAGS"] = flags.get("FCFLAGS", "") + " -fpp "
        else:
            flags["FCFLAGS"] = flags.get("FCFLAGS", "") + " -cpp "

        # Set CPPFLAGS
        if "+scalapack" in spec:
            flags["CPPFLAGS"] = flags.get("CPPFLAGS", "") + " -DHAVE_SCALAPACK -DHAVE_MPI "

        if spec["lapack"].name in INTEL_MATH_LIBRARIES:
            flags["CPPFLAGS"] = flags.get("CPPFLAGS", "") + " -DHAVE_MKL "

        # Write configuration file
        with open("my_machine.arch", "w") as f:
            for k, v in flags.items():
                f.write(k + "=" + v + "\n")