forked from 3rdparty/wrf-python
				
			
				 37 changed files with 1764 additions and 989 deletions
			
			
		@ -0,0 +1,182 @@
				@@ -0,0 +1,182 @@
					 | 
				
			||||
from __future__ import (absolute_import, division, print_function,  | 
				
			||||
                        unicode_literals) | 
				
			||||
 | 
				
			||||
from math import floor, ceil | 
				
			||||
 | 
				
			||||
import numpy as np | 
				
			||||
 | 
				
			||||
from .extension import interp2dxy | 
				
			||||
 | 
				
			||||
__all__ = ["to_positive_idxs", "calc_xy", "get_xy_z_params", "get_xy"] | 
				
			||||
 | 
				
			||||
def to_positive_idxs(shape, coord): | 
				
			||||
    if (coord[-2] >= 0 and coord[-1] >= 0): | 
				
			||||
        return coord | 
				
			||||
     | 
				
			||||
    return [x if (x >= 0) else shape[i]+x for (i,x) in enumerate(coord) ] | 
				
			||||
 | 
				
			||||
def calc_xy(xdim, ydim, pivot_point=None, angle=None,  | 
				
			||||
           start_point=None, end_point=None): | 
				
			||||
    """Returns the x,y points for the horizontal cross section line. | 
				
			||||
     | 
				
			||||
    xdim - maximum x-dimension | 
				
			||||
    ydim - maximum y-dimension | 
				
			||||
    pivot_point - a pivot point of (south_north, west_east)  | 
				
			||||
                  (must be used with angle) | 
				
			||||
    angle - the angle through the pivot point in degrees | 
				
			||||
    start_point - a start_point sequence of [south_north1, west_east1] | 
				
			||||
    end_point - an end point sequence of [south_north2, west_east2] | 
				
			||||
     | 
				
			||||
    """  | 
				
			||||
     | 
				
			||||
    # Have a pivot point with an angle to find cross section | 
				
			||||
    if pivot_point is not None and angle is not None: | 
				
			||||
        xp = pivot_point[-1] | 
				
			||||
        yp = pivot_point[-2] | 
				
			||||
         | 
				
			||||
        if (angle > 315.0 or angle < 45.0  | 
				
			||||
            or ((angle > 135.0) and (angle < 225.0))): | 
				
			||||
             | 
				
			||||
            #x = y*slope + intercept | 
				
			||||
            slope = -(360.-angle)/45. | 
				
			||||
            if( angle < 45. ): | 
				
			||||
                slope = angle/45. | 
				
			||||
            if( angle > 135.): | 
				
			||||
                slope = (angle-180.)/45. | 
				
			||||
             | 
				
			||||
            intercept = xp - yp*slope | 
				
			||||
             | 
				
			||||
            # find intersections with domain boundaries | 
				
			||||
            y0 = 0. | 
				
			||||
            x0 = y0*slope + intercept | 
				
			||||
             | 
				
			||||
            if( x0 < 0.):  # intersect outside of left boundary | 
				
			||||
                x0 = 0. | 
				
			||||
                y0 =  (x0 - intercept)/slope | 
				
			||||
            if( x0 > xdim-1):  #intersect outside of right boundary | 
				
			||||
                x0 = xdim-1 | 
				
			||||
                y0 =  (x0 - intercept)/slope | 
				
			||||
            y1 = ydim-1.  #need to make sure this will be a float? | 
				
			||||
            x1 = y1*slope + intercept | 
				
			||||
             | 
				
			||||
            if( x1 < 0.):  # intersect outside of left boundary | 
				
			||||
                x1 = 0. | 
				
			||||
                y1 =  (x1 - intercept)/slope | 
				
			||||
             | 
				
			||||
            if( x1 > xdim-1):  # intersect outside of right boundary | 
				
			||||
                x1 = xdim-1 | 
				
			||||
                y1 =  (x1 - intercept)/slope | 
				
			||||
        else: | 
				
			||||
            #  y = x*slope + intercept | 
				
			||||
            slope = (90.-angle)/45. | 
				
			||||
            if( angle > 225. ): | 
				
			||||
                slope = (270.-angle)/45. | 
				
			||||
            intercept = yp - xp*slope | 
				
			||||
 | 
				
			||||
            #find intersections with domain boundaries | 
				
			||||
            x0 = 0. | 
				
			||||
            y0 = x0*slope + intercept | 
				
			||||
             | 
				
			||||
            if( y0 < 0.):  # intersect outside of bottom boundary | 
				
			||||
                y0 = 0. | 
				
			||||
                x0 =  (y0 - intercept)/slope | 
				
			||||
             | 
				
			||||
            if( y0 > ydim-1):  # intersect outside of top boundary | 
				
			||||
                y0 = ydim-1 | 
				
			||||
                x0 =  (y0 - intercept)/slope | 
				
			||||
             | 
				
			||||
            x1 = xdim-1.  #  need to make sure this will be a float? | 
				
			||||
            y1 = x1*slope + intercept | 
				
			||||
             | 
				
			||||
            if( y1 < 0.):  # intersect outside of bottom boundary | 
				
			||||
                y1 = 0. | 
				
			||||
                x1 =  (y1 - intercept)/slope | 
				
			||||
             | 
				
			||||
            if( y1 > ydim-1):# intersect outside of top boundary | 
				
			||||
                y1 = ydim-1 | 
				
			||||
                x1 =  (y1 - intercept)/slope | 
				
			||||
    elif start_point is not None and end_point is not None: | 
				
			||||
        x0 = start_point[-1] | 
				
			||||
        y0 = start_point[-2] | 
				
			||||
        x1 = end_point[-1] | 
				
			||||
        y1 = end_point[-2] | 
				
			||||
        if ( x1 > xdim-1 ):  | 
				
			||||
            x1 = xdim | 
				
			||||
        if ( y1 > ydim-1):  | 
				
			||||
            y1 = ydim | 
				
			||||
    else: | 
				
			||||
        raise ValueError("invalid start/end or pivot/angle arguments") | 
				
			||||
     | 
				
			||||
    dx = x1 - x0 | 
				
			||||
    dy = y1 - y0 | 
				
			||||
    distance = (dx*dx + dy*dy)**0.5 | 
				
			||||
    npts = int(distance) | 
				
			||||
    dxy = distance/npts | 
				
			||||
     | 
				
			||||
    xy = np.zeros((npts,2), "float") | 
				
			||||
 | 
				
			||||
    dx = dx/npts | 
				
			||||
    dy = dy/npts | 
				
			||||
     | 
				
			||||
    for i in xrange(npts): | 
				
			||||
        xy[i,0] = x0 + i*dx | 
				
			||||
        xy[i,1] = y0 + i*dy | 
				
			||||
         | 
				
			||||
    return xy | 
				
			||||
 | 
				
			||||
