Bill Ladwig 6 years ago
parent
commit
f3068c2b69
  1. 9
      src/wrf/geobnds.py
  2. 134
      src/wrf/interp.py
  3. 78
      src/wrf/interputils.py
  4. 79
      src/wrf/latlonutils.py
  5. 229
      src/wrf/metadecorators.py
  6. 258
      src/wrf/projection.py
  7. 3
      src/wrf/projutils.py
  8. 4
      src/wrf/py3compat.py
  9. 325
      src/wrf/routines.py
  10. 85
      src/wrf/specialdec.py
  11. 286
      src/wrf/units.py
  12. 219
      src/wrf/util.py
  13. 1
      src/wrf/version.py

9
src/wrf/geobnds.py

@ -2,6 +2,7 @@ from __future__ import (absolute_import, division, print_function) @@ -2,6 +2,7 @@ from __future__ import (absolute_import, division, print_function)
from .coordpair import CoordPair
class GeoBounds(object):
"""A class that stores the geographic boundaries.
@ -56,8 +57,8 @@ class GeoBounds(object): @@ -56,8 +57,8 @@ class GeoBounds(object):
raise ValueError("'top_right' parameter does not contain a"
"'lon' attribute")
elif lats is not None and lons is not None:
self.bottom_left = CoordPair(lat=lats[0,0], lon=lons[0,0])
self.top_right = CoordPair(lat=lats[-1,-1], lon=lons[-1,-1])
self.bottom_left = CoordPair(lat=lats[0, 0], lon=lons[0, 0])
self.top_right = CoordPair(lat=lats[-1, -1], lon=lons[-1, -1])
else:
raise ValueError("must specify either 'bottom_top' and "
"'top_right' parameters "
@ -84,7 +85,3 @@ class NullGeoBounds(GeoBounds): @@ -84,7 +85,3 @@ class NullGeoBounds(GeoBounds):
def __repr__(self):
return "{}()".format(self.__class__.__name__)

134
src/wrf/interp.py

@ -110,7 +110,7 @@ def interplevel(field3d, vert, desiredlev, missing=default_fill(np.float64), @@ -110,7 +110,7 @@ def interplevel(field3d, vert, desiredlev, missing=default_fill(np.float64),
else:
result = _interpz3d_lev2d(field3d, vert, _desiredlev, missing)
masked = ma.masked_values (result, missing)
masked = ma.masked_values(result, missing)
if not meta:
if squeeze:
@ -175,9 +175,9 @@ def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64), @@ -175,9 +175,9 @@ def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64),
timeidx (:obj:`int`, optional): The
desired time index when obtaining map boundary information
from moving nests. This value can be a positive or negative integer.
Only required when *wrfin* is specified and the nest is moving.
Currently, :data:`wrf.ALL_TIMES` is not supported.
from moving nests. This value can be a positive or negative
integer. Only required when *wrfin* is specified and the nest is
moving. Currently, :data:`wrf.ALL_TIMES` is not supported.
Default is 0.
stagger (:obj:`str`): If using latitude, longitude coordinate pairs
@ -286,7 +286,7 @@ def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64), @@ -286,7 +286,7 @@ def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64),
pivot_point_xy = None
if (latlon is True or is_latlon_pair(start_point) or
is_latlon_pair(pivot_point)):
is_latlon_pair(pivot_point)):
if wrfin is not None:
is_moving = is_moving_domain(wrfin)
@ -299,12 +299,12 @@ def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64), @@ -299,12 +299,12 @@ def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64),
# domain could move outside of the line, which causes
# crashes or different line lengths.
if is_moving:
raise ValueError("Requesting all times with a moving nest "
"is not supported when using lat/lon "
"cross sections because the domain could "
"move outside of the cross section. "
"You must request each time "
"individually.")
raise ValueError("Requesting all times with a moving "
"nest is not supported when using "
"lat/lon cross sections because the "
"domain could move outside of the "
"cross section. You must request "
"each time individually.")
else:
# Domain not moving, just use 0
_timeidx = 0
@ -356,8 +356,8 @@ def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64), @@ -356,8 +356,8 @@ def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64),
result = np.empty(outshape, dtype=field3d.dtype)
for i in py3range(field3d.shape[0]):
result[i,:] = _vertcross(field3d[i,:], xy, var2dz, z_var2d,
missing)[:]
result[i, :] = _vertcross(field3d[i, :], xy, var2dz, z_var2d,
missing)[:]
return ma.masked_values(result, missing)
@ -392,9 +392,9 @@ def interpline(field2d, wrfin=None, timeidx=0, stagger=None, projection=None, @@ -392,9 +392,9 @@ def interpline(field2d, wrfin=None, timeidx=0, stagger=None, projection=None,
timeidx (:obj:`int`, optional): The
desired time index when obtaining map boundary information
from moving nests. This value can be a positive or negative integer.
Only required when *wrfin* is specified and the nest is moving.
Currently, :data:`wrf.ALL_TIMES` is not supported.
from moving nests. This value can be a positive or negative
integer. Only required when *wrfin* is specified and the nest is
moving. Currently, :data:`wrf.ALL_TIMES` is not supported.
Default is 0.
stagger (:obj:`str`): If using latitude, longitude coordinate pairs
@ -496,7 +496,7 @@ def interpline(field2d, wrfin=None, timeidx=0, stagger=None, projection=None, @@ -496,7 +496,7 @@ def interpline(field2d, wrfin=None, timeidx=0, stagger=None, projection=None,
pivot_point_xy = None
if (latlon is True or is_latlon_pair(start_point) or
is_latlon_pair(pivot_point)):
is_latlon_pair(pivot_point)):
if wrfin is not None:
is_moving = is_moving_domain(wrfin)
@ -509,10 +509,10 @@ def interpline(field2d, wrfin=None, timeidx=0, stagger=None, projection=None, @@ -509,10 +509,10 @@ def interpline(field2d, wrfin=None, timeidx=0, stagger=None, projection=None,
# domain could move outside of the line, which causes
# crashes or different line lengths.
if is_moving:
raise ValueError("Requesting all times with a moving nest "
"is not supported when using a lat/lon "
"line because the domain could "
"move outside of line. "
raise ValueError("Requesting all times with a moving "
"nest is not supported when using a "
"lat/lon line because the domain "
"could move outside of line. "
"You must request each time "
"individually.")
else:
@ -585,8 +585,8 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False, @@ -585,8 +585,8 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False,
* 'ght_msl': grid point height msl [km]
* 'ght_agl': grid point height agl [km]
* 'theta', 'th': potential temperature [K]
* 'theta-e', 'thetae', 'eth': equivalent potential temperature \
[K]
* 'theta-e', 'thetae', 'eth': equivalent potential \
temperature [K]
interp_levels (sequence): A 1D sequence of vertical levels to
interpolate to. Values must be in the same units as specified
@ -675,40 +675,38 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False, @@ -675,40 +675,38 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False,
"tc", "tk", "theta", "th", "theta-e", "thetae",
"eth", "ght", 'z_km', 'ght_km')
icase_lookup = {"none" : 0,
"p" : 1,
"pres" : 1,
"pressure" : 1,
"p_hpa" : 1,
"pres_hpa" : 1,
"pressure_hpa" : 1,
"z" : 2,
"ght" : 2,
"z_km" : 2,
"ght_km" : 2,
"tc" : 3,
"tk" : 4,
"theta" : 5,
"th" : 5,
"theta-e" : 6,
"thetae" : 6,
"eth" : 6}
in_unitmap = {"p_hpa" : 1.0/ConversionFactors.PA_TO_HPA,
"pres_hpa" : 1.0/ConversionFactors.PA_TO_HPA,
"pressure_hpa" : 1.0/ConversionFactors.PA_TO_HPA,
"z_km" : 1.0/ConversionFactors.M_TO_KM,
"ght_km" : 1.0/ConversionFactors.M_TO_KM,
}
out_unitmap = {"p_hpa" : ConversionFactors.PA_TO_HPA,
"pres_hpa" : ConversionFactors.PA_TO_HPA,
"pressure_hpa" : ConversionFactors.PA_TO_HPA,
"z_km" : ConversionFactors.M_TO_KM,
"ght_km" : ConversionFactors.M_TO_KM,
}
icase_lookup = {"none": 0,
"p": 1,
"pres": 1,
"pressure": 1,
"p_hpa": 1,
"pres_hpa": 1,
"pressure_hpa": 1,
"z": 2,
"ght": 2,
"z_km": 2,
"ght_km": 2,
"tc": 3,
"tk": 4,
"theta": 5,
"th": 5,
"theta-e": 6,
"thetae": 6,
"eth": 6}
in_unitmap = {"p_hpa": 1.0/ConversionFactors.PA_TO_HPA,
"pres_hpa": 1.0/ConversionFactors.PA_TO_HPA,
"pressure_hpa": 1.0/ConversionFactors.PA_TO_HPA,
"z_km": 1.0/ConversionFactors.M_TO_KM,
"ght_km": 1.0/ConversionFactors.M_TO_KM,
}
out_unitmap = {"p_hpa": ConversionFactors.PA_TO_HPA,
"pres_hpa": ConversionFactors.PA_TO_HPA,
"pressure_hpa": ConversionFactors.PA_TO_HPA,
"z_km": ConversionFactors.M_TO_KM,
"ght_km": ConversionFactors.M_TO_KM,
}
# These constants match what's in the fortran code.
rgas = Constants.RD
@ -728,12 +726,12 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False, @@ -728,12 +726,12 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False,
# Check for valid coord
if vert_coord not in valid_coords:
raise ValueError("'%s' is not a valid vertical "
"coordinate type" % vert_coord)
raise ValueError("'{}' is not a valid vertical "
"coordinate type".format(vert_coord))
# Check for valid field type
if field_type not in valid_field_types:
raise ValueError("'%s' is not a valid field type" % field_type)
raise ValueError("'{}' is not a valid field type".format(field_type))
log_p_int = 1 if log_p else 0
@ -778,16 +776,16 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False, @@ -778,16 +776,16 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False,
elif vert_coord == "ght_agl":
ht_agl = get_height(_wrfin, timeidx, msl=False, units="m",
method=method, squeeze=squeeze, cache=cache,
meta=False, _key=_key)
method=method, squeeze=squeeze, cache=cache,
meta=False, _key=_key)
vcor = 3
vcord_array = np.exp(-ht_agl/sclht)
elif vert_coord in ("theta", "th"):
t = get_theta(_wrfin, timeidx, units="k",
method=method, squeeze=squeeze, cache=cache,
meta=False, _key=_key)
method=method, squeeze=squeeze, cache=cache,
meta=False, _key=_key)
coriolis = extract_vars(_wrfin, timeidx, "F",
method, squeeze, cache, meta=False,
@ -814,7 +812,7 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False, @@ -814,7 +812,7 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False,
delta = 0.01
eth = get_eth(_wrfin, timeidx, method=method, squeeze=squeeze,
cache=cache, meta=False, _key=_key)
cache=cache, meta=False, _key=_key)
coriolis = extract_vars(_wrfin, timeidx, "F",
method, squeeze, cache, meta=False,
@ -861,9 +859,3 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False, @@ -861,9 +859,3 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False,
res_ = res
return ma.masked_values(res_, missing)

78
src/wrf/interputils.py

@ -31,11 +31,11 @@ def to_positive_idxs(shape, coord): @@ -31,11 +31,11 @@ def to_positive_idxs(shape, coord):
if (coord[-2] >= 0 and coord[-1] >= 0):
return coord
return [x if (x >= 0) else shape[-i-1]+x for (i,x) in enumerate(coord)]
return [x if (x >= 0) else shape[-i-1]+x for (i, x) in enumerate(coord)]
def _calc_xy(xdim, ydim, pivot_point=None, angle=None,
start_point=None, end_point=None):
start_point=None, end_point=None):
"""Return the x,y points for the horizontal cross section line.
Args:
@ -80,16 +80,15 @@ def _calc_xy(xdim, ydim, pivot_point=None, angle=None, @@ -80,16 +80,15 @@ def _calc_xy(xdim, ydim, pivot_point=None, angle=None,
if xp >= xdim or yp >= ydim:
raise ValueError("pivot point {} is outside of domain "
"with shape {}".format(pivot_point,
(xdim, ydim)))
(xdim, ydim)))
if (angle > 315.0 or angle < 45.0
or ((angle > 135.0) and (angle < 225.0))):
or ((angle > 135.0) and (angle < 225.0))):
#x = y*slope + intercept
slope = -(360.-angle)/45.
if( angle < 45. ):
if(angle < 45.):
slope = angle/45.
if( angle > 135.):
if(angle > 135.):
slope = (angle-180.)/45.
intercept = xp - yp*slope
@ -98,51 +97,51 @@ def _calc_xy(xdim, ydim, pivot_point=None, angle=None, @@ -98,51 +97,51 @@ def _calc_xy(xdim, ydim, pivot_point=None, angle=None,
y0 = 0.
x0 = y0*slope + intercept
if( x0 < 0.): # intersect outside of left boundary
if(x0 < 0.): # intersect outside of left boundary
x0 = 0.
y0 = (x0 - intercept)/slope
if( x0 > xdim-1): #intersect outside of right boundary
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?
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
if(x1 < 0.): # intersect outside of left boundary
x1 = 0.
y1 = (x1 - intercept)/slope
y1 = (x1 - intercept)/slope
if( x1 > xdim-1): # intersect outside of right boundary
if(x1 > xdim-1): # intersect outside of right boundary
x1 = xdim-1
y1 = (x1 - intercept)/slope
y1 = (x1 - intercept)/slope
else:
# y = x*slope + intercept
slope = (90.-angle)/45.
if( angle > 225. ):
if (angle > 225.):
slope = (270.-angle)/45.
intercept = yp - xp*slope
#find intersections with domain boundaries
# Find intersections with domain boundaries
x0 = 0.
y0 = x0*slope + intercept
if( y0 < 0.): # intersect outside of bottom boundary
if (y0 < 0.): # intersect outside of bottom boundary
y0 = 0.
x0 = (y0 - intercept)/slope
x0 = (y0 - intercept)/slope
if( y0 > ydim-1): # intersect outside of top boundary
if (y0 > ydim-1): # intersect outside of top boundary
y0 = ydim-1
x0 = (y0 - intercept)/slope
x0 = (y0 - intercept)/slope
x1 = xdim-1. # need to make sure this will be a float?
x1 = xdim-1. # need to make sure this will be a float?
y1 = x1*slope + intercept
if( y1 < 0.): # intersect outside of bottom boundary
if (y1 < 0.): # intersect outside of bottom boundary
y1 = 0.
x1 = (y1 - intercept)/slope
x1 = (y1 - intercept)/slope
if( y1 > ydim-1):# intersect outside of top boundary
if (y1 > ydim-1): # intersect outside of top boundary
y1 = ydim-1
x1 = (y1 - intercept)/slope
x1 = (y1 - intercept)/slope
elif start_point is not None and end_point is not None:
x0 = start_point[-2]
y0 = start_point[-1]
@ -164,14 +163,14 @@ def _calc_xy(xdim, ydim, pivot_point=None, angle=None, @@ -164,14 +163,14 @@ def _calc_xy(xdim, ydim, pivot_point=None, angle=None,
distance = (dx*dx + dy*dy)**0.5
npts = int(distance) + 1
xy = np.zeros((npts,2), "float")
xy = np.zeros((npts, 2), "float")
dx = dx/(npts-1)
dy = dy/(npts-1)
for i in py3range(npts):
xy[i,0] = x0 + i*dx
xy[i,1] = y0 + i*dy
xy[i, 0] = x0 + i*dx
xy[i, 1] = y0 + i*dy
return xy
@ -237,8 +236,8 @@ def get_xy_z_params(z, pivot_point=None, angle=None, @@ -237,8 +236,8 @@ def get_xy_z_params(z, pivot_point=None, angle=None,
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])
idx1 = tuple([0]*extra_dim_num + [0, 0])
idx2 = tuple([0]*extra_dim_num + [-1, 0])
if levels is None:
# interp to constant z grid
@ -256,7 +255,7 @@ def get_xy_z_params(z, pivot_point=None, angle=None, @@ -256,7 +255,7 @@ def get_xy_z_params(z, pivot_point=None, angle=None,
z_var2d = np.zeros((autolevels), dtype=z.dtype)
z_var2d[0] = z_min
for i in py3range(1,autolevels):
for i in py3range(1, autolevels):
z_var2d[i] = z_var2d[0] + i*dz
else:
z_var2d = np.asarray(levels, z.dtype)
@ -323,6 +322,7 @@ def get_xy(var, pivot_point=None, angle=None, @@ -323,6 +322,7 @@ def get_xy(var, pivot_point=None, angle=None,
return xy
def to_xy_coords(pairs, wrfin=None, timeidx=0, stagger=None, projection=None,
ll_point=None):
"""Return the coordinate pairs in grid space.
@ -381,15 +381,16 @@ def to_xy_coords(pairs, wrfin=None, timeidx=0, stagger=None, projection=None, @@ -381,15 +381,16 @@ def to_xy_coords(pairs, wrfin=None, timeidx=0, stagger=None, projection=None,
"""
if (wrfin is None and (projection is None or ll_point is None)):
raise ValueError ("'wrfin' parameter or "
"'projection' and 'll_point' parameters "
"are required")
raise ValueError("'wrfin' parameter or "
"'projection' and 'll_point' parameters "
"are required")
lat, lon = pairs_to_latlon(pairs)
if wrfin is not None:
xy_vals = _ll_to_xy(lat, lon, wrfin=wrfin, timeidx=timeidx,
squeeze=True, meta=False, stagger=stagger, as_int=True)
squeeze=True, meta=False, stagger=stagger,
as_int=True)
else:
map_proj = projection.map_proj
@ -427,9 +428,8 @@ def to_xy_coords(pairs, wrfin=None, timeidx=0, stagger=None, projection=None, @@ -427,9 +428,8 @@ def to_xy_coords(pairs, wrfin=None, timeidx=0, stagger=None, projection=None,
xy_vals = xy_vals.squeeze()
if xy_vals.ndim == 1:
return CoordPair(x=xy_vals[0], y=xy_vals[1])
else:
return [CoordPair(x=xy_vals[0,i], y=xy_vals[1,i])
return [CoordPair(x=xy_vals[0, i], y=xy_vals[1, i])
for i in py3range(xy_vals.shape[1])]

79
src/wrf/latlonutils.py

@ -7,8 +7,8 @@ import numpy as np @@ -7,8 +7,8 @@ import numpy as np
from .constants import Constants, ProjectionTypes
from .extension import _lltoxy, _xytoll
from .util import (extract_vars, extract_global_attrs,
either, is_moving_domain, is_multi_time_req,
iter_left_indexes, is_mapping, is_multi_file)
either, is_moving_domain, iter_left_indexes,
is_mapping, is_multi_file)
from .py3compat import viewkeys, viewitems
from .projutils import dict_keys_to_upper
@ -46,6 +46,7 @@ def _lat_varname(wrfin, stagger): @@ -46,6 +46,7 @@ def _lat_varname(wrfin, stagger):
return varname
def _lon_varname(wrfin, stagger):
"""Return the longitude variable name for the specified stagger type.
@ -79,6 +80,7 @@ def _lon_varname(wrfin, stagger): @@ -79,6 +80,7 @@ def _lon_varname(wrfin, stagger):
return varname
def _get_proj_params(wrfin, timeidx, stagger, method, squeeze, cache, _key):
"""Return the map projection parameters.
@ -181,9 +183,9 @@ def _get_proj_params(wrfin, timeidx, stagger, method, squeeze, cache, _key): @@ -181,9 +183,9 @@ def _get_proj_params(wrfin, timeidx, stagger, method, squeeze, cache, _key):
method, squeeze, cache, key)
xlat = extract_vars(wrfin, lat_timeidx, (latvar,), method, squeeze, cache,
meta=False, _key=_key)[latvar]
meta=False, _key=_key)[latvar]
xlon = extract_vars(wrfin, lat_timeidx, (lonvar,), method, squeeze, cache,
meta=False, _key=_key)[lonvar]
meta=False, _key=_key)[lonvar]
ref_lat = np.ravel(xlat[..., 0, 0])
ref_lon = np.ravel(xlon[..., 0, 0])
@ -222,8 +224,8 @@ def _kwarg_proj_params(**projparams): @@ -222,8 +224,8 @@ def _kwarg_proj_params(**projparams):
ref_lon = projparams.get("REF_LON")
pole_lat = projparams.get("POLE_LAT", 90.0)
pole_lon = projparams.get("POLE_LON", 0.0)
known_x = projparams.get("KNOWN_X") # Use 0-based
known_y = projparams.get("KNOWN_Y") # Use 0-based
known_x = projparams.get("KNOWN_X") # Use 0-based
known_y = projparams.get("KNOWN_Y") # Use 0-based
dx = projparams.get("DX")
dy = projparams.get("DY")
@ -232,12 +234,12 @@ def _kwarg_proj_params(**projparams): @@ -232,12 +234,12 @@ def _kwarg_proj_params(**projparams):
# Sanity checks
# Required args for all projections
for name, var in viewitems({"MAP_PROJ" : map_proj,
"REF_LAT" : ref_lat,
"REF_LON" : ref_lon,
"KNOWN_X" : known_x,
"KNOWN_Y" : known_y,
"DX" : dx}):
for name, var in viewitems({"MAP_PROJ": map_proj,
"REF_LAT": ref_lat,
"REF_LON": ref_lon,
"KNOWN_X": known_x,
"KNOWN_Y": known_y,
"DX": dx}):
if var is None:
raise ValueError("'{}' argument required".format(name))
@ -279,8 +281,8 @@ def _kwarg_proj_params(**projparams): @@ -279,8 +281,8 @@ def _kwarg_proj_params(**projparams):
# Will return 0-based indexes
def _ll_to_xy(latitude, longitude, wrfin=None, timeidx=0,
stagger=None, method="cat", squeeze=True, cache=None,
_key=None, as_int=True, **projparams):
stagger=None, method="cat", squeeze=True, cache=None,
_key=None, as_int=True, **projparams):
"""Return the x,y coordinates for a specified latitude and longitude.
The *latitude* and *longitude* arguments can be a single value or a
@ -359,13 +361,13 @@ def _ll_to_xy(latitude, longitude, wrfin=None, timeidx=0, @@ -359,13 +361,13 @@ def _ll_to_xy(latitude, longitude, wrfin=None, timeidx=0,
if wrfin is not None:
(map_proj, truelat1, truelat2, stdlon, ref_lat, ref_lon,
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc,
loninc) = _get_proj_params(wrfin, timeidx, stagger, method, squeeze,
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc,
loninc) = _get_proj_params(wrfin, timeidx, stagger, method, squeeze,
cache, _key)
else:
(map_proj, truelat1, truelat2, stdlon, ref_lat, ref_lon,
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc,
loninc) = _kwarg_proj_params(**projparams)
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc,
loninc) = _kwarg_proj_params(**projparams)
if isinstance(latitude, Iterable):
lats = np.asarray(latitude)
@ -391,7 +393,6 @@ def _ll_to_xy(latitude, longitude, wrfin=None, timeidx=0, @@ -391,7 +393,6 @@ def _ll_to_xy(latitude, longitude, wrfin=None, timeidx=0,
result = np.empty(outdim, np.float64)
for left_idxs in iter_left_indexes(extra_dims):
#left_and_slice_idxs = left_idxs + (slice(None), )
# Left indexes is a misnomer, since these will be on the right
x_idxs = (0,) + left_idxs
y_idxs = (1,) + left_idxs
@ -406,9 +407,9 @@ def _ll_to_xy(latitude, longitude, wrfin=None, timeidx=0, @@ -406,9 +407,9 @@ def _ll_to_xy(latitude, longitude, wrfin=None, timeidx=0,
lon = lons[left_idxs[-1]]
xy = _lltoxy(map_proj, truelat1, truelat2, stdlon,
ref_lat_val, ref_lon_val, pole_lat, pole_lon,
known_x, known_y, dx, dy, latinc, loninc,
lat, lon)
ref_lat_val, ref_lon_val, pole_lat, pole_lon,
known_x, known_y, dx, dy, latinc, loninc,
lat, lon)
# Note: comes back from fortran as y,x
result[x_idxs] = xy[1]
@ -418,15 +419,14 @@ def _ll_to_xy(latitude, longitude, wrfin=None, timeidx=0, @@ -418,15 +419,14 @@ def _ll_to_xy(latitude, longitude, wrfin=None, timeidx=0,
result = np.empty((2,), np.float64)
fort_out = _lltoxy(map_proj, truelat1, truelat2, stdlon,
ref_lat, ref_lon, pole_lat, pole_lon,
known_x, known_y, dx, dy, latinc, loninc,
latitude, longitude)
ref_lat, ref_lon, pole_lat, pole_lon,
known_x, known_y, dx, dy, latinc, loninc,
latitude, longitude)
# Note, comes back from fortran as y,x. So, need to swap them.
result[0] = fort_out[1]
result[1] = fort_out[0]
# Make indexes 0-based
result = result - 1
@ -435,10 +435,11 @@ def _ll_to_xy(latitude, longitude, wrfin=None, timeidx=0, @@ -435,10 +435,11 @@ def _ll_to_xy(latitude, longitude, wrfin=None, timeidx=0,
return result
# X and Y should be 0-based
def _xy_to_ll(x, y, wrfin=None, timeidx=0, stagger=None,
method="cat", squeeze=True, cache=None, _key=None,
**projparams):
method="cat", squeeze=True, cache=None, _key=None,
**projparams):
"""Return the latitude and longitude for specified x,y coordinates.
@ -520,14 +521,13 @@ def _xy_to_ll(x, y, wrfin=None, timeidx=0, stagger=None, @@ -520,14 +521,13 @@ def _xy_to_ll(x, y, wrfin=None, timeidx=0, stagger=None,
if wrfin is not None:
(map_proj, truelat1, truelat2, stdlon, ref_lat, ref_lon,
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc,
loninc) = _get_proj_params(wrfin, timeidx, stagger, method, squeeze,
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc,
loninc) = _get_proj_params(wrfin, timeidx, stagger, method, squeeze,
cache, _key)
else:
(map_proj, truelat1, truelat2, stdlon, ref_lat, ref_lon,
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc,
loninc) = _kwarg_proj_params(**projparams)
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc,
loninc) = _kwarg_proj_params(**projparams)
if isinstance(x, Iterable):
x_arr = np.asarray(x)
@ -555,7 +555,6 @@ def _xy_to_ll(x, y, wrfin=None, timeidx=0, stagger=None, @@ -555,7 +555,6 @@ def _xy_to_ll(x, y, wrfin=None, timeidx=0, stagger=None,
result = np.empty(outdim, np.float64)
for left_idxs in iter_left_indexes(extra_dims):
#left_and_slice_idxs = left_idxs + (slice(None), )
lat_idxs = (0,) + left_idxs
lon_idxs = (1,) + left_idxs
@ -573,7 +572,6 @@ def _xy_to_ll(x, y, wrfin=None, timeidx=0, stagger=None, @@ -573,7 +572,6 @@ def _xy_to_ll(x, y, wrfin=None, timeidx=0, stagger=None,
ref_lon_val, pole_lat, pole_lon, known_x, known_y,
dx, dy, latinc, loninc, x_val, y_val)
#result[left_and_slice_idxs] = ll[:]
result[lat_idxs] = ll[0]
result[lon_idxs] = ll[1]
@ -582,13 +580,8 @@ def _xy_to_ll(x, y, wrfin=None, timeidx=0, stagger=None, @@ -582,13 +580,8 @@ def _xy_to_ll(x, y, wrfin=None, timeidx=0, stagger=None,
x_val = x + 1
y_val = y + 1
result = _xytoll(map_proj, truelat1, truelat2, stdlon, ref_lat, ref_lon,
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc,
loninc, x_val, y_val)
result = _xytoll(map_proj, truelat1, truelat2, stdlon, ref_lat,
ref_lon, pole_lat, pole_lon, known_x, known_y,
dx, dy, latinc, loninc, x_val, y_val)
return result

229
src/wrf/metadecorators.py

@ -112,7 +112,6 @@ def copy_and_set_metadata(copy_varname=None, delete_attrs=None, name=None, @@ -112,7 +112,6 @@ def copy_and_set_metadata(copy_varname=None, delete_attrs=None, name=None,
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(wrfin, timeidx, (_copy_varname,),
method, squeeze, cache,
@ -155,7 +154,6 @@ def copy_and_set_metadata(copy_varname=None, delete_attrs=None, name=None, @@ -155,7 +154,6 @@ def copy_and_set_metadata(copy_varname=None, delete_attrs=None, name=None,
except KeyError:
pass
if name is not None:
outname = name
@ -177,7 +175,7 @@ def copy_and_set_metadata(copy_varname=None, delete_attrs=None, name=None, @@ -177,7 +175,7 @@ def copy_and_set_metadata(copy_varname=None, delete_attrs=None, name=None,
outattrs["missing_value"] = result.fill_value
return DataArray(result, name=outname, coords=outcoords,
dims=outdimnames, attrs=outattrs)
dims=outdimnames, attrs=outattrs)
return func_wrapper
@ -241,7 +239,7 @@ def set_wind_metadata(copy_varname, name, description, @@ -241,7 +239,7 @@ def set_wind_metadata(copy_varname, name, description,
argvars = from_args(wrapped, ("wrfin", "timeidx", "units",
"method", "squeeze", "ten_m", "cache",
"_key"),
*args, **kwargs)
*args, **kwargs)
wrfin = argvars["wrfin"]
timeidx = argvars["timeidx"]
units = argvars["units"]
@ -277,10 +275,8 @@ def set_wind_metadata(copy_varname, name, description, @@ -277,10 +275,8 @@ def set_wind_metadata(copy_varname, name, description,
outattrs = OrderedDict()
outdimnames = list(copy_var.dims)
#outcoords.update(copy_var.coords)
outattrs.update(copy_var.attrs)
if wind_ncvar:
outcoords.update(copy_var.coords)
elif not wspd_wdir:
@ -307,7 +303,7 @@ def set_wind_metadata(copy_varname, name, description, @@ -307,7 +303,7 @@ def set_wind_metadata(copy_varname, name, description,
# So, need to rebuild the XLAT, XLONG, coordinates again since the
# leftmost index changed.
if not wind_ncvar:
for key,dataarray in viewitems(copy_var.coords):
for key, dataarray in viewitems(copy_var.coords):
if is_coordvar(key):
outcoords[key] = dataarray.dims, to_np(dataarray)
elif key == "XTIME":
@ -319,7 +315,7 @@ def set_wind_metadata(copy_varname, name, description, @@ -319,7 +315,7 @@ def set_wind_metadata(copy_varname, name, description,
outattrs["description"] = description
return DataArray(result, name=outname, coords=outcoords,
dims=outdimnames, attrs=outattrs)
dims=outdimnames, attrs=outattrs)
return func_wrapper
@ -359,7 +355,7 @@ def set_cape_metadata(is2d): @@ -359,7 +355,7 @@ def set_cape_metadata(is2d):
argvars = from_args(wrapped, ("wrfin", "timeidx", "method", "squeeze",
"cache", "_key", "missing"),
*args, **kwargs)
*args, **kwargs)
wrfin = argvars["wrfin"]
timeidx = argvars["timeidx"]
method = argvars["method"]
@ -414,13 +410,12 @@ def set_cape_metadata(is2d): @@ -414,13 +410,12 @@ def set_cape_metadata(is2d):
outattrs["_FillValue"] = missing
outattrs["missing_value"] = missing
# xarray doesn't line up coordinate dimensions based on
# names, it just remembers the index it originally mapped to.
# So, need to rebuild the XLAT, XLONG, coordinates again since the
# leftmost index changed.
for key,dataarray in viewitems(copy_var.coords):
for key, dataarray in viewitems(copy_var.coords):
if is_coordvar(key):
outcoords[key] = dataarray.dims, to_np(dataarray)
elif key == "XTIME":
@ -433,9 +428,8 @@ def set_cape_metadata(is2d): @@ -433,9 +428,8 @@ def set_cape_metadata(is2d):
else:
outcoords["cape_cin"] = ["cape", "cin"]
return DataArray(result, name=outname, coords=outcoords,
dims=outdimnames, attrs=outattrs)
dims=outdimnames, attrs=outattrs)
return func_wrapper
@ -543,7 +537,7 @@ def set_cloudfrac_metadata(): @@ -543,7 +537,7 @@ def set_cloudfrac_metadata():
# So, need to rebuild the XLAT, XLONG, coordinates again since the
# leftmost index changed.
for key,dataarray in viewitems(copy_var.coords):
for key, dataarray in viewitems(copy_var.coords):
if is_coordvar(key):
outcoords[key] = dataarray.dims, to_np(dataarray)
elif key == "XTIME":
@ -554,7 +548,7 @@ def set_cloudfrac_metadata(): @@ -554,7 +548,7 @@ def set_cloudfrac_metadata():
outcoords["low_mid_high"] = ["low", "mid", "high"]
return DataArray(result, name=outname, coords=outcoords,
dims=outdimnames, attrs=outattrs)
dims=outdimnames, attrs=outattrs)
return func_wrapper
@ -629,12 +623,12 @@ def set_latlon_metadata(xy=False): @@ -629,12 +623,12 @@ def set_latlon_metadata(xy=False):
coords = {}
if not xy:
coords["xy_coord"] = (dimnames[-1], [CoordPair(x=x[0], y=x[1])
for x in zip(arr1, arr2)])
for x in zip(arr1, arr2)])
coords[dimnames[0]] = ["lat", "lon"]
else:
coords["latlon_coord"] = (dimnames[-1], [CoordPair(lat=x[0],
lon=x[1])
for x in zip(arr1, arr2)])
coords["latlon_coord"] = (dimnames[-1],
[CoordPair(lat=x[0], lon=x[1])
for x in zip(arr1, arr2)])
coords[dimnames[0]] = ["x", "y"]
da = DataArray(result, name=outname, dims=dimnames, coords=coords)
@ -685,9 +679,9 @@ def set_height_metadata(geopt=False, stag=False): @@ -685,9 +679,9 @@ def set_height_metadata(geopt=False, stag=False):
return wrapped(*args, **kwargs)
argvars = from_args(wrapped, ("wrfin", "timeidx", "method",
"squeeze", "units", "msl", "cache",
"_key"),
*args, **kwargs)
"squeeze", "units", "msl", "cache",
"_key"),
*args, **kwargs)
wrfin = argvars["wrfin"]
timeidx = argvars["timeidx"]
units = argvars["units"]
@ -750,11 +744,12 @@ def set_height_metadata(geopt=False, stag=False): @@ -750,11 +744,12 @@ def set_height_metadata(geopt=False, stag=False):
"(mass grid)".format(height_type))
else:
outattrs["description"] = ("model height - [{}] (vertically "
"staggered grid)".format(height_type))
"staggered grid)".format(
height_type))
return DataArray(result, name=outname, dims=outdimnames,
coords=outcoords, attrs=outattrs)
return DataArray(result, name=outname,
dims=outdimnames, coords=outcoords, attrs=outattrs)
return func_wrapper
@ -794,7 +789,7 @@ def _set_horiz_meta(wrapped, instance, args, kwargs): @@ -794,7 +789,7 @@ def _set_horiz_meta(wrapped, instance, args, kwargs):
"""
argvars = from_args(wrapped, ("field3d", "vert", "desiredlev",
"missing", "squeeze"),
*args, **kwargs)
*args, **kwargs)
field3d = argvars["field3d"]
z = argvars["vert"]
@ -819,7 +814,6 @@ def _set_horiz_meta(wrapped, instance, args, kwargs): @@ -819,7 +814,6 @@ def _set_horiz_meta(wrapped, instance, args, kwargs):
if isinstance(z, DataArray):
vert_units = z.attrs.get("units", None)
if isinstance(field3d, DataArray):
outcoords = OrderedDict()
outdimnames = list(field3d.dims)
@ -830,7 +824,7 @@ def _set_horiz_meta(wrapped, instance, args, kwargs): @@ -830,7 +824,7 @@ def _set_horiz_meta(wrapped, instance, args, kwargs):
try:
del outcoords[field3d.dims[-3]]
except KeyError:
pass # xarray 0.9
pass # xarray 0.9
if not levsare2d:
outdimnames.insert(-2, "level")
@ -910,7 +904,7 @@ def _set_cross_meta(wrapped, instance, args, kwargs): @@ -910,7 +904,7 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
"ll_point", "pivot_point", "angle",
"start_point", "end_point", "autolevels",
"cache"),
*args, **kwargs)
*args, **kwargs)
field3d = argvars["field3d"]
z = argvars["vert"]
@ -934,7 +928,7 @@ def _set_cross_meta(wrapped, instance, args, kwargs): @@ -934,7 +928,7 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
pivot_point_xy = None
if (inc_latlon is True or is_latlon_pair(start_point) or
is_latlon_pair(pivot_point)):
is_latlon_pair(pivot_point)):
if wrfin is not None:
is_moving = is_moving_domain(wrfin)
@ -993,7 +987,8 @@ def _set_cross_meta(wrapped, instance, args, kwargs): @@ -993,7 +987,8 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
end_point_xy = (end_point.x, end_point.y)
xy, var2dz, z_var2d = get_xy_z_params(to_np(z), pivot_point_xy, angle,
start_point_xy, end_point_xy, levels, autolevels)
start_point_xy, end_point_xy,
levels, autolevels)
# Make a copy so we don't modify a user supplied cache
if cache is not None:
@ -1018,10 +1013,10 @@ def _set_cross_meta(wrapped, instance, args, kwargs): @@ -1018,10 +1013,10 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
outattrs = OrderedDict()
# 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]
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:
@ -1032,13 +1027,12 @@ def _set_cross_meta(wrapped, instance, args, kwargs): @@ -1032,13 +1027,12 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
outcoords = OrderedDict()
outdimnames = list(field3d.dims)
outcoords.update(field3d.coords)
for i in py3range(-3,0,1):
for i in py3range(-3, 0, 1):
outdimnames.remove(field3d.dims[i])
try:
del outcoords[field3d.dims[i]]
except KeyError:
pass # Xarray 0.9
pass # Xarray 0.9
# Delete any lat,lon coords
delkeys = [key for key in viewkeys(outcoords) if is_coordvar(key)]
@ -1069,12 +1063,10 @@ def _set_cross_meta(wrapped, instance, args, kwargs): @@ -1069,12 +1063,10 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
lats = _interpline(latcoord, xy)
lons = _interpline(loncoord, xy)
outcoords["xy_loc"] = ("cross_line_idx",
np.asarray(tuple(
CoordPair(x=xy[i,0], y=xy[i,1],
lat=lats[i], lon=lons[i])
for i in py3range(xy.shape[-2])))
)
outcoords["xy_loc"] = ("cross_line_idx", np.asarray(tuple(
CoordPair(x=xy[i, 0], y=xy[i, 1],
lat=lats[i], lon=lons[i])
for i in py3range(xy.shape[-2]))))
# Moving domain
else:
extra_dims = latcoord.shape[0:-2]
@ -1086,12 +1078,11 @@ def _set_cross_meta(wrapped, instance, args, kwargs): @@ -1086,12 +1078,11 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
lats = _interpline(latcoord[idxs], xy)
lons = _interpline(loncoord[idxs], xy)
latlon_loc[idxs] = np.asarray(tuple(
CoordPair(x=xy[i,0], y=xy[i,1],
lat=lats[i], lon=lons[i])
for i in py3range(xy.shape[-2]))
)[:]
latlon_loc[idxs] = np.asarray(
tuple(CoordPair(
x=xy[i, 0], y=xy[i, 1],
lat=lats[i], lon=lons[i])
for i in py3range(xy.shape[-2])))[:]
extra_dimnames = latcoord.dims[0:-2]
loc_dimnames = extra_dimnames + ("cross_line_idx",)
@ -1099,15 +1090,17 @@ def _set_cross_meta(wrapped, instance, args, kwargs): @@ -1099,15 +1090,17 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
else:
warnings.warn("'latlon' is set to True, but 'field3d' "
" contains no coordinate information")
outcoords["xy_loc"] = ("cross_line_idx", np.asarray(tuple(
CoordPair(xy[i,0], xy[i,1])
for i in py3range(xy.shape[-2]))))
"contains no coordinate information")
outcoords["xy_loc"] = ("cross_line_idx",
np.asarray(tuple(
CoordPair(xy[i, 0], xy[i, 1])
for i in py3range(xy.shape[-2]))))
else:
outcoords["xy_loc"] = ("cross_line_idx", np.asarray(tuple(
CoordPair(xy[i,0], xy[i,1])
for i in py3range(xy.shape[-2]))))
outcoords["xy_loc"] = ("cross_line_idx",
np.asarray(tuple(
CoordPair(xy[i, 0], xy[i, 1])
for i in py3range(xy.shape[-2]))))
outcoords["vertical"] = z_var2d[:]
@ -1160,12 +1153,11 @@ def _set_line_meta(wrapped, instance, args, kwargs): @@ -1160,12 +1153,11 @@ def _set_line_meta(wrapped, instance, args, kwargs):
:mod:`wrapt`
"""
argvars = from_args(wrapped, ("field2d",
"wrfin", "timeidx", "stagger", "projection",
"ll_point", "pivot_point", "angle",
"start_point", "end_point", "latlon",
"cache"),
*args, **kwargs)
argvars = from_args(wrapped, ("field2d", "wrfin", "timeidx", "stagger",
"projection", "ll_point", "pivot_point",
"angle", "start_point", "end_point",
"latlon", "cache"),
*args, **kwargs)
field2d = argvars["field2d"]
wrfin = argvars["wrfin"]
@ -1188,7 +1180,7 @@ def _set_line_meta(wrapped, instance, args, kwargs): @@ -1188,7 +1180,7 @@ def _set_line_meta(wrapped, instance, args, kwargs):
pivot_point_xy = None
if (inc_latlon is True or is_latlon_pair(start_point) or
is_latlon_pair(pivot_point)):
is_latlon_pair(pivot_point)):
if wrfin is not None:
is_moving = is_moving_domain(wrfin)
@ -1223,7 +1215,6 @@ def _set_line_meta(wrapped, instance, args, kwargs): @@ -1223,7 +1215,6 @@ def _set_line_meta(wrapped, instance, args, kwargs):
# to avoid problems downstream
_timeidx = 0
if pivot_point is not None:
if pivot_point.lat is not None and pivot_point.lon is not None:
xy_coords = to_xy_coords(pivot_point, wrfin, _timeidx,
@ -1232,7 +1223,6 @@ def _set_line_meta(wrapped, instance, args, kwargs): @@ -1232,7 +1223,6 @@ def _set_line_meta(wrapped, instance, args, kwargs):
else:
pivot_point_xy = (pivot_point.x, pivot_point.y)
if start_point is not None and end_point is not None:
if start_point.lat is not None and start_point.lon is not None:
xy_coords = to_xy_coords(start_point, wrfin, _timeidx,
@ -1248,7 +1238,6 @@ def _set_line_meta(wrapped, instance, args, kwargs): @@ -1248,7 +1238,6 @@ def _set_line_meta(wrapped, instance, args, kwargs):
else:
end_point_xy = (end_point.x, end_point.y)
xy = get_xy(field2d, pivot_point_xy, angle, start_point_xy, end_point_xy)
# Make a copy so we don't modify a user supplied cache
@ -1269,26 +1258,25 @@ def _set_line_meta(wrapped, instance, args, kwargs): @@ -1269,26 +1258,25 @@ def _set_line_meta(wrapped, instance, args, kwargs):
outattrs = OrderedDict()
# 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]
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)
cross_str += " ; center={0} ; angle={1}".format(pivot_point, angle)
if isinstance(field2d, DataArray):
outcoords = OrderedDict()
outdimnames = list(field2d.dims)
outcoords.update(field2d.coords)
for i in py3range(-2,0,1):
for i in py3range(-2, 0, 1):
outdimnames.remove(field2d.dims[i])
try:
del outcoords[field2d.dims[i]]
except KeyError:
pass # xarray 0.9
pass # xarray 0.9
# Delete any lat,lon coords
delkeys = [key for key in viewkeys(outcoords) if is_coordvar(key)]
@ -1318,12 +1306,10 @@ def _set_line_meta(wrapped, instance, args, kwargs): @@ -1318,12 +1306,10 @@ def _set_line_meta(wrapped, instance, args, kwargs):
lats = _interpline(latcoord, xy)
lons = _interpline(loncoord, xy)
outcoords["xy_loc"] = ("line_idx",
np.asarray(tuple(
CoordPair(x=xy[i,0], y=xy[i,1],
lat=lats[i], lon=lons[i])
for i in py3range(xy.shape[-2])))
)
outcoords["xy_loc"] = ("line_idx", np.asarray(tuple(
CoordPair(x=xy[i, 0], y=xy[i, 1],
lat=lats[i], lon=lons[i])
for i in py3range(xy.shape[-2]))))
# Moving domain
else:
@ -1337,11 +1323,9 @@ def _set_line_meta(wrapped, instance, args, kwargs): @@ -1337,11 +1323,9 @@ def _set_line_meta(wrapped, instance, args, kwargs):
lons = _interpline(loncoord[idxs], xy)
latlon_loc[idxs] = np.asarray(tuple(
CoordPair(x=xy[i,0], y=xy[i,1],
lat=lats[i], lon=lons[i])
for i in py3range(xy.shape[-2]))
)[:]
CoordPair(x=xy[i, 0], y=xy[i, 1],
lat=lats[i], lon=lons[i])
for i in py3range(xy.shape[-2])))[:]
extra_dimnames = latcoord.dims[0:-2]
loc_dimnames = extra_dimnames + ("line_idx",)
@ -1350,15 +1334,13 @@ def _set_line_meta(wrapped, instance, args, kwargs): @@ -1350,15 +1334,13 @@ def _set_line_meta(wrapped, instance, args, kwargs):
else:
warnings.warn("'latlon' is set to True, but 'field2d' "
"contains no coordinate information")
outcoords["xy_loc"] = ("line_idx", np.asarray(tuple(
CoordPair(xy[i,0], xy[i,1])
for i in py3range(xy.shape[-2]))))
outcoords["xy_loc"] = ("line_idx", np.asarray(
tuple(CoordPair(xy[i, 0], xy[i, 1])
for i in py3range(xy.shape[-2]))))
else:
outcoords["xy_loc"] = ("line_idx", np.asarray(tuple(
CoordPair(xy[i,0], xy[i,1])
for i in py3range(xy.shape[-2]))))
outcoords["xy_loc"] = ("line_idx", np.asarray(
tuple(CoordPair(xy[i, 0], xy[i, 1])
for i in py3range(xy.shape[-2]))))
else:
if inc_latlon:
warnings.warn("'latlon' is set to True, but 'field2d' is "
@ -1412,7 +1394,7 @@ def _set_vinterp_meta(wrapped, instance, args, kwargs): @@ -1412,7 +1394,7 @@ def _set_vinterp_meta(wrapped, instance, args, kwargs):
"field_type", "log_p",
"timeidx", "method", "squeeze",
"cache"),
*args, **kwargs)
*args, **kwargs)
field = argvars["field"]
vert_coord = argvars["vert_coord"]
@ -1427,7 +1409,6 @@ def _set_vinterp_meta(wrapped, instance, args, kwargs): @@ -1427,7 +1409,6 @@ def _set_vinterp_meta(wrapped, instance, args, kwargs):
outcoords = None
outattrs = OrderedDict()
if isinstance(field, DataArray):
outcoords = OrderedDict()
outdimnames = list(field.dims)
@ -1437,13 +1418,12 @@ def _set_vinterp_meta(wrapped, instance, args, kwargs): @@ -1437,13 +1418,12 @@ def _set_vinterp_meta(wrapped, instance, args, kwargs):
try:
del outcoords[field.dims[-3]]
except KeyError:
pass # xarray 0.9
pass # xarray 0.9
outdimnames.insert(-2, "interp_level")
outcoords["interp_level"] = interp_levels
outattrs.update(field.attrs)
outname = field.name
else:
@ -1498,13 +1478,12 @@ def _set_2dxy_meta(wrapped, instance, args, kwargs): @@ -1498,13 +1478,12 @@ def _set_2dxy_meta(wrapped, instance, args, kwargs):
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]
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)
cross_str = "({0},{1}) to ({2},{3})".format(st_x, st_y, ed_x, ed_y)
outname = None
outdimnames = None
@ -1517,22 +1496,21 @@ def _set_2dxy_meta(wrapped, instance, args, kwargs): @@ -1517,22 +1496,21 @@ def _set_2dxy_meta(wrapped, instance, args, kwargs):
outdimnames = list(field3d.dims)
outcoords.update(field3d.coords)
for i in py3range(-2,0,1):
for i in py3range(-2, 0, 1):
try:
del outcoords[field3d.dims[i]]
except KeyError:
pass # xarray 0.9
pass # xarray 0.9
outdimnames.remove(field3d.dims[i])
# Need to remove XLAT, XLONG...
delkeys = (key for key,arr in viewitems(field3d.coords)
delkeys = (key for key, arr in viewitems(field3d.coords)
if arr.ndim > 1)
for key in delkeys:
del outcoords[key]
outdimnames.append("line_idx")
#outattrs.update(field3d.attrs)
desc = field3d.attrs.get("description", None)
if desc is not None:
@ -1544,8 +1522,9 @@ def _set_2dxy_meta(wrapped, instance, args, kwargs): @@ -1544,8 +1522,9 @@ def _set_2dxy_meta(wrapped, instance, args, kwargs):
outname = "{0}_2dxy".format(field3d.name)
outcoords["xy_loc"] = ("line_idx", [CoordPair(xy[i,0], xy[i,1])
for i in py3range(xy.shape[-2])])
outcoords["xy_loc"] = ("line_idx",
[CoordPair(xy[i, 0], xy[i, 1])
for i in py3range(xy.shape[-2])])
for key in ("MemoryOrder",):
try:
@ -1597,7 +1576,7 @@ def _set_1d_meta(wrapped, instance, args, kwargs): @@ -1597,7 +1576,7 @@ def _set_1d_meta(wrapped, instance, args, kwargs):
"""
argvars = from_args(wrapped, ("field", "z_in", "z_out", "missingval"),
*args, **kwargs)
*args, **kwargs)
field = argvars["field"]
z_in = argvars["z_in"]
@ -1611,7 +1590,7 @@ def _set_1d_meta(wrapped, instance, args, kwargs): @@ -1611,7 +1590,7 @@ def _set_1d_meta(wrapped, instance, args, kwargs):
outcoords = None
outattrs = OrderedDict()
# Dims are (...,xy,z)
# Dims are (..., xy, z)
if isinstance(field, DataArray):
outcoords = OrderedDict()
outdimnames = list(field.dims)
@ -1824,7 +1803,6 @@ def set_alg_metadata(alg_ndims, refvarname, @@ -1824,7 +1803,6 @@ def set_alg_metadata(alg_ndims, refvarname,
if not xarray_enabled() or not do_meta:
return wrapped(*args, **kwargs)
result = wrapped(*args, **kwargs)
outname = wrapped.__name__
@ -1858,7 +1836,6 @@ def set_alg_metadata(alg_ndims, refvarname, @@ -1858,7 +1836,6 @@ def set_alg_metadata(alg_ndims, refvarname,
if _units is not None:
outattrs["units"] = _units
if description is not None:
if isinstance(description, from_var):
desc = description(wrapped, *args, **kwargs)
@ -1867,7 +1844,6 @@ def set_alg_metadata(alg_ndims, refvarname, @@ -1867,7 +1844,6 @@ def set_alg_metadata(alg_ndims, refvarname,
else:
outattrs["description"] = description
# Copy the dimnames from the reference variable, otherwise, use
# the supplied dimnames
if refvarname is not None:
@ -1878,7 +1854,7 @@ def set_alg_metadata(alg_ndims, refvarname, @@ -1878,7 +1854,7 @@ def set_alg_metadata(alg_ndims, refvarname,
if stagsubvar is not None:
stagvar = from_args(wrapped, (stagsubvar,),
*args, **kwargs)[stagsubvar]
*args, **kwargs)[stagsubvar]
else:
stagvar = None
@ -1909,7 +1885,7 @@ def set_alg_metadata(alg_ndims, refvarname, @@ -1909,7 +1885,7 @@ def set_alg_metadata(alg_ndims, refvarname,
ref_extra = refvar.ndim - refvarndims
ref_left_dimnames = refvar.dims[0:ref_extra]
for i,dimname in enumerate(ref_left_dimnames[::-1], 1):
for i, dimname in enumerate(ref_left_dimnames[::-1], 1):
if i <= result.ndim:
outdims[-alg_ndims - i] = dimname
else:
@ -1960,7 +1936,7 @@ def set_smooth_metdata(): @@ -1960,7 +1936,7 @@ def set_smooth_metdata():
outattrs["missing_value"] = result.fill_value
return DataArray(result, name=outname, coords=outcoords,
dims=outdimnames, attrs=outattrs)
dims=outdimnames, attrs=outattrs)
return func_wrapper
@ -2078,7 +2054,7 @@ def set_cape_alg_metadata(is2d, copyarg="pres_hpa"): @@ -2078,7 +2054,7 @@ def set_cape_alg_metadata(is2d, copyarg="pres_hpa"):
result = wrapped(*args, **kwargs)
argvals = from_args(wrapped, (copyarg,"missing"), *args, **kwargs)
argvals = from_args(wrapped, (copyarg, "missing"), *args, **kwargs)
p = argvals[copyarg]
missing = argvals["missing"]
@ -2094,7 +2070,6 @@ def set_cape_alg_metadata(is2d, copyarg="pres_hpa"): @@ -2094,7 +2070,6 @@ def set_cape_alg_metadata(is2d, copyarg="pres_hpa"):
outattrs = OrderedDict()
if is2d:
if is1d:
outname = "cape_2d"
@ -2114,7 +2089,6 @@ def set_cape_alg_metadata(is2d, copyarg="pres_hpa"): @@ -2114,7 +2089,6 @@ def set_cape_alg_metadata(is2d, copyarg="pres_hpa"):
outattrs["description"] = "cape; cin"
outattrs["units"] = "J kg-1 ; J kg-1"
if isinstance(p, DataArray):
if is2d:
if not is1d:
@ -2131,7 +2105,6 @@ def set_cape_alg_metadata(is2d, copyarg="pres_hpa"): @@ -2131,7 +2105,6 @@ def set_cape_alg_metadata(is2d, copyarg="pres_hpa"):
else:
outdims[1] = p.dims[0]
outcoords = {}
# Left-most is always cape_cin or cape_cin_lcl_lfc
if is2d:
@ -2184,9 +2157,9 @@ def set_cloudfrac_alg_metadata(copyarg="vert"): @@ -2184,9 +2157,9 @@ def set_cloudfrac_alg_metadata(copyarg="vert"):
result = wrapped(*args, **kwargs)
argvals = from_args(wrapped, (copyarg, "low_thresh",
"mid_thresh", "high_thresh",
"missing"),
*args, **kwargs)
"mid_thresh", "high_thresh",
"missing"),
*args, **kwargs)
cp = argvals[copyarg]
low_thresh = argvals["low_thresh"]
mid_thresh = argvals["mid_thresh"]
@ -2214,7 +2187,6 @@ def set_cloudfrac_alg_metadata(copyarg="vert"): @@ -2214,7 +2187,6 @@ def set_cloudfrac_alg_metadata(copyarg="vert"):
# Left dims
outdims[1:-2] = cp.dims[0:-3]
outcoords = {}
# Left-most is always low_mid_high
outdims[0] = "low_mid_high"
@ -2294,8 +2266,3 @@ def set_destag_metadata(): @@ -2294,8 +2266,3 @@ def set_destag_metadata():
return out
return func_wrapper

258
src/wrf/projection.py

@ -54,16 +54,17 @@ if cartopy_enabled(): @@ -54,16 +54,17 @@ if cartopy_enabled():
"""
proj4_params = [("proj", "merc"),
("lon_0", central_longitude),
("lat_ts", latitude_true_scale),
("k", 1),
("units", "m")]
("lon_0", central_longitude),
("lat_ts", latitude_true_scale),
("k", 1),
("units", "m")]
super(crs.Mercator, self).__init__(proj4_params, globe=globe)
# Calculate limits.
limits = self.transform_points(crs.Geodetic(),
np.array([-180, 180]) + central_longitude,
np.array([min_latitude, max_latitude]))
limits = self.transform_points(
crs.Geodetic(),
np.array([-180, 180]) + central_longitude,
np.array([min_latitude, max_latitude]))
# When using a latitude of true scale, the min/max x-limits get set
# to the same value, so make sure the left one is negative
@ -195,7 +196,6 @@ class WrfProj(object): @@ -195,7 +196,6 @@ class WrfProj(object):
if self.stand_lon is None:
self.stand_lon = self._cen_lon
@staticmethod
def _context_equal(x, y, ctx):
"""Return True if both objects are equal based on the provided context.
@ -222,7 +222,7 @@ class WrfProj(object): @@ -222,7 +222,7 @@ class WrfProj(object):
# numpy.float32 or numpy.float64, which Decimal does not know
# how to handle.
if (Decimal(float(x)).normalize(ctx) !=
Decimal(float(y)).normalize(ctx)):
Decimal(float(y)).normalize(ctx)):
return False
else:
if y is not None:
@ -230,7 +230,6 @@ class WrfProj(object): @@ -230,7 +230,6 @@ class WrfProj(object):
return True
def __eq__(self, other):
"""Return True if this projection object is the same as *other*.
@ -254,7 +253,7 @@ class WrfProj(object): @@ -254,7 +253,7 @@ class WrfProj(object):
return (WrfProj._context_equal(self.truelat1, other.truelat1, ctx) and
WrfProj._context_equal(self.truelat2, other.truelat2, ctx) and
WrfProj._context_equal(self.moad_cen_lat, other.moad_cen_lat,
ctx) and
ctx) and
WrfProj._context_equal(self.stand_lon, other.stand_lon,
ctx) and
WrfProj._context_equal(self.pole_lat, other.pole_lat, ctx) and
@ -262,7 +261,6 @@ class WrfProj(object): @@ -262,7 +261,6 @@ class WrfProj(object):
WrfProj._context_equal(self.dx, other.dx, ctx) and
WrfProj._context_equal(self.dy, other.dy, ctx))
def _basemap(self, geobounds, **kwargs):
return None
@ -275,21 +273,19 @@ class WrfProj(object): @@ -275,21 +273,19 @@ class WrfProj(object):
def _calc_extents(self, geobounds):
# Need to modify the extents for the new projection
pc = crs.PlateCarree()
xs, ys, _ = self._cartopy().transform_points(pc,
np.array([geobounds.bottom_left.lon,
geobounds.top_right.lon]),
np.array([geobounds.bottom_left.lat,
geobounds.top_right.lat])).T
xs, ys, _ = self._cartopy().transform_points(
pc,
np.array([geobounds.bottom_left.lon, geobounds.top_right.lon]),
np.array([geobounds.bottom_left.lat, geobounds.top_right.lat])).T
_xlimits = xs.tolist()
_ylimits = ys.tolist()
return (_xlimits, _ylimits)
def _cart_extents(self, geobounds):
try:
_ = len(geobounds)
except TypeError: # Only a single object
except TypeError: # Only a single object
extents = self._calc_extents(geobounds)
else:
extents = np.empty(geobounds.shape, np.object)
@ -327,7 +323,7 @@ class WrfProj(object): @@ -327,7 +323,7 @@ class WrfProj(object):
try:
_ = len(geobounds)
except TypeError:
x_extents= self._cart_extents(geobounds)[0]
x_extents = self._cart_extents(geobounds)[0]
else:
extents = self._cart_extents(geobounds)
x_extents = np.empty(extents.shape, np.object)
@ -352,7 +348,7 @@ class WrfProj(object): @@ -352,7 +348,7 @@ class WrfProj(object):
try:
_ = len(geobounds)
except TypeError:
y_extents= self._cart_extents(geobounds)[1]
y_extents = self._cart_extents(geobounds)[1]
else:
extents = self._cart_extents(geobounds)
y_extents = np.empty(extents.shape, np.object)
@ -529,10 +525,9 @@ class LambertConformal(WrfProj): @@ -529,10 +525,9 @@ class LambertConformal(WrfProj):
if self.truelat2 is not None:
self._std_parallels.append(self.truelat2)
def _cf_params(self):
_cf_params = {}
_cf_params["grid_mapping_name"] = "lambert_conformal_conic";
_cf_params["grid_mapping_name"] = "lambert_conformal_conic"
_cf_params["standard_parallel"] = self._std_parallels
_cf_params["longitude_of_central_meridian"] = self.stand_lon
_cf_params["latitude_of_projection_origin"] = self.moad_cen_lat
@ -540,14 +535,12 @@ class LambertConformal(WrfProj): @@ -540,14 +535,12 @@ class LambertConformal(WrfProj):
return _cf_params
def _pyngl(self, geobounds, **kwargs):
if not pyngl_enabled():
return None
truelat2 = (self.truelat1
if _ismissing(self.truelat2)
else self.truelat2)
truelat2 = (self.truelat1 if _ismissing(self.truelat2)
else self.truelat2)
_pyngl = Resources()
_pyngl.mpProjection = "LambertConformal"
@ -567,22 +560,21 @@ class LambertConformal(WrfProj): @@ -567,22 +560,21 @@ class LambertConformal(WrfProj):
return _pyngl
def _basemap(self, geobounds, **kwargs):
if not basemap_enabled():
return None
local_kwargs = dict(projection = "lcc",
lon_0 = self.stand_lon,
lat_0 = self.moad_cen_lat,
lat_1 = self.truelat1,
lat_2 = self.truelat2,
llcrnrlat = geobounds.bottom_left.lat,
urcrnrlat = geobounds.top_right.lat,
llcrnrlon = geobounds.bottom_left.lon,
urcrnrlon = geobounds.top_right.lon,
rsphere = Constants.WRF_EARTH_RADIUS,
resolution = 'l')
local_kwargs = dict(projection="lcc",
lon_0=self.stand_lon,
lat_0=self.moad_cen_lat,
lat_1=self.truelat1,
lat_2=self.truelat2,
llcrnrlat=geobounds.bottom_left.lat,
urcrnrlat=geobounds.top_right.lat,
llcrnrlon=geobounds.bottom_left.lon,
urcrnrlon=geobounds.top_right.lon,
rsphere=Constants.WRF_EARTH_RADIUS,
resolution='l')
local_kwargs.update(kwargs)
_basemap = Basemap(**local_kwargs)
@ -597,11 +589,11 @@ class LambertConformal(WrfProj): @@ -597,11 +589,11 @@ class LambertConformal(WrfProj):
cutoff = -30.0 if self.moad_cen_lat >= 0 else 30.0
_cartopy = crs.LambertConformal(
central_longitude = self.stand_lon,
central_latitude = self.moad_cen_lat,
standard_parallels = self._std_parallels,
globe = self._globe(),
cutoff = cutoff)
central_longitude=self.stand_lon,
central_latitude=self.moad_cen_lat,
standard_parallels=self._std_parallels,
globe=self._globe(),
cutoff=cutoff)
return _cartopy
@ -612,12 +604,12 @@ class LambertConformal(WrfProj): @@ -612,12 +604,12 @@ class LambertConformal(WrfProj):
_proj4 = ("+proj=lcc +units=meters +a={} +b={} +lat_1={} "
"+lat_2={} +lat_0={} +lon_0={} +nadgrids=@null".format(
Constants.WRF_EARTH_RADIUS,
Constants.WRF_EARTH_RADIUS,
self.truelat1,
truelat2,
self.moad_cen_lat,
self.stand_lon))
Constants.WRF_EARTH_RADIUS,
Constants.WRF_EARTH_RADIUS,
self.truelat1,
truelat2,
self.moad_cen_lat,
self.stand_lon))
return _proj4
@ -650,16 +642,14 @@ class Mercator(WrfProj): @@ -650,16 +642,14 @@ class Mercator(WrfProj):
"""
super(Mercator, self).__init__(**proj_params)
self._lat_ts = (None
if self.truelat1 == 0. or _ismissing(self.truelat1)
self._lat_ts = (
None if self.truelat1 == 0. or _ismissing(self.truelat1)
else self.truelat1)
self._stand_lon = (0. if _ismissing(self.stand_lon, islat=False)
else self.stand_lon)
def _cf_params(self):
_cf_params = {}
_cf_params["grid_mapping_name"] = "mercator"
_cf_params["longitude_of_projection_origin"] = self.stand_lon
@ -667,7 +657,6 @@ class Mercator(WrfProj): @@ -667,7 +657,6 @@ class Mercator(WrfProj):
return _cf_params
def _pyngl(self, geobounds, **kwargs):
if not pyngl_enabled():
return None
@ -689,46 +678,40 @@ class Mercator(WrfProj): @@ -689,46 +678,40 @@ class Mercator(WrfProj):
return _pyngl
def _basemap(self, geobounds, **kwargs):
if not basemap_enabled():
return None
local_kwargs = dict(projection = "merc",
lon_0 = self._stand_lon,
lat_0 = self.moad_cen_lat,
lat_ts = self._lat_ts,
llcrnrlat = geobounds.bottom_left.lat,
urcrnrlat = geobounds.top_right.lat,
llcrnrlon = geobounds.bottom_left.lon,
urcrnrlon = geobounds.top_right.lon,
rsphere = Constants.WRF_EARTH_RADIUS,
resolution = "l")
local_kwargs = dict(projection="merc",
lon_0=self._stand_lon,
lat_0=self.moad_cen_lat,
lat_ts=self._lat_ts,
llcrnrlat=geobounds.bottom_left.lat,
urcrnrlat=geobounds.top_right.lat,
llcrnrlon=geobounds.bottom_left.lon,
urcrnrlon=geobounds.top_right.lon,
rsphere=Constants.WRF_EARTH_RADIUS,
resolution="l")
local_kwargs.update(kwargs)
_basemap = Basemap(**local_kwargs)
return _basemap
def _cartopy(self):
if not cartopy_enabled():
return None
if self._lat_ts == 0.0:
_cartopy = crs.Mercator(
central_longitude = self._stand_lon,
globe = self._globe())
_cartopy = crs.Mercator(central_longitude=self._stand_lon,
globe=self._globe())
else:
_cartopy = MercatorWithLatTS(
central_longitude = self._stand_lon,
latitude_true_scale = self._lat_ts,
globe = self._globe())
_cartopy = MercatorWithLatTS(central_longitude=self._stand_lon,
latitude_true_scale=self._lat_ts,
globe=self._globe())
return _cartopy
def _proj4(self):
_proj4 = ("+proj=merc +units=meters +a={} +b={} "
@ -740,6 +723,7 @@ class Mercator(WrfProj): @@ -740,6 +723,7 @@ class Mercator(WrfProj):
return _proj4
class PolarStereographic(WrfProj):
"""A :class:`wrf.WrfProj` subclass for Polar Stereographic projections.
@ -750,7 +734,6 @@ class PolarStereographic(WrfProj): @@ -750,7 +734,6 @@ class PolarStereographic(WrfProj):
:class:`Mercator`, :class:`LambertConformal`
"""
def __init__(self, **proj_params):
"""Initialize a :class:`wrf.PolarStereographic` object.
@ -770,10 +753,7 @@ class PolarStereographic(WrfProj): @@ -770,10 +753,7 @@ class PolarStereographic(WrfProj):
"""
super(PolarStereographic, self).__init__(**proj_params)
self._hemi = -90. if self.truelat1 < 0 else 90.
self._lat_ts = (None
if _ismissing(self.truelat1)
else self.truelat1)
self._lat_ts = (None if _ismissing(self.truelat1) else self.truelat1)
def _cf_params(self):
_cf_params = {}
@ -785,7 +765,6 @@ class PolarStereographic(WrfProj): @@ -785,7 +765,6 @@ class PolarStereographic(WrfProj):
return _cf_params
def _pyngl(self, geobounds, **kwargs):
if not pyngl_enabled():
return None
@ -811,39 +790,36 @@ class PolarStereographic(WrfProj): @@ -811,39 +790,36 @@ class PolarStereographic(WrfProj):
return _pyngl
def _basemap(self, geobounds, **kwargs):
if not basemap_enabled():
return None
local_kwargs = dict(projection = "stere",
lon_0 = self.stand_lon,
lat_0 = self._hemi,
lat_ts = self._lat_ts,
llcrnrlat = geobounds.bottom_left.lat,
urcrnrlat = geobounds.top_right.lat,
llcrnrlon = geobounds.bottom_left.lon,
urcrnrlon = geobounds.top_right.lon,
rsphere = Constants.WRF_EARTH_RADIUS,
resolution = "l")
local_kwargs = dict(projection="stere",
lon_0=self.stand_lon,
lat_0=self._hemi,
lat_ts=self._lat_ts,
llcrnrlat=geobounds.bottom_left.lat,
urcrnrlat=geobounds.top_right.lat,
llcrnrlon=geobounds.bottom_left.lon,
urcrnrlon=geobounds.top_right.lon,
rsphere=Constants.WRF_EARTH_RADIUS,
resolution="l")
local_kwargs.update(kwargs)
_basemap = Basemap(**local_kwargs)
return _basemap
def _cartopy(self):
if not cartopy_enabled():
return None
_cartopy = crs.Stereographic(central_latitude=self._hemi,
central_longitude=self.stand_lon,
true_scale_latitude=self._lat_ts,
globe=self._globe())
central_longitude=self.stand_lon,
true_scale_latitude=self._lat_ts,
globe=self._globe())
return _cartopy
def _proj4(self):
_proj4 = ("+proj=stere +units=meters +a={} +b={} "
"+lat0={} +lon_0={} +lat_ts={} +nadgrids=@null".format(
@ -856,7 +832,6 @@ class PolarStereographic(WrfProj): @@ -856,7 +832,6 @@ class PolarStereographic(WrfProj):
return _proj4
class LatLon(WrfProj):
"""A :class:`wrf.WrfProj` subclass for Lat Lon projections.
@ -886,13 +861,11 @@ class LatLon(WrfProj): @@ -886,13 +861,11 @@ class LatLon(WrfProj):
"""
super(LatLon, self).__init__(**proj_params)
def _cf_params(self):
_cf_params = {}
_cf_params["grid_mapping_name"] = "latitude_longitude"
return _cf_params
def _pyngl(self, geobounds, **kwargs):
if not pyngl_enabled():
return None
@ -914,27 +887,25 @@ class LatLon(WrfProj): @@ -914,27 +887,25 @@ class LatLon(WrfProj):
return _pyngl
def _basemap(self, geobounds, **kwargs):
if not basemap_enabled():
return None
local_kwargs = dict(projection = "cyl",
lon_0 = self.stand_lon,
lat_0 = self.moad_cen_lat,
llcrnrlat = geobounds.bottom_left.lat,
urcrnrlat = geobounds.top_right.lat,
llcrnrlon = geobounds.bottom_left.lon,
urcrnrlon = geobounds.top_right.lon,
rsphere = Constants.WRF_EARTH_RADIUS,
resolution = "l")
local_kwargs = dict(projection="cyl",
lon_0=self.stand_lon,
lat_0=self.moad_cen_lat,
llcrnrlat=geobounds.bottom_left.lat,
urcrnrlat=geobounds.top_right.lat,
llcrnrlon=geobounds.bottom_left.lon,
urcrnrlon=geobounds.top_right.lon,
rsphere=Constants.WRF_EARTH_RADIUS,
resolution="l")
local_kwargs.update(kwargs)
_basemap = Basemap(**local_kwargs)
return _basemap
def _cartopy(self):
if not cartopy_enabled():
return None
@ -944,19 +915,19 @@ class LatLon(WrfProj): @@ -944,19 +915,19 @@ class LatLon(WrfProj):
return _cartopy
def _cart_extents(self, geobounds):
return ([geobounds.bottom_left.lon, geobounds.top_right.lon],
[geobounds.bottom_left.lat, geobounds.top_right.lat])
def _proj4(self):
_proj4 = ("+proj=eqc +units=meters +a={} +b={} "
"+lon_0={} +nadgrids=@null".format(Constants.WRF_EARTH_RADIUS,
Constants.WRF_EARTH_RADIUS,
self.stand_lon))
"+lon_0={} +nadgrids=@null".format(
Constants.WRF_EARTH_RADIUS,
Constants.WRF_EARTH_RADIUS,
self.stand_lon))
return _proj4
# Notes (may not be correct since this projection confuses me):
# Each projection system handles this differently.
# 1) In WRF, if following the WPS instructions, POLE_LON is mainly used to
@ -1036,29 +1007,28 @@ class RotatedLatLon(WrfProj): @@ -1036,29 +1007,28 @@ class RotatedLatLon(WrfProj):
if self.pole_lat is not None and self.stand_lon is not None:
self._pyngl_cen_lat = (90. - self.pole_lat if self._north
else self.pole_lat - 90.0)
else self.pole_lat - 90.0)
self._pyngl_cen_lon = (-self.stand_lon if self._north
else 180.0 - self.stand_lon)
else 180.0 - self.stand_lon)
self._bm_lon_0 = (-self.stand_lon if self._north
else 180.0 - self.stand_lon)
self._bm_cart_pole_lat = (self.pole_lat if self._north
else -self.pole_lat )
else -self.pole_lat)
# The important point is that pole longitude is the position
# of the dateline of the new projection, not its central
# longitude (per the creator of cartopy). This is based on
# how it's handled by agencies like WMO, but not proj4.
self._cart_pole_lon = (-self.stand_lon - 180.0 if self._north
else -self.stand_lon)
else -self.stand_lon)
else:
self._pyngl_cen_lat = self.moad_cen_lat
self._pyngl_cen_lon = self.stand_lon
self._bm_cart_pole_lat = (90.0 - self.moad_cen_lat if self._north
else -90.0 - self.moad_cen_lat)
else -90.0 - self.moad_cen_lat)
self._bm_lon_0 = (-self.stand_lon if self._north
else 180.0 - self.stand_lon)
self._cart_pole_lon = (-self.stand_lon - 180.0 if self._north
else -self.stand_lon)
else -self.stand_lon)
def _cf_params(self):
_cf_params = {}
@ -1070,7 +1040,6 @@ class RotatedLatLon(WrfProj): @@ -1070,7 +1040,6 @@ class RotatedLatLon(WrfProj):
return _cf_params
def _pyngl(self, geobounds, **kwargs):
if not pyngl_enabled():
return None
@ -1092,38 +1061,35 @@ class RotatedLatLon(WrfProj): @@ -1092,38 +1061,35 @@ class RotatedLatLon(WrfProj):
return _pyngl
def _basemap(self, geobounds, **kwargs):
if not basemap_enabled():
return None
local_kwargs = dict(projection = "rotpole",
o_lat_p = self._bm_cart_pole_lat,
o_lon_p = self.pole_lon,
llcrnrlat = geobounds.bottom_left.lat,
urcrnrlat = geobounds.top_right.lat,
llcrnrlon = geobounds.bottom_left.lon,
urcrnrlon = geobounds.top_right.lon,
lon_0 = self._bm_lon_0,
rsphere = Constants.WRF_EARTH_RADIUS,
resolution = "l")
local_kwargs = dict(projection="rotpole",
o_lat_p=self._bm_cart_pole_lat,
o_lon_p=self.pole_lon,
llcrnrlat=geobounds.bottom_left.lat,
urcrnrlat=geobounds.top_right.lat,
llcrnrlon=geobounds.bottom_left.lon,
urcrnrlon=geobounds.top_right.lon,
lon_0=self._bm_lon_0,
rsphere=Constants.WRF_EARTH_RADIUS,
resolution="l")
local_kwargs.update(kwargs)
_basemap = Basemap(**local_kwargs)
return _basemap
def _cartopy(self):
if not cartopy_enabled():
return None
_cartopy = crs.RotatedPole(
pole_longitude=self._cart_pole_lon,
pole_latitude=self._bm_cart_pole_lat,
central_rotated_longitude=(
180.0 - self.pole_lon), # Probably
globe = self._globe())
_cartopy = crs.RotatedPole(pole_longitude=self._cart_pole_lon,
pole_latitude=self._bm_cart_pole_lat,
central_rotated_longitude=(
180.0 - self.pole_lon), # Probably
globe=self._globe())
return _cartopy
def _proj4(self):
@ -1138,6 +1104,7 @@ class RotatedLatLon(WrfProj): @@ -1138,6 +1104,7 @@ class RotatedLatLon(WrfProj):
return _proj4
def getproj(**proj_params):
"""Return a :class:`wrf.WrfProj` subclass.
@ -1164,7 +1131,6 @@ def getproj(**proj_params): @@ -1164,7 +1131,6 @@ def getproj(**proj_params):
specified map projection parameters.
"""
up_proj_params = dict_keys_to_upper(proj_params)
proj_type = up_proj_params.get("MAP_PROJ", 0)
@ -1177,12 +1143,10 @@ def getproj(**proj_params): @@ -1177,12 +1143,10 @@ def getproj(**proj_params):
elif (proj_type == ProjectionTypes.ZERO or
proj_type == ProjectionTypes.LAT_LON):
if (up_proj_params.get("POLE_LAT", None) == 90.
and up_proj_params.get("POLE_LON", None) == 0.):
and up_proj_params.get("POLE_LON", None) == 0.):
return LatLon(**proj_params)
else:
return RotatedLatLon(**proj_params)
else:
# Unknown projection
return WrfProj(**proj_params)

3
src/wrf/projutils.py

@ -2,6 +2,7 @@ from __future__ import (absolute_import, division, print_function) @@ -2,6 +2,7 @@ from __future__ import (absolute_import, division, print_function)
from .py3compat import viewitems
def dict_keys_to_upper(d):
"""Return a dictionary with the keys changed to uppercase.
@ -14,4 +15,4 @@ def dict_keys_to_upper(d): @@ -14,4 +15,4 @@ def dict_keys_to_upper(d):
:obj:`dict`: A dictionary with uppercase keys.
"""
return {key.upper() : val for key, val in viewitems(d)}
return {key.upper(): val for key, val in viewitems(d)}

4
src/wrf/py3compat.py

@ -3,6 +3,7 @@ from __future__ import (absolute_import, division, print_function) @@ -3,6 +3,7 @@ from __future__ import (absolute_import, division, print_function)
from sys import version_info
from math import floor, copysign
# Dictionary python 2-3 compatibility stuff
def viewitems(d):
"""Return either the items or viewitems method for a dictionary.
@ -57,6 +58,7 @@ def viewvalues(d): @@ -57,6 +58,7 @@ def viewvalues(d):
func = d.values
return func()
def isstr(s):
"""Return True if the object is a string type.
@ -165,5 +167,3 @@ def ucode(*args, **kwargs): @@ -165,5 +167,3 @@ def ucode(*args, **kwargs):
return str(*args, **kwargs)
return unicode(*args, **kwargs)

325
src/wrf/routines.py

@ -16,16 +16,17 @@ from .g_pressure import get_pressure, get_pressure_hpa @@ -16,16 +16,17 @@ from .g_pressure import get_pressure, get_pressure_hpa
from .g_pw import get_pw
from .g_rh import get_rh, get_rh_2m
from .g_slp import get_slp
from .g_temp import get_tc, get_eth, get_temp, get_theta, get_tk, get_tv, get_tw
from .g_temp import (get_tc, get_eth, get_temp, get_theta, get_tk, get_tv,
get_tw)
from .g_terrain import get_terrain
from .g_uvmet import (get_uvmet, get_uvmet10, get_uvmet10_wspd_wdir,
get_uvmet_wspd_wdir, get_uvmet_wspd, get_uvmet_wdir,
get_uvmet10_wspd, get_uvmet10_wdir)
from .g_vorticity import get_avo, get_pvo
from .g_wind import (get_destag_wspd_wdir, get_destag_wspd_wdir10,
get_u_destag, get_v_destag, get_w_destag,
get_destag_wspd, get_destag_wdir, get_destag_wspd10,
get_destag_wdir10)
get_u_destag, get_v_destag, get_w_destag,
get_destag_wspd, get_destag_wdir, get_destag_wspd10,
get_destag_wdir10)
from .g_times import get_times, get_xtimes
from .g_cloudfrac import (get_cloudfrac, get_low_cloudfrac, get_mid_cloudfrac,
get_high_cloudfrac)
@ -33,167 +34,168 @@ from .g_cloudfrac import (get_cloudfrac, get_low_cloudfrac, get_mid_cloudfrac, @@ -33,167 +34,168 @@ from .g_cloudfrac import (get_cloudfrac, get_low_cloudfrac, get_mid_cloudfrac,
# func is the function to call. kargs are required arguments that should
# not be altered by the user
_FUNC_MAP = {"cape2d" : get_2dcape,
"cape3d" : get_3dcape,
"dbz" : get_dbz,
"maxdbz" : get_max_dbz,
"dp" : get_dp,
"dp2m" : get_dp_2m,
"height" : get_height,
"geopt" : get_geopt,
"srh" : get_srh,
"uhel" : get_uh,
"omega" : get_omega,
"pw" : get_pw,
"rh" : get_rh,
"rh2m" : get_rh_2m,
"slp" : get_slp,
"theta" : get_theta,
"temp" : get_temp,
"tk" : get_tk,
"tc" : get_tc,
"theta_e" : get_eth,
"tv" : get_tv,
"twb" : get_tw,
"terrain" : get_terrain,
"times" : get_times,
"xtimes" : get_xtimes,
"uvmet" : get_uvmet,
"uvmet10" : get_uvmet10,
"avo" : get_avo,
"pvo" : get_pvo,
"ua" : get_u_destag,
"va" : get_v_destag,
"wa" : get_w_destag,
"lat" : get_lat,
"lon" : get_lon,
"pressure" : get_pressure_hpa,
"pres" : get_pressure,
"wspd_wdir" : get_destag_wspd_wdir,
"wspd_wdir10" : get_destag_wspd_wdir10,
"uvmet_wspd_wdir" : get_uvmet_wspd_wdir,
"uvmet10_wspd_wdir" : get_uvmet10_wspd_wdir,
"ctt" : get_ctt,
"cloudfrac" : get_cloudfrac,
"geopt_stag" : get_stag_geopt,
"zstag" : get_stag_height,
_FUNC_MAP = {"cape2d": get_2dcape,
"cape3d": get_3dcape,
"dbz": get_dbz,
"maxdbz": get_max_dbz,
"dp": get_dp,
"dp2m": get_dp_2m,
"height": get_height,
"geopt": get_geopt,
"srh": get_srh,
"uhel": get_uh,
"omega": get_omega,
"pw": get_pw,
"rh": get_rh,
"rh2m": get_rh_2m,
"slp": get_slp,
"theta": get_theta,
"temp": get_temp,
"tk": get_tk,
"tc": get_tc,
"theta_e": get_eth,
"tv": get_tv,
"twb": get_tw,
"terrain": get_terrain,
"times": get_times,
"xtimes": get_xtimes,
"uvmet": get_uvmet,
"uvmet10": get_uvmet10,
"avo": get_avo,
"pvo": get_pvo,
"ua": get_u_destag,
"va": get_v_destag,
"wa": get_w_destag,
"lat": get_lat,
"lon": get_lon,
"pressure": get_pressure_hpa,
"pres": get_pressure,
"wspd_wdir": get_destag_wspd_wdir,
"wspd_wdir10": get_destag_wspd_wdir10,
"uvmet_wspd_wdir": get_uvmet_wspd_wdir,
"uvmet10_wspd_wdir": get_uvmet10_wspd_wdir,
"ctt": get_ctt,
"cloudfrac": get_cloudfrac,
"geopt_stag": get_stag_geopt,
"zstag": get_stag_height,
# Diagnostics below are extracted from multi-product diagnostics
"cape2d_only" : get_cape2d_only,
"cin2d_only" : get_cin2d_only,
"lcl" : get_lcl,
"lfc" : get_lfc,
"cape3d_only" : get_3dcape_only,
"cape2d_only": get_cape2d_only,
"cin2d_only": get_cin2d_only,
"lcl": get_lcl,
"lfc": get_lfc,
"cape3d_only": get_3dcape_only,
"cin3d_only": get_3dcin_only,
"uvmet_wspd" : get_uvmet_wspd,
"uvmet_wdir" : get_uvmet_wdir,
"uvmet10_wspd" : get_uvmet10_wspd,
"uvmet10_wdir" : get_uvmet10_wdir,
"wspd" : get_destag_wspd,
"wdir" : get_destag_wdir,
"wspd10" : get_destag_wspd10,
"wdir10" : get_destag_wdir10,
"low_cloudfrac" : get_low_cloudfrac,
"mid_cloudfrac" : get_mid_cloudfrac,
"high_cloudfrac" : get_high_cloudfrac
"uvmet_wspd": get_uvmet_wspd,
"uvmet_wdir": get_uvmet_wdir,
"uvmet10_wspd": get_uvmet10_wspd,
"uvmet10_wdir": get_uvmet10_wdir,
"wspd": get_destag_wspd,
"wdir": get_destag_wdir,
"wspd10": get_destag_wspd10,
"wdir10": get_destag_wdir10,
"low_cloudfrac": get_low_cloudfrac,
"mid_cloudfrac": get_mid_cloudfrac,
"high_cloudfrac": get_high_cloudfrac
}
_VALID_KARGS = {"cape2d" : ["missing"],
"cape3d" : ["missing"],
"dbz" : ["do_variant", "do_liqskin"],
"maxdbz" : ["do_variant", "do_liqskin"],
"dp" : ["units"],
"dp2m" : ["units"],
"height" : ["msl", "units"],
"geopt" : [],
"srh" : ["top"],
"uhel" : ["bottom", "top"],
"omega" : [],
"pw" : [],
"rh" : [],
"rh2m" : [],
"slp" : ["units"],
"temp" : ["units"],
"tk" : [],
"tc" : [],
"theta" : ["units"],
"theta_e" : ["units"],
"tv" : ["units"],
"twb" : ["units"],
"terrain" : ["units"],
"times" : [],
"xtimes" : [],
"uvmet" : ["units"],
"uvmet10" : ["units"],
"avo" : [],
"pvo" : [],
"ua" : ["units"],
"va" : ["units"],
"wa" : ["units"],
"lat" : [],
"lon" : [],
"pres" : ["units"],
"pressure" : ["units"],
"wspd_wdir" : ["units"],
"wspd_wdir10" : ["units"],
"uvmet_wspd_wdir" : ["units"],
"uvmet10_wspd_wdir" : ["units"],
"ctt" : ["fill_nocloud", "missing", "opt_thresh", "units"],
"cloudfrac" : ["vert_type", "low_thresh",
"mid_thresh", "high_thresh"],
"geopt_stag" : [],
"zstag" : ["msl", "units"],
"cape2d_only" : ["missing"],
"cin2d_only" : ["missing"],
"lcl" : ["missing"],
"lfc" : ["missing"],
"cape3d_only" : ["missing"],
"cin3d_only": ["missing"],
"uvmet_wspd" : ["units"],
"uvmet_wdir" : ["units"],
"uvmet10_wspd" : ["units"],
"uvmet10_wdir" : ["units"],
"wspd" : ["units"],
"wdir" : ["units"],
"wspd10" : ["units"],
"wdir10" : ["units"],
"low_cloudfrac" : ["vert_type", "low_thresh",
"mid_thresh", "high_thresh"],
"mid_cloudfrac" : ["vert_type", "low_thresh",
"mid_thresh", "high_thresh"],
"high_cloudfrac" : ["vert_type", "low_thresh",
"mid_thresh", "high_thresh"],
"default" : []
}
_ALIASES = {"cape_2d" : "cape2d",
"cape_3d" : "cape3d",
"eth" : "theta_e",
"mdbz" : "maxdbz",
"geopotential" : "geopt",
"helicity" : "srh",
"latitude" : "lat",
"longitude" : "lon",
"omg" : "omega",
"p" : "pres",
"rh2" : "rh2m",
_VALID_KARGS = {"cape2d": ["missing"],
"cape3d": ["missing"],
"dbz": ["do_variant", "do_liqskin"],
"maxdbz": ["do_variant", "do_liqskin"],
"dp": ["units"],
"dp2m": ["units"],
"height": ["msl", "units"],
"geopt": [],
"srh": ["top"],
"uhel": ["bottom", "top"],
"omega": [],
"pw": [],
"rh": [],
"rh2m": [],
"slp": ["units"],
"temp": ["units"],
"tk": [],
"tc": [],
"theta": ["units"],
"theta_e": ["units"],
"tv": ["units"],
"twb": ["units"],
"terrain": ["units"],
"times": [],
"xtimes": [],
"uvmet": ["units"],
"uvmet10": ["units"],
"avo": [],
"pvo": [],
"ua": ["units"],
"va": ["units"],
"wa": ["units"],
"lat": [],
"lon": [],
"pres": ["units"],
"pressure": ["units"],
"wspd_wdir": ["units"],
"wspd_wdir10": ["units"],
"uvmet_wspd_wdir": ["units"],
"uvmet10_wspd_wdir": ["units"],
"ctt": ["fill_nocloud", "missing", "opt_thresh", "units"],
"cloudfrac": ["vert_type", "low_thresh",
"mid_thresh", "high_thresh"],
"geopt_stag": [],
"zstag": ["msl", "units"],
"cape2d_only": ["missing"],
"cin2d_only": ["missing"],
"lcl": ["missing"],
"lfc": ["missing"],
"cape3d_only": ["missing"],
"cin3d_only": ["missing"],
"uvmet_wspd": ["units"],
"uvmet_wdir": ["units"],
"uvmet10_wspd": ["units"],
"uvmet10_wdir": ["units"],
"wspd": ["units"],
"wdir": ["units"],
"wspd10": ["units"],
"wdir10": ["units"],
"low_cloudfrac": ["vert_type", "low_thresh",
"mid_thresh", "high_thresh"],
"mid_cloudfrac": ["vert_type", "low_thresh",
"mid_thresh", "high_thresh"],
"high_cloudfrac": ["vert_type", "low_thresh",
"mid_thresh", "high_thresh"],
"default": []
}
_ALIASES = {"cape_2d": "cape2d",
"cape_3d": "cape3d",
"eth": "theta_e",
"mdbz": "maxdbz",
"geopotential": "geopt",
"helicity": "srh",
"latitude": "lat",
"longitude": "lon",
"omg": "omega",
"p": "pres",
"rh2": "rh2m",
"z": "height",
"ter" : "terrain",
"updraft_helicity" : "uhel",
"td" : "dp",
"td2" : "dp2m",
"cfrac" : "cloudfrac",
"wspd_wdir_uvmet" : "uvmet_wspd_wdir",
"wspd_wdir_uvmet10" : "uvmet10_wspd_wdir",
"th" : "theta",
"low_cfrac" : "low_cloudfrac",
"mid_cfrac" : "mid_cloudfrac",
"high_cfrac" : "high_cloudfrac",
"wspd_uvmet" : "uvmet_wspd" ,
"wdir_uvmet" : "uvmet_wdir" ,
"wspd_uvmet10" : "uvmet10_wspd" ,
"wdir_uvmet10" : "uvmet10_wdir" ,
"ter": "terrain",
"updraft_helicity": "uhel",
"td": "dp",
"td2": "dp2m",
"cfrac": "cloudfrac",
"wspd_wdir_uvmet": "uvmet_wspd_wdir",
"wspd_wdir_uvmet10": "uvmet10_wspd_wdir",
"th": "theta",
"low_cfrac": "low_cloudfrac",
"mid_cfrac": "mid_cloudfrac",
"high_cfrac": "high_cloudfrac",
"wspd_uvmet": "uvmet_wspd",
"wdir_uvmet": "uvmet_wdir",
"wspd_uvmet10": "uvmet10_wspd",
"wdir_uvmet10": "uvmet10_wdir",
}
class ArgumentError(Exception):
def __init__(self, msg):
self.msg = msg
@ -201,6 +203,7 @@ class ArgumentError(Exception): @@ -201,6 +203,7 @@ class ArgumentError(Exception):
def __str__(self):
return self.msg
def _undo_alias(alias):
actual = _ALIASES.get(alias, None)
if actual is None:
@ -208,12 +211,13 @@ def _undo_alias(alias): @@ -208,12 +211,13 @@ def _undo_alias(alias):
else:
return actual
def _check_kargs(var, kargs):
for arg in viewkeys(kargs):
if arg not in _VALID_KARGS[var]:
if var != "default":
raise ValueError("'{}' is an invalid keyword "
"argument for '{}'".format(arg, var))
"argument for '{}'".format(arg, var))
else:
raise ValueError("'{}' is an invalid keyword "
"argument".format(arg))
@ -340,10 +344,9 @@ def getvar(wrfin, varname, timeidx=0, @@ -340,10 +344,9 @@ def getvar(wrfin, varname, timeidx=0,
actual_var = _undo_alias(varname)
if actual_var not in _VALID_KARGS:
raise ValueError("'%s' is not a valid variable name" % (varname))
raise ValueError("'{}' is not a valid variable name".format(varname))
_check_kargs(actual_var, kwargs)
return _FUNC_MAP[actual_var](wrfin, timeidx, method, squeeze, cache,
meta, _key, **kwargs)

85
src/wrf/specialdec.py

@ -43,7 +43,7 @@ def uvmet_left_iter(alg_dtype=np.float64): @@ -43,7 +43,7 @@ def uvmet_left_iter(alg_dtype=np.float64):
v = args[1]
lat = args[2]
lon = args[3]
cen_long = args[4]
cen_long = args[4]
cone = args[5]
orig_dtype = u.dtype
@ -62,12 +62,12 @@ def uvmet_left_iter(alg_dtype=np.float64): @@ -62,12 +62,12 @@ def uvmet_left_iter(alg_dtype=np.float64):
raise ValueError("number of 'lat' dimensions is greater than 'u'")
if lat_lon_fixed:
mode = 0 # fixed lat/lon
mode = 0 # fixed lat/lon
else:
if num_left_dims_u == num_left_dims_lat:
mode = 1 # lat/lon same as u
mode = 1 # lat/lon same as u
else:
mode = 2 # probably 3D with 2D lat/lon plus Time
mode = 2 # probably 3D with 2D lat/lon plus Time
has_missing = False
u_arr = to_np(u)
@ -99,8 +99,6 @@ def uvmet_left_iter(alg_dtype=np.float64): @@ -99,8 +99,6 @@ def uvmet_left_iter(alg_dtype=np.float64):
if (u.shape[-1] == lat.shape[-1] or u.shape[-2] == lat.shape[-2]):
raise ValueError("v is staggered but u is not")
# No special left side iteration, return the function result
if (num_left_dims_u == 0):
return wrapped(u, v, lat, lon, cen_long, cone, isstag=is_stag,
@ -109,7 +107,7 @@ def uvmet_left_iter(alg_dtype=np.float64): @@ -109,7 +107,7 @@ def uvmet_left_iter(alg_dtype=np.float64):
# Initial output is time,nz,2,ny,nx to create contiguous views
outdims = u.shape[0:num_left_dims_u]
extra_dims = tuple(outdims) # Copy the left-most dims for iteration
extra_dims = tuple(outdims) # Copy the left-most dims for iteration
outdims += (2,)
@ -132,15 +130,14 @@ def uvmet_left_iter(alg_dtype=np.float64): @@ -132,15 +130,14 @@ def uvmet_left_iter(alg_dtype=np.float64):
lat_left_and_slice = left_and_slice_idxs
elif mode == 2:
# Only need the left-most
lat_left_and_slice = tuple(left_idx
for left_idx in left_idxs[0:num_left_dims_lat])
lat_left_and_slice = tuple(
left_idx for left_idx in left_idxs[0:num_left_dims_lat])
u_output_idxs = (0,) + left_idxs + (slice(None),)
v_output_idxs = (1,) + left_idxs + (slice(None),)
u_view_idxs = left_idxs + (0, slice(None))
v_view_idxs = left_idxs + (1, slice(None))
new_u = u[left_and_slice_idxs]
new_v = v[left_and_slice_idxs]
new_lat = lat[lat_left_and_slice]
@ -170,7 +167,7 @@ def uvmet_left_iter(alg_dtype=np.float64): @@ -170,7 +167,7 @@ def uvmet_left_iter(alg_dtype=np.float64):
# Make sure the result is the same data as what got passed in
# Can delete this once everything works
if (result.__array_interface__["data"][0] !=
outview.__array_interface__["data"][0]):
outview.__array_interface__["data"][0]):
raise RuntimeError("output array was copied")
output[u_output_idxs] = (
@ -186,7 +183,6 @@ def uvmet_left_iter(alg_dtype=np.float64): @@ -186,7 +183,6 @@ def uvmet_left_iter(alg_dtype=np.float64):
return func_wrapper
def cape_left_iter(alg_dtype=np.float64):
"""A decorator to handle iterating over the leftmost dimensions for the
cape diagnostic.
@ -250,10 +246,10 @@ def cape_left_iter(alg_dtype=np.float64): @@ -250,10 +246,10 @@ def cape_left_iter(alg_dtype=np.float64):
if p_hpa[bot_idxs] > p_hpa[top_idxs]:
flip = True
p_hpa = np.ascontiguousarray(p_hpa[...,::-1,:,:])
tk = np.ascontiguousarray(tk[...,::-1,:,:])
qv = np.ascontiguousarray(qv[...,::-1,:,:])
ht = np.ascontiguousarray(ht[...,::-1,:,:])
p_hpa = np.ascontiguousarray(p_hpa[..., ::-1, :, :])
tk = np.ascontiguousarray(tk[..., ::-1, :, :])
qv = np.ascontiguousarray(qv[..., ::-1, :, :])
ht = np.ascontiguousarray(ht[..., ::-1, :, :])
new_args[0] = p_hpa
new_args[1] = tk
new_args[2] = qv
@ -279,8 +275,8 @@ def cape_left_iter(alg_dtype=np.float64): @@ -279,8 +275,8 @@ def cape_left_iter(alg_dtype=np.float64):
new_args[1] = tk.reshape((1, 1, tk.shape[0]), order='F')
new_args[2] = qv.reshape((1, 1, qv.shape[0]), order='F')
new_args[3] = ht.reshape((1, 1, ht.shape[0]), order='F')
new_args[4] = np.full((1,1), ter, orig_dtype)
new_args[5] = np.full((1,1), sfp, orig_dtype)
new_args[4] = np.full((1, 1), ter, orig_dtype)
new_args[5] = np.full((1, 1), sfp, orig_dtype)
num_left_dims = 0
@ -298,19 +294,19 @@ def cape_left_iter(alg_dtype=np.float64): @@ -298,19 +294,19 @@ def cape_left_iter(alg_dtype=np.float64):
output = np.empty(output_dims, orig_dtype)
if flip and not is2d:
output[0,:] = cape[::-1,:,:]
output[1,:] = cin[::-1,:,:]
output[0, :] = cape[::-1, :, :]
output[1, :] = cin[::-1, :, :]
else:
output[0,:] = cape[:]
output[1,:] = cin[:]
output[0, :] = cape[:]
output[1, :] = cin[:]
return output
# Initial output is ...,cape_cin,nz,ny,nx to create contiguous views
outdims = p_hpa.shape[0:num_left_dims]
extra_dims = tuple(outdims) # Copy the left-most dims for iteration
extra_dims = tuple(outdims) # Copy the left-most dims for iteration
outdims += (2,) # cape_cin
outdims += (2,) # cape_cin
outdims += p_hpa.shape[-3:]
@ -329,9 +325,9 @@ def cape_left_iter(alg_dtype=np.float64): @@ -329,9 +325,9 @@ def cape_left_iter(alg_dtype=np.float64):
cape_output_idxs = (0,) + left_idxs + (slice(None),)
cin_output_idxs = (1,) + left_idxs + (slice(None),)
view_cape_reverse_idxs = left_idxs + (0, slice(None,None,-1),
view_cape_reverse_idxs = left_idxs + (0, slice(None, None, -1),
slice(None))
view_cin_reverse_idxs = left_idxs + (1, slice(None,None,-1),
view_cin_reverse_idxs = left_idxs + (1, slice(None, None, -1),
slice(None))
new_args[0] = p_hpa[left_and_slice_idxs]
@ -371,10 +367,9 @@ def cape_left_iter(alg_dtype=np.float64): @@ -371,10 +367,9 @@ def cape_left_iter(alg_dtype=np.float64):
# Make sure the result is the same data as what got passed in
# Can delete this once everything works
if (cape.__array_interface__["data"][0] !=
capeview.__array_interface__["data"][0]):
capeview.__array_interface__["data"][0]):
raise RuntimeError("output array was copied")
if flip and not is2d:
output[cape_output_idxs] = (
outview_array[view_cape_reverse_idxs].astype(orig_dtype))
@ -382,9 +377,9 @@ def cape_left_iter(alg_dtype=np.float64): @@ -382,9 +377,9 @@ def cape_left_iter(alg_dtype=np.float64):
outview_array[view_cin_reverse_idxs].astype(orig_dtype))
else:
output[cape_output_idxs] = (
outview_array[cape_idxs].astype(orig_dtype))
outview_array[cape_idxs].astype(orig_dtype))
output[cin_output_idxs] = (
outview_array[cin_idxs].astype(orig_dtype))
outview_array[cin_idxs].astype(orig_dtype))
return output
@ -435,18 +430,18 @@ def cloudfrac_left_iter(alg_dtype=np.float64): @@ -435,18 +430,18 @@ def cloudfrac_left_iter(alg_dtype=np.float64):
output_dims += vert.shape[-2:]
output = np.empty(output_dims, orig_dtype)
output[0,:] = low[:]
output[1,:] = mid[:]
output[2,:] = high[:]
output[0, :] = low[:]
output[1, :] = mid[:]
output[2, :] = high[:]
return output
# Initial output is ...,low_mid_high,nz,ny,nx to create contiguous views
# Initial output is ...,low_mid_high,nz,ny,nx to create contiguous
# views
outdims = vert.shape[0:num_left_dims]
extra_dims = tuple(outdims) # Copy the left-most dims for iteration
extra_dims = tuple(outdims) # Copy the left-most dims for iteration
outdims += (3,) # low_mid_high
outdims += (3,) # low_mid_high
outdims += vert.shape[-2:]
@ -503,15 +498,15 @@ def cloudfrac_left_iter(alg_dtype=np.float64): @@ -503,15 +498,15 @@ def cloudfrac_left_iter(alg_dtype=np.float64):
# Make sure the result is the same data as what got passed in
# Can delete this once everything works
if (low.__array_interface__["data"][0] !=
lowview.__array_interface__["data"][0]):
lowview.__array_interface__["data"][0]):
raise RuntimeError("output array was copied")
output[low_output_idxs] = (
outview_array[low_idxs].astype(orig_dtype))
outview_array[low_idxs].astype(orig_dtype))
output[mid_output_idxs] = (
outview_array[mid_idxs].astype(orig_dtype))
outview_array[mid_idxs].astype(orig_dtype))
output[high_output_idxs] = (
outview_array[high_idxs].astype(orig_dtype))
outview_array[high_idxs].astype(orig_dtype))
if has_missing:
output = np.ma.masked_values(output, missing)
@ -548,8 +543,8 @@ def interplevel_left_iter(is2dlev, alg_dtype=np.float64): @@ -548,8 +543,8 @@ def interplevel_left_iter(is2dlev, alg_dtype=np.float64):
output = np.empty(outshape, dtype=alg_dtype)
for i in py3range(field3d.shape[0]):
new_args[0] = field3d[i,:]
new_kwargs["outview"] = output[i,:]
new_args[0] = field3d[i, :]
new_kwargs["outview"] = output[i, :]
_ = wrapped(*new_args, **new_kwargs)
else:
output = wrapped(*args, **kwargs)
@ -579,7 +574,6 @@ def interplevel_left_iter(is2dlev, alg_dtype=np.float64): @@ -579,7 +574,6 @@ def interplevel_left_iter(is2dlev, alg_dtype=np.float64):
else:
z_slice_idxs = left_idxs + (slice(None),)
new_args[0] = field3d[field_out_slice_idxs]
new_args[1] = z[z_slice_idxs]
@ -687,7 +681,7 @@ def check_interplevel_args(is2dlev): @@ -687,7 +681,7 @@ def check_interplevel_args(is2dlev):
if is2dlev:
if levels.ndim != 2:
if (levels.shape[0:-2] != z.shape[0:-3] or
levels.shape[-2:] != z.shape[-2:]):
levels.shape[-2:] != z.shape[-2:]):
raise ValueError("argument 1 and 2 must have "
"the same leftmost and rightmost "
"dimensions")
@ -695,4 +689,3 @@ def check_interplevel_args(is2dlev): @@ -695,4 +689,3 @@ def check_interplevel_args(is2dlev):
return wrapped(*args, **kwargs)
return func_wrapper

286
src/wrf/units.py

@ -37,7 +37,7 @@ def _apply_conv_fact(var, vartype, var_unit, dest_unit): @@ -37,7 +37,7 @@ def _apply_conv_fact(var, vartype, var_unit, dest_unit):
return var*(_CONV_FACTORS[vartype]["to_base"][var_unit])
else:
return var*(_CONV_FACTORS[vartype]["to_base"][var_unit] *
_CONV_FACTORS[vartype]["to_dest"][dest_unit])
_CONV_FACTORS[vartype]["to_dest"][dest_unit])
def _to_kelvin(var, var_unit):
@ -129,175 +129,170 @@ def _apply_temp_conv(var, var_unit, dest_unit): @@ -129,175 +129,170 @@ def _apply_temp_conv(var, var_unit, dest_unit):
# A mapping of unit names to their dictionary key names
_UNIT_ALIASES = {"mps" : "m s-1",
"m/s" : "m s-1",
"ms-1" : "m s-1",
"meters_per_second" : "m s-1",
"metres_per_second" : "m s-1",
"knots" : "kt",
"knot" : "kt",
"kts" : "kt",
"kn" : "kt",
"miles_per_hour" : "mi h-1",
"mih-1" : "mi h-1",
"mph" : "mi h-1",
"mi/h" : "mi h-1",
"kmph" : "km h-1",
"kmh-1" : "km h-1",
"km/h" : "km h-1",
"kilometers_per_hour" : "km h-1",
"kilometres_per_hour" : "km h-1",
"ft/s" : "ft s-1",
"ft/sec" : "ft s-1",
"fps" : "ft s-1",
"fs-1" : "ft s-1",
"feet_per_second" : "ft s-1",
"pascal" : "pa",
"pascals" : "pa",
"hecto_pascal" : "hpa",
"hecto_pascals" : "hpa",
"millibar" : "mb",
"millibars" : "mb",
"mbar" : "mb",
"kelvin" : "k",
"degree_kelvin" : "k",
"degrees_kelvin" : "k",
"degree_k" : "k",
"degrees_k" : "k",
"degreek" : "k",
"degreesk" : "k",
"degk" : "k",
"degsk" : "k",
"deg_k" : "k",
"degs_k" : "k",
"deg k" : "k",
"degs k" : "k",
"celsius" : "c",
"degree_celsius" : "c",
"degrees_celsius" : "c",
"degree_c" : "c",
"degrees_c" : "c",
"degreec" : "c",
"degreesc" : "c",
"degc" : "c",
"degsc" : "c",
"deg_c" : "c",
"degs_c" : "c",
"deg c" : "c",
"degs c" : "c",
"fahrenheit" : "f",
"degree_fahrenheit" : "f",
"degrees_fahrenheit" : "f",
"degree_f" : "f",
"degrees_f" : "f",
"degreef" : "f",
"degreesf" : "f",
"degf" : "f",
"degsf" : "f",
"deg_f" : "f",
"degs_f" : "f",
"deg f" : "f",
"degs f" : "f",
"meter" : "m",
"meters" : "m",
"metre" : "m",
"metres" : "m",
"kilometer" : "km",
"kilometers" : "km",
"dekameter" : "dm",
"dekameters" : "dm",
"decameter" : "dm",
"decameters" : "dm",
"dekametre" : "dm",
"dekametres" : "dm",
"decametre" : "dm",
"decametres" : "dm",
"dam" : "dm",
"dkm" : "dm",
"feet" : "ft",
"foot" : "ft",
"mile" : "mi",
"miles" : "mi"
}
_UNIT_ALIASES = {"mps": "m s-1",
"m/s": "m s-1",
"ms-1": "m s-1",
"meters_per_second": "m s-1",
"metres_per_second": "m s-1",
"knots": "kt",
"knot": "kt",
"kts": "kt",
"kn": "kt",
"miles_per_hour": "mi h-1",
"mih-1": "mi h-1",
"mph": "mi h-1",
"mi/h": "mi h-1",
"kmph": "km h-1",
"kmh-1": "km h-1",
"km/h": "km h-1",
"kilometers_per_hour": "km h-1",
"kilometres_per_hour": "km h-1",
"ft/s": "ft s-1",
"ft/sec": "ft s-1",
"fps": "ft s-1",
"fs-1": "ft s-1",
"feet_per_second": "ft s-1",
"pascal": "pa",
"pascals": "pa",
"hecto_pascal": "hpa",
"hecto_pascals": "hpa",
"millibar": "mb",
"millibars": "mb",
"mbar": "mb",
"kelvin": "k",
"degree_kelvin": "k",
"degrees_kelvin": "k",
"degree_k": "k",
"degrees_k": "k",
"degreek": "k",
"degreesk": "k",
"degk": "k",
"degsk": "k",
"deg_k": "k",
"degs_k": "k",
"deg k": "k",
"degs k": "k",
"celsius": "c",
"degree_celsius": "c",
"degrees_celsius": "c",
"degree_c": "c",
"degrees_c": "c",
"degreec": "c",
"degreesc": "c",
"degc": "c",
"degsc": "c",
"deg_c": "c",
"degs_c": "c",
"deg c": "c",
"degs c": "c",
"fahrenheit": "f",
"degree_fahrenheit": "f",
"degrees_fahrenheit": "f",
"degree_f": "f",
"degrees_f": "f",
"degreef": "f",
"degreesf": "f",
"degf": "f",
"degsf": "f",
"deg_f": "f",
"degs_f": "f",
"deg f": "f",
"degs f": "f",
"meter": "m",
"meters": "m",
"metre": "m",
"metres": "m",
"kilometer": "km",
"kilometers": "km",
"dekameter": "dm",
"dekameters": "dm",
"decameter": "dm",
"decameters": "dm",
"dekametre": "dm",
"dekametres": "dm",
"decametre": "dm",
"decametres": "dm",
"dam": "dm",
"dkm": "dm",
"feet": "ft",
"foot": "ft",
"mile": "mi",
"miles": "mi"
}
# A mapping of unit types to the avaible units
_VALID_UNITS = {"wind" : ["m s-1", "kt", "mi h-1", "km h-1", "ft s-1"],
"pressure" : ["pa", "hpa", "mb", "torr", "mmhg", "atm"],
"temp" : ["k", "f", "c"],
"height" : ["m", "km", "dm", "ft", "mi"]
}
_VALID_UNITS = {"wind": ["m s-1", "kt", "mi h-1", "km h-1", "ft s-1"],
"pressure": ["pa", "hpa", "mb", "torr", "mmhg", "atm"],
"temp": ["k", "f", "c"],
"height": ["m", "km", "dm", "ft", "mi"]
}
# Conversion factor map for wind from base units
_WIND_BASE_FACTORS = {"kt" : ConversionFactors.MPS_TO_KTS,
"km h-1" : ConversionFactors.MPS_TO_KMPH,
"mi h-1" : ConversionFactors.MPS_TO_MPH,
"ft s-1" : ConversionFactors.MPS_TO_FPS
}
_WIND_BASE_FACTORS = {"kt": ConversionFactors.MPS_TO_KTS,
"km h-1": ConversionFactors.MPS_TO_KMPH,
"mi h-1": ConversionFactors.MPS_TO_MPH,
"ft s-1": ConversionFactors.MPS_TO_FPS
}
# Conversion factor map to base units
_WIND_TOBASE_FACTORS = {"kt" : 1.0/ConversionFactors.MPS_TO_KTS,
"km h-1" : 1.0/ConversionFactors.MPS_TO_KMPH,
"mi h-1" : 1.0/ConversionFactors.MPS_TO_MPH,
"ft s-1" : 1.0/ConversionFactors.MPS_TO_FPS
_WIND_TOBASE_FACTORS = {"kt": 1.0/ConversionFactors.MPS_TO_KTS,
"km h-1": 1.0/ConversionFactors.MPS_TO_KMPH,
"mi h-1": 1.0/ConversionFactors.MPS_TO_MPH,
"ft s-1": 1.0/ConversionFactors.MPS_TO_FPS
}
# Conversion factor map for pressure from base units
_PRES_BASE_FACTORS = {"hpa" : ConversionFactors.PA_TO_HPA,
"mb" : ConversionFactors.PA_TO_HPA,
"torr" : ConversionFactors.PA_TO_TORR,
"mmhg" : ConversionFactors.PA_TO_MMHG,
"atm" : ConversionFactors.PA_TO_ATM
_PRES_BASE_FACTORS = {"hpa": ConversionFactors.PA_TO_HPA,
"mb": ConversionFactors.PA_TO_HPA,
"torr": ConversionFactors.PA_TO_TORR,
"mmhg": ConversionFactors.PA_TO_MMHG,
"atm": ConversionFactors.PA_TO_ATM
}
# Conversion factor map for pressure to base units
_PRES_TOBASE_FACTORS = {"hpa" : 1.0/ConversionFactors.PA_TO_HPA,
"mb" : 1.0/ConversionFactors.PA_TO_HPA,
"torr" : 1.0/ConversionFactors.PA_TO_TORR,
"mmhg" : 1.0/ConversionFactors.PA_TO_MMHG,
"atm" : 1.0/ConversionFactors.PA_TO_ATM
_PRES_TOBASE_FACTORS = {"hpa": 1.0/ConversionFactors.PA_TO_HPA,
"mb": 1.0/ConversionFactors.PA_TO_HPA,
"torr": 1.0/ConversionFactors.PA_TO_TORR,
"mmhg": 1.0/ConversionFactors.PA_TO_MMHG,
"atm": 1.0/ConversionFactors.PA_TO_ATM
}
# Conversion factor map for height from base units
_HEIGHT_BASE_FACTORS = {"km" : ConversionFactors.M_TO_KM,
"dm" : ConversionFactors.M_TO_DM,
"ft" : ConversionFactors.M_TO_FT,
"mi" : ConversionFactors.M_TO_MILES
_HEIGHT_BASE_FACTORS = {"km": ConversionFactors.M_TO_KM,
"dm": ConversionFactors.M_TO_DM,
"ft": ConversionFactors.M_TO_FT,
"mi": ConversionFactors.M_TO_MILES
}
# Conversion factor map for height to base units
_HEIGHT_TOBASE_FACTORS = {"km" : 1.0/ConversionFactors.M_TO_KM,
"dm" : 1.0/ConversionFactors.M_TO_DM,
"ft" : 1.0/ConversionFactors.M_TO_FT,
"mi" : 1.0/ConversionFactors.M_TO_MILES
}
_HEIGHT_TOBASE_FACTORS = {"km": 1.0/ConversionFactors.M_TO_KM,
"dm": 1.0/ConversionFactors.M_TO_DM,
"ft": 1.0/ConversionFactors.M_TO_FT,
"mi": 1.0/ConversionFactors.M_TO_MILES
}
# Mapping of unit type to base unit type
_BASE_UNITS = {"wind" : "m s-1",
"pressure" : "pa",
"temp" : "k",
"height" : "m"
_BASE_UNITS = {"wind": "m s-1",
"pressure": "pa",
"temp": "k",
"height": "m"
}
# A mapping of unit type to a mapping of to/from base conversion factors
_CONV_FACTORS = {"wind" : {"to_dest" : _WIND_BASE_FACTORS,
"to_base" : _WIND_TOBASE_FACTORS},
"pressure" : {"to_dest" : _PRES_BASE_FACTORS,
"to_base" : _PRES_TOBASE_FACTORS},
"height" : {"to_dest" : _HEIGHT_BASE_FACTORS,
"to_base" : _HEIGHT_TOBASE_FACTORS}
_CONV_FACTORS = {"wind": {"to_dest": _WIND_BASE_FACTORS,
"to_base": _WIND_TOBASE_FACTORS},
"pressure": {"to_dest": _PRES_BASE_FACTORS,
"to_base": _PRES_TOBASE_FACTORS},
"height": {"to_dest": _HEIGHT_BASE_FACTORS,
"to_base": _HEIGHT_TOBASE_FACTORS}
}
# A mapping of temperature type to the conversion function
_TEMP_CONV_METHODS = {"c" : _k_to_c,
"f" : _k_to_f
_TEMP_CONV_METHODS = {"c": _k_to_c,
"f": _k_to_f
}
def dealias_and_clean_unit(unit):
"""Return the properly cleaned and dealiased unit name.
@ -336,7 +331,7 @@ def check_units(unit, unit_type): @@ -336,7 +331,7 @@ def check_units(unit, unit_type):
"""
u_cleaned = dealias_and_clean_unit(unit)
if u_cleaned not in _VALID_UNITS[unit_type]:
raise ValueError("invalid unit type '%s'" % unit)
raise ValueError("invalid unit type '{}'".format(unit))
def do_conversion(var, vartype, var_unit, dest_unit):
@ -365,8 +360,3 @@ def do_conversion(var, vartype, var_unit, dest_unit): @@ -365,8 +360,3 @@ def do_conversion(var, vartype, var_unit, dest_unit):
return _apply_conv_fact(var, vartype, var_unit.lower(), u_cleaned)
else:
return _apply_temp_conv(var, var_unit.lower(), u_cleaned)

219
src/wrf/util.py

@ -41,24 +41,24 @@ if xarray_enabled(): @@ -41,24 +41,24 @@ if xarray_enabled():
from xarray import DataArray
_COORD_PAIR_MAP = {"XLAT" : ("XLAT", "XLONG"),
"XLONG" : ("XLAT", "XLONG"),
"XLAT_M" : ("XLAT_M", "XLONG_M"),
"XLONG_M" : ("XLAT_M", "XLONG_M"),
"XLAT_U" : ("XLAT_U", "XLONG_U"),
"XLONG_U" : ("XLAT_U", "XLONG_U"),
"XLAT_V" : ("XLAT_V", "XLONG_V"),
"XLONG_V" : ("XLAT_V", "XLONG_V"),
"CLAT" : ("CLAT", "CLONG"),
"CLONG" : ("CLAT", "CLONG")}
_COORD_PAIR_MAP = {"XLAT": ("XLAT", "XLONG"),
"XLONG": ("XLAT", "XLONG"),
"XLAT_M": ("XLAT_M", "XLONG_M"),
"XLONG_M": ("XLAT_M", "XLONG_M"),
"XLAT_U": ("XLAT_U", "XLONG_U"),
"XLONG_U": ("XLAT_U", "XLONG_U"),
"XLAT_V": ("XLAT_V", "XLONG_V"),
"XLONG_V": ("XLAT_V", "XLONG_V"),
"CLAT": ("CLAT", "CLONG"),
"CLONG": ("CLAT", "CLONG")}
_COORD_VARS = ("XLAT", "XLONG", "XLAT_M", "XLONG_M", "XLAT_U", "XLONG_U",
"XLAT_V", "XLONG_V", "CLAT", "CLONG")
_LAT_COORDS = ("XLAT", "XLAT_M", "XLAT_U", "XLAT_V", "CLAT")
_LAT_COORDS = ("XLAT", "XLAT_M", "XLAT_U", "XLAT_V", "CLAT")
_LON_COORDS = ("XLONG", "XLONG_M", "XLONG_U","XLONG_V", "CLONG")
_LON_COORDS = ("XLONG", "XLONG_M", "XLONG_U", "XLONG_V", "CLONG")
_TIME_COORD_VARS = ("XTIME",)
@ -210,11 +210,11 @@ def _generator_copy(gen): @@ -210,11 +210,11 @@ def _generator_copy(gen):
if module is not None:
try:
try:
argd = {key:argvals.locals[key] for key in argvals.args}
argd = {key: argvals.locals[key] for key in argvals.args}
res = module.get(funcname)(**argd)
except AttributeError:
res = getattr(module, funcname)(**argd)
except:
except Exception:
# This is the old way it used to work, but it looks like this was
# fixed by Python.
try:
@ -226,9 +226,9 @@ def _generator_copy(gen): @@ -226,9 +226,9 @@ def _generator_copy(gen):
import __main__
try:
argd = {key:argvals.locals[key] for key in argvals.args}
argd = {key: argvals.locals[key] for key in argvals.args}
res = getattr(__main__, funcname)(**argd)
except:
except Exception:
# This was the old way it used to work, but appears to have
# been fixed by Python.
res = getattr(__main__, funcname)(**argvals.locals)
@ -237,7 +237,7 @@ def _generator_copy(gen): @@ -237,7 +237,7 @@ def _generator_copy(gen):
def test():
q = [1,2,3]
q = [1, 2, 3]
for i in q:
yield i
@ -388,13 +388,13 @@ def get_iterable(wrfseq): @@ -388,13 +388,13 @@ def get_iterable(wrfseq):
if isinstance(wrfseq, (list, tuple, IterWrapper)):
return wrfseq
else:
return IterWrapper(wrfseq) # generator/custom iterable class
return IterWrapper(wrfseq) # generator/custom iterable class
else:
if isinstance(wrfseq, dict):
return wrfseq
else:
return dict(wrfseq) # generator/custom iterable dict class
return dict(wrfseq) # generator/custom iterable dict class
# Helper to extract masked arrays from DataArrays that convert to NaN
@ -433,9 +433,9 @@ def to_np(array): @@ -433,9 +433,9 @@ def to_np(array):
try:
fill_value = array.attrs["_FillValue"]
except AttributeError:
result = array # Not a DataArray
result = array # Not a DataArray
except KeyError:
result = array.values # Does not have missing values
result = array.values # Does not have missing values
else:
result = ma.masked_invalid(array.values, copy=False)
result.set_fill_value(fill_value)
@ -496,7 +496,7 @@ class either(object): @@ -496,7 +496,7 @@ class either(object):
return varname
raise ValueError("{} are not valid variable names".format(
self.varnames))
self.varnames))
# This should look like:
@ -661,25 +661,25 @@ def _corners_moved(wrfnc, first_ll_corner, first_ur_corner, latvar, lonvar): @@ -661,25 +661,25 @@ def _corners_moved(wrfnc, first_ll_corner, first_ur_corner, latvar, lonvar):
# Need to check all times
for i in py3range(lats.shape[-3]):
start_idxs = [0]*len(lats.shape) # PyNIO does not support ndim
start_idxs = [0] * len(lats.shape) # PyNIO does not support ndim
start_idxs[-3] = i
start_idxs = tuple(start_idxs)
end_idxs = [-1]*len(lats.shape)
end_idxs = [-1] * len(lats.shape)
end_idxs[-3] = i
end_idxs = tuple(end_idxs)
if (first_ll_corner[0] != lats[start_idxs] or
first_ll_corner[1] != lons[start_idxs] or
first_ur_corner[0] != lats[end_idxs] or
first_ur_corner[1] != lons[end_idxs]):
if (first_ll_corner[0] != lats[start_idxs]
or first_ll_corner[1] != lons[start_idxs]
or first_ur_corner[0] != lats[end_idxs]
or first_ur_corner[1] != lons[end_idxs]):
return True
return False
def is_moving_domain(wrfin, varname=None, latvar=either("XLAT", "XLAT_M"),
lonvar=either("XLONG", "XLONG_M"), _key=None):
lonvar=either("XLONG", "XLONG_M"), _key=None):
"""Return True if the domain is a moving nest.
@ -877,7 +877,7 @@ def extract_global_attrs(wrfin, attrs): @@ -877,7 +877,7 @@ def extract_global_attrs(wrfin, attrs):
entry = wrfin[next(iter(viewkeys(wrfin)))]
return extract_global_attrs(entry, attrs)
return {attr:_get_global_attr(wrfin, attr) for attr in attrlist}
return {attr: _get_global_attr(wrfin, attr) for attr in attrlist}
def extract_dim(wrfin, dim):
@ -907,17 +907,18 @@ def extract_dim(wrfin, dim): @@ -907,17 +907,18 @@ def extract_dim(wrfin, dim):
d = wrfin.dimensions[dim]
if not isinstance(d, int):
try:
return len(d) #netCDF4
except TypeError: #scipy.io.netcdf
return len(d) # netCDF4
except TypeError: # scipy.io.netcdf
# Scipy can't handled unlimited dimensions, so now we have to
# figure it out
try:
s = wrfin.variables["P"].shape
return s[-4]
except:
except Exception:
raise ValueError("unsupported NetCDF reader")
else:
return s[-4]
return d # PyNIO
return d # PyNIO
def _combine_dict(wrfdict, varname, timeidx, method, meta, _key):
@ -981,15 +982,15 @@ def _combine_dict(wrfdict, varname, timeidx, method, meta, _key): @@ -981,15 +982,15 @@ def _combine_dict(wrfdict, varname, timeidx, method, meta, _key):
_cache_key = _key[first_key] if _key is not None else None
first_array = _extract_var(wrfdict[first_key], varname,
timeidx, is_moving=is_moving, method=method,
squeeze=False, cache=None, meta=meta,
_key=_cache_key)
timeidx, is_moving=is_moving, method=method,
squeeze=False, cache=None, meta=meta,
_key=_cache_key)
# Create the output data numpy array based on the first array
outdims = [numkeys]
outdims += first_array.shape
outdata = np.empty(outdims, first_array.dtype)
outdata[0,:] = first_array[:]
outdata[0, :] = first_array[:]
idx = 1
while True:
@ -1007,8 +1008,8 @@ def _combine_dict(wrfdict, varname, timeidx, method, meta, _key): @@ -1007,8 +1008,8 @@ def _combine_dict(wrfdict, varname, timeidx, method, meta, _key):
if outdata.shape[1:] != vardata.shape:
raise ValueError("data sequences must have the "
"same size for all dictionary keys")
outdata[idx,:] = to_np(vardata)[:]
"same size for all dictionary keys")
outdata[idx, :] = to_np(vardata)[:]
idx += 1
if xarray_enabled() and meta:
@ -1044,12 +1045,10 @@ def _combine_dict(wrfdict, varname, timeidx, method, meta, _key): @@ -1044,12 +1045,10 @@ def _combine_dict(wrfdict, varname, timeidx, method, meta, _key):
# make it so that key_0 is leftmost
outdims = key_coordnames + list(first_array.dims[existing_cnt:])
# Create the new 'key_n', value pairs
for coordname, coordval in zip(key_coordnames, coord_vals):
outcoords[coordname] = coordval
outattrs = OrderedDict(first_array.attrs)
outarr = DataArray(outdata, name=outname, coords=outcoords,
@ -1268,7 +1267,7 @@ def _build_data_array(wrfnc, varname, timeidx, is_moving_domain, is_multifile, @@ -1268,7 +1267,7 @@ def _build_data_array(wrfnc, varname, timeidx, is_moving_domain, is_multifile,
for dkey, val in viewitems(var.__dict__):
# scipy.io adds these but don't want them
if dkey in ("data", "_shape", "_size", "_typecode", "_attributes",
"maskandscale", "dimensions"):
"maskandscale", "dimensions"):
continue
_dkey = dkey if isinstance(dkey, str) else dkey.decode()
@ -1276,7 +1275,7 @@ def _build_data_array(wrfnc, varname, timeidx, is_moving_domain, is_multifile, @@ -1276,7 +1275,7 @@ def _build_data_array(wrfnc, varname, timeidx, is_moving_domain, is_multifile,
_val = val
else:
if isinstance(val, bytes):
_val = val.decode() # scipy.io.netcdf
_val = val.decode() # scipy.io.netcdf
else:
_val = val
@ -1292,7 +1291,6 @@ def _build_data_array(wrfnc, varname, timeidx, is_moving_domain, is_multifile, @@ -1292,7 +1291,6 @@ def _build_data_array(wrfnc, varname, timeidx, is_moving_domain, is_multifile,
except IndexError:
pass
coords = OrderedDict()
# Handle lat/lon coordinates and projection information if available
@ -1354,17 +1352,17 @@ def _build_data_array(wrfnc, varname, timeidx, is_moving_domain, is_multifile, @@ -1354,17 +1352,17 @@ def _build_data_array(wrfnc, varname, timeidx, is_moving_domain, is_multifile,
else:
coords[lon_coord] = (lon_coord_dims[1:],
lon_coord_vals[0,:])
lon_coord_vals[0, :])
coords[lat_coord] = (lat_coord_dims[1:],
lat_coord_vals[0,:])
lat_coord_vals[0, :])
if time_coord is not None:
coords[time_coord] = (lon_coord_dims[0], time_coord_vals)
else:
coords[lon_coord] = (lon_coord_dims[1:],
lon_coord_vals[timeidx,:])
lon_coord_vals[timeidx, :])
coords[lat_coord] = (lat_coord_dims[1:],
lat_coord_vals[timeidx,:])
lat_coord_vals[timeidx, :])
if time_coord is not None:
coords[time_coord] = (lon_coord_dims[0],
@ -1513,7 +1511,7 @@ def _find_reverse(wrfseq, varname, timeidx, is_moving, meta, _key): @@ -1513,7 +1511,7 @@ def _find_reverse(wrfseq, varname, timeidx, is_moving, meta, _key):
is_moving, True, _key)
else:
result = wrfnc.variables[varname][filetimeidx, :]
return result[np.newaxis, :] # So that nosqueeze works
return result[np.newaxis, :] # So that nosqueeze works
else:
comboidx += numtimes
@ -1618,8 +1616,6 @@ def _cat_files(wrfseq, varname, timeidx, is_moving, squeeze, meta, _key): @@ -1618,8 +1616,6 @@ def _cat_files(wrfseq, varname, timeidx, is_moving, squeeze, meta, _key):
return _find_arr_for_time(wrfseq, varname, timeidx, is_moving, meta,
_key)
#time_idx_or_slice = timeidx if not multitime else slice(None)
# If all times are requested, need to build a new array and cat together
# all of the arrays in the sequence
wrf_iter = iter(wrfseq)
@ -1665,7 +1661,8 @@ def _cat_files(wrfseq, varname, timeidx, is_moving, squeeze, meta, _key): @@ -1665,7 +1661,8 @@ def _cat_files(wrfseq, varname, timeidx, is_moving, squeeze, meta, _key):
outxtimes = get_cached_item(_key, timekey)
if outxtimes is None:
outxtimes = np.empty(outdims[0])
outxtimes[startidx:endidx] = to_np(first_var.coords[timename][:])
outxtimes[startidx:endidx] = to_np(
first_var.coords[timename][:])
else:
timecached = True
@ -1677,7 +1674,8 @@ def _cat_files(wrfseq, varname, timeidx, is_moving, squeeze, meta, _key): @@ -1677,7 +1674,8 @@ def _cat_files(wrfseq, varname, timeidx, is_moving, squeeze, meta, _key):
outlats = get_cached_item(_key, latkey)
if outlats is None:
outlats = np.empty(outcoorddims, first_var.dtype)
outlats[startidx:endidx, :] = to_np(first_var.coords[latname][:])
outlats[startidx:endidx, :] = to_np(
first_var.coords[latname][:])
else:
latcached = True
@ -1685,11 +1683,11 @@ def _cat_files(wrfseq, varname, timeidx, is_moving, squeeze, meta, _key): @@ -1685,11 +1683,11 @@ def _cat_files(wrfseq, varname, timeidx, is_moving, squeeze, meta, _key):
outlons = get_cached_item(_key, lonkey)
if outlons is None:
outlons = np.empty(outcoorddims, first_var.dtype)
outlons[startidx:endidx, :] = to_np(first_var.coords[lonname][:])
outlons[startidx:endidx, :] = to_np(
first_var.coords[lonname][:])
else:
loncached = True
startidx = endidx
while True:
try:
@ -1940,7 +1938,7 @@ def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key): @@ -1940,7 +1938,7 @@ def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key):
else:
loncached = True
file_idx=1
file_idx = 1
while True:
try:
wrfnc = next(wrf_iter)
@ -1964,8 +1962,8 @@ def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key): @@ -1964,8 +1962,8 @@ def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key):
# For join, the times are a function of fileidx
file_times = extract_times(wrfnc, ALL_TIMES, meta=False,
do_xtime=False)
time_coord[file_idx, 0:numtimes] = np.asarray(file_times,
"datetime64[ns]")[:]
time_coord[file_idx, 0:numtimes] = np.asarray(
file_times, "datetime64[ns]")[:]
if timename is not None and not timecached:
xtimedata = wrfnc.variables[timename][:]
@ -2219,8 +2217,8 @@ def _extract_var(wrfin, varname, timeidx, is_moving, @@ -2219,8 +2217,8 @@ def _extract_var(wrfin, varname, timeidx, is_moving,
multifile, _key)
else:
if not multitime:
result = wrfin.variables[varname][timeidx,:]
result = result[np.newaxis, :] # So that no squeeze works
result = wrfin.variables[varname][timeidx, :]
result = result[np.newaxis, :] # So that no squeeze works
else:
result = wrfin.variables[varname][:]
else:
@ -2288,8 +2286,8 @@ def extract_vars(wrfin, timeidx, varnames, method="cat", squeeze=True, @@ -2288,8 +2286,8 @@ def extract_vars(wrfin, timeidx, varnames, method="cat", squeeze=True,
else:
varlist = varnames
return {var:_extract_var(wrfin, var, timeidx, None,
method, squeeze, cache, meta, _key)
return {var: _extract_var(wrfin, var, timeidx, None,
method, squeeze, cache, meta, _key)
for var in varlist}
@ -2322,7 +2320,7 @@ def _make_time(timearr): @@ -2322,7 +2320,7 @@ def _make_time(timearr):
"""
try:
return dt.datetime.strptime("".join(npbytes_to_str(timearr)),
"%Y-%m-%d_%H:%M:%S")
"%Y-%m-%d_%H:%M:%S")
except ValueError:
return np.datetime64("NaT")
@ -2351,9 +2349,9 @@ def _file_times(wrfin, do_xtime): @@ -2351,9 +2349,9 @@ def _file_times(wrfin, do_xtime):
"""
if not do_xtime:
times = wrfin.variables["Times"][:,:]
times = wrfin.variables["Times"][:, :]
for i in py3range(times.shape[0]):
yield _make_time(times[i,:])
yield _make_time(times[i, :])
else:
xtimes = wrfin.variables["XTIME"][:]
for i in py3range(xtimes.shape[0]):
@ -2390,7 +2388,7 @@ def _extract_time_map(wrfin, timeidx, do_xtime, meta=False): @@ -2390,7 +2388,7 @@ def _extract_time_map(wrfin, timeidx, do_xtime, meta=False):
otherwise the sequence is :class:`numpy.ndarray`.
"""
return {key : extract_times(wrfseq, timeidx, do_xtime, meta)
return {key: extract_times(wrfseq, timeidx, do_xtime, meta)
for key, wrfseq in viewitems(wrfin)}
@ -2478,19 +2476,19 @@ def extract_times(wrfin, timeidx, method="cat", squeeze=True, cache=None, @@ -2478,19 +2476,19 @@ def extract_times(wrfin, timeidx, method="cat", squeeze=True, cache=None,
num_cols = len(time_list[0])
time_arr = np.full((num_rows, num_cols), fill_value, dtype=dt)
for i,row in enumerate(time_list):
for i, row in enumerate(time_list):
if len(row) == num_cols:
time_arr[i,:] = row[:]
time_arr[i, :] = row[:]
else:
for j,val in enumerate(row):
time_arr[i,j] = val
for j, val in enumerate(row):
time_arr[i, j] = val
time_arr = ma.masked_values(time_arr, fill_value)
else:
raise ValueError("invalid method argument '{}'".format(method))
except KeyError:
return None # Thrown for pre-3.7 XTIME not existing
return None # Thrown for pre-3.7 XTIME not existing
if xarray_enabled() and meta:
outattrs = OrderedDict()
@ -2514,10 +2512,8 @@ def extract_times(wrfin, timeidx, method="cat", squeeze=True, cache=None, @@ -2514,10 +2512,8 @@ def extract_times(wrfin, timeidx, method="cat", squeeze=True, cache=None,
outname = "XTIME"
outarr = DataArray(time_arr, name=outname, coords=outcoords,
dims=outdimnames, attrs=outattrs)
else:
outarr = time_arr
@ -2670,7 +2666,7 @@ def get_right_slices(var, right_ndims, fixed_val=0): @@ -2670,7 +2666,7 @@ def get_right_slices(var, right_ndims, fixed_val=0):
[slice(None)]*right_ndims)
def get_proj_params(wrfin):#, timeidx=0, varname=None):
def get_proj_params(wrfin):
"""Return a tuple of latitude, longitude, and projection parameters from
a WRF output file object or a sequence of WRF output file objects.
@ -2697,12 +2693,13 @@ def get_proj_params(wrfin):#, timeidx=0, varname=None): @@ -2697,12 +2693,13 @@ def get_proj_params(wrfin):#, timeidx=0, varname=None):
longitude coordinate, and global projection attributes.
"""
proj_params = extract_global_attrs(wrfin, attrs=("MAP_PROJ",
"CEN_LAT", "CEN_LON",
"TRUELAT1", "TRUELAT2",
"MOAD_CEN_LAT", "STAND_LON",
"POLE_LAT", "POLE_LON",
"DX", "DY"))
proj_params = extract_global_attrs(wrfin,
attrs=("MAP_PROJ",
"CEN_LAT", "CEN_LON",
"TRUELAT1", "TRUELAT2",
"MOAD_CEN_LAT", "STAND_LON",
"POLE_LAT", "POLE_LON",
"DX", "DY"))
return proj_params
@ -2710,7 +2707,7 @@ def get_proj_params(wrfin):#, timeidx=0, varname=None): @@ -2710,7 +2707,7 @@ def get_proj_params(wrfin):#, timeidx=0, varname=None):
def from_args(func, argnames, *args, **kwargs):
"""Return a mapping of argument name to value for the called function.
This function parses the function \*args and \*\*kwargs to obtain the \
This function parses the function args and kwargs to obtain the
desired argument value. If the argument has not been passed in, the value
is taken from the default keyword argument value.
@ -2719,7 +2716,7 @@ def from_args(func, argnames, *args, **kwargs): @@ -2719,7 +2716,7 @@ def from_args(func, argnames, *args, **kwargs):
Note:
This function currently does not work with functions that contain
\*args or \*\*kwargs arguments.
variable length args or kwargs arguments.
Args:
@ -2763,7 +2760,7 @@ def _args_to_list2(func, args, kwargs): @@ -2763,7 +2760,7 @@ def _args_to_list2(func, args, kwargs):
Note:
This function currently does not work with functions that contain
*args or **kwargs arguments.
variable length args or kwargs arguments.
Args:
@ -2784,15 +2781,15 @@ def _args_to_list2(func, args, kwargs): @@ -2784,15 +2781,15 @@ def _args_to_list2(func, args, kwargs):
# Build the full tuple with defaults filled in
outargs = [None]*len(argspec.args)
if argspec.defaults is not None:
for i,default in enumerate(argspec.defaults[::-1], 1):
for i, default in enumerate(argspec.defaults[::-1], 1):
outargs[-i] = default
# Add the supplied args
for i,arg in enumerate(args):
for i, arg in enumerate(args):
outargs[i] = arg
# Fill in the supplied kargs
for argname,val in viewitems(kwargs):
for argname, val in viewitems(kwargs):
argidx = argspec.args.index(argname)
outargs[argidx] = val
@ -2850,7 +2847,7 @@ def _args_to_list3(func, args, kwargs): @@ -2850,7 +2847,7 @@ def _args_to_list3(func, args, kwargs):
Note:
This function currently does not work with functions that contain
*args or **kwargs arguments.
variable length args or kwargs arguments.
Args:
@ -2885,7 +2882,7 @@ def args_to_list(func, args, kwargs): @@ -2885,7 +2882,7 @@ def args_to_list(func, args, kwargs):
Note:
This function currently does not work with functions that contain
\*args or \*\*kwargs arguments.
variable length args or kwargs arguments.
Args:
@ -3039,13 +3036,27 @@ def psafilepath(): @@ -3039,13 +3036,27 @@ def psafilepath():
def get_filepath(obj):
"""Return the file path for the specified object.
This is used to return the file path for a netcdf object. If the
particular object does not have the appropriate file path information,
then one is created based on the timestep in the file.
Args:
obj: An object.
Returns:
:obj:`str`: A string for a file path.
"""
try:
path = obj.filepath()
except AttributeError:
try:
path = obj.file.path
except:
except AttributeError:
# Let's make up a filename from the first file time
found = False
times = extract_times(obj, None, meta=False, do_xtime=False)
@ -3059,6 +3070,7 @@ def get_filepath(obj): @@ -3059,6 +3070,7 @@ def get_filepath(obj):
return path
def get_id(obj, prefix=''):
"""Return the cache id.
@ -3091,11 +3103,11 @@ def get_id(obj, prefix=''): @@ -3091,11 +3103,11 @@ def get_id(obj, prefix=''):
# For each key in the mapping, recursively call get_id until
# until a non-mapping is found
return {key : get_id(val, prefix) for key,val in viewitems(obj)}
return {key: get_id(val, prefix) for key, val in viewitems(obj)}
def geo_bounds(var=None, wrfin=None, varname=None, timeidx=0, method="cat",
squeeze=True, cache=None):
squeeze=True, cache=None):
"""Return the geographic boundaries for the variable or file(s).
When using a :class:`xarray.DataArray` as the *var* parameter, the variable
@ -3234,6 +3246,7 @@ def geo_bounds(var=None, wrfin=None, varname=None, timeidx=0, method="cat", @@ -3234,6 +3246,7 @@ def geo_bounds(var=None, wrfin=None, varname=None, timeidx=0, method="cat",
# Non-moving domains
return GeoBounds(lats=lats, lons=lons)
def _get_wrf_proj_geobnds(var, wrfin, varname, timeidx, method, squeeze,
cache):
"""Return the :class:`wrf.WrfProj` subclass and :class:`wrf.GeoBounds`.
@ -3301,7 +3314,7 @@ def _get_wrf_proj_geobnds(var, wrfin, varname, timeidx, method, squeeze, @@ -3301,7 +3314,7 @@ def _get_wrf_proj_geobnds(var, wrfin, varname, timeidx, method, squeeze,
"information")
else:
geobnds = geo_bounds(wrfin=wrfin, varname=varname, timeidx=timeidx,
method=method, cache=cache)
method=method, cache=cache)
proj_params = get_proj_params(wrfin)
wrf_proj = getproj(**proj_params)
@ -3376,7 +3389,7 @@ def _get_proj_obj(ob_type, var, wrfin, varname, timeidx, method, squeeze, @@ -3376,7 +3389,7 @@ def _get_proj_obj(ob_type, var, wrfin, varname, timeidx, method, squeeze,
elif ob_type == "basemap":
try:
_ = len(geobnds)
except TypeError: # Only a single object
except TypeError: # Only a single object
proj_obj = wrf_proj.basemap(geobnds, **kwargs)
else:
proj_obj = np.empty(geobnds.shape, np.object)
@ -3386,7 +3399,7 @@ def _get_proj_obj(ob_type, var, wrfin, varname, timeidx, method, squeeze, @@ -3386,7 +3399,7 @@ def _get_proj_obj(ob_type, var, wrfin, varname, timeidx, method, squeeze,
elif ob_type == "pyngl":
try:
_ = len(geobnds)
except TypeError: # Only a single object
except TypeError: # Only a single object
proj_obj = wrf_proj.pyngl(geobnds, **kwargs)
else:
proj_obj = np.empty(geobnds.shape, np.object)
@ -3443,7 +3456,7 @@ def latlon_coords(var, as_np=False): @@ -3443,7 +3456,7 @@ def latlon_coords(var, as_np=False):
def get_cartopy(var=None, wrfin=None, varname=None, timeidx=0, method="cat",
squeeze=True, cache=None):
squeeze=True, cache=None):
"""Return a :class:`cartopy.crs.Projection` subclass for the
map projection.
@ -3511,7 +3524,7 @@ def get_cartopy(var=None, wrfin=None, varname=None, timeidx=0, method="cat", @@ -3511,7 +3524,7 @@ def get_cartopy(var=None, wrfin=None, varname=None, timeidx=0, method="cat",
def get_basemap(var=None, wrfin=None, varname=None, timeidx=0, method="cat",
squeeze=True, cache=None, **kwargs):
squeeze=True, cache=None, **kwargs):
"""Return a :class:`matplotlib.mpl_toolkits.basemap.Basemap` object
for the map projection.
@ -3737,7 +3750,8 @@ def cartopy_xlim(var=None, geobounds=None, wrfin=None, varname=None, timeidx=0, @@ -3737,7 +3750,8 @@ def cartopy_xlim(var=None, geobounds=None, wrfin=None, varname=None, timeidx=0,
"""
wrf_proj, native_geobnds = _get_wrf_proj_geobnds(var, wrfin, varname,
timeidx, method, squeeze, cache)
timeidx, method, squeeze,
cache)
if geobounds is not None:
return wrf_proj.cartopy_xlim(geobounds)
@ -3823,7 +3837,8 @@ def cartopy_ylim(var=None, geobounds=None, wrfin=None, varname=None, timeidx=0, @@ -3823,7 +3837,8 @@ def cartopy_ylim(var=None, geobounds=None, wrfin=None, varname=None, timeidx=0,
"""
wrf_proj, native_geobnds = _get_wrf_proj_geobnds(var, wrfin, varname,
timeidx, method, squeeze, cache)
timeidx, method, squeeze,
cache)
if geobounds is not None:
return wrf_proj.cartopy_ylim(geobounds)
@ -3854,8 +3869,8 @@ def ll_points(lat, lon): @@ -3854,8 +3869,8 @@ def ll_points(lat, lon):
object or a list of :class:`wrf.CoordPair` objects.
"""
latvals = np.ravel(to_np(lat)[...,0,0])
lonvals = np.ravel(to_np(lon)[...,0,0])
latvals = np.ravel(to_np(lat)[..., 0, 0])
lonvals = np.ravel(to_np(lon)[..., 0, 0])
if latvals.shape[0] == 1:
return CoordPair(lat=float(latvals), lon=float(lonvals))

1
src/wrf/version.py

@ -1,2 +1 @@ @@ -1,2 +1 @@
__version__ = "1.3.1"

Loading…
Cancel
Save