|
|
|
@ -5,6 +5,7 @@ from itertools import product
@@ -5,6 +5,7 @@ from itertools import product
|
|
|
|
|
import numpy as n |
|
|
|
|
|
|
|
|
|
from wrf.var.units import do_conversion, check_units |
|
|
|
|
from wrf.var.destagger import destagger |
|
|
|
|
|
|
|
|
|
__all__ = ["convert_units", "handle_left_iter"] |
|
|
|
|
|
|
|
|
@ -59,7 +60,7 @@ def _left_indexes(dims):
@@ -59,7 +60,7 @@ def _left_indexes(dims):
|
|
|
|
|
|
|
|
|
|
def handle_left_iter(alg_out_num_dims, ref_var_expected_dims, ref_var_idx=-1, |
|
|
|
|
ref_var_name=None, alg_out_fixed_dims=(), |
|
|
|
|
ignore_args=(), ignore_kargs={}): |
|
|
|
|
ignore_args=(), ignore_kargs={}, ref_stag_dim=None): |
|
|
|
|
"""Decorator to handle iterating over leftmost dimensions when using |
|
|
|
|
multiple files and/or multiple times. |
|
|
|
|
|
|
|
|
@ -78,18 +79,22 @@ def handle_left_iter(alg_out_num_dims, ref_var_expected_dims, ref_var_idx=-1,
@@ -78,18 +79,22 @@ def handle_left_iter(alg_out_num_dims, ref_var_expected_dims, ref_var_idx=-1,
|
|
|
|
|
directly without any slicing |
|
|
|
|
- ignore_kargs - keys of any keyword arguments which should be passed |
|
|
|
|
directly without slicing |
|
|
|
|
- ref_stag_dim - in some cases the reference variable dimensions |
|
|
|
|
have a staggered dimension that needs to be corrected when calculating |
|
|
|
|
the output dimensions (e.g. avo) |
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
def indexing_decorator(func): |
|
|
|
|
@wraps(func) |
|
|
|
|
def func_wrapper(*args, **kargs): |
|
|
|
|
|
|
|
|
|
if ref_var_idx >= 0: |
|
|
|
|
ref_var = args[ref_var_idx] |
|
|
|
|
else: |
|
|
|
|
ref_var = kargs[ref_var_name] |
|
|
|
|
|
|
|
|
|
ref_var_shape = ref_var.shape |
|
|
|
|
extra_dim_num = len(ref_var_shape) - ref_var_expected_dims |
|
|
|
|
extra_dim_num = ref_var.ndim- ref_var_expected_dims |
|
|
|
|
|
|
|
|
|
# No special left side iteration, return the function result |
|
|
|
|
if (extra_dim_num == 0): |
|
|
|
@ -109,10 +114,13 @@ def handle_left_iter(alg_out_num_dims, ref_var_expected_dims, ref_var_idx=-1,
@@ -109,10 +114,13 @@ def handle_left_iter(alg_out_num_dims, ref_var_expected_dims, ref_var_idx=-1,
|
|
|
|
|
# numerical algorithm has greater dim count than reference, |
|
|
|
|
# Note: user must provide this information to decorator |
|
|
|
|
right_dims = [dim for dim in alg_out_fixed_dims] |
|
|
|
|
neg_start_idx = -(alg_out_num_dims - len(alg_out_fixed_dims)) |
|
|
|
|
right_dims += [ref_var_shape[x] |
|
|
|
|
for x in xrange(-alg_out_num_dims,0,1)] |
|
|
|
|
for x in xrange(neg_start_idx,0,1)] |
|
|
|
|
outdims += right_dims |
|
|
|
|
|
|
|
|
|
if ref_stag_dim is not None: |
|
|
|
|
outdims[ref_stag_dim] -= 1 |
|
|
|
|
|
|
|
|
|
out_inited = False |
|
|
|
|
for left_idxs in _left_indexes(extra_dims): |
|
|
|
@ -121,7 +129,6 @@ def handle_left_iter(alg_out_num_dims, ref_var_expected_dims, ref_var_idx=-1,
@@ -121,7 +129,6 @@ def handle_left_iter(alg_out_num_dims, ref_var_expected_dims, ref_var_idx=-1,
|
|
|
|
|
# the right (e.g. [1,1,:]) |
|
|
|
|
left_and_slice_idxs = ([x for x in left_idxs] + |
|
|
|
|
[slice(None, None, None)]) |
|
|
|
|
|
|
|
|
|
# Slice the args if applicable |
|
|
|
|
new_args = [arg[left_and_slice_idxs] |
|
|
|
|
if i not in ignore_args else arg |
|
|
|
@ -133,7 +140,6 @@ def handle_left_iter(alg_out_num_dims, ref_var_expected_dims, ref_var_idx=-1,
@@ -133,7 +140,6 @@ def handle_left_iter(alg_out_num_dims, ref_var_expected_dims, ref_var_idx=-1,
|
|
|
|
|
if key not in ignore_kargs else val) |
|
|
|
|
for key,val in kargs.iteritems()} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Call the numerical routine |
|
|
|
|
res = func(*new_args, **new_kargs) |
|
|
|
|
|
|
|
|
@ -147,11 +153,93 @@ def handle_left_iter(alg_out_num_dims, ref_var_expected_dims, ref_var_idx=-1,
@@ -147,11 +153,93 @@ def handle_left_iter(alg_out_num_dims, ref_var_expected_dims, ref_var_idx=-1,
|
|
|
|
|
|
|
|
|
|
else: # This should be a list or a tuple (cape) |
|
|
|
|
if not out_inited: |
|
|
|
|
output = [n.zeros(outdims, ref_var.dtype)] |
|
|
|
|
output = [n.zeros(outdims, ref_var.dtype) |
|
|
|
|
for i in xrange(len(res))] |
|
|
|
|
out_inited = True |
|
|
|
|
|
|
|
|
|
for outarr in output: |
|
|
|
|
outarr[left_and_slice_idxs] = res[:] |
|
|
|
|
for i,outarr in enumerate(res): |
|
|
|
|
(output[i])[left_and_slice_idxs] = outarr[:] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return output |
|
|
|
|
|
|
|
|
|
return func_wrapper |
|
|
|
|
|
|
|
|
|
return indexing_decorator |
|
|
|
|
|
|
|
|
|
def uvmet_left_iter(): |
|
|
|
|
"""Decorator to handle iterating over leftmost dimensions when using |
|
|
|
|
multiple files and/or multiple times with the uvmet product. |
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
def indexing_decorator(func): |
|
|
|
|
@wraps(func) |
|
|
|
|
def func_wrapper(*args): |
|
|
|
|
u = args[0] |
|
|
|
|
v = args[1] |
|
|
|
|
lat = args[2] |
|
|
|
|
lon = args[3] |
|
|
|
|
cen_long = args[4] |
|
|
|
|
cone = args[5] |
|
|
|
|
|
|
|
|
|
if u.ndim == lat.ndim: |
|
|
|
|
num_right_dims = 2 |
|
|
|
|
is_3d = False |
|
|
|
|
else: |
|
|
|
|
num_right_dims = 3 |
|
|
|
|
is_3d = True |
|
|
|
|
|
|
|
|
|
is_stag = False |
|
|
|
|
if ((u.shape[-1] != lat.shape[-1]) or |
|
|
|
|
(u.shape[-2] != lat.shape[-2])): |
|
|
|
|
is_stag = True |
|
|
|
|
|
|
|
|
|
if is_3d: |
|
|
|
|
extra_dim_num = u.ndim - 3 |
|
|
|
|
else: |
|
|
|
|
extra_dim_num = u.ndim - 2 |
|
|
|
|
|
|
|
|
|
if is_stag: |
|
|
|
|
u = destagger(u,-1) |
|
|
|
|
v = destagger(v,-2) |
|
|
|
|
|
|
|
|
|
# No special left side iteration, return the function result |
|
|
|
|
if (extra_dim_num == 0): |
|
|
|
|
return func(u,v,lat,lon,cen_long,cone) |
|
|
|
|
|
|
|
|
|
# Start by getting the left-most 'extra' dims |
|
|
|
|
outdims = [u.shape[x] for x in xrange(extra_dim_num)] |
|
|
|
|
extra_dims = list(outdims) # Copy the left-most dims for iteration |
|
|
|
|
|
|
|
|
|
# Append the right-most dimensions |
|
|
|
|
outdims += [2] # For u/v components |
|
|
|
|
|
|
|
|
|
outdims += [u.shape[x] for x in xrange(-num_right_dims,0,1)] |
|
|
|
|
|
|
|
|
|
output = n.zeros(outdims, u.dtype) |
|
|
|
|
|
|
|
|
|
for left_idxs in _left_indexes(extra_dims): |
|
|
|
|
# Make the left indexes plus a single slice object |
|
|
|
|
# The single slice will handle all the dimensions to |
|
|
|
|
# the right (e.g. [1,1,:]) |
|
|
|
|
left_and_slice_idxs = ([x for x in left_idxs] + |
|
|
|
|
[slice(None, None, None)]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
new_u = u[left_and_slice_idxs] |
|
|
|
|
new_v = v[left_and_slice_idxs] |
|
|
|
|
new_lat = lat[left_and_slice_idxs] |
|
|
|
|
new_lon = lon[left_and_slice_idxs] |
|
|
|
|
|
|
|
|
|
# Call the numerical routine |
|
|
|
|
res = func(new_u, new_v, new_lat, new_lon, cen_long, cone) |
|
|
|
|
|
|
|
|
|
# Note: The 2D version will return a 3D array with a 1 length |
|
|
|
|
# dimension. Numpy is unable to broadcast this without |
|
|
|
|
# sqeezing first. |
|
|
|
|
res = n.squeeze(res) |
|
|
|
|
|
|
|
|
|
output[left_and_slice_idxs] = res[:] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return output |
|
|
|
@ -161,3 +249,4 @@ def handle_left_iter(alg_out_num_dims, ref_var_expected_dims, ref_var_idx=-1,
@@ -161,3 +249,4 @@ def handle_left_iter(alg_out_num_dims, ref_var_expected_dims, ref_var_idx=-1,
|
|
|
|
|
return indexing_decorator |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|