Source code for pycif.plugins.models.dalecbethy.io.inputs.make_auxiliary

import os
from logging import debug, info

from ......utils import path
from .utils import find_unique_match


# Reference obs.nml defaults, as shipped with the D&B sources (see
# model_sources/dalecbethy/obs.nml); 'synthetic=True' makes D&B compute
# and write out its own pseudo-observations instead of expecting real
# observation files, which is what a pyCIF forward run needs.
# TODO: expose these as proper 'input_arguments' once the intended use of
# the SIF/L-VOD/soil-moisture/slope/FAPAR assimilation streams within CIF
# is decided (presently only NEE is wired as an output, see __init__.py).
_OBS_NML_DEFAULTS = {
    "asssif": ".false.",
    "asslvod": ".false.",
    "asssm": ".false.",
    "assslope": ".false.",
    "assfapar": ".false.",
    "assnee": ".false.",
    "synthetic": ".true.",
    "sifsrc": "'gu'",
    "conv743": "721.056688",
}


[docs] def make_auxiliary(self, ddi, runsubdir, do_simu=True, mode="fwd", **kwargs): """Stage every file D&B's ``runmodel.x`` expects, in ``runsubdir``. D&B hard-wires relative input paths in its Fortran sources (e.g. ``src/prior.f90``: ``input/core-params.csv``; ``src/ncread_forcing.f90``: ``input/staticforcing.nc``, ``input/dynforcing.nc``; ``src/obs.f90``: ``obs.nml``), so this function must reproduce, inside ``runsubdir``, the same layout as the reference D&B checkout (see the ``Jobs``/``Makefile`` "model_input" target for the equivalent shell-level logic): * neither ``runsubdir/input/staticforcing.nc`` nor ``runsubdir/input/dynforcing.nc`` are linked here: both are (re)written per sub-simulation, from the ``("dalecbethy_static", <component>)``/``("meteo", <component>)`` data-store entries, by :func:`~.native2inputs.native2inputs`/ :func:`~.make_forcing.make_static`/:func:`~.make_forcing.make_meteo` (see :func:`pycif.plugins.models.dalecbethy.ini_mapper.ini_mapper`); * link the four prior-parameter CSV files for ``self.domain_name`` (from ``self.parameters_dir``) to ``runsubdir/input/{core,sif,lvod,slope}-params.csv``; * write ``runsubdir/obs.nml`` (see :data:`_OBS_NML_DEFAULTS`); * create the (empty) ``runsubdir/diagout`` directory D&B writes its NetCDF diagnostics to. The compiled executable itself is staged into ``runsubdir`` by :func:`~.run.run`, not here -- ``run.run`` is also what lazily triggers :func:`~.compile.compile` on first use (see the package ``__init__.py`` note on why compilation cannot happen any earlier). Args: self: the dalecbethy model plugin. ddi (datetime.datetime): start date of the present simulation period. runsubdir (str): path to the current sub-simulation work directory. do_simu (bool): if False, the simulation does not need to be run. mode (str): the running mode ('fwd', 'tl', 'adj'). """ if not do_simu: debug("Doing nothing in make_auxiliary as do_simu is False.") return if mode != "fwd": raise NotImplementedError( f"dalecbethy make_auxiliary: mode={mode!r} not implemented yet" ) domain_name = self.domain_name input_dir = os.path.join(runsubdir, "input") os.makedirs(input_dir, exist_ok=True) os.makedirs(os.path.join(runsubdir, "diagout"), exist_ok=True) # --- prior parameter files (D&B's own control vector, src/prior.f90) for kind in ("core", "sif", "lvod", "slope"): _link_unique_match( self.parameters_dir, f"{domain_name}-{kind}-params.csv", os.path.join(input_dir, f"{kind}-params.csv")) # --- namelists (D&B reads these from the run directory root) with open(os.path.join(runsubdir, "obs.nml"), "w") as f: f.write("&obs\n") for key, val in _OBS_NML_DEFAULTS.items(): f.write(f" {key}={val}\n") f.write("/\n") info(f"D&B inputs staged in {runsubdir} for domain '{domain_name}'")
def _link_unique_match(directory, pattern, dest): """Link the single file matching ``pattern`` in ``directory`` to ``dest``.""" path.link(find_unique_match(directory, pattern), dest)