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

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


[docs] def adjoint( transf, ddi, mapper, outputs, inout_datastore, onlyinit, nthreads=1 ): if ddi not in mapper["interpol_indexes"]: return interpol_indexes = mapper["interpol_indexes"][ddi] # Load input and output dates from transform trid_ref = list(mapper["inputs"].keys())[0] in_dates = mapper["inputs"][trid_ref]["input_dates"] out_dates = mapper["outputs"][trid_ref]["input_dates"] if np.size(out_dates[ddi]) == 1: raise CifError("Output dates should not be single for adjoint interpolation") else: out_dates_start = out_dates[ddi]["start_date"] out_dates_end = out_dates[ddi]["end_date"] # Output dates from output datastore ds_out_dates_start = outputs[trid_ref][ddi]["metadata"]["date"] ds_out_dates_end = outputs[trid_ref][ddi]["metadata"]["enddate"] # Initializing inputs inout_datastore["inputs"][trid_ref] = {} # Initialize metadata if not already done transf.metadata = getattr(transf, "metadata", {}) transf.metadata[ddi] = {} # Now loop over target dates for ddtarget in interpol_indexes: # Crop out_dates to the date interval covered by input dates in_dates_all = in_dates[ddtarget].stack().reset_index( drop=True).drop_duplicates() tmp_mask = ( (out_dates_start <= in_dates_all.max()) & (out_dates_end >= in_dates_all.min()) ) # Now manage for redundant dates out_dates_end_tmp = out_dates_end[tmp_mask] out_dates_start_tmp = out_dates_start[tmp_mask] out_dates_tmp = pd.DataFrame( data={'date_start': out_dates_start_tmp, 'date_end': out_dates_end_tmp, 'index': range(len(out_dates_end_tmp))} ) unique_index = out_dates_tmp.drop_duplicates( ['date_start', 'date_end'])['index'].values out_dates_ref = pd.DataFrame( index=pd.MultiIndex.from_frame( out_dates_tmp.iloc[unique_index].loc[:, ['date_start', 'date_end']]), data={'index': unique_index} ) # Find correspondance between reference dates and present datastore ds_tmp_mask = ( (ds_out_dates_start <= in_dates_all.max()) & (ds_out_dates_end >= in_dates_all.min()) ) ds_out_dates_end_tmp = ds_out_dates_end[ds_tmp_mask] ds_out_dates_start_tmp = ds_out_dates_start[ds_tmp_mask] target = pd.MultiIndex.from_frame(pd.DataFrame({ 'date_start': ds_out_dates_start_tmp, 'date_end': ds_out_dates_end_tmp})) out_unique_index = out_dates_ref.loc[target, 'index'].values # Merge outputs with indexes inter_index = copy.deepcopy(interpol_indexes[ddtarget]) iterables = [["interpol_indexes"], inter_index.columns] inter_index.columns = pd.MultiIndex.from_product(iterables) # Threading adjoint propogation nthreads_tmp = min(nthreads, len(mapper["inputs"])) thread_intervals = np.linspace( 0, len(mapper["inputs"]), nthreads_tmp + 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] outputs_tmp = outputs[trid][ddi].loc[ds_tmp_mask] outputs_tmp.loc[:, "target_index"] = np.arange( len(outputs[trid][ddi]) )[ds_tmp_mask] outputs_tmp.index = out_unique_index data_out = pd.merge(outputs_tmp, inter_index, left_index=True, right_index=True) data_out[("metadata", "tstep")] = \ data_out["interpol_indexes"]["indexes"].values.astype(int) data_out[("metadata", "dtstep")] = 1 # Put new data into respective input # for data_id in inout_datastore["inputs"]: # if data_id != trid: # continue inout_datastore["inputs"][trid][ddtarget] = \ data_out wgt = data_out.loc[:, [ ("interpol_indexes", "weights"), ("target_index", "")]] del inout_datastore["inputs"][trid][ddtarget]["interpol_indexes"] # Update metadata for later forward run transf.metadata[ddi][ddtarget] = { "weights": wgt, "target_mask": ds_tmp_mask } # Stop here if only init if onlyinit: continue inout_datastore["inputs"][trid][ ddtarget].loc[:, ("maindata", "adj_out")] *= \ wgt.loc[:, ("interpol_indexes", "weights")].values # Apply threaded function thread_function(range(nthreads_tmp))