Source code for pycif.plugins.transforms.basic.vertical_interpolation.utils.array.weight

import numpy as np
import pandas as pd
import xarray as xr
import copy


[docs] def weight_fwd(transf, pres_in, pres_out, mode, inout_datastore, trid, ddi, mapper): nlev_in = pres_in.size nlev_out = pres_out.size - 1 xmod = inout_datastore["inputs"] in_thickness = np.abs(np.diff(pres_in)) # Find index of lower interface index_tmplow = \ np.sort(np.unique(np.append(pres_in, pres_out[:-1]))) df_index = pd.Series(range(len(pres_in)), index=pres_in) df_index = df_index.reindex(index_tmplow) low_inside = df_index.interpolate( method="index", limit_area="inside").loc[pres_out[:-1]] df_index = df_index.interpolate( method="index", limit_direction="both") out_index_low = df_index.loc[pres_out[:-1]] # Find index of upper interface index_tmpup = \ np.sort(np.unique(np.append(pres_in, pres_out[1:]))) df_index = \ pd.Series(range(len(pres_in)), index=pres_in) df_index = df_index.reindex(index_tmpup) up_inside = df_index.interpolate( method="index", limit_area="inside").loc[pres_out[1:]] df_index = df_index.interpolate( method="index", limit_direction="both") out_index_up = df_index.loc[pres_out[1:]] # Compute weights for each layer out_thickness = ( np.ceil(out_index_up.values) - np.floor(out_index_low.values)).astype(int) out_thickness[ np.isnan(low_inside).values & np.isnan(up_inside).values] = 0 out_df = pd.DataFrame({"low": out_index_low.values, "up": out_index_up.values, "thickness": out_thickness}) weights = copy.deepcopy( out_df.iloc[ out_df.index.repeat( out_df["thickness"])]) indexes = np.zeros(len(weights)) low_index = np.array( [0] + list(np.cumsum( out_df["thickness"].loc[out_df["thickness"] > 0].values[:-1])) ).astype(int) indexes[low_index] = low_index np.maximum.accumulate(indexes, out=indexes) weights["indexes"] = \ np.arange(len(weights)) - indexes + np.floor(weights["low"]) weights["weights"] = \ np.minimum(weights["indexes"] + 1, weights["up"]) \ - np.maximum(weights["indexes"], weights["low"]) weights["weights"] *= \ in_thickness[weights["indexes"].astype(int)] group_weights = weights["weights"].groupby(by=weights.index).sum() weights["weights"] /= group_weights.loc[weights.index].values # Now apply weights data_id = ["spec"] if mode == "fwd" else ["spec", "incr"] inout_datastore["outputs"][trid][ddi] = {} for did in data_id: if did not in xmod[trid][ddi]: continue var_in = xmod[trid][ddi][did] ntimes, nlev, nlat, nlon = var_in.shape var_out = np.zeros((ntimes, nlev_out, nlat, nlon), dtype=var_in.dtype) mesh_out = np.meshgrid(np.arange(ntimes), weights.index, np.arange(nlat), np.arange(nlon), indexing="ij") mesh_in = np.meshgrid(np.arange(ntimes), weights["indexes"].astype(int), np.arange(nlat), np.arange(nlon), indexing="ij") np.add.at(var_out, tuple(mesh_out), var_in.values[mesh_in[0], mesh_in[1], mesh_in[2], mesh_in[3]] * weights["weights"].values[ np.newaxis, :, np.newaxis, np.newaxis]) inout_datastore["outputs"][trid][ddi][did] = xr.DataArray( var_out, coords={"time": var_in.time}, dims=("time", "lev", "lat", "lon"), )