-
Oriol Tintó authoredOriol Tintó authored
package.py 9.12 KiB
# 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 pathlib import Path
import os
from urllib.parse import urlparse
from spack.package import *
class IconNwp(Package):
"""
Recipe to build ICON-NWP using the LMU gitlab repository.
"""
git = "https://gitlab.dkrz.de/icon/icon-nwp.git"
homepage = "https://code.mpimet.mpg.de/projects/iconpublic"
# maintainers("oriol.tinto")
version("w2w-B6", branch="w2w/B6_MCRPH")
# FIXME: The ugly configuration system in older icon versions prevents us from using this package with it.
# version("2.5.0-nwp3", branch="icon-nwp/op-release-2.5.0-nwp3")
version("2.6.4-nwp3", branch="icon-nwp/op-release-2.6.4-nwp3")
version("2.6.5-nwp0", branch="icon-nwp/op-release-2.6.5-nwp0")
version("psp", branch="icon-nwp/icon-nwp-psp")
version("plexrt", branch="icon-nwp/icon-nwp-plexrt")
version("master", branch="master")
# FIXME: Workaround to deal with different sources. The default is using dkrz's through ssh.
variant("source", values=('dkrz', 'dkrz_https', 'lmu'), default='dkrz_https',
description='Select the source of the ICON: dkrz (ssh), dkrz_https, lmu (ssh)')
custom_fetchers = {
"dkrz": "ssh://git@gitlab.dkrz.de/icon/icon-nwp.git",
"dkrz_https": "https://gitlab.dkrz.de/icon/icon-nwp.git",
"lmu": "ssh://git@gitlab.physik.uni-muenchen.de/w2w/icon.git",
}
variant("debug", default=False, description="add debug flags when compiling icon")
variant("parallelnetcdf", default=True, description="enable-parallel-netcdf")
variant("yaxt", default=True, description="enable-yaxt")
variant("grib2", default=True, description="enable-grib2")
variant("mpichecks", default=True, description="enable-mpi-checks")
variant("waves" , default=False, description="enable-waves")
variant("ecrad" , default=False, description="enable-ecrad")
variant("rttov" , default=False, description="enable-rttov")
variant("dace" , default=False, description="enable-dace")
variant("emvorado", default=False, description="enable-emvorado")
variant("art" , default=False, description="enable-art")
variant("plexrt" , default=False, description="add 3D radiation support with TenStream")
variant("petsc" , default=False, description="add PETSc support")
# Dependencies
depends_on("mpi")
depends_on("netcdf-c")
depends_on("netcdf-fortran")
depends_on("eccodes+fortran")
depends_on("libxml2")
depends_on("libfyaml")
depends_on("petsc", when="@psp")
depends_on("petsc", when="+petsc")
depends_on("tenstream", when="@plexrt")
depends_on("tenstream", when="+plexrt")
# Openblas? best way of doing it?
depends_on("openblas", when="%gcc")
depends_on("intel-mkl", when="%intel")
phases = ["configure", "build", "install"]
def do_fetch(self, mirror_only=False):
# FIXME: Using the custom_fetchers workaround
source = self.spec.variants['source'].value
url = self.custom_fetchers[source]
token = os.environ.get('SPACK_ICON_NWP_GITTOKEN')
if token is not None:
if 'https' in url:
parsed = urlparse(url)
user = 'token'
password = token
url = "{}://{}:{}@{}/{}".format(parsed.scheme, user, password, parsed.netloc, parsed.path)
self.fetcher.url = self.git = url
super(IconNwp, self).do_fetch(mirror_only)
def patch(self):
# Run git submodule update
git = which("git")
git("submodule", "update", "--init", "--recursive")
def setup_build_environment(self, env):
spec = self.spec
# Some environment variables to set
env_variables_to_set = {
"CC": spec["mpi"].mpicc,
"FC": spec["mpi"].mpifc,
"F77": spec["mpi"].mpif77,
}
for variable, value in env_variables_to_set.items():
env.set(variable, value)
def configure(self, spec, prefix):
spec = self.spec
INCLUDES = [f"-I{spec['libxml2'].prefix}/include/libxml2", ]
libs = [
f"-L{spec['netcdf-c'].prefix.lib} -lnetcdf ", # netcdf-c libs
f"-L{spec['netcdf-fortran'].prefix.lib} -lnetcdff", # netcdf-fortran libs
f"-L{spec['eccodes'].prefix.lib} -leccodes_f90 -leccodes",
f"-L{spec['libxml2'].prefix.lib} -lxml2", # XML2 libs
f"-L{spec['libfyaml'].prefix.lib} -lfyaml", # libfyaml libs.
]
if self.spec.satisfies("%gcc"):
libs.append("-lopenblas")
elif self.spec.satisfies("%intel"):
libs.append("-qmkl=sequential")
mtune = "generic"
CPPFLAGS = []
if "+plexrt" in self.spec:
CPPFLAGS.append("-DHAVE_PLEXRT")
INCLUDES.append(f"-I{spec['tenstream'].prefix}/include")
libs.append(f"-L{spec['tenstream'].prefix.lib} -ltenstream")
if "+petsc" in self.spec:
CPPFLAGS.append("-DHAVE_PETSC")
INCLUDES.append(f"-I{spec['petsc'].prefix}/include")
libs.append(f"-L{spec['petsc'].prefix.lib} -lpetsc")
if self.spec.satisfies("%gcc"):
FCFLAGS = "-std=legacy -fmodule-private -fimplicit-none -fmax-identifier-length=63 -Wall " \
"-Wcharacter-truncation -Wconversion -Wunderflow -Wunused-parameter " \
"-Wno-surprising -fall-intrinsics -g -mpc64 -w"
ARCH_FLAG = f"-mtune={mtune}"
ICON_FCFLAGS = "-std=f2008 -fallow-argument-mismatch -fmodule-private -fimplicit-none -Wall"
elif self.spec.satisfies("%intel"):
FCFLAGS = "-stand none -implicitnone -warn all -warn unused -fall-intrinsics -g -w"
ARCH_FLAG = f"-xHost"
ICON_FCFLAGS = "-stand f08 -implicitnone -warn all"
else:
raise AssertionError
options = [
f"CC={spec['mpi'].mpicc}",
f"FC={spec['mpi'].mpifc}",
f"CFLAGS=-g -mpc64 {' '.join(INCLUDES)}",
f"ICON_CFLAGS=-O3 -g {ARCH_FLAG}",
f"ICON_BUNDLED_CFLAGS=-O3 -mtune={mtune}",
f"CPPFLAGS={' '.join(CPPFLAGS)}",
f"FCFLAGS={FCFLAGS}",
f"ICON_OCEAN_FCFLAGS=-O3 {ARCH_FLAG}",
f"LDFLAGS={' '.join(libs)}",
f"LIBS={' '.join(libs)}",
f"--prefix={prefix}",
]
if "+debug" in self.spec:
if self.spec.satisfies("%gcc"):
options.append(f"ICON_FCFLAGS={ICON_FCFLAGS} -fbacktrace -fbounds-check -fstack-protector-all -finit-real=nan -finit-integer=-2147483648 -finit-character=127 -w -O2")
elif self.spec.satisfies("%intel"):
options.append(f"ICON_FCFLAGS={ICON_FCFLAGS} -traceback -check bounds -init=snan -O2")
else:
raise AssertionError("Compiler does not satisfy gcc nor intel.")
else:
options.append(f"ICON_FCFLAGS={ICON_FCFLAGS} -O3")
if "~mpichecks" in self.spec:
options.append("--enable-mpi-checks=no")
if "+parallelnetcdf" in self.spec:
options.append("--enable-parallel-netcdf")
if "+yaxt" in self.spec:
options.append("--enable-yaxt")
if "+grib2" in self.spec:
options.append("--enable-grib2")
if "+waves" in self.spec:
options.append("--enable-waves")
if "+ecrad" in self.spec:
options.append("--enable-ecrad")
if "+rttov" in self.spec:
options.append("--enable-rttov")
if "+dace" in self.spec:
options.append("--enable-dace")
if "+emvorado" in self.spec:
options.append("--enable-emvorado")
if "+art" in self.spec:
options.append("--enable-art")
configure(*options)
def build(self, spec, prefix):
make()
def install(self, spec, prefix):
make("install")
# Create extra folders with the data and the docs
self.make_extra_folders(prefix)
def setup_run_environment(self, env):
env.set("ICON_BASE_PATH", self.spec.prefix)
env.set("ICON_DATA_PATH", self.spec.prefix.join("data"))
env.set("ICON_DOCS_PATH", self.spec.prefix.join("doc"))
def make_extra_folders(self, prefix):
mkdir = which("mkdir")
rsync = which("rsync")
curl = which("curl")
# copy executables and documentation
mkdir("-p", f"{prefix}/data")
mkdir("-p", f"{prefix}/doc")
mkdir("-p", f"{prefix}/run")
rsync("-av", "data/", f"{prefix}/data")
rsync("-av", "run/", f"{prefix}/run")
rsync("-av", "--include='*.pdf'", "--exclude='*.*'", "doc/", f"{prefix}/doc/")
curl(
"https://code.mpimet.mpg.de/attachments/download/19568/ICON_tutorial_2019.pdf",
"--output",
f"{prefix}/doc/ICON_tutorial_2019.pdf",
)
curl(
"http://www.cosmo-model.org/content/model/documentation/core/emvorado_userguide.pdf",
"--output",
f"{prefix}/doc/emvorado_userguide.pdf",
)