Source code for pycif.plugins.transforms.basic.vertical_interpolation.utils.sparse.forward
from logging import warning
import numpy as np
import copy
import pandas as pd
from .vcoordfromfile import vcoordfromfile
from .......utils.check.errclass import CifWarning, CifNotImplementedError
[docs]
def sparse_forward(transf, mapper, inout_datastore,
ddi, onlyinit, mode, **kwargs):
# Initialize outputs
xmod_in = inout_datastore["inputs"]
inout_datastore["outputs"] = {
trid: {ddi: {}}
for trid in xmod_in
}
# Stop here if onlyinit
if onlyinit:
return
# Raise error for unrecognized method
if transf.method not in transf.input_arguments["method"]["accepted"]:
raise CifWarning(f"The method {transf.method} is not recognized!")
# Just forward propagation for static-levels
if transf.method == "static-levels":
inout_datastore["outputs"] = {
trid: {ddi: xmod_in[trid][ddi]} for trid in xmod_in
}
return
# Otherwise loop over trids
for trid in xmod_in[trid][ddi]:
raise CifNotImplementedError(
f"Method {transf.method} is not yet implemented for vertical interpolation"
)
# Reshaping the dataframe to unfold data
xmod_out = inout_datastore["outputs"][trid][ddi]
nobs = len(xmod_out)
nlev_inputs = mapper["inputs"][trid]["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)
coord_out = mapper["outputs"][trid].get("coord_out", "height")
spec = xmod_in[trid][ddi][("maindata", "spec")].values.reshape((nobs, -1))
incr = xmod_in[trid][ddi][("maindata", "incr")].values.reshape((nobs, -1))
hthick = xmod_in[("hlay", trid[1])][ddi][
("maindata", "spec")].values.reshape((nobs, -1))
hlay = np.concatenate([
np.zeros((nobs, 1)),
hthick.cumsum(axis=1),
np.inf * np.ones((nobs, 1))
], axis=1)
# Use orography or not
# oro = xmod_in[("oro", trid[1])][ddi][
# ("maindata", "spec")].values.reshape((nobs, -1))
# Find where the data is in the input mesh
alt_low = xmod_out["metadata"]["alt"].values
alt_high = xmod_out["metadata"]["alt"] \
+ xmod_out["metadata"].get("dalt", 0) + 250
alt_high = alt_high.values
alt_mid = 0.5 * (alt_high + alt_low)
levmeshin = np.arange(0, nlev_inputs + 2)
levout_low = np.zeros(nobs)
levout_high = np.zeros(nobs)
levout_mid = np.zeros(nobs)
weights = {"i": [], "wgt": []}
for i in range(nobs):
levout_low[i] = np.interp(alt_low[i], hlay[i], levmeshin)
levout_high[i] = np.interp(alt_high[i], hlay[i], levmeshin)
levout_mid[i] = np.interp(alt_mid[i], hlay[i], levmeshin)
# Compute weights per layers
iout_mid = np.floor(levout_mid).astype(int)
if transf.method == "match-layer":
xmod_out.loc[:, ("metadata", "level")] = iout_mid
xmod_out.loc[:, ("maindata", "spec")] = spec[range(nobs), iout_mid]
if mode == "tl":
xmod_out.loc[:, ("maindata", "incr")] = incr[range(nobs), iout_mid]
weights["i"] = iout_mid
weights["wgt"] = np.ones(nobs)
# elif transf.method == "linear":
# Save weights for later adjoint
transf.fwd_weights = weights
# print(__file__)
# import code
# code.interact(local=dict(locals(), **globals()))