summaryrefslogtreecommitdiff
path: root/var/spack/repos/builtin/packages/regcm/package.py
blob: 2b47d0e5223739a6c9fd1b8fcb88648f2c4c99db (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
141
142
143
144
145
146
147
148
149
150
# Copyright 2013-2024 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.package import *


class Regcm(AutotoolsPackage):
    """RegCM, ICTP Regional Climate Model (https://ictp.it)."""

    homepage = "https://gforge.ictp.it/gf/project/regcm/"

    license("AFL-1.1")

    version(
        "4.7.0",
        sha256="456631c10dcb83d70e51c3babda2f7a1aa41ed9e60cb4209deb3764655267519",
        url="https://gforge.ictp.it/gf/download/frsrelease/259/1845/RegCM-4.7.0.tar.gz",
    )

    variant("debug", default=False, description="Build RegCM using debug options.")
    variant("profile", default=False, description="Build RegCM using profiling options.")
    variant(
        "singleprecision",
        default=False,
        description="Build RegCM using single precision float type.",
    )

    # On Intel and PGI compilers, multiple archs can be built at the same time,
    # producing a so-called fat binary. Unfortunately, gcc builds only the last
    # architecture provided at the configure line.
    # For this reason, we allow a single arch when using GCC (checks are
    # performed below in the configure_args).
    # Moreover, RegCM supports optimizations only for GCC and Intel compilers.
    # To sum up:
    # - intel: a user is able to build a single executables for all the
    #   combinations of architectures (e.g. `--extension=knl,skl,bdw,nhl`);
    # - gcc: a user is allowed to build an executable using a single
    #   optimization/extension;
    # - other compilers: no extensions/optimizations are supported.
    #
    # See also discussions: #974, #9934, #10797.
    extensions = ("knl", "skl", "bdw", "nhl")
    variant(
        "extension",
        values=any_combination_of(*extensions),
        description="Build extensions for a specific architecture. Only "
        "available for GCC and Intel compilers; moreover, "
        "GCC builds only one architecture optimization.",
    )

    variant(
        "pnetcdf",
        default=False,
        description="Build NetCDF using the high performance parallel " "NetCDF implementation.",
    )

    depends_on("netcdf-c")
    depends_on("netcdf-fortran")
    depends_on("hdf5")
    depends_on("mpi")
    depends_on("netcdf-c +parallel-netcdf", when="+pnetcdf")

    intel_msg = (
        "Intel compiler not working with this specific version of "
        "RegCM (generates a bug at runtime): please install a newer "
        "version of RegCM or use a different compiler."
    )
    conflicts("%intel", when="@4.7.0", msg=intel_msg)

    # 'make' sometimes crashes when compiling with more than 10-12 cores.
    # Moreover, parallel compile time is ~ 1m 30s, while serial is ~ 50s.
    parallel = False

    def flag_handler(self, name, flags):
        if name == "fflags" and self.compiler.fc.endswith("gfortran"):
            flags.extend(
                [
                    "-Wall",
                    "-Wextra",
                    "-Warray-temporaries",
                    "-Wconversion",
                    "-fimplicit-none",
                    "-fbacktrace",
                    "-ffree-line-length-0",
                    "-finit-real=nan",
                    "-ffpe-trap=zero,overflow,underflow",
                    "-fcheck=all",
                ]
            )

        elif name == "ldlibs":
            flags.extend(["-lnetcdff", "-lnetcdf"])
            if self.compiler.fc.endswith("gfortran"):
                flags.extend(["-lm", "-ldl"])
            else:
                flags.extend(["-lhdf5_hl", "-lhdf5", "-lz"])

        return (None, None, flags)

    def configure_args(self):
        args = ["--enable-shared"]

        optimizations = self.spec.variants["extension"].value
        first_optim = optimizations[0]

        if first_optim != "none":
            if not (self.spec.satisfies(r"%gcc") or self.spec.satisfies(r"%intel")):
                # This means the user chose some optimizations on a different
                # compiler from GCC and Intel, which are the only compiler
                # supported by RegCM 4.7.x.
                raise InstallError(
                    "Architecture optimizations are available " "only for GCC and Intel compilers."
                )

            if len(optimizations) > 1 and self.spec.satisfies(r"%gcc"):
                # https://github.com/spack/spack/issues/974
                raise InstallError(
                    "The GCC compiler does not support " "multiple architecture optimizations."
                )

            # RegCM configure script treats --disable-X as --enable-X, so we
            # cannot use enable_or_disable; enable only the flags requested.
            args += ("--enable-" + ext for ext in optimizations)

        for opt in ("debug", "profile", "singleprecision"):
            if ("+" + opt) in self.spec:
                args.append("--enable-" + opt)

        # RegCM SVN6916 introduced a specific flag to use some pnetcdf calls.
        if "+pnetcdf" in self.spec and "@4.7.0-SVN6916:" in self.spec:
            args.append("--enable-parallel-nc")

        # RegCM doesn't listen to the FFLAGS variable, so we have to route
        # flags to FCFLAGS.
        fcflags = list(self.spec.compiler_flags["fflags"])

        # RegCM complains when compiled with gfortran.
        if self.compiler.fc.endswith("gfortran"):
            fcflags.append("-fno-range-check")

        args.append("FCFLAGS=" + " ".join(fcflags))

        # The configure needs a hint on the MPI Fortran compiler, otherwise it
        # doesn't find it and tries to compile MPI Fortran code with the system
        # Fortran non-MPI compiler.
        args.append("MPIFC=" + self.spec["mpi"].mpifc)

        return args