Source code for pycif.plugins.transforms.basic.vertical_interpolation.utils.sparse.adjoint

from logging import warning, info
import numpy as np
import copy
from .vcoordfromfile import vcoordfromfile
from .......utils.check.errclass import CifWarning


[docs] def sparse_adjoint(transf, mapper, inout_datastore, ddi, onlyinit, **kwargs): xmod_out = inout_datastore["outputs"] inout_datastore["inputs"] = {} trid_ref = list(xmod_out)[0] if transf.method not in transf.input_arguments["method"]["accepted"]: raise CifWarning(f"The method {transf.method} is not recognized!") if transf.method == "static-levels": # First propagate datastores to inputs for trid in inout_datastore["outputs"]: if trid not in inout_datastore["inputs"]: inout_datastore["inputs"][trid] = {} inout_datastore["inputs"][trid][ddi] = xmod_out[trid][ddi] # if no statlev file or ignore_level, just keep same levels # WARNING: this can be dangerous! file_statlev = transf.file_statlev if file_statlev == "" or transf.ignore_level: info( f"Kept levels as defined in original datastore for {trid_ref}" ) return # Otherwise, fetch levels from pre-defined file levels = vcoordfromfile( inout_datastore["outputs"][trid_ref][ddi], file_statlev, **kwargs ) for trid in inout_datastore["outputs"]: inout_datastore["inputs"][trid][ddi][( "metadata", "level")] = levels return # Extract limited layers if already computed if hasattr(transf, "fwd_weights"): weights = transf.fwd_weights nobs = len(xmod_out[trid_ref][ddi]) for trid_in in inout_datastore["outputs"]: if trid_in not in inout_datastore["inputs"]: inout_datastore["inputs"][trid_in] = {} inout_datastore["inputs"][trid_in][ddi] = \ xmod_out[xmod_out][ddi].iloc[range(nobs)] inout_datastore["inputs"][trid_in][ddi].loc[ :, ("metadata", "level")] = weights["i"] if not onlyinit: inout_datastore["inputs"][trid_in][ddi].loc[ :, ("maindata", "adj_out")] *= weights["wgt"] return # Other methods require the full extraction of the input column # If not already done in previous forward run warning(f"Doing vertical interpolation for {trid_ref} with method '" f"{transf.method}'. \n Need all input levels to be extracted. \n" f"This can be computationally demanding and should be used only once" f" to determine the matching layers, then reused with pre-computed " f"levels") # Reshaping the dataframe to unfold data nobs = len(xmod_out[trid_ref][ddi]) nlev_inputs = mapper["inputs"][trid_ref]["domain"].nlev dlev = np.ones(nobs, dtype=int) * nlev_inputs # Index in the original data of the level-extended dataframe native_inds_main = np.append([0], dlev.cumsum()) # Output index idx = np.zeros((native_inds_main[-1]), dtype=int) idx[native_inds_main[:-1]] = np.arange(nobs) np.maximum.accumulate(idx, out=idx) # Copy output datastore to inputs for trid_in in inout_datastore["outputs"]: inout_datastore["inputs"][trid_in][ddi] = \ copy.deepcopy(xmod_out[trid_ref][ddi].iloc[idx]) inout_datastore["inputs"][trid_in][ddi].loc[:, ("metadata", "level")] = \ np.arange(nobs * nlev_inputs) - idx * nlev_inputs # Propagate adjoint to correct indexes if onlyinit: return