summaryrefslogtreecommitdiff
path: root/var/spack/repos/builtin/packages/fplo/package.py
blob: a9e8cbc2c2fb1167a5ccef9e71fcdb8f7cc41dd7 (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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# 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)

import glob
import os
import platform

from spack.package import *


class Fplo(MakefilePackage):
    """The FPLO(R) package is a full-potential local-orbital code to solve the
    Kohn-Sham equations on a regular lattice or with free boundary conditions
    (finite systems). Relativistic effects are treated either in a
    scalar-relativistic or a full  4-component formalism.  Available
    functionals are LSDA, GGA (PBE 96) and LSDA/GGA+U. Orbital polarization
    correction can be applied."""

    homepage = "https://www.fplo.de/"
    url = "file://{0}/FPLO22.00-62.tar.gz".format(os.getcwd())
    manual_download = True

    version("22.00-62", sha256="0d1d4e9c1e8e41900901e26c3cd08ee39dcfdeb3f2c4c8862055eaf704b6d69e")

    # TODO: Try to get LAPACK to work with something other than MKL. The build
    # fails even with the fallback/builtin lapack.

    # This patch replaces the default builtin lapack with MKL, as MKL is the
    # only functioning LAPACK implementation.
    patch("lapackconfig.patch")

    # This patch does 3 things: (1) Change the order of the src directories so
    # the object dependencies are correct; (2) removes interactivity; and (3)
    # explicitly sets the configuration.
    patch("MMakefile.patch")

    # Add '-ltinfo' for linking.
    patch("ncurses.patch")

    # Set the names for QT and PYTHON.
    patch("qt-make.patch")

    # Sets the correct python module import order.
    patch("fedit_py.patch")

    depends_on("mkl")
    depends_on("ncurses")
    depends_on("perl", type="run")
    depends_on("qt@5+opengl")

    extends("python")
    depends_on("py-numpy")

    conflicts("%gcc@12:")

    @property
    def build_directory(self):
        return join_path(self.stage.source_path, "FPLO{0}".format(self.version))

    def edit(self, spec, prefix):
        # Need to set this to 'gcc' even if using the intel compiler as all of
        # the configuration files are named with 'gcc'.
        if platform.system() == "Linux":
            fplo_cc = "gcc"
        else:
            fplo_cc = os.path.basename(self.compiler.cc)

        fplo_fc = os.path.basename(self.compiler.fc)

        conffile = "{0}-{1}-{2}-{3}".format(
            fplo_cc, fplo_fc, platform.system(), platform.machine()
        )
        mmakefile = FileFilter(join_path(self.build_directory, "install", "MMakefile"))
        mmakefile.filter(r"(^conffile=\$configdir/)$", r"\1{0}".format(conffile))
        mmakefile.filter(r"(^mkl=).*", r"\11")

        # use spack compiler
        files = glob.glob(join_path(self.build_directory, "install", "conf", "*"))
        filter_file(r"^\s*CC\s*=.*", "CC=" + spack_cc, *files)
        filter_file(r"^\s*CXX\s*=.*", "CXX=" + spack_cxx, *files)
        filter_file(r"^\s*F90\s*=.*", "F90=" + spack_fc, *files)

        # patch for 64 bit integers
        if spec["mkl"].satisfies("+ilp64"):
            setuphelper = FileFilter(join_path(self.build_directory, "PYTHON", "setuphelper.py"))
            setuphelper.filter("mkl 64bit integer 32bit", "mkl 64bit integer 64bit")

        # setup python build
        python_makefile = FileFilter(join_path(self.build_directory, "PYTHON", "Makefile"))
        python_makefile.filter(r"(build_ext\s* --inplace)\s*--interactive(\s*.*)", r"\1\2")

    def build(self, spec, prefix):
        mmakefile = Executable(join_path(self.build_directory, "install", "MMakefile"))
        mmakefile_args = ["-f90", spack_fc, "-cc", spack_cc, "-c+", spack_cxx]

        with working_dir(self.build_directory):
            # copy contents of bin
            copy_tree("bin", join_path(self.stage.source_path, "bin"))

            # configure the build
            with working_dir("install"):
                mmakefile(*mmakefile_args)

            # build main
            make()
            make("install")

            # build XFBP
            with working_dir(join_path("XFBP_rel", "XFBP")):
                make()
                make("install")

            # build XFPLO
            with working_dir(join_path("XFPLO_rel", "XFPLO")):
                make()
                make("install")

            # build python
            with working_dir("PYTHON"):
                make("python3")

    def install(self, spec, prefix):
        with working_dir(self.stage.source_path):
            install_tree("bin", prefix.bin)

        with working_dir(self.build_directory):
            install_tree("DOC", join_path(prefix.share, "DOC"))
            with working_dir("PYTHON"):
                install_tree("pyfplo", join_path(python_platlib, "pyfplo"))

    @run_after("install")
    def perl_interpreter(self):
        with working_dir(self.prefix.bin):
            pattern = "^#!.*/usr/bin/perl"
            repl = "#!{0}".format(self.spec["perl"].command.path)
            files = ["fconv2", "fconvdens2", "fdowngrad.pl", "fout2in", "grBhfat", "grpop"]
            for file in files:
                filter_file(pattern, repl, *files, backup=False)