Browse Source

Moved the CoordPair to a new module. Added operators for CoordPair. Fixed some missing from __future__ imports. Fixed some metadata issues due to arg name changes.

main
Bill Ladwig 9 years ago
parent
commit
bf0d26b7b0
  1. 2
      src/wrf/api.py
  2. 131
      src/wrf/coordpair.py
  3. 41
      src/wrf/metadecorators.py
  4. 8
      src/wrf/py3compat.py
  5. 51
      src/wrf/util.py

2
src/wrf/api.py

@ -17,6 +17,7 @@ from .util import (npvalues, extract_global_attrs,
extract_dim, extract_vars, extract_times, combine_files, extract_dim, extract_vars, extract_times, combine_files,
is_staggered, get_left_indexes, iter_left_indexes, is_staggered, get_left_indexes, iter_left_indexes,
get_right_slices, get_proj_params) get_right_slices, get_proj_params)
from .coordpair import CoordPair
from .version import __version__ from .version import __version__
__all__ = [] __all__ = []
@ -39,5 +40,6 @@ __all__ += ["npvalues", "extract_global_attrs",
"extract_dim", "extract_vars", "extract_times", "combine_files", "extract_dim", "extract_vars", "extract_times", "combine_files",
"is_staggered", "get_left_indexes", "iter_left_indexes", "is_staggered", "get_left_indexes", "iter_left_indexes",
"get_right_slices", "get_proj_params"] "get_right_slices", "get_proj_params"]
__all__ += ["CoordPair"]
__all__ += ["__version__"] __all__ += ["__version__"]

131
src/wrf/coordpair.py

@ -0,0 +1,131 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
from .py3compat import py2round
def _binary_operator(operator):
def func(self, other):
if isinstance(other, CoordPair):
args = [
None if getattr(self, attr) is None or getattr(other, attr) is None
else getattr(getattr(self, attr), operator)(getattr(other, attr))
for attr in ("x", "y", "lat", "lon")]
else:
args = [
None if getattr(self, attr) is None
else getattr(getattr(self, attr), operator)(other)
for attr in ("x", "y", "lat", "lon")]
return CoordPair(*args)
return func
def _unary_operator(operator):
def func(self):
args = [None if getattr(self, attr) is None
else getattr(getattr(self, attr), operator)()
for attr in ("x", "y", "lat", "lon")]
return CoordPair(*args)
return func
def _cmp_operator(operator):
def func(self, other):
vals = [getattr(getattr(self, attr), operator)(getattr(other, attr))
for attr in ("x", "y", "lat", "lon")
if getattr(self, attr) is not None]
return all(vals)
return func
class CoordPair(object):
def __init__(self, x=None, y=None, lat=None, lon=None):
self.x = x
self.y = y
self.lat = lat
self.lon = lon
def __repr__(self):
args = []
if self.x is not None:
args.append("x={}".format(self.x))
args.append("y={}".format(self.y))
if self.lat is not None:
args.append("lat={}".format(self.lat))
args.append("lon={}".format(self.lon))
argstr = ", ".join(args)
return "{}({})".format(self.__class__.__name__, argstr)
def __str__(self):
return self.__repr__()
def xy_str(self, fmt="{:.4f}, {:.4f}"):
if self.x is None or self.y is None:
return None
return fmt.format(self.x, self.y)
def latlon_str(self, fmt="{:.4f}, {:.4f}"):
if self.lat is None or self.lon is None:
return None
return fmt.format(self.lat, self.lon)
def __round__(self, d=None):
args = [None if getattr(self, attr) is None
else py2round(getattr(self, attr), d)
for attr in ("x", "y", "lat", "lon")]
return CoordPair(*args)
def __pow__(self, other, modulo=None):
if isinstance(other, CoordPair):
args = [
None if getattr(self, attr) is None or getattr(other, attr) is None
else getattr(getattr(self, attr), "__pow__")(getattr(other, attr),
modulo)
for attr in ("x", "y", "lat", "lon")]
else:
args = [
None if getattr(self, attr) is None
else getattr(getattr(self, attr), "__pow__")(other, modulo)
for attr in ("x", "y", "lat", "lon")]
return CoordPair(*args)
def __rpow__(self, other):
return self.__pow__(other)
for operator in ("__add__", "__divmod__", "__floordiv__", "__mod__",
"__mul__", "__sub__", "__truediv__", "__radd__",
"__rdivmod__", "__rsub__", "__rmul__", "__rtruediv__",
"__rfloordiv__", "__rmod__"):
setattr(CoordPair, operator, _binary_operator(operator))
for operator in ("__neg__", "__pos__", "__abs__", "__invert__"):
setattr(CoordPair, operator, _unary_operator(operator))
for operator in ("__lt__", "__le__", "__eq__", "__ne__", "__gt__", "__ge__"):
setattr(CoordPair, operator, _cmp_operator(operator))

