Source code for pycif.plugins.models.lmdz_old.compile
import numpy as np
from pathlib import Path
import os
import subprocess
import shutil
import re
from logging import info, debug
[docs]
def compile(self):
"""Compile or copy LMDZ-old executables into the CIF work directory.
Attempts to copy pre-compiled binaries from ``self.direxec`` first
(skipped if ``force-recompile`` is set), then falls back to running
``make`` inside the LMDZ source tree.
Args:
self: LMDZ-old model plugin instance with ``workdir`` and
``direxec`` (or ``dirsrc``) set.
"""
# Copying the executables
comp_dir = f"{self.workdir}/model/"
try:
# If force-recompile = True, return IOError to avoid copying
if getattr(self, "force-recompile"):
raise IOError
# copying the executable
target = f"{comp_dir}/dispersion.e"
shutil.copy(self.fileexec, target)
# Keep in memory from where the executable was copied
with open(f"{comp_dir}/README", "w") as f:
f.write(f"DISPERSION was copied from: {self.fileexec}")
return
except IOError as e:
if not getattr(self, "auto-recompile"):
raise Exception(
f"LMDZ could not find executables ({self.fileexec}) and was not asked to compile them; specify auto-recompile = True in Yaml to do so"
)
# Otherwise, re-compile
# Copying sources locally; overwrite folder if exists
if os.path.isdir(f"{comp_dir}/sources"):
shutil.rmtree(f"{comp_dir}/sources")
dir_sources = self.dir_sources if self.dir_sources != "" \
else os.path.dirname(self.fileexec)
# Check that the path is consistent with DISPERSION sources
if self.dir_sources != "" and not os.path.isdir(self.dir_sources):
raise Exception(
f"WARNING! Trying to compile DISPERSION from the following non existing "
f"folder: {self.dir_sources}"
)
elif self.dir_sources == "" and not os.path.dirname(self.fileexec):
raise Exception(
f"Warning! Trying to compile DISPERSION from the non-existing "
f"directory {dir_sources}, inferred from fileexec ({self.fileexec}). \n"
f"Please consider forcing a path to the sources with the argument "
f"'dir_sources' in your yml. \n The source path should include the files and "
f"folders: 'compile_dispersion', 'makefile.sef', 'libf', etc."
)
list_sources = os.listdir(dir_sources)
check_files = ["makefile.sed", "libf", "compile_dispersion", "def"]
if not np.all([f in list_sources for f in check_files]):
raise Exception(
f"WARNING! Try to compile DISPERSION from the following path: "
f"{dir_sources}. \n"
f"The path is not consistent with expected source directory. \n"
f"Please consider forcing a path to the sources with the argument "
f"'dir_sources' in your yml\n The source path should include the files and "
f"folders: 'compile_dispersion', 'makefile.sef', 'libf', etc."
)
shutil.copytree(
dir_sources,
f"{comp_dir}/sources",
ignore=shutil.ignore_patterns("*.a"),
)
# Now compile LMDZ
debug("Compiling LMDZ")
domain = self.domain
with open(f"{comp_dir}/LMDZ_compiling.log", "w") as log:
process = subprocess.Popen(
f"./compile_dispersion "
f"-d {domain.nlon - 1}x{domain.nlat - 1}x{domain.nlev} "
f"-p {self.nfilun}x{self.nfilus} "
f"{'-c' if getattr(self, 'compile-clean') else ''} "
f"{'--debug' if getattr(self, 'compile-mode') == 'DEBUG' else ''}"
f"{'--gfortran' if self.compiler == 'gfortran' else ''}",
shell=True,
stdout=log,
cwd=f"{comp_dir}/sources/",
stderr=subprocess.PIPE,
)
_, stderr = process.communicate()
# Print errors if no executable created (or if forced to)
exe_file = f"{comp_dir}/sources/dispersion.e"
if not os.path.isfile(exe_file) \
or getattr(self, "force-compile-stderr"):
debug("LMDZ returned errors during compiling.")
debug("There might be some bugs in the Fortran or in the "
"libraries loaded in the system:")
debug("### START OF LMDZ ERROR MESSAGE ###")
for ln in stderr.decode().split("\n"):
debug(ln)
debug("### END OF LMDZ ERROR MESSAGE ###")
# Copy executable at model root directory
shutil.copy(exe_file, comp_dir)