def get_xy_z_params(z, pivot_point=None, angle=None, | 
				
			||||
                    start_point=None, end_point=None): | 
				
			||||
     | 
				
			||||
    xy = get_xy(z, pivot_point, angle, start_point, end_point) | 
				
			||||
     | 
				
			||||
    # Interp z | 
				
			||||
    var2dz = interp2dxy(z, xy) | 
				
			||||
     | 
				
			||||
    extra_dim_num = z.ndim - 3 | 
				
			||||
    idx1 = tuple([0]*extra_dim_num + [0,0]) | 
				
			||||
    idx2 = tuple([0]*extra_dim_num + [-1,0]) | 
				
			||||
     | 
				
			||||
    #  interp to constant z grid | 
				
			||||
    if(var2dz[idx1] > var2dz[idx2]):  # monotonically decreasing coordinate | 
				
			||||
        z_max = floor(np.amax(z) / 10) * 10     # bottom value | 
				
			||||
        z_min = ceil(np.amin(z) / 10) * 10      # top value | 
				
			||||
        dz = 10 | 
				
			||||
        nlevels = int((z_max-z_min) / dz) | 
				
			||||
        z_var2d = np.zeros((nlevels), dtype=z.dtype) | 
				
			||||
        z_var2d[0] = z_max | 
				
			||||
        dz = -dz | 
				
			||||
    else: | 
				
			||||
        z_max = np.amax(z) | 
				
			||||
        z_min = 0. | 
				
			||||
        dz = 0.01 * z_max | 
				
			||||
        nlevels = int(z_max / dz) | 
				
			||||
        z_var2d = np.zeros((nlevels), dtype=z.dtype) | 
				
			||||
        z_var2d[0] = z_min | 
				
			||||
     | 
				
			||||
    for i in xrange(1,nlevels): | 
				
			||||
        z_var2d[i] = z_var2d[0] + i*dz | 
				
			||||
         | 
				
			||||
    return xy, var2dz, z_var2d | 
				
			||||
 | 
				
			||||
def get_xy(var, pivot_point=None, angle=None, start_point=None, end_point=None): | 
				
			||||
    if pivot_point is not None: | 
				
			||||
        pos_pivot = to_positive_idxs(var.shape[-2:], pivot_point) | 
				
			||||
    else: | 
				
			||||
        pos_pivot = pivot_point | 
				
			||||
         | 
				
			||||
    if start_point is not None: | 
				
			||||
        pos_start = to_positive_idxs(var.shape[-2:], start_point) | 
				
			||||
    else: | 
				
			||||
        pos_start = start_point | 
				
			||||
     | 
				
			||||
    if end_point is not None: | 
				
			||||
        pos_end = to_positive_idxs(var.shape[-2:], end_point) | 
				
			||||
    else: | 
				
			||||
        pos_end = start_point    | 
				
			||||
         | 
				
			||||
    xdim = var.shape[-1] | 
				
			||||
    ydim = var.shape[-2] | 
				
			||||
     | 
				
			||||
    xy = calc_xy(xdim, ydim, pos_pivot, angle, pos_start, pos_end) | 
				
			||||
     | 
				
			||||
    return xy | 
				
			||||
@ -0,0 +1,695 @@
				@@ -0,0 +1,695 @@
					 | 
				
			||||
from __future__ import (absolute_import, division, print_function,  | 
				
			||||
                        unicode_literals) | 
				
			||||
import wrapt  | 
				
			||||
from collections import OrderedDict | 
				
			||||
 | 
				
			||||
import numpy as np | 
				
			||||
import numpy.ma as ma | 
				
			||||
 | 
				
			||||
 | 
				
			||||
from .util import (viewkeys, viewitems, extract_vars,  | 
				
			||||
                   combine_with, either, from_args, arg_location, | 
				
			||||
                   _is_coord_var, XYCoord, npvalues) | 
				
			||||
from .interputils import get_xy_z_params, get_xy | 
				
			||||
from .config import xarray_enabled | 
				
			||||
 | 
				
			||||
if xarray_enabled(): | 
				
			||||
    from xarray import DataArray | 
				
			||||
     | 
				
			||||
__all__ = ["copy_and_set_metadata", "set_wind_metadata", | 
				
			||||
           "set_latlon_metadata", "set_height_metadata", | 
				
			||||
           "set_interp_metadata"] | 
				
			||||
 | 
				
			||||
