Source code for pycif.plugins.transforms.basic.time_interpolation.utils.array.adjoint

import numpy as np
import xarray as xr
import pandas as pd
import copy
from .......utils.parallel import thread
from .......utils.check.errclass import CifError


[docs] def adjoint( ddi, mapper, inout_datastore, outputs, onlyinit, nthreads=1 ): if ddi not in mapper["interpol_indexes"]: return if onlyinit: return # Initializing inputs list_trids = copy.deepcopy(list(mapper["inputs"].keys())) inout_datastore["inputs"] = { trid: {} for trid in list_trids } if not mapper["do_interpolation"][ddi]: if sum(mapper["reorder_periods"][ddi]) != 0: interpol_indexes = mapper["interpol_indexes"][ddi] target_period = list(interpol_indexes.keys())[0] for trid in list_trids: inout_datastore["inputs"][trid][target_period] = \ outputs[trid][ddi] return # Handling output dates trid_ref = list(mapper["inputs"].keys())[0] out_dates = mapper["outputs"][trid_ref]["input_dates"][ddi] if np.size(out_dates) == 0: raise CifError("This should not happen") elif np.size(out_dates) == 1: raise CifError("Output dates should not be single for adjoint interpolation") else: out_dates_start = out_dates["start_date"] out_dates_end = out_dates["end_date"] all_interpol_indexes = mapper["interpol_indexes"][ddi] data_out = outputs[trid_ref][ddi]["adj_out"] for ddtarget in all_interpol_indexes: dates_in = mapper["inputs"][trid_ref]["input_dates"][ddtarget]["start_date"] interpol_indexes = all_interpol_indexes[ddtarget] interpol_indexes.loc[ interpol_indexes["weights"] == 0, "weights"] = 1 # Account for filter on crop dates in_dates = mapper["inputs"][trid_ref]["input_dates"][ddtarget] in_dates_all = pd.DatetimeIndex( in_dates.stack().drop_duplicates().sort_values()) ddi_mask = ( (out_dates_start <= in_dates_all.max()) & (out_dates_end >= in_dates_all.min()) ) target_indexes = np.where(ddi_mask)[0] mesh = np.meshgrid(interpol_indexes["indexes"].astype(int), np.arange(data_out.shape[1]), np.arange(data_out.shape[2]), np.arange(data_out.shape[3]), indexing="ij") # Threading filling of outputs thread_intervals = np.linspace( 0, len(mapper["inputs"]), nthreads + 1 ).astype(int) list_trids = copy.deepcopy(list(mapper["inputs"].keys())) @thread def thread_function(ithread): for itrid in range(thread_intervals[ithread], thread_intervals[ithread + 1]): trid = list_trids[itrid] data_out_tmp = outputs[trid][ddi]["adj_out"] data_in = np.zeros((len(dates_in), *data_out_tmp.shape[1:])) np.add.at( data_in, tuple(mesh), data_out_tmp.values[target_indexes[interpol_indexes.index.values]] * interpol_indexes["weights"].values[ :, np.newaxis, np.newaxis, np.newaxis] ) data_in = \ xr.DataArray(data_in, coords={"time": dates_in}, dims=("time", "lev", "lat", "lon")) if ddtarget not in inout_datastore["inputs"][trid]: inout_datastore["inputs"][trid][ddtarget] = {} if "adj_out" not in inout_datastore["inputs"][trid][ddtarget]: inout_datastore["inputs"][trid][ddtarget]["adj_out"] = \ data_in else: inout_datastore["inputs"][trid][ddtarget]["adj_out"] += \ data_in # Apply threaded function thread_function(range(nthreads))