import os
import subprocess
from shutil import copytree, ignore_patterns, rmtree, copy
from logging import info, debug
[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 Exception(
"CHIMERE could not find executables ({}) and was not asked to "
"compile them; specify auto-recompile = True in Yaml to do so"
.format(self.direxec)
)
# 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") or hasattr(self, "NETCDFLIB") or hasattr(self, "NETCDFINC"):
old_lines = open(
"{}/sources/Makefile".format(comp_dir), "r"
).readlines()
old_lines = [ln.rstrip() for ln in old_lines]
for k, ln in enumerate(old_lines):
if ln[:9] == "LIBRARIES" and hasattr(self, "LDFLAGS"):
info('change LIBRARIES')
old_lines[k] = "LIBRARIES =\t{}".format(self.LDFLAGS)
if ln[:10] == "NETCDF_LIB" and hasattr(self, "NETCDFLIB"):
info('change NETCDF_LIB')
old_lines[k] = "NETCDF_LIB =\t{}".format(self.NETCDFLIB)
if ln[:10] == "NETCDF_INC" and hasattr(self, "NETCDFINC"):
info('change NETCDF_INC')
old_lines[k] = "NETCDF_INC =\t{}".format(self.NETCDFINC)
with open("{}/sources/Makefile".format(comp_dir), "w") as f:
f.write("\n".join(old_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", "gpu"))
for mode, pref, suff in zip(
["A", "L", "D"], ["a", "tl", "fwd"], ["_ad", "_tl", ""]
):
if not mode in getattr(self, "compile-only"):
continue
info("Compiling CHIMERE {}".format(mode))
info(f"./compile-chimere {compiler} -m {mode} {comp_mode} {comp_clean}")
with open("{}/CHIMERE_compiling_{}.log"
.format(comp_dir, mode), "w") as log:
process = subprocess.Popen(
f"./compile-chimere {compiler} -m "
f"{mode} {comp_mode} {comp_clean}",
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)