def copy_and_set_metadata(copy_varname=None, delete_attrs=None, name=None, | 
				
			||||
                          remove_dims=None, dimnames=None,  | 
				
			||||
                          coords=None, **fixed_attrs): | 
				
			||||
    """Decorator to set the metadata for a WRF method. | 
				
			||||
     | 
				
			||||
    A cache is inserted/updated to include the extracted variable that will  | 
				
			||||
    have its metadata copied. This prevents the variable being extracted more  | 
				
			||||
    than once.  This extraction can be slow with sequences of large files. | 
				
			||||
     | 
				
			||||
    """ | 
				
			||||
    @wrapt.decorator | 
				
			||||
    def func_wrapper(wrapped, instance, args, kwargs): | 
				
			||||
        if not xarray_enabled(): | 
				
			||||
            return wrapped(*args, **kwargs) | 
				
			||||
         | 
				
			||||
        argvars = from_args(wrapped, ("wrfnc", "timeidx", "method",  | 
				
			||||
                                      "squeeze", "cache", "units"),  | 
				
			||||
                            *args, **kwargs) | 
				
			||||
        wrfnc = argvars["wrfnc"] | 
				
			||||
        timeidx = argvars["timeidx"] | 
				
			||||
        units = argvars["units"] | 
				
			||||
        method = argvars["method"] | 
				
			||||
        squeeze = argvars["squeeze"] | 
				
			||||
        cache = argvars["cache"] | 
				
			||||
        if cache is None: | 
				
			||||
            cache = {} | 
				
			||||
         | 
				
			||||
        # Note:  can't modify nonlocal var | 
				
			||||
        if (callable(copy_varname)): | 
				
			||||
            _copy_varname = copy_varname(wrfnc) | 
				
			||||
        else: | 
				
			||||
            _copy_varname = copy_varname | 
				
			||||
         | 
				
			||||
        # Extract the copy_from argument | 
				
			||||
        var_to_copy = None if cache is None else cache.get(_copy_varname,  | 
				
			||||
                                                           None) | 
				
			||||
 | 
				
			||||
             | 
				
			||||
        if var_to_copy is None: | 
				
			||||
            var_to_copy = extract_vars(wrfnc, timeidx, (_copy_varname,),  | 
				
			||||
                                       method, squeeze, cache, | 
				
			||||
                                       nometa=False)[_copy_varname] | 
				
			||||
         | 
				
			||||
        # Make a copy so we don't modify a user supplied cache | 
				
			||||
        new_cache = dict(cache)  | 
				
			||||
        new_cache[_copy_varname] = var_to_copy | 
				
			||||
         | 
				
			||||
        # Don't modify the original args/kargs.  The args need to be a list | 
				
			||||
        # so it can be modified. | 
				
			||||
        new_args, cache_argloc = arg_location(wrapped, "cache", args, kwargs) | 
				
			||||
        new_args[cache_argloc] = new_cache | 
				
			||||
         | 
				
			||||
        result = wrapped(*new_args) | 
				
			||||
         | 
				
			||||
        outname = "" | 
				
			||||
        outdimnames = list() | 
				
			||||
        outcoords = OrderedDict() | 
				
			||||
        outattrs = OrderedDict() | 
				
			||||
         | 
				
			||||
        if copy_varname is not None: | 
				
			||||
            outname = unicode(var_to_copy.name) | 
				
			||||
             | 
				
			||||
            if dimnames is not None: | 
				
			||||
                if isinstance(dimnames, combine_with): | 
				
			||||
                    outdimnames, outcoords = dimnames(var_to_copy) | 
				
			||||
                else: | 
				
			||||
                    outdimnames = dimnames | 
				
			||||
                    outcoords = coords | 
				
			||||
            else: | 
				
			||||
                outdimnames += var_to_copy.dims | 
				
			||||
                outcoords.update(var_to_copy.coords) | 
				
			||||
             | 
				
			||||
            outattrs.update(var_to_copy.attrs) | 
				
			||||
             | 
				
			||||
            if remove_dims is not None: | 
				
			||||
                for dimname in remove_dims: | 
				
			||||
                    outdimnames.remove(dimname) | 
				
			||||
                     | 
				
			||||
                    try: | 
				
			||||
                        del outcoords[dimname] | 
				
			||||
                    except KeyError: | 
				
			||||
                        pass | 
				
			||||
                      | 
				
			||||
         | 
				
			||||
        if name is not None: | 
				
			||||
            outname = name | 
				
			||||
         | 
				
			||||
        if units is not None: | 
				
			||||
            outattrs["units"] = units | 
				
			||||
             | 
				
			||||
        for argname, val in viewitems(fixed_attrs): | 
				
			||||
            outattrs[argname] = val | 
				
			||||
         | 
				
			||||
        if delete_attrs is not None: | 
				
			||||
            for attr in delete_attrs: | 
				
			||||
                try: | 
				
			||||
                    del outattrs[attr] | 
				
			||||
                except KeyError: | 
				
			||||
                    pass | 
				
			||||
                 | 
				
			||||
        if isinstance(result, ma.MaskedArray): | 
				
			||||
            outattrs["_FillValue"] = result.fill_value | 
				
			||||
            outattrs["missing_value"] = result.fill_value | 
				
			||||
         | 
				
			||||
        return DataArray(result, name=outname, coords=outcoords,  | 
				
			||||
                       dims=outdimnames, attrs=outattrs) | 
				
			||||
     | 
				
			||||
    return func_wrapper | 
				
			||||
 | 
				
			||||
 | 
				
			||||
def set_wind_metadata(copy_varname, name, description,  | 
				
			||||
                      wind_ncvar=False,  | 
				
			||||
                      two_d=False, wspd_wdir=False): | 
				
			||||
    @wrapt.decorator | 
				
			||||
    def func_wrapper(wrapped, instance, args, kwargs): | 
				
			||||
        if not xarray_enabled(): | 
				
			||||
            return wrapped(*args, **kwargs) | 
				
			||||
         | 
				
			||||
        argvars = from_args(wrapped, ("wrfnc", "timeidx", "units",  | 
				
			||||
                                      "method", "squeeze", "ten_m", "cache"),  | 
				
			||||
                          *args, **kwargs) | 
				
			||||
        wrfnc = argvars["wrfnc"] | 
				
			||||
        timeidx = argvars["timeidx"] | 
				
			||||
        units = argvars["units"] | 
				
			||||
        method = argvars["method"] | 
				
			||||
        squeeze = argvars["squeeze"] | 
				
			||||
        ten_m = argvars["ten_m"] | 
				
			||||
        cache = argvars["cache"] | 
				
			||||
        if cache is None: | 
				
			||||
            cache = {} | 
				
			||||
         | 
				
			||||
        if isinstance(copy_varname, either): | 
				
			||||
            _copy_varname = copy_varname(wrfnc) | 
				
			||||
        else: | 
				
			||||
            _copy_varname = copy_varname | 
				
			||||
         | 
				
			||||
        copy_var = extract_vars(wrfnc, timeidx, _copy_varname,  | 
				
			||||
                                method, squeeze, cache,  | 
				
			||||
                                nometa=False)[_copy_varname] | 
				
			||||
         | 
				
			||||
        # Make a copy so we don't modify a user supplied cache | 
				
			||||
        new_cache = dict(cache)  | 
				
			||||
        new_cache[_copy_varname] = copy_var | 
				
			||||
         | 
				
			||||
        # Don't modify the original args/kargs.  The args need to be a list | 
				
			||||
        # so it can be modified. | 
				
			||||
        new_args, cache_argloc = arg_location(wrapped, "cache", args, kwargs) | 
				
			||||
        new_args[cache_argloc] = new_cache | 
				
			||||
         | 
				
			||||
        result = wrapped(*new_args) | 
				
			||||
         | 
				
			||||
        outcoords = OrderedDict() | 
				
			||||
        outattrs = OrderedDict() | 
				
			||||
         | 
				
			||||
        outdimnames = list(copy_var.dims) | 
				
			||||
        outcoords.update(copy_var.coords) | 
				
			||||
        outattrs.update(copy_var.attrs) | 
				
			||||
         | 
				
			||||
        if wind_ncvar: | 
				
			||||
            pass | 
				
			||||
         | 
				
			||||
        elif not wspd_wdir: | 
				
			||||
            if not two_d: | 
				
			||||
                outdimnames.insert(-3, "u_v") | 
				
			||||
            else: | 
				
			||||
                outdimnames.insert(-2, "u_v") | 
				
			||||
                outattrs["MemoryOrder"] = "XY" | 
				
			||||
            outcoords["u_v"] = ["u", "v"] | 
				
			||||
        else: | 
				
			||||
            if not two_d: | 
				
			||||
                outdimnames.insert(-3, "wspd_wdir") | 
				
			||||
            else: | 
				
			||||
                outdimnames.insert(-2, "wspd_wdir") | 
				
			||||
                outattrs["MemoryOrder"] = "XY" | 
				
			||||
                 | 
				
			||||
            outcoords["wspd_wdir"] = ["wspd", "wdir"] | 
				
			||||
         | 
				
			||||
        if units is not None:  | 
				
			||||
            outattrs["units"] = units | 
				
			||||
             | 
				
			||||
        outname = name | 
				
			||||
        outattrs["description"] = description | 
				
			||||
         | 
				
			||||
        return DataArray(result, name=outname, coords=outcoords,  | 
				
			||||
                       dims=outdimnames, attrs=outattrs) | 
				
			||||
         | 
				
			||||
    return func_wrapper | 
				
			||||
 | 
				
			||||
def set_latlon_metadata(ij=False): | 
				
			||||
    @wrapt.decorator | 
				
			||||
    def func_wrapper(wrapped, instance, args, kwargs): | 
				
			||||
        if not xarray_enabled(): | 
				
			||||
            return wrapped(*args, **kwargs) | 
				
			||||
         | 
				
			||||
        res = wrapped(*args, **kwargs) | 
				
			||||
         | 
				
			||||
        argnames = ("latitude", "longitude") if not ij else ("i", "j") | 
				
			||||
        outname = "latlon" if not ij else "ij" | 
				
			||||
         | 
				
			||||
        if res.ndim <= 2: | 
				
			||||
            dimnames = (["lat_lon", "i_j"] if not ij  | 
				
			||||
                        else ["i_j", "lat_lon"]) | 
				
			||||
        else: | 
				
			||||
            dimnames = (["lat_lon", "domain", "i_j"] if not ij  | 
				
			||||
                        else ["i_j", "domain", "lat_lon"]) | 
				
			||||
             | 
				
			||||
         | 
				
			||||
        argvars = from_args(wrapped, argnames, *args, **kwargs) | 
				
			||||
         | 
				
			||||
        var1 = argvars[argnames[0]] | 
				
			||||
        var2 = argvars[argnames[1]] | 
				
			||||
         | 
				
			||||
        arr1 = np.asarray(var1).ravel() | 
				
			||||
        arr2 = np.asarray(var2).ravel() | 
				
			||||
         | 
				
			||||
        coords = {} | 
				
			||||
        coords[dimnames[0]] = [x for x in zip(arr1, arr2)] | 
				
			||||
         | 
				
			||||
        return DataArray(res, name=outname, dims=dimnames, coords=coords) | 
				
			||||
     | 
				
			||||
    return func_wrapper | 
				
			||||
     | 
				
			||||
def set_height_metadata(geopt=False): | 
				
			||||
    @wrapt.decorator | 
				
			||||
    def func_wrapper(wrapped, instance, args, kwargs): | 
				
			||||
        if not xarray_enabled(): | 
				
			||||
            return wrapped(*args, **kwargs) | 
				
			||||
         | 
				
			||||
        argvars = from_args(wrapped, ("wrfnc", "timeidx", "method",  | 
				
			||||
                                    "squeeze", "units", "msl", "cache"),  | 
				
			||||
                          *args, **kwargs) | 
				
			||||
        wrfnc = argvars["wrfnc"] | 
				
			||||
        timeidx = argvars["timeidx"] | 
				
			||||
        units = argvars["units"] | 
				
			||||
        method = argvars["method"] | 
				
			||||
        squeeze = argvars["squeeze"] | 
				
			||||
        msl = argvars["msl"] | 
				
			||||
        cache = argvars["cache"] | 
				
			||||
         | 
				
			||||
        if cache is None: | 
				
			||||
            cache = {} | 
				
			||||
         | 
				
			||||
        # For height, either copy the met_em GHT variable or copy and modify | 
				
			||||
        # pressure (which has the same dims as destaggered height) | 
				
			||||
        ht_metadata_varname = either("P", "GHT")(wrfnc) | 
				
			||||
        ht_var = extract_vars(wrfnc, timeidx, ht_metadata_varname,  | 
				
			||||
                              method, squeeze, cache, nometa=False) | 
				
			||||
        ht_metadata_var = ht_var[ht_metadata_varname] | 
				
			||||
         | 
				
			||||
        # Make a copy so we don't modify a user supplied cache | 
				
			||||
        new_cache = dict(cache)  | 
				
			||||
        new_cache[ht_metadata_varname] = ht_metadata_var | 
				
			||||
         | 
				
			||||
        # Don't modify the original args/kargs.  The args need to be a list | 
				
			||||
        # so it can be modified. | 
				
			||||
        new_args, cache_argloc = arg_location(wrapped, "cache", args, kwargs) | 
				
			||||
        new_args[cache_argloc] = new_cache | 
				
			||||
         | 
				
			||||
        result = wrapped(*new_args) | 
				
			||||
         | 
				
			||||
        outcoords = OrderedDict() | 
				
			||||
        outattrs = OrderedDict() | 
				
			||||
        outdimnames = list(ht_metadata_var.dims) | 
				
			||||
        outcoords.update(ht_metadata_var.coords) | 
				
			||||
        outattrs.update(ht_metadata_var.attrs) | 
				
			||||
         | 
				
			||||
        if geopt: | 
				
			||||
            outname = "geopt" | 
				
			||||
            outattrs["units"] = "m2 s-2" | 
				
			||||
            outattrs["description"] = "full model geopotential" | 
				
			||||
        else: | 
				
			||||
            outname = "height" if msl else "height_agl"  | 
				
			||||
            outattrs["units"] = units | 
				
			||||
            height_type = "MSL" if msl else "AGL" | 
				
			||||
            outattrs["description"] = "model height ({})".format(height_type) | 
				
			||||
         | 
				
			||||
         | 
				
			||||
        return DataArray(result, name=outname,  | 
				
			||||
                         dims=outdimnames, coords=outcoords, attrs=outattrs) | 
				
			||||
    return func_wrapper | 
				
			||||
 | 
				
			||||
def _set_horiz_meta(wrapped, instance, args, kwargs): | 
				
			||||
    argvars = from_args(wrapped, ("field3d", "z", "desiredloc",  | 
				
			||||
                                  "missingval"),  | 
				
			||||
                          *args, **kwargs)   | 
				
			||||
     | 
				
			||||
    field3d = argvars["field3d"] | 
				
			||||
    z = argvars["z"] | 
				
			||||
    desiredloc = argvars["desiredloc"] | 
				
			||||
    missingval = argvars["missingval"] | 
				
			||||
     | 
				
			||||
    result = wrapped(*args, **kwargs) | 
				
			||||
     | 
				
			||||
    # Defaults, in case the data isn't a DataArray | 
				
			||||
    outname = None | 
				
			||||
    outdimnames = None | 
				
			||||
    outcoords = None | 
				
			||||
    outattrs = None | 
				
			||||
     | 
				
			||||
    # Get the vertical level units | 
				
			||||
    vert_units = None | 
				
			||||
    if isinstance(z, DataArray): | 
				
			||||
        vert_units = z.attrs.get("units", None) | 
				
			||||
     | 
				
			||||
    # If we have no metadata to start with, only set the level | 
				
			||||
    levelstr = ("{0} {1}".format(desiredloc, vert_units)  | 
				
			||||
                if vert_units is not None  | 
				
			||||
                else "{0}".format(desiredloc)) | 
				
			||||
     | 
				
			||||
    if isinstance(field3d, DataArray): | 
				
			||||
        outcoords = OrderedDict() | 
				
			||||
        outattrs = OrderedDict() | 
				
			||||
        outdimnames = list(field3d.dims) | 
				
			||||
        outcoords.update(field3d.coords) | 
				
			||||
        outdimnames.remove(field3d.dims[-3]) | 
				
			||||
        del outcoords[field3d.dims[-3]] | 
				
			||||
        outattrs.update(field3d.attrs) | 
				
			||||
        outname = "{0}_{1}".format(field3d.name, levelstr) | 
				
			||||
         | 
				
			||||
    else: | 
				
			||||
        outname = "field3d_{0}".format(levelstr) | 
				
			||||
        outattrs = OrderedDict() | 
				
			||||
         | 
				
			||||
    outattrs["PlotLevelID"] = levelstr | 
				
			||||
    outattrs["missing_value"] = missingval | 
				
			||||
    outattrs["_FillValue"] = missingval | 
				
			||||
     | 
				
			||||
    for key in ("MemoryOrder", "description"): | 
				
			||||
        try: | 
				
			||||
            del outattrs[key] | 
				
			||||
        except KeyError: | 
				
			||||
            pass | 
				
			||||
     | 
				
			||||
    return DataArray(result, name=outname, dims=outdimnames,  | 
				
			||||
                     coords=outcoords, attrs=outattrs) | 
				
			||||
     | 
				
			||||
def _set_cross_meta(wrapped, instance, args, kwargs): | 
				
			||||
    argvars = from_args(wrapped, ("field3d", "z", "missingval",  | 
				
			||||
                                  "pivot_point", "angle", | 
				
			||||
                                  "start_point", "end_point", | 
				
			||||
                                  "cache"),  | 
				
			||||
                          *args, **kwargs)   | 
				
			||||
     | 
				
			||||
    field3d = argvars["field3d"] | 
				
			||||
    z = argvars["z"] | 
				
			||||
    missingval = argvars["missingval"] | 
				
			||||
    pivot_point = argvars["pivot_point"] | 
				
			||||
    angle = argvars["angle"] | 
				
			||||
    start_point = argvars["start_point"] | 
				
			||||
    end_point = argvars["end_point"] | 
				
			||||
    cache = argvars["cache"] | 
				
			||||
     | 
				
			||||
    xy, var2dz, z_var2d = get_xy_z_params(npvalues(z), pivot_point, angle, | 
				
			||||
              start_point, end_point) | 
				
			||||
     | 
				
			||||
    # Make a copy so we don't modify a user supplied cache | 
				
			||||
    if cache is not None: | 
				
			||||
        new_cache = dict(cache) | 
				
			||||
    else: | 
				
			||||
        new_cache = {} | 
				
			||||
    new_cache["xy"] = xy | 
				
			||||
    new_cache["var2dz"] = var2dz | 
				
			||||
    new_cache["z_var2d"] = z_var2d | 
				
			||||
     | 
				
			||||
    # Don't modify the original args/kargs.  The args need to be a list | 
				
			||||
    # so it can be modified. | 
				
			||||
    new_args, cache_argloc = arg_location(wrapped, "cache", args, kwargs) | 
				
			||||
    new_args[cache_argloc] = new_cache | 
				
			||||
         | 
				
			||||
    result = wrapped(*new_args) | 
				
			||||
     | 
				
			||||
    # Defaults, in case the data isn't a DataArray | 
				
			||||
    outname = None | 
				
			||||
    outdimnames = None | 
				
			||||
    outcoords = None | 
				
			||||
    outattrs = None | 
				
			||||
     | 
				
			||||
    # Use XY to set the cross-section metadata | 
				
			||||
    st_x = xy[0,0] | 
				
			||||
    st_y = xy[0,1] | 
				
			||||
    ed_x = xy[-1,0] | 
				
			||||
    ed_y = xy[-1,1] | 
				
			||||
     | 
				
			||||
    cross_str = "cross-section: ({0}, {1}) to ({2}, {3})".format(st_x, st_y,  | 
				
			||||
                                                               ed_x, ed_y) | 
				
			||||
    if angle is not None: | 
				
			||||
        cross_str += " ; center={0} ; angle={1}".format(pivot_point, | 
				
			||||
                                                        angle) | 
				
			||||
     | 
				
			||||
    if isinstance(field3d, DataArray): | 
				
			||||
        outcoords = OrderedDict() | 
				
			||||
        outattrs = OrderedDict() | 
				
			||||
        outdimnames = list(field3d.dims) | 
				
			||||
        outcoords.update(field3d.coords) | 
				
			||||
        for i in xrange(-3,0,1): | 
				
			||||
            outdimnames.remove(field3d.dims[i]) | 
				
			||||
            del outcoords[field3d.dims[i]] | 
				
			||||
         | 
				
			||||
         | 
				
			||||
        # Delete any lat,lon coords | 
				
			||||
        for key in viewkeys(outcoords): | 
				
			||||
            if _is_coord_var(key): | 
				
			||||
                del outcoords[key] | 
				
			||||
         | 
				
			||||
        outdimnames.append("vertical") | 
				
			||||
        outdimnames.append("xy") | 
				
			||||
        outattrs.update(field3d.attrs) | 
				
			||||
         | 
				
			||||
        outname = "{0}_cross".format(field3d.name) | 
				
			||||
         | 
				
			||||
        for key in ("MemoryOrder",): | 
				
			||||
            try: | 
				
			||||
                del outattrs[key] | 
				
			||||
            except KeyError: | 
				
			||||
                pass | 
				
			||||
             | 
				
			||||
        outcoords["xy"] = [XYCoord(xy[i,0], xy[i,1])  | 
				
			||||
                           for i in xrange(xy.shape[-2])] | 
				
			||||
         | 
				
			||||
        outcoords["vertical"] = z_var2d[:] | 
				
			||||
         | 
				
			||||
    else: | 
				
			||||
        outname = "field3d_cross" | 
				
			||||
        outattrs = OrderedDict() | 
				
			||||
     | 
				
			||||
    outattrs["orientation"] = cross_str | 
				
			||||
    outattrs["missing_value"] = missingval | 
				
			||||
    outattrs["_FillValue"] = missingval | 
				
			||||
     | 
				
			||||
    return DataArray(result, name=outname, dims=outdimnames,  | 
				
			||||
                     coords=outcoords, attrs=outattrs)   | 
				
			||||
     | 
				
			||||
     | 
				
			||||
 | 
				
			||||
def _set_line_meta(wrapped, instance, args, kwargs): | 
				
			||||
    argvars = from_args(wrapped, ("field2d", "pivot_point", "angle", | 
				
			||||
                                  "start_point", "end_point", "cache"),  | 
				
			||||
                          *args, **kwargs)   | 
				
			||||
     | 
				
			||||
    field2d = argvars["field2d"] | 
				
			||||
    pivot_point = argvars["pivot_point"] | 
				
			||||
    angle = argvars["angle"] | 
				
			||||
    start_point = argvars["start_point"] | 
				
			||||
    end_point = argvars["end_point"] | 
				
			||||
    cache = argvars["cache"] | 
				
			||||
     | 
				
			||||
    if cache is None: | 
				
			||||
        cache = {} | 
				
			||||
     | 
				
			||||
    xy = get_xy(field2d, pivot_point, angle, start_point, end_point) | 
				
			||||
     | 
				
			||||
    # Make a copy so we don't modify a user supplied cache | 
				
			||||
    new_cache = dict(cache)  | 
				
			||||
    new_cache["xy"] = xy | 
				
			||||
     | 
				
			||||
    # Don't modify the original args/kargs.  The args need to be a list | 
				
			||||
    # so it can be modified. | 
				
			||||
    new_args, cache_argloc = arg_location(wrapped, "cache", args, kwargs) | 
				
			||||
    new_args[cache_argloc] = new_cache | 
				
			||||
         | 
				
			||||
    result = wrapped(*new_args) | 
				
			||||
     | 
				
			||||
    # Defaults, in case the data isn't a DataArray | 
				
			||||
    outname = None | 
				
			||||
    outdimnames = None | 
				
			||||
    outcoords = None | 
				
			||||
    outattrs = None | 
				
			||||
     | 
				
			||||
    # Use XY to set the cross-section metadata | 
				
			||||
    st_x = xy[0,0] | 
				
			||||
    st_y = xy[0,1] | 
				
			||||
    ed_x = xy[-1,0] | 
				
			||||
    ed_y = xy[-1,1] | 
				
			||||
     | 
				
			||||
    cross_str = "({0}, {1}) to ({2}, {3})".format(st_x, st_y,  | 
				
			||||
                                                ed_x, ed_y) | 
				
			||||
    if angle is not None: | 
				
			||||
        cross_str += " ; center={0} ; angle={1}".format(pivot_point, | 
				
			||||
                                                        angle) | 
				
			||||
     | 
				
			||||
    if isinstance(field2d, DataArray): | 
				
			||||
        outcoords = OrderedDict() | 
				
			||||
        outattrs = OrderedDict() | 
				
			||||
        outdimnames = list(field2d.dims) | 
				
			||||
        outcoords.update(field2d.coords) | 
				
			||||
        for i in xrange(-2,0,1): | 
				
			||||
            outdimnames.remove(field2d.dims[i]) | 
				
			||||
            del outcoords[field2d.dims[i]] | 
				
			||||
             | 
				
			||||
        # Delete any lat,lon coords | 
				
			||||
        for key in viewkeys(outcoords): | 
				
			||||
            if _is_coord_var(key): | 
				
			||||
                del outcoords[key] | 
				
			||||
         | 
				
			||||
        outdimnames.append("xy") | 
				
			||||
        outattrs.update(field2d.attrs) | 
				
			||||
         | 
				
			||||
        outname = "{0}_line".format(field2d.name) | 
				
			||||
         | 
				
			||||
        for key in ("MemoryOrder",): | 
				
			||||
            try: | 
				
			||||
                del outattrs[key] | 
				
			||||
            except KeyError: | 
				
			||||
                pass | 
				
			||||
             | 
				
			||||
        outcoords["xy"] = [XYCoord(xy[i,0], xy[i,1])  | 
				
			||||
                           for i in xrange(xy.shape[-2])] | 
				
			||||
         | 
				
			||||
    else: | 
				
			||||
        outname = "field2d_line" | 
				
			||||
        outattrs = OrderedDict() | 
				
			||||
     | 
				
			||||
    outattrs["orientation"] = cross_str | 
				
			||||
     | 
				
			||||
    return DataArray(result, name=outname, dims=outdimnames,  | 
				
			||||
                     coords=outcoords, attrs=outattrs)  | 
				
			||||
     | 
				
			||||
 | 
				
			||||
def _set_vinterp_meta(wrapped, instance, args, kwargs): | 
				
			||||
    argvars = from_args(wrapped, ("wrfnc", "field", "vert_coord",  | 
				
			||||
                                  "interp_levels", "extrapolate", | 
				
			||||
                                  "field_type", "log_p", | 
				
			||||
                                  "timeidx", "method", "squeeze", | 
				
			||||
                                  "cache"),  | 
				
			||||
                          *args, **kwargs)   | 
				
			||||
     | 
				
			||||
    field = argvars["field"] | 
				
			||||
    vert_coord = argvars["vert_coord"] | 
				
			||||
    interp_levels = argvars["interp_levels"] | 
				
			||||
    field_type = argvars["field_type"] | 
				
			||||
     | 
				
			||||
    result = wrapped(*args, **kwargs) | 
				
			||||
     | 
				
			||||
    # Defaults, in case the data isn't a DataArray | 
				
			||||
    outname = None | 
				
			||||
    outdimnames = None | 
				
			||||
    outcoords = None | 
				
			||||
    outattrs = None | 
				
			||||
     | 
				
			||||
     | 
				
			||||
    if isinstance(field, DataArray): | 
				
			||||
        outcoords = OrderedDict() | 
				
			||||
        outattrs = OrderedDict() | 
				
			||||
        outdimnames = list(field.dims) | 
				
			||||
        outcoords.update(field.coords) | 
				
			||||
         | 
				
			||||
        outdimnames.remove(field.dims[-3]) | 
				
			||||
        del outcoords[field.dims[-3]] | 
				
			||||
         | 
				
			||||
        outdimnames.insert(-2, "interp_level") | 
				
			||||
        outcoords["interp_level"] = interp_levels | 
				
			||||
        outattrs.update(field.attrs) | 
				
			||||
        outattrs["vert_interp_type"] = vert_coord | 
				
			||||
         | 
				
			||||
        outname = field.name | 
				
			||||
         | 
				
			||||
    else: | 
				
			||||
        outname = field_type | 
				
			||||
     | 
				
			||||
     | 
				
			||||
    return DataArray(result, name=outname, dims=outdimnames,  | 
				
			||||
                     coords=outcoords, attrs=outattrs)   | 
				
			||||
       | 
				
			||||
         | 
				
			||||
def _set_2dxy_meta(wrapped, instance, args, kwargs): | 
				
			||||
    argvars = from_args(wrapped, ("field3d", "xy"),  | 
				
			||||
                          *args, **kwargs)   | 
				
			||||
     | 
				
			||||
    field3d = argvars["field3d"] | 
				
			||||
    xy = argvars["xy"] | 
				
			||||
     | 
				
			||||
    result = wrapped(*args, **kwargs) | 
				
			||||
     | 
				
			||||
    # Use XY to set the cross-section metadata | 
				
			||||
    st_x = xy[0,0] | 
				
			||||
    st_y = xy[0,1] | 
				
			||||
    ed_x = xy[-1,0] | 
				
			||||
    ed_y = xy[-1,1] | 
				
			||||
     | 
				
			||||
    cross_str = "({0},{1}) to ({2},{3})".format(st_x, st_y,  | 
				
			||||
                                                ed_x, ed_y) | 
				
			||||
     | 
				
			||||
    # Dims are (...,xy,z) | 
				
			||||
    if isinstance(field3d, DataArray): | 
				
			||||
        outcoords = OrderedDict() | 
				
			||||
        outattrs = OrderedDict() | 
				
			||||
        outdimnames = list(field3d.dims) | 
				
			||||
        outcoords.update(field3d.coords) | 
				
			||||
        for i in xrange(-2,0,1): | 
				
			||||
            outdimnames.remove(field3d.dims[i]) | 
				
			||||
            del outcoords[field3d.dims[i]] | 
				
			||||
         | 
				
			||||
        outdimnames[-2] = "xy" | 
				
			||||
        outattrs.update(field3d.attrs) | 
				
			||||
         | 
				
			||||
        outname = "{0}_xy".format(field3d.name) | 
				
			||||
         | 
				
			||||
        outcoords["xy"] = [XYCoord(xy[i,0], xy[i,1])  | 
				
			||||
                           for i in xrange(xy.shape[-2])] | 
				
			||||
         | 
				
			||||
        for key in ("MemoryOrder",): | 
				
			||||
            try: | 
				
			||||
                del outattrs[key] | 
				
			||||
            except KeyError: | 
				
			||||
                pass | 
				
			||||
         | 
				
			||||
    else: | 
				
			||||
        outname = "field3d_xy" | 
				
			||||
     | 
				
			||||
    outattrs["Orientation"] = cross_str | 
				
			||||
     | 
				
			||||
    return DataArray(result, name=outname, dims=outdimnames,  | 
				
			||||
                     coords=outcoords, attrs=outattrs)  | 
				
			||||
 | 
				
			||||
 | 
				
			||||
def _set_1d_meta(wrapped, instance, args, kwargs): | 
				
			||||
    argvars = from_args(wrapped, ("v_in", "z_in", "z_out", "missingval"),  | 
				
			||||
                          *args, **kwargs)   | 
				
			||||
     | 
				
			||||
    v_in = argvars["v_in"] | 
				
			||||
    z_in = argvars["z_in"] | 
				
			||||
    z_out = argvars["z_out"] | 
				
			||||
    missingval = argvars["missingval"] | 
				
			||||
     | 
				
			||||
    result = wrapped(*args, **kwargs) | 
				
			||||
     | 
				
			||||
    # Dims are (...,xy,z) | 
				
			||||
    if isinstance(v_in, DataArray): | 
				
			||||
        outcoords = OrderedDict() | 
				
			||||
        outattrs = OrderedDict() | 
				
			||||
        outdimnames = list(v_in.dims) | 
				
			||||
        outcoords.update(v_in.coords) | 
				
			||||
         | 
				
			||||
         | 
				
			||||
        outdimnames.remove(v_in.dims[-1]) | 
				
			||||
        del outcoords[v_in.dims[-1]] | 
				
			||||
        outdimnames.append("z") | 
				
			||||
        outname = "{0}_z".format(v_in.name) | 
				
			||||
        outcoords["z"] = z_out | 
				
			||||
         | 
				
			||||
        outattrs.update(v_in.attrs) | 
				
			||||
        outattrs["_FillValue"] = missingval | 
				
			||||
        outattrs["missing_value"] = missingval | 
				
			||||
         | 
				
			||||
    else: | 
				
			||||
        outname = "v_in_z" | 
				
			||||
     | 
				
			||||
     | 
				
			||||
    return DataArray(result, name=outname, dims=outdimnames,  | 
				
			||||
                     coords=outcoords, attrs=outattrs) | 
				
			||||
     | 
				
			||||
     | 
				
			||||
           | 
				
			||||
 | 
				
			||||
def set_interp_metadata(interp_type): | 
				
			||||
    @wrapt.decorator | 
				
			||||
    def func_wrapper(wrapped, instance, args, kwargs): | 
				
			||||
        if not xarray_enabled(): | 
				
			||||
            return wrapped(*args, **kwargs) | 
				
			||||
         | 
				
			||||
        if interp_type == "horiz": | 
				
			||||
            return _set_horiz_meta(wrapped, instance, args, kwargs) | 
				
			||||
        elif interp_type == "cross": | 
				
			||||
            return _set_cross_meta(wrapped, instance, args, kwargs) | 
				
			||||
        elif interp_type == "line": | 
				
			||||
            return _set_line_meta(wrapped, instance, args, kwargs) | 
				
			||||
        elif interp_type == "vinterp": | 
				
			||||
            return _set_vinterp_meta(wrapped, instance, args, kwargs) | 
				
			||||
        elif interp_type == "2dxy": | 
				
			||||
            return _set_2dxy_meta(wrapped, instance, args, kwargs) | 
				
			||||
        elif interp_type == "1d": | 
				
			||||
            return _set_1d_meta(wrapped, instance, args, kwargs) | 
				
			||||
    return func_wrapper | 
				
			||||
@ -0,0 +1,90 @@
				@@ -0,0 +1,90 @@
					 | 
				
			||||
from __future__ import (absolute_import, division, print_function,  | 
				
			||||
                        unicode_literals) | 
				
			||||
 | 
				
			||||
import numpy as np | 
				
			||||
 | 
				
			||||
import wrapt  | 
				
			||||
 | 
				
			||||
from .destag import destagger | 
				
			||||
from .util import iter_left_indexes | 
				
			||||
 | 
				
			||||
__all__ = ["uvmet_left_iter"] | 
				
			||||
 | 
				
			||||
# Placed in separate module to resolve a circular dependency with destagger  | 
				
			||||
# module | 
				
			||||
 | 
				
			||||
def uvmet_left_iter(): | 
				
			||||
    """Decorator to handle iterating over leftmost dimensions when using  | 
				
			||||
    multiple files and/or multiple times with the uvmet product. | 
				
			||||
     | 
				
			||||
    """ | 
				
			||||
    @wrapt.decorator | 
				
			||||
    def func_wrapper(wrapped, instance, args, kwargs): | 
				
			||||
        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 wrapped(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 = np.empty(outdims, u.dtype) | 
				
			||||
         | 
				
			||||
        for left_idxs in iter_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 = tuple([x for x in left_idxs] + [slice(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 = wrapped(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 = np.squeeze(res)  | 
				
			||||
             | 
				
			||||
            output[left_and_slice_idxs] = res[:] | 
				
			||||
             | 
				
			||||
        return output | 
				
			||||
     | 
				
			||||
    return func_wrapper | 
				
			||||
 | 
				
			||||
					Loading…
					
					
				
		Reference in new issue