Source code for pycif.plugins.transforms.system.array2sampled.adjoint

import numpy as np
import pandas as pd
import xarray as xr
from logging import info, debug


[docs] def adjoint( transform, inout_datastore, controlvect, obsvect, mapper, di, df, mode, runsubdir, workdir, onlyinit=False, **kwargs ): """Scatter observation-space adjoint sensitivities back onto the model grid. The adjoint of :func:`forward`: for each observation, reads the ``'adj_out'`` value from the sparse output DataFrame and adds it to the corresponding ``(tstep, lev, i, j)`` cell of the gridded ``'adj_out'`` array via ``np.add.at`` (atomic accumulation for multiple observations mapping to the same cell). Initialises ``xmod_in["adj_out"]`` as a zero array shaped like ``xmod_in["spec"]`` if not already present. Args: transform (Plugin): array2sampled instance. inout_datastore (dict): mutable datastore; ``'inputs'`` has the gridded arrays, ``'outputs'`` has the observation DataFrame with ``'adj_out'`` column. controlvect: unused. obsvect: unused. mapper (dict): transform mapper. di (datetime): sub-simulation start date. df (datetime): sub-simulation end date. mode (str): ``'adj'``. runsubdir (str): unused. workdir (str): unused. onlyinit (bool): if ``True``, return immediately. **kwargs: unused. """ ddi = min(di, df) for trid_in, trid_out in zip(mapper["inputs"], mapper["outputs"]): xmod_out = inout_datastore["outputs"][trid_out][ddi] t = xmod_out["metadata"]["tstep"].astype(int).values i = xmod_out["metadata"]["i"].astype(int).values j = xmod_out["metadata"]["j"].astype(int).values # Input coordinates nlev = mapper['inputs'][trid_in]['domain'].nlev ntimes = len(mapper['inputs'][trid_in]['input_dates'][ddi]) nlon = mapper['inputs'][trid_in]['domain'].nlon nlat = mapper['inputs'][trid_in]['domain'].nlat # Deal with levels differently if nlev == 1: lev = (0. * i).astype(int) else: lev = xmod_out["metadata"]["level"].astype(int).values # Save metadata for later use transform.metadata = getattr(transform, "metadata", {}) transform.metadata[ddi] = transform.metadata.get(ddi, {}) transform.metadata[ddi][trid_in] = { "tstep": t, "i": i, "j": j, "level": lev, } # Stop here if only init if onlyinit: return xmod_in = xr.Dataset( data_vars={'spec': (("time", "lev", "lat", "lon"), np.zeros((ntimes, nlev, nlat, nlon)))}) if "adj_out" not in xmod_in: xmod_in["adj_out"] = 0 * xmod_in["spec"] data_out = xmod_out[("maindata", "adj_out")].values data_in = xmod_in["adj_out"] np.add.at(data_in.data, (t, lev, i, j), data_out) inout_datastore["inputs"][trid_in][ddi] = xmod_in