import os
import subprocess
from logging import debug
from shutil import copy, copytree, ignore_patterns, rmtree
[docs]
def compile(self):
comp_dir = "{}/model".format(self.workdir)
# Copying the executables
try:
# If force-recompile = True, return IOError to avoid copying
if getattr(self, "force-recompile"):
raise IOError
# Otherwise, try copying executables
source = "{}/src/fwdchimere.e".format(self.direxec)
copy(source, comp_dir)
source = "{}/src_tl/tlchimere.e".format(self.direxec)
copy(source, comp_dir)
source = "{}/src_ad/achimere.e".format(self.direxec)
copy(source, comp_dir)
return
except IOError as e:
if not getattr(self, "auto-recompile"):
raise RuntimeError(
f"CHIMERE could not find executables ({self.direxec}) and was not asked to "
"compile them; specify auto-recompile = True in Yaml to do so"
) from e
# Otherwise, re-compile
# Copying sources locally; overwrite folder if exists
if os.path.isdir("{}/sources".format(comp_dir)):
rmtree("{}/sources".format(comp_dir))
dir_sources = self.dir_sources if self.dir_sources != "" else self.direxec
copytree(
dir_sources,
"{}/sources".format(comp_dir),
ignore=ignore_patterns("*.a"),
)
# Modifying LDFLAGS if needed
if hasattr(self, "LDFLAGS"):
for fld in ["src", "src_tl", "src_ad"]:
old_lines = open(
"{}/sources/{}/Makefile_chimere".format(comp_dir, fld), "r"
).readlines()
old_lines = [ln.rstrip() for ln in old_lines]
for k, ln in enumerate(old_lines):
if ln[:7] == "LDFLAGS":
old_lines[k] = "LDFLAGS =\t{}".format(self.LDFLAGS)
with open("{}/sources/{}/Makefile_chimere".format(comp_dir, fld), "w") as f:
f.write("\n".join(old_lines))
# Modifying Makefile header if needed
makefile_sed = os.path.join(comp_dir, "sources", "Makefile.hdr.sed")
with open(makefile_sed, "r") as f:
lines = [line.strip() for line in f.readlines()]
# Join lines that are split with a backslash (keep backslash and newline characters)
joined_lines = []
join = False
for line in lines:
if join:
joined_lines[-1] = joined_lines[-1] + "\n" + line # append line to previous
else:
joined_lines.append(line) # new line
# Join next line if current line ends with a backslash
join = line.endswith("\\")
gfortran_line = False
new_lines = []
for line in joined_lines:
if gfortran_line:
gfortran_line = False # Reset flag
if line.startswith("MF77") and hasattr(self, "gfortran_executable"):
line = f"MF77\t=\t{self.gfortran_executable}" # Replace line with new value
elif line.startswith("F77FLAGS1") and hasattr(self, "COMPILOPTIONS"):
line = line + " " + self.COMPILOPTIONS # append value to line
elif line == "REALFC\t=\tgfortran":
gfortran_line = True # Replace next line
else:
for varname in ("NETCDFLIB", "NETCDFINC", "GRIBLIB", "GRIBINC"):
if line.startswith(varname) and hasattr(self, varname):
line = f"{varname}\t=\t{getattr(self, varname)}" # Replace line with new value
break
new_lines.append(line)
with open(makefile_sed, "w") as f:
f.write("\n".join(new_lines))
# Now compiling
comp_mode = "" if getattr(self, "compile-mode") == "PROD" else "--debug"
comp_clean = "--clean" if getattr(self, "compile-clean") else ""
compiler = "--{}".format(getattr(self, "compiler", "ifort"))
for mode, pref, suff in zip(
["A", "L", "D"], ["a", "tl", "fwd"], ["_ad", "_tl", ""]
):
if not mode in getattr(self, "compile-only"):
continue
debug("Compiling CHIMERE {}".format(mode))
with open("{}/CHIMERE_compiling_{}.log"
.format(comp_dir, mode), "w") as log:
process = subprocess.Popen(
f"./compile-chimere -m "
f"{mode} {comp_mode} {comp_clean} {compiler}",
shell=True,
stdout=log,
cwd="{}/sources/".format(comp_dir),
stderr=subprocess.PIPE,
)
_, stderr = process.communicate()
# Print errors if no executable created (or if forced to)
exe_file = "{}/sources/src{}/{}chimere.e".format(comp_dir, suff, pref)
if not os.path.isfile(exe_file) or getattr(self, "force-compile-stderr"):
debug("CHIMERE returned errors during compiling.")
debug("There might be some bugs in the Fortran or in the "
"libraries loaded in the system:")
debug("### START OF CHIMERE ERROR MESSAGE ###")
for ln in stderr.decode().split("\n"):
debug(ln)
debug("### END OF CHIMERE ERROR MESSAGE ###")
# Copy executable at model root directory
copy(exe_file, comp_dir)