Source code for pycif.plugins.models.chimere_acc.compile

import os
import subprocess
from shutil import copytree, ignore_patterns, rmtree, copy
from logging import info, debug


[docs] def compile(self): """Compile or copy CHIMERE-ACC executables into the CIF work directory. Two strategies (tried in order): 1. **Copy from pre-compiled cache** — copies ``fwdchimere.e``, ``tlchimere.e``, and ``achimere.e`` from ``self.direxec`` into ``{self.workdir}/model/``. Skipped if ``force-recompile`` is set. 2. **Full recompile** — runs ``make`` inside the CHIMERE-ACC source tree (``self.dirsrc``). Args: self: CHIMERE-ACC model plugin instance with ``workdir``, ``direxec``, and ``dirsrc`` set. """ comp_dir = f"{self.workdir}/model" # Copying the executables try: # If force-recompile = True, return IOError to avoid copying if getattr(self, "force-recompile"): raise IOError # Otherwise, try copying executables for mode, pref, suff in zip( ["A", "L", "D"], ["a", "tl", "fwd"], ["_ad", "_tl", ""] ): if not mode in getattr(self, "compile-only"): continue exe_file = ( f"{self.direxec}/src{suff}/" f"{pref}chimere_{getattr(self, 'gpu-mode')}_" f"{getattr(self, 'optimization-mode').lower()}" f"{'_monitor' if self.monitor else ''}.e" ) copy(exe_file, comp_dir) return except IOError as e: if not getattr(self, "auto-recompile"): raise Exception( f"CHIMERE could not find executables ({self.direxec}) 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"): rmtree(f"{comp_dir}/sources") dir_sources = self.dir_sources if self.dir_sources != "" else self.direxec copytree( dir_sources, f"{comp_dir}/sources", ignore=ignore_patterns("*.a"), ) # Modifying LDFLAGS if needed if hasattr(self, "LDFLAGS") or hasattr(self, "NETCDFLIB") or hasattr(self, "NETCDFINC"): old_lines = open( f"{comp_dir}/sources/Makefile", "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] = f"LIBRARIES =\t{self.LDFLAGS}" if ln[:10] == "NETCDF_LIB" and hasattr(self, "NETCDFLIB"): info('change NETCDF_LIB') old_lines[k] = f"NETCDF_LIB =\t{self.NETCDFLIB}" if ln[:10] == "NETCDF_INC" and hasattr(self, "NETCDFINC"): info('change NETCDF_INC') old_lines[k] = f"NETCDF_INC =\t{self.NETCDFINC}" with open(f"{comp_dir}/sources/Makefile", "w") as f: f.write("\n".join(old_lines)) # Now compiling comp_mode = "" if getattr(self, "optimization-mode") == "PROD" else "--debug" comp_clean = "--clean" if getattr(self, "compile-clean") else "" gpu_mode = f"--{getattr(self, 'gpu-mode')}" monitor = "-monit" if self.monitor else "" compiler = f"--compiler {self.compiler}" for mode, pref, suff in zip( ["A", "L", "D"], ["a", "tl", "fwd"], ["_ad", "_tl", ""] ): if not mode in getattr(self, "compile-only"): continue info(f"Compiling CHIMERE {mode}") info( f"./compile-chimere {gpu_mode} -m {mode} {comp_mode} {comp_clean} {monitor} {compiler}" ) with open(f"{comp_dir}/CHIMERE_compiling_{mode}.log", "w") as log: process = subprocess.Popen( f"./compile-chimere {gpu_mode} -m " f"{mode} {comp_mode} {comp_clean} {monitor} {compiler}", 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/src{suff}/" f"{pref}chimere_{getattr(self, 'gpu-mode')}_" f"{getattr(self, 'optimization-mode').lower()}" f"{'_monitor' if self.monitor else ''}.e" ) 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 target_exe = f"{comp_dir}/{pref}chimere.e" copy(exe_file, target_exe)