41
src/wrf/metadecorators.py

@ -8,8 +8,9 @@ import numpy.ma as ma
from .extension import _interpline from .extension import _interpline
from .util import (extract_vars, combine_with, either, from_args, arg_location, from .util import (extract_vars, combine_with, either, from_args, arg_location,
is_coordvar, latlon_coordvars, CoordPair, npvalues, is_coordvar, latlon_coordvars, npvalues,
from_var, iter_left_indexes) from_var, iter_left_indexes)
from .coordpair import CoordPair
from .py3compat import viewkeys, viewitems, py3range, ucode from .py3compat import viewkeys, viewitems, py3range, ucode
from .interputils import get_xy_z_params, get_xy from .interputils import get_xy_z_params, get_xy
from .config import xarray_enabled from .config import xarray_enabled
@ -637,7 +638,7 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
ed_x = xy[-1,0] ed_x = xy[-1,0]
ed_y = xy[-1,1] ed_y = xy[-1,1]
cross_str = "Cross-Section: ({0}, {1}) to ({2}, {3})".format(st_x, st_y, cross_str = "({0}, {1}) to ({2}, {3})".format(st_x, st_y,
ed_x, ed_y) ed_x, ed_y)
if angle is not None: if angle is not None:
cross_str += " ; center={0} ; angle={1}".format(pivot_point, cross_str += " ; center={0} ; angle={1}".format(pivot_point,
@ -726,7 +727,7 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
outname = "field3d_cross" outname = "field3d_cross"
outattrs = OrderedDict() outattrs = OrderedDict()
outattrs["Orientation"] = cross_str outattrs["orientation"] = cross_str
outattrs["missing_value"] = missingval outattrs["missing_value"] = missingval
outattrs["_FillValue"] = missingval outattrs["_FillValue"] = missingval
@ -863,7 +864,7 @@ def _set_line_meta(wrapped, instance, args, kwargs):
outname = "field2d_line" outname = "field2d_line"
outattrs = OrderedDict() outattrs = OrderedDict()
outattrs["Orientation"] = cross_str outattrs["orientation"] = cross_str
return DataArray(result, name=outname, dims=outdimnames, return DataArray(result, name=outname, dims=outdimnames,
coords=outcoords, attrs=outattrs) coords=outcoords, attrs=outattrs)
@ -933,6 +934,11 @@ def _set_2dxy_meta(wrapped, instance, args, kwargs):
cross_str = "({0},{1}) to ({2},{3})".format(st_x, st_y, cross_str = "({0},{1}) to ({2},{3})".format(st_x, st_y,
ed_x, ed_y) ed_x, ed_y)
outname = None
outdimnames = None
outcoords = None
outattrs = None
# Dims are (...,xy,z) # Dims are (...,xy,z)
if isinstance(field3d, DataArray): if isinstance(field3d, DataArray):
outcoords = OrderedDict() outcoords = OrderedDict()
@ -976,56 +982,59 @@ def _set_2dxy_meta(wrapped, instance, args, kwargs):
else: else:
outname = "field3d_2dxy" outname = "field3d_2dxy"
outattrs["Orientation"] = cross_str outattrs["orientation"] = cross_str
return DataArray(result, name=outname, dims=outdimnames, return DataArray(result, name=outname, dims=outdimnames,
coords=outcoords, attrs=outattrs) coords=outcoords, attrs=outattrs)
def _set_1d_meta(wrapped, instance, args, kwargs): def _set_1d_meta(wrapped, instance, args, kwargs):
argvars = from_args(wrapped, ("v_in", "z_in", "z_out", "missingval"), argvars = from_args(wrapped, ("field", "z_in", "z_out", "missingval"),
*args, **kwargs) *args, **kwargs)
v_in = argvars["v_in"] field = argvars["field"]
z_in = argvars["z_in"] z_in = argvars["z_in"]
z_out = argvars["z_out"] z_out = argvars["z_out"]
missingval = argvars["missingval"] missingval = argvars["missingval"]
result = wrapped(*args, **kwargs) result = wrapped(*args, **kwargs)
outname = None
outdimnames = None
outcoords = None
outattrs = None
# Dims are (...,xy,z) # Dims are (...,xy,z)
if isinstance(v_in, DataArray): if isinstance(field, DataArray):
outcoords = OrderedDict() outcoords = OrderedDict()
outattrs = OrderedDict() outattrs = OrderedDict()
outdimnames = list(v_in.dims) outdimnames = list(field.dims)
#outcoords.update(v_in.coords)
outdimnames.pop(-1) outdimnames.pop(-1)
for name in outdimnames: for name in outdimnames:
try: try:
outcoords[name] = v_in.coords[name] outcoords[name] = field.coords[name]
except KeyError: except KeyError:
continue continue
outdimnames.append("z") outdimnames.append("z")
outname = "{0}_z".format(v_in.name) outname = "{0}_z".format(field.name)
outcoords["z"] = z_out outcoords["z"] = z_out
#outattrs.update(v_in.attrs)
outattrs["_FillValue"] = missingval outattrs["_FillValue"] = missingval
outattrs["missing_value"] = missingval outattrs["missing_value"] = missingval
desc = v_in.attrs.get("description", None) desc = field.attrs.get("description", None)
if desc is not None: if desc is not None:
outattrs["description"] = desc outattrs["description"] = desc
units = v_in.attrs.get("units", None) units = field.attrs.get("units", None)
if units is not None: if units is not None:
outattrs["units"] = units outattrs["units"] = units
else: else:
outname = "v_in_z" outname = "field_z"
return DataArray(result, name=outname, dims=outdimnames, return DataArray(result, name=outname, dims=outdimnames,

8
src/wrf/py3compat.py

@ -1,3 +1,6 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
from sys import version_info from sys import version_info
from math import floor, copysign from math import floor, copysign
@ -30,12 +33,13 @@ def isstr(s):
# Python 2 rounding behavior # Python 2 rounding behavior
def _round2(x, d=0): def _round2(x, d=None):
d = 0 if d is None else d
p = 10 ** d p = 10 ** d
return float(floor((x * p) + copysign(0.5, x)))/p return float(floor((x * p) + copysign(0.5, x)))/p
def py2round(x, d=0): def py2round(x, d=None):
if version_info >= (3,): if version_info >= (3,):
return _round2(x, d) return _round2(x, d)

51
src/wrf/util.py

@ -1509,55 +1509,6 @@ def get_proj_params(wrfnc, timeidx=0, varname=None):
proj_params) proj_params)
class CoordPair(object):
def __init__(self, x=None, y=None, i=None, j=None, lat=None, lon=None):
self.x = x
self.y = y
self.i = i
self.j = j
self.lat = lat
self.lon = lon
def __repr__(self):
args = []
if self.x is not None:
args.append("x={}".format(self.x))
args.append("y={}".format(self.y))
if self.i is not None:
args.append("i={}".format(self.i))
args.append("j={}".format(self.j))
if self.lat is not None:
args.append("lat={}".format(self.lat))
args.append("lon={}".format(self.lon))
argstr = ", ".join(args)
return "{}({})".format(self.__class__.__name__, argstr)
def __str__(self):
return self.__repr__()
def xy_str(self, fmt="{:.4f}, {:.4f}"):
if self.x is None or self.y is None:
return None
return fmt.format(self.x, self.y)
def latlon_str(self, fmt="{:.4f}, {:.4f}"):
if self.lat is None or self.lon is None:
return None
return fmt.format(self.lat, self.lon)
def ij_str(self, fmt="{:.4f}, {:.4f}"):
if self.i is None or self.j is None:
return None
return fmt.format(self.i, self.j)
def from_args(func, argnames, *args, **kwargs): def from_args(func, argnames, *args, **kwargs):
"""Parses the function args and kargs looking for the desired argument """Parses the function args and kargs looking for the desired argument
value. Otherwise, the value is taken from the default keyword argument value. Otherwise, the value is taken from the default keyword argument
@ -1569,7 +1520,7 @@ def from_args(func, argnames, *args, **kwargs):
else: else:
arglist = argnames arglist = argnames
result = {} result = OrderedDict()
for argname in arglist: for argname in arglist:
arg_loc = arg_location(func, argname, args, kwargs) arg_loc = arg_location(func, argname, args, kwargs)

Loading…
Cancel
Save