diff --git a/doc/source/contrib.rst b/doc/source/contrib.rst new file mode 100644 index 0000000..e5621ff --- /dev/null +++ b/doc/source/contrib.rst @@ -0,0 +1,63 @@ +.. _contrib_guide: + +Contributor Guide +================================= + +.. note:: + + This contributor guide is written for wrf-python v1.3.x. In the + not-too-distant future, wrf-python will undergo a significant refactoring + to remove the wrapt decorators (which don't serialize for dask), but the + concepts will remain the same as described below. + + +Ways to Contribute +----------------------------- + +Users are encouraged to contribute various ways. This includes: + +- Submitting a bug report +- Submitting bug fixes +- Submitting new Fortran computational routines +- Submitting new Python computational routines +- Submitting fully wrapped computational routines + + +Getting the source code +------------------------------ + +The source code is available on GitHub: + + https://github.com/NCAR/wrf-python + +To checkout the code:: + + git clone https://github.com/NCAR/wrf-python + + +Git Flow +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This project follows the GitFlow Workflow, which you can read about here if it +is new to you: + +https://leanpub.com/git-flow/read + +When you first clone the repository, by default you will be on the 'develop' +branch, which is what you should use for your development. + + +Pull Requests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In order to submit changes, you must use GitHub to issue a pull request. + + +Overview of WRF-Python Internals +---------------------------------- + +WRF-Python is a collection of diagnostic and interpolation routines for WRF-ARW +data. The API consists of a handful of functions + + + diff --git a/doc/source/index.rst b/doc/source/index.rst index 9156d82..7b9fe01 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -13,6 +13,14 @@ university corporation for atmospheric research, pynio, pyngl, interpolation + +.. .. image:: _static/images/nsf.png +.. :scale: 100% +.. :align: right + +.. | +.. | + wrf-python =========== @@ -57,6 +65,7 @@ Indices and tables * :ref:`modindex` * :ref:`search` + -------------------- *The National Center for Atmospheric Research is sponsored by the National @@ -64,4 +73,3 @@ Science Foundation. Any opinions, findings and conclusions or recommendations expressed in this material do not necessarily reflect the views of the National Science Foundation.* - diff --git a/src/wrf/__init__.py b/src/wrf/__init__.py index 2a60704..39cd608 100755 --- a/src/wrf/__init__.py +++ b/src/wrf/__init__.py @@ -2,19 +2,24 @@ from __future__ import (absolute_import, division, print_function) import os import pkg_resources -# For gfortran+msvc combination, extra shared libraries may exist (stored by numpy.distutils) -if os.name == "nt": - try: +try: + from . import api + from .api import * +except ImportError: + # For gfortran+msvc combination, extra shared libraries may exist + # (stored by numpy.distutils) + if os.name == "nt": req = pkg_resources.Requirement.parse("wrf-python") - extra_dll_dir = pkg_resources.resource_filename(req, + extra_dll_dir = pkg_resources.resource_filename(req, "wrf-python/.libs") if os.path.isdir(extra_dll_dir): os.environ["PATH"] += os.pathsep + extra_dll_dir - except ImportError: - pass -from . import api -from .api import * + from . import api + from .api import * + else: + raise + __all__ = [] __all__.extend(api.__all__) diff --git a/src/wrf/api.py b/src/wrf/api.py index 46f7d46..7882541 100644 --- a/src/wrf/api.py +++ b/src/wrf/api.py @@ -3,24 +3,24 @@ from .config import (xarray_enabled, disable_xarray, enable_xarray, basemap_enabled, disable_basemap, enable_basemap, pyngl_enabled, enable_pyngl, disable_pyngl, set_cache_size, get_cache_size, omp_enabled) -from .constants import (ALL_TIMES, Constants, ConversionFactors, +from .constants import (ALL_TIMES, Constants, ConversionFactors, ProjectionTypes, default_fill, - OMP_SCHED_STATIC, OMP_SCHED_DYNAMIC, + OMP_SCHED_STATIC, OMP_SCHED_DYNAMIC, OMP_SCHED_GUIDED, OMP_SCHED_AUTO) from .destag import destagger from .routines import getvar -from .computation import (xy, interp1d, interp2dxy, interpz3d, slp, tk, td, rh, +from .computation import (xy, interp1d, interp2dxy, interpz3d, slp, tk, td, rh, uvmet, smooth2d, cape_2d, cape_3d, cloudfrac, ctt, dbz, srhel, udhel, avo, pvo, eth, wetbulb, tvirtual, omega, pw) -from .extension import (DiagnosticError, omp_set_num_threads, - omp_get_num_threads, +from .extension import (DiagnosticError, omp_set_num_threads, + omp_get_num_threads, omp_get_max_threads, omp_get_thread_num, - omp_get_num_procs, omp_in_parallel, + omp_get_num_procs, omp_in_parallel, omp_set_dynamic, omp_get_dynamic, omp_set_nested, - omp_get_nested, omp_set_schedule, - omp_get_schedule, omp_get_thread_limit, - omp_set_max_active_levels, + omp_get_nested, omp_set_schedule, + omp_get_schedule, omp_get_thread_limit, + omp_set_max_active_levels, omp_get_max_active_levels, omp_get_level, omp_get_ancestor_thread_num, omp_get_team_size, omp_get_active_level, omp_in_final, @@ -32,23 +32,23 @@ from .extension import (DiagnosticError, omp_set_num_threads, omp_get_wtime, omp_get_wtick) from .interp import (interplevel, vertcross, interpline, vinterp) from .g_latlon import (xy_to_ll, ll_to_xy, xy_to_ll_proj, ll_to_xy_proj) -from .py3compat import (viewitems, viewkeys, viewvalues, isstr, py2round, +from .py3compat import (viewitems, viewkeys, viewvalues, isstr, py2round, py3range, ucode) from .util import (to_np, extract_global_attrs, is_standard_wrf_var, extract_dim, extract_vars, extract_times, combine_files, - extract_times, npbytes_to_str, is_moving_domain, + extract_times, npbytes_to_str, is_moving_domain, is_staggered, get_left_indexes, iter_left_indexes, - get_right_slices, get_proj_params, from_args, + get_right_slices, get_proj_params, from_args, args_to_list, arg_location, psafilepath, get_id, from_var, combine_dims, either, get_iterable, IterWrapper, is_coordvar, latlon_coordvars, is_mapping, has_time_coord, is_multi_file, is_multi_time_req, - get_coord_pairs, is_time_coord_var, geo_bounds, + get_coord_pairs, is_time_coord_var, geo_bounds, get_cartopy, get_basemap, get_pyngl, cartopy_xlim, cartopy_ylim, latlon_coords, ll_points, pairs_to_latlon) from .geobnds import GeoBounds, NullGeoBounds from .projection import (WrfProj, NullProjection, LambertConformal, Mercator, - PolarStereographic, LatLon, RotatedLatLon, + PolarStereographic, LatLon, RotatedLatLon, getproj) from .coordpair import CoordPair from .interputils import to_xy_coords @@ -62,22 +62,22 @@ __all__ += ["xarray_enabled", "disable_xarray", "enable_xarray", "pyngl_enabled", "enable_pyngl", "disable_pyngl", "set_cache_size", "get_cache_size", "omp_enabled"] __all__ += ["ALL_TIMES", "Constants", "ConversionFactors", "ProjectionTypes", - "default_fill", "OMP_SCHED_STATIC", "OMP_SCHED_DYNAMIC", + "default_fill", "OMP_SCHED_STATIC", "OMP_SCHED_DYNAMIC", "OMP_SCHED_GUIDED", "OMP_SCHED_AUTO"] __all__ += ["destagger"] __all__ += ["getvar"] -__all__ += ["xy", "interp1d", "interp2dxy", "interpz3d", "slp", "tk", "td", +__all__ += ["xy", "interp1d", "interp2dxy", "interpz3d", "slp", "tk", "td", "rh", "uvmet", "smooth2d", "cape_2d", "cape_3d", "cloudfrac", "ctt", "dbz", "srhel", "udhel", "avo", "pvo", "eth", "wetbulb", "tvirtual", "omega", "pw"] -__all__ += ["DiagnosticError", "omp_set_num_threads", - "omp_get_num_threads", +__all__ += ["DiagnosticError", "omp_set_num_threads", + "omp_get_num_threads", "omp_get_max_threads", "omp_get_thread_num", - "omp_get_num_procs", "omp_in_parallel", + "omp_get_num_procs", "omp_in_parallel", "omp_set_dynamic", "omp_get_dynamic", "omp_set_nested", - "omp_get_nested", "omp_set_schedule", - "omp_get_schedule", "omp_get_thread_limit", - "omp_set_max_active_levels", + "omp_get_nested", "omp_set_schedule", + "omp_get_schedule", "omp_get_thread_limit", + "omp_set_max_active_levels", "omp_get_max_active_levels", "omp_get_level", "omp_get_ancestor_thread_num", "omp_get_team_size", "omp_get_active_level", "omp_in_final", @@ -89,18 +89,18 @@ __all__ += ["DiagnosticError", "omp_set_num_threads", "omp_get_wtime", "omp_get_wtick"] __all__ += ["interplevel", "vertcross", "interpline", "vinterp"] __all__ += ["xy_to_ll", "ll_to_xy", "xy_to_ll_proj", "ll_to_xy_proj"] -__all__ += ["viewitems", "viewkeys", "viewvalues", "isstr", "py2round", +__all__ += ["viewitems", "viewkeys", "viewvalues", "isstr", "py2round", "py3range", "ucode"] __all__ += ["to_np", "extract_global_attrs", "is_standard_wrf_var", "extract_dim", "extract_vars", "extract_times", "combine_files", - "extract_times", "npbytes_to_str", "is_moving_domain", - "is_staggered", "get_left_indexes", "iter_left_indexes", - "get_right_slices", "get_proj_params", "from_args", + "extract_times", "npbytes_to_str", "is_moving_domain", + "is_staggered", "get_left_indexes", "iter_left_indexes", + "get_right_slices", "get_proj_params", "from_args", "args_to_list", "arg_location", "psafilepath", "get_id", "from_var", "combine_dims", "either", "get_iterable", "IterWrapper", "is_coordvar", "latlon_coordvars", "is_mapping", "has_time_coord", "is_multi_file", "is_multi_time_req", - "get_coord_pairs", "is_time_coord_var", "geo_bounds", + "get_coord_pairs", "is_time_coord_var", "geo_bounds", "get_cartopy", "get_basemap", "get_pyngl", "cartopy_xlim", "cartopy_ylim", "latlon_coords", "ll_points", "pairs_to_latlon"] __all__ += ["GeoBounds", "NullGeoBounds"] @@ -110,4 +110,3 @@ __all__ += ["CoordPair"] __all__ += ["to_xy_coords"] __all__ += ["cache_item", "get_cached_item"] __all__ += ["__version__"] - diff --git a/src/wrf/cache.py b/src/wrf/cache.py index 571f653..64a4da6 100644 --- a/src/wrf/cache.py +++ b/src/wrf/cache.py @@ -11,158 +11,153 @@ _local_storage = local() def _shrink_cache(): """Shrink the cache if applicable. - - This only applies if a user has modified the cache size, otherwise it + + This only applies if a user has modified the cache size, otherwise it just returns. - + Returns: - + None - + """ global _local_storage - + try: cache = _local_storage.cache except AttributeError: return - + diff = len(cache) - get_cache_size() - + if diff > 0: for _ in py3range(diff): cache.popitem(last=False) - + def cache_item(key, product, value): """Store an item in the threadlocal cache. - - The cache should be viewed as two nested dictionaries. The outer key is - usually the id for the sequence where the cached item was generated. The + + The cache should be viewed as two nested dictionaries. The outer key is + usually the id for the sequence where the cached item was generated. The inner key is the product type. - + Storing a cached item behaves like: - + cache[key][product] = value - - The cache is thread local, so stored items are only available in + + The cache is thread local, so stored items are only available in the thread that cached them. - + Args: - - key (:obj:`int`): The outer dictionary cache key, which is typically + + key (:obj:`int`): The outer dictionary cache key, which is typically the id of the sequence where the cached item was generated. - - product (:obj:`str`): The inner dictionary cache key, which is a + + product (:obj:`str`): The inner dictionary cache key, which is a string for the product type. - + value (:obj:`object`): The object to store in the cache. - + Returns: - + None. - + See Also: - + :meth:`get_cached_item` - + """ global _local_storage - + _shrink_cache() - + if key is None or get_cache_size() == 0: return - + try: cache = _local_storage.cache except AttributeError: _local_storage.cache = OrderedDict() cache = _local_storage.cache - + try: _ = cache[key] except KeyError: if len(cache) >= get_cache_size(): - cache.popitem(last=False) # Remove the oldest dataset - + cache.popitem(last=False) # Remove the oldest dataset + cache[key] = OrderedDict() - + cache[key][product] = value - - + + def get_cached_item(key, product): """Return an item from the threadlocal cache. - - The cache should be viewed as two nested dictionaries. The outer key is - usually the id for the sequence where the cached item was generated. The + + The cache should be viewed as two nested dictionaries. The outer key is + usually the id for the sequence where the cached item was generated. The inner key is the product type. - + Retrieving a cached item behaves like: - + value = cache[key][product] - - The cache is thread local, so stored items are only available in + + The cache is thread local, so stored items are only available in the thread that cached them. - + Args: - - key (:obj:`int`): The outer dictionary cache key, which is typically + + key (:obj:`int`): The outer dictionary cache key, which is typically the id of the sequence where the cached item was generated. - - product (:obj:`str`): The inner dictionary cache key, which is a + + product (:obj:`str`): The inner dictionary cache key, which is a string for the product type. - + Returns: - + :obj:`object`: The cached object. - + See Also: - + :meth:`cache_item` - + """ global _local_storage - + _shrink_cache() - + if key is None or get_cache_size == 0: return None - + cache = getattr(_local_storage, "cache", None) - + if cache is None: return None - + if len(cache) == 0: return None - + prod_dict = cache.get(key, None) - + if prod_dict is None: return None - + result = prod_dict.get(product, None) - + return result def _get_cache(): """Return the threadlocal cache. - + This is primarily used for testing. - + Returns: - + :class:`threading.local` - + """ global _local_storage - + _shrink_cache() return getattr(_local_storage, "cache", None) - - - - - \ No newline at end of file diff --git a/src/wrf/computation.py b/src/wrf/computation.py index f75ae87..5241230 100644 --- a/src/wrf/computation.py +++ b/src/wrf/computation.py @@ -4,174 +4,175 @@ import numpy as np import numpy.ma as ma from .constants import default_fill -from .extension import (_interpz3d, _interp2dxy, _interp1d, _slp, _tk, _td, +from .extension import (_interpz3d, _interp2dxy, _interp1d, _slp, _tk, _td, _rh, _uvmet, _smooth2d, _cape, _cloudfrac, _ctt, _dbz, - _srhel, _udhel, _avo, _pvo, _eth, _wetbulb, _tv, + _srhel, _udhel, _avo, _pvo, _eth, _wetbulb, _tv, _omega, _pw) from .decorators import convert_units -from .metadecorators import (set_alg_metadata, set_uvmet_alg_metadata, +from .metadecorators import (set_alg_metadata, set_uvmet_alg_metadata, set_interp_metadata, set_cape_alg_metadata, set_cloudfrac_alg_metadata, set_smooth_metdata) from .interputils import get_xy + @set_interp_metadata("xy") def xy(field, pivot_point=None, angle=None, start_point=None, end_point=None, meta=True): """Return the x,y points for a line within a two-dimensional grid. - - This function is primarily used to obtain the x,y points when making a + + This function is primarily used to obtain the x,y points when making a cross section. - + Args: - - field (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A + + field (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A field with at least two dimensions. - - pivot_point (:obj:`tuple` or :obj:`list`, optional): A - :obj:`tuple` or :obj:`list` with two entries, - in the form of [x, y] (or [west_east, south_north]), which - indicates the x,y location through which the plane will pass. + + pivot_point (:obj:`tuple` or :obj:`list`, optional): A + :obj:`tuple` or :obj:`list` with two entries, + in the form of [x, y] (or [west_east, south_north]), which + indicates the x,y location through which the plane will pass. Must also specify `angle`. - - angle (:obj:`float`, optional): Only valid for cross sections where - a plane will be plotted through - a given point on the model domain. 0.0 represents a S-N cross - section. 90.0 is a W-E cross section. - - start_point (:obj:`tuple` or :obj:`list`, optional): A - :obj:`tuple` or :obj:`list` with two entries, in the form of - [x, y] (or [west_east, south_north]), which indicates the start + + angle (:obj:`float`, optional): Only valid for cross sections where + a plane will be plotted through + a given point on the model domain. 0.0 represents a S-N cross + section. 90.0 is a W-E cross section. + + start_point (:obj:`tuple` or :obj:`list`, optional): A + :obj:`tuple` or :obj:`list` with two entries, in the form of + [x, y] (or [west_east, south_north]), which indicates the start x,y location through which the plane will pass. - - end_point (:obj:`tuple` or :obj:`list`, optional): A - :obj:`tuple` or :obj:`list` with two entries, in the form of - [x, y] (or [west_east, south_north]), which indicates the end x,y + + end_point (:obj:`tuple` or :obj:`list`, optional): A + :obj:`tuple` or :obj:`list` with two entries, in the form of + [x, y] (or [west_east, south_north]), which indicates the end x,y location through which the plane will pass. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: An array of - x,y points, which has shape num_points x 2. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: An array of + x,y points, which has shape num_points x 2. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + Examples: - + Example 1: Using Pivot Point and Angle - + .. code-block:: python - + from wrf import getvar, xy from netCDF4 import Dataset - + wrfnc = Dataset("wrfout_d02_2010-06-13_21:00:00") field = wrf.getvar(wrfnc, "slp") - + # Use the center of the grid pivot = (field.shape[-1]/2.0, field.shape[-2]/2.0) - + # West-East angle = 90.0 - + xy_points = xy(field, pivot_point=pivot, angle=angle) - + Example 2: Using Start Point and End Point - + .. code-block:: python - + from wrf import getvar, xy from netCDF4 import Dataset - + wrfnc = Dataset("wrfout_d02_2010-06-13_21:00:00") field = wrf.getvar(wrfnc, "slp") - + # Make a diagonal of lower left to upper right start = (0, 0) end = (-1, -1) - + xy_points = xy(field, start_point=start, end_point=end) - - + + """ return get_xy(field, pivot_point, angle, start_point, end_point) - + @set_interp_metadata("1d") -def interp1d(field, z_in, z_out, missing=default_fill(np.float64), +def interp1d(field, z_in, z_out, missing=default_fill(np.float64), meta=True): """Return the linear interpolation of a one-dimensional variable. - + This function is typically used to interpolate a variable in a vertical - column, but the coordinate system need not be a vertical coordinate - system. Multiple interpolation points may be specified in the *z_out* + column, but the coordinate system need not be a vertical coordinate + system. Multiple interpolation points may be specified in the *z_out* parameter. - + Args: - + field (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A - one-dimensional field. Metadata for *field* is only copied + one-dimensional field. Metadata for *field* is only copied to the output if *field* is a :class:`xarray.DataArray` object. - - z_in (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The - one-dimensional coordinates associated with *field* (usually the + + z_in (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The + one-dimensional coordinates associated with *field* (usually the vertical coordinates, either height or pressure). - - z_out (:class:`xarray.DataArray`, :class:`numpy.ndarray`): A - one-dimensional array of *z_in* coordinate points to interpolate - to. Must be the same type as *z_in*. - - missing (:obj:`float`, optional): The fill value to use for the + + z_out (:class:`xarray.DataArray`, :class:`numpy.ndarray`): A + one-dimensional array of *z_in* coordinate points to interpolate + to. Must be the same type as *z_in*. + + missing (:obj:`float`, optional): The fill value to use for the output. Default is :data:`wrf.default_fill(np.float64)`. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - + :class:`xarray.DataArray` or :class:`numpy.ndarray`: An array with the same dimensionality as *z_out* containing the interpolated values. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - - + + Examples: - + Example 1: Calculate the 850 hPa and 500 hPa values at location \ x,y = (100,200) - + .. code-block:: python - + import numpy as np from wrf import getvar, interp1d from netCDF4 import Dataset - + wrfnc = Dataset("wrfout_d02_2010-06-13_21:00:00") - + # Get a 1D vertical column for pressure at location x,y = 100,200 p_1d = wrf.getvar(wrfnc, "pres", units="hPa")[:,200,100] - + # Get a 1D vertical column for height at location 100,200 ht_1d = wrf.getvar(wrfnc, "z", units="dm")[:,200,100] - + # Want the heights (in decameters) at 850, 500 hPa levels = np.asarray([850., 500.]) - + # Get the 850 hPa and 500 hPa values at location 100,200. interp_vals = interp1d(p_1d, ht_1d, levels) - + """ return _interp1d(field, z_in, z_out, missing) @@ -179,72 +180,72 @@ def interp1d(field, z_in, z_out, missing=default_fill(np.float64), @set_interp_metadata("2dxy") def interp2dxy(field3d, xy, meta=True): """Return a cross section for a three-dimensional field. - - The returned array will hold the vertical cross section data along the + + The returned array will hold the vertical cross section data along the line described by *xy*. - - This method differs from :meth:`wrf.vertcross` in that it will return - all vertical levels found in *field3d*. :meth:`wrf.vertcross` includes - an additional interpolation to set the output to a fixed number of - vertical levels. Also, a :class:`numpy.ma.MaskedArray` is not created - and this routine should be considered as low-level access to the underlying + + This method differs from :meth:`wrf.vertcross` in that it will return + all vertical levels found in *field3d*. :meth:`wrf.vertcross` includes + an additional interpolation to set the output to a fixed number of + vertical levels. Also, a :class:`numpy.ma.MaskedArray` is not created + and this routine should be considered as low-level access to the underlying Fortran routine. - + See Also: - + :meth:`wrf.xy`, :meth:`wrf.vertcross` - + Args: - - field3d (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The - array to interpolate with at least three dimensions, whose + + field3d (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The + array to interpolate with at least three dimensions, whose rightmost dimensions are nz x ny x nx. - - xy (:class:`xarray.DataArray` or :class:`numpy.ndarray`): An array - of one less dimension than *field3d*, whose rightmost dimensions - are nxy x 2. This array holds the x,y pairs of a line across the - model domain. The requested vertical cross section will be + + xy (:class:`xarray.DataArray` or :class:`numpy.ndarray`): An array + of one less dimension than *field3d*, whose rightmost dimensions + are nxy x 2. This array holds the x,y pairs of a line across the + model domain. The requested vertical cross section will be extracted from *field3d* along this line. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - - + + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: An array - containing the vertical cross section along the line *xy*. The + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: An array + containing the vertical cross section along the line *xy*. The returned dimensions will be the same as *xy*, but with the rightmost - dimensions being nz x nxy. If xarray is enabled and the *meta* - parameter is True, then the result will be a :class:`xarray.DataArray` - object. Otherwise, the result will + dimensions being nz x nxy. If xarray is enabled and the *meta* + parameter is True, then the result will be a :class:`xarray.DataArray` + object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + Examples: - - Example 1: Calculate the vertical cross section for RH for a diagonal + + Example 1: Calculate the vertical cross section for RH for a diagonal line from the lower left to the upper right of the domain. - + .. code-block:: python - + from wrf import getvar, xy, interp2dxy from netCDF4 import Dataset - + wrfnc = Dataset("wrfout_d02_2010-06-13_21:00:00") - + rh = getvar(wrfnc, "rh") start = (0, 0) end = (-1, -1) xy_line = xy(rh, start_point=start, end_point=end) - + vert_cross = interp2dxy(rh, xy_line) - + """ return _interp2dxy(field3d, xy) @@ -253,67 +254,67 @@ def interp2dxy(field3d, xy, meta=True): def interpz3d(field3d, vert, desiredlev, missing=default_fill(np.float64), meta=True): """Return the field interpolated to a specified pressure or height level. - - This function is roughly equivalent to :meth:`interplevel`, but does not - handle multi-product diagnostics (uvmet, cape_3d, etc) that contain an - additional leftmost dimension for the product type. Also, a + + This function is roughly equivalent to :meth:`interplevel`, but does not + handle multi-product diagnostics (uvmet, cape_3d, etc) that contain an + additional leftmost dimension for the product type. Also, a :class:`numpy.ma.MaskedArray` is not created and this routine should be considered as low-level access to the underlying Fortran routine. - + See Also: - + :meth:`wrf.interplevel` - + Args: - - field3d (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A - three-dimensional field to interpolate, with the rightmost + + field3d (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A + three-dimensional field to interpolate, with the rightmost dimensions of nz x ny x nx. - - vert (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A - three-dimensional array for the vertical coordinate, typically + + vert (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A + three-dimensional array for the vertical coordinate, typically pressure or height. This array must have the same dimensionality as *field3d*. - - desiredlev (:obj:`float`): The desired vertical level. + + desiredlev (:obj:`float`): The desired vertical level. Must be in the same units as the *vert* parameter. - - missing (:obj:`float`): The fill value to use for the output. + + missing (:obj:`float`): The fill value to use for the output. Default is :data:`wrf.default_fill(numpy.float64)`. - - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - interpolated variable. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + interpolated variable. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + Example: - + Example 1: Interpolate Geopotential Height to 500 hPa - + .. code-block:: python - + from netCDF4 import Dataset from wrf import getvar, interpz3d - + wrfin = Dataset("wrfout_d02_2010-06-13_21:00:00") - + p = getvar(wrfin, "pressure") ht = getvar(wrfin, "z", units="dm") - + ht_500 = interpz3d(ht, p, 500.0) - + """ return _interpz3d(field3d, vert, desiredlev, missing) @@ -322,59 +323,59 @@ def interpz3d(field3d, vert, desiredlev, missing=default_fill(np.float64), @convert_units("pressure", "hpa") def slp(height, tkel, pres, qv, meta=True, units="hPa"): """Return the sea level pressure. - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - + Args: - - height (:class:`xarray.DataArray` or :class:`numpy.ndarray`): - Geopotential height in [m] with the rightmost dimensions being + + height (:class:`xarray.DataArray` or :class:`numpy.ndarray`): + Geopotential height in [m] with the rightmost dimensions being bottom_top x south_north x west_east. - + tkel (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Temperature - in [K] with same dimensionality as *height*. - - pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full - pressure (perturbation + base state pressure) in [Pa] with - the same dimensionality as *height*. - - Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + in [K] with same dimensionality as *height*. + + pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full + pressure (perturbation + base state pressure) in [Pa] with + the same dimensionality as *height*. + + Note: + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - - qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor + + qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor mixing ratio in [kg/kg] with the same dimensionality as *height*. - - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'slp'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'slp'. Default is 'hPa'. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - sea level pressure. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + sea level pressure. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar`, :meth:`wrf.temp`, :meth:`wrf.tk` - + """ return _slp(height, tkel, pres, qv) @@ -383,56 +384,56 @@ def slp(height, tkel, pres, qv, meta=True, units="hPa"): @convert_units("temp", "k") def tk(pres, theta, meta=True, units="K"): """Return the temperature. - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full + + Args: + + pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full pressure (perturbation + base state pressure) in [Pa] with at least - three dimensions. The rightmost dimensions are bottom_top x - south_north x west_east. - + three dimensions. The rightmost dimensions are bottom_top x + south_north x west_east. + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - + theta (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Potential temperature (perturbation plus reference temperature) in [K] with the same dimensionality as *pres*. - - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'temp'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'temp'. Default is 'K'. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - temperature in the specified units. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + temperature in the specified units. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar`, :meth:`wrf.tk` - + """ - + return _tk(pres, theta) @@ -440,53 +441,53 @@ def tk(pres, theta, meta=True, units="K"): @convert_units("temp", "c") def td(pres, qv, meta=True, units="degC"): """Return the dewpoint temperature. - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full - pressure (perturbation + base state pressure) in [hPa] with at - least three dimensions. The rightmost dimensions are bottom_top x - south_north x west_east. - + + Args: + + pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full + pressure (perturbation + base state pressure) in [hPa] with at + least three dimensions. The rightmost dimensions are bottom_top x + south_north x west_east. + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - - qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor + + qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor mixing ratio in [kg/kg] with the same dimensionality as *pres*. - - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'dp'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'dp'. Default is 'degC'. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - dewpoint temperature. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + dewpoint temperature. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar`, :meth:`wrf.rh` - + """ return _td(pres, qv) @@ -494,59 +495,59 @@ def td(pres, qv, meta=True, units="degC"): @set_alg_metadata(3, "pres", description="relative humidity", units=None) def rh(qv, pres, tkel, meta=True): """Return the relative humidity. - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor - mixing ratio in [kg/kg] with at least three dimensions. The - rightmost dimensions are bottom_top x south_north x west_east. - - pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full - pressure (perturbation + base state pressure) in [Pa] with the - same dimensionality as *qv*. - + + Args: + + qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor + mixing ratio in [kg/kg] with at least three dimensions. The + rightmost dimensions are bottom_top x south_north x west_east. + + pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full + pressure (perturbation + base state pressure) in [Pa] with the + same dimensionality as *qv*. + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - + tkel (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Temperature in [K] with same dimensionality as *qv*. - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - relative humidity. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + relative humidity. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar`, :meth:`wrf.td` - + """ return _rh(qv, pres, tkel) @@ -555,123 +556,123 @@ def rh(qv, pres, tkel, meta=True): @convert_units("wind", "m s-1") def uvmet(u, v, lat, lon, cen_long, cone, meta=True, units="m s-1"): """Return the u,v components of the wind rotated to earth coordinates. - - The leftmost dimension of the returned array represents two different + + The leftmost dimension of the returned array represents two different quantities: - - - return_val[0,...] will contain U + + - return_val[0,...] will contain U - return_val[1,...] will contain V - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - u (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The u - component of the wind [m s-1]. This variable can be staggered or + + Args: + + u (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The u + component of the wind [m s-1]. This variable can be staggered or unstaggered, but must be at least two dimensions. If staggered, the rightmost dimensions are south_north x west east. - - If staggered, the rightmost dimensions are south_north x + + If staggered, the rightmost dimensions are south_north x west_east_stag. - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will - be used. - - v (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The v - component of the wind [m s-1]. This variable can be staggered or + be used. + + v (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The v + component of the wind [m s-1]. This variable can be staggered or unstaggered, but must be at least two dimensions. If staggered, the rightmost dimensions are south_north x west east. - - If staggered, the rightmost dimensions are south_north_stag x + + If staggered, the rightmost dimensions are south_north_stag x west_east. - - lat (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The - latitude array. - + + lat (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The + latitude array. + This array can either be: - + - two-dimensional of size south_north x west_east. - - multi-dimensional with the same number of dimensions as *u* - and *v*, but with rightmost dimensions south_north x + - multi-dimensional with the same number of dimensions as *u* + and *v*, but with rightmost dimensions south_north x west_east and the same leftmost dimensions as *u* and *v* - - multi-dimensional with one fewer dimensions as *u* and *v*, - with rightmost dimensions south_north x west_east and the same - leftmost dimensions as *u* and *v*, minus the + - multi-dimensional with one fewer dimensions as *u* and *v*, + with rightmost dimensions south_north x west_east and the + same leftmost dimensions as *u* and *v*, minus the third-from-the-right dimension of *u* and *v*. - + Note: - - This variable must also be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must also be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will - be used. - - lon (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The - longitude array. - + be used. + + lon (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The + longitude array. + This array can either be: - + - two-dimensional of size south_north x west_east. - - multi-dimensional with the same number of dimensions as *u* - and *v*, but with rightmost dimensions south_north x + - multi-dimensional with the same number of dimensions as *u* + and *v*, but with rightmost dimensions south_north x west_east and the same leftmost dimensions as *u* and *v* - - multi-dimensional with one fewer dimensions as *u* and *v*, - with rightmost dimensions south_north x west_east and the same - leftmost dimensions as *u* and *v*, minus the + - multi-dimensional with one fewer dimensions as *u* and *v*, + with rightmost dimensions south_north x west_east and the + same leftmost dimensions as *u* and *v*, minus the third-from-the-right dimension of *u* and *v*. - - + + cen_long (:obj:`float`): The standard longitude for the map projection. - - cone (:obj:`float`): The cone factor used for the map project. If the - projection is not a conic projection, the *cone* is simply 1.0. + + cone (:obj:`float`): The cone factor used for the map project. If the + projection is not a conic projection, the *cone* is simply 1.0. For conic projections, the cone factor is given by: - + .. code-block:: python - - if((fabs(true_lat1 - true_lat2) > 0.1) and - (fabs(true_lat2 - 90.) > 0.1)): - cone = (log(cos(true_lat1*radians_per_degree)) + + if((fabs(true_lat1 - true_lat2) > 0.1) and + (fabs(true_lat2 - 90.) > 0.1)): + cone = (log(cos(true_lat1*radians_per_degree)) - log(cos(true_lat2*radians_per_degree))) - - cone = (cone / - (log(tan((45.-fabs(true_lat1/2.))*radians_per_degree)) - - log(tan((45.-fabs(true_lat2/2.))*radians_per_degree)))) + + cone = (cone / + (log(tan((45.-fabs(true_lat1/2.))*radians_per_degree)) + - log(tan((45.-fabs(true_lat2/2.))*radians_per_degree)))) else: cone = sin(fabs(true_lat1)*radians_per_degree) - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'uvmet'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'uvmet'. Default is 'm s-1'. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - u,v components of the wind rotated to earth coordinates. The leftmost - dimension size is 2, for u and v. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + u,v components of the wind rotated to earth coordinates. The leftmost + dimension size is 2, for u and v. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar` - + """ return _uvmet(u, v, lat, lon, cen_long, cone) @@ -679,323 +680,323 @@ def uvmet(u, v, lat, lon, cen_long, cone, meta=True, units="m s-1"): @set_smooth_metdata() def smooth2d(field, passes, cenweight=2.0, meta=True): """Return the field smoothed. - + The smoothing kernel applied is: - - .. math:: - + + .. math:: + \\frac{1}{4 + cenweight} * \\begin{bmatrix} 0 & 1 & 0 \\\\ 1 & cenweight & 1 \\\\ 0 & 1 & 0 \\end{bmatrix} - - Data values along the borders are left unchanged. This routine does not + + Data values along the borders are left unchanged. This routine does not modify the original data supplied by the *field* parameter.. - - If you need more general purpose multidimensional filtering tools, + + If you need more general purpose multidimensional filtering tools, try the :meth:`scipy.ndimage.convolve` method. - + Args: - + field (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The field - to smooth, which must be at least two dimensions. Missing/fill - values will be ignored as long as the type is either a - :class:`numpy.ma.MaskedArray` or a :class:`xarray.DataArray` with + to smooth, which must be at least two dimensions. Missing/fill + values will be ignored as long as the type is either a + :class:`numpy.ma.MaskedArray` or a :class:`xarray.DataArray` with a *_FillValue* attribute. - + passes (:obj:`int`): The number of smoothing passes. - - cenweight (:obj:`float`, optional): The weight to apply to the + + cenweight (:obj:`float`, optional): The weight to apply to the center of the smoothing kernel. Default is 2.0. - - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Returns: - + :class:`xarray.DataArray`, :class:`numpy.ma.MaskedArray` or \ - :class:`numpy.ndarray`): The smoothed field. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will - be either a :class:`numpy.ndarray` or a :class:`numpy.ma.MaskedArray` + :class:`numpy.ndarray`): The smoothed field. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will + be either a :class:`numpy.ndarray` or a :class:`numpy.ma.MaskedArray` depending on the type for *field*. - + See Also: - + :meth:`scipy.ndimage.convolve` - - + + """ return _smooth2d(field, passes, cenweight) @set_cape_alg_metadata(is2d=True, copyarg="pres_hpa") -def cape_2d(pres_hpa, tkel, qv, height, terrain, psfc_hpa, ter_follow, +def cape_2d(pres_hpa, tkel, qv, height, terrain, psfc_hpa, ter_follow, missing=default_fill(np.float64), meta=True): """Return the two-dimensional MCAPE, MCIN, LCL, and LFC. - - This function calculates the maximum convective available potential - energy (MCAPE), maximum convective inhibition (MCIN), - lifted condensation level (LCL), and level of free convection (LFC). This - function uses the RIP [Read/Interpolate/plot] code to calculate - potential energy (CAPE) and convective inhibition - (CIN) [J kg-1] only for the parcel with max theta-e - in the column (i.e. something akin to Colman's MCAPE). CAPE is defined as - the accumulated buoyant energy from the level of free convection (LFC) to - the equilibrium level (EL). CIN is defined as the accumulated negative - buoyant energy from the parcel starting point to the LFC. - - The cape_2d algorithm works by first finding the maximum theta-e height - level in the lowest 3000 m. A parcel with a depth of 500 m is then - calculated and centered over this maximum theta-e height level. The - parcel's moisture and temperature characteristics are calculated by - averaging over the depth of this 500 m parcel. This 'maximum' parcel + + This function calculates the maximum convective available potential + energy (MCAPE), maximum convective inhibition (MCIN), + lifted condensation level (LCL), and level of free convection (LFC). This + function uses the RIP [Read/Interpolate/plot] code to calculate + potential energy (CAPE) and convective inhibition + (CIN) [J kg-1] only for the parcel with max theta-e + in the column (i.e. something akin to Colman's MCAPE). CAPE is defined as + the accumulated buoyant energy from the level of free convection (LFC) to + the equilibrium level (EL). CIN is defined as the accumulated negative + buoyant energy from the parcel starting point to the LFC. + + The cape_2d algorithm works by first finding the maximum theta-e height + level in the lowest 3000 m. A parcel with a depth of 500 m is then + calculated and centered over this maximum theta-e height level. The + parcel's moisture and temperature characteristics are calculated by + averaging over the depth of this 500 m parcel. This 'maximum' parcel is then used to compute MCAPE, MCIN, LCL and LFC. - - The leftmost dimension of the returned array represents four different + + The leftmost dimension of the returned array represents four different quantities: - + - return_val[0,...] will contain MCAPE [J kg-1] - return_val[1,...] will contain MCIN [J kg-1] - return_val[2,...] will contain LCL [m] - return_val[3,...] will contain LFC [m] - - This function also supports computing MCAPE along a single vertical + + This function also supports computing MCAPE along a single vertical column. In this mode, the *pres_hpa*, *tkel*, *qv* and *height* arguments - must be one-dimensional vertical columns, and the *terrain* and - *psfc_hpa* arguments must be scalar values + must be one-dimensional vertical columns, and the *terrain* and + *psfc_hpa* arguments must be scalar values (:obj:`float`, :class:`numpy.float32` or :class:`numpy.float64`). - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - pres_hpa (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full - pressure (perturbation + base state pressure) in [hPa] with at - least three dimensions. The rightmost dimensions can be + + Args: + + pres_hpa (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full + pressure (perturbation + base state pressure) in [hPa] with at + least three dimensions. The rightmost dimensions can be top_bottom x south_north x west_east or bottom_top x south_north x west_east. - When operating on only a single column of values, the vertical - column can be bottom_top or top_bottom. In this case, *terrain* + When operating on only a single column of values, the vertical + column can be bottom_top or top_bottom. In this case, *terrain* and *psfc_hpa* must be scalars. - + Note: - + The units for *pres_hpa* are [hPa]. - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - + tkel (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Temperature in [K] with same dimensionality as *pres_hpa*. - - qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor + + qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor mixing ratio in [kg/kg] with the same dimensionality as *pres_hpa*. - - height (:class:`xarray.DataArray` or :class:`numpy.ndarray`): - Geopotential height in [m] with the same dimensionality as + + height (:class:`xarray.DataArray` or :class:`numpy.ndarray`): + Geopotential height in [m] with the same dimensionality as *pres_hpa*. - - terrain (:class:`xarray.DataArray` or :class:`numpy.ndarray`): - Terrain height in [m]. This is at least a two-dimensional array - with the same dimensionality as *pres_hpa*, excluding the vertical - (bottom_top/top_bottom) dimension. When operating on a single - vertical column, this argument must be a scalar (:obj:`float`, + + terrain (:class:`xarray.DataArray` or :class:`numpy.ndarray`): + Terrain height in [m]. This is at least a two-dimensional array + with the same dimensionality as *pres_hpa*, excluding the vertical + (bottom_top/top_bottom) dimension. When operating on a single + vertical column, this argument must be a scalar (:obj:`float`, :class:`numpy.float32`, or :class:`numpy.float64`). - - psfc_hpa (:class:`xarray.DataArray` or :class:`numpy.ndarray`): - The surface pressure in [hPa]. This is at least a two-dimensional - array with the same dimensionality as *pres_hpa*, excluding the - vertical (bottom_top/top_bottom) dimension. When operating on a - singlevertical column, this argument must be a scalar + + psfc_hpa (:class:`xarray.DataArray` or :class:`numpy.ndarray`): + The surface pressure in [hPa]. This is at least a two-dimensional + array with the same dimensionality as *pres_hpa*, excluding the + vertical (bottom_top/top_bottom) dimension. When operating on a + singlevertical column, this argument must be a scalar (:obj:`float`, :class:`numpy.float32`, or :class:`numpy.float64`). - + Note: - + The units for *psfc_hpa* are [hPa]. - - ter_follow (:obj:`bool`): A boolean that should be set to True if the - data uses terrain following coordinates (WRF data). Set to + + ter_follow (:obj:`bool`): A boolean that should be set to True if the + data uses terrain following coordinates (WRF data). Set to False for pressure level data. - - missing (:obj:`float`, optional): The fill value to use for the + + missing (:obj:`float`, optional): The fill value to use for the output. Default is :data:`wrf.default_fill(numpy.float64)`. - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - cape, cin, lcl, and lfc values as an array whose - leftmost dimension is 4 (0=CAPE, 1=CIN, 2=LCL, 3=LFC) . If xarray is - enabled and the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + cape, cin, lcl, and lfc values as an array whose + leftmost dimension is 4 (0=CAPE, 1=CIN, 2=LCL, 3=LFC) . If xarray is + enabled and the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar`, :meth:`wrf.cape_3d` - + """ - + if isinstance(ter_follow, bool): ter_follow = 1 if ter_follow else 0 - + i3dflag = 0 - cape_cin = _cape(pres_hpa, tkel, qv, height, terrain, psfc_hpa, + cape_cin = _cape(pres_hpa, tkel, qv, height, terrain, psfc_hpa, missing, i3dflag, ter_follow) - + left_dims = cape_cin.shape[1:-3] right_dims = cape_cin.shape[-2:] - + resdim = (4,) + left_dims + right_dims - + # Make a new output array for the result result = np.zeros(resdim, cape_cin.dtype) - - # Cape 2D output is not flipped in the vertical, so index from the + + # Cape 2D output is not flipped in the vertical, so index from the # end - result[0,...,:,:] = cape_cin[0,...,-1,:,:] - result[1,...,:,:] = cape_cin[1,...,-1,:,:] - result[2,...,:,:] = cape_cin[1,...,-2,:,:] - result[3,...,:,:] = cape_cin[1,...,-3,:,:] - + result[0, ..., :, :] = cape_cin[0, ..., -1, :, :] + result[1, ..., :, :] = cape_cin[1, ..., -1, :, :] + result[2, ..., :, :] = cape_cin[1, ..., -2, :, :] + result[3, ..., :, :] = cape_cin[1, ..., -3, :, :] + return ma.masked_values(result, missing) @set_cape_alg_metadata(is2d=False, copyarg="pres_hpa") -def cape_3d(pres_hpa, tkel, qv, height, terrain, psfc_hpa, ter_follow, +def cape_3d(pres_hpa, tkel, qv, height, terrain, psfc_hpa, ter_follow, missing=default_fill(np.float64), meta=True): """Return the three-dimensional CAPE and CIN. - - This function calculates the maximum convective available potential - energy (CAPE) and maximum convective inhibition (CIN). This - function uses the RIP [Read/Interpolate/plot] code to calculate - potential energy (CAPE) and convective inhibition - (CIN) [J kg-1] for every grid point in the entire 3D domain + + This function calculates the maximum convective available potential + energy (CAPE) and maximum convective inhibition (CIN). This + function uses the RIP [Read/Interpolate/plot] code to calculate + potential energy (CAPE) and convective inhibition + (CIN) [J kg-1] for every grid point in the entire 3D domain (treating each grid point as a parcel). - - The leftmost dimension of the returned array represents two different + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain CAPE [J kg-1] - return_val[1,...] will contain CIN [J kg-1] - - This function also supports computing CAPE along a single vertical + + This function also supports computing CAPE along a single vertical column. In this mode, the *pres_hpa*, *tkel*, *qv* and *height* arguments - must be one-dimensional vertical columns, and the *terrain* and - *psfc_hpa* arguments must be scalar values + must be one-dimensional vertical columns, and the *terrain* and + *psfc_hpa* arguments must be scalar values (:obj:`float`, :class:`numpy.float32` or :class:`numpy.float64`). - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - pres_hpa (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full - pressure (perturbation + base state pressure) in [hPa] with at - least three dimensions when operating on a grid of values. The - rightmost dimensions can be top_bottom x south_north x west_east - or bottom_top x south_north x west_east. - When operating on only a single column of values, the vertical - column can be bottom_top or top_bottom. In this case, *terrain* + + Args: + + pres_hpa (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full + pressure (perturbation + base state pressure) in [hPa] with at + least three dimensions when operating on a grid of values. The + rightmost dimensions can be top_bottom x south_north x west_east + or bottom_top x south_north x west_east. + When operating on only a single column of values, the vertical + column can be bottom_top or top_bottom. In this case, *terrain* and *psfc_hpa* must be scalars. - + Note: - + The units for *pres_hpa* are [hPa]. - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - + tkel (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Temperature in [K] with same dimensionality as *pres_hpa*. - - qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor + + qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor mixing ratio in [kg/kg] with the same dimensionality as *pres_hpa*. - - height (:class:`xarray.DataArray` or :class:`numpy.ndarray`): - Geopotential height in [m] with the same dimensionality as + + height (:class:`xarray.DataArray` or :class:`numpy.ndarray`): + Geopotential height in [m] with the same dimensionality as *pres_hpa*. - + terrain (:class:`xarray.DataArray`, :class:`numpy.ndarray`, \ - or a scalar): Terrain height in [m]. When operating on a grid of - values, this argument is at least a two-dimensional array - with the same dimensionality as *pres_hpa*, excluding the vertical - (bottom_top/top_bottom) dimension. When operating on a single - vertical column, this argument must be a scalar (:obj:`float`, + or a scalar): Terrain height in [m]. When operating on a grid of + values, this argument is at least a two-dimensional array + with the same dimensionality as *pres_hpa*, excluding the vertical + (bottom_top/top_bottom) dimension. When operating on a single + vertical column, this argument must be a scalar (:obj:`float`, :class:`numpy.float32`, or :class:`numpy.float64`). - + psfc_hpa (:class:`xarray.DataArray`, :class:`numpy.ndarray`, \ - or a scalar): Surface pressure in [hPa]. When operating on a - grid of values, this argument is at least a two-dimensional array - with the same dimensionality as *pres_hpa*, excluding the vertical - (bottom_top/top_bottom) dimension. When operating on a single - vertical column, this argument must be a scalar (:obj:`float`, + or a scalar): Surface pressure in [hPa]. When operating on a + grid of values, this argument is at least a two-dimensional array + with the same dimensionality as *pres_hpa*, excluding the vertical + (bottom_top/top_bottom) dimension. When operating on a single + vertical column, this argument must be a scalar (:obj:`float`, :class:`numpy.float32`, or :class:`numpy.float64`). - + Note: - + The units for *psfc_hpa* are [hPa]. - - ter_follow (:obj:`bool`): A boolean that should be set to True if the - data uses terrain following coordinates (WRF data). Set to + + ter_follow (:obj:`bool`): A boolean that should be set to True if the + data uses terrain following coordinates (WRF data). Set to False for pressure level data. - - missing (:obj:`float`, optional): The fill value to use for the + + missing (:obj:`float`, optional): The fill value to use for the output. Default is :data:`wrf.default_fill(numpy.float64)`. - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - CAPE and CIN as an array whose - leftmost dimension is 2 (0=CAPE, 1=CIN). If xarray is - enabled and the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + CAPE and CIN as an array whose + leftmost dimension is 2 (0=CAPE, 1=CIN). If xarray is + enabled and the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar`, :meth:`wrf.cape_2d` - + """ - + if isinstance(ter_follow, bool): ter_follow = 1 if ter_follow else 0 - + i3dflag = 1 - cape_cin = _cape(pres_hpa, tkel, qv, height, terrain, psfc_hpa, + cape_cin = _cape(pres_hpa, tkel, qv, height, terrain, psfc_hpa, missing, i3dflag, ter_follow) - + return ma.masked_values(cape_cin, missing) @@ -1003,296 +1004,295 @@ def cape_3d(pres_hpa, tkel, qv, height, terrain, psfc_hpa, ter_follow, def cloudfrac(vert, relh, vert_inc_w_height, low_thresh, mid_thresh, high_thresh, missing=default_fill(np.float64), meta=True): """Return the cloud fraction. - - The leftmost dimension of the returned array represents three different + + The leftmost dimension of the returned array represents three different quantities: - + - return_val[0,...] will contain LOW level cloud fraction - return_val[1,...] will contain MID level cloud fraction - return_val[2,...] will contain HIGH level cloud fraction - - The *low_thresh*, *mid_thresh*, and *high_threshold* paramters specify the + + The *low_thresh*, *mid_thresh*, and *high_threshold* paramters specify the low, mid, and high cloud levels in the same units as *vert*. - - In mountainous regions, there is a possibility - that the lowest WRF level will be higher than the low_cloud or mid_cloud - threshold. When this happens, a fill value will be used in the output at + + In mountainous regions, there is a possibility + that the lowest WRF level will be higher than the low_cloud or mid_cloud + threshold. When this happens, a fill value will be used in the output at that location. - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - vert (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The - vertical coordinate variable (usually pressure or height) with the + + Args: + + vert (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The + vertical coordinate variable (usually pressure or height) with the rightmost dimensions as bottom_top x south_north x west_east - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - - relh (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Relative + + relh (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Relative humidity with the same dimensionality as *vert* - - vert_inc_w_height (:obj:`int`): Set to 1 if the vertical coordinate - values increase with height (height values). Set to 0 if the + + vert_inc_w_height (:obj:`int`): Set to 1 if the vertical coordinate + values increase with height (height values). Set to 0 if the vertical coordinate values decrease with height (pressure values). - - low_thresh (:obj:`float`): The bottom vertical threshold for what is + + low_thresh (:obj:`float`): The bottom vertical threshold for what is considered a low cloud. - - mid_thresh (:obj:`float`): The bottom vertical threshold for what is + + mid_thresh (:obj:`float`): The bottom vertical threshold for what is considered a mid level cloud. - - high_thresh (:obj:`float`): The bottom vertical threshold for what is + + high_thresh (:obj:`float`): The bottom vertical threshold for what is considered a high cloud. - - missing (:obj:`float:`, optional): The fill value to use for areas - where the surface is higher than the cloud threshold level - (e.g. mountains). Default is + + missing (:obj:`float:`, optional): The fill value to use for areas + where the surface is higher than the cloud threshold level + (e.g. mountains). Default is :data:`wrf.default_fill(numpy.float64)`. - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - cloud fraction array whose leftmost dimension is 3 (LOW=0, MID=1, - HIGH=2). If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + cloud fraction array whose leftmost dimension is 3 (LOW=0, MID=1, + HIGH=2). If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar`, :meth:`wrf.rh` - + """ - cfrac = _cloudfrac(vert, relh, vert_inc_w_height, low_thresh, mid_thresh, - high_thresh, missing) - + cfrac = _cloudfrac(vert, relh, vert_inc_w_height, low_thresh, mid_thresh, + high_thresh, missing) + return ma.masked_values(cfrac, missing) -@set_alg_metadata(2, "pres_hpa", refvarndims=3, +@set_alg_metadata(2, "pres_hpa", refvarndims=3, description="cloud top temperature") @convert_units("temp", "c") -def ctt(pres_hpa, tkel, qv, qcld, height, terrain, qice=None, - fill_nocloud=False, missing=default_fill(np.float64), +def ctt(pres_hpa, tkel, qv, qcld, height, terrain, qice=None, + fill_nocloud=False, missing=default_fill(np.float64), opt_thresh=1.0, meta=True, units="degC"): """Return the cloud top temperature. - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - pres_hpa (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full - pressure (perturbation + base state pressure) in [hPa], with the + + Args: + + pres_hpa (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full + pressure (perturbation + base state pressure) in [hPa], with the rightmost dimensions as bottom_top x south_north x west_east - + Note: - + The units for *psfc_hpa* are [hPa]. - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - + tkel (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Temperature in [K] with same dimensionality as *pres_hpa*. - - qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor + + qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor mixing ratio in [kg/kg] with the same dimensionality as *pres_hpa*. - - qcld (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Cloud water - vapor mixing ratio in [kg/kg] with the same dimensionality as + + qcld (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Cloud water + vapor mixing ratio in [kg/kg] with the same dimensionality as *pres_hpa*. - - height (:class:`xarray.DataArray` or :class:`numpy.ndarray`): - Geopotential height in [m] with the same dimensionality as + + height (:class:`xarray.DataArray` or :class:`numpy.ndarray`): + Geopotential height in [m] with the same dimensionality as *pres_hpa*. - - terrain (:class:`xarray.DataArray` or :class:`numpy.ndarray`): - Terrain height in [m]. This is at least a two-dimensional array - with the same dimensionality as *pres_hpa*, excluding the vertical + + terrain (:class:`xarray.DataArray` or :class:`numpy.ndarray`): + Terrain height in [m]. This is at least a two-dimensional array + with the same dimensionality as *pres_hpa*, excluding the vertical (bottom_top/top_bottom) dimension. - - qice (:class:`xarray.DataArray` or :class:`numpy.ndarray`, optional): - Ice mixing ratio in [kg/kg] with the same dimensionality as + + qice (:class:`xarray.DataArray` or :class:`numpy.ndarray`, optional): + Ice mixing ratio in [kg/kg] with the same dimensionality as *pres_hpa*. - - fill_nocloud (:obj:`bool`, optional): Set to True to use fill values in - regions where clouds are not detected (optical depth less than 1). - Otherwise, the output will contain the surface temperature for + + fill_nocloud (:obj:`bool`, optional): Set to True to use fill values in + regions where clouds are not detected (optical depth less than 1). + Otherwise, the output will contain the surface temperature for areas without clouds. Default is False. - - missing (:obj:`float`, optional): The fill value to use for areas - where no clouds are detected. Only used if *fill_nocloud* is - True. Default is - :data:`wrf.default_fill(numpy.float64)`. - - opt_thresh (:obj:`float`, optional): The amount of optical - depth (integrated from top down) required to trigger a cloud top - temperature calculation. The cloud top temperature is calculated at - the vertical level where this threshold is met. Vertical columns - with less than this threshold will be treated as cloud free areas. - In general, the larger the value is for this - threshold, the lower the altitude will be for the cloud top - temperature calculation, and therefore higher cloud top - temperature values. Default is 1.0, which should be sufficient for + + missing (:obj:`float`, optional): The fill value to use for areas + where no clouds are detected. Only used if *fill_nocloud* is + True. Default is + :data:`wrf.default_fill(numpy.float64)`. + + opt_thresh (:obj:`float`, optional): The amount of optical + depth (integrated from top down) required to trigger a cloud top + temperature calculation. The cloud top temperature is calculated at + the vertical level where this threshold is met. Vertical columns + with less than this threshold will be treated as cloud free areas. + In general, the larger the value is for this + threshold, the lower the altitude will be for the cloud top + temperature calculation, and therefore higher cloud top + temperature values. Default is 1.0, which should be sufficient for most users. - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'ctt'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'ctt'. Default is 'degC'. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - cloud top temperature. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + cloud top temperature. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar`, :meth:`wrf.cloudfrac` - + """ - + # Qice and QCLD need to be in g/kg if qice is None: qice = np.zeros(qv.shape, qv.dtype) haveqci = 0 else: haveqci = 1 if qice.any() else 0 - + _fill_nocloud = 1 if fill_nocloud else 0 - + ctt = _ctt(pres_hpa, tkel, qice, qcld, qv, height, terrain, haveqci, - _fill_nocloud, missing, opt_thresh) - + _fill_nocloud, missing, opt_thresh) + return ma.masked_values(ctt, missing) - @set_alg_metadata(3, "pres", units="dBZ", description="radar reflectivity") -def dbz(pres, tkel, qv, qr, qs=None, qg=None, use_varint=False, +def dbz(pres, tkel, qv, qr, qs=None, qg=None, use_varint=False, use_liqskin=False, meta=True): """Return the simulated radar reflectivity. - - This function computes equivalent reflectivity factor [dBZ] at each - model grid point assuming spherical particles of constant density, - with exponential size distributions. This function is based on - "dbzcalc.f" in RIP. - - This is the raw computational algorithm and does not extract any variables + + This function computes equivalent reflectivity factor [dBZ] at each + model grid point assuming spherical particles of constant density, + with exponential size distributions. This function is based on + "dbzcalc.f" in RIP. + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full - pressure (perturbation + base state pressure) in [Pa], with the + + Args: + + pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full + pressure (perturbation + base state pressure) in [Pa], with the rightmost dimensions as bottom_top x south_north x west_east - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - + tkel (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Temperature in [K] with same dimensionality as *pres*. - - qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor + + qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor mixing ratio in [kg/kg] with the same dimensionality as *pres*. - - qr (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Rain water - vapor mixing ratio in [kg/kg] with the same dimensionality as + + qr (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Rain water + vapor mixing ratio in [kg/kg] with the same dimensionality as *pres*. - - qs (:class:`xarray.DataArray` or :class:`numpy.ndarray`, optional): - Snow mixing ratio in [kg/kg] with the same dimensionality as + + qs (:class:`xarray.DataArray` or :class:`numpy.ndarray`, optional): + Snow mixing ratio in [kg/kg] with the same dimensionality as *pres*. - - qg (:class:`xarray.DataArray` or :class:`numpy.ndarray`, optional): - Graupel mixing ratio in [kg/kg] with the same dimensionality as + + qg (:class:`xarray.DataArray` or :class:`numpy.ndarray`, optional): + Graupel mixing ratio in [kg/kg] with the same dimensionality as *pres*. - - use_varint (:obj:`bool`, optional): When set to False, - the intercept parameters are assumed constant - (as in MM5's Reisner-2 bulk microphysical scheme). - When set to True, the variable intercept - parameters are used as in the more recent version of Reisner-2 - (based on Thompson, Rasmussen, and Manning, 2004, Monthly weather - Review, Vol. 132, No. 2, pp. 519-542.). - - use_liqskin (:obj:`bool`, optional): When set to True, frozen particles - that are at a temperature above freezing are assumed to scatter + + use_varint (:obj:`bool`, optional): When set to False, + the intercept parameters are assumed constant + (as in MM5's Reisner-2 bulk microphysical scheme). + When set to True, the variable intercept + parameters are used as in the more recent version of Reisner-2 + (based on Thompson, Rasmussen, and Manning, 2004, Monthly weather + Review, Vol. 132, No. 2, pp. 519-542.). + + use_liqskin (:obj:`bool`, optional): When set to True, frozen particles + that are at a temperature above freezing are assumed to scatter as a liquid particle. Set to False to disable. - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - simulated radar reflectivity. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + simulated radar reflectivity. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar` - + """ - + if qs is None: qs = np.zeros(qv.shape, qv.dtype) - + if qg is None: qg = np.zeros(qv.shape, qv.dtype) - + sn0 = 1 if qs.any() else 0 ivarint = 1 if use_varint else 0 iliqskin = 1 if use_liqskin else 0 - + return _dbz(pres, tkel, qv, qr, qs, qg, sn0, ivarint, iliqskin) @@ -1300,174 +1300,174 @@ def dbz(pres, tkel, qv, qr, qs=None, qg=None, use_varint=False, description="storm relative helicity") def srhel(u, v, height, terrain, top=3000.0, lats=None, meta=True): """Return the storm relative helicity. - - This function calculates storm relative helicity from WRF ARW output. - SRH (Storm Relative Helicity) is a measure of the potential for cyclonic - updraft rotation in right-moving supercells, and is calculated for the - lowest 1-km and 3-km layers above ground level. There is no clear threshold - value for SRH when forecasting supercells, since the formation of - supercells appears to be related more strongly to the deeper layer - vertical shear. Larger values of 0-3 km SRH (greater than 250 m2 s-2) - and 0-1 km SRH (greater than 100 m2 s-2), however, do suggest an - increased threat of tornadoes with supercells. For SRH, larger values are - generally better, but there are no clear "boundaries" between non-tornadic + + This function calculates storm relative helicity from WRF ARW output. + SRH (Storm Relative Helicity) is a measure of the potential for cyclonic + updraft rotation in right-moving supercells, and is calculated for the + lowest 1-km and 3-km layers above ground level. There is no clear threshold + value for SRH when forecasting supercells, since the formation of + supercells appears to be related more strongly to the deeper layer + vertical shear. Larger values of 0-3 km SRH (greater than 250 m2 s-2) + and 0-1 km SRH (greater than 100 m2 s-2), however, do suggest an + increased threat of tornadoes with supercells. For SRH, larger values are + generally better, but there are no clear "boundaries" between non-tornadic and significant tornadic supercells. - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - u (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The u - component of the wind that must have at least three dimensions. + + Args: + + u (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The u + component of the wind that must have at least three dimensions. The rightmost dimensions are bottom_top x south_north x west_east. - - v (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The v - component of the wind with the same dimensionality as *u*. - - height (:class:`xarray.DataArray` or :class:`numpy.ndarray`): - Geopotential height in [m] with the same dimensionality as + + v (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The v + component of the wind with the same dimensionality as *u*. + + height (:class:`xarray.DataArray` or :class:`numpy.ndarray`): + Geopotential height in [m] with the same dimensionality as *u*. - - terrain (:class:`xarray.DataArray` or :class:`numpy.ndarray`): - Terrain height in [m]. This is at least a two-dimensional array - with the same dimensionality as *u*, excluding the bottom_top + + terrain (:class:`xarray.DataArray` or :class:`numpy.ndarray`): + Terrain height in [m]. This is at least a two-dimensional array + with the same dimensionality as *u*, excluding the bottom_top dimension. - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will - be used. - - top (:obj:`float`): The height of the layer below which helicity is + be used. + + top (:obj:`float`): The height of the layer below which helicity is calculated (meters above ground level). - - lats (:class:`xarray.DataArray` or :class:`numpy.ndarray`, optional): - Array of latitudes. This is required if any (or all) of your - domain is in the southern hemisphere. If not provided, the + + lats (:class:`xarray.DataArray` or :class:`numpy.ndarray`, optional): + Array of latitudes. This is required if any (or all) of your + domain is in the southern hemisphere. If not provided, the northern hemisphere is assumed. Default is None. - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - storm relative helicity. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + storm relative helicity. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar`, :meth:`wrf.udhel` - + """ - + # u, v get swapped in vertical - _u = np.ascontiguousarray(u[...,::-1,:,:]) - _v = np.ascontiguousarray(v[...,::-1,:,:]) - _height = np.ascontiguousarray(height[...,::-1,:,:]) - + _u = np.ascontiguousarray(u[..., ::-1, :, :]) + _v = np.ascontiguousarray(v[..., ::-1, :, :]) + _height = np.ascontiguousarray(height[..., ::-1, :, :]) + if lats is None: _lats = np.ones_like(terrain) else: _lats = lats - + return _srhel(_u, _v, _height, terrain, _lats, top) @set_alg_metadata(2, "u", refvarndims=3, units="m2 s-2", description="updraft helicity") -def udhel(zstag, mapfct, u, v, wstag, dx, dy, bottom=2000.0, top=5000.0, +def udhel(zstag, mapfct, u, v, wstag, dx, dy, bottom=2000.0, top=5000.0, meta=True): """Return the updraft helicity. - - This function calculates updraft helicity to detect - rotating updrafts. The formula follows Kain et al., 2008, Wea. and - Forecasting, 931-952, but this version has controls for the limits of - integration, *bottom* to *top*, in m AGL. Kain et al used 2000 to 5000 m. - The expected range is 25 to 250 m-2/s-2. Keith Brewster, CAPS/Univ. of + + This function calculates updraft helicity to detect + rotating updrafts. The formula follows Kain et al., 2008, Wea. and + Forecasting, 931-952, but this version has controls for the limits of + integration, *bottom* to *top*, in m AGL. Kain et al used 2000 to 5000 m. + The expected range is 25 to 250 m-2/s-2. Keith Brewster, CAPS/Univ. of Oklahoma ; March, 2010 - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - zstag (:class:`xarray.DataArray` or :class:`numpy.ndarray`): + + Args: + + zstag (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Geopotential height in [m] that is at least three dimensions with - a staggered vertical dimension. The rightmost dimensions are + a staggered vertical dimension. The rightmost dimensions are bottom_top_stag x south_north x west_east. - - mapfct (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The map - scale factor on the mass grid. An array of at least - two dimensions, whose rightmost two dimensions must be - south_north x west_east. If this array is more than two dimensions, + + mapfct (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The map + scale factor on the mass grid. An array of at least + two dimensions, whose rightmost two dimensions must be + south_north x west_east. If this array is more than two dimensions, they must be the same as *zstag*'s leftmost dimensions. - - u (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The u - component of the wind [m s-1] whose rightmost three dimensions - must be bottom_top x south_north x west_east. The leftmost + + u (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The u + component of the wind [m s-1] whose rightmost three dimensions + must be bottom_top x south_north x west_east. The leftmost dimensions must be the same as zp's leftmost dimensions. - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will - be used. - - v (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The v - component of the wind [m s-1] whose rightmost three dimensions - must be bottom_top x south_north x west_east. The leftmost - dimensions must be the same as *zstag*'s leftmost dimensions. - + be used. + + v (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The v + component of the wind [m s-1] whose rightmost three dimensions + must be bottom_top x south_north x west_east. The leftmost + dimensions must be the same as *zstag*'s leftmost dimensions. + wstag (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The z - component of the wind [m s-1] with the same dimensionality as + component of the wind [m s-1] with the same dimensionality as *zstag*. - + dx (:obj:`float`): The distance between x grid points. - + dy (:obj:`float`): The distance between y grid points. - - bottom (:obj:`float`, optional): The bottom limit of integration. + + bottom (:obj:`float`, optional): The bottom limit of integration. Default is 2000.0. - - top (:obj:`float`, optional): The upper limit of integration. + + top (:obj:`float`, optional): The upper limit of integration. Default is 5000.0. - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - updraft helicity. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + updraft helicity. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar`, :meth:`wrf.srhel` - + """ return _udhel(zstag, mapfct, u, v, wstag, dx, dy, bottom, top) @@ -1478,91 +1478,91 @@ def udhel(zstag, mapfct, u, v, wstag, dx, dy, bottom=2000.0, top=5000.0, description="absolute vorticity") def avo(ustag, vstag, msfu, msfv, msfm, cor, dx, dy, meta=True): """Return the absolute vorticity. - - This function returns absolute vorticity [10-5 s-1], which is the sum of - the relative vorticity at each grid point and the Coriolis parameter + + This function returns absolute vorticity [10-5 s-1], which is the sum of + the relative vorticity at each grid point and the Coriolis parameter at the latitude. - This is the raw computational algorithm and does not extract any variables + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - ustag (:class:`xarray.DataArray` or :class:`numpy.ndarray`): - The u component of the wind in [m s-1] that is at least three - dimensions with a staggered west_east dimension. The rightmost + + Args: + + ustag (:class:`xarray.DataArray` or :class:`numpy.ndarray`): + The u component of the wind in [m s-1] that is at least three + dimensions with a staggered west_east dimension. The rightmost dimensions are bottom_top x south_north x west_east_stag. - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will - be used. - - vstag (:class:`xarray.DataArray` or :class:`numpy.ndarray`): - The v component of the wind in [m s-1] that is at least three - dimensions with a staggered south_north dimension. The rightmost + be used. + + vstag (:class:`xarray.DataArray` or :class:`numpy.ndarray`): + The v component of the wind in [m s-1] that is at least three + dimensions with a staggered south_north dimension. The rightmost dimensions are bottom_top x south_north_stag x west_east. - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will - be used. - - msfu (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The map - scale factor on the u-grid that is at least - two dimensions, whose rightmost two dimensions must be - the same as *ustag*. If this array contains more than two - dimensions, they must be the same as *ustag* and *vstag*'s leftmost + be used. + + msfu (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The map + scale factor on the u-grid that is at least + two dimensions, whose rightmost two dimensions must be + the same as *ustag*. If this array contains more than two + dimensions, they must be the same as *ustag* and *vstag*'s leftmost dimensions. - - msfv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The map - scale factor on the v-grid that is at least - two dimensions, whose rightmost two dimensions must be - the same as *vstag*. If this array contains more than two - dimensions, they must be the same as *ustag* and *vstag*'s leftmost + + msfv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The map + scale factor on the v-grid that is at least + two dimensions, whose rightmost two dimensions must be + the same as *vstag*. If this array contains more than two + dimensions, they must be the same as *ustag* and *vstag*'s leftmost dimensions. - - msfm (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The map - scale factor on the mass grid that is at least - two dimensions, whose rightmost two dimensions must be - south_north x west_east. If this array contains more than two - dimensions, they must be the same as *ustag* and *vstag*'s leftmost + + msfm (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The map + scale factor on the mass grid that is at least + two dimensions, whose rightmost two dimensions must be + south_north x west_east. If this array contains more than two + dimensions, they must be the same as *ustag* and *vstag*'s leftmost dimensions. - - cor (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The Coriolis - sine latitude array that is at least + + cor (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The Coriolis + sine latitude array that is at least two dimensions, whose dimensions must be the same as *msfm*. - + dx (:obj:`float`): The distance between x grid points. - + dy (:obj:`float`): The distance between y grid points. - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - absolute vorticity. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + absolute vorticity. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar`, :meth:`wrf.pvo` - + """ return _avo(ustag, vstag, msfu, msfv, msfm, cor, dx, dy) @@ -1571,92 +1571,92 @@ def avo(ustag, vstag, msfu, msfv, msfm, cor, dx, dy, meta=True): description="potential vorticity") def pvo(ustag, vstag, theta, pres, msfu, msfv, msfm, cor, dx, dy, meta=True): """Return the potential vorticity. - + This function calculates the potential vorticity [PVU] at each grid point. - This is the raw computational algorithm and does not extract any variables + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - ustag (:class:`xarray.DataArray` or :class:`numpy.ndarray`): - The u component of the wind in [m s-1] that is at least three - dimensions with a staggered west_east dimension. The rightmost + + Args: + + ustag (:class:`xarray.DataArray` or :class:`numpy.ndarray`): + The u component of the wind in [m s-1] that is at least three + dimensions with a staggered west_east dimension. The rightmost dimensions are bottom_top x south_north x west_east_stag. - - - vstag (:class:`xarray.DataArray` or :class:`numpy.ndarray`): - The v component of the wind in [m s-1] that is at least three - dimensions with a staggered south_north dimension. The rightmost + + + vstag (:class:`xarray.DataArray` or :class:`numpy.ndarray`): + The v component of the wind in [m s-1] that is at least three + dimensions with a staggered south_north dimension. The rightmost dimensions are bottom_top x south_north_stag x west_east. - - theta (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The - potential temperature field [K] whose rightmost dimensions are + + theta (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The + potential temperature field [K] whose rightmost dimensions are bottom_top x south_north x west_east and whose leftmost dimensions are the same as *ustag*. - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - - pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full - pressure (perturbation + base state pressure) in [Pa], with the + + pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full + pressure (perturbation + base state pressure) in [Pa], with the same dimensions as *theta*. - - msfu (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The map - scale factor on the u-grid that is at least - two dimensions, whose rightmost two dimensions must be - the same as *ustag*. If this array contains more than two - dimensions, they must be the same as *ustag* and *vstag*'s leftmost + + msfu (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The map + scale factor on the u-grid that is at least + two dimensions, whose rightmost two dimensions must be + the same as *ustag*. If this array contains more than two + dimensions, they must be the same as *ustag* and *vstag*'s leftmost dimensions. - - msfv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The map - scale factor on the v-grid that is at least - two dimensions, whose rightmost two dimensions must be - the same as *vstag*. If this array contains more than two - dimensions, they must be the same as *ustag* and *vstag*'s leftmost + + msfv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The map + scale factor on the v-grid that is at least + two dimensions, whose rightmost two dimensions must be + the same as *vstag*. If this array contains more than two + dimensions, they must be the same as *ustag* and *vstag*'s leftmost dimensions. - - msfm (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The map - scale factor on the mass grid that is at least - two dimensions, whose rightmost two dimensions must be - south_north x west_east. If this array contains more than two - dimensions, they must be the same as *ustag* and *vstag*'s leftmost + + msfm (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The map + scale factor on the mass grid that is at least + two dimensions, whose rightmost two dimensions must be + south_north x west_east. If this array contains more than two + dimensions, they must be the same as *ustag* and *vstag*'s leftmost dimensions. - - cor (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The Coriolis - sine latitude array that is at least + + cor (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The Coriolis + sine latitude array that is at least two dimensions, whose dimensions must be the same as *msfm*. - + dx (:obj:`float`): The distance between x grid points. - + dy (:obj:`float`): The distance between y grid points. - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - potential vorticity. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + potential vorticity. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar`, :meth:`wrf.avo` - + """ return _pvo(ustag, vstag, theta, pres, msfu, msfv, msfm, cor, dx, dy) @@ -1666,59 +1666,59 @@ def pvo(ustag, vstag, theta, pres, msfu, msfv, msfm, cor, dx, dy, meta=True): @convert_units("temp", "k") def eth(qv, tkel, pres, meta=True, units="K"): """Return the equivalent potential temperature. - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor - mixing ratio in [kg/kg] that is at least three dimensions, with + + Args: + + qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor + mixing ratio in [kg/kg] that is at least three dimensions, with the rightmost dimensions of bottom_top x south_north x west_east. - + tkel (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Temperature in [K] with same dimensionality as *qv*. - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - - pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full - pressure (perturbation + base state pressure) in [Pa] with the - same dimensionality as *qv*. - - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + + pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full + pressure (perturbation + base state pressure) in [Pa] with the + same dimensionality as *qv*. + + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'eth'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'eth'. Default is 'K'. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - equivalent potential temperature. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + equivalent potential temperature. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - - :meth:`wrf.getvar`, :meth:`wrf.temp`, :meth:`wrf.wetbulb`, + + :meth:`wrf.getvar`, :meth:`wrf.temp`, :meth:`wrf.wetbulb`, :meth:`tvirtual` - + """ - + return _eth(qv, tkel, pres) @@ -1727,57 +1727,57 @@ def eth(qv, tkel, pres, meta=True, units="K"): @convert_units("temp", "k") def wetbulb(pres, tkel, qv, meta=True, units="K"): """Return the wetbulb temperature. - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full - pressure (perturbation + base state pressure) in [Pa], with the + + Args: + + pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full + pressure (perturbation + base state pressure) in [Pa], with the rightmost dimensions as bottom_top x south_north x west_east - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - + tkel (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Temperature in [K] with same dimensionality as *pres*. - - qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor - mixing ratio in [kg/kg] with the same dimensionality as + + qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor + mixing ratio in [kg/kg] with the same dimensionality as *pres* - - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'twb'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'twb'. Default is 'K'. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - wetbulb temperature. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + wetbulb temperature. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - - :meth:`wrf.getvar`, :meth:`wrf.temp`, :meth:`wrf.eth`, + + :meth:`wrf.getvar`, :meth:`wrf.temp`, :meth:`wrf.eth`, :meth:`tvirtual` - + """ return _wetbulb(pres, tkel, qv) @@ -1787,54 +1787,54 @@ def wetbulb(pres, tkel, qv, meta=True, units="K"): @convert_units("temp", "k") def tvirtual(tkel, qv, meta=True, units="K"): """Return the virtual temperature. - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - + + Args: + tkel (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Temperature - in [K] with the rightmost dimensions as bottom_top x south_north + in [K] with the rightmost dimensions as bottom_top x south_north x west_east. - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - - qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor - mixing ratio in [kg/kg] with the same dimensionality as + + qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor + mixing ratio in [kg/kg] with the same dimensionality as *tkel* - - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'tv'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'tv'. Default is 'K'. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - virtual temperature. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + virtual temperature. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - - :meth:`wrf.getvar`, :meth:`wrf.temp`, :meth:`wrf.eth`, + + :meth:`wrf.getvar`, :meth:`wrf.temp`, :meth:`wrf.eth`, :meth:`wetbulb` - + """ return _tv(tkel, qv) @@ -1843,57 +1843,57 @@ def tvirtual(tkel, qv, meta=True, units="K"): description="omega") def omega(qv, tkel, w, pres, meta=True): """Return omega. - + This function calculates omega (dp/dt) [Pa s-1]. - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor - mixing ratio in [kg/kg] with the rightmost dimensions as + + Args: + + qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor + mixing ratio in [kg/kg] with the rightmost dimensions as bottom_top x south_north x west_east. - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - + tkel (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Temperature in [K] with the same dimensionality as *qv*. - - w (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The vertical + + w (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The vertical velocity [m s-1] with the same dimensionality as *qv*. - - pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full - pressure (perturbation + base state pressure) in [Pa] with the - same dimensionality as *qv*. - - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + + pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full + pressure (perturbation + base state pressure) in [Pa] with the + same dimensionality as *qv*. + + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: Omega. - If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: Omega. + If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar`, :meth:`uvmet` - + """ return _omega(qv, tkel, w, pres) @@ -1902,59 +1902,56 @@ def omega(qv, tkel, w, pres, meta=True): description="precipitable water") def pw(pres, tkel, qv, height, meta=True): """Return the precipitable water. - - This is the raw computational algorithm and does not extract any variables + + This is the raw computational algorithm and does not extract any variables from WRF output files. Use :meth:`wrf.getvar` to both extract and compute diagnostic variables. - - Args: - - pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full - pressure (perturbation + base state pressure) in [Pa], with the + + Args: + + pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full + pressure (perturbation + base state pressure) in [Pa], with the rightmost dimensions as bottom_top x south_north x west_east - + Note: - - This variable must be - supplied as a :class:`xarray.DataArray` in order to copy the + + This variable must be + supplied as a :class:`xarray.DataArray` in order to copy the dimension names to the output. Otherwise, default names will be used. - + tkel (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Temperature in [K] with the same dimensionality as *pres*. - - qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor + + qv (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Water vapor mixing ratio in [kg/kg] with the same dimensionality as *pres* - - height (:class:`xarray.DataArray` or :class:`numpy.ndarray`): - Geopotential height in [m] with the same dimensionality as + + height (:class:`xarray.DataArray` or :class:`numpy.ndarray`): + Geopotential height in [m] with the same dimensionality as *pres*. - - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Warning: - - The input arrays must not contain any missing/fill values or + + The input arrays must not contain any missing/fill values or :data:`numpy.nan` values. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The precipitable - water [kg m-2]. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The precipitable + water [kg m-2]. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :meth:`wrf.getvar` - + """ tv = _tv(tkel, qv) - - return _pw(pres, tv, qv, height) - - + return _pw(pres, tv, qv, height) diff --git a/src/wrf/config.py b/src/wrf/config.py index 513cf1f..fa20201 100644 --- a/src/wrf/config.py +++ b/src/wrf/config.py @@ -3,42 +3,43 @@ from __future__ import (absolute_import, division, print_function) from threading import local import wrapt -from ._wrffortran import (fomp_enabled, fomp_set_num_threads, +from ._wrffortran import (fomp_enabled, fomp_set_num_threads, fomp_set_schedule, fomp_set_dynamic, omp_constants) _local_config = local() + def _init_local(): global _local_config - + _local_config.xarray_enabled = True _local_config.cartopy_enabled = True _local_config.basemap_enabled = True _local_config.pyngl_enabled = True _local_config.cache_size = 20 _local_config.initialized = True - + try: from xarray import DataArray except ImportError: _local_config.xarray_enabled = False - + try: from cartopy import crs except ImportError: _local_config.cartopy_enabled = False - + try: from mpl_toolkits.basemap import Basemap except ImportError: _local_config.basemap_enabled = False - + try: from Ngl import Resources except ImportError: _local_config.pyngl_enabled = False - + # Initialize the main thread's configuration _init_local() @@ -55,21 +56,21 @@ def init_local(): _init_local() else: if not init: - _init_local() - + _init_local() + return wrapped(*args, **kwargs) - + return func_wrapper @init_local() def xarray_enabled(): """Return True if xarray is installed and enabled. - + Returns: - + :obj:`bool`: True if xarray is installed and enabled. - + """ global _local_config return _local_config.xarray_enabled @@ -80,23 +81,23 @@ def disable_xarray(): """Disable xarray.""" global _local_config _local_config.xarray_enabled = False - + @init_local() def enable_xarray(): """Enable xarray.""" global _local_config _local_config.xarray_enabled = True - + @init_local() def cartopy_enabled(): """Return True if cartopy is installed and enabled. - + Returns: - + :obj:`bool`: True if cartopy is installed and enabled. - + """ global _local_config return _local_config.cartopy_enabled @@ -107,23 +108,23 @@ def enable_cartopy(): """Enable cartopy.""" global _local_config _local_config.cartopy_enabled = True - + @init_local() def disable_cartopy(): """Disable cartopy.""" global _local_config _local_config.cartopy_enabled = True - + @init_local() def basemap_enabled(): """Return True if basemap is installed and enabled. - + Returns: - + :obj:`bool`: True if basemap is installed and enabled. - + """ global _local_config return _local_config.basemap_enabled @@ -134,7 +135,7 @@ def enable_basemap(): """Enable basemap.""" global _local_config _local_config.basemap_enabled = True - + @init_local() def disable_basemap(): @@ -146,11 +147,11 @@ def disable_basemap(): @init_local() def pyngl_enabled(): """Return True if pyngl is installed and enabled. - + Returns: - + :obj:`bool`: True if pyngl is installed and enabled. - + """ global _local_config return _local_config.pyngl_enabled @@ -161,63 +162,64 @@ def enable_pyngl(): """Enable pyngl.""" global _local_config _local_config.pyngl_enabled = True - -@init_local() + +@init_local() def disable_pyngl(): """Disable pyngl.""" global _local_config _local_config.pyngl_enabled = True - -@init_local() + +@init_local() def set_cache_size(size): """Set the maximum number of items that the threadlocal cache can retain. - + This cache is primarily used for coordinate variables. - + Args: - + size (:obj:`int`): The number of items to retain in the cache. - + Returns: - + None - + """ global _local_config _local_config.cache_size = size - -@init_local() + +@init_local() def get_cache_size(): - """Return the maximum number of items that the threadlocal cache can retain. - + """Return the maximum number of items that the threadlocal cache can + retain. + Returns: - + :obj:`int`: The maximum number of items the cache can retain. - + """ global _local_config return int(_local_config.cache_size) - - + + def omp_enabled(): """Return True if OpenMP is enabled. - + OpenMP is only enabled if compiled with OpenMP features. - + Returns: - + :obj:`bool`: True if OpenMP is enabled, otherwise False. - + """ - + return True if fomp_enabled() else False # Set OpenMP to use 1 thread, static scheduler, and no dynamic -# Note: Using the raw extension functions here to prevent possible +# Note: Using the raw extension functions here to prevent possible # circular import problems in the future. fomp_set_num_threads(1) fomp_set_schedule(omp_constants.fomp_sched_static, 0) diff --git a/src/wrf/constants.py b/src/wrf/constants.py index 11cdc6c..47821ef 100755 --- a/src/wrf/constants.py +++ b/src/wrf/constants.py @@ -10,10 +10,12 @@ from ._wrffortran import wrf_constants, omp_constants #: Indicates that all times should be used in a diagnostic routine. ALL_TIMES = None + class Constants(object): pass - -for key,val in viewitems(wrf_constants.__dict__): + + +for key, val in viewitems(wrf_constants.__dict__): setattr(Constants, key.upper(), np.asscalar(val)) OMP_SCHED_STATIC = omp_constants.fomp_sched_static @@ -35,7 +37,7 @@ class ConversionFactors(object): M_TO_DM = 1.0/10.0 M_TO_FT = 3.28084 M_TO_MILES = .000621371 - + class ProjectionTypes(object): ZERO = 0 @@ -44,21 +46,22 @@ class ProjectionTypes(object): MERCATOR = 3 LAT_LON = 6 -# Create the default fill mapping based on type. + +# Create the default fill mapping based on type. _DEFAULT_FILL_MAP = {None: Constants.DEFAULT_FILL, - np.dtype(np.bool_) : False, - np.dtype(np.intc) : Constants.DEFAULT_FILL_INT32, # Usually true - np.dtype(np.int8) : Constants.DEFAULT_FILL_INT8, - np.dtype(np.uint8) : 255, - np.dtype(np.int16) : Constants.DEFAULT_FILL_INT16, - np.dtype(np.uint16) : 65535, - np.dtype(np.int32) : Constants.DEFAULT_FILL_INT32, - np.dtype(np.uint32) : 4294967295, - np.dtype(np.int64) : Constants.DEFAULT_FILL_INT64, - np.dtype(np.uint64) : 18446744073709551614, - np.dtype(np.float_) : Constants.DEFAULT_FILL_DOUBLE, - np.dtype(np.float32) : Constants.DEFAULT_FILL_FLOAT, - np.dtype(np.float64) : Constants.DEFAULT_FILL_DOUBLE + np.dtype(np.bool_): False, + np.dtype(np.intc): Constants.DEFAULT_FILL_INT32, + np.dtype(np.int8): Constants.DEFAULT_FILL_INT8, + np.dtype(np.uint8): 255, + np.dtype(np.int16): Constants.DEFAULT_FILL_INT16, + np.dtype(np.uint16): 65535, + np.dtype(np.int32): Constants.DEFAULT_FILL_INT32, + np.dtype(np.uint32): 4294967295, + np.dtype(np.int64): Constants.DEFAULT_FILL_INT64, + np.dtype(np.uint64): 18446744073709551614, + np.dtype(np.float_): Constants.DEFAULT_FILL_DOUBLE, + np.dtype(np.float32): Constants.DEFAULT_FILL_FLOAT, + np.dtype(np.float64): Constants.DEFAULT_FILL_DOUBLE } if version_info >= (3, ): @@ -76,9 +79,3 @@ else: def default_fill(dtype=None): dt = np.dtype(dtype) if dtype is not None else None return _DEFAULT_FILL_MAP.get(dt, Constants.DEFAULT_FILL) - - - - - - \ No newline at end of file diff --git a/src/wrf/coordpair.py b/src/wrf/coordpair.py index 62000cc..3aed083 100644 --- a/src/wrf/coordpair.py +++ b/src/wrf/coordpair.py @@ -1,265 +1,254 @@ from __future__ import (absolute_import, division, print_function) from .py3compat import py2round - - + + def _binary_operator(operator): """Function wrapper for binary operators. - + Args: - + operator (method): The operator to wrap. - + Returns: - + method: An implementation for the *operator* type. - + """ def func(self, other): """Operator implementation. - - Operator action is performed across the same class attributes when + + Operator action is performed across the same class attributes when the *other* object is a :class:`CoordPair`. If the *other* object is - a scalar value, the operator action is performed across all + a scalar value, the operator action is performed across all attributes with the scalar value. - + Args: - - other (:class:`CoordPair` or scalar): A separate :class:`CoordPair` + + other (:class:`CoordPair` or scalar): A separate :class:`CoordPair` object or scalar value. - + Returns: - - :class:`CoordPair`: A new :class:`CoordPair` object that is the + + :class:`CoordPair`: A new :class:`CoordPair` object that is the result of the operator action. - + """ 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")] + 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")] - + 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): """Function wrapper for unary operators. - + Args: - + operator (method): The operator to wrap. - + Returns: - + method: An implementation for the *operator* type. - + """ def func(self): """Operator implementation. - + Operator action is performed across all class attributes. - + Returns: - - :class:`CoordPair`: A new :class:`CoordPair` object that is the + + :class:`CoordPair`: A new :class:`CoordPair` object that is the result of the operator action. - + """ args = [None if getattr(self, attr) is None - else getattr(getattr(self, attr), operator)() + else getattr(getattr(self, attr), operator)() for attr in ("x", "y", "lat", "lon")] - + return CoordPair(*args) - + return func def _cmp_operator(operator): """Function wrapper for comparison operators. - + Args: - + operator (method): The operator to wrap. - + Returns: - + method: An implementation for the *operator* type. - + """ - + def func(self, other): """Operator implementation. - - Performs a comparison operation across all of the same class - attributes, and returns True if all these operations are True. - + + Performs a comparison operation across all of the same class + attributes, and returns True if all these operations are True. + Returns: - - :obj:`boot`: Returns True if all comparisons across class + + :obj:`boot`: Returns True if all comparisons across class attributes returns True, otherwise False. - + """ vals = [getattr(getattr(self, attr), operator)(getattr(other, attr)) - for attr in ("x", "y", "lat", "lon") + for attr in ("x", "y", "lat", "lon") if getattr(self, attr) is not None] - + return all(vals) - + return func - - + + class CoordPair(object): - """A class that stores (x, y) and/or (latitude, longitude) + """A class that stores (x, y) and/or (latitude, longitude) coordinate pairs. - - Most math operators are supplied. When the other operand is a - :class:`CoordPair`, the operation is performed with the same attribute. - When a math operation uses a scalar as the other operand, the - operation is applied across all attributes. - + + Most math operators are supplied. When the other operand is a + :class:`CoordPair`, the operation is performed with the same attribute. + When a math operation uses a scalar as the other operand, the + operation is applied across all attributes. + Attributes: - + x (:obj:`float`): The x-coordinate. y (:obj:`float`): The y-coordinate. lat (:obj:`float`): The latitude coordinate. lon (:obj:`float`): The longitude coordinate. - - + + """ def __init__(self, x=None, y=None, lat=None, lon=None): """Initialize a :class:`CoordPair` object. - + Args: - + x (:obj:`float`, optional): The x-coordinate. y (:obj:`float`, optional): The y-coordinate. lat (:obj:`float`, optional): The latitude coordinate. lon (:obj:`float`, optional): The longitude coordinate. - - + + """ 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}"): """Return a :obj:`str` for the (x,y) coordinate pair. - + Args: - + fmt (:obj:`str`): The format string. Default is '{:.4f}, {:.4f}' - + Returns: - + :obj:`str`: A string for the (x,y) coordinate pair - + """ 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}"): """Return a :obj:`str` for the (latitude, longitude) coordinate pair. - + Args: - + fmt (:obj:`str`): The format string. Default is '{:.4f}, {:.4f}' - + Returns: - + :obj:`str`: A string for the (latitude, longitude) coordinate pair - + """ if self.lat is None or self.lon is None: return None - + return fmt.format(self.lat, self.lon) - - + def __round__(self, ndigits=None): """Return a new :class:`CoordPair` object with all coordinate values rounded to the nearest integer. - + Args: - + ndigits (:obj:`int`): The number of digits. - + Returns: - + :class:`CoordPair`: A CoordPair object. - + """ args = [None if getattr(self, attr) is None - else py2round(getattr(self, attr), ndigits) + else py2round(getattr(self, attr), ndigits) 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")] + 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")] - + 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__", + +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)) - - - \ No newline at end of file diff --git a/src/wrf/decorators.py b/src/wrf/decorators.py index 1427462..806fbf5 100644 --- a/src/wrf/decorators.py +++ b/src/wrf/decorators.py @@ -2,7 +2,7 @@ from __future__ import (absolute_import, division, print_function) from collections import Iterable, OrderedDict -import wrapt +import wrapt import numpy as np import numpy.ma as ma @@ -14,188 +14,177 @@ from .constants import default_fill if xarray_enabled(): from xarray import DataArray - + + def convert_units(unit_type, alg_unit): """A decorator that converts the units from the wrapped function's output. - + The desired units are determined from the wrapped function's arguments. - + Args: - - unit_type (:obj:`str`): The unit type. Choices are: 'wind', + + unit_type (:obj:`str`): The unit type. Choices are: 'wind', 'pressure', 'temp', or 'height'. - - alg_unit (:obj:`str`): The units returned by the wrapped function, + + alg_unit (:obj:`str`): The units returned by the wrapped function, which is usually the units returned by the Fortran routine. - + Returns: - - :class:`numpy.ndarray`: The wrapped function's output in the desired + + :class:`numpy.ndarray`: The wrapped function's output in the desired units. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): desired_units = from_args(wrapped, "units", *args, **kwargs)["units"] u_cleaned = dealias_and_clean_unit(desired_units) check_units(u_cleaned, unit_type) - + # Unit conversion done here - return do_conversion(wrapped(*args, **kwargs), unit_type, + return do_conversion(wrapped(*args, **kwargs), unit_type, alg_unit, desired_units) - - return func_wrapper + return func_wrapper -#def _calc_out_dims(outvar, left_dims): -# """ -# -# """ -# #left_dims = [x for x in left_dims] -# #right_dims = [x for x in outvar.shape] -# #return left_dims + right_dims -# -# return left_dims + outvar.shape - def left_iteration(ref_var_expected_dims, ref_var_right_ndims, insert_dims=None, ref_var_idx=None, ref_var_name=None, - ignore_args=None, + ignore_args=None, ignore_kargs=None, outviews="outview", alg_dtype=np.float64, cast_output=True): """A decorator to handle iterating over the leftmost dimensions. - + For example, if a wrapped function works with three-dimensional arrays, but - the variables include a 4th leftmost dimension for 'Time', this decorator + the variables include a 4th leftmost dimension for 'Time', this decorator will iterate over all times, call the 3D Fortran routine, and aggregate the results in to a 4D output array. - - It is also important to note that the final output array is allocated - first, and then views are passed to the wrapped function so that values + + It is also important to note that the final output array is allocated + first, and then views are passed to the wrapped function so that values do not need to get copied in to the final output array. - + Args: - - ref_var_expected_dims (:obj:`int`): The number of dimensions that the + + ref_var_expected_dims (:obj:`int`): The number of dimensions that the Fortran routine is expecting for the reference variable. - - ref_var_right_ndims (:obj:`int`): The number of dimensions from the - right to keep for the reference variable when making the output. - Can also be a :class:`combine_dims` object if the sizes are + + ref_var_right_ndims (:obj:`int`): The number of dimensions from the + right to keep for the reference variable when making the output. + Can also be a :class:`combine_dims` object if the sizes are determined from multiple variables. - - insert_dims (sequence of :obj:`int`, optional): A sequence of - dimensions to insert between the left dimensions (e.g. time) and + + insert_dims (sequence of :obj:`int`, optional): A sequence of + dimensions to insert between the left dimensions (e.g. time) and the kept right dimensions. Default is None. - - ref_var_idx (:obj:`int`, optional): The index in the wrapped function's - positional arguments to be used as the reference variable for - determining the leftmost dimensions. Must be specified if + + ref_var_idx (:obj:`int`, optional): The index in the wrapped function's + positional arguments to be used as the reference variable for + determining the leftmost dimensions. Must be specified if *ref_var_name* is None. Default is None. - - ref_var_name (:obj:`str`, optional): The keyword argument name for the - wrapped function's keyword arguments to be used as the reference - variable for calculating the leftmost dimensions. Must be + + ref_var_name (:obj:`str`, optional): The keyword argument name for the + wrapped function's keyword arguments to be used as the reference + variable for calculating the leftmost dimensions. Must be specified if *ref_var_idx* is None. Default is None. - + ignore_args (sequence of :obj:`int`): Indexes of any arguments that - should be ignored when creating the sliced views that are + should be ignored when creating the sliced views that are passed to the Fortran routine. - - ignore_kargs (sequence of :obj:`str`): Keys of any keyword arguments - that should be ignored when creating the sliced views that are + + ignore_kargs (sequence of :obj:`str`): Keys of any keyword arguments + that should be ignored when creating the sliced views that are passed to the Fortran routine. - - outviews (:obj:`str` or a sequence): A single key or sequence of keys - that indicate the wrapped function's keyword argument to use + + outviews (:obj:`str` or a sequence): A single key or sequence of keys + that indicate the wrapped function's keyword argument to use as the output variable(s) in the wrapped function. - - alg_dtype (:class:`numpy.dtype` or :obj:`str`): The numpy data type + + alg_dtype (:class:`numpy.dtype` or :obj:`str`): The numpy data type used in the wrapped function. - - cast_output (:obj:`bool`): Set to True to cast the wrapped function's + + cast_output (:obj:`bool`): Set to True to cast the wrapped function's output to the same type as the reference variable. - + Returns: - - :class:`numpy.ndarray`: The aggregated output array that includes + + :class:`numpy.ndarray`: The aggregated output array that includes all extra leftmost dimensions found in the reference variable. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): _ignore_args = ignore_args if ignore_args is not None else () _ignore_kargs = ignore_kargs if ignore_kargs is not None else () _outkeys = [outviews] if isstr(outviews) else outviews - + if ref_var_idx is not None: ref_var = args[ref_var_idx] else: ref_var = kwargs[ref_var_name] - + ref_var_dtype = ref_var.dtype ref_var_shape = ref_var.shape extra_dim_num = ref_var.ndim - ref_var_expected_dims - + # No special left side iteration, return the function result if (extra_dim_num == 0): return wrapped(*args, **kwargs) - + # Start by getting the left-most 'extra' dims - extra_dims = ref_var_shape[0:extra_dim_num] - + extra_dims = ref_var_shape[0:extra_dim_num] + mid_dims = () if insert_dims is None else tuple(insert_dims) - + if not isinstance(ref_var_right_ndims, combine_dims): right_dims = ref_var_shape[-ref_var_right_ndims:] else: right_dims = ref_var_right_ndims(*args) - + left_dims = extra_dims outdims = left_dims + mid_dims + right_dims - + if "outview" not in kwargs: outd = OrderedDict((outkey, np.empty(outdims, alg_dtype)) - for outkey in _outkeys) - + for outkey in _outkeys) + mask_output = False for left_idxs in iter_left_indexes(extra_dims): # Make the left indexes plus a single slice object # The single slice will handle all the dimensions to # the right (e.g. [1,1,:]) left_and_slice_idxs = left_idxs + (slice(None), ) - - + # Slice the args if applicable - new_args = [arg[left_and_slice_idxs] - if i not in _ignore_args else arg - for i,arg in enumerate(args)] - + new_args = [arg[left_and_slice_idxs] + if i not in _ignore_args else arg + for i, arg in enumerate(args)] + # Slice the kwargs if applicable - new_kargs = {key:(val[left_and_slice_idxs] + new_kargs = {key: (val[left_and_slice_idxs] if key not in _ignore_kargs else val) - for key,val in viewitems(kwargs)} - + for key, val in viewitems(kwargs)} + # Skip the possible empty/missing arrays for the join method skip_missing = False for arg in new_args: try: _ = arg.ndim except AttributeError: - continue # Not an array object + continue # Not an array object else: arr = to_np(arg) - + try: all_masked = arr.mask.all() except AttributeError: - pass # Not a masked array + pass # Not a masked array else: if all_masked: for output in viewvalues(outd): @@ -204,261 +193,257 @@ def left_iteration(ref_var_expected_dims, skip_missing = True mask_output = True break - + if skip_missing: continue - + # Insert the output views if one hasn't been provided if "outview" not in new_kargs: - for outkey,output in viewitems(outd): + for outkey, output in viewitems(outd): outview = output[left_and_slice_idxs] new_kargs[outkey] = outview - + result = wrapped(*new_args, **new_kargs) - - # Make sure the result is the same data as what got passed in + + # 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]): + if (result.__array_interface__["data"][0] != + outview.__array_interface__["data"][0]): raise RuntimeError("output array was copied") - - + if len(outd) == 1: output = next(iter(viewvalues(outd))) else: output = tuple(arr for arr in viewvalues(outd)) - - - + if cast_output: if isinstance(output, np.ndarray): output = output.astype(ref_var_dtype) else: output = tuple(arr.astype(ref_var_dtype) for arr in output) - + # Mostly when used with join if mask_output: if isinstance(output, np.ndarray): output = ma.masked_values(output, default_fill(np.float64)) else: - output = tuple(ma.masked_values(arr, default_fill(np.float64)) + output = tuple(ma.masked_values(arr, default_fill(np.float64)) for arr in output) - + return output - + return func_wrapper -def cast_type(ref_idx=0, arg_idxs=None, karg_names=None, +def cast_type(ref_idx=0, arg_idxs=None, karg_names=None, alg_dtype=np.float64, outviews="outview"): - """A decorator to handle type casting. - - This decorator is used to cast variables to and from the required + """A decorator to handle type casting. + + This decorator is used to cast variables to and from the required :class:`numpy.dtype` used in the wrapped function. - + Args: - - ref_idx (:obj:`int`, optional): The index in the wrapped function's - positional arguments to be used as the reference variable for + + ref_idx (:obj:`int`, optional): The index in the wrapped function's + positional arguments to be used as the reference variable for determining the :class:`numpy.dtype` to return. Default is 0. - - arg_idxs (sequence of :obj:`int`, optional): A sequence of indexes in the - wrapped function's positional arguments that indicate which + + arg_idxs (sequence of :obj:`int`, optional): A sequence of indexes in + the wrapped function's positional arguments that indicate which arguments to cast. Must be specified if *karg_names* is None. Default is None. - + karg_names (sequence of :obj:`str`): A sequence of keyword arguments - in the wrapped function's keyword arguments that indicate the - arguments to cast. Must be specified if *arg_idxs* is None. + in the wrapped function's keyword arguments that indicate the + arguments to cast. Must be specified if *arg_idxs* is None. Default is None. - - alg_dtype (:class:`numpy.dtype` or :obj:`str`): The numpy data type used - in the wrapped function. - - outviews (:obj:`str` or a sequence): A single key or sequence of keys - that indicate the wrapped function's keyword argument to use + + alg_dtype (:class:`numpy.dtype` or :obj:`str`): The numpy data type + used in the wrapped function. + + outviews (:obj:`str` or a sequence): A single key or sequence of keys + that indicate the wrapped function's keyword argument to use as the output variable(s) in the wrapped function. - + Returns: - - :class:`numpy.ndarray`: The wrapped function's output cast to the + + :class:`numpy.ndarray`: The wrapped function's output cast to the same :class:`numpy.dtype` as the reference variable. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): _arg_idxs = arg_idxs if arg_idxs is not None else () _karg_names = karg_names if karg_names is not None else () - + # Handle output views if applicable _outkeys = [outviews] if isstr(outviews) else outviews _outviews = from_args(wrapped, _outkeys, *args, **kwargs) - + has_outview = False for outkey in _outkeys: _outview = _outviews[outkey] if _outview is not None: has_outview = True - - + orig_type = args[ref_idx].dtype - + new_args = [arg.astype(alg_dtype) - if i in _arg_idxs else arg - for i,arg in enumerate(args)] - - new_kargs = {key:(val.astype(alg_dtype) - if key in _karg_names else val) - for key,val in viewitems(kwargs)} - - result = wrapped(*new_args, **new_kargs) - + if i in _arg_idxs else arg + for i, arg in enumerate(args)] + + new_kargs = {key: (val.astype(alg_dtype) + if key in _karg_names else val) + for key, val in viewitems(kwargs)} + + result = wrapped(*new_args, **new_kargs) + # Do nothing for supplied output views if not has_outview: if isinstance(result, np.ndarray): if result.dtype == orig_type: return result return result.astype(orig_type) - elif isinstance(result, Iterable): # got back a sequence of arrays - return tuple(arr.astype(orig_type) + elif isinstance(result, Iterable): # got back a sequence of arrays + return tuple(arr.astype(orig_type) if arr.dtype != orig_type else arr for arr in result) - + return result - + return func_wrapper def _extract_and_transpose(arg, do_transpose): - """Return a transposed view of the :class:`numpy.ndarray` inside of a + """Return a transposed view of the :class:`numpy.ndarray` inside of a :class:`xarray.DataArray` object. - - If the *arg* parameter is not a :class:`xarray.DataArray` object, then + + If the *arg* parameter is not a :class:`xarray.DataArray` object, then *arg* is returned. - + Args: - - arg (:class:`xarray.DataArray` or :obj:`object`): Can be any object + + arg (:class:`xarray.DataArray` or :obj:`object`): Can be any object type. - + do_transpose: Set to False to only extract the variable. When True, the extracted array will also be transposed to a Fortran view if it is not already Fortran contiguous. - + Returns: - - :class:`numpy.ndarray`: A numpy array. If *do_transpose* is True, + + :class:`numpy.ndarray`: A numpy array. If *do_transpose* is True, the numpy array will also be a Fortran contiguous view. - + """ - + if xarray_enabled(): if isinstance(arg, DataArray): arg = to_np(arg) - + if do_transpose: if isinstance(arg, np.ndarray): if not arg.flags.f_contiguous and arg.ndim > 1: return arg.T - + return arg - + def extract_and_transpose(do_transpose=True, outviews="outview"): - """A decorator to extract the data array from a :class:`xarray.DataArray` - - This decorator also transposes the view of the data to Fortran + """A decorator to extract the data array from a :class:`xarray.DataArray` + + This decorator also transposes the view of the data to Fortran contiguous if *do_transpose* is True. - + Args: - + do_transpose: Set to False to only extract the variable. When True, the extracted array will also be transposed to a Fortran view if it is not already Fortran contiguous. - - outviews (:obj:`str` or a sequence): A single key or sequence of keys - that indicate the wrapped function's keyword argument to use + + outviews (:obj:`str` or a sequence): A single key or sequence of keys + that indicate the wrapped function's keyword argument to use as the output variable(s) in the wrapped function. - + Returns: - - :class:`numpy.ndarray`: A numpy array. If *do_transpose* is True, + + :class:`numpy.ndarray`: A numpy array. If *do_transpose* is True, the numpy array will also be a Fortran contiguous view. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): - + # Handle output views if applicable _outkeys = [outviews] if isstr(outviews) else outviews _outviews = from_args(wrapped, _outkeys, *args, **kwargs) - + has_outview = False for outkey in _outkeys: _outview = _outviews[outkey] if _outview is not None: has_outview = True - + new_args = [_extract_and_transpose(arg, do_transpose) for arg in args] - - new_kargs = {key:_extract_and_transpose(val, do_transpose) - for key,val in viewitems(kwargs)} - - result = wrapped(*new_args, **new_kargs) - + + new_kargs = {key: _extract_and_transpose(val, do_transpose) + for key, val in viewitems(kwargs)} + + result = wrapped(*new_args, **new_kargs) + # Do nothing for supplied output views if has_outview: return result - + if isinstance(result, np.ndarray): if result.flags.f_contiguous and result.ndim > 1: return result.T elif isinstance(result, Iterable): - return tuple(x.T if x.flags.f_contiguous and x.ndim > 1 else x + return tuple(x.T if x.flags.f_contiguous and x.ndim > 1 else x for x in result) - + return result - + return func_wrapper def check_args(refvaridx, refvarndim, rightdims, stagger=None, refstagdim=None): """A decorator to check that the wrapped function's arguments are valid. - + An exception is raised when an invalid argument is found. - + Args: - - refvaridx (:obj:`int`): The wrapped function's positional argument + + refvaridx (:obj:`int`): The wrapped function's positional argument index to use as the reference variable. - - refvarndim (:obj:`int`): The number of dimensions for the reference + + refvarndim (:obj:`int`): The number of dimensions for the reference variable that is expected by the wrapped function. - - rightdims (sequence of :obj:`int`): The expected number of right + + rightdims (sequence of :obj:`int`): The expected number of right dimensions for each argument. - - stagger (sequence of :obj:`int` or :obj:`None`, optional): The - dimension that is staggered for each argument in the wrapped - function. Use :obj:`None` in the sequence to indicate no + + stagger (sequence of :obj:`int` or :obj:`None`, optional): The + dimension that is staggered for each argument in the wrapped + function. Use :obj:`None` in the sequence to indicate no staggering for that argument. Default is None. - - refstagdim (:obj:`int`, optional): The staggered dimension for the + + refstagdim (:obj:`int`, optional): The staggered dimension for the reference variable, if applicable. Default is None. - + Returns: - + None - + Raises: - + :class:`ValueError`: Raised when an invalid argument is detected. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): - + refvar = args[refvaridx] try: _ndim = refvar.ndim @@ -467,7 +452,7 @@ def check_args(refvaridx, refvarndim, rightdims, stagger=None, "object".format(refvaridx)) else: extra_dims = refvar.ndim - refvarndim - + # Always use unstaggered as the basis of comparison if refstagdim is not None: _refshape = list(refvar.shape) @@ -475,33 +460,34 @@ def check_args(refvaridx, refvarndim, rightdims, stagger=None, _refshape = tuple(_refshape) else: _refshape = refvar.shape - + if stagger is None: _stagger = [None]*len(rightdims) else: _stagger = stagger - - for i,ndim in enumerate(rightdims): + + for i, ndim in enumerate(rightdims): if ndim is None: continue - + var = args[i] - + try: _ = var.ndim except AttributeError: raise ValueError("argument {} is not an arraylike " "object".format(i)) - + right_var_ndims = rightdims[i] - + # Check that the number of dims is correct if (var.ndim - extra_dims != right_var_ndims): raise ValueError("invalid number of dimensions for argument " - "{} (got {}, expected {}).".format(i, - var.ndim, - right_var_ndims + extra_dims)) - + "{} (got {}, expected {}).".format( + i, + var.ndim, + right_var_ndims + extra_dims)) + # Add 1 to the reference staggered dim index before doing the check if _stagger[i] is not None: ref_shape = list(_refshape) @@ -509,27 +495,19 @@ def check_args(refvaridx, refvarndim, rightdims, stagger=None, ref_shape = tuple(ref_shape) else: ref_shape = _refshape - - ref_right_sizes = ref_shape[extra_dims:] - - # Check that right dimensions are lined up - if (var.shape[-right_var_ndims:] != - ref_right_sizes[-right_var_ndims:]): - - raise ValueError("invalid shape for argument " - "{} (got {}, expected {})".format(i, - var.shape[-right_var_ndims:], - ref_right_sizes[-right_var_ndims:])) - - return wrapped(*args, **kwargs) - - return func_wrapper + ref_right_sizes = ref_shape[extra_dims:] - - + # Check that right dimensions are lined up + if (var.shape[-right_var_ndims:] != + ref_right_sizes[-right_var_ndims:]): - - + raise ValueError("invalid shape for argument " + "{} (got {}, expected {})".format( + i, + var.shape[-right_var_ndims:], + ref_right_sizes[-right_var_ndims:])) + return wrapped(*args, **kwargs) + return func_wrapper diff --git a/src/wrf/destag.py b/src/wrf/destag.py index 21d688d..2a1275c 100755 --- a/src/wrf/destag.py +++ b/src/wrf/destag.py @@ -8,57 +8,55 @@ from .metadecorators import set_destag_metadata @extract_and_transpose(do_transpose=False) def destagger(var, stagger_dim, meta=False): """Return the variable on the unstaggered grid. - - This function destaggers the variable by taking the average of the - values located on either side of the grid box. - + + This function destaggers the variable by taking the average of the + values located on either side of the grid box. + Args: - - var (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A variable + + var (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A variable on a staggered grid. - + stagger_dim (:obj:`int`): The dimension index to destagger. - Negative values can be used to choose dimensions referenced + Negative values can be used to choose dimensions referenced from the right hand side (-1 is the rightmost dimension). - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is False. - + Returns: - + :class:`xarray.DataArray` or :class:`numpy.ndarray`: - The destaggered variable. If xarray is enabled and - the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + The destaggered variable. If xarray is enabled and + the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ var_shape = var.shape num_dims = var.ndim stagger_dim_size = var_shape[stagger_dim] - - # Dynamically building the range slices to create the appropriate + + # Dynamically building the range slices to create the appropriate # number of ':'s in the array accessor lists. - # For example, for a 3D array, the calculation would be - # result = .5 * (var[:,:,0:stagger_dim_size-2] + # For example, for a 3D array, the calculation would be + # result = .5 * (var[:,:,0:stagger_dim_size-2] # + var[:,:,1:stagger_dim_size-1]) - # for stagger_dim=2. So, full slices would be used for dims 0 and 1, but - # dim 2 needs the special slice. + # for stagger_dim=2. So, full slices would be used for dims 0 and 1, but + # dim 2 needs the special slice. full_slice = slice(None) slice1 = slice(0, stagger_dim_size - 1, 1) slice2 = slice(1, stagger_dim_size, 1) - + # default to full slices dim_ranges_1 = [full_slice] * num_dims dim_ranges_2 = [full_slice] * num_dims - + # for the stagger dim, insert the appropriate slice range dim_ranges_1[stagger_dim] = slice1 dim_ranges_2[stagger_dim] = slice2 - + result = .5*(var[tuple(dim_ranges_1)] + var[tuple(dim_ranges_2)]) - - return result - \ No newline at end of file + return result diff --git a/src/wrf/extension.py b/src/wrf/extension.py index 84803ef..177fc64 100755 --- a/src/wrf/extension.py +++ b/src/wrf/extension.py @@ -5,148 +5,150 @@ import numpy as np from .constants import Constants, default_fill from wrf._wrffortran import (dcomputetk, dinterp3dz, dinterp2dxy, dinterp1d, - dcomputeseaprs, dfilter2d, dcomputerh, dcomputeuvmet, - dcomputetd, dcapecalc2d, dcapecalc3d, dcloudfrac2, - wrfcttcalc, calcdbz, dcalrelhl, dcalcuh, dcomputepv, - dcomputeabsvort, dlltoij, dijtoll, deqthecalc, - omgcalc, virtual_temp, wetbulbcalc, dcomputepw, - wrf_monotonic, wrf_vintrp, dcomputewspd, - dcomputewdir, dinterp3dz_2dlev, - fomp_set_num_threads, fomp_get_num_threads, - fomp_get_max_threads, fomp_get_thread_num, - fomp_get_num_procs, fomp_in_parallel, - fomp_set_dynamic, fomp_get_dynamic, fomp_set_nested, - fomp_get_nested, fomp_set_schedule, - fomp_get_schedule, fomp_get_thread_limit, - fomp_set_max_active_levels, - fomp_get_max_active_levels, fomp_get_level, - fomp_get_ancestor_thread_num, fomp_get_team_size, - fomp_get_active_level, fomp_in_final, - fomp_init_lock, fomp_init_nest_lock, - fomp_destroy_lock, fomp_destroy_nest_lock, - fomp_set_lock, fomp_set_nest_lock, - fomp_unset_lock, fomp_unset_nest_lock, - fomp_test_lock, fomp_test_nest_lock, - fomp_get_wtime, fomp_get_wtick, fomp_enabled) - -from .decorators import (left_iteration, cast_type, + dcomputeseaprs, dfilter2d, dcomputerh, + dcomputeuvmet, dcomputetd, dcapecalc2d, + dcapecalc3d, dcloudfrac2, wrfcttcalc, calcdbz, + dcalrelhl, dcalcuh, dcomputepv, dcomputeabsvort, + dlltoij, dijtoll, deqthecalc, omgcalc, + virtual_temp, wetbulbcalc, dcomputepw, + wrf_monotonic, wrf_vintrp, dcomputewspd, + dcomputewdir, dinterp3dz_2dlev, + fomp_set_num_threads, fomp_get_num_threads, + fomp_get_max_threads, fomp_get_thread_num, + fomp_get_num_procs, fomp_in_parallel, + fomp_set_dynamic, fomp_get_dynamic, + fomp_set_nested, fomp_get_nested, + fomp_set_schedule, fomp_get_schedule, + fomp_get_thread_limit, fomp_set_max_active_levels, + fomp_get_max_active_levels, fomp_get_level, + fomp_get_ancestor_thread_num, fomp_get_team_size, + fomp_get_active_level, fomp_in_final, + fomp_init_lock, fomp_init_nest_lock, + fomp_destroy_lock, fomp_destroy_nest_lock, + fomp_set_lock, fomp_set_nest_lock, + fomp_unset_lock, fomp_unset_nest_lock, + fomp_test_lock, fomp_test_nest_lock, + fomp_get_wtime, fomp_get_wtick, fomp_enabled) + +from .decorators import (left_iteration, cast_type, extract_and_transpose, check_args) from .util import combine_dims, npbytes_to_str, psafilepath from .py3compat import py3range -from .specialdec import (uvmet_left_iter, cape_left_iter, +from .specialdec import (uvmet_left_iter, cape_left_iter, cloudfrac_left_iter, check_cape_args, interplevel_left_iter, check_interplevel_args) + class DiagnosticError(Exception): """Raised when an error occurs in a diagnostic routine.""" def __init__(self, message=None): """Initialize a :class:`wrf.DiagnosticError` object. - + Args: - + message (:obj:`str`): The error message. - + """ self._msg = message - + def __str__(self): return self._msg - + def __call__(self, message): """Callable method to make the exception object raise itself. - - This allows the exception to be thrown from inside Fortran routines - by using f2py's callback mechanism. This is no longer used within + + This allows the exception to be thrown from inside Fortran routines + by using f2py's callback mechanism. This is no longer used within wrf-python, but may be useful to other users. - + See Also: - + `f2py doc `_ - + """ raise self.__class__(message) -# The routines below are thin wrappers around the Fortran functions. These -# are not meant to be called by end users. Use the public API instead for + +# The routines below are thin wrappers around the Fortran functions. These +# are not meant to be called by end users. Use the public API instead for # that purpose. -# IMPORTANT! Unless otherwise noted, all variables used in the routines +# IMPORTANT! Unless otherwise noted, all variables used in the routines # below assume that Fortran-ordered views are being used. This allows # f2py to pass the array pointers directly to the Fortran routine. - @check_interplevel_args(is2dlev=False) @interplevel_left_iter(is2dlev=False) -@cast_type(arg_idxs=(0,1,2)) +@cast_type(arg_idxs=(0, 1, 2)) @extract_and_transpose() def _interpz3d(field3d, z, desiredloc, missingval, outview=None): """Wrapper for dinterp3dz. - + Located in wrf_user.f90. - + """ - if outview is None: + if outview is None: outshape = field3d.shape[0:2] + desiredloc.shape outview = np.empty(outshape, np.float64, order="F") - - result = dinterp3dz(field3d, + + result = dinterp3dz(field3d, outview, - z, - desiredloc, + z, + desiredloc, missingval) return result @check_interplevel_args(is2dlev=True) @interplevel_left_iter(is2dlev=True) -@cast_type(arg_idxs=(0,1,2)) +@cast_type(arg_idxs=(0, 1, 2)) @extract_and_transpose() def _interpz3d_lev2d(field3d, z, lev2d, missingval, outview=None): """Wrapper for dinterp3dz. - + Located in wrf_user.f90. - + """ if outview is None: outview = np.empty(field3d.shape[0:2], np.float64, order="F") - - result = dinterp3dz_2dlev(field3d, + + result = dinterp3dz_2dlev(field3d, outview, - z, - lev2d, + z, + lev2d, missingval) return result -@check_args(0, 3, (3,)) -@left_iteration(3, combine_dims([(0,-3),(1,-2)]), ref_var_idx=0, - ignore_args=(1,)) -@cast_type(arg_idxs=(0,1)) +@check_args(0, 3, (3, )) +@left_iteration(3, combine_dims([(0, -3), (1, -2)]), ref_var_idx=0, + ignore_args=(1, )) +@cast_type(arg_idxs=(0, 1)) @extract_and_transpose() def _interp2dxy(field3d, xy, outview=None): """Wrapper for dinterp2dxy. - + Located in wrf_user.f90. - + """ if outview is None: - outview = np.empty((xy.shape[-1], field3d.shape[-1]), np.float64, + outview = np.empty((xy.shape[-1], field3d.shape[-1]), np.float64, order="F") - + result = dinterp2dxy(field3d, outview, xy) return result -@check_args(0, 1, (1,1,None,None)) -@left_iteration(1, combine_dims([(2,0)]), ref_var_idx=0, ignore_args=(2,3)) -@cast_type(arg_idxs=(0,1,2)) +@check_args(0, 1, (1, 1, None, None)) +@left_iteration(1, combine_dims([(2, 0)]), ref_var_idx=0, ignore_args=(2, 3)) +@cast_type(arg_idxs=(0, 1, 2)) @extract_and_transpose() def _interp1d(v_in, z_in, z_out, missingval, outview=None): """Wrapper for dinterp1d. - + Located in wrf_user.f90. - + """ if outview is None: outview = np.empty_like(z_out) @@ -156,47 +158,47 @@ def _interp1d(v_in, z_in, z_out, missingval, outview=None): z_in, z_out, missingval) - + return result -@left_iteration(3, combine_dims([(3,0), (1,0)]), - ref_var_idx=0, ignore_args=(1,3,4)) -@cast_type(arg_idxs=(0,)) +@left_iteration(3, combine_dims([(3, 0), (1, 0)]), + ref_var_idx=0, ignore_args=(1, 3, 4)) +@cast_type(arg_idxs=(0, )) @extract_and_transpose(do_transpose=False) def _vertcross(field3d, xy, var2dz, z_var2d, missingval, outview=None): """Return the vertical cross section. - - This routine was originally written in scripted NCL code and doesn't + + This routine was originally written in scripted NCL code and doesn't directly wrap a Fortran routine. - + Located in WRFUserARW.ncl. - + """ # Note: This is using C-ordering if outview is None: outview = np.empty((z_var2d.shape[0], xy.shape[0]), dtype=var2dz.dtype) - + var2dtmp = _interp2dxy(field3d, xy) - + for i in py3range(xy.shape[0]): - outview[:,i] = _interp1d(var2dtmp[:,i], var2dz[:,i], z_var2d, - missingval) - + outview[:, i] = _interp1d(var2dtmp[:, i], var2dz[:, i], z_var2d, + missingval) + return outview -@left_iteration(2, combine_dims([(1,0)]), ref_var_idx=0, ignore_args=(1,)) -@cast_type(arg_idxs=(0,)) +@left_iteration(2, combine_dims([(1, 0)]), ref_var_idx=0, ignore_args=(1, )) +@cast_type(arg_idxs=(0, )) @extract_and_transpose(do_transpose=False) def _interpline(field2d, xy, outview=None): """Return the two-dimensional field interpolated to a line. - - This routine was originally written in scripted NCL code and doesn't + + This routine was originally written in scripted NCL code and doesn't directly wrap a Fortran routine. - + Located in WRFUserARW.ncl. - + """ # Note: This is using C-ordering if outview is None: @@ -204,35 +206,35 @@ def _interpline(field2d, xy, outview=None): tmp_shape = (1,) + field2d.shape var2dtmp = np.empty(tmp_shape, field2d.dtype) - var2dtmp[0,:,:] = field2d[:,:] - + var2dtmp[0, :, :] = field2d[:, :] + var1dtmp = _interp2dxy(var2dtmp, xy) - + outview[:] = var1dtmp[0, :] - + return outview -@check_args(0, 3, (3,3,3,3)) +@check_args(0, 3, (3, 3, 3, 3)) @left_iteration(3, 2, ref_var_idx=0) -@cast_type(arg_idxs=(0,1,2,3)) +@cast_type(arg_idxs=(0, 1, 2, 3)) @extract_and_transpose() def _slp(z, t, p, q, outview=None): """Wrapper for dcomputeseaprs. - + Located in wrf_user.f90. - + """ t_surf = np.zeros(z.shape[0:2], np.float64, order="F") t_sea_level = np.zeros(z.shape[0:2], np.float64, order="F") level = np.zeros(z.shape[0:2], np.int32, order="F") - + if outview is None: outview = np.empty(z.shape[0:2], np.float64, order="F") - + errstat = np.array(0) errmsg = np.zeros(Constants.ERRLEN, "c") - + result = dcomputeseaprs(z, t, p, @@ -243,98 +245,98 @@ def _slp(z, t, p, q, outview=None): level, errstat=errstat, errmsg=errmsg) - + if int(errstat) != 0: raise DiagnosticError("".join(npbytes_to_str(errmsg)).strip()) - + return result -@check_args(0, 3, (3,3)) +@check_args(0, 3, (3, 3)) @left_iteration(3, 3, ref_var_idx=0) -@cast_type(arg_idxs=(0,1)) +@cast_type(arg_idxs=(0, 1)) @extract_and_transpose() def _tk(pressure, theta, outview=None): """Wrapper for dcomputetk. - + Located in wrf_user.f90. - + """ # No need to transpose here since operations on 1D array shape = pressure.shape - if outview is None: + if outview is None: outview = np.empty_like(pressure) result = dcomputetk(outview.ravel(order="A"), - pressure.ravel(order="A"), - theta.ravel(order="A")) + pressure.ravel(order="A"), + theta.ravel(order="A")) result = np.reshape(result, shape, order="F") - - return result + return result -@check_args(0, 2, (2,2)) + +@check_args(0, 2, (2, 2)) @left_iteration(2, 2, ref_var_idx=0) -@cast_type(arg_idxs=(0,1)) +@cast_type(arg_idxs=(0, 1)) @extract_and_transpose() def _td(pressure, qv_in, outview=None): """Wrapper for dcomputetd. - + Located in wrf_user.f90. - + """ shape = pressure.shape if outview is None: outview = np.empty_like(pressure) - + result = dcomputetd(outview.ravel(order="A"), - pressure.ravel(order="A"), + pressure.ravel(order="A"), qv_in.ravel(order="A")) result = np.reshape(result, shape, order="F") - + return result -@check_args(0, 2, (2,2,2)) +@check_args(0, 2, (2, 2, 2)) @left_iteration(2, 2, ref_var_idx=0) -@cast_type(arg_idxs=(0,1,2)) +@cast_type(arg_idxs=(0, 1, 2)) @extract_and_transpose() def _rh(qv, q, t, outview=None): """Wrapper for dcomputerh. - + Located in wrf_user.f90. - + """ shape = qv.shape if outview is None: outview = np.empty_like(qv) result = dcomputerh(qv.ravel(order="A"), - q.ravel(order="A"), - t.ravel(order="A"), - outview.ravel(order="A")) + q.ravel(order="A"), + t.ravel(order="A"), + outview.ravel(order="A")) result = np.reshape(result, shape, order="F") - + return result -# Note: combining the -3 and -2 dimensions from u, then the -1 dimension +# Note: combining the -3 and -2 dimensions from u, then the -1 dimension # from v -@check_args(0, 3, (3,3,2,2,2,2), stagger=(-1,-2,-1,-2,None,None), +@check_args(0, 3, (3, 3, 2, 2, 2, 2), stagger=(-1, -2, -1, -2, None, None), refstagdim=-1) -@left_iteration(3, combine_dims([(0, (-3,-2)), - (1, (-1,))]), - ref_var_idx=0, ignore_args=(6,7)) -@cast_type(arg_idxs=(0,1,2,3,4,5)) +@left_iteration(3, combine_dims([(0, (-3, -2)), + (1, (-1, ))]), + ref_var_idx=0, ignore_args=(6, 7)) +@cast_type(arg_idxs=(0, 1, 2, 3, 4, 5)) @extract_and_transpose() def _avo(u, v, msfu, msfv, msfm, cor, dx, dy, outview=None): """Wrapper for dcomputeabsvort. - + Located in wrf_pvo.f90. - + """ if outview is None: - outshape = (v.shape[0],) + u.shape[1:] + outshape = (v.shape[0], ) + u.shape[1:] outview = np.empty(outshape, np.float64, order="F") - + result = dcomputeabsvort(outview, u, v, @@ -344,25 +346,24 @@ def _avo(u, v, msfu, msfv, msfm, cor, dx, dy, outview=None): cor, dx, dy) - + return result -@check_args(0, 3, (3,3,3,3,2,2,2,2), stagger=(-1,-2,None,None,-1,-2,None, - None), - refstagdim=-1) -@left_iteration(3, 3, ref_var_idx=2, ignore_args=(8,9)) -@cast_type(arg_idxs=(0,1,2,3,4,5,6,7)) +@check_args(0, 3, (3, 3, 3, 3, 2, 2, 2, 2), + stagger=(-1, -2, None, None, -1, -2, None, None), refstagdim=-1) +@left_iteration(3, 3, ref_var_idx=2, ignore_args=(8, 9)) +@cast_type(arg_idxs=(0, 1, 2, 3, 4, 5, 6, 7)) @extract_and_transpose() def _pvo(u, v, theta, prs, msfu, msfv, msfm, cor, dx, dy, outview=None): """Wrapper for dcomputepv. - + Located in wrf_pvo.f90. - + """ if outview is None: outview = np.empty_like(prs) - + result = dcomputepv(outview, u, v, @@ -374,50 +375,52 @@ def _pvo(u, v, theta, prs, msfu, msfv, msfm, cor, dx, dy, outview=None): cor, dx, dy) - + return result -@check_args(0, 3, (3,3,3)) +@check_args(0, 3, (3, 3, 3)) @left_iteration(3, 3, ref_var_idx=0) -@cast_type(arg_idxs=(0,1,2)) +@cast_type(arg_idxs=(0, 1, 2)) @extract_and_transpose() def _eth(qv, tk, p, outview=None): """Wrapper for deqthecalc. - + Located in eqthecalc.f90. - + """ if outview is None: outview = np.empty_like(qv) - + result = deqthecalc(qv, tk, p, outview) - + return result @uvmet_left_iter() -@cast_type(arg_idxs=(0,1,2,3)) +@cast_type(arg_idxs=(0, 1, 2, 3)) @extract_and_transpose() -def _uvmet(u, v, lat, lon, cen_long, cone, isstag=0, has_missing=False, - umissing=default_fill(np.float64), vmissing=default_fill(np.float64), - uvmetmissing=default_fill(np.float64), outview=None): +def _uvmet(u, v, lat, lon, cen_long, cone, isstag=0, has_missing=False, + umissing=default_fill(np.float64), + vmissing=default_fill(np.float64), + uvmetmissing=default_fill(np.float64), + outview=None): """Wrapper for dcomputeuvmet. - + Located in wrf_user.f90. - + """ longca = np.zeros(lat.shape[0:2], np.float64, order="F") longcb = np.zeros(lon.shape[0:2], np.float64, order="F") rpd = Constants.PI/180. - + if outview is None: outdims = u.shape + (2,) outview = np.empty(outdims, np.float64, order="F") - + result = dcomputeuvmet(u, v, outview, @@ -428,73 +431,73 @@ def _uvmet(u, v, lat, lon, cen_long, cone, isstag=0, has_missing=False, cen_long, cone, rpd, - isstag, + isstag, has_missing, umissing, vmissing, uvmetmissing) - + return result -@check_args(0, 3, (3,3,3,3)) +@check_args(0, 3, (3, 3, 3, 3)) @left_iteration(3, 3, ref_var_idx=0) -@cast_type(arg_idxs=(0,1,2,3)) +@cast_type(arg_idxs=(0, 1, 2, 3)) @extract_and_transpose() def _omega(qv, tk, w, p, outview=None): """Wrapper for omgcalc. - + Located in wrf_rip_phys_routines.f90. - + """ if outview is None: outview = np.empty_like(qv) - + result = omgcalc(qv, tk, w, p, outview) - + return result -@check_args(0, 3, (3,3)) +@check_args(0, 3, (3, 3)) @left_iteration(3, 3, ref_var_idx=0) -@cast_type(arg_idxs=(0,1)) +@cast_type(arg_idxs=(0, 1)) @extract_and_transpose() def _tv(tk, qv, outview=None): """Wrapper for virtual_temp. - + Located in wrf_rip_phys_routines.f90. - + """ if outview is None: outview = np.empty_like(tk) - + result = virtual_temp(tk, qv, outview) - + return result -@check_args(0, 3, (3,3,3)) +@check_args(0, 3, (3, 3, 3)) @left_iteration(3, 3, ref_var_idx=0, ignore_args=(3,)) -@cast_type(arg_idxs=(0,1,2)) +@cast_type(arg_idxs=(0, 1, 2)) @extract_and_transpose() def _wetbulb(p, tk, qv, psafile=psafilepath(), outview=None): """Wrapper for wetbulbcalc. - + Located in wrf_rip_phys_routines.f90. - + """ if outview is None: outview = np.empty_like(p) - + errstat = np.array(0) errmsg = np.zeros(Constants.ERRLEN, "c") - + result = wetbulbcalc(p, tk, qv, @@ -502,106 +505,106 @@ def _wetbulb(p, tk, qv, psafile=psafilepath(), outview=None): psafile, errstat, errmsg) - + if int(errstat) != 0: raise DiagnosticError("".join(npbytes_to_str(errmsg)).strip()) - + return result -@check_args(0, 3, (3,3,3,2,2)) -@left_iteration(3, 2, ref_var_idx=0, ignore_args=(5,)) -@cast_type(arg_idxs=(0,1,2,3,4)) +@check_args(0, 3, (3, 3, 3, 2, 2)) +@left_iteration(3, 2, ref_var_idx=0, ignore_args=(5, )) +@cast_type(arg_idxs=(0, 1, 2, 3, 4)) @extract_and_transpose() def _srhel(u, v, z, ter, lats, top, outview=None): """Wrapper for dcalrelhl. - + Located in wrf_relhl.f90. - + """ if outview is None: outview = np.empty_like(ter) - - result = dcalrelhl(u, - v, - z, - ter, + + result = dcalrelhl(u, + v, + z, + ter, lats, top, outview) - + return result -@check_args(2, 3, (3,2,3,3,3), stagger=(-3,None,None,None,-3)) -@left_iteration(3, 2, ref_var_idx=2, ignore_args=(5,6,7,8)) -@cast_type(arg_idxs=(0,1,2,3,4)) +@check_args(2, 3, (3, 2, 3, 3, 3), stagger=(-3, None, None, None, -3)) +@left_iteration(3, 2, ref_var_idx=2, ignore_args=(5, 6, 7, 8)) +@cast_type(arg_idxs=(0, 1, 2, 3, 4)) @extract_and_transpose() def _udhel(zstag, mapfct, u, v, wstag, dx, dy, bottom, top, outview=None): """Wrapper for dcalcuh. - + Located in calc_uh.f90. - + """ if outview is None: outview = np.empty_like(mapfct) - - tem1 = np.zeros((u.shape[0], u.shape[1], u.shape[2]), np.float64, + + tem1 = np.zeros((u.shape[0], u.shape[1], u.shape[2]), np.float64, order="F") - tem2 = np.zeros((u.shape[0], u.shape[1], u.shape[2]), np.float64, + tem2 = np.zeros((u.shape[0], u.shape[1], u.shape[2]), np.float64, order="F") - - result = dcalcuh(zstag, - mapfct, - dx, - dy, - bottom, - top, + + result = dcalcuh(zstag, + mapfct, + dx, + dy, + bottom, + top, u, - v, - wstag, - outview, - tem1, + v, + wstag, + outview, + tem1, tem2) - + return result -@check_args(0, 3, (3,3,3,3), stagger=(None, None, None, -3)) +@check_args(0, 3, (3, 3, 3, 3), stagger=(None, None, None, -3)) @left_iteration(3, 2, ref_var_idx=0) -@cast_type(arg_idxs=(0,1,2,3)) +@cast_type(arg_idxs=(0, 1, 2, 3)) @extract_and_transpose() def _pw(p, tv, qv, ht, outview=None): """Wrapper for dcomputepw. - + Located in wrf_pw.f90. - + """ if outview is None: outview = np.empty(p.shape[0:2], p.dtype, order="F") - + result = dcomputepw(p, tv, qv, ht, outview) - + return result -@check_args(0, 3, (3,3,3,3,3,3)) -@left_iteration(3, 3, ref_var_idx=0, ignore_args=(6,7,8)) -@cast_type(arg_idxs=(0,1,2,3,4,5)) +@check_args(0, 3, (3, 3, 3, 3, 3, 3)) +@left_iteration(3, 3, ref_var_idx=0, ignore_args=(6, 7, 8)) +@cast_type(arg_idxs=(0, 1, 2, 3, 4, 5)) @extract_and_transpose() def _dbz(p, tk, qv, qr, qs, qg, sn0, ivarint, iliqskin, outview=None): """Wrapper for calcdbz. - + Located in wrf_user_dbz.f90. - + """ if outview is None: outview = np.empty_like(p) - + result = calcdbz(p, tk, qv, @@ -612,35 +615,35 @@ def _dbz(p, tk, qv, qr, qs, qg, sn0, ivarint, iliqskin, outview=None): ivarint, iliqskin, outview) - + return result @check_cape_args() @cape_left_iter() -@cast_type(arg_idxs=(0,1,2,3,4,5), outviews=("capeview", "cinview")) +@cast_type(arg_idxs=(0, 1, 2, 3, 4, 5), outviews=("capeview", "cinview")) @extract_and_transpose(outviews=("capeview", "cinview")) def _cape(p_hpa, tk, qv, ht, ter, sfp, missing, i3dflag, ter_follow, psafile=psafilepath(), capeview=None, cinview=None): """Wrapper for dcapecalc3d. - + Located in rip_cape.f90. - + """ if capeview is None: capeview = np.zeros(p_hpa.shape[0:3], p_hpa.dtype, order="F") - + if cinview is None: cinview = np.zeros(p_hpa.shape[0:3], p_hpa.dtype, order="F") - + errstat = np.array(0) errmsg = np.zeros(Constants.ERRLEN, "c") - + if i3dflag: cape_routine = dcapecalc3d else: cape_routine = dcapecalc2d - + # Work arrays k_left_shape = (p_hpa.shape[2], p_hpa.shape[0], p_hpa.shape[1]) prsf = np.empty(k_left_shape, np.float64, order="F") @@ -648,7 +651,7 @@ def _cape(p_hpa, tk, qv, ht, ter, sfp, missing, i3dflag, ter_follow, tmk_new = np.empty(k_left_shape, np.float64, order="F") qvp_new = np.empty(k_left_shape, np.float64, order="F") ght_new = np.empty(k_left_shape, np.float64, order="F") - + # note that p_hpa, tk, qv, and ht have the vertical flipped result = cape_routine(p_hpa, tk, @@ -658,53 +661,55 @@ def _cape(p_hpa, tk, qv, ht, ter, sfp, missing, i3dflag, ter_follow, sfp, capeview, cinview, - prsf, - prs_new, - tmk_new, - qvp_new, + prsf, + prs_new, + tmk_new, + qvp_new, ght_new, missing, ter_follow, psafile, errstat, errmsg) - + if int(errstat) != 0: raise DiagnosticError("".join(npbytes_to_str(errmsg)).strip()) - + return result -@check_args(0, 3, (3,3)) + +@check_args(0, 3, (3, 3)) @cloudfrac_left_iter() @cast_type(arg_idxs=(0, 1), outviews=("lowview", "midview", "highview")) @extract_and_transpose(outviews=("lowview", "midview", "highview")) def _cloudfrac(vert, rh, vert_inc_w_height, low_thresh, mid_thresh, - high_thresh, missing, lowview=None, midview=None, highview=None): + high_thresh, missing, lowview=None, midview=None, + highview=None): """Wrapper for dcloudfrac2. - + Located in wrf_cloud_fracf.f90. - + """ if lowview is None: lowview = np.zeros(vert.shape[0:2], vert.dtype, order="F") - + if midview is None: midview = np.zeros(vert.shape[0:2], vert.dtype, order="F") - + if highview is None: highview = np.zeros(vert.shape[0:2], vert.dtype, order="F") - - result = dcloudfrac2(vert, + + result = dcloudfrac2(vert, rh, vert_inc_w_height, low_thresh, mid_thresh, high_thresh, missing, - lowview, - midview, + lowview, + midview, highview) - + return result @@ -713,16 +718,16 @@ def _lltoxy(map_proj, truelat1, truelat2, stdlon, known_x, known_y, dx, dy, latinc, loninc, lat, lon, outview=None): """Wrapper for dlltoij. - + Located in wrf_user_latlon_routines.f90. - + """ if outview is None: outview = np.zeros((2), dtype=np.float64, order="F") - + errstat = np.array(0) errmsg = np.zeros(Constants.ERRLEN, "c") - + result = dlltoij(map_proj, truelat1, truelat2, @@ -742,27 +747,27 @@ def _lltoxy(map_proj, truelat1, truelat2, stdlon, outview, errstat, errmsg) - + if int(errstat) != 0: raise DiagnosticError("".join(npbytes_to_str(errmsg)).strip()) - + return result def _xytoll(map_proj, truelat1, truelat2, stdlon, lat1, lon1, - pole_lat, pole_lon, known_x, known_y, dx, dy, latinc, - loninc, x, y, outview=None): + pole_lat, pole_lon, known_x, known_y, dx, dy, latinc, + loninc, x, y, outview=None): """Wrapper for dijtoll. - + Located in wrf_user_latlon_routines.f90. - + """ if outview is None: outview = np.zeros((2), dtype=np.float64, order="F") - + errstat = np.array(0) errmsg = np.zeros(Constants.ERRLEN, "c") - + result = dijtoll(map_proj, truelat1, truelat2, @@ -782,29 +787,29 @@ def _xytoll(map_proj, truelat1, truelat2, stdlon, lat1, lon1, outview, errstat, errmsg) - + if int(errstat) != 0: raise DiagnosticError("".join(npbytes_to_str(errmsg)).strip()) - + return result -@check_args(0, 3, (3,3,3,3,3,3,2)) -@left_iteration(3, 2, ref_var_idx=0, ignore_args=(7,8,9,10)) -@cast_type(arg_idxs=(0,1,2,3,4,5,6)) +@check_args(0, 3, (3, 3, 3, 3, 3, 3, 2)) +@left_iteration(3, 2, ref_var_idx=0, ignore_args=(7, 8, 9, 10)) +@cast_type(arg_idxs=(0, 1, 2, 3, 4, 5, 6)) @extract_and_transpose() -def _ctt(p_hpa, tk, qice, qcld, qv, ght, ter, haveqci, fill_nocloud, +def _ctt(p_hpa, tk, qice, qcld, qv, ght, ter, haveqci, fill_nocloud, missing, opt_thresh, outview=None): """Wrapper for wrfcttcalc. - + Located in wrf_fctt.f90. - + """ if outview is None: outview = np.empty_like(ter) - + pf = np.empty(p_hpa.shape[0:3], np.float64, order="F") - + result = wrfcttcalc(p_hpa, tk, qice, @@ -814,65 +819,65 @@ def _ctt(p_hpa, tk, qice, qcld, qv, ght, ter, haveqci, fill_nocloud, ter, outview, pf, - haveqci, - fill_nocloud, + haveqci, + fill_nocloud, missing, opt_thresh) - + return result -@check_args(0, 2, (2,)) -@left_iteration(2, 2, ref_var_idx=0, ignore_args=(1,2)) -@cast_type(arg_idxs=(0,)) +@check_args(0, 2, (2, )) +@left_iteration(2, 2, ref_var_idx=0, ignore_args=(1, 2)) +@cast_type(arg_idxs=(0, )) @extract_and_transpose() def _smooth2d(field, passes, cenweight, outview=None): """Wrapper for dfilter2d. - + Located in wrf_user.f90. - + """ - # Unlike NCL, this routine will not modify the values in place, but + # Unlike NCL, this routine will not modify the values in place, but # copies the original data before modifying it. - + if isinstance(field, np.ma.MaskedArray): missing = field.fill_value else: missing = default_fill(np.float64) - + if outview is None: outview = field.copy(order="A") else: outview[:] = field[:] - - field_tmp = np.zeros(outview.shape, outview.dtype, order="F") - dfilter2d(outview, - field_tmp, + field_tmp = np.zeros(outview.shape, outview.dtype, order="F") + + dfilter2d(outview, + field_tmp, passes, missing, cenweight) - + return outview -@check_args(0, 3, (3,3,2)) -@left_iteration(3, 3, ref_var_idx=0, ignore_args=(3,4,5)) -@cast_type(arg_idxs=(0,1,2)) +@check_args(0, 3, (3, 3, 2)) +@left_iteration(3, 3, ref_var_idx=0, ignore_args=(3, 4, 5)) +@cast_type(arg_idxs=(0, 1, 2)) @extract_and_transpose() def _monotonic(var, lvprs, coriolis, idir, delta, icorsw, outview=None): """Wrapper for wrf_monotonic. - + Located in wrf_vinterp.f90. - + """ - # If icorsw is not 0, then the input variable might get modified by the + # If icorsw is not 0, then the input variable might get modified by the # fortran routine. We don't want this, so make a copy and pass that on. var = var.copy(order="A") if icorsw != 0 else var - + if outview is None: outview = np.empty_like(var) - + result = wrf_monotonic(outview, var, lvprs, @@ -880,34 +885,34 @@ def _monotonic(var, lvprs, coriolis, idir, delta, icorsw, outview=None): idir, delta, icorsw) - + return result # Output shape is interp_levels.shape + field.shape[-2:] -@check_args(0, 3, (3,3,3,3,3,2,2,2,3)) -@left_iteration(3, combine_dims([(9, (-1,)), - (0, (-2,-1))]), - ref_var_idx=0, ignore_args=(9,10,11,12,13,14)) -@cast_type(arg_idxs=(0,1,2,3,4,5,6,7,8,9)) +@check_args(0, 3, (3, 3, 3, 3, 3, 2, 2, 2, 3)) +@left_iteration(3, combine_dims([(9, (-1, )), + (0, (-2, -1))]), + ref_var_idx=0, ignore_args=(9, 10, 11, 12, 13, 14)) +@cast_type(arg_idxs=(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) @extract_and_transpose() def _vintrp(field, pres, tk, qvp, ght, terrain, sfp, smsfp, vcarray, interp_levels, icase, extrap, vcor, logp, missing, outview=None): """Wrapper for wrf_vintrp. - + Located in wrf_vinterp.f90. - + """ if outview is None: outdims = field.shape[0:2] + interp_levels.shape outview = np.empty(outdims, field.dtype, order="F") - + tempout = np.zeros(field.shape[0:2], np.float64, order="F") - + errstat = np.array(0) errmsg = np.zeros(Constants.ERRLEN, "c") - + result = wrf_vintrp(field, outview, pres, @@ -927,49 +932,50 @@ def _vintrp(field, pres, tk, qvp, ght, terrain, sfp, smsfp, missing, errstat, errmsg) - + if int(errstat) != 0: raise DiagnosticError("".join(npbytes_to_str(errmsg)).strip()) - + return result -@check_args(0, 2, (2,2)) + +@check_args(0, 2, (2, 2)) @left_iteration(2, 2, ref_var_idx=0) -@cast_type(arg_idxs=(0,1)) +@cast_type(arg_idxs=(0, 1)) @extract_and_transpose() def _wspd(u, v, outview=None): """Wrapper for dcomputewspd. - + Located in wrf_wind.f90. - + """ if outview is None: outview = np.empty_like(u) - + result = dcomputewspd(outview, u, v) - + return result -@check_args(0, 2, (2,2)) +@check_args(0, 2, (2, 2)) @left_iteration(2, 2, ref_var_idx=0) -@cast_type(arg_idxs=(0,1)) +@cast_type(arg_idxs=(0, 1)) @extract_and_transpose() def _wdir(u, v, outview=None): """Wrapper for dcomputewdir. - + Located in wrf_wind.f90. - + """ if outview is None: outview = np.empty_like(u) - + result = dcomputewdir(outview, u, v) - + return result @@ -977,47 +983,47 @@ def _wdir(u, v, outview=None): def omp_set_num_threads(num_threads): """Specify the number of threads to use. - - The omp_set_num_threads routine affects the number of threads to be used - for subsequent parallel regions that do not specify a num_threads - clause, by setting the value of the first element of the nthreads-var + + The omp_set_num_threads routine affects the number of threads to be used + for subsequent parallel regions that do not specify a num_threads + clause, by setting the value of the first element of the nthreads-var ICV of the current task. - + Args: - - num_threads (a positive :obj:`int`): The number of threads. Must be + + num_threads (a positive :obj:`int`): The number of threads. Must be positive. - + Returns: - + None. - + """ if num_threads < 0 and fomp_enabled(): raise ValueError("'num_threads' must be a positive integer.") - + fomp_set_num_threads(num_threads) def omp_get_num_threads(): """Return the number of threads in the current team. - - The omp_get_num_threads routine returns the number of threads in the - team executing the parallel region to which the routine region binds. + + The omp_get_num_threads routine returns the number of threads in the + team executing the parallel region to which the routine region binds. If called from the sequential part of a program, this routine returns 1. - + Note: - + This function always returns 1 when called from within Python. - + Returns: - + :obj:`int`: The number of threads in the current team. - + See Also: - + :meth:`wrf.omp_get_max_threads`, :meth:`wrf.omp_set_num_threads` - + """ return fomp_get_num_threads() @@ -1025,20 +1031,20 @@ def omp_get_num_threads(): def omp_get_max_threads(): """Return the maximum number of threads that can be used in a parallel \ region. - - The omp_get_max_threads routine returns an upper bound on the number of - threads that could be used to form a new team if a parallel construct - without a num_threads clause were encountered after execution returns from + + The omp_get_max_threads routine returns an upper bound on the number of + threads that could be used to form a new team if a parallel construct + without a num_threads clause were encountered after execution returns from this routine. - + Returns: - + :obj:`int`: The number of threads in the current team. - + See Also: - + :meth:`wrf.omp_set_num_threads` - + """ return fomp_get_max_threads() @@ -1046,43 +1052,43 @@ def omp_get_max_threads(): def omp_get_thread_num(): """Return the thread number, within the current team, of the \ calling thread. - - The omp_get_thread_num routine returns the thread number of the calling - thread, within the team executing the parallel region to which the routine - region binds. The thread number is an integer between 0 and one less than - the value returned by omp_get_num_threads, inclusive. The thread number of - the master thread of the team is 0. The routine returns 0 if it is called + + The omp_get_thread_num routine returns the thread number of the calling + thread, within the team executing the parallel region to which the routine + region binds. The thread number is an integer between 0 and one less than + the value returned by omp_get_num_threads, inclusive. The thread number of + the master thread of the team is 0. The routine returns 0 if it is called from the sequential part of a program. - + Note: - + This function always returns 0 when called from within Python. - + Returns: - + :obj:`int`: The thread number. - + See Also: - + :meth:`wrf.omp_get_num_procs` - + """ return fomp_get_thread_num() - - + + def omp_get_num_procs(): """Return the number of processors on the device. - - The omp_get_num_procs routine returns the number of processors that are - available to the device at the time the routine is called. This value may - change between the time that it is determined by the omp_get_num_procs - routine and the time that it is read in the calling context due to system + + The omp_get_num_procs routine returns the number of processors that are + available to the device at the time the routine is called. This value may + change between the time that it is determined by the omp_get_num_procs + routine and the time that it is read in the calling context due to system actions outside the control of the OpenMP implementation. - + Returns: - + :obj:`int`: The number of processors. - + """ return fomp_get_num_procs() @@ -1090,21 +1096,21 @@ def omp_get_num_procs(): def omp_in_parallel(): """Return 1 if the active-levels-var ICV is greater than zero; \ otherwise, return 0. - - The effect of the omp_in_parallel routine is to return 1 if the current - task is enclosed by an active parallel region, and the parallel region is - enclosed by the outermost initial task region on the device; otherwise it + + The effect of the omp_in_parallel routine is to return 1 if the current + task is enclosed by an active parallel region, and the parallel region is + enclosed by the outermost initial task region on the device; otherwise it returns 0. - + Note: - + This function always returns 0 when called from within Python. - + Returns: - - :obj:`int`: Returns 1 if the active-levels-var ICV is greater than + + :obj:`int`: Returns 1 if the active-levels-var ICV is greater than zero. Otherwise, it returns 0. - + """ return fomp_in_parallel() @@ -1113,27 +1119,27 @@ def omp_set_dynamic(dynamic_threads): """Enable or disable dynamic adjustment of the number of threads \ available for the execution of subsequent parallel regions by setting the \ value of the dyn-var ICV. - - For implementations that support dynamic adjustment of the number of - threads, if the argument to omp_set_dynamic evaluates to True, dynamic - adjustment is enabled for the current task; otherwise, dynamic adjustment - is disabled for the current task. For implementations that do not support - dynamic adjustment of the number of threads this routine has no effect: + + For implementations that support dynamic adjustment of the number of + threads, if the argument to omp_set_dynamic evaluates to True, dynamic + adjustment is enabled for the current task; otherwise, dynamic adjustment + is disabled for the current task. For implementations that do not support + dynamic adjustment of the number of threads this routine has no effect: the value of dyn-var remains false. - + Args: - - dynamic_threads (:obj:`bool`): Set to True to support the dynamic + + dynamic_threads (:obj:`bool`): Set to True to support the dynamic adjustment of the number of threads. Otherwise, set to False. - + Returns: - + None. - + See Also: - + :meth:`wrf.omp_get_dynamic` - + """ fomp_set_dynamic(dynamic_threads) @@ -1141,47 +1147,47 @@ def omp_set_dynamic(dynamic_threads): def omp_get_dynamic(): """Return the value of the dyn-var ICV, which determines whether \ dynamic adjustment of the number of threads is enabled or disabled. - - This routine returns 1 if dynamic adjustment of the number of threads - is enabled for the current task; it returns 0, otherwise. If an - implementation does not support dynamic adjustment of the + + This routine returns 1 if dynamic adjustment of the number of threads + is enabled for the current task; it returns 0, otherwise. If an + implementation does not support dynamic adjustment of the number of threads, then this routine always returns 0. - + Returns: - - :obj:`int`: Returns 1 if dynamic thread adjustment is enabled, 0 + + :obj:`int`: Returns 1 if dynamic thread adjustment is enabled, 0 if disabled. - + See Also: - + :meth:`wrf.omp_set_dynamic` - + """ return fomp_get_dynamic() def omp_set_nested(nested): """Enable or disable nested parallelism, by setting the nest-var ICV - - For implementations that support nested parallelism, if the argument to - omp_set_nested evaluates to True, nested parallelism is enabled for the - current task; otherwise, nested parallelism is disabled for the current - task. For implementations that do not support nested parallelism, this + + For implementations that support nested parallelism, if the argument to + omp_set_nested evaluates to True, nested parallelism is enabled for the + current task; otherwise, nested parallelism is disabled for the current + task. For implementations that do not support nested parallelism, this routine has no effect: the value of nest-var remains False. - + Args: - - dynamic_threads (:obj:`bool`): Set to True to support nested + + dynamic_threads (:obj:`bool`): Set to True to support nested parallelism, otherwise False. - + Returns: - + None - + See Also: - + :meth:`wrf.omp_get_nested` - + """ fomp_set_nested(nested) @@ -1189,19 +1195,19 @@ def omp_set_nested(nested): def omp_get_nested(): """Return the value of the nest-var ICV, which determines if nested \ parallelism is enabled or disabled - - This routine returns 1 if nested parallelism is enabled for the current - task; it returns 0, otherwise. If an implementation does not support + + This routine returns 1 if nested parallelism is enabled for the current + task; it returns 0, otherwise. If an implementation does not support nested parallelism, this routine always returns 0. - + Returns: - + :obj:`int`: Returns 1 if nested parallelism is enabled, otherwise 0. - + See Also: - + :meth:`wrf.omp_set_nested` - + """ return fomp_get_nested() @@ -1209,80 +1215,80 @@ def omp_get_nested(): def omp_set_schedule(kind, modifier=0): """Set the schedule that is applied when *runtime* is used as \ schedule kind, by setting the value of the run-sched-var ICV. - - The effect of this routine is to set the value of the run-sched-var ICV - of the current task to the values specified in the two arguments. The - schedule is set to the schedule type specified by the first argument kind. - It can be any of the standard schedule types or any other implementation - specific one. For the schedule types static, dynamic, and guided the - chunk_size is set to the value of the second argument, or to the default - chunk_size if the value of the second argument is less than 1; for the - schedule type auto the second argument has no meaning; for implementation - specific schedule types, the values and associated meanings of the second + + The effect of this routine is to set the value of the run-sched-var ICV + of the current task to the values specified in the two arguments. The + schedule is set to the schedule type specified by the first argument kind. + It can be any of the standard schedule types or any other implementation + specific one. For the schedule types static, dynamic, and guided the + chunk_size is set to the value of the second argument, or to the default + chunk_size if the value of the second argument is less than 1; for the + schedule type auto the second argument has no meaning; for implementation + specific schedule types, the values and associated meanings of the second argument are implementation defined. - + Args: - + kind (:obj:`int`): Must be :data:`wrf.OMP_SCHED_STATIC`, - :data:`wrf.OMP_SCHED_DYNAMIC`, :data:`wrf.OMP_SCHED_GUIDED`, + :data:`wrf.OMP_SCHED_DYNAMIC`, :data:`wrf.OMP_SCHED_GUIDED`, or :data:`wrf.OMP_SCHED_AUTO`. - - modifier(:obj:`int`): An implementation specific value, depending on - the choice for *kind*. This parameter is alternatively named - chunk_size in some OpenMP documentation. Default is 0, which + + modifier(:obj:`int`): An implementation specific value, depending on + the choice for *kind*. This parameter is alternatively named + chunk_size in some OpenMP documentation. Default is 0, which means the OpenMP implementation will use its default value. - + Returns: - + None - + See Also: - + :meth:`wrf.omp_get_schedule` - + """ - fomp_set_schedule(kind, modifier) + fomp_set_schedule(kind, modifier) def omp_get_schedule(): """Return the schedule that is applied when the runtime schedule is used. - - This routine returns the run-sched-var ICV in the task to which the routine - binds. The first item is the schedule kind, which will be one of - :data:`wrf.OMP_SCHED_STATIC`, :data:`wrf.OMP_SCHED_DYNAMIC`, - :data:`wrf.OMP_SCHED_GUIDED`, or :data:`wrf.OMP_SCHED_AUTO`. The second - item returned is the modifier, which is often named chunk_size in + + This routine returns the run-sched-var ICV in the task to which the routine + binds. The first item is the schedule kind, which will be one of + :data:`wrf.OMP_SCHED_STATIC`, :data:`wrf.OMP_SCHED_DYNAMIC`, + :data:`wrf.OMP_SCHED_GUIDED`, or :data:`wrf.OMP_SCHED_AUTO`. The second + item returned is the modifier, which is often named chunk_size in OpenMP documentation. - + Returns: - + :obj:`tuple`: The first item is an :obj:`int` for the schedule *kind*. The second items is :obj:`int` for the *modifier* (chunk_size). - + See Also: - + :meth:`wrf.omp_set_schedule` - + """ return fomp_get_schedule() -def omp_get_thread_limit(): +def omp_get_thread_limit(): """Return the maximum number of OpenMP threads available to participate \ in the current contention group. - - The omp_get_thread_limit routine returns the value of the thread-limit-var + + The omp_get_thread_limit routine returns the value of the thread-limit-var ICV. - + Returns: - - :obj:`int`: The number of OpenMP threads available to participate in + + :obj:`int`: The number of OpenMP threads available to participate in the current contention group. - + See Also: - + :meth:`wrf.omp_get_max_threads` - + """ return fomp_get_thread_limit() @@ -1290,96 +1296,96 @@ def omp_get_thread_limit(): def omp_set_max_active_levels(max_levels): """Limit the number of nested active parallel regions on the device, \ by setting the max-active-levels-var ICV. - - The effect of this routine is to set the value of the max-active-levels-var - ICV to the value specified in the argument. If the number of parallel - levels requested exceeds the number of levels of parallelism supported by - the implementation, the value of the max-active-levels-var ICV will be set - to the number of parallel levels supported by the implementation. This - routine has the described effect only when called from a sequential part - of the program. When called from within an explicit parallel region, the + + The effect of this routine is to set the value of the max-active-levels-var + ICV to the value specified in the argument. If the number of parallel + levels requested exceeds the number of levels of parallelism supported by + the implementation, the value of the max-active-levels-var ICV will be set + to the number of parallel levels supported by the implementation. This + routine has the described effect only when called from a sequential part + of the program. When called from within an explicit parallel region, the effect of this routine is implementation defined. - + Args: - + max_levels (:obj:`int`): The maximum number of nested active parallel regions. - + Returns: - + None. - + See Also: - + :meth:`wrf.omp_get_max_active_levels` - + """ - fomp_set_max_active_levels(max_levels) + fomp_set_max_active_levels(max_levels) def omp_get_max_active_levels(): """Return the value of the max-active-levels-var ICV, which determines \ the maximum number of nested active parallel regions on the device - - The omp_get_max_active_levels routine returns the value of the - max-active-levels-var ICV, which determines the maximum number of nested + + The omp_get_max_active_levels routine returns the value of the + max-active-levels-var ICV, which determines the maximum number of nested active parallel regions on the device. - + Returns: - + :obj:`int`: The maximum number of nested active parallel regions. - + See Also: - + :meth:`wrf.omp_set_max_active_levels` - + """ return fomp_get_max_active_levels() def omp_get_level(): """Return the value of the levels-var ICV. - - The effect of the omp_get_level routine is to return the number of nested - parallel regions (whether active or inactive) enclosing the current task - such that all of the parallel regions are enclosed by the outermost initial + + The effect of the omp_get_level routine is to return the number of nested + parallel regions (whether active or inactive) enclosing the current task + such that all of the parallel regions are enclosed by the outermost initial task region on the current device. - + Returns: - + :obj:`int`: The number of nested parallel regions. - + See Also: - + :meth:`wrf.omp_get_active_level` - + """ return fomp_get_level() - - + + def omp_get_ancestor_thread_num(level): """Return, for a given nested level of the current thread, the thread \ number of the ancestor of the current thread. - - The omp_get_ancestor_thread_num routine returns the thread number of the - ancestor at a given nest level of the current thread or the thread number - of the current thread. If the requested nest level is outside the range of - 0 and the nest level of the current thread, as returned by the + + The omp_get_ancestor_thread_num routine returns the thread number of the + ancestor at a given nest level of the current thread or the thread number + of the current thread. If the requested nest level is outside the range of + 0 and the nest level of the current thread, as returned by the omp_get_level routine, the routine returns -1. - + Args: - + level (:obj:`int`): The nested level of the current thread. - + Returns: - - :obj:`int`: The thread number of the ancestor at a given nest level + + :obj:`int`: The thread number of the ancestor at a given nest level of the current thread. - + See Also: - + :meth:`wrf.omp_get_max_active_levels`, :meth:`wrf.omp_get_level` - + """ return fomp_get_ancestor_thread_num(level) @@ -1387,270 +1393,267 @@ def omp_get_ancestor_thread_num(level): def omp_get_team_size(level): """Return, for a given nested level of the current thread, the size \ of the thread team to which the ancestor or the current thread belongs - - The omp_get_team_size routine returns the size of the thread team to which - the ancestor or the current thread belongs. If the requested nested level - is outside the range of 0 and the nested level of the current thread, as - returned by the omp_get_level routine, the routine returns -1. Inactive - parallel regions are regarded like active parallel regions executed with + + The omp_get_team_size routine returns the size of the thread team to which + the ancestor or the current thread belongs. If the requested nested level + is outside the range of 0 and the nested level of the current thread, as + returned by the omp_get_level routine, the routine returns -1. Inactive + parallel regions are regarded like active parallel regions executed with one thread. - + Args: - + level (:obj:`int`): The nested level of the current thread. - + Returns: - + :obj:`int`: The size of the thread team. - + See Also: - + :meth:`wrf.omp_get_ancestor_thread_num` - + """ return fomp_get_team_size(level) def omp_get_active_level(): """Return the value of the active-level-vars ICV. - - The effect of the omp_get_active_level routine is to return the number of - nested, active parallel regions enclosing the current task such that all - of the parallel regions are enclosed by the outermost initial task region + + The effect of the omp_get_active_level routine is to return the number of + nested, active parallel regions enclosing the current task such that all + of the parallel regions are enclosed by the outermost initial task region on the current device. - + Returns: - + :obj:`int`: The number of nested activate parallel regions. - + See Also: - + :meth:`wrf.omp_get_team_size` - + """ - return fomp_get_active_level() + return fomp_get_active_level() def omp_in_final(): """Return 1 (True) if the routine is executed in a final task region; \ otherwise, it returns 0 (False). - + Returns: - - :obj:`int`: Return 1 if the routine is executed in a final task + + :obj:`int`: Return 1 if the routine is executed in a final task region, 0 otherwise. - + """ return fomp_in_final() def omp_init_lock(): """Initialize a simple OpenMP lock. - + Returns: - + :obj:`int`: An integer representing the lock. - + See Also: - + :meth:`wrf.omp_init_nest_lock`, :meth:`wrf.omp_destroy_lock` - + """ return fomp_init_lock() def omp_init_nest_lock(): """Initialize a nestable OpenMP lock. - + Returns: - + :obj:`int`: An integer representing the nestable lock. - + See Also: - + :meth:`wrf.omp_init_lock` - + """ return fomp_init_nest_lock() def omp_destroy_lock(svar): """Destroy a simple OpenMP lock. - + This sets the lock to an uninitialized state. - + Args: - + svar (:obj:`int`): An integer representing the lock. - + See Also: - + :meth:`wrf.omp_destroy_nest_lock`, :meth:`wrf.omp_init_lock` - + """ fomp_destroy_lock(svar) def omp_destroy_nest_lock(nvar): """Destroy a nestable OpenMP lock. - + This sets the lock to an uninitialized state. - + Args: - + nvar (:obj:`int`): An integer representing the nestable lock. - + See Also: - + :meth:`wrf.omp_destroy_lock`, :meth:`wrf.omp_init_nest_lock` - + """ fomp_destroy_nest_lock(nvar) def omp_set_lock(svar): """Set a simple OpenMP lock. - + Args: - + svar (:obj:`int`): An integer representing the lock. - + See Also: - + :meth:`wrf.omp_unset_lock`, :meth:`wrf.omp_set_nest_lock` - + """ fomp_set_lock(svar) def omp_set_nest_lock(nvar): """Set a nestable OpenMP lock. - + Args: - + nvar (:obj:`int`): An integer representing the nestable lock. - + See Also: - + :meth:`wrf.omp_unset_nest_lock`, :meth:`wrf.omp_set_lock` - + """ fomp_set_nest_lock(nvar) def omp_unset_lock(svar): """Unset a simple OpenMP lock. - + Args: - + svar (:obj:`int`): An integer representing the simple lock. - + See Also: - + :meth:`wrf.omp_unset_nest_lock`, :meth:`wrf.omp_set_lock` - + """ fomp_unset_lock(svar) def omp_unset_nest_lock(nvar): """Unset a nestable OpenMP lock. - + Args: - + nvar (:obj:`int`): An integer representing the nestable lock. - + See Also: - + :meth:`wrf.omp_set_nest_lock`, :meth:`wrf.omp_unset_lock` - + """ fomp_unset_nest_lock(nvar) - + def omp_test_lock(svar): """Test a simple OpenMP lock. - + This method attempts to set the lock, but does not suspend execution. - + Args: - + svar (:obj:`int`): An integer representing the simple lock. - + Returns: - - :obj:`int`: Returns 1 (True) if the lock is successfully set, + + :obj:`int`: Returns 1 (True) if the lock is successfully set, otherwise 0 (False). - + See Also: - + :meth:`wrf.test_nest_lock`, :meth:`wrf.omp_set_lock` - + """ return fomp_test_lock(svar) def omp_test_nest_lock(nvar): """Test a nestable OpenMP lock. - + This method attempts to set the lock, but does not suspend execution. - + Args: - + nvar (:obj:`int`): An integer representing the simple lock. - + Returns: - - :obj:`int`: Returns the nesting count if successful, + + :obj:`int`: Returns the nesting count if successful, otherwise 0 (False). - + See Also: - + :meth:`wrf.test_lock`, :meth:`wrf.omp_set_nest_lock` - + """ return fomp_test_nest_lock(nvar) def omp_get_wtime(): """Return elapsed wall clock time in seconds. - - The omp_get_wtime routine returns a value equal to the elapsed wall clock - time in seconds since some "time in the past". The actual - "time in the past" is arbitrary, but it is guaranteed not to change during - the execution of the application program. The time returned is a - "per-thread time", so it is not required to be globally consistent across + + The omp_get_wtime routine returns a value equal to the elapsed wall clock + time in seconds since some "time in the past". The actual + "time in the past" is arbitrary, but it is guaranteed not to change during + the execution of the application program. The time returned is a + "per-thread time", so it is not required to be globally consistent across all threads participating in an application. - + Returns: - + :obj:`float`: Returns the wall clock time in seconds. - + See Also: - + :meth:`wrf.omp_get_wtick` - + """ return fomp_get_wtime() def omp_get_wtick(): """Return the precision of the timer used by :meth:`wrf.omp_get_wtime`. - - The omp_get_wtick routine returns a value equal to the number of - seconds between successive clock ticks of the timer used by + + The omp_get_wtick routine returns a value equal to the number of + seconds between successive clock ticks of the timer used by :meth:`wrf.omp_get_wtime`. - + Returns: - + :obj:`float`: Returns the precision of the timer. - + See Also: - + :meth:`wrf.omp_get_wtime` - + """ return fomp_get_wtick() - - - diff --git a/src/wrf/g_cape.py b/src/wrf/g_cape.py index d2ce0e7..e2f48c7 100755 --- a/src/wrf/g_cape.py +++ b/src/wrf/g_cape.py @@ -9,78 +9,79 @@ from .constants import default_fill, Constants, ConversionFactors from .util import extract_vars from .metadecorators import set_cape_metadata + @set_cape_metadata(is2d=True) -def get_2dcape(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, +def get_2dcape(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, missing=default_fill(np.float64)): """Return the two-dimensional fields of MCAPE, MCIN, LCL, and LFC. - - The leftmost dimension of the returned array represents four different + + The leftmost dimension of the returned array represents four different quantities: - + - return_val[0,...] will contain MCAPE [J kg-1] - return_val[1,...] will contain MCIN [J kg-1] - return_val[2,...] will contain LCL [m] - return_val[3,...] will contain LFC [m] - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - missing (:obj:`float`): The fill value to use for the output. + + missing (:obj:`float`): The fill value to use for the output. Default is :data:`wrf.default_fill(np.float64)`. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - cape, cin, lcl, and lfc values as an array whose - leftmost dimension is 4 (0=CAPE, 1=CIN, 2=LCL, 3=LFC). - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + cape, cin, lcl, and lfc values as an array whose + leftmost dimension is 4 (0=CAPE, 1=CIN, 2=LCL, 3=LFC). + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - varnames = ("T", "P", "PB", "QVAPOR", "PH","PHB", "HGT", "PSFC") + varnames = ("T", "P", "PB", "QVAPOR", "PH", "PHB", "HGT", "PSFC") ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, meta=False, _key=_key) - + t = ncvars["T"] p = ncvars["P"] pb = ncvars["PB"] @@ -89,107 +90,107 @@ def get_2dcape(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, phb = ncvars["PHB"] ter = ncvars["HGT"] psfc = ncvars["PSFC"] - + full_t = t + Constants.T_BASE full_p = p + pb tk = _tk(full_p, full_t) - + geopt = ph + phb geopt_unstag = destagger(geopt, -3) z = geopt_unstag/Constants.G - + # Convert pressure to hPa p_hpa = ConversionFactors.PA_TO_HPA * full_p - psfc_hpa = ConversionFactors.PA_TO_HPA * psfc - + psfc_hpa = ConversionFactors.PA_TO_HPA * psfc + i3dflag = 0 ter_follow = 1 - - cape_cin = _cape(p_hpa, tk, qv, z, ter, psfc_hpa, missing, i3dflag, + + cape_cin = _cape(p_hpa, tk, qv, z, ter, psfc_hpa, missing, i3dflag, ter_follow) - + left_dims = cape_cin.shape[1:-3] right_dims = cape_cin.shape[-2:] - + resdim = (4,) + left_dims + right_dims - + # Make a new output array for the result result = np.zeros(resdim, cape_cin.dtype) - - # Cape 2D output is not flipped in the vertical, so index from the + + # Cape 2D output is not flipped in the vertical, so index from the # end - result[0,...,:,:] = cape_cin[0,...,-1,:,:] - result[1,...,:,:] = cape_cin[1,...,-1,:,:] - result[2,...,:,:] = cape_cin[1,...,-2,:,:] - result[3,...,:,:] = cape_cin[1,...,-3,:,:] - + result[0, ..., :, :] = cape_cin[0, ..., -1, :, :] + result[1, ..., :, :] = cape_cin[1, ..., -1, :, :] + result[2, ..., :, :] = cape_cin[1, ..., -2, :, :] + result[3, ..., :, :] = cape_cin[1, ..., -3, :, :] + return ma.masked_values(result, missing) @set_cape_metadata(is2d=False) -def get_3dcape(wrfin, timeidx=0, method="cat", +def get_3dcape(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, missing=default_fill(np.float64)): """Return the three-dimensional CAPE and CIN. - - The leftmost dimension of the returned array represents two different + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain CAPE [J kg-1] - return_val[1,...] will contain CIN [J kg-1] - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - missing (:obj:`float`): The fill value to use for the output. + + missing (:obj:`float`): The fill value to use for the output. Default is :data:`wrf.default_fill(np.float64)`. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - CAPE and CIN as an array whose leftmost dimension is 2 (0=CAPE, 1=CIN). - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + CAPE and CIN as an array whose leftmost dimension is 2 (0=CAPE, 1=CIN). + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ varnames = ("T", "P", "PB", "QVAPOR", "PH", "PHB", "HGT", "PSFC") ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, @@ -202,433 +203,429 @@ def get_3dcape(wrfin, timeidx=0, method="cat", phb = ncvars["PHB"] ter = ncvars["HGT"] psfc = ncvars["PSFC"] - + full_t = t + Constants.T_BASE full_p = p + pb tk = _tk(full_p, full_t) - + geopt = ph + phb geopt_unstag = destagger(geopt, -3) z = geopt_unstag/Constants.G - + # Convert pressure to hPa p_hpa = ConversionFactors.PA_TO_HPA * full_p - psfc_hpa = ConversionFactors.PA_TO_HPA * psfc - + psfc_hpa = ConversionFactors.PA_TO_HPA * psfc + i3dflag = 1 ter_follow = 1 - - cape_cin = _cape(p_hpa, tk, qv, z, ter, psfc_hpa, missing, i3dflag, + + cape_cin = _cape(p_hpa, tk, qv, z, ter, psfc_hpa, missing, i3dflag, ter_follow) - - + return ma.masked_values(cape_cin, missing) -def get_cape2d_only(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, - meta=True, _key=None, missing=default_fill(np.float64)): - """Return the two-dimensional field of MCAPE (Max Convective Available +def get_cape2d_only(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, + meta=True, _key=None, missing=default_fill(np.float64)): + """Return the two-dimensional field of MCAPE (Max Convective Available Potential Energy). - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - missing (:obj:`float`): The fill value to use for the output. + + missing (:obj:`float`): The fill value to use for the output. Default is :data:`wrf.default_fill(np.float64)`. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - 2D MCAPE field. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + 2D MCAPE field. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - result = get_2dcape(wrfin, timeidx, method, squeeze, cache, - meta, _key, missing)[0,:] - + result = get_2dcape(wrfin, timeidx, method, squeeze, cache, + meta, _key, missing)[0, :] + if meta: result.attrs["description"] = "mcape" result.attrs["units"] = "J kg-1" - + return result - - -def get_cin2d_only(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, - meta=True, _key=None, missing=default_fill(np.float64)): + + +def get_cin2d_only(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, + meta=True, _key=None, missing=default_fill(np.float64)): """Return the two-dimensional field of MCIN (Max Convective Inhibition). - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - missing (:obj:`float`): The fill value to use for the output. + + missing (:obj:`float`): The fill value to use for the output. Default is :data:`wrf.default_fill(np.float64)`. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - 2D MCIN field. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + 2D MCIN field. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - result = get_2dcape(wrfin, timeidx, method, squeeze, cache, - meta, _key, missing)[1,:] - + result = get_2dcape(wrfin, timeidx, method, squeeze, cache, + meta, _key, missing)[1, :] + if meta: result.attrs["description"] = "mcin" result.attrs["units"] = "J kg-1" - + return result - -def get_lcl(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, - meta=True, _key=None, missing=default_fill(np.float64)): + +def get_lcl(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, + meta=True, _key=None, missing=default_fill(np.float64)): """Return the two-dimensional field of LCL (Lifted Condensation Level). - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - missing (:obj:`float`): The fill value to use for the output. + + missing (:obj:`float`): The fill value to use for the output. Default is :data:`wrf.default_fill(np.float64)`. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - 2D LCL field. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + 2D LCL field. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - result = get_2dcape(wrfin, timeidx, method, squeeze, cache, - meta, _key, missing)[2,:] - + result = get_2dcape(wrfin, timeidx, method, squeeze, cache, + meta, _key, missing)[2, :] + if meta: result.attrs["description"] = "lcl" result.attrs["units"] = "m" - + return result - - -def get_lfc(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, - meta=True, _key=None, missing=default_fill(np.float64)): + + +def get_lfc(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, + meta=True, _key=None, missing=default_fill(np.float64)): """Return the two-dimensional field of LFC (Level of Free Convection). - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - missing (:obj:`float`): The fill value to use for the output. + + missing (:obj:`float`): The fill value to use for the output. Default is :data:`wrf.default_fill(np.float64)`. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - 2D LFC field. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + 2D LFC field. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - result = get_2dcape(wrfin, timeidx, method, squeeze, cache, - meta, _key, missing)[3,:] - + result = get_2dcape(wrfin, timeidx, method, squeeze, cache, + meta, _key, missing)[3, :] + if meta: result.attrs["description"] = "lfc" result.attrs["units"] = "m" - + return result - -def get_3dcape_only(wrfin, timeidx=0, method="cat", - squeeze=True, cache=None, meta=True, - _key=None, missing=default_fill(np.float64)): - """Return the three-dimensional field of CAPE (Convective Available + +def get_3dcape_only(wrfin, timeidx=0, method="cat", + squeeze=True, cache=None, meta=True, + _key=None, missing=default_fill(np.float64)): + """Return the three-dimensional field of CAPE (Convective Available Potential Energy). - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - missing (:obj:`float`): The fill value to use for the output. + + missing (:obj:`float`): The fill value to use for the output. Default is :data:`wrf.default_fill(np.float64)`. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - 3D CAPE field. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + 3D CAPE field. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ result = get_3dcape(wrfin, timeidx, method, squeeze, cache, meta, - _key, missing)[0,:] - + _key, missing)[0, :] + if meta: result.attrs["description"] = "cape" result.attrs["units"] = "J kg-1" - + return result - - -def get_3dcin_only(wrfin, timeidx=0, method="cat", - squeeze=True, cache=None, meta=True, - _key=None, missing=default_fill(np.float64)): + + +def get_3dcin_only(wrfin, timeidx=0, method="cat", + squeeze=True, cache=None, meta=True, + _key=None, missing=default_fill(np.float64)): """Return the three-dimensional field of CIN (Convective Inhibition). - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - missing (:obj:`float`): The fill value to use for the output. + + missing (:obj:`float`): The fill value to use for the output. Default is :data:`wrf.default_fill(np.float64)`. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - 3D CIN field. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + 3D CIN field. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ result = get_3dcape(wrfin, timeidx, method, squeeze, cache, meta, - _key, missing)[1,:] - + _key, missing)[1, :] + if meta: result.attrs["description"] = "cin" result.attrs["units"] = "J kg-1" - + return result - - - \ No newline at end of file diff --git a/src/wrf/g_cloudfrac.py b/src/wrf/g_cloudfrac.py index 49af329..c585b0f 100644 --- a/src/wrf/g_cloudfrac.py +++ b/src/wrf/g_cloudfrac.py @@ -11,142 +11,142 @@ from .g_geoht import _get_geoht @set_cloudfrac_metadata() -def get_cloudfrac(wrfin, timeidx=0, method="cat", squeeze=True, - cache=None, meta=True, _key=None, - vert_type="height_agl", low_thresh=None, mid_thresh=None, - high_thresh=None, missing=default_fill(np.float64)): +def get_cloudfrac(wrfin, timeidx=0, method="cat", squeeze=True, + cache=None, meta=True, _key=None, + vert_type="height_agl", low_thresh=None, mid_thresh=None, + high_thresh=None, missing=default_fill(np.float64)): """Return the cloud fraction for low, mid, and high level clouds. - - The leftmost dimension of the returned array represents three different + + The leftmost dimension of the returned array represents three different quantities: - + - return_val[0,...] will contain LOW level cloud fraction - return_val[1,...] will contain MID level cloud fraction - return_val[2,...] will contain HIGH level cloud fraction - - If the vertical coordinate type is 'height_agl' or 'height_msl', the + + If the vertical coordinate type is 'height_agl' or 'height_msl', the default cloud levels are defined as: - + 300 m <= low_cloud < 2000 m 2000 m <= mid_cloud < 6000 m 6000 m <= high_cloud - - For 'pressure', the default cloud levels are defined as: - + + For 'pressure', the default cloud levels are defined as: + 97000 Pa <= low_cloud < 80000 Pa 80000 Pa <= mid_cloud < 45000 Pa 45000 Pa <= high_cloud - + Note that the default low cloud levels are chosen to - exclude clouds near the surface (fog). If you want fog included, set - *low_thresh* to ~99500 Pa if *vert_type* is set to 'pressure', or 15 m if - using 'height_msl' or 'height_agl'. Keep in mind that the lowest mass grid - points are slightly above the ground, and in order to find clouds, the - *low_thresh* needs to be set to values that are slightly greater than + exclude clouds near the surface (fog). If you want fog included, set + *low_thresh* to ~99500 Pa if *vert_type* is set to 'pressure', or 15 m if + using 'height_msl' or 'height_agl'. Keep in mind that the lowest mass grid + points are slightly above the ground, and in order to find clouds, the + *low_thresh* needs to be set to values that are slightly greater than (less than) the lowest height (pressure) values. - - When using 'pressure' or 'height_agl' for *vert_type*, there is a - possibility that the lowest WRF level will be higher than the low_cloud or - mid_cloud threshold, particularly for mountainous regions. When this + + When using 'pressure' or 'height_agl' for *vert_type*, there is a + possibility that the lowest WRF level will be higher than the low_cloud or + mid_cloud threshold, particularly for mountainous regions. When this happens, a fill value will be used in the output. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - vert_type (:obj:`str`, optional): The type of vertical coordinate used - to determine cloud type thresholds. Must be 'height_agl', + + vert_type (:obj:`str`, optional): The type of vertical coordinate used + to determine cloud type thresholds. Must be 'height_agl', 'height_msl', or 'pres'. The default is 'height_agl'. - - low_thresh (:obj:`float`, optional): The lower bound for what is - considered a low cloud. If *vert_type* is 'pres', the default is - 97000 Pa. If *vert_type* is 'height_agl' or 'height_msl', then the - default is 300 m. - - mid_thresh (:obj:`float`, optional): The lower bound for what is - considered a mid level cloud. If *vert_type* is 'pres', the - default is 80000 Pa. If *vert_type* is 'height_agl' or - 'height_msl', then the default is 2000 m. - - high_thresh (:obj:`float`, optional): The lower bound for what is - considered a high level cloud. If *vert_type* is 'pres', the - default is 45000 Pa. If *vert_type* is 'height_agl' or - 'height_msl', then the default is 6000 m. - + + low_thresh (:obj:`float`, optional): The lower bound for what is + considered a low cloud. If *vert_type* is 'pres', the default is + 97000 Pa. If *vert_type* is 'height_agl' or 'height_msl', then the + default is 300 m. + + mid_thresh (:obj:`float`, optional): The lower bound for what is + considered a mid level cloud. If *vert_type* is 'pres', the + default is 80000 Pa. If *vert_type* is 'height_agl' or + 'height_msl', then the default is 2000 m. + + high_thresh (:obj:`float`, optional): The lower bound for what is + considered a high level cloud. If *vert_type* is 'pres', the + default is 45000 Pa. If *vert_type* is 'height_agl' or + 'height_msl', then the default is 6000 m. + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - cloud fraction array whose leftmost dimension is 3 (LOW=0, MID=1, - HIGH=2). - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + cloud fraction array whose leftmost dimension is 3 (LOW=0, MID=1, + HIGH=2). + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - - ncvars = extract_vars(wrfin, timeidx, ("P", "PB", "QVAPOR", "T"), + + ncvars = extract_vars(wrfin, timeidx, ("P", "PB", "QVAPOR", "T"), method, squeeze, cache, meta=False, _key=_key) - + p = ncvars["P"] pb = ncvars["PB"] qv = ncvars["QVAPOR"] t = ncvars["T"] - + full_p = p + pb full_t = t + Constants.T_BASE - + tk = _tk(full_p, full_t) rh = _rh(qv, full_p, tk) - + if vert_type.lower() == "pres" or vert_type.lower() == "pressure": v_coord = full_p _low_thresh = 97000. if low_thresh is None else low_thresh _mid_thresh = 80000. if mid_thresh is None else mid_thresh _high_thresh = 45000. if high_thresh is None else high_thresh vert_inc_w_height = 0 - elif (vert_type.lower() == "height_msl" + elif (vert_type.lower() == "height_msl" or vert_type.lower() == "height_agl"): is_msl = vert_type.lower() == "height_msl" - v_coord = _get_geoht(wrfin, timeidx, method, squeeze, - cache, meta=False, _key=_key, height=True, + v_coord = _get_geoht(wrfin, timeidx, method, squeeze, + cache, meta=False, _key=_key, height=True, msl=is_msl) _low_thresh = 300. if low_thresh is None else low_thresh _mid_thresh = 2000. if mid_thresh is None else mid_thresh @@ -155,344 +155,346 @@ def get_cloudfrac(wrfin, timeidx=0, method="cat", squeeze=True, else: raise ValueError("'vert_type' must be 'pres', 'height_msl', " "or 'height_agl'") - - cfrac = _cloudfrac(v_coord, rh, vert_inc_w_height, - _low_thresh, _mid_thresh, _high_thresh, missing) - + + cfrac = _cloudfrac(v_coord, rh, vert_inc_w_height, + _low_thresh, _mid_thresh, _high_thresh, missing) + return ma.masked_values(cfrac, missing) -def get_low_cloudfrac(wrfin, timeidx=0, method="cat", squeeze=True, - cache=None, meta=True, _key=None, - vert_type="height_agl", low_thresh=None, mid_thresh=None, - high_thresh=None, missing=default_fill(np.float64)): +def get_low_cloudfrac(wrfin, timeidx=0, method="cat", squeeze=True, + cache=None, meta=True, _key=None, + vert_type="height_agl", low_thresh=None, + mid_thresh=None, high_thresh=None, + missing=default_fill(np.float64)): """Return the cloud fraction for the low level clouds. - - If the vertical coordinate type is 'height_agl' or 'height_msl', the + + If the vertical coordinate type is 'height_agl' or 'height_msl', the default cloud levels are defined as: - + 300 m <= low_cloud < 2000 m 2000 m <= mid_cloud < 6000 m 6000 m <= high_cloud - - For 'pressure', the default cloud levels are defined as: - + + For 'pressure', the default cloud levels are defined as: + 97000 Pa <= low_cloud < 80000 Pa 80000 Pa <= mid_cloud < 45000 Pa 45000 Pa <= high_cloud - + Note that the default low cloud levels are chosen to - exclude clouds near the surface (fog). If you want fog included, set - *low_thresh* to ~99500 Pa if *vert_type* is set to 'pressure', or 15 m if - using 'height_msl' or 'height_agl'. Keep in mind that the lowest mass grid - points are slightly above the ground, and in order to find clouds, the - *low_thresh* needs to be set to values that are slightly greater than + exclude clouds near the surface (fog). If you want fog included, set + *low_thresh* to ~99500 Pa if *vert_type* is set to 'pressure', or 15 m if + using 'height_msl' or 'height_agl'. Keep in mind that the lowest mass grid + points are slightly above the ground, and in order to find clouds, the + *low_thresh* needs to be set to values that are slightly greater than (less than) the lowest height (pressure) values. - - When using 'pressure' or 'height_agl' for *vert_type*, there is a - possibility that the lowest WRF level will be higher than the low_cloud or - mid_cloud threshold, particularly for mountainous regions. When this + + When using 'pressure' or 'height_agl' for *vert_type*, there is a + possibility that the lowest WRF level will be higher than the low_cloud or + mid_cloud threshold, particularly for mountainous regions. When this happens, a fill value will be used in the output. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - vert_type (:obj:`str`, optional): The type of vertical coordinate used - to determine cloud type thresholds. Must be 'height_agl', + + vert_type (:obj:`str`, optional): The type of vertical coordinate used + to determine cloud type thresholds. Must be 'height_agl', 'height_msl', or 'pres'. The default is 'height_agl'. - - low_thresh (:obj:`float`, optional): The lower bound for what is - considered a low cloud. If *vert_type* is 'pres', the default is - 97000 Pa. If *vert_type* is 'height_agl' or 'height_msl', then the - default is 300 m. - - mid_thresh (:obj:`float`, optional): The lower bound for what is - considered a mid level cloud. If *vert_type* is 'pres', the - default is 80000 Pa. If *vert_type* is 'height_agl' or - 'height_msl', then the default is 2000 m. - - high_thresh (:obj:`float`, optional): The lower bound for what is - considered a high level cloud. If *vert_type* is 'pres', the - default is 45000 Pa. If *vert_type* is 'height_agl' or - 'height_msl', then the default is 6000 m. - + + low_thresh (:obj:`float`, optional): The lower bound for what is + considered a low cloud. If *vert_type* is 'pres', the default is + 97000 Pa. If *vert_type* is 'height_agl' or 'height_msl', then the + default is 300 m. + + mid_thresh (:obj:`float`, optional): The lower bound for what is + considered a mid level cloud. If *vert_type* is 'pres', the + default is 80000 Pa. If *vert_type* is 'height_agl' or + 'height_msl', then the default is 2000 m. + + high_thresh (:obj:`float`, optional): The lower bound for what is + considered a high level cloud. If *vert_type* is 'pres', the + default is 45000 Pa. If *vert_type* is 'height_agl' or + 'height_msl', then the default is 6000 m. + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - cloud fraction array for low level clouds. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + cloud fraction array for low level clouds. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - result = get_cloudfrac(wrfin, timeidx, method, squeeze, - cache, meta, _key, - vert_type, low_thresh, mid_thresh, - high_thresh, missing)[0,:] - + result = get_cloudfrac(wrfin, timeidx, method, squeeze, + cache, meta, _key, vert_type, low_thresh, + mid_thresh, high_thresh, missing)[0, :] + if meta: result.attrs["description"] = "low clouds" - + return result - - -def get_mid_cloudfrac(wrfin, timeidx=0, method="cat", squeeze=True, - cache=None, meta=True, _key=None, - vert_type="height_agl", low_thresh=None, mid_thresh=None, - high_thresh=None, missing=default_fill(np.float64)): + + +def get_mid_cloudfrac(wrfin, timeidx=0, method="cat", squeeze=True, + cache=None, meta=True, _key=None, + vert_type="height_agl", low_thresh=None, + mid_thresh=None, high_thresh=None, + missing=default_fill(np.float64)): """Return the cloud fraction for the mid level clouds. - - If the vertical coordinate type is 'height_agl' or 'height_msl', the + + If the vertical coordinate type is 'height_agl' or 'height_msl', the default cloud levels are defined as: - + 300 m <= low_cloud < 2000 m 2000 m <= mid_cloud < 6000 m 6000 m <= high_cloud - - For 'pressure', the default cloud levels are defined as: - + + For 'pressure', the default cloud levels are defined as: + 97000 Pa <= low_cloud < 80000 Pa 80000 Pa <= mid_cloud < 45000 Pa 45000 Pa <= high_cloud - + Note that the default low cloud levels are chosen to - exclude clouds near the surface (fog). If you want fog included, set - *low_thresh* to ~99500 Pa if *vert_type* is set to 'pressure', or 15 m if - using 'height_msl' or 'height_agl'. Keep in mind that the lowest mass grid - points are slightly above the ground, and in order to find clouds, the - *low_thresh* needs to be set to values that are slightly greater than + exclude clouds near the surface (fog). If you want fog included, set + *low_thresh* to ~99500 Pa if *vert_type* is set to 'pressure', or 15 m if + using 'height_msl' or 'height_agl'. Keep in mind that the lowest mass grid + points are slightly above the ground, and in order to find clouds, the + *low_thresh* needs to be set to values that are slightly greater than (less than) the lowest height (pressure) values. - - When using 'pressure' or 'height_agl' for *vert_type*, there is a - possibility that the lowest WRF level will be higher than the low_cloud or - mid_cloud threshold, particularly for mountainous regions. When this + + When using 'pressure' or 'height_agl' for *vert_type*, there is a + possibility that the lowest WRF level will be higher than the low_cloud or + mid_cloud threshold, particularly for mountainous regions. When this happens, a fill value will be used in the output. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - vert_type (:obj:`str`, optional): The type of vertical coordinate used - to determine cloud type thresholds. Must be 'height_agl', + + vert_type (:obj:`str`, optional): The type of vertical coordinate used + to determine cloud type thresholds. Must be 'height_agl', 'height_msl', or 'pres'. The default is 'height_agl'. - - low_thresh (:obj:`float`, optional): The lower bound for what is - considered a low cloud. If *vert_type* is 'pres', the default is - 97000 Pa. If *vert_type* is 'height_agl' or 'height_msl', then the - default is 300 m. - - mid_thresh (:obj:`float`, optional): The lower bound for what is - considered a mid level cloud. If *vert_type* is 'pres', the - default is 80000 Pa. If *vert_type* is 'height_agl' or - 'height_msl', then the default is 2000 m. - - high_thresh (:obj:`float`, optional): The lower bound for what is - considered a high level cloud. If *vert_type* is 'pres', the - default is 45000 Pa. If *vert_type* is 'height_agl' or - 'height_msl', then the default is 6000 m. - + + low_thresh (:obj:`float`, optional): The lower bound for what is + considered a low cloud. If *vert_type* is 'pres', the default is + 97000 Pa. If *vert_type* is 'height_agl' or 'height_msl', then the + default is 300 m. + + mid_thresh (:obj:`float`, optional): The lower bound for what is + considered a mid level cloud. If *vert_type* is 'pres', the + default is 80000 Pa. If *vert_type* is 'height_agl' or + 'height_msl', then the default is 2000 m. + + high_thresh (:obj:`float`, optional): The lower bound for what is + considered a high level cloud. If *vert_type* is 'pres', the + default is 45000 Pa. If *vert_type* is 'height_agl' or + 'height_msl', then the default is 6000 m. + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - cloud fraction array for mid level clouds. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + cloud fraction array for mid level clouds. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - result = get_cloudfrac(wrfin, timeidx, method, squeeze, - cache, meta, _key, - vert_type, low_thresh, mid_thresh, - high_thresh, missing)[1,:] - + result = get_cloudfrac(wrfin, timeidx, method, squeeze, + cache, meta, _key, + vert_type, low_thresh, mid_thresh, + high_thresh, missing)[1, :] + if meta: result.attrs["description"] = "mid clouds" - + return result - - -def get_high_cloudfrac(wrfin, timeidx=0, method="cat", squeeze=True, - cache=None, meta=True, _key=None, - vert_type="height_agl", low_thresh=None, mid_thresh=None, - high_thresh=None, missing=default_fill(np.float64)): + + +def get_high_cloudfrac(wrfin, timeidx=0, method="cat", squeeze=True, + cache=None, meta=True, _key=None, + vert_type="height_agl", low_thresh=None, + mid_thresh=None, high_thresh=None, + missing=default_fill(np.float64)): """Return the cloud fraction for the high level clouds. - - If the vertical coordinate type is 'height_agl' or 'height_msl', the + + If the vertical coordinate type is 'height_agl' or 'height_msl', the default cloud levels are defined as: - + 300 m <= low_cloud < 2000 m 2000 m <= mid_cloud < 6000 m 6000 m <= high_cloud - - For 'pressure', the default cloud levels are defined as: - + + For 'pressure', the default cloud levels are defined as: + 97000 Pa <= low_cloud < 80000 Pa 80000 Pa <= mid_cloud < 45000 Pa 45000 Pa <= high_cloud - + Note that the default low cloud levels are chosen to - exclude clouds near the surface (fog). If you want fog included, set - *low_thresh* to ~99500 Pa if *vert_type* is set to 'pressure', or 15 m if - using 'height_msl' or 'height_agl'. Keep in mind that the lowest mass grid - points are slightly above the ground, and in order to find clouds, the - *low_thresh* needs to be set to values that are slightly greater than + exclude clouds near the surface (fog). If you want fog included, set + *low_thresh* to ~99500 Pa if *vert_type* is set to 'pressure', or 15 m if + using 'height_msl' or 'height_agl'. Keep in mind that the lowest mass grid + points are slightly above the ground, and in order to find clouds, the + *low_thresh* needs to be set to values that are slightly greater than (less than) the lowest height (pressure) values. - - When using 'pressure' or 'height_agl' for *vert_type*, there is a - possibility that the lowest WRF level will be higher than the low_cloud or - mid_cloud threshold, particularly for mountainous regions. When this + + When using 'pressure' or 'height_agl' for *vert_type*, there is a + possibility that the lowest WRF level will be higher than the low_cloud or + mid_cloud threshold, particularly for mountainous regions. When this happens, a fill value will be used in the output. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - vert_type (:obj:`str`, optional): The type of vertical coordinate used - to determine cloud type thresholds. Must be 'height_agl', + + vert_type (:obj:`str`, optional): The type of vertical coordinate used + to determine cloud type thresholds. Must be 'height_agl', 'height_msl', or 'pres'. The default is 'height_agl'. - - low_thresh (:obj:`float`, optional): The lower bound for what is - considered a low cloud. If *vert_type* is 'pres', the default is - 97000 Pa. If *vert_type* is 'height_agl' or 'height_msl', then the - default is 300 m. - - mid_thresh (:obj:`float`, optional): The lower bound for what is - considered a mid level cloud. If *vert_type* is 'pres', the - default is 80000 Pa. If *vert_type* is 'height_agl' or - 'height_msl', then the default is 2000 m. - - high_thresh (:obj:`float`, optional): The lower bound for what is - considered a high level cloud. If *vert_type* is 'pres', the - default is 45000 Pa. If *vert_type* is 'height_agl' or - 'height_msl', then the default is 6000 m. - + + low_thresh (:obj:`float`, optional): The lower bound for what is + considered a low cloud. If *vert_type* is 'pres', the default is + 97000 Pa. If *vert_type* is 'height_agl' or 'height_msl', then the + default is 300 m. + + mid_thresh (:obj:`float`, optional): The lower bound for what is + considered a mid level cloud. If *vert_type* is 'pres', the + default is 80000 Pa. If *vert_type* is 'height_agl' or + 'height_msl', then the default is 2000 m. + + high_thresh (:obj:`float`, optional): The lower bound for what is + considered a high level cloud. If *vert_type* is 'pres', the + default is 45000 Pa. If *vert_type* is 'height_agl' or + 'height_msl', then the default is 6000 m. + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - cloud fraction array for high level clouds. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + cloud fraction array for high level clouds. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - result = get_cloudfrac(wrfin, timeidx, method, squeeze, - cache, meta, _key, - vert_type, low_thresh, mid_thresh, - high_thresh, missing)[2,:] - + result = get_cloudfrac(wrfin, timeidx, method, squeeze, + cache, meta, _key, + vert_type, low_thresh, mid_thresh, + high_thresh, missing)[2, :] + if meta: result.attrs["description"] = "high clouds" - + return result diff --git a/src/wrf/g_ctt.py b/src/wrf/g_ctt.py index 1003a4e..aa339a7 100644 --- a/src/wrf/g_ctt.py +++ b/src/wrf/g_ctt.py @@ -3,11 +3,10 @@ from __future__ import (absolute_import, division, print_function) import numpy as np import numpy.ma as ma -#from .extension import computectt, computetk from .extension import _ctt, _tk from .constants import Constants, ConversionFactors, default_fill from .destag import destagger -from .decorators import convert_units +from .decorators import convert_units from .metadecorators import copy_and_set_metadata from .util import extract_vars @@ -17,86 +16,86 @@ from .util import extract_vars description="cloud top temperature", MemoryOrder="XY") @convert_units("temp", "c") -def get_ctt(wrfin, timeidx=0, method="cat", +def get_ctt(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, - fill_nocloud=False, missing=default_fill(np.float64), + fill_nocloud=False, missing=default_fill(np.float64), opt_thresh=1.0, units="degC"): """Return the cloud top temperature. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - fill_nocloud (:obj:`bool`, optional): Set to True to use fill values in - regions where clouds are not detected (optical depth less than 1). - Otherwise, the output will contain the surface temperature for + + fill_nocloud (:obj:`bool`, optional): Set to True to use fill values in + regions where clouds are not detected (optical depth less than 1). + Otherwise, the output will contain the surface temperature for areas without clouds. Default is False. - - missing (:obj:`float`, optional): The fill value to use for areas - where no clouds are detected. Only used if *fill_nocloud* is - True. Default is - :data:`wrf.default_fill(numpy.float64)`. - - opt_thresh (:obj:`float`, optional): The amount of optical - depth (integrated from top down) required to trigger a cloud top - temperature calculation. The cloud top temperature is calculated at - the vertical level where this threshold is met. Vertical columns - with less than this threshold will be treated as cloud free areas. - In general, the larger the value is for this - threshold, the lower the altitude will be for the cloud top - temperature calculation, and therefore higher cloud top - temperature values. Default is 1.0, which should be sufficient for + + missing (:obj:`float`, optional): The fill value to use for areas + where no clouds are detected. Only used if *fill_nocloud* is + True. Default is + :data:`wrf.default_fill(numpy.float64)`. + + opt_thresh (:obj:`float`, optional): The amount of optical + depth (integrated from top down) required to trigger a cloud top + temperature calculation. The cloud top temperature is calculated at + the vertical level where this threshold is met. Vertical columns + with less than this threshold will be treated as cloud free areas. + In general, the larger the value is for this + threshold, the lower the altitude will be for the cloud top + temperature calculation, and therefore higher cloud top + temperature values. Default is 1.0, which should be sufficient for most users. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'ctt'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'ctt'. Default is 'degC'. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The cloud top temperature. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ varnames = ("T", "P", "PB", "PH", "PHB", "HGT", "QVAPOR") ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, @@ -107,40 +106,40 @@ def get_ctt(wrfin, timeidx=0, method="cat", ph = ncvars["PH"] phb = ncvars["PHB"] ter = ncvars["HGT"] - qv = ncvars["QVAPOR"] * 1000.0 # g/kg - + qv = ncvars["QVAPOR"] * 1000.0 # g/kg + haveqci = 1 try: - icevars = extract_vars(wrfin, timeidx, "QICE", + icevars = extract_vars(wrfin, timeidx, "QICE", method, squeeze, cache, meta=False, _key=_key) except KeyError: qice = np.zeros(qv.shape, qv.dtype) haveqci = 0 else: - qice = icevars["QICE"] * 1000.0 #g/kg - + qice = icevars["QICE"] * 1000.0 # g/kg + try: - cldvars = extract_vars(wrfin, timeidx, "QCLOUD", + cldvars = extract_vars(wrfin, timeidx, "QCLOUD", method, squeeze, cache, meta=False, _key=_key) except KeyError: raise RuntimeError("'QCLOUD' not found in NetCDF file") else: - qcld = cldvars["QCLOUD"] * 1000.0 #g/kg - + qcld = cldvars["QCLOUD"] * 1000.0 # g/kg + full_p = p + pb p_hpa = full_p * ConversionFactors.PA_TO_HPA full_t = t + Constants.T_BASE tk = _tk(full_p, full_t) - + geopt = ph + phb geopt_unstag = destagger(geopt, -3) ght = geopt_unstag / Constants.G - + _fill_nocloud = 1 if fill_nocloud else 0 - + ctt = _ctt(p_hpa, tk, qice, qcld, qv, ght, ter, haveqci, _fill_nocloud, missing, opt_thresh) - + return ma.masked_values(ctt, missing) diff --git a/src/wrf/g_dbz.py b/src/wrf/g_dbz.py index 77b2523..caae9ef 100755 --- a/src/wrf/g_dbz.py +++ b/src/wrf/g_dbz.py @@ -2,82 +2,81 @@ from __future__ import (absolute_import, division, print_function) import numpy as np -#from .extension import computedbz,computetk from .extension import _dbz, _tk from .constants import Constants from .util import extract_vars, to_np from .metadecorators import copy_and_set_metadata -@copy_and_set_metadata(copy_varname="T", name="dbz", +@copy_and_set_metadata(copy_varname="T", name="dbz", description="radar reflectivity", units="dBZ") -def get_dbz(wrfin, timeidx=0, method="cat", +def get_dbz(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, use_varint=False, use_liqskin=False): """Return the simulated radar reflectivity. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - use_varint (:obj:`bool`, optional): When set to False, - the intercept parameters are assumed constant - (as in MM5's Reisner-2 bulk microphysical scheme). - When set to True, the variable intercept - parameters are used as in the more recent version of Reisner-2 - (based on Thompson, Rasmussen, and Manning, 2004, Monthly weather - Review, Vol. 132, No. 2, pp. 519-542.). - - use_liqskin (:obj:`bool`, optional): When set to True, frozen particles - that are at a temperature above freezing are assumed to scatter + + use_varint (:obj:`bool`, optional): When set to False, + the intercept parameters are assumed constant + (as in MM5's Reisner-2 bulk microphysical scheme). + When set to True, the variable intercept + parameters are used as in the more recent version of Reisner-2 + (based on Thompson, Rasmussen, and Manning, 2004, Monthly weather + Review, Vol. 132, No. 2, pp. 519-542.). + + use_liqskin (:obj:`bool`, optional): When set to True, frozen particles + that are at a temperature above freezing are assumed to scatter as a liquid particle. Set to False to disable. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The simulated - radar reflectivity. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The simulated + radar reflectivity. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ varnames = ("T", "P", "PB", "QVAPOR", "QRAIN") ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, @@ -87,113 +86,112 @@ def get_dbz(wrfin, timeidx=0, method="cat", pb = ncvars["PB"] qv = ncvars["QVAPOR"] qr = ncvars["QRAIN"] - + try: - snowvars = extract_vars(wrfin, timeidx, "QSNOW", + snowvars = extract_vars(wrfin, timeidx, "QSNOW", method, squeeze, cache, meta=False, _key=_key) except KeyError: qs = np.zeros(qv.shape, qv.dtype) else: qs = snowvars["QSNOW"] - + try: - graupvars = extract_vars(wrfin, timeidx, "QGRAUP", + graupvars = extract_vars(wrfin, timeidx, "QGRAUP", method, squeeze, cache, meta=False, _key=_key) except KeyError: qg = np.zeros(qv.shape, qv.dtype) else: qg = graupvars["QGRAUP"] - + full_t = t + Constants.T_BASE full_p = p + pb tk = _tk(full_p, full_t) - + # If qsnow is not all 0, set sn0 to 1 sn0 = 1 if qs.any() else 0 ivarint = 1 if use_varint else 0 iliqskin = 1 if use_liqskin else 0 - + return _dbz(full_p, tk, qv, qr, qs, qg, sn0, ivarint, iliqskin) -@copy_and_set_metadata(copy_varname="T", name="max_dbz", +@copy_and_set_metadata(copy_varname="T", name="max_dbz", remove_dims=("bottom_top",), description="maximum radar reflectivity", units="dBZ", MemoryOrder="XY") -def get_max_dbz(wrfin, timeidx=0, method="cat", +def get_max_dbz(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, use_varint=False, use_liqskin=False): """Return the maximum simulated radar reflectivity. - - This function returns the maximum reflectivity found in the column for + + This function returns the maximum reflectivity found in the column for each grid point. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - use_varint (:obj:`bool`, optional): When set to False, - the intercept parameters are assumed constant - (as in MM5's Reisner-2 bulk microphysical scheme). - When set to True, the variable intercept - parameters are used as in the more recent version of Reisner-2 - (based on Thompson, Rasmussen, and Manning, 2004, Monthly weather - Review, Vol. 132, No. 2, pp. 519-542.). - - use_liqskin (:obj:`bool`, optional): When set to True, frozen particles - that are at a temperature above freezing are assumed to scatter + + use_varint (:obj:`bool`, optional): When set to False, + the intercept parameters are assumed constant + (as in MM5's Reisner-2 bulk microphysical scheme). + When set to True, the variable intercept + parameters are used as in the more recent version of Reisner-2 + (based on Thompson, Rasmussen, and Manning, 2004, Monthly weather + Review, Vol. 132, No. 2, pp. 519-542.). + + use_liqskin (:obj:`bool`, optional): When set to True, frozen particles + that are at a temperature above freezing are assumed to scatter as a liquid particle. Set to False to disable. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The maximum - simulated radar reflectivity. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The maximum + simulated radar reflectivity. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ return np.amax(to_np(get_dbz(wrfin, timeidx, method, squeeze, cache, meta, - _key, use_varint, use_liqskin)), - axis=-3) - + _key, use_varint, use_liqskin)), + axis=-3) diff --git a/src/wrf/g_dewpoint.py b/src/wrf/g_dewpoint.py index 57cd656..bf9fed2 100755 --- a/src/wrf/g_dewpoint.py +++ b/src/wrf/g_dewpoint.py @@ -1,164 +1,163 @@ from __future__ import (absolute_import, division, print_function) -#from .extension import computetd from .extension import _td from .decorators import convert_units from .metadecorators import copy_and_set_metadata from .util import extract_vars -@copy_and_set_metadata(copy_varname="QVAPOR", name="td", +@copy_and_set_metadata(copy_varname="QVAPOR", name="td", description="dew point temperature") @convert_units("temp", "c") -def get_dp(wrfin, timeidx=0, method="cat", squeeze=True, +def get_dp(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="degC"): """Return the dewpoint temperature. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'td'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'td'. Default is 'degC'. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The dewpoint temperature. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - - varnames=("P", "PB", "QVAPOR") + + varnames = ("P", "PB", "QVAPOR") ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, meta=False, _key=_key) - + p = ncvars["P"] pb = ncvars["PB"] - # Copy needed for the mmap nonsense of scipy.io.netcdf, which seems to + # Copy needed for the mmap nonsense of scipy.io.netcdf, which seems to # break with every release qvapor = ncvars["QVAPOR"].copy() - + # Algorithm requires hPa full_p = .01*(p + pb) qvapor[qvapor < 0] = 0 - + td = _td(full_p, qvapor) return td -@copy_and_set_metadata(copy_varname="Q2", name="td2", + +@copy_and_set_metadata(copy_varname="Q2", name="td2", description="2m dew point temperature") @convert_units("temp", "c") -def get_dp_2m(wrfin, timeidx=0, method="cat", squeeze=True, +def get_dp_2m(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="degC"): """Return the 2m dewpoint temperature. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'td2'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'td2'. Default is 'degC'. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The 2m dewpoint temperature. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - varnames=("PSFC", "Q2") + varnames = ("PSFC", "Q2") ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, meta=False, _key=_key) # Algorithm requires hPa psfc = .01*(ncvars["PSFC"]) - # Copy needed for the mmap nonsense of scipy.io.netcdf, which seems to + # Copy needed for the mmap nonsense of scipy.io.netcdf, which seems to # break with every release q2 = ncvars["Q2"].copy() q2[q2 < 0] = 0 - + td = _td(psfc, q2) - - return td + return td diff --git a/src/wrf/g_geoht.py b/src/wrf/g_geoht.py index 6b041ef..7e78e5a 100755 --- a/src/wrf/g_geoht.py +++ b/src/wrf/g_geoht.py @@ -8,79 +8,80 @@ from .decorators import convert_units from .metadecorators import set_height_metadata from .util import extract_vars, either -def _get_geoht(wrfin, timeidx, method="cat", squeeze=True, + +def _get_geoht(wrfin, timeidx, method="cat", squeeze=True, cache=None, meta=True, _key=None, height=True, msl=True, stag=False): """Return the geopotential or geopotential height. - - If *height* is False, then geopotential is returned in units of - [m2 s-2]. If *height* is True, then geopotential height is - returned in units of [m]. If *msl* is True, then geopotential height - is return as Mean Sea Level (MSL). If *msl* is False, then geopotential + + If *height* is False, then geopotential is returned in units of + [m2 s-2]. If *height* is True, then geopotential height is + returned in units of [m]. If *msl* is True, then geopotential height + is return as Mean Sea Level (MSL). If *msl* is False, then geopotential height is returned as Above Ground Level (AGL). - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - height (:obj:`bool`, optional): Set to True to return geopotential + + height (:obj:`bool`, optional): Set to True to return geopotential height instead of geopotential. Default is True. - + msl (:obj:`bool`, optional): Set to True to return geopotential height - as Mean Sea Level (MSL). Set to False to return the - geopotential height as Above Ground Level (AGL) by subtracting + as Mean Sea Level (MSL). Set to False to return the + geopotential height as Above Ground Level (AGL) by subtracting the terrain height. Default is True. - - stag (:obj:`bool`, optional): Set to True to use the vertical + + stag (:obj:`bool`, optional): Set to True to use the vertical staggered grid, rather than the mass grid. Default is False. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The geopotential or geopotential height. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - + varname = either("PH", "GHT")(wrfin) if varname == "PH": ph_vars = extract_vars(wrfin, timeidx, ("PH", "PHB", "HGT"), @@ -100,11 +101,11 @@ def _get_geoht(wrfin, timeidx, method="cat", squeeze=True, _key=_key) geopt_unstag = ght_vars["GHT"] * Constants.G hgt = ght_vars["HGT_M"] - + if stag: warnings.warn("file contains no vertically staggered geopotential " "height variable, returning unstaggered result " - "instead" ) + "instead") if height: if msl: return geopt_unstag / Constants.G @@ -113,70 +114,70 @@ def _get_geoht(wrfin, timeidx, method="cat", squeeze=True, # array needs to be reshaped to a 3D array so the right dims # line up new_dims = list(hgt.shape) - new_dims.insert(-2,1) + new_dims.insert(-2, 1) hgt = hgt.reshape(new_dims) - + return (geopt_unstag / Constants.G) - hgt else: return geopt_unstag @set_height_metadata(geopt=True, stag=False) -def get_geopt(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, +def get_geopt(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None): """Return the geopotential. - + The geopotential is returned in units of [m2 s-2]. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The geopotential. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ return _get_geoht(wrfin, timeidx, method, squeeze, cache, meta, _key, False, True) @@ -184,135 +185,135 @@ def get_geopt(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, @set_height_metadata(geopt=False, stag=False) @convert_units("height", "m") -def get_height(wrfin, timeidx=0, method="cat", squeeze=True, +def get_height(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, msl=True, units="m"): """Return the geopotential height. - - If *msl* is True, then geopotential height is returned as Mean Sea Level - (MSL). If *msl* is False, then geopotential height is returned as + + If *msl* is True, then geopotential height is returned as Mean Sea Level + (MSL). If *msl* is False, then geopotential height is returned as Above Ground Level (AGL) by subtracting the terrain height. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + msl (:obj:`bool`, optional): Set to True to return geopotential height - as Mean Sea Level (MSL). Set to False to return the - geopotential height as Above Ground Level (AGL) by subtracting + as Mean Sea Level (MSL). Set to False to return the + geopotential height as Above Ground Level (AGL) by subtracting the terrain height. Default is True. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'z'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'z'. Default is 'm'. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The geopotential height. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - + return _get_geoht(wrfin, timeidx, method, squeeze, cache, meta, _key, True, msl) @set_height_metadata(geopt=True, stag=True) -def get_stag_geopt(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, - meta=True, _key=None): +def get_stag_geopt(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, + meta=True, _key=None): """Return the geopotential for the vertically staggered grid. - + The geopotential is returned in units of [m2 s-2]. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The geopotential. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ return _get_geoht(wrfin, timeidx, method, squeeze, cache, meta, _key, False, True, stag=True) @@ -320,75 +321,73 @@ def get_stag_geopt(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, @set_height_metadata(geopt=False, stag=True) @convert_units("height", "m") -def get_stag_height(wrfin, timeidx=0, method="cat", squeeze=True, - cache=None, meta=True, _key=None, - msl=True, units="m"): +def get_stag_height(wrfin, timeidx=0, method="cat", squeeze=True, + cache=None, meta=True, _key=None, msl=True, units="m"): """Return the geopotential height for the vertically staggered grid. - - If *msl* is True, then geopotential height is returned as Mean Sea Level - (MSL). If *msl* is False, then geopotential height is returned as + + If *msl* is True, then geopotential height is returned as Mean Sea Level + (MSL). If *msl* is False, then geopotential height is returned as Above Ground Level (AGL) by subtracting the terrain height. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + msl (:obj:`bool`, optional): Set to True to return geopotential height - as Mean Sea Level (MSL). Set to False to return the - geopotential height as Above Ground Level (AGL) by subtracting + as Mean Sea Level (MSL). Set to False to return the + geopotential height as Above Ground Level (AGL) by subtracting the terrain height. Default is True. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'z'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'z'. Default is 'm'. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The geopotential height. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - + return _get_geoht(wrfin, timeidx, method, squeeze, cache, meta, _key, True, msl, stag=True) - \ No newline at end of file diff --git a/src/wrf/g_helicity.py b/src/wrf/g_helicity.py index 5ae17ab..a7ef39f 100755 --- a/src/wrf/g_helicity.py +++ b/src/wrf/g_helicity.py @@ -9,87 +9,88 @@ from .util import extract_vars, extract_global_attrs, either from .metadecorators import copy_and_set_metadata from .g_latlon import get_lat -@copy_and_set_metadata(copy_varname="HGT", name="srh", + +@copy_and_set_metadata(copy_varname="HGT", name="srh", description="storm relative helicity", units="m2 s-2") -def get_srh(wrfin, timeidx=0, method="cat", squeeze=True, +def get_srh(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, top=3000.0): """Return the storm relative helicity. - + The *top* argument specifies the top of the integration in [m]. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - top (:obj:`float`, optional): The top of the integration in [m]. + + top (:obj:`float`, optional): The top of the integration in [m]. Default is 3000.0. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The storm relative helicity. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ # Top can either be 3000 or 1000 (for 0-1 srh or 0-3 srh) - - lats = get_lat(wrfin, timeidx, method, squeeze, + + lats = get_lat(wrfin, timeidx, method, squeeze, cache, meta=False, _key=_key, stagger=None) - + ncvars = extract_vars(wrfin, timeidx, ("HGT", "PH", "PHB"), method, squeeze, cache, meta=False, _key=_key) - + ter = ncvars["HGT"] ph = ncvars["PH"] phb = ncvars["PHB"] - + # As coded in NCL, but not sure this is possible varname = either("U", "UU")(wrfin) u_vars = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) - u = destagger(u_vars[varname], -1) - + u = destagger(u_vars[varname], -1) + varname = either("V", "VV")(wrfin) v_vars = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) @@ -97,117 +98,113 @@ def get_srh(wrfin, timeidx=0, method="cat", squeeze=True, geopt = ph + phb geopt_unstag = destagger(geopt, -3) - + z = geopt_unstag / Constants.G - + # Re-ordering from high to low - u1 = np.ascontiguousarray(u[...,::-1,:,:]) - v1 = np.ascontiguousarray(v[...,::-1,:,:]) - z1 = np.ascontiguousarray(z[...,::-1,:,:]) - + u1 = np.ascontiguousarray(u[..., ::-1, :, :]) + v1 = np.ascontiguousarray(v[..., ::-1, :, :]) + z1 = np.ascontiguousarray(z[..., ::-1, :, :]) + srh = _srhel(u1, v1, z1, ter, lats, top) - + return srh -@copy_and_set_metadata(copy_varname="MAPFAC_M", name="updraft_helicity", + +@copy_and_set_metadata(copy_varname="MAPFAC_M", name="updraft_helicity", description="updraft helicity", units="m2 s-2") -def get_uh(wrfin, timeidx=0, method="cat", squeeze=True, +def get_uh(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, bottom=2000.0, top=5000.0): - + """Return the updraft helicity. - - The *bottom* and *top* arguments specify the bottom and top limits + + The *bottom* and *top* arguments specify the bottom and top limits for the integration in [m]. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - bottom (:obj:`float`, optional): The bottom limit for the integration + + bottom (:obj:`float`, optional): The bottom limit for the integration in [m]. Default is 2000.0. - - top (:obj:`float`, optional): The top limit for the integration in [m]. + + top (:obj:`float`, optional): The top limit for the integration in [m]. Default is 5000.0. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The updraft helicity. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - + ncvars = extract_vars(wrfin, timeidx, ("W", "PH", "PHB", "MAPFAC_M"), method, squeeze, cache, meta=False, _key=_key) - + wstag = ncvars["W"] ph = ncvars["PH"] phb = ncvars["PHB"] mapfct = ncvars["MAPFAC_M"] - - attrs = extract_global_attrs(wrfin, attrs=("DX", "DY")) + + attrs = extract_global_attrs(wrfin, attrs=("DX", "DY")) dx = attrs["DX"] dy = attrs["DY"] - + # As coded in NCL, but not sure this is possible varname = either("U", "UU")(wrfin) u_vars = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) - u = destagger(u_vars[varname], -1) - + u = destagger(u_vars[varname], -1) + varname = either("V", "VV")(wrfin) v_vars = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) - v = destagger(v_vars[varname], -2) - + v = destagger(v_vars[varname], -2) + zp = (ph + phb) / Constants.G - + uh = _udhel(zp, mapfct, u, v, wstag, dx, dy, bottom, top) - - return uh - - - - \ No newline at end of file + return uh diff --git a/src/wrf/g_latlon.py b/src/wrf/g_latlon.py index 03aef1f..0e4cfae 100755 --- a/src/wrf/g_latlon.py +++ b/src/wrf/g_latlon.py @@ -15,237 +15,237 @@ if xarray_enabled(): from xarray import DataArray -def get_lat(wrfin, timeidx=0, method="cat", squeeze=True, +def get_lat(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, stagger=None): """Return the two dimensional latitude coordinate variable. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + stagger (:obj:`str`): By default, the latitude is returned on the mass - grid, but a staggered grid can be chosen with the following + grid, but a staggered grid can be chosen with the following options: - + - 'm': Use the mass grid (default). - - 'u': Use the same staggered grid as the u wind component, + - 'u': Use the same staggered grid as the u wind component, which has a staggered west_east (x) dimension. - - 'v': Use the same staggered grid as the v wind component, + - 'v': Use the same staggered grid as the v wind component, which has a staggered south_north (y) dimension. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The two dimensional latitude coordinate variable. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - + varname = _lat_varname(wrfin, stagger) lat_var = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta, _key) - + return lat_var[varname] - -def get_lon(wrfin, timeidx=0, method="cat", squeeze=True, + +def get_lon(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, stagger=None): """Return the two dimensional longitude coordinate variable. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + stagger (:obj:`str`): By default, the longitude is returned on the mass - grid, but a staggered grid can be chosen with the following + grid, but a staggered grid can be chosen with the following options: - + - 'm': Use the mass grid (default). - - 'u': Use the same staggered grid as the u wind component, + - 'u': Use the same staggered grid as the u wind component, which has a staggered west_east (x) dimension. - - 'v': Use the same staggered grid as the v wind component, + - 'v': Use the same staggered grid as the v wind component, which has a staggered south_north (y) dimension. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The two dimensional longitude coordinate variable. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - + varname = _lon_varname(wrfin, stagger) lon_var = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta, _key) - + return lon_var[varname] -def _llxy_mapping(wrfin, x_or_lat, y_or_lon, func, timeidx, stagger, +def _llxy_mapping(wrfin, x_or_lat, y_or_lon, func, timeidx, stagger, squeeze, meta, as_int=None): - + """Return the x,y/lat,lon coordinates for a dictionary input. - + The leftmost dimension(s) for the result is: - + - return_val[key,...,0,...] will contain the x/lat values. - return_val[key,...,1,...] will contain the y/lon values. - + Nested dictionaries are allowed. - + Args: - - wrfin (:obj:`dict`): A mapping of key name to a WRF NetCDF file object + + wrfin (:obj:`dict`): A mapping of key name to a WRF NetCDF file object or sequence of WRF NetCDF file objects. - - x_or_lat (:obj:`float` or sequence): A single latitude/x value or a + + x_or_lat (:obj:`float` or sequence): A single latitude/x value or a sequence of latitude/x values to be converted. - - y_or_lon (:obj:`float` or sequence): A single longitude/y value or a + + y_or_lon (:obj:`float` or sequence): A single longitude/y value or a sequence of longitude/y values to be converted. - + func (function): Either the xy_to_ll or ll_to_xy function. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - + stagger (:obj:`str`): By default, the values are returned on the mass - grid, but a staggered grid can be chosen with the following + grid, but a staggered grid can be chosen with the following options: - + - 'm': Use the mass grid (default). - - 'u': Use the same staggered grid as the u wind component, + - 'u': Use the same staggered grid as the u wind component, which has a staggered west_east (x) dimension. - - 'v': Use the same staggered grid as the v wind component, + - 'v': Use the same staggered grid as the v wind component, which has a staggered south_north (y) dimension. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - as_int (:obj:`bool`, optional): Set to True to return the x,y values as + as_int (:obj:`bool`, optional): Set to True to return the x,y values as :obj:`int`, otherwise they will be returned as :obj:`float`. This is only used when *func* is ll_to_xy. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - lat,lon/x,y coordinate value(s) whose leftmost dimensions are the - dictionary keys, followed by a dimension of size + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + lat,lon/x,y coordinate value(s) whose leftmost dimensions are the + dictionary keys, followed by a dimension of size 2 (0=X, 1=Y)/(0=lat, 1=lon). - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - + keynames = [] # This might not work once mapping iterators are implemented - numkeys = len(wrfin) - + numkeys = len(wrfin) + key_iter = iter(viewkeys(wrfin)) first_key = next(key_iter) keynames.append(first_key) - + first_args = [wrfin[first_key], x_or_lat, y_or_lon, timeidx, squeeze, meta, stagger] if as_int is not None: first_args.append(as_int) - + first_array = func(*first_args) - + # 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: try: @@ -254,25 +254,25 @@ def _llxy_mapping(wrfin, x_or_lat, y_or_lon, func, timeidx, stagger, break else: keynames.append(key) - + args = [wrfin[first_key], x_or_lat, y_or_lon, timeidx, squeeze, meta, stagger] if as_int is not None: args.append(as_int) - + result_array = func(*args) - + if outdata.shape[1:] != result_array.shape: raise ValueError("data sequences must have the " "same size for all dictionary keys") - outdata[idx,:] = to_np(result_array)[:] + outdata[idx, :] = to_np(result_array)[:] idx += 1 - + if xarray_enabled() and meta: outname = str(first_array.name) # Note: assumes that all entries in dict have same coords outcoords = OrderedDict(first_array.coords) - + # First find and store all the existing key coord names/values # This is applicable only if there are nested dictionaries. key_coordnames = [] @@ -280,164 +280,162 @@ def _llxy_mapping(wrfin, x_or_lat, y_or_lon, func, timeidx, stagger, existing_cnt = 0 while True: key_coord_name = "key_{}".format(existing_cnt) - + if key_coord_name not in first_array.dims: break - + key_coordnames.append(key_coord_name) coord_vals.append(to_np(first_array.coords[key_coord_name])) - + existing_cnt += 1 - + # Now add the key coord name and values for THIS dictionary. - # Put the new key_n name at the bottom, but the new values will + # Put the new key_n name at the bottom, but the new values will # be at the top to be associated with key_0 (left most). This - # effectively shifts the existing 'key_n' coordinate values to the - # right one dimension so *this* dicionary's key coordinate values + # effectively shifts the existing 'key_n' coordinate values to the + # right one dimension so *this* dicionary's key coordinate values # are at 'key_0'. key_coordnames.append(key_coord_name) coord_vals.insert(0, keynames) - + # 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, + + outarr = DataArray(outdata, name=outname, coords=outcoords, dims=outdims, attrs=outattrs) else: outarr = outdata - + return outarr -@set_latlon_metadata(xy=True) -def ll_to_xy(wrfin, latitude, longitude, timeidx=0, +@set_latlon_metadata(xy=True) +def ll_to_xy(wrfin, latitude, longitude, timeidx=0, squeeze=True, meta=True, stagger=None, as_int=True): """Return the x,y coordinates for a specified latitude and longitude. - - The *latitude* and *longitude* arguments can be a single value or a + + The *latitude* and *longitude* arguments can be a single value or a sequence of values. - - The leftmost dimension of the returned array represents two different + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain the X (west_east) values. - return_val[1,...] will contain the Y (south_north) values. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - latitude (:obj:`float` or sequence): A single latitude or a sequence + + latitude (:obj:`float` or sequence): A single latitude or a sequence of latitude values to be converted. - - longitude (:obj:`float` or sequence): A single longitude or a sequence + + longitude (:obj:`float` or sequence): A single longitude or a sequence of latitude values to be converted. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + stagger (:obj:`str`): By default, the latitude is returned on the mass - grid, but a staggered grid can be chosen with the following + grid, but a staggered grid can be chosen with the following options: - + - 'm': Use the mass grid (default). - - 'u': Use the same staggered grid as the u wind component, + - 'u': Use the same staggered grid as the u wind component, which has a staggered west_east (x) dimension. - - 'v': Use the same staggered grid as the v wind component, + - 'v': Use the same staggered grid as the v wind component, which has a staggered south_north (y) dimension. - - as_int (:obj:`bool`): Set to False to return the x,y values as + + as_int (:obj:`bool`): Set to False to return the x,y values as :obj:`float`, otherwise they will be returned as :obj:`int`. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The x,y coordinate value(s) whose leftmost dimension is 2 (0=X, 1=Y). - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ if is_mapping(wrfin): - return _llxy_mapping(wrfin, latitude, longitude, ll_to_xy, + return _llxy_mapping(wrfin, latitude, longitude, ll_to_xy, timeidx, stagger, squeeze, meta, as_int) _key = get_id(wrfin) _wrfin = get_iterable(wrfin) - return _ll_to_xy(latitude, longitude, _wrfin, timeidx, stagger, "cat", + return _ll_to_xy(latitude, longitude, _wrfin, timeidx, stagger, "cat", squeeze, None, _key, as_int, **{}) def _set_defaults(projparams): """Check projection parameters and set defaults. - - Throws an exception if projection parameters required by WPS are not + + Throws an exception if projection parameters required by WPS are not provided, along with any other parameters required by the map projection - transformation routines. - - For parameters not used by the projection type, defaults are used so that + transformation routines. + + For parameters not used by the projection type, defaults are used so that the None values don't pass through to fortran downstream. - + Args: - + projparams (:obj:`dict`): Projection parameters dictionary. - + Returns: - :obj:`dict`: The projection parameters with default values inserted + :obj:`dict`: The projection parameters with default values inserted where applicable. - + """ _params = dict(projparams) - + map_proj = _params.get("map_proj") # All projections require these arguments if map_proj is None: raise ValueError("'map_proj' cannot be None") - + if _params.get("ref_lat") is None: raise ValueError("'ref_lat' cannot be None") - + if _params.get("ref_lon") is None: raise ValueError("'ref_lon' cannot be None") - + if _params.get("known_x") is None: raise ValueError("'known_x' cannot be None") - + if _params.get("known_y") is None: raise ValueError("'known_y' cannot be None") - + if _params.get("dx") is None: raise ValueError("'dx' cannot be None") - + # Requires truelat1,stand_lon, truelat2, dx, dy if map_proj == ProjectionTypes.LAMBERT_CONFORMAL: if _params.get("truelat1") is None: raise ValueError("'truelat1' cannot be None") - + if _params.get("stand_lon") is None: raise ValueError("'stand_lon' cannot be None") - + if _params.get("truelat2") is None: _params["truelat2"] = _params["truelat1"] @@ -445,347 +443,341 @@ def _set_defaults(projparams): elif map_proj == ProjectionTypes.POLAR_STEREOGRAPHIC: if _params.get("truelat1") is None: raise ValueError("'truelat1' cannot be None") - + if _params.get("stand_lon") is None: raise ValueError("'stand_lon' cannot be None") - + # Requires truelat1 elif map_proj == ProjectionTypes.MERCATOR: if _params.get("truelat1") is None: raise ValueError("'truelat1' cannot be None") - + if _params.get("stand_lon") is None: _params["stand_lon"] = 0.0 - + # Requires pole_lat, pole_lon, stand_lon - elif map_proj == ProjectionTypes.LAT_LON: + elif map_proj == ProjectionTypes.LAT_LON: if _params.get("stand_lon") is None: raise ValueError("'stand_lon' cannot be None") - + if _params.get("dy") is None: raise ValueError("'dy' cannot be None") - + if _params.get("pole_lat") is None: raise ValueError("'pole_lat' cannot be None") - + if _params.get("pole_lon") is None: raise ValueError("'pole_lon' cannot be None") - + if _params.get("latinc") is None: - _params["latinc"] = ((_params["dy"]*360.0)/2.0 / - Constants.PI/Constants.WRF_EARTH_RADIUS) - + _params["latinc"] = ((_params["dy"]*360.0)/2.0 / + Constants.PI/Constants.WRF_EARTH_RADIUS) + if _params.get("loninc") is None: - _params["loninc"] = ((_params["dx"]*360.0)/2.0 / + _params["loninc"] = ((_params["dx"]*360.0)/2.0 / Constants.PI/Constants.WRF_EARTH_RADIUS) - + else: raise ValueError("invalid 'map_proj' value of {}".format(map_proj)) - + # Set these to defaults if not used so that the Fortran routines # don't crash if _params.get("truelat1") is None: _params["truelat1"] = 0. - + if _params.get("truelat2") is None: _params["truelat2"] = 0. - + if _params.get("pole_lat") is None: _params["pole_lat"] = 90.0 - + if _params.get("pole_lon") is None: _params["pole_lon"] = 0.0 - + if _params.get("dx") is None: _params["dx"] = 0.0 - + if _params.get("dy") is None: _params["dy"] = 0.0 - + if _params.get("latinc") is None: _params["latinc"] = 0. - + if _params.get("loninc") is None: _params["loninc"] = 0. - + return _params -@set_latlon_metadata(xy=True) +@set_latlon_metadata(xy=True) def ll_to_xy_proj(latitude, longitude, meta=True, squeeze=True, as_int=True, - map_proj=None, truelat1=None, truelat2=None, stand_lon=None, - ref_lat=None, ref_lon=None, pole_lat=None, pole_lon=None, - known_x=None, known_y=None, dx=None, dy=None, + map_proj=None, truelat1=None, truelat2=None, stand_lon=None, + ref_lat=None, ref_lon=None, pole_lat=None, pole_lon=None, + known_x=None, known_y=None, dx=None, dy=None, latinc=None, loninc=None): """Return the x, y coordinates for a specified latitude and longitude. - - The *latitude* and *longitude* arguments can be a single value or a - sequence of values. This version of the ll_to_xy routine allows users - to manually specify projection parameters. - - The leftmost dimension of the returned array represents two different + + The *latitude* and *longitude* arguments can be a single value or a + sequence of values. This version of the ll_to_xy routine allows users + to manually specify projection parameters. + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain the X (west_east) values. - return_val[1,...] will contain the Y (south_north) values. - + Args: - - latitude (:obj:`float` or sequence): A single latitude or a sequence + + latitude (:obj:`float` or sequence): A single latitude or a sequence of latitude values to be converted. - - longitude (:obj:`float` or sequence): A single longitude or a sequence + + longitude (:obj:`float` or sequence): A single longitude or a sequence of latitude values to be converted. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - as_int (:obj:`bool`): Set to False to return the x,y values as - :obj:`float`, otherwise they will be returned as :obj:`int`. + + as_int (:obj:`bool`): Set to False to return the x,y values as + :obj:`float`, otherwise they will be returned as :obj:`int`. Default is True. - - map_proj (:obj:`int`): Model projection [1=Lambert Conformal, + + map_proj (:obj:`int`): Model projection [1=Lambert Conformal, 2=Polar Stereographic, 3=Mercator, 6=Lat-Lon]. Required. - - truelat1 (:obj:`float`): Latitude of true scale 1. Required for + + truelat1 (:obj:`float`): Latitude of true scale 1. Required for map_proj = 1, 2, 3 (defaults to 0 otherwise). - - truelat2 (:obj:`float`): Latitude of true scale 2. Optional for + + truelat2 (:obj:`float`): Latitude of true scale 2. Optional for map_proj = 1 (defaults to 0 otherwise). - - stand_lon (:obj:`float`): Standard longitude. Required for *map_proj* = + + stand_lon (:obj:`float`): Standard longitude. Required for *map_proj* = 1, 2, 6 (defaults to 0 otherwise). - - ref_lat (:obj:`float`): A reference latitude. Required. - + + ref_lat (:obj:`float`): A reference latitude. Required. + ref_lon (:obj:`float`): A reference longitude. Required. - - known_x (:obj:`float`): The known x-coordinate associated with + + known_x (:obj:`float`): The known x-coordinate associated with *ref_lon*. Required. - - known_y (:obj:`float`): The known y-coordinate associated with + + known_y (:obj:`float`): The known y-coordinate associated with *ref_lat*. Required. - - pole_lat (:obj:`float`): Pole latitude. Required for + + pole_lat (:obj:`float`): Pole latitude. Required for *map_proj* = 6 (use 90 for no rotation). - - pole_lon (:obj:`float`): Pole longitude. Required for + + pole_lon (:obj:`float`): Pole longitude. Required for *map_proj* = 6 (use 0 for no rotation). - - dx (:obj:`float`): The x spacing in meters at the true latitude. + + dx (:obj:`float`): The x spacing in meters at the true latitude. Required for all map projections. - - dy (:obj:`float`) - The y spacing in meters at the true latitude. + + dy (:obj:`float`) - The y spacing in meters at the true latitude. Required for *map_proj* = 6 (defaults to 0 otherwise). - + latinc (:obj:`float`): Optional for *map_proj* = 6. Default is: - + .. code-block:: python - + latinc = (dy*360.0)/2.0/Constants.PI/Constants.WRF_EARTH_RADIUS - + loninc (:obj:`float`): Optional for *map_proj* = 6. Default is: - + .. code-block:: python - + loninc = (dx*360.0)/2.0/Constants.PI/Constants.WRF_EARTH_RADIUS Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The x,y coordinate value(s) whose leftmost dimension is 2 (0=X, 1=Y). - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ loc = locals() - _projparams = {name : loc[name] for name in ("map_proj", "truelat1", - "truelat2", "stand_lon", "ref_lat", - "ref_lon", "pole_lat", "pole_lon", - "known_x", "known_y", "dx", "dy", - "latinc", "loninc")} - + _projparams = {name: loc[name] for name in ("map_proj", "truelat1", + "truelat2", "stand_lon", + "ref_lat", "ref_lon", + "pole_lat", "pole_lon", + "known_x", "known_y", "dx", + "dy", "latinc", "loninc")} + projparams = _set_defaults(_projparams) return _ll_to_xy(latitude, longitude, None, 0, True, "cat", squeeze, None, None, as_int, **projparams) -@set_latlon_metadata(xy=False) +@set_latlon_metadata(xy=False) def xy_to_ll(wrfin, x, y, timeidx=0, squeeze=True, meta=True, stagger=None): """Return the latitude and longitude for specified x,y coordinates. - + The *x* and *y* arguments can be a single value or a sequence of values. - - The leftmost dimension of the returned array represents two different + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain the latitude values. - return_val[1,...] will contain the longitude values. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - x (:obj:`float` or sequence): A single x-coordinate or a sequence + + x (:obj:`float` or sequence): A single x-coordinate or a sequence of x-coordinate values to be converted. - - y (:obj:`float` or sequence): A single y-coordinate or a sequence + + y (:obj:`float` or sequence): A single y-coordinate or a sequence of y-coordinate values to be converted. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + stagger (:obj:`str`): By default, the latitude is returned on the mass - grid, but a staggered grid can be chosen with the following + grid, but a staggered grid can be chosen with the following options: - + - 'm': Use the mass grid (default). - - 'u': Use the same staggered grid as the u wind component, + - 'u': Use the same staggered grid as the u wind component, which has a staggered west_east (x) dimension. - - 'v': Use the same staggered grid as the v wind component, + - 'v': Use the same staggered grid as the v wind component, which has a staggered south_north (y) dimension. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - latitude and longitude values whose leftmost dimension is 2 + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + latitude and longitude values whose leftmost dimension is 2 (0=latitude, 1=longitude). - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ if is_mapping(wrfin): - return _llxy_mapping(wrfin, x, y, xy_to_ll, + return _llxy_mapping(wrfin, x, y, xy_to_ll, timeidx, stagger, squeeze, meta) - + _key = get_id(wrfin) _wrfin = get_iterable(wrfin) - return _xy_to_ll(x, y, _wrfin, timeidx, stagger, "cat", True, None, + return _xy_to_ll(x, y, _wrfin, timeidx, stagger, "cat", True, None, _key, **{}) - - -@set_latlon_metadata(xy=False) -def xy_to_ll_proj(x, y, meta=True, squeeze=True, map_proj=None, truelat1=None, - truelat2=None, stand_lon=None, ref_lat=None, ref_lon=None, - pole_lat=None, pole_lon=None, known_x=None, known_y=None, + + +@set_latlon_metadata(xy=False) +def xy_to_ll_proj(x, y, meta=True, squeeze=True, map_proj=None, truelat1=None, + truelat2=None, stand_lon=None, ref_lat=None, ref_lon=None, + pole_lat=None, pole_lon=None, known_x=None, known_y=None, dx=None, dy=None, latinc=None, loninc=None): """Return the latitude and longitude for the specified x,y coordinates. - - The *x* and *y* arguments can be a single value or a - sequence of values. This version of the xy_to_ll routine allows users - to manually specify map projection parameters. - - The leftmost dimension of the returned array represents two different + + The *x* and *y* arguments can be a single value or a + sequence of values. This version of the xy_to_ll routine allows users + to manually specify map projection parameters. + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain the latitude values. - return_val[1,...] will contain the longitude values. - + Args: - - x (:obj:`float` or sequence): A single x-coordinate or a sequence + + x (:obj:`float` or sequence): A single x-coordinate or a sequence of x-coordinate values to be converted. - - y (:obj:`float` or sequence): A single y-coordinate or a sequence + + y (:obj:`float` or sequence): A single y-coordinate or a sequence of y-coordinate values to be converted. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - map_proj (:obj:`int`): Model projection [1=Lambert Conformal, + + map_proj (:obj:`int`): Model projection [1=Lambert Conformal, 2=Polar Stereographic, 3=Mercator, 6=Lat-Lon]. Required. - - truelat1 (:obj:`float`): Latitude of true scale 1. Required for + + truelat1 (:obj:`float`): Latitude of true scale 1. Required for map_proj = 1, 2, 3 (defaults to 0 otherwise). - - truelat2 (:obj:`float`): Latitude of true scale 2. Optional for + + truelat2 (:obj:`float`): Latitude of true scale 2. Optional for map_proj = 1 (defaults to 0 otherwise). - - stand_lon (:obj:`float`): Standard longitude. Required for *map_proj* = + + stand_lon (:obj:`float`): Standard longitude. Required for *map_proj* = 1, 2, 6 (defaults to 0 otherwise). - - ref_lat (:obj:`float`): A reference latitude. Required. - + + ref_lat (:obj:`float`): A reference latitude. Required. + ref_lon (:obj:`float`): A reference longitude. Required. - - known_x (:obj:`float`): The known x-coordinate associated with + + known_x (:obj:`float`): The known x-coordinate associated with *ref_lon*. Required. - - known_y (:obj:`float`): The known y-coordinate associated with + + known_y (:obj:`float`): The known y-coordinate associated with *ref_lat*. Required. - - pole_lat (:obj:`float`): Pole latitude. Required for + + pole_lat (:obj:`float`): Pole latitude. Required for *map_proj* = 6 (use 90 for no rotation). - - pole_lon (:obj:`float`): Pole longitude. Required for + + pole_lon (:obj:`float`): Pole longitude. Required for *map_proj* = 6 (use 0 for no rotation). - - dx (:obj:`float`): The x spacing in meters at the true latitude. + + dx (:obj:`float`): The x spacing in meters at the true latitude. Required for all map projections. - - dy (:obj:`float`) - The y spacing in meters at the true latitude. + + dy (:obj:`float`) - The y spacing in meters at the true latitude. Required for *map_proj* = 6 (defaults to 0 otherwise). - + latinc (:obj:`float`): Optional for *map_proj* = 6. Default is: - + .. code-block:: python - + latinc = (dy*360.0)/2.0/Constants.PI/Constants.WRF_EARTH_RADIUS - + loninc (:obj:`float`): Optional for *map_proj* = 6. Default is: - + .. code-block:: python - + loninc = (dx*360.0)/2.0/Constants.PI/Constants.WRF_EARTH_RADIUS Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - latitude and longitude values whose leftmost dimension is 2 + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + latitude and longitude values whose leftmost dimension is 2 (0=latitude, 1=longitude). - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. """ loc = locals() - _projparams = {name : loc[name] for name in ("map_proj", "truelat1", - "truelat2", "stand_lon", "ref_lat", - "ref_lon", "pole_lat", "pole_lon", - "known_x", "known_y", "dx", "dy", - "latinc", "loninc")} - + _projparams = {name: loc[name] for name in ("map_proj", "truelat1", + "truelat2", "stand_lon", + "ref_lat", "ref_lon", + "pole_lat", "pole_lon", + "known_x", "known_y", "dx", + "dy", "latinc", "loninc")} + projparams = _set_defaults(_projparams) return _xy_to_ll(x, y, None, 0, None, "cat", squeeze, None, None, **projparams) - - - - - - - - \ No newline at end of file diff --git a/src/wrf/g_omega.py b/src/wrf/g_omega.py index 6bddfa3..f2f70ba 100755 --- a/src/wrf/g_omega.py +++ b/src/wrf/g_omega.py @@ -7,64 +7,64 @@ from .util import extract_vars from .metadecorators import copy_and_set_metadata -@copy_and_set_metadata(copy_varname="T", name="omega", +@copy_and_set_metadata(copy_varname="T", name="omega", description="omega", units="Pa s-1") def get_omega(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None): """Return Omega. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: Omega. - If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + :class:`xarray.DataArray` or :class:`numpy.ndarray`: Omega. + If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - varnames=("T", "P", "W", "PB", "QVAPOR") + varnames = ("T", "P", "W", "PB", "QVAPOR") ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, meta=False, _key=_key) t = ncvars["T"] @@ -72,13 +72,12 @@ def get_omega(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, w = ncvars["W"] pb = ncvars["PB"] qv = ncvars["QVAPOR"] - + wa = destagger(w, -3) full_t = t + Constants.T_BASE full_p = p + pb tk = _tk(full_p, full_t) - + omega = _omega(qv, tk, wa, full_p) - + return omega - \ No newline at end of file diff --git a/src/wrf/g_precip.py b/src/wrf/g_precip.py index aa75a80..0d5dbc8 100755 --- a/src/wrf/g_precip.py +++ b/src/wrf/g_precip.py @@ -2,29 +2,29 @@ from __future__ import (absolute_import, division, print_function) from .util import extract_vars -__all__ = ["get_accum_precip", "get_precip_diff"] def get_accum_precip(wrfin, timeidx=0): ncvars = extract_vars(wrfin, timeidx, varnames=("RAINC", "RAINNC")) rainc = ncvars["RAINC"] rainnc = ncvars["RAINNC"] - + rainsum = rainc + rainnc - + return rainsum + def get_precip_diff(wrfin1, wrfin2, timeidx=0): vars1 = extract_vars(wrfin1, timeidx, varnames=("RAINC", "RAINNC")) vars2 = extract_vars(wrfin2, timeidx, varnames=("RAINC", "RAINNC")) rainc1 = vars1["RAINC"] rainnc1 = vars1["RAINNC"] - + rainc2 = vars2["RAINC"] rainnc2 = vars2["RAINNC"] - + rainsum1 = rainc1 + rainnc1 rainsum2 = rainc2 + rainnc2 - + return (rainsum1 - rainsum2) # TODO: Handle bucket flipping diff --git a/src/wrf/g_pressure.py b/src/wrf/g_pressure.py index 44676ad..e93d807 100755 --- a/src/wrf/g_pressure.py +++ b/src/wrf/g_pressure.py @@ -5,144 +5,141 @@ from .metadecorators import copy_and_set_metadata from .util import extract_vars, either -@copy_and_set_metadata(copy_varname=either("P", "PRES"), name="pressure", +@copy_and_set_metadata(copy_varname=either("P", "PRES"), name="pressure", description="pressure") @convert_units("pressure", "pa") -def get_pressure(wrfin, timeidx=0, method="cat", squeeze=True, +def get_pressure(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="Pa"): - + """Return the pressure in the specified units. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'pres'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'pres'. Default is 'Pa'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The pressure in - the specified units. - If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The pressure in + the specified units. + If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ varname = either("P", "PRES")(wrfin) if varname == "P": - p_vars = extract_vars(wrfin, timeidx, ("P", "PB"), + p_vars = extract_vars(wrfin, timeidx, ("P", "PB"), method, squeeze, cache, meta=False, _key=_key) p = p_vars["P"] pb = p_vars["PB"] pres = p + pb else: - pres = extract_vars(wrfin, timeidx, "PRES", + pres = extract_vars(wrfin, timeidx, "PRES", method, squeeze, cache, meta=False, _key=_key)["PRES"] - + return pres -def get_pressure_hpa(wrfin, timeidx=0, method="cat", squeeze=True, + +def get_pressure_hpa(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None): """Return the pressure in [hPa]. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The pressure in - [hPa]. - If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The pressure in + [hPa]. + If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ return get_pressure(wrfin, timeidx, method, squeeze, cache, meta, _key, units="hPa") - - - - \ No newline at end of file diff --git a/src/wrf/g_pw.py b/src/wrf/g_pw.py index 73d6f74..b63d252 100755 --- a/src/wrf/g_pw.py +++ b/src/wrf/g_pw.py @@ -1,91 +1,86 @@ from __future__ import (absolute_import, division, print_function) -#from .extension import computepw,computetv,computetk from .extension import _pw, _tv, _tk from .constants import Constants from .util import extract_vars from .metadecorators import copy_and_set_metadata -@copy_and_set_metadata(copy_varname="T", name="pw", +@copy_and_set_metadata(copy_varname="T", name="pw", remove_dims=("bottom_top",), description="precipitable water", MemoryOrder="XY", units="kg m-2") -def get_pw(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, +def get_pw(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None): """Return the preciptiable water. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The preciptable - water. If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The preciptable + water. If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - varnames=("T", "P", "PB", "PH", "PHB", "QVAPOR") + varnames = ("T", "P", "PB", "PH", "PHB", "QVAPOR") ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, meta=False, _key=_key) - + t = ncvars["T"] p = ncvars["P"] pb = ncvars["PB"] ph = ncvars["PH"] phb = ncvars["PHB"] qv = ncvars["QVAPOR"] - + full_p = p + pb ht = (ph + phb)/Constants.G full_t = t + Constants.T_BASE - + tk = _tk(full_p, full_t) tv = _tv(tk, qv) - + return _pw(full_p, tv, qv, ht) - - - - \ No newline at end of file diff --git a/src/wrf/g_rh.py b/src/wrf/g_rh.py index 40f1263..21dd4aa 100755 --- a/src/wrf/g_rh.py +++ b/src/wrf/g_rh.py @@ -1,156 +1,154 @@ from __future__ import (absolute_import, division, print_function) -from .constants import Constants -#from .extension import computerh, computetk +from .constants import Constants from .extension import _rh, _tk from .util import extract_vars from .metadecorators import copy_and_set_metadata -@copy_and_set_metadata(copy_varname="T", name="rh", +@copy_and_set_metadata(copy_varname="T", name="rh", description="relative humidity", units="%") -def get_rh(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, +def get_rh(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None): """Return the relative humidity. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The relative - humidity. If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The relative + humidity. If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - varnames=("T", "P", "PB", "QVAPOR") + varnames = ("T", "P", "PB", "QVAPOR") ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, meta=False, _key=_key) t = ncvars["T"] p = ncvars["P"] pb = ncvars["PB"] - # Copy needed for the mmap nonsense of scipy.io.netcdf, which seems to + # Copy needed for the mmap nonsense of scipy.io.netcdf, which seems to # break with every release qvapor = ncvars["QVAPOR"].copy() - + full_t = t + Constants.T_BASE full_p = p + pb qvapor[qvapor < 0] = 0 tk = _tk(full_p, full_t) rh = _rh(qvapor, full_p, tk) - + return rh -@copy_and_set_metadata(copy_varname="T2", name="rh2", +@copy_and_set_metadata(copy_varname="T2", name="rh2", description="2m relative humidity", units="%") def get_rh_2m(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None): """Return the 2m relative humidity. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + Returns: :class:`xarray.DataArray` or :class:`numpy.ndarray`: The 2m relative - humidity. If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + humidity. If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - varnames=("T2", "PSFC", "Q2") + varnames = ("T2", "PSFC", "Q2") ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, meta=False, _key=_key) t2 = ncvars["T2"] psfc = ncvars["PSFC"] - # Copy needed for the mmap nonsense of scipy.io.netcdf, which seems to + # Copy needed for the mmap nonsense of scipy.io.netcdf, which seems to # break with every release q2 = ncvars["Q2"].copy() - + q2[q2 < 0] = 0 rh = _rh(q2, psfc, t2) - - return rh + return rh diff --git a/src/wrf/g_slp.py b/src/wrf/g_slp.py index a8f0e03..f422bed 100755 --- a/src/wrf/g_slp.py +++ b/src/wrf/g_slp.py @@ -1,6 +1,5 @@ from __future__ import (absolute_import, division, print_function) -#from .extension import computeslp, computetk from .extension import _slp, _tk from .constants import Constants from .destag import destagger @@ -10,94 +9,93 @@ from .util import extract_vars @copy_and_set_metadata(copy_varname="T", name="slp", - remove_dims=("bottom_top",), + remove_dims=("bottom_top",), description="sea level pressure", MemoryOrder="XY") @convert_units("pressure", "hpa") -def get_slp(wrfin, timeidx=0, method="cat", squeeze=True, +def get_slp(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="hPa"): - + """Return the sea level pressure in the specified units. - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'slp'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'slp'. Default is 'Pa'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The sea level - pressure in the specified units. If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The sea level + pressure in the specified units. If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - varnames=("T", "P", "PB", "QVAPOR", "PH", "PHB") + varnames = ("T", "P", "PB", "QVAPOR", "PH", "PHB") ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, meta=False, _key=_key) t = ncvars["T"] p = ncvars["P"] pb = ncvars["PB"] - # Copy needed for the mmap nonsense of scipy.io.netcdf, which seems to + # Copy needed for the mmap nonsense of scipy.io.netcdf, which seems to # break with every release qvapor = ncvars["QVAPOR"].copy() ph = ncvars["PH"] phb = ncvars["PHB"] - + full_t = t + Constants.T_BASE full_p = p + pb qvapor[qvapor < 0] = 0. - + full_ph = (ph + phb) / Constants.G - + destag_ph = destagger(full_ph, -3) - + tk = _tk(full_p, full_t) slp = _slp(destag_ph, tk, full_p, qvapor) - - return slp + return slp diff --git a/src/wrf/g_temp.py b/src/wrf/g_temp.py index f29969c..a4c6d93 100755 --- a/src/wrf/g_temp.py +++ b/src/wrf/g_temp.py @@ -7,70 +7,70 @@ from .metadecorators import copy_and_set_metadata from .util import extract_vars -@copy_and_set_metadata(copy_varname="T", name="theta", +@copy_and_set_metadata(copy_varname="T", name="theta", description="potential temperature") @convert_units("temp", "k") -def get_theta(wrfin, timeidx=0, method="cat", squeeze=True, +def get_theta(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="K"): """Return the potential temperature. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'theta'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'theta'. Default is 'K'. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The potential temperature. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - varnames = ("T",) - + varnames = ("T", ) + ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, meta=False, _key=_key) t = ncvars["T"] @@ -79,438 +79,435 @@ def get_theta(wrfin, timeidx=0, method="cat", squeeze=True, return full_t -@copy_and_set_metadata(copy_varname="T", name="temp", +@copy_and_set_metadata(copy_varname="T", name="temp", description="temperature") @convert_units("temp", "k") -def get_temp(wrfin, timeidx=0, method="cat", squeeze=True, +def get_temp(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="K"): """Return the temperature in the specified units. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'temp'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'temp'. Default is 'K'. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The temperature in the specified units. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - - varnames=("T", "P", "PB") + + varnames = ("T", "P", "PB") ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, meta=False, _key=_key) t = ncvars["T"] p = ncvars["P"] pb = ncvars["PB"] - + full_t = t + Constants.T_BASE full_p = p + pb tk = _tk(full_p, full_t) - + return tk -@copy_and_set_metadata(copy_varname="T", name="theta_e", +@copy_and_set_metadata(copy_varname="T", name="theta_e", description="equivalent potential temperature") @convert_units("temp", "K") -def get_eth(wrfin, timeidx=0, method="cat", squeeze=True, +def get_eth(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="K"): """Return the equivalent potential temperature. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'eth'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'eth'. Default is 'K'. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The equivalent potential temperature. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - - varnames=("T", "P", "PB", "QVAPOR") + + varnames = ("T", "P", "PB", "QVAPOR") ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, meta=False, _key=_key) t = ncvars["T"] p = ncvars["P"] pb = ncvars["PB"] qv = ncvars["QVAPOR"] - + full_t = t + Constants.T_BASE full_p = p + pb tk = _tk(full_p, full_t) - + eth = _eth(qv, tk, full_p) - + return eth -@copy_and_set_metadata(copy_varname="T", name="tv", +@copy_and_set_metadata(copy_varname="T", name="tv", description="virtual temperature") @convert_units("temp", "k") -def get_tv(wrfin, timeidx=0, method="cat", squeeze=True, +def get_tv(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="K"): """Return the virtual temperature. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'tv'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'tv'. Default is 'K'. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The virtual temperature. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - - varnames=("T", "P", "PB", "QVAPOR") + + varnames = ("T", "P", "PB", "QVAPOR") ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, meta=False, _key=_key) - + t = ncvars["T"] p = ncvars["P"] pb = ncvars["PB"] qv = ncvars["QVAPOR"] - + full_t = t + Constants.T_BASE full_p = p + pb tk = _tk(full_p, full_t) - + tv = _tv(tk, qv) - + return tv - - -@copy_and_set_metadata(copy_varname="T", name="twb", + + +@copy_and_set_metadata(copy_varname="T", name="twb", description="wetbulb temperature") @convert_units("temp", "k") -def get_tw(wrfin, timeidx=0, method="cat", squeeze=True, +def get_tw(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="K"): """Return the wetbulb temperature. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'twb'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'twb'. Default is 'K'. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wetbulb temperature. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - - varnames=("T", "P", "PB", "QVAPOR") + + varnames = ("T", "P", "PB", "QVAPOR") ncvars = extract_vars(wrfin, timeidx, varnames, method, squeeze, cache, meta=False, _key=_key) t = ncvars["T"] p = ncvars["P"] pb = ncvars["PB"] qv = ncvars["QVAPOR"] - + full_t = t + Constants.T_BASE full_p = p + pb - + tk = _tk(full_p, full_t) tw = _wetbulb(full_p, tk, qv) - + return tw -def get_tk(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, +def get_tk(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None): """Return the temperature in [K]. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The temperature in [K]. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - return get_temp(wrfin, timeidx, method, squeeze, cache, meta, _key, + return get_temp(wrfin, timeidx, method, squeeze, cache, meta, _key, units="K") def get_tc(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None): """Return the temperature in [degC]. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The temperature in [degC]. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ return get_temp(wrfin, timeidx, method, squeeze, cache, meta, _key, units="degC") - - - diff --git a/src/wrf/g_terrain.py b/src/wrf/g_terrain.py index 80910ed..c70110a 100755 --- a/src/wrf/g_terrain.py +++ b/src/wrf/g_terrain.py @@ -6,73 +6,70 @@ from .util import extract_vars, either # Need to handle either -@copy_and_set_metadata(copy_varname=either("HGT", "HGT_M"), name="terrain", +@copy_and_set_metadata(copy_varname=either("HGT", "HGT_M"), name="terrain", description="terrain height") @convert_units("height", "m") -def get_terrain(wrfin, timeidx=0, method="cat", squeeze=True, - cache=None, meta=False, _key=None, units="m"): +def get_terrain(wrfin, timeidx=0, method="cat", squeeze=True, + cache=None, meta=False, _key=None, units="m"): """Return the terrain height in the specified units. - - This functions extracts the necessary variables from the NetCDF file + + This functions extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'ter'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'ter'. Default is 'm'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The terrain - height in the specified units. If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The terrain + height in the specified units. If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ varname = either("HGT", "HGT_M")(wrfin) - - return extract_vars(wrfin, timeidx, varname, + + return extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key)[varname] - - - \ No newline at end of file diff --git a/src/wrf/g_times.py b/src/wrf/g_times.py index 3c46b19..7523a58 100755 --- a/src/wrf/g_times.py +++ b/src/wrf/g_times.py @@ -3,119 +3,118 @@ from __future__ import (absolute_import, division, print_function) from .util import extract_times -def get_times(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, +def get_times(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None): """Return a sequence of time objects. - - This function reads the 'Times' variable and creates a sequence of + + This function reads the 'Times' variable and creates a sequence of :class:`datetime.datetime` objects. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - + meta (:obj:`bool`, optional): Set to False to disable metadata. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: A sequence of - :class:`datetime.datetime` objects. If *meta* is True, the sequence - will be of type :class:`xarray.DataArray`, otherwise the sequence is + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: A sequence of + :class:`datetime.datetime` objects. If *meta* is True, the sequence + will be of type :class:`xarray.DataArray`, otherwise the sequence is :class:`numpy.ndarray`. - + """ - return extract_times(wrfin, timeidx, method, squeeze, cache, + return extract_times(wrfin, timeidx, method, squeeze, cache, meta=meta, do_xtime=False) -def get_xtimes(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, +def get_xtimes(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None): """Return a sequence of time objects. - - This function reads the 'XTIME' variable and creates a sequence of - :obj:`float` objects. - + + This function reads the 'XTIME' variable and creates a sequence of + :obj:`float` objects. + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - + meta (:obj:`bool`, optional): Set to False to disable metadata. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: A sequence of - :obj:`float` objects. If *meta* is True, the sequence will be of type - :class:`xarray.DataArray`, otherwise the sequence is + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: A sequence of + :obj:`float` objects. If *meta* is True, the sequence will be of type + :class:`xarray.DataArray`, otherwise the sequence is :class:`numpy.ndarray`. - + Raises: - - :class:`KeyError`: Raised if the 'XTIME' variable is not present + + :class:`KeyError`: Raised if the 'XTIME' variable is not present in the NetCDF file. - + """ - return extract_times(wrfin, timeidx, method, squeeze, cache, + return extract_times(wrfin, timeidx, method, squeeze, cache, meta=meta, do_xtime=True) - diff --git a/src/wrf/g_uvmet.py b/src/wrf/g_uvmet.py index dc1d0e0..b748120 100755 --- a/src/wrf/g_uvmet.py +++ b/src/wrf/g_uvmet.py @@ -4,7 +4,6 @@ from math import fabs, log, tan, sin, cos import numpy as np -#from .extension import computeuvmet from .extension import _uvmet from .destag import destagger from .constants import Constants @@ -15,83 +14,83 @@ from .util import extract_vars, extract_global_attrs, either @convert_units("wind", "m s-1") -def _get_uvmet(wrfin, timeidx=0, method="cat", squeeze=True, +def _get_uvmet(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, ten_m=False, units="m s-1"): """Return the u,v wind components rotated to earth coordinates. - - The leftmost dimension of the returned array represents two different + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain U_EARTH - return_val[1,...] will contain V_EARTH - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - ten_m (:obj:`bool`, optional): Set to True to use the 10m surface - winds, rather than the three-dimensional wind field. Default is + + ten_m (:obj:`bool`, optional): Set to True to use the 10m surface + winds, rather than the three-dimensional wind field. Default is False. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'uvmet'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'uvmet'. Default is 'm s-1'. - + Returns: - - :class:`numpy.ndarray`: The u,v components of the wind rotated to - earth coordinates, whose leftmost dimensions is 2 (0=U, 1=V). The - *meta* parameter is ignored for this function, so only a + + :class:`numpy.ndarray`: The u,v components of the wind rotated to + earth coordinates, whose leftmost dimensions is 2 (0=U, 1=V). The + *meta* parameter is ignored for this function, so only a :class:`numpy.ndarray` is returned. - + """ - + if not ten_m: varname = either("U", "UU")(wrfin) u_vars = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) - + u = destagger(u_vars[varname], -1) - + varname = either("V", "VV")(wrfin) v_vars = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) @@ -100,40 +99,40 @@ def _get_uvmet(wrfin, timeidx=0, method="cat", squeeze=True, varname = either("U10", "UU")(wrfin) u_vars = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) - u = (u_vars[varname] if varname == "U10" else - destagger(u_vars[varname][...,0,:,:], -1)) - + u = (u_vars[varname] if varname == "U10" else + destagger(u_vars[varname][..., 0, :, :], -1)) + varname = either("V10", "VV")(wrfin) v_vars = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) - v = (v_vars[varname] if varname == "V10" else - destagger(v_vars[varname][...,0,:,:], -2)) - + v = (v_vars[varname] if varname == "V10" else + destagger(v_vars[varname][..., 0, :, :], -2)) + map_proj_attrs = extract_global_attrs(wrfin, attrs="MAP_PROJ") map_proj = map_proj_attrs["MAP_PROJ"] - + # 1 - Lambert # 2 - Polar Stereographic # 3 - Mercator # 6 - Lat/Lon - # Note: NCL has no code to handle other projections (0,4,5) as they + # Note: NCL has no code to handle other projections (0,4,5) as they # don't appear to be supported any longer - - if map_proj in (0,3,6): + + if map_proj in (0, 3, 6): # No rotation needed for Mercator and Lat/Lon, but still need # u,v aggregated in to one array - + end_idx = -3 if not ten_m else -2 resdim = (2,) + u.shape[0:end_idx] + u.shape[end_idx:] - + # Make a new output array for the result result = np.empty(resdim, u.dtype) - + # For 2D array, this makes (0,...,:,:) and (1,...,:,:) # For 3D array, this makes (0,...,:,:,:) and (1,...,:,:,:) idx0 = (0,) + (Ellipsis,) + (slice(None),)*(-end_idx) idx1 = (1,) + (Ellipsis,) + (slice(None),)*(-end_idx) - + try: fill = u.fill_value except AttributeError: @@ -143,16 +142,16 @@ def _get_uvmet(wrfin, timeidx=0, method="cat", squeeze=True, result[idx0] = np.ma.filled(u[:], fill) result[idx1] = np.ma.filled(v[:], fill) result = np.ma.masked_values(result, fill) - + return result - elif map_proj in (1,2): + elif map_proj in (1, 2): lat_attrs = extract_global_attrs(wrfin, attrs=("TRUELAT1", "TRUELAT2")) radians_per_degree = Constants.PI/180.0 # Rotation needed for Lambert and Polar Stereographic true_lat1 = lat_attrs["TRUELAT1"] true_lat2 = lat_attrs["TRUELAT2"] - + try: lon_attrs = extract_global_attrs(wrfin, attrs="STAND_LON") except AttributeError: @@ -164,643 +163,641 @@ def _get_uvmet(wrfin, timeidx=0, method="cat", squeeze=True, cen_lon = cen_lon_attrs["CEN_LON"] else: cen_lon = lon_attrs["STAND_LON"] - - + varname = either("XLAT_M", "XLAT")(wrfin) - xlat_var = extract_vars(wrfin, timeidx, varname, + xlat_var = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) lat = xlat_var[varname] - + varname = either("XLONG_M", "XLONG")(wrfin) - xlon_var = extract_vars(wrfin, timeidx, varname, + xlon_var = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) lon = xlon_var[varname] - + if map_proj == 1: if((fabs(true_lat1 - true_lat2) > 0.1) and - (fabs(true_lat2 - 90.) > 0.1)): - cone = (log(cos(true_lat1*radians_per_degree)) - - log(cos(true_lat2*radians_per_degree))) - cone = (cone / - (log(tan((45.-fabs(true_lat1/2.))*radians_per_degree)) - - log(tan((45.-fabs(true_lat2/2.))*radians_per_degree)))) + (fabs(true_lat2 - 90.) > 0.1)): + cone = (log(cos(true_lat1*radians_per_degree)) - + log(cos(true_lat2*radians_per_degree))) + cone = (cone / + (log(tan((45.-fabs(true_lat1/2.))*radians_per_degree)) + - log(tan((45.-fabs(true_lat2/2.)) * + radians_per_degree)))) else: cone = sin(fabs(true_lat1)*radians_per_degree) else: cone = 1 - + result = _uvmet(u, v, lat, lon, cen_lon, cone) - + if squeeze: result = result.squeeze() - + return result - -@set_wind_metadata(copy_varname=either("P", "PRES"), + +@set_wind_metadata(copy_varname=either("P", "PRES"), name="uvmet", description="earth rotated u,v", - two_d=False, - wspd_wdir=False) -def get_uvmet(wrfin, timeidx=0, method="cat", squeeze=True, + two_d=False, + wspd_wdir=False) +def get_uvmet(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="m s-1"): """Return the u,v wind components rotated to earth coordinates. - - The leftmost dimension of the returned array represents two different + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain U_EARTH - return_val[1,...] will contain V_EARTH - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'uvmet'. Default + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'uvmet'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The u,v components - of the wind rotated to earth coordinates, whose leftmost dimensions is - 2 (0=U_EARTH, 1=V_EARTH). - If xarray is enabled and the *meta* parameter is True, - then the result will be a :class:`xarray.DataArray` object. Otherwise, + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The u,v components + of the wind rotated to earth coordinates, whose leftmost dimensions is + 2 (0=U_EARTH, 1=V_EARTH). + If xarray is enabled and the *meta* parameter is True, + then the result will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - + return _get_uvmet(wrfin, timeidx, method, squeeze, cache, meta, _key, False, units) -@set_wind_metadata(copy_varname=either("PSFC", "F"), +@set_wind_metadata(copy_varname=either("PSFC", "F"), name="uvmet10", description="10m earth rotated u,v", - two_d=True, + two_d=True, wspd_wdir=False) -def get_uvmet10(wrfin, timeidx=0, method="cat", squeeze=True, +def get_uvmet10(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="m s-1"): - """Return the u,v components for the 10m winds rotated to earth + """Return the u,v components for the 10m winds rotated to earth coordinates. - - The leftmost dimension of the returned array represents two different + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain U10_EARTH - return_val[1,...] will contain V10_EARTH - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'uvmet10'. + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'uvmet10'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The u,v components - of the 10m wind rotated to earth coordinates, whose leftmost dimensions - is 2 (0=U10_EARTH, 1=V10_EARTH). - If xarray is enabled and the *meta* parameter is - True, then the result will be a :class:`xarray.DataArray` object. - Otherwise, the result will be a :class:`numpy.ndarray` object with no + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The u,v components + of the 10m wind rotated to earth coordinates, whose leftmost dimensions + is 2 (0=U10_EARTH, 1=V10_EARTH). + If xarray is enabled and the *meta* parameter is + True, then the result will be a :class:`xarray.DataArray` object. + Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - - return _get_uvmet(wrfin, timeidx, method, squeeze, cache, meta, _key, + + return _get_uvmet(wrfin, timeidx, method, squeeze, cache, meta, _key, True, units) -@set_wind_metadata(copy_varname=either("P", "PRES"), +@set_wind_metadata(copy_varname=either("P", "PRES"), name="uvmet_wspd_wdir", description="earth rotated wspd,wdir", - two_d=False, + two_d=False, wspd_wdir=True) -def get_uvmet_wspd_wdir(wrfin, timeidx=0, method="cat", squeeze=True, +def get_uvmet_wspd_wdir(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="m s-1"): - """Return the wind speed and wind direction for the wind rotated to + """Return the wind speed and wind direction for the wind rotated to earth coordinates. - + This function should be used when comparing with observations. - - The leftmost dimension of the returned array represents two different + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain WSPD_EARTH - return_val[1,...] will contain WDIR_EARTH - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'uvmet_wspd_wdir'. + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'uvmet_wspd_wdir'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind speed and - wind direction for the wind rotated to earth coordinates, whose - leftmost dimensions is 2 (0=WSPD_EARTH, 1=WDIR_EARTH). If - xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind speed and + wind direction for the wind rotated to earth coordinates, whose + leftmost dimensions is 2 (0=WSPD_EARTH, 1=WDIR_EARTH). If + xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - - uvmet = _get_uvmet(wrfin, timeidx, method, squeeze, + + uvmet = _get_uvmet(wrfin, timeidx, method, squeeze, cache, meta, _key, False, units="m s-1") - - return _calc_wspd_wdir(uvmet[0,...,:,:,:], uvmet[1,...,:,:,:], + + return _calc_wspd_wdir(uvmet[0, ..., :, :, :], uvmet[1, ..., :, :, :], False, units) - -@set_wind_metadata(copy_varname=either("PSFC", "F"), + +@set_wind_metadata(copy_varname=either("PSFC", "F"), name="uvmet10_wspd_wdir", description="10m earth rotated wspd,wdir", - two_d=True, + two_d=True, wspd_wdir=True) -def get_uvmet10_wspd_wdir(wrfin, timeidx=0, method="cat", squeeze=True, +def get_uvmet10_wspd_wdir(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="m s-1"): - """Return the wind speed and wind direction for the 10m wind rotated to + """Return the wind speed and wind direction for the 10m wind rotated to earth coordinates. - + This function should be used when comparing with observations. - - The leftmost dimension of the returned array represents two different + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain WSPD10_EARTH - return_val[1,...] will contain WDIR10_EARTH - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'uvmet10_wspd_wdir'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind speed and - wind direction for the 10m wind rotated to earth coordinates, whose - leftmost dimensions is 2 (0=WSPD10_EARTH, 1=WDIR10_EARTH). If - xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind speed and + wind direction for the 10m wind rotated to earth coordinates, whose + leftmost dimensions is 2 (0=WSPD10_EARTH, 1=WDIR10_EARTH). If + xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - - uvmet10 = _get_uvmet(wrfin, timeidx, method, squeeze, cache, meta, _key, + + uvmet10 = _get_uvmet(wrfin, timeidx, method, squeeze, cache, meta, _key, True, units="m s-1") - - return _calc_wspd_wdir(uvmet10[0,...,:,:], uvmet10[1,...,:,:], True, units) - -def get_uvmet_wspd(wrfin, timeidx=0, method="cat", squeeze=True, + return _calc_wspd_wdir(uvmet10[0, ..., :, :], uvmet10[1, ..., :, :], + True, units) + + +def get_uvmet_wspd(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="m s-1"): """Return the wind speed for the wind rotated to earth coordinates. - + This function should be used when comparing with observations. - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'uvmet_wspd_wdir'. + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'uvmet_wspd_wdir'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind speed - for the wind rotated to earth coordinates. If - xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind speed + for the wind rotated to earth coordinates. If + xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - result = get_uvmet_wspd_wdir(wrfin, timeidx, method, squeeze, - cache, meta, _key, units)[0,:] - + result = get_uvmet_wspd_wdir(wrfin, timeidx, method, squeeze, + cache, meta, _key, units)[0, :] + if meta: result.attrs["description"] = "earth rotated wspd" - + return result - - -def get_uvmet_wdir(wrfin, timeidx=0, method="cat", squeeze=True, + + +def get_uvmet_wdir(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="m s-1"): """Return the wind direction for the wind rotated to earth coordinates. - + This function should be used when comparing with observations. - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'uvmet_wspd_wdir'. + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'uvmet_wspd_wdir'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind direction - for the wind rotated to earth coordinates. If - xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind direction + for the wind rotated to earth coordinates. If + xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - result = get_uvmet_wspd_wdir(wrfin, timeidx, method, squeeze, - cache, meta, _key, units)[1,:] - + result = get_uvmet_wspd_wdir(wrfin, timeidx, method, squeeze, + cache, meta, _key, units)[1, :] + if meta: result.attrs["description"] = "earth rotated wdir" - + return result - - -def get_uvmet10_wspd(wrfin, timeidx=0, method="cat", squeeze=True, - cache=None, meta=True, _key=None, - units="m s-1"): + + +def get_uvmet10_wspd(wrfin, timeidx=0, method="cat", squeeze=True, + cache=None, meta=True, _key=None, + units="m s-1"): """Return the wind speed for the 10m wind rotated to earth coordinates. - + This function should be used when comparing with observations. - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'uvmet_wspd_wdir'. + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'uvmet_wspd_wdir'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind speed - for the 10m wind rotated to earth coordinates. If - xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind speed + for the 10m wind rotated to earth coordinates. If + xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - result = get_uvmet10_wspd_wdir(wrfin, timeidx, method, squeeze, - cache, meta, _key, units)[0,:] + result = get_uvmet10_wspd_wdir(wrfin, timeidx, method, squeeze, + cache, meta, _key, units)[0, :] if meta: result.attrs["description"] = "10m earth rotated wspd" - + return result - - -def get_uvmet10_wdir(wrfin, timeidx=0, method="cat", squeeze=True, - cache=None, meta=True, _key=None, - units="m s-1"): + + +def get_uvmet10_wdir(wrfin, timeidx=0, method="cat", squeeze=True, + cache=None, meta=True, _key=None, + units="m s-1"): """Return the wind direction for the 10m wind rotated to earth coordinates. - + This function should be used when comparing with observations. - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'uvmet_wspd_wdir'. + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'uvmet_wspd_wdir'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind direction - for the 10m wind rotated to earth coordinates. If - xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind direction + for the 10m wind rotated to earth coordinates. If + xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - result = get_uvmet10_wspd_wdir(wrfin, timeidx, method, squeeze, - cache, meta, _key, units)[1,:] - + result = get_uvmet10_wspd_wdir(wrfin, timeidx, method, squeeze, + cache, meta, _key, units)[1, :] + if meta: result.attrs["description"] = "10m earth rotated wdir" - + return result - - - \ No newline at end of file diff --git a/src/wrf/g_vorticity.py b/src/wrf/g_vorticity.py index 660f688..0d00a12 100755 --- a/src/wrf/g_vorticity.py +++ b/src/wrf/g_vorticity.py @@ -5,69 +5,69 @@ from .util import extract_vars, extract_global_attrs from .metadecorators import copy_and_set_metadata -@copy_and_set_metadata(copy_varname="T", name="avo", +@copy_and_set_metadata(copy_varname="T", name="avo", description="absolute vorticity", units="10-5 s-1") -def get_avo(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, +def get_avo(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None): """Return the absolute vorticity. - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The absolute - vorticity. If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The absolute + vorticity. If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ ncvars = extract_vars(wrfin, timeidx, ("U", "V", "MAPFAC_U", "MAPFAC_V", "MAPFAC_M", "F"), method, squeeze, cache, meta=False, _key=_key) - + attrs = extract_global_attrs(wrfin, attrs=("DX", "DY")) u = ncvars["U"] v = ncvars["V"] @@ -75,70 +75,70 @@ def get_avo(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, msfv = ncvars["MAPFAC_V"] msfm = ncvars["MAPFAC_M"] cor = ncvars["F"] - + dx = attrs["DX"] dy = attrs["DY"] - + return _avo(u, v, msfu, msfv, msfm, cor, dx, dy) -@copy_and_set_metadata(copy_varname="T", name="pvo", +@copy_and_set_metadata(copy_varname="T", name="pvo", description="potential vorticity", units="PVU") -def get_pvo(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, +def get_pvo(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None): """Return the potential vorticity. - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The potential - vorticity. If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The potential + vorticity. If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ ncvars = extract_vars(wrfin, timeidx, ("U", "V", "T", "P", "PB", "MAPFAC_U", @@ -146,7 +146,7 @@ def get_pvo(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, "F"), method, squeeze, cache, meta=False, _key=_key) attrs = extract_global_attrs(wrfin, attrs=("DX", "DY")) - + u = ncvars["U"] v = ncvars["V"] t = ncvars["T"] @@ -156,12 +156,11 @@ def get_pvo(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, msfv = ncvars["MAPFAC_V"] msfm = ncvars["MAPFAC_M"] cor = ncvars["F"] - + dx = attrs["DX"] dy = attrs["DY"] - + full_t = t + 300 full_p = p + pb - + return _pvo(u, v, full_t, full_p, msfu, msfv, msfm, cor, dx, dy) - \ No newline at end of file diff --git a/src/wrf/g_wind.py b/src/wrf/g_wind.py index 9edaeea..bdfbca1 100755 --- a/src/wrf/g_wind.py +++ b/src/wrf/g_wind.py @@ -12,776 +12,773 @@ from .metadecorators import set_wind_metadata @convert_units("wind", "m s-1") def _calc_wspd(u, v, units="m s-1"): """Return the wind speed. - + Args: - + u (:class:`numpy.ndarray`): The u component of the wind. - + v (:class:`numpy.ndarray`): The v component of the wind. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'uvmet_wspd_wdir'. + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'uvmet_wspd_wdir'. Default is 'm s-1'. - + Returns: - + :class:`numpy.ndarray`: The wind speed. - + """ return _wspd(u, v) def _calc_wdir(u, v): """Return the wind direction. - + Args: - + u (:class:`numpy.ndarray`): The u component of the wind. - + v (:class:`numpy.ndarray`): The v component of the wind. - + Returns: - + :class:`numpy.ndarray`: The wind direction. - + """ return _wdir(u, v) def _calc_wspd_wdir(u, v, two_d, units): """Return the wind speed and wind direction. - - The leftmost dimension of the returned array represents two different + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain WSPD - return_val[1,...] will contain WDIR - + Args: - + u (:class:`numpy.ndarray`): The u component of the wind. - + v (:class:`numpy.ndarray`): The v component of the wind. - - two_d (:obj:`bool`): Set to True if the u,v wind components are + + two_d (:obj:`bool`): Set to True if the u,v wind components are for a two-dimensional array (no height dimension). Otherwise, set to False. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'uvmet_wspd_wdir'. + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'uvmet_wspd_wdir'. Default is 'm s-1'. - + Returns: - - :class:`numpy.ndarray`: The wind speed and wind direction, whose + + :class:`numpy.ndarray`: The wind speed and wind direction, whose leftmost dimension is 2 (0=WSPD, 1=WDIR). - + """ wspd = _calc_wspd(u, v, units) wdir = _calc_wdir(u, v) - + try: fill = wspd.fill_value except AttributeError: fill = None idx_end = -2 if two_d else -3 - + outdims = [2] + list(wspd.shape[0:idx_end]) + list(wspd.shape[idx_end:]) - + result = np.zeros(outdims, wspd.dtype) - - idxs0 = ((0,Ellipsis, slice(None), slice(None), slice(None)) - if not two_d else - (0, Ellipsis, slice(None), slice(None))) - - idxs1 = ((1, Ellipsis, slice(None), slice(None), slice(None)) - if not two_d else - (1, Ellipsis, slice(None), slice(None))) - + + idxs0 = ((0, Ellipsis, slice(None), slice(None), slice(None)) + if not two_d else (0, Ellipsis, slice(None), slice(None))) + + idxs1 = ((1, Ellipsis, slice(None), slice(None), slice(None)) + if not two_d else (1, Ellipsis, slice(None), slice(None))) + result[idxs0] = wspd[:] result[idxs1] = wdir[:] - + if fill is not None: result = np.ma.masked_equal(result, fill) - + return result -@set_wind_metadata(copy_varname=either("P", "PRES"), +@set_wind_metadata(copy_varname=either("P", "PRES"), name="ua", description="destaggered u-wind component", - wind_ncvar=True, - two_d=False, + wind_ncvar=True, + two_d=False, wspd_wdir=False) @convert_units("wind", "m s-1") -def get_u_destag(wrfin, timeidx=0, method="cat", squeeze=True, +def get_u_destag(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="m s-1"): """Return the u-component of the wind on mass points. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'wspd_wdir'. + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'wspd_wdir'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The u-component - of the wind. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The u-component + of the wind. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ varname = either("U", "UU")(wrfin) u_vars = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) u = destagger(u_vars[varname], -1) - + return u -@set_wind_metadata(copy_varname=either("P", "PRES"), +@set_wind_metadata(copy_varname=either("P", "PRES"), name="va", description="destaggered v-wind component", two_d=False, - wind_ncvar=True, + wind_ncvar=True, wspd_wdir=False) @convert_units("wind", "m s-1") -def get_v_destag(wrfin, timeidx=0, method="cat", squeeze=True, +def get_v_destag(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="m s-1"): """Return the v-component of the wind on mass points. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'wspd_wdir'. + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'wspd_wdir'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The v-component - of the wind. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The v-component + of the wind. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ varname = either("V", "VV")(wrfin) v_vars = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) v = destagger(v_vars[varname], -2) - + return v -@set_wind_metadata(copy_varname=either("P", "PRES"), +@set_wind_metadata(copy_varname=either("P", "PRES"), name="wa", description="destaggered w-wind component", two_d=False, - wind_ncvar=True, + wind_ncvar=True, wspd_wdir=False) @convert_units("wind", "m s-1") -def get_w_destag(wrfin, timeidx=0, method="cat", squeeze=True, +def get_w_destag(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="m s-1"): """Return the w-component of the wind on mass points. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'wspd_wdir'. + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'wspd_wdir'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The w-component - of the wind. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The w-component + of the wind. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - w_vars = extract_vars(wrfin, timeidx, "W", method, squeeze, cache, + w_vars = extract_vars(wrfin, timeidx, "W", method, squeeze, cache, meta=False, _key=_key) w = destagger(w_vars["W"], -3) return w -@set_wind_metadata(copy_varname=either("P", "PRES"), +@set_wind_metadata(copy_varname=either("P", "PRES"), name="wspd_wdir", description="wspd,wdir in projection space", - two_d=False, + two_d=False, wspd_wdir=True) -def get_destag_wspd_wdir(wrfin, timeidx=0, method="cat", +def get_destag_wspd_wdir(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="m s-1"): """Return the wind speed and wind direction for the wind in the projected - coordinate (i.e. grid) space. - - The wind speed and direction from this function will be relative to the - grid. This function should not be used to compare with observations, - instead use :meth:`wrf.uvmet10_wspd_wdir` to get the earth relative wind + coordinate (i.e. grid) space. + + The wind speed and direction from this function will be relative to the + grid. This function should not be used to compare with observations, + instead use :meth:`wrf.uvmet10_wspd_wdir` to get the earth relative wind speed and direction. - - The leftmost dimension of the returned array represents two different + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain WSPD - return_val[1,...] will contain WDIR - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'wspd_wdir'. + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'wspd_wdir'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind speed and - wind direction for the wind in projected space, whose - leftmost dimensions is 2 (0=WSPD, 1=WDIR). If - xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind speed and + wind direction for the wind in projected space, whose + leftmost dimensions is 2 (0=WSPD, 1=WDIR). If + xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ varname = either("U", "UU")(wrfin) u_vars = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) u = destagger(u_vars[varname], -1) - + varname = either("V", "VV")(wrfin) v_vars = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) v = destagger(v_vars[varname], -2) - + return _calc_wspd_wdir(u, v, False, units) -@set_wind_metadata(copy_varname=either("PSFC", "F"), +@set_wind_metadata(copy_varname=either("PSFC", "F"), name="wspd_wdir10", description="10m wspd,wdir in projection space", - two_d=False, + two_d=False, wspd_wdir=True) -def get_destag_wspd_wdir10(wrfin, timeidx=0, method="cat", - squeeze=True, cache=None, meta=True, _key=None, +def get_destag_wspd_wdir10(wrfin, timeidx=0, method="cat", + squeeze=True, cache=None, meta=True, _key=None, units="m s-1"): - """Return the wind speed and wind direction for the 10m wind in + """Return the wind speed and wind direction for the 10m wind in projected coordinate (i.e. grid) space. - - The wind speed and direction from this function will be relative to the - grid. This function should not be used to compare with observations, - instead use :meth:`wrf.uvmet10_wspd_wdir` to get the earth relative wind - speed and direction. - - The leftmost dimension of the returned array represents two different + + The wind speed and direction from this function will be relative to the + grid. This function should not be used to compare with observations, + instead use :meth:`wrf.uvmet10_wspd_wdir` to get the earth relative wind + speed and direction. + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain WSPD10 - return_val[1,...] will contain WDIR10 - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'wspd_wdir10'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind speed and - wind direction for the 10m wind in projected space, whose - leftmost dimensions is 2 (0=WSPD10, 1=WDIR10). If - xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind speed and + wind direction for the 10m wind in projected space, whose + leftmost dimensions is 2 (0=WSPD10, 1=WDIR10). If + xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - + varname = either("U10", "UU")(wrfin) u_vars = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) - u = (u_vars[varname] if varname == "U10" else - destagger(u_vars[varname][...,0,:,:], -1)) - + u = (u_vars[varname] if varname == "U10" else + destagger(u_vars[varname][..., 0, :, :], -1)) + varname = either("V10", "VV")(wrfin) v_vars = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=False, _key=_key) - v = (v_vars[varname] if varname == "V10" else - destagger(v_vars[varname][...,0,:,:], -2)) - + v = (v_vars[varname] if varname == "V10" else + destagger(v_vars[varname][..., 0, :, :], -2)) + return _calc_wspd_wdir(u, v, True, units) -def get_destag_wspd(wrfin, timeidx=0, method="cat", +def get_destag_wspd(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="m s-1"): - """Return the wind speed in the projected coordinate (i.e. grid) space. - - This function extracts the necessary variables from the NetCDF file + """Return the wind speed in the projected coordinate (i.e. grid) space. + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'wspd_wdir'. + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'wspd_wdir'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind - speed in projected space. If - xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind + speed in projected space. If + xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - result = get_destag_wspd_wdir(wrfin, timeidx, method, squeeze, cache, - meta, _key, units)[0,:] - + result = get_destag_wspd_wdir(wrfin, timeidx, method, squeeze, cache, + meta, _key, units)[0, :] + if meta: result.attrs["description"] = "wspd in projection space" - + return result - - -def get_destag_wdir(wrfin, timeidx=0, method="cat", + + +def get_destag_wdir(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, meta=True, _key=None, units="m s-1"): """Return the wind direction in the projected coordinate (i.e. grid) space. - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for 'wspd_wdir'. + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'wspd_wdir'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind - direction in projected space. If - xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind + direction in projected space. If + xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - result = get_destag_wspd_wdir(wrfin, timeidx, method, squeeze, cache, - meta, _key, units)[1,:] - + result = get_destag_wspd_wdir(wrfin, timeidx, method, squeeze, cache, + meta, _key, units)[1, :] + if meta: result.attrs["description"] = "wdir in projection space" - + return result - - -def get_destag_wspd10(wrfin, timeidx=0, method="cat", - squeeze=True, cache=None, meta=True, _key=None, + + +def get_destag_wspd10(wrfin, timeidx=0, method="cat", + squeeze=True, cache=None, meta=True, _key=None, units="m s-1"): - """Return the wind speed for the 10m wind in projected coordinate + """Return the wind speed for the 10m wind in projected coordinate (i.e. grid) space. - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'wspd_wdir10'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind speed - for the 10m wind in projected space. If - xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind speed + for the 10m wind in projected space. If + xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - result = get_destag_wspd_wdir10(wrfin, timeidx, method, - squeeze, cache, meta, _key, units)[0,:] - + result = get_destag_wspd_wdir10(wrfin, timeidx, method, + squeeze, cache, meta, _key, units)[0, :] + if meta: result.attrs["description"] = "10m wspd in projection space" - + return result - - -def get_destag_wdir10(wrfin, timeidx=0, method="cat", - squeeze=True, cache=None, meta=True, _key=None, + + +def get_destag_wdir10(wrfin, timeidx=0, method="cat", + squeeze=True, cache=None, meta=True, _key=None, units="m s-1"): - """Return the wind direction for the 10m wind in projected coordinate + """Return the wind direction for the 10m wind in projected coordinate (i.e. grid) space. - - This function extracts the necessary variables from the NetCDF file + + This function extracts the necessary variables from the NetCDF file object in order to perform the calculation. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - units (:obj:`str`): The desired units. Refer to the :meth:`getvar` - product table for a list of available units for + + units (:obj:`str`): The desired units. Refer to the :meth:`getvar` + product table for a list of available units for 'wspd_wdir10'. Default is 'm s-1'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind direction - for the 10m wind in projected space. If - xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wind direction + for the 10m wind in projected space. If + xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - result = get_destag_wspd_wdir10(wrfin, timeidx, method, - squeeze, cache, meta, _key, units)[1,:] - + result = get_destag_wspd_wdir10(wrfin, timeidx, method, + squeeze, cache, meta, _key, units)[1, :] + if meta: result.attrs["description"] = "10m wdir in projection space" - + return result - diff --git a/src/wrf/geobnds.py b/src/wrf/geobnds.py index 2014b5c..5dff84c 100644 --- a/src/wrf/geobnds.py +++ b/src/wrf/geobnds.py @@ -2,46 +2,47 @@ from __future__ import (absolute_import, division, print_function) from .coordpair import CoordPair + class GeoBounds(object): """A class that stores the geographic boundaries. - - Currently, only corner points are used, specified as the bottom left and - top right corners. Users can specify the corner points directly, or + + Currently, only corner points are used, specified as the bottom left and + top right corners. Users can specify the corner points directly, or specify two-dimensional latitude and longitude arrays and the corner points will be extracted from them. - + Attributes: - + bottom_left (:class:`wrf.CoordPair`): The bottom left coordinate. top_right (:class:`wrf.CoordPair`): The top right coordinate. - + """ def __init__(self, bottom_left=None, top_right=None, lats=None, lons=None): """ Initialize a :class:`wrf.GeoBounds` object. - - Args: - - bottom_left (:class:`wrf.CoordPair`, optional): The lower left - corner. Must also specify *top_right* if used. + + Args: + + bottom_left (:class:`wrf.CoordPair`, optional): The lower left + corner. Must also specify *top_right* if used. Default is None. - - top_right (:class:`wrf.CoordPair`, optional): The upper right - corner. Must also specify *bottom_left* if used. + + top_right (:class:`wrf.CoordPair`, optional): The upper right + corner. Must also specify *bottom_left* if used. Default is None. - - lats (:class:`numpy.ndarray`, optional): An array of at least - two dimensions containing all of the latitude values. Must + + lats (:class:`numpy.ndarray`, optional): An array of at least + two dimensions containing all of the latitude values. Must also specify *lons* if used. Default is None. - - lons (:class:`numpy.ndarray`, optional): An array of at least - two dimensions containing all of the longitude values. Must + + lons (:class:`numpy.ndarray`, optional): An array of at least + two dimensions containing all of the longitude values. Must also specify *lats* if used. Default is None. - + """ if bottom_left is not None and top_right is not None: self.bottom_left = bottom_left self.top_right = top_right - + # Make sure the users set lat/lon coordinates if self.bottom_left.lat is None: raise ValueError("'bottom_left' parameter does not contain a " @@ -56,35 +57,31 @@ 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 " "or 'lats' and 'lons' parameters") - + def __repr__(self): - argstr = "{}, {}".format(repr(self.bottom_left), + argstr = "{}, {}".format(repr(self.bottom_left), repr(self.top_right)) - + return "{}({})".format(self.__class__.__name__, argstr) - + class NullGeoBounds(GeoBounds): """An emtpy :class:`wrf.GeoBounds` subclass. - - This is used for initializing arrays of :class:`wrf.GeoBounds`, in - particular when working with moving domains and variables combined with the + + This is used for initializing arrays of :class:`wrf.GeoBounds`, in + particular when working with moving domains and variables combined with the 'join' method. - + """ def __init__(self): """ Initialize a :class:`wrf.NullGeoBounds` object.""" pass - + def __repr__(self): return "{}()".format(self.__class__.__name__) - - - - \ No newline at end of file diff --git a/src/wrf/interp.py b/src/wrf/interp.py index d875fd1..0e004bc 100755 --- a/src/wrf/interp.py +++ b/src/wrf/interp.py @@ -3,7 +3,7 @@ from __future__ import (absolute_import, division, print_function) import numpy as np import numpy.ma as ma -from .extension import (_interpz3d, _vertcross, _interpline, _smooth2d, +from .extension import (_interpz3d, _vertcross, _interpline, _smooth2d, _monotonic, _vintrp, _interpz3d_lev2d) from .metadecorators import set_interp_metadata @@ -20,71 +20,84 @@ from wrf.g_pressure import get_pressure # Note: Extension decorator is good enough to handle left dims @set_interp_metadata("horiz") -def interplevel(field3d, vert, desiredlev, missing=default_fill(np.float64), +def interplevel(field3d, vert, desiredlev, missing=default_fill(np.float64), squeeze=True, meta=True): - """Return the three-dimensional field interpolated to a horizontal plane + """Return the three-dimensional field interpolated to a horizontal plane at the specified vertical level. Args: - - field3d (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A - three-dimensional field to interpolate, with the rightmost + + field3d (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A + three-dimensional field to interpolate, with the rightmost dimensions of nz x ny x nx. - - vert (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A - three-dimensional array for the vertical coordinate, typically + + vert (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A + three-dimensional array for the vertical coordinate, typically pressure or height. This array must have the same dimensionality as *field3d*. - - desiredlev (:obj:`float`, 1D sequence, or :class:`numpy.ndarray`): The - desired vertical level(s). This can be a single value (e.g. 500), - a sequence of values (e.g. [1000, 850, 700, 500, 250]), or a - multidimensional array where the right two dimensions (ny x nx) - must match *field3d*, and any leftmost dimensions match - field3d.shape[:-3] (e.g. planetary boundary layer). + + desiredlev (:obj:`float`, 1D sequence, or :class:`numpy.ndarray`): The + desired vertical level(s). This can be a single value (e.g. 500), + a sequence of values (e.g. [1000, 850, 700, 500, 250]), or a + multidimensional array where the right two dimensions (ny x nx) + must match *field3d*, and any leftmost dimensions match + field3d.shape[:-3] (e.g. planetary boundary layer). Must be in the same units as the *vert* parameter. - - missing (:obj:`float`): The fill value to use for the output. + + missing (:obj:`float`): The fill value to use for the output. Default is :data:`wrf.default_fill(numpy.float64)`. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - meta (:obj:`bool`): Set to False to disable metadata and return - :class:`numpy.ndarray` instead of + + meta (:obj:`bool`): Set to False to disable metadata and return + :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - interpolated variable. If xarray is enabled and - the *meta* parameter is True, then the result will be an - :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + interpolated variable. If xarray is enabled and + the *meta* parameter is True, then the result will be an + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + Example: - + Interpolate Geopotential Height to 500 hPa - + .. code-block:: python - + from netCDF4 import Dataset from wrf import getvar, interplevel - + wrfin = Dataset("wrfout_d02_2010-06-13_21:00:00") - + p = getvar(wrfin, "pressure") ht = getvar(wrfin, "z", units="dm") - pblh = getvar(wrfin, "PBLH") - + ht_500 = interplevel(ht, p, 500.0) - - - - + + + Interpolate Relative Humidity to Boundary Layer Heights + + .. code-block:: python + + from netCDF4 import Dataset + from wrf import getvar, interplevel + + wrfin = Dataset("wrfout_d02_2010-06-13_21:00:00") + + rh = getvar(wrfin, "rh") + z = getvar(wrfin, "z") + pblh = getvar(wrfin, "PBLH") + + rh_pblh = interplevel(rh, p, pblh) + + """ - + _desiredlev = np.asarray(desiredlev) if _desiredlev.ndim == 0: _desiredlev = np.array([desiredlev], np.float64) @@ -96,13 +109,13 @@ def interplevel(field3d, vert, desiredlev, missing=default_fill(np.float64), result = _interpz3d(field3d, vert, _desiredlev, missing) 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: return masked.squeeze() - + return masked @@ -114,154 +127,154 @@ def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64), start_point=None, end_point=None, latlon=False, autolevels=100, cache=None, meta=True): """Return the vertical cross section for a three-dimensional field. - - The cross section is defined by a horizontal line through the domain. - This horizontal line is defined by either including the - *pivot_point* and *angle* parameters, or the *start_point* and - *end_point* parameters. The *pivot_point*, *start_point*, and *end_point* - coordinates can be defined in either x,y or latitude,longitude space. - If latitude,longitude coordinates are used, then a WRF input file or + + The cross section is defined by a horizontal line through the domain. + This horizontal line is defined by either including the + *pivot_point* and *angle* parameters, or the *start_point* and + *end_point* parameters. The *pivot_point*, *start_point*, and *end_point* + coordinates can be defined in either x,y or latitude,longitude space. + If latitude,longitude coordinates are used, then a WRF input file or map projection must also be specified. - - The vertical levels for the cross section are fixed if *levels* is not - specified, and are determined by dividing the vertical coordinate in to - grid boxes of roughly 1% of the maximum vertical distance from top to - bottom. Otherwise, the *levels* argument can be used to specify specific - vertical levels. If all vertical levels are desired, use the raw + + The vertical levels for the cross section are fixed if *levels* is not + specified, and are determined by dividing the vertical coordinate in to + grid boxes of roughly 1% of the maximum vertical distance from top to + bottom. Otherwise, the *levels* argument can be used to specify specific + vertical levels. If all vertical levels are desired, use the raw :meth:`wrf.interp2dxy` function. - + See Also: - + :meth:`wrf.interp2dxy` - + Args: - - field3d (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A - three-dimensional field to interpolate, whose + + field3d (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A + three-dimensional field to interpolate, whose rightmost dimensions are nz x ny x nx. - - vert (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A - three-dimensional variable for the vertical coordinate, typically + + vert (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A + three-dimensional variable for the vertical coordinate, typically pressure or height. This array must have the same dimensionality as *field3d* - + levels (sequence, optional): A sequence of :obj:`float` for the desired - vertical levels in the output array. Must be in the same units - as *vert*. If None, a fixed set of vertical levels is provided. + vertical levels in the output array. Must be in the same units + as *vert*. If None, a fixed set of vertical levels is provided. Default is None. - - missing (:obj:`float`): The fill value to use for the output. + + missing (:obj:`float`): The fill value to use for the output. Default is :data:`wrf.default_fill(numpy.float64)`. - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable, optional): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable, optional): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. This is used - to obtain the map projection when using latitude,longitude + to obtain the map projection when using latitude,longitude coordinates. Default is 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. + + 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. Default is 0. - - stagger (:obj:`str`): If using latitude, longitude coordinate pairs - for *start_point*, *end_point*, or *pivot_point*, + + stagger (:obj:`str`): If using latitude, longitude coordinate pairs + for *start_point*, *end_point*, or *pivot_point*, set the appropriate grid staggering type for *field3d*. By default, the mass grid is used. The options are: - + - 'm': Use the mass grid (default). - - 'u': Use the same staggered grid as the u wind component, + - 'u': Use the same staggered grid as the u wind component, which has a staggered west_east (x) dimension. - - 'v': Use the same staggered grid as the v wind component, + - 'v': Use the same staggered grid as the v wind component, which has a staggered south_north (y) dimension. - - projection (:class:`wrf.WrfProj` subclass, optional): The map - projection object to use when working with latitude, longitude - coordinates, and must be specified if *wrfin* is None. Default + + projection (:class:`wrf.WrfProj` subclass, optional): The map + projection object to use when working with latitude, longitude + coordinates, and must be specified if *wrfin* is None. Default is None. - + ll_point (:class:`wrf.CoordPair`, sequence of :class:`wrf.CoordPair`, \ - optional): The lower left latitude, longitude point for your domain, - and must be specified - if *wrfin* is None. If the domain is a moving nest, this should be + optional): The lower left latitude, longitude point for your domain, + and must be specified + if *wrfin* is None. If the domain is a moving nest, this should be a sequence of :class:`wrf.CoordPair`. Default is None. - - pivot_point (:class:`wrf.CoordPair`, optional): A coordinate pair for - the pivot point, which indicates the location through which - the plane will pass. Must also specify *angle*. The coordinate - pair can be in x,y grid coordinates or latitude, longitude - coordinates. If using latitude, longitude coordinates, then - either *wrfin* or *projection* must be specified to obtain the + + pivot_point (:class:`wrf.CoordPair`, optional): A coordinate pair for + the pivot point, which indicates the location through which + the plane will pass. Must also specify *angle*. The coordinate + pair can be in x,y grid coordinates or latitude, longitude + coordinates. If using latitude, longitude coordinates, then + either *wrfin* or *projection* must be specified to obtain the map projection. Default is None. - - angle (:obj:`float`, optional): Only valid for cross sections where - a plane will be plotted through - a given point on the model domain. 0.0 represents a S-N cross - section. 90.0 is a W-E cross section. - - start_point (:class:`wrf.CoordPair`, optional): A coordinate pair - which indicates the start location through which the plane will - pass. Must also specify *end_point*. The coordinate - pair can be in x,y grid coordinates or latitude, longitude - coordinates. If using latitude, longitude coordinates, then - either *wrfin* or *projection* must be specified to obtain the + + angle (:obj:`float`, optional): Only valid for cross sections where + a plane will be plotted through + a given point on the model domain. 0.0 represents a S-N cross + section. 90.0 is a W-E cross section. + + start_point (:class:`wrf.CoordPair`, optional): A coordinate pair + which indicates the start location through which the plane will + pass. Must also specify *end_point*. The coordinate + pair can be in x,y grid coordinates or latitude, longitude + coordinates. If using latitude, longitude coordinates, then + either *wrfin* or *projection* must be specified to obtain the map projection. Default is None. - - end_point (:class:`wrf.CoordPair`, optional): A coordinate pair - which indicates the end location through which the plane will - pass. Must also specify *end_point*. The coordinate - pair can be in x,y grid coordinates or latitude, longitude - coordinates. If using latitude, longitude coordinates, then - either *wrfin* or *projection* must be specified to obtain the + + end_point (:class:`wrf.CoordPair`, optional): A coordinate pair + which indicates the end location through which the plane will + pass. Must also specify *end_point*. The coordinate + pair can be in x,y grid coordinates or latitude, longitude + coordinates. If using latitude, longitude coordinates, then + either *wrfin* or *projection* must be specified to obtain the map projection. Default is None. - - latlon (:obj:`bool`, optional): Set to True to also interpolate the - two-dimensional latitude and longitude coordinates along the same - horizontal line and include this information in the metadata + + latlon (:obj:`bool`, optional): Set to True to also interpolate the + two-dimensional latitude and longitude coordinates along the same + horizontal line and include this information in the metadata (if enabled). This can be helpful for plotting. Default is False. - + Note: - - Currently, *field3d* must be of type :class:`xarray.DataArray` - and contain coordinate information in order to generate the - latitude and longitude coordinates along the line if + + Currently, *field3d* must be of type :class:`xarray.DataArray` + and contain coordinate information in order to generate the + latitude and longitude coordinates along the line if *latlon* is set to True. Otherwise, a warning will be issued, - and the latitude and longitude information will not be + and the latitude and longitude information will not be present. - - autolevels(:obj:`int`, optional): The number of evenly spaced - automatically chosen vertical levels to use when *levels* + + autolevels(:obj:`int`, optional): The number of evenly spaced + automatically chosen vertical levels to use when *levels* is None. Default is 100. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Returns: - + :class:`xarray.DataArray` or :class:`numpy.ndarray`: - The interpolated variable. If xarray is enabled and - the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + The interpolated variable. If xarray is enabled and + the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ # Some fields like uvmet have an extra left dimension for the product # type, we'll handle that iteration here. multi = True if field3d.ndim - vert.ndim == 1 else False - + try: xy = cache["xy"] var2dz = cache["var2dz"] @@ -271,31 +284,31 @@ def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64), start_point_xy = None end_point_xy = None pivot_point_xy = None - - if (latlon is True or is_latlon_pair(start_point) or - is_latlon_pair(pivot_point)): - + + if (latlon is True or is_latlon_pair(start_point) or + is_latlon_pair(pivot_point)): + if wrfin is not None: is_moving = is_moving_domain(wrfin) else: is_moving = False - + if timeidx is None: if wrfin is not None: - # Moving nests aren't supported with ALL_TIMES because the - # domain could move outside of the line, which causes + # Moving nests aren't supported with ALL_TIMES because the + # 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 - + # If using grid coordinates, then don't care about lat/lon # coordinates. Just use 0. else: @@ -304,48 +317,48 @@ def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64), if is_moving: _timeidx = timeidx else: - # When using non-moving nests, set the time to 0 + # When using non-moving nests, set the time to 0 # 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, + xy_coords = to_xy_coords(pivot_point, wrfin, _timeidx, stagger, projection, ll_point) pivot_point_xy = (xy_coords.x, xy_coords.y) 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, + xy_coords = to_xy_coords(start_point, wrfin, _timeidx, stagger, projection, ll_point) start_point_xy = (xy_coords.x, xy_coords.y) else: start_point_xy = (start_point.x, start_point.y) - + if end_point.lat is not None and end_point.lon is not None: - xy_coords = to_xy_coords(end_point, wrfin, _timeidx, + xy_coords = to_xy_coords(end_point, wrfin, _timeidx, stagger, projection, ll_point) end_point_xy = (xy_coords.x, xy_coords.y) else: end_point_xy = (end_point.x, end_point.y) - - xy, var2dz, z_var2d = get_xy_z_params(to_np(vert), pivot_point_xy, - angle, start_point_xy, + + xy, var2dz, z_var2d = get_xy_z_params(to_np(vert), pivot_point_xy, + angle, start_point_xy, end_point_xy, levels, autolevels) - + if not multi: result = _vertcross(field3d, xy, var2dz, z_var2d, missing) else: outshape = field3d.shape[0:-3] + (z_var2d.shape[0], xy.shape[0]) 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) @@ -353,159 +366,159 @@ def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64), def interpline(field2d, wrfin=None, timeidx=0, stagger=None, projection=None, ll_point=None, pivot_point=None, angle=None, start_point=None, - end_point=None, latlon=False, + end_point=None, latlon=False, cache=None, meta=True): """Return the two-dimensional field interpolated along a line. - - This line is defined by either including the - *pivot_point* and *angle* parameters, or the *start_point* and - *end_point* parameters. The *pivot_point*, *start_point*, and *end_point* - coordinates can be defined in either x,y or latitude,longitude space. - If latitude,longitude coordinates are used, then a WRF input file or + + This line is defined by either including the + *pivot_point* and *angle* parameters, or the *start_point* and + *end_point* parameters. The *pivot_point*, *start_point*, and *end_point* + coordinates can be defined in either x,y or latitude,longitude space. + If latitude,longitude coordinates are used, then a WRF input file or map projection must also be specified. - + Args: - + field2d (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A two-dimensional field. - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable, optional): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable, optional): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. This is used - to obtain the map projection when using latitude,longitude - coordinates. Should not be used when working with x,y + to obtain the map projection when using latitude,longitude + coordinates. Should not be used when working with x,y coordinates. Default is 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. - Default is 0. - - stagger (:obj:`str`): If using latitude, longitude coordinate pairs - for *start_point*, *end_point*, or *pivot_point*, + + 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. + Default is 0. + + stagger (:obj:`str`): If using latitude, longitude coordinate pairs + for *start_point*, *end_point*, or *pivot_point*, set the appropriate grid staggering type for *field2d*. By default, the mass grid is used. The options are: - + - 'm': Use the mass grid (default). - - 'u': Use the same staggered grid as the u wind component, + - 'u': Use the same staggered grid as the u wind component, which has a staggered west_east (x) dimension. - - 'v': Use the same staggered grid as the v wind component, + - 'v': Use the same staggered grid as the v wind component, which has a staggered south_north (y) dimension. - - projection (:class:`wrf.WrfProj`, optional): The map - projection object to use when working with latitude, longitude - coordinates, and must be specified if *wrfin* is None. Should - not be used when working with x,y coordinates. Default + + projection (:class:`wrf.WrfProj`, optional): The map + projection object to use when working with latitude, longitude + coordinates, and must be specified if *wrfin* is None. Should + not be used when working with x,y coordinates. Default is None. - + ll_point (:class:`wrf.CoordPair`, sequence of :class:`wrf.CoordPair`, \ - optional): The lower left latitude, longitude point for your domain, - and must be specified - if *wrfin* is None. If the domain is a moving nest, this should be + optional): The lower left latitude, longitude point for your domain, + and must be specified + if *wrfin* is None. If the domain is a moving nest, this should be a sequence of :class:`wrf.CoordPair`. Default is None. - - pivot_point (:class:`wrf.CoordPair`, optional): A coordinate pair for - the pivot point, which indicates the location through which - the plane will pass. Must also specify *angle*. The coordinate - pair can be in x,y grid coordinates or latitude, longitude - coordinates. If using latitude, longitude coordinates, then - either *wrfin* or *projection* must be specified to obtain the + + pivot_point (:class:`wrf.CoordPair`, optional): A coordinate pair for + the pivot point, which indicates the location through which + the plane will pass. Must also specify *angle*. The coordinate + pair can be in x,y grid coordinates or latitude, longitude + coordinates. If using latitude, longitude coordinates, then + either *wrfin* or *projection* must be specified to obtain the map projection. Default is None. - - angle (:obj:`float`, optional): Only valid for cross sections where - a plane will be plotted through - a given point on the model domain. 0.0 represents a S-N cross - section. 90.0 is a W-E cross section. - - start_point (:class:`wrf.CoordPair`, optional): A coordinate pair - which indicates the start location through which the plane will - pass. Must also specify *end_point*. The coordinate - pair can be in x,y grid coordinates or latitude, longitude - coordinates. If using latitude, longitude coordinates, then - either *wrfin* or *projection* must be specified to obtain the + + angle (:obj:`float`, optional): Only valid for cross sections where + a plane will be plotted through + a given point on the model domain. 0.0 represents a S-N cross + section. 90.0 is a W-E cross section. + + start_point (:class:`wrf.CoordPair`, optional): A coordinate pair + which indicates the start location through which the plane will + pass. Must also specify *end_point*. The coordinate + pair can be in x,y grid coordinates or latitude, longitude + coordinates. If using latitude, longitude coordinates, then + either *wrfin* or *projection* must be specified to obtain the map projection. Default is None. - - end_point (:class:`wrf.CoordPair`, optional): A coordinate pair - which indicates the end location through which the plane will - pass. Must also specify *end_point*. The coordinate - pair can be in x,y grid coordinates or latitude, longitude - coordinates. If using latitude, longitude coordinates, then - either *wrfin* or *projection* must be specified to obtain the + + end_point (:class:`wrf.CoordPair`, optional): A coordinate pair + which indicates the end location through which the plane will + pass. Must also specify *end_point*. The coordinate + pair can be in x,y grid coordinates or latitude, longitude + coordinates. If using latitude, longitude coordinates, then + either *wrfin* or *projection* must be specified to obtain the map projection. Default is None. - - latlon (:obj:`bool`, optional): Set to True to also interpolate the - two-dimensional latitude and longitude coordinates along the same - horizontal line and include this information in the metadata + + latlon (:obj:`bool`, optional): Set to True to also interpolate the + two-dimensional latitude and longitude coordinates along the same + horizontal line and include this information in the metadata (if enabled). This can be helpful for plotting. Default is False. - + Note: - - Currently, *field2d* must be of type :class:`xarray.DataArray` - and contain coordinate information in order to generate the - latitude and longitude coordinates along the line if + + Currently, *field2d* must be of type :class:`xarray.DataArray` + and contain coordinate information in order to generate the + latitude and longitude coordinates along the line if *latlon* is set to True. Otherwise, a warning will be issued, - and the latitude and longitude information will not be + and the latitude and longitude information will not be present. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - + + Returns: - + :class:`xarray.DataArray` or :class:`numpy.ndarray`: - The interpolated variable. If xarray is enabled and - the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + The interpolated variable. If xarray is enabled and + the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - - + + """ - + try: xy = cache["xy"] except (KeyError, TypeError): start_point_xy = None end_point_xy = None pivot_point_xy = None - - if (latlon is True or is_latlon_pair(start_point) or - is_latlon_pair(pivot_point)): - + + if (latlon is True or is_latlon_pair(start_point) or + is_latlon_pair(pivot_point)): + if wrfin is not None: is_moving = is_moving_domain(wrfin) else: is_moving = False - + if timeidx is None: if wrfin is not None: - # Moving nests aren't supported with ALL_TIMES because the - # domain could move outside of the line, which causes + # Moving nests aren't supported with ALL_TIMES because the + # 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: # Domain not moving, just use 0 _timeidx = 0 - + # If using grid coordinates, then don't care about lat/lon # coordinates. Just use 0. else: @@ -514,84 +527,84 @@ def interpline(field2d, wrfin=None, timeidx=0, stagger=None, projection=None, if is_moving: _timeidx = timeidx else: - # When using non-moving nests, set the time to 0 + # When using non-moving nests, set the time to 0 # 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, + xy_coords = to_xy_coords(pivot_point, wrfin, _timeidx, stagger, projection, ll_point) pivot_point_xy = (xy_coords.x, xy_coords.y) 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, + xy_coords = to_xy_coords(start_point, wrfin, _timeidx, stagger, projection, ll_point) start_point_xy = (xy_coords.x, xy_coords.y) else: start_point_xy = (start_point.x, start_point.y) - + if end_point.lat is not None and end_point.lon is not None: - xy_coords = to_xy_coords(end_point, wrfin, _timeidx, + xy_coords = to_xy_coords(end_point, wrfin, _timeidx, stagger, projection, ll_point) end_point_xy = (xy_coords.x, xy_coords.y) else: end_point_xy = (end_point.x, end_point.y) - - xy = get_xy(field2d, pivot_point_xy, angle, start_point_xy, + + xy = get_xy(field2d, pivot_point_xy, angle, start_point_xy, end_point_xy) - + return _interpline(field2d, xy) @set_interp_metadata("vinterp") -def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False, - field_type=None, log_p=False, timeidx=0, method="cat", +def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False, + field_type=None, log_p=False, timeidx=0, method="cat", squeeze=True, cache=None, meta=True): - """Return the field vertically interpolated to the given the type of + """Return the field vertically interpolated to the given the type of surface and a set of new levels. - + Args: wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`,\ or an iterable): - WRF-ARW NetCDF data as a :class:`netCDF4.Dataset`, - :class:`Nio.NioFile` or an iterable sequence of the + WRF-ARW NetCDF data as a :class:`netCDF4.Dataset`, + :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - field (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A + + field (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A three-dimensional field. - - vert_coord (:obj:`str`): A string indicating the vertical coordinate + + vert_coord (:obj:`str`): A string indicating the vertical coordinate type to interpolate to. - - Valid strings are: + + Valid strings are: * 'pressure', 'pres', 'p': pressure [hPa] * '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] - - interp_levels (sequence): A 1D sequence of vertical levels to - interpolate to. Values must be in the same units as specified + * '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 above for the *vert_coord* parameter. - - extrapolate (:obj:`bool`, optional): Set to True to extrapolate - values below ground. This is only performed when *vert_coord* is - a pressure or height type, and the *field_type* is a pressure type - (with height vertical coordinate), a height type (with pressure as - the vertical coordinate), or a temperature type (with either height - or pressure as the vertical coordinate). If those conditions are - not met, or *field_type* is None, then the lowest model level + + extrapolate (:obj:`bool`, optional): Set to True to extrapolate + values below ground. This is only performed when *vert_coord* is + a pressure or height type, and the *field_type* is a pressure type + (with height vertical coordinate), a height type (with pressure as + the vertical coordinate), or a temperature type (with either height + or pressure as the vertical coordinate). If those conditions are + not met, or *field_type* is None, then the lowest model level will be used. Extrapolation is performed using standard atmosphere. - Default is False. - - field_type (:obj:`str`, optional): + Default is False. + + field_type (:obj:`str`, optional): The type of field. Default is None. - + Valid strings are: * 'none': None * 'pressure', 'pres', 'p': pressure [Pa] @@ -602,255 +615,247 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False, * 'tk': temperature [K] * 'theta', 'th': potential temperature [K] * 'theta-e', 'thetae', 'eth': equivalent potential temperature - - log_p (:obj:`bool`, optional): Set to True to use the log of the - vertical coordinate for interpolation. This is mainly intended - for pressure vertical coordinate types, but note that the log - will still be taken for any vertical coordinate type when + + log_p (:obj:`bool`, optional): Set to True to use the log of the + vertical coordinate for interpolation. This is mainly intended + for pressure vertical coordinate types, but note that the log + will still be taken for any vertical coordinate type when this is set to True. Default is False. - + timeidx (:obj:`int`, optional): - The time index to use when extracting auxiallary variables used in + The time index to use when extracting auxiallary variables used in the interpolation. This value must be set to match the same value used when the `field` variable was extracted. Default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - + Returns: - + :class:`xarray.DataArray` or :class:`numpy.ndarray`: - The interpolated variable. If xarray is enabled and - the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + The interpolated variable. If xarray is enabled and + the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ _key = get_id(wrfin) - + _wrfin = get_iterable(wrfin) - + # Remove case sensitivity field_type = field_type.lower() if field_type is not None else "none" vert_coord = vert_coord.lower() if vert_coord is not None else "none" - - valid_coords = ("pressure", "pres", "p", "ght_msl", + + valid_coords = ("pressure", "pres", "p", "ght_msl", "ght_agl", "theta", "th", "theta-e", "thetae", "eth") - - valid_field_types = ("none", "pressure", "pres", "p", + + valid_field_types = ("none", "pressure", "pres", "p", 'pressure_hpa', 'pres_hpa', 'p_hpa', "z", - "tc", "tk", "theta", "th", "theta-e", "thetae", + "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, - - } - - # These constants match what's in the fortran code. + + 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 ussalr = Constants.USSALR sclht = Constants.SCLHT - + # interp_levels might be a list or tuple, make a numpy array if not isinstance(interp_levels, np.ndarray): interp_levels = np.asarray(interp_levels, np.float64) - + if len(interp_levels) == 0: raise ValueError("'interp_levels' contains no values") - + # Check if field is staggered if is_staggered(_wrfin, field): raise ValueError("Please unstagger field in the vertical") - + # 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 - + icase = 0 extrap = 0 - + if extrapolate: extrap = 1 icase = icase_lookup[field_type] - + # Extract variables - ncvars = extract_vars(_wrfin, timeidx, ("PSFC", "QVAPOR"), + ncvars = extract_vars(_wrfin, timeidx, ("PSFC", "QVAPOR"), method, squeeze, cache, meta=False, _key=_key) - + sfp = ncvars["PSFC"] * ConversionFactors.PA_TO_HPA qv = ncvars["QVAPOR"] - - terht = get_terrain(_wrfin, timeidx, units="m", + + terht = get_terrain(_wrfin, timeidx, units="m", method=method, squeeze=squeeze, cache=cache, meta=False, _key=_key) - tk = get_temp(_wrfin, timeidx, units="k", - method=method, squeeze=squeeze, cache=cache, + tk = get_temp(_wrfin, timeidx, units="k", + method=method, squeeze=squeeze, cache=cache, meta=False, _key=_key) - p = get_pressure(_wrfin, timeidx, units="pa", + p = get_pressure(_wrfin, timeidx, units="pa", method=method, squeeze=squeeze, cache=cache, meta=False, _key=_key) - ght = get_height(_wrfin, timeidx, msl=True, units="m", + ght = get_height(_wrfin, timeidx, msl=True, units="m", method=method, squeeze=squeeze, cache=cache, meta=False, _key=_key) - - smsfp = _smooth2d(sfp, 3, 2.0) + + smsfp = _smooth2d(sfp, 3, 2.0) vcor = 0 - + if vert_coord in ("pressure", "pres", "p"): vcor = 1 vcord_array = p * ConversionFactors.PA_TO_HPA - + elif vert_coord == "ght_msl": vcor = 2 vcord_array = np.exp(-ght/sclht) - + 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) - - coriolis = extract_vars(_wrfin, timeidx, "F", - method, squeeze, cache, meta=False, + t = get_theta(_wrfin, timeidx, units="k", + method=method, squeeze=squeeze, cache=cache, + meta=False, _key=_key) + + coriolis = extract_vars(_wrfin, timeidx, "F", + method, squeeze, cache, meta=False, _key=_key)["F"] - + vcor = 4 idir = 1 icorsw = 0 delta = 0.01 - + p_hpa = p * ConversionFactors.PA_TO_HPA - + vcord_array = _monotonic(t, p_hpa, coriolis, idir, delta, icorsw) - - # We only extrapolate temperature fields below ground + + # We only extrapolate temperature fields below ground # if we are interpolating to pressure or height vertical surfaces. - - icase = 0 - + + icase = 0 + elif vert_coord in ("theta-e", "thetae", "eth"): vcor = 5 icorsw = 0 idir = 1 delta = 0.01 - - eth = get_eth(_wrfin, timeidx, method=method, squeeze=squeeze, - cache=cache, meta=False, _key=_key) - - coriolis = extract_vars(_wrfin, timeidx, "F", - method, squeeze, cache, meta=False, + + eth = get_eth(_wrfin, timeidx, method=method, squeeze=squeeze, + cache=cache, meta=False, _key=_key) + + coriolis = extract_vars(_wrfin, timeidx, "F", + method, squeeze, cache, meta=False, _key=_key)["F"] - + p_hpa = p * ConversionFactors.PA_TO_HPA - + vcord_array = _monotonic(eth, p_hpa, coriolis, idir, delta, icorsw) # We only extrapolate temperature fields below ground if we are # interpolating to pressure or height vertical surfaces icase = 0 - + # Set the missing value if isinstance(field, ma.MaskedArray): missing = field.fill_value else: missing = default_fill(np.float64) - + if (field.shape != p.shape): raise ValueError("'field' shape does not match other variable shapes. " "Verify that the 'timeidx' parameter matches the " "same value used when extracting the 'field' " "variable.") - - # Some field types are in different units than the Fortran routine + + # Some field types are in different units than the Fortran routine # expects - + conv_factor = in_unitmap.get(field_type) - + if conv_factor is not None: field_ = field * conv_factor else: field_ = field - + res = _vintrp(field_, p, tk, qv, ght, terht, sfp, smsfp, vcord_array, interp_levels, icase, extrap, vcor, log_p_int, missing) - + conv_factor = out_unitmap.get(field_type) - + if conv_factor is not None: res_ = res * conv_factor else: res_ = res - - return ma.masked_values(res_, missing) - - - - - + return ma.masked_values(res_, missing) diff --git a/src/wrf/interputils.py b/src/wrf/interputils.py index 8e04c86..f5cf8d1 100644 --- a/src/wrf/interputils.py +++ b/src/wrf/interputils.py @@ -14,165 +14,164 @@ from .util import pairs_to_latlon def to_positive_idxs(shape, coord): """Return the positive index values. - + This function converts negative index values to positive index values. - + Args: - + shape (indexable sequence): The array shape. - + coord (indexable sequence): The coordinate pair for x and y. - + Returns: - + :obj:`list`: The coordinate values with all positive indexes. - + """ 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): + +def _calc_xy(xdim, ydim, pivot_point=None, angle=None, + start_point=None, end_point=None): """Return the x,y points for the horizontal cross section line. - + Args: - + xdim (:obj:`int`): The x-dimension size. - + ydim (:obj:`int`): The y-dimension size. - - pivot_point (:obj:`tuple` or :obj:`list`, optional): A - :obj:`tuple` or :obj:`list` with two entries, - in the form of [x, y] (or [west_east, south_north]), which - indicates the x,y location through which the plane will pass. + + pivot_point (:obj:`tuple` or :obj:`list`, optional): A + :obj:`tuple` or :obj:`list` with two entries, + in the form of [x, y] (or [west_east, south_north]), which + indicates the x,y location through which the plane will pass. Must also specify `angle`. - - angle (:obj:`float`, optional): Only valid for cross sections where - a plane will be plotted through - a given point on the model domain. 0.0 represents a S-N cross - section. 90.0 is a W-E cross section. - - start_point (:obj:`tuple` or :obj:`list`, optional): A - :obj:`tuple` or :obj:`list` with two entries, in the form of - [x, y] (or [west_east, south_north]), which indicates the start + + angle (:obj:`float`, optional): Only valid for cross sections where + a plane will be plotted through + a given point on the model domain. 0.0 represents a S-N cross + section. 90.0 is a W-E cross section. + + start_point (:obj:`tuple` or :obj:`list`, optional): A + :obj:`tuple` or :obj:`list` with two entries, in the form of + [x, y] (or [west_east, south_north]), which indicates the start x,y location through which the plane will pass. - - end_point (:obj:`tuple` or :obj:`list`, optional): A - :obj:`tuple` or :obj:`list` with two entries, in the form of - [x, y] (or [west_east, south_north]), which indicates the end x,y + + end_point (:obj:`tuple` or :obj:`list`, optional): A + :obj:`tuple` or :obj:`list` with two entries, in the form of + [x, y] (or [west_east, south_north]), which indicates the end x,y location through which the plane will pass. - + Returns: - - :class:`np.ndarray`: A two-dimensional array with the left index - representing each point along the line, and the rightmost dimension + + :class:`np.ndarray`: A two-dimensional array with the left index + representing each point along the line, and the rightmost dimension having two values for the x and y coordinates [0=X, 1=Y]. - + """ # Have a pivot point with an angle to find cross section if pivot_point is not None and angle is not None: xp = pivot_point[-2] yp = pivot_point[-1] - + if xp >= xdim or yp >= ydim: raise ValueError("pivot point {} is outside of domain " "with shape {}".format(pivot_point, - (xdim, ydim))) - - if (angle > 315.0 or angle < 45.0 - or ((angle > 135.0) and (angle < 225.0))): - - #x = y*slope + intercept + (xdim, ydim))) + + if (angle > 315.0 or angle < 45.0 + or ((angle > 135.0) and (angle < 225.0))): + 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 - + # find intersections with domain boundaries 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 - - if( x1 > xdim-1): # intersect outside of right boundary + y1 = (x1 - intercept)/slope + + 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 - - if( y0 > ydim-1): # intersect outside of top boundary + x0 = (y0 - intercept)/slope + + if (y0 > ydim-1): # intersect outside of top boundary y0 = ydim-1 - x0 = (y0 - intercept)/slope - - x1 = xdim-1. # need to make sure this will be a float? + x0 = (y0 - intercept)/slope + + x1 = xdim-1. # need to make sure this will be a float? y1 = x1*slope + intercept - - if( y1 < 0.): # intersect outside of bottom boundary + + if (y1 < 0.): # intersect outside of bottom boundary y1 = 0. - x1 = (y1 - intercept)/slope - - if( y1 > ydim-1):# intersect outside of top boundary + x1 = (y1 - intercept)/slope + + 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] x1 = end_point[-2] y1 = end_point[-1] - + if x0 >= xdim or y0 >= ydim: raise ValueError("start_point {} is outside of domain " "with shape {}".format(start_point, (xdim, ydim))) - + if x1 >= xdim or y1 >= ydim: raise ValueError("end_point {} is outside of domain " "with shape {}".format(end_point, (xdim, ydim))) else: raise ValueError("invalid start/end or pivot/angle arguments") - + dx = x1 - x0 dy = y1 - y0 distance = (dx*dx + dy*dy)**0.5 npts = int(distance) + 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 @@ -180,66 +179,66 @@ def get_xy_z_params(z, pivot_point=None, angle=None, start_point=None, end_point=None, levels=None, autolevels=100): """Return the cross section parameters. - - This function returns the xy horizontal cross section line coordinates, - the xy x z vertical values interpolated along the xy cross section + + This function returns the xy horizontal cross section line coordinates, + the xy x z vertical values interpolated along the xy cross section line, and the fixed vertical levels to be used by the cross section - algorithm (at ~1% increments for the minimum to maximum vertical + algorithm (at ~1% increments for the minimum to maximum vertical span). - + Args: - - z (:class:`numpy.ndarray`): The vertical coordinate, whose rightmost + + z (:class:`numpy.ndarray`): The vertical coordinate, whose rightmost dimensions are bottom_top x south_north x west_east. - - pivot_point (:obj:`tuple` or :obj:`list`, optional): A - :obj:`tuple` or :obj:`list` with two entries, - in the form of [x, y] (or [west_east, south_north]), which - indicates the x,y location through which the plane will pass. + + pivot_point (:obj:`tuple` or :obj:`list`, optional): A + :obj:`tuple` or :obj:`list` with two entries, + in the form of [x, y] (or [west_east, south_north]), which + indicates the x,y location through which the plane will pass. Must also specify `angle`. - - angle (:obj:`float`, optional): Only valid for cross sections where - a plane will be plotted through - a given point on the model domain. 0.0 represents a S-N cross - section. 90.0 is a W-E cross section. - - start_point (:obj:`tuple` or :obj:`list`, optional): A - :obj:`tuple` or :obj:`list` with two entries, in the form of - [x, y] (or [west_east, south_north]), which indicates the start + + angle (:obj:`float`, optional): Only valid for cross sections where + a plane will be plotted through + a given point on the model domain. 0.0 represents a S-N cross + section. 90.0 is a W-E cross section. + + start_point (:obj:`tuple` or :obj:`list`, optional): A + :obj:`tuple` or :obj:`list` with two entries, in the form of + [x, y] (or [west_east, south_north]), which indicates the start x,y location through which the plane will pass. - - end_point (:obj:`tuple` or :obj:`list`, optional): A - :obj:`tuple` or :obj:`list` with two entries, in the form of - [x, y] (or [west_east, south_north]), which indicates the end x,y + + end_point (:obj:`tuple` or :obj:`list`, optional): A + :obj:`tuple` or :obj:`list` with two entries, in the form of + [x, y] (or [west_east, south_north]), which indicates the end x,y location through which the plane will pass. - + levels (sequence): A sequence of :obj:`float` for the desired - vertical levels in the output array. If None, a fixed set of + vertical levels in the output array. If None, a fixed set of vertical levels is provided. Default is None. - - autolevels(:obj:`int`, optional): The number of evenly spaced - automatically chosen vertical levels to use when *levels* + + autolevels(:obj:`int`, optional): The number of evenly spaced + automatically chosen vertical levels to use when *levels* is None. Default is 100. - + Returns: - - :obj:`tuple`: A tuple containing the xy horizontal cross section - coordinates, the vertical values interpolated along the xy cross - section line, and the fixed vertical levels used by the - cross section algorithm at ~1% increments of minimum to maximum + + :obj:`tuple`: A tuple containing the xy horizontal cross section + coordinates, the vertical values interpolated along the xy cross + section line, and the fixed vertical levels used by the + cross section algorithm at ~1% increments of minimum to maximum vertical span. - + """ - + xy = get_xy(z, pivot_point, angle, start_point, end_point) - + # Interp z var2dz = _interp2dxy(z, xy) - + extra_dim_num = z.ndim - 3 - idx1 = tuple([0]*extra_dim_num + [0,0]) - idx2 = tuple([0]*extra_dim_num + [-1,0]) - + 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 if(var2dz[idx1] > var2dz[idx2]): # monotonically decreasing coordinate @@ -255,181 +254,182 @@ def get_xy_z_params(z, pivot_point=None, angle=None, dz = (1.0/autolevels)*z_max 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) - + return xy, var2dz, z_var2d -def get_xy(var, pivot_point=None, angle=None, +def get_xy(var, pivot_point=None, angle=None, start_point=None, end_point=None): """Return the x,y points for the horizontal cross section line. - + Args: - + var (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A variable that contains a :attr:`shape` attribute. - - pivot_point (:obj:`tuple` or :obj:`list`, optional): A - :obj:`tuple` or :obj:`list` with two entries, - in the form of [x, y] (or [west_east, south_north]), which - indicates the x,y location through which the plane will pass. + + pivot_point (:obj:`tuple` or :obj:`list`, optional): A + :obj:`tuple` or :obj:`list` with two entries, + in the form of [x, y] (or [west_east, south_north]), which + indicates the x,y location through which the plane will pass. Must also specify `angle`. - - angle (:obj:`float`, optional): Only valid for cross sections where - a plane will be plotted through - a given point on the model domain. 0.0 represents a S-N cross - section. 90.0 is a W-E cross section. - - start_point (:obj:`tuple` or :obj:`list`, optional): A - :obj:`tuple` or :obj:`list` with two entries, in the form of - [x, y] (or [west_east, south_north]), which indicates the start + + angle (:obj:`float`, optional): Only valid for cross sections where + a plane will be plotted through + a given point on the model domain. 0.0 represents a S-N cross + section. 90.0 is a W-E cross section. + + start_point (:obj:`tuple` or :obj:`list`, optional): A + :obj:`tuple` or :obj:`list` with two entries, in the form of + [x, y] (or [west_east, south_north]), which indicates the start x,y location through which the plane will pass. - - end_point (:obj:`tuple` or :obj:`list`, optional): A - :obj:`tuple` or :obj:`list` with two entries, in the form of - [x, y] (or [west_east, south_north]), which indicates the end x,y + + end_point (:obj:`tuple` or :obj:`list`, optional): A + :obj:`tuple` or :obj:`list` with two entries, in the form of + [x, y] (or [west_east, south_north]), which indicates the end x,y location through which the plane will pass. - + Returns: - - :class:`np.ndarray`: A two-dimensional array with the left index - representing each point along the line, and the rightmost dimension + + :class:`np.ndarray`: A two-dimensional array with the left index + representing each point along the line, and the rightmost dimension having two values for the x and y coordinates [0=X, 1=Y]. - + """ if pivot_point is not None: pos_pivot = to_positive_idxs(var.shape[-2:], pivot_point) else: pos_pivot = pivot_point - + if start_point is not None: pos_start = to_positive_idxs(var.shape[-2:], start_point) else: pos_start = start_point - + if end_point is not None: pos_end = to_positive_idxs(var.shape[-2:], end_point) else: pos_end = start_point - + xdim = var.shape[-1] ydim = var.shape[-2] - + xy = _calc_xy(xdim, ydim, pos_pivot, angle, pos_start, pos_end) - + return xy + def to_xy_coords(pairs, wrfin=None, timeidx=0, stagger=None, projection=None, ll_point=None): """Return the coordinate pairs in grid space. - - This function converts latitude,longitude coordinate pairs to + + This function converts latitude,longitude coordinate pairs to x,y coordinate pairs. - + Args: - - pairs (:class:`CoordPair` or sequence): A single coordinate pair or + + pairs (:class:`CoordPair` or sequence): A single coordinate pair or a sequence of coordinate pairs to be converted. - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable, optional): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable, optional): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. This is used - to obtain the map projection when using latitude,longitude - coordinates. Should not be used when working with x,y + to obtain the map projection when using latitude,longitude + coordinates. Should not be used when working with x,y coordinates. Default is None. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index when obtaining map boundary information - from moving nests. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return - all times in the file or sequence. Only required when + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index when obtaining map boundary information + from moving nests. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return + all times in the file or sequence. Only required when *wrfin* is specified and the nest is moving. Default is 0. - - stagger (:obj:`str`): If using latitude, longitude coordinate pairs - for *start_point*, *end_point*, or *pivot_point*, + + stagger (:obj:`str`): If using latitude, longitude coordinate pairs + for *start_point*, *end_point*, or *pivot_point*, set the appropriate grid staggering type for *field2d*. By default, the mass grid is used. The options are: - + - 'm': Use the mass grid (default). - - 'u': Use the same staggered grid as the u wind component, + - 'u': Use the same staggered grid as the u wind component, which has a staggered west_east (x) dimension. - - 'v': Use the same staggered grid as the v wind component, + - 'v': Use the same staggered grid as the v wind component, which has a staggered south_north (y) dimension. - - projection (:class:`wrf.WrfProj`, optional): The map - projection object to use when working with latitude, longitude - coordinates, and must be specified if *wrfin* is None. Default + + projection (:class:`wrf.WrfProj`, optional): The map + projection object to use when working with latitude, longitude + coordinates, and must be specified if *wrfin* is None. Default is None. - + ll_point (:class:`wrf.CoordPair`, sequence of :class:`wrf.CoordPair`, \ - optional): The lower left latitude, longitude point for your domain, - and must be specified - if *wrfin* is None. If the domain is a moving nest, this should be + optional): The lower left latitude, longitude point for your domain, + and must be specified + if *wrfin* is None. If the domain is a moving nest, this should be a sequence of :class:`wrf.CoordPair`. Default is None. - + Returns: - - :class:`wrf.CoordPair` or sequence: The coordinate pair(s) in + + :class:`wrf.CoordPair` or sequence: The coordinate pair(s) in x,y grid coordinates. - + """ - + 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) - + xy_vals = _ll_to_xy(lat, lon, wrfin=wrfin, timeidx=timeidx, + squeeze=True, meta=False, stagger=stagger, + as_int=True) + else: map_proj = projection.map_proj - + if map_proj == ProjectionTypes.LAT_LON: pole_lat = projection.pole_lat pole_lon = projection.pole_lon - latinc = ((projection.dy*360.0)/2.0 / + latinc = ((projection.dy*360.0)/2.0 / Constants.PI/Constants.WRF_EARTH_RADIUS) - loninc = ((projection.dx*360.0)/2.0 / + loninc = ((projection.dx*360.0)/2.0 / Constants.PI/Constants.WRF_EARTH_RADIUS) else: pole_lat = 90.0 pole_lon = 0.0 latinc = 0.0 loninc = 0.0 - + ll_lat, ll_lon = pairs_to_latlon(ll_point) - xy_vals = _ll_to_xy(lat, lon, meta=False, squeeze=True, + xy_vals = _ll_to_xy(lat, lon, meta=False, squeeze=True, as_int=True, - map_proj=projection.map_proj, - truelat1=projection.truelat1, - truelat2=projection.truelat2, - stand_lon=projection.stand_lon, - ref_lat=ll_lat, - ref_lon=ll_lon, - pole_lat=pole_lat, - pole_lon=pole_lon, - known_x=0, - known_y=0, - dx=projection.dx, - dy=projection.dy, - latinc=latinc, + map_proj=projection.map_proj, + truelat1=projection.truelat1, + truelat2=projection.truelat2, + stand_lon=projection.stand_lon, + ref_lat=ll_lat, + ref_lon=ll_lon, + pole_lat=pole_lat, + pole_lon=pole_lon, + known_x=0, + known_y=0, + dx=projection.dx, + dy=projection.dy, + latinc=latinc, loninc=loninc) - + 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])] diff --git a/src/wrf/latlonutils.py b/src/wrf/latlonutils.py index 505b204..22191af 100644 --- a/src/wrf/latlonutils.py +++ b/src/wrf/latlonutils.py @@ -6,36 +6,36 @@ 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) +from .util import (extract_vars, extract_global_attrs, + either, is_moving_domain, iter_left_indexes, + is_mapping, is_multi_file) from .py3compat import viewkeys, viewitems from .projutils import dict_keys_to_upper - + def _lat_varname(wrfin, stagger): """Return the latitude variable name for the specified stagger type. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - stagger (:obj:`str`): The staggered grid type which is one of the + + stagger (:obj:`str`): The staggered grid type which is one of the following: - + - 'm': Use the mass grid (default). - - 'u': Use the same staggered grid as the u wind component, + - 'u': Use the same staggered grid as the u wind component, which has a staggered west_east (x) dimension. - - 'v': Use the same staggered grid as the v wind component, + - 'v': Use the same staggered grid as the v wind component, which has a staggered south_north (y) dimension. - + Returns: - + :obj:`str`: The latitude variable name. - + """ if stagger is None or stagger.lower() == "m": varname = either("XLAT", "XLAT_M")(wrfin) @@ -43,32 +43,33 @@ def _lat_varname(wrfin, stagger): varname = "XLAT_{}".format(stagger.upper()) else: raise ValueError("invalid 'stagger' value") - + return varname - + + def _lon_varname(wrfin, stagger): """Return the longitude variable name for the specified stagger type. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - stagger (:obj:`str`): The staggered grid type, which is one of the + + stagger (:obj:`str`): The staggered grid type, which is one of the following: - + - 'm': Use the mass grid (default). - - 'u': Use the same staggered grid as the u wind component, + - 'u': Use the same staggered grid as the u wind component, which has a staggered west_east (x) dimension. - - 'v': Use the same staggered grid as the v wind component, + - 'v': Use the same staggered grid as the v wind component, which has a staggered south_north (y) dimension. - + Returns: - + :obj:`str`: The latitude variable name. - + """ if stagger is None or stagger.lower() == "m": varname = either("XLONG", "XLONG_M")(wrfin) @@ -76,64 +77,65 @@ def _lon_varname(wrfin, stagger): varname = "XLONG_{}".format(stagger.upper()) else: raise ValueError("invalid 'stagger' value") - + return varname + def _get_proj_params(wrfin, timeidx, stagger, method, squeeze, cache, _key): """Return the map projection parameters. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - stagger (:obj:`str`): The staggered grid type, which is one of the + + stagger (:obj:`str`): The staggered grid type, which is one of the following: - + - 'm': Use the mass grid (default). - - 'u': Use the same staggered grid as the u wind component, + - 'u': Use the same staggered grid as the u wind component, which has a staggered west_east (x) dimension. - - 'v': Use the same staggered grid as the v wind component, + - 'v': Use the same staggered grid as the v wind component, which has a staggered south_north (y) dimension. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + Returns: - - + + """ if timeidx is not None: if timeidx < 0: raise ValueError("'timeidx' must be greater than 0") - + attrs = extract_global_attrs(wrfin, attrs=("MAP_PROJ", "TRUELAT1", "TRUELAT2", "STAND_LON", "DX", "DY")) @@ -143,9 +145,9 @@ def _get_proj_params(wrfin, timeidx, stagger, method, squeeze, cache, _key): stdlon = attrs["STAND_LON"] dx = attrs["DX"] dy = attrs["DY"] - + if map_proj == ProjectionTypes.LAT_LON: - pole_attrs = extract_global_attrs(wrfin, attrs=("POLE_LAT", + pole_attrs = extract_global_attrs(wrfin, attrs=("POLE_LAT", "POLE_LON")) pole_lat = pole_attrs["POLE_LAT"] pole_lon = pole_attrs["POLE_LON"] @@ -156,20 +158,20 @@ def _get_proj_params(wrfin, timeidx, stagger, method, squeeze, cache, _key): pole_lon = 0.0 latinc = 0.0 loninc = 0.0 - + latvar = _lat_varname(wrfin, stagger) lonvar = _lon_varname(wrfin, stagger) - + lat_timeidx = timeidx - - is_moving = is_moving_domain(wrfin, latvar=latvar, lonvar=lonvar, + + is_moving = is_moving_domain(wrfin, latvar=latvar, lonvar=lonvar, _key=_key) - + # Only need one file and one time if the domain is not moving if not is_moving: # Always use the 0th time for non-moving domains to avoid problems lat_timeidx = 0 - + if is_multi_file(wrfin): if not is_mapping(wrfin): wrfin = next(iter(wrfin)) # only need one file @@ -177,43 +179,43 @@ def _get_proj_params(wrfin, timeidx, stagger, method, squeeze, cache, _key): first_entry = next(iter(viewkeys(wrfin))) wrfin = wrfin[first_entry] key = _key[first_entry] - return _get_proj_params(wrfin, timeidx, stagger, + return _get_proj_params(wrfin, timeidx, stagger, 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]) - + # Note: fortran index known_x = 1.0 known_y = 1.0 - + return (map_proj, truelat1, truelat2, stdlon, ref_lat, ref_lon, pole_lat, pole_lon, known_x, known_y, dx, dy, latinc, loninc) - + # known_x and known_y are 0-based def _kwarg_proj_params(**projparams): """Return the map projection parameters. - - This function aggregates the projection parameter keyword + + This function aggregates the projection parameter keyword arguments and also performs sanity checking on them. - + Args: - + **projparams: Projection parameter keyword arguments. - + Returns: - + :obj:`tuple`: The map projection parameters. - + """ projparams = dict_keys_to_upper(projparams) - + map_proj = projparams.get("MAP_PROJ") truelat1 = projparams.get("TRUELAT1") truelat2 = projparams.get("TRUELAT2") @@ -222,164 +224,164 @@ 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") latinc = projparams.get("LATINC") loninc = projparams.get("LONINC") - + # 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)) - + # ref_lat and ref_lon are expected to be lists ref_lat = np.ravel(np.asarray([ref_lat])) ref_lon = np.ravel(np.asarray([ref_lon])) - + # Fortran wants 1-based indexing known_x = known_x + 1 known_y = known_y + 1 - - if map_proj in (ProjectionTypes.LAMBERT_CONFORMAL, - ProjectionTypes.POLAR_STEREOGRAPHIC, + + if map_proj in (ProjectionTypes.LAMBERT_CONFORMAL, + ProjectionTypes.POLAR_STEREOGRAPHIC, ProjectionTypes.MERCATOR): if truelat1 is None: raise ValueError("'TRUELAT1' argument required") else: if truelat1 is None: truelat1 = 0.0 - + # Map projection 6 (lat lon) required latinc, loninc, and dy if map_proj == ProjectionTypes.LAT_LON: if latinc is None: raise ValueError("'LATINC' argument required") - + if loninc is None: raise ValueError("'LONINC' argument required") - + if dy is None: raise ValueError("'DY' argument required") else: latinc = 0.0 loninc = 0.0 dy = 0.0 - + return (map_proj, truelat1, truelat2, stdlon, ref_lat, ref_lon, pole_lat, pole_lon, known_x, known_y, dx, dy, latinc, loninc) # 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 + + The *latitude* and *longitude* arguments can be a single value or a sequence of values. - - The leftmost dimension of the returned array represents two different + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain the X (west_east) values. - return_val[1,...] will contain the Y (south_north) values. - + Args: - - latitude (:obj:`float` or sequence): A single latitude or a sequence + + latitude (:obj:`float` or sequence): A single latitude or a sequence of latitude values to be converted. - - longitude (:obj:`float` or sequence): A single longitude or a sequence + + longitude (:obj:`float` or sequence): A single longitude or a sequence of latitude values to be converted. - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - stagger (:obj:`str`): By default, the latitude and longitude are - returned on the mass grid, but a staggered grid can be chosen + + stagger (:obj:`str`): By default, the latitude and longitude are + returned on the mass grid, but a staggered grid can be chosen with the following options: - + - 'm': Use the mass grid (default). - - 'u': Use the same staggered grid as the u wind component, + - 'u': Use the same staggered grid as the u wind component, which has a staggered west_east (x) dimension. - - 'v': Use the same staggered grid as the v wind component, + - 'v': Use the same staggered grid as the v wind component, which has a staggered south_north (y) dimension. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - - as_int (:obj:`bool`): Set to True to return the x,y values as + + as_int (:obj:`bool`): Set to True to return the x,y values as :obj:`int`, otherwise they will be returned as :obj:`float`. - + **projparams: Map projection keyword arguments to set manually. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The x,y coordinate value(s) whose leftmost dimension is 2 (0=X, 1=Y). - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - + 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) lons = np.asarray(longitude) - + # Note: For scalars, this will make a single element array lats = lats.ravel() - + lons = lons.ravel() - + if (lats.size != lons.size): raise ValueError("'latitude' and 'longitude' " "must be the same length") - + if ref_lat.size == 1: outdim = [2, lats.size] extra_dims = [outdim[1]] @@ -387,11 +389,10 @@ def _ll_to_xy(latitude, longitude, wrfin=None, timeidx=0, # Moving domain will have moving ref_lats/ref_lons outdim = [2, ref_lat.size, lats.size] extra_dims = outdim[1:] - + 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 @@ -401,149 +402,148 @@ def _ll_to_xy(latitude, longitude, wrfin=None, timeidx=0, else: ref_lat_val = ref_lat[left_idxs[-2]] ref_lon_val = ref_lon[left_idxs[-2]] - + lat = lats[left_idxs[-1]] 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] result[y_idxs] = xy[0] - + else: 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 - + if as_int: result = np.rint(result).astype(int) - + 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): - +def _xy_to_ll(x, y, wrfin=None, timeidx=0, stagger=None, + method="cat", squeeze=True, cache=None, _key=None, + **projparams): + """Return the latitude and longitude for specified x,y coordinates. - + The *x* and *y* arguments can be a single value or a sequence of values. - - The leftmost dimension of the returned array represents two different + + The leftmost dimension of the returned array represents two different quantities: - + - return_val[0,...] will contain the latitude values. - return_val[1,...] will contain the longitude values. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - x (:obj:`float` or sequence): A single x-coordinate or a sequence + + x (:obj:`float` or sequence): A single x-coordinate or a sequence of x-coordinate values to be converted. - - y (:obj:`float` or sequence): A single y-coordinate or a sequence + + y (:obj:`float` or sequence): A single y-coordinate or a sequence of y-coordinate values to be converted. - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - stagger (:obj:`str`): By default, the latitude and longitude are - returned on the mass grid, but a staggered grid can be chosen + + stagger (:obj:`str`): By default, the latitude and longitude are + returned on the mass grid, but a staggered grid can be chosen with the following options: - + - 'm': Use the mass grid (default). - - 'u': Use the same staggered grid as the u wind component, + - 'u': Use the same staggered grid as the u wind component, which has a staggered west_east (x) dimension. - - 'v': Use the same staggered grid as the v wind component, + - 'v': Use the same staggered grid as the v wind component, which has a staggered south_north (y) dimension. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + **projparams: Map projection keyword arguments to set manually. - + Returns: - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The - latitude and longitude values whose leftmost dimension is 2 + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The + latitude and longitude values whose leftmost dimension is 2 (0=latitude, 1=longitude). - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - + 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) y_arr = np.asarray(y) - + # Convert 0-based x, y to 1-based x_arr = x_arr + 1 y_arr = y_arr + 1 - + x_arr = x_arr.ravel() - + y_arr = y_arr.ravel() - + if (x_arr.size != y_arr.size): raise ValueError("'x' and 'y' must be the same length") - + if ref_lat.size == 1: outdim = [2, x_arr.size] extra_dims = [outdim[1]] @@ -551,44 +551,37 @@ def _xy_to_ll(x, y, wrfin=None, timeidx=0, stagger=None, # Moving domain will have moving ref_lats/ref_lons outdim = [2, ref_lat.size, x_arr.size] extra_dims = outdim[1:] - + 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 - + if ref_lat.size == 1: ref_lat_val = ref_lat[0] ref_lon_val = ref_lon[0] else: ref_lat_val = ref_lat[left_idxs[-2]] ref_lon_val = ref_lon[left_idxs[-2]] - + x_val = x_arr[left_idxs[-1]] y_val = y_arr[left_idxs[-1]] - - ll = _xytoll(map_proj, truelat1, truelat2, stdlon, ref_lat_val, + + ll = _xytoll(map_proj, truelat1, truelat2, stdlon, ref_lat_val, 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] - + else: # Convert 0-based to 1-based for Fortran 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) - - return result - + 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 diff --git a/src/wrf/metadecorators.py b/src/wrf/metadecorators.py index ea00d75..0d58908 100644 --- a/src/wrf/metadecorators.py +++ b/src/wrf/metadecorators.py @@ -1,6 +1,6 @@ from __future__ import (absolute_import, division, print_function) import warnings -import wrapt +import wrapt from collections import OrderedDict import numpy as np @@ -8,7 +8,7 @@ import numpy.ma as ma from .extension import _interpline from .util import (extract_vars, either, from_args, arg_location, - is_coordvar, latlon_coordvars, to_np, + is_coordvar, latlon_coordvars, to_np, from_var, iter_left_indexes, is_mapping, is_moving_domain, is_latlon_pair) from .coordpair import CoordPair @@ -18,80 +18,80 @@ from .config import xarray_enabled if xarray_enabled(): from xarray import DataArray - + def copy_and_set_metadata(copy_varname=None, delete_attrs=None, name=None, - remove_dims=None, dimnames=None, + remove_dims=None, dimnames=None, coords=None, **fixed_attrs): """A decorator that sets the metadata for a wrapped function's output. - - Generally, the metadata is copied from the variable specified by - *copy_varname*, with other fixed fields set by the other decorator + + Generally, the metadata is copied from the variable specified by + *copy_varname*, with other fixed fields set by the other decorator arguments. - - The *cache* argument used by most diagnostic routines is supplied by + + The *cache* argument used by most diagnostic routines is supplied by this decorator when the *copy_varname* variable is extracted, in order to prevent the variable from being extracted again by the wrapped function. - - If the wrapped function's *meta* argument is False, then this decorator + + If the wrapped function's *meta* argument is False, then this decorator returns the wrapped function output without applying the metadata. - + Args: - + copy_varname (:obj:`str`, optional): The NetCDF variable name to copy. Default is None. - - delete_attrs (sequence of :obj:`str`, optional): A sequence of key - names to remove from the :attr:`xarray.DataArray.attrs` attribute - in the wrapped function output (after being copied from + + delete_attrs (sequence of :obj:`str`, optional): A sequence of key + names to remove from the :attr:`xarray.DataArray.attrs` attribute + in the wrapped function output (after being copied from *copy_varname*). Default is None. - - name (:obj:`str`): The name to use for the + + name (:obj:`str`): The name to use for the :attr:`xarray.DataArray.name` attribute. - - remove_dims (sequence of :obj:`int`, optional): A sequence of dimension - indexes to be removed from the wrapped function output (after being - copied from *copy_varname*). This is useful when the copy - variable is three dimensional but the wrapped function output - is two dimensional, and you still want to keep the names of + + remove_dims (sequence of :obj:`int`, optional): A sequence of dimension + indexes to be removed from the wrapped function output (after being + copied from *copy_varname*). This is useful when the copy + variable is three dimensional but the wrapped function output + is two dimensional, and you still want to keep the names of the rightmost two dimensions. Default is None. - + dimnames (sequence of :obj:`str`, optional): A sequence of dimension - names in order to manually set the + names in order to manually set the :attr:`xarray.DataArray.dims` attribute. Default is None. - - coords (:obj:`dict`): A mapping of coordinate name to coordinate - value to manually specify the :attr:`xarray.DataArray.coords` + + coords (:obj:`dict`): A mapping of coordinate name to coordinate + value to manually specify the :attr:`xarray.DataArray.coords` attribute. Default is None. - - **fixed_attrs: These keyword arguments are added to the + + **fixed_attrs: These keyword arguments are added to the :attr:`xarray.DataArray.attrs` attribute. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - function output with or without metadata. If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + function output with or without metadata. If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - - + + """ @wrapt.decorator - def func_wrapper(wrapped, instance, args, kwargs): + def func_wrapper(wrapped, instance, args, kwargs): do_meta = from_args(wrapped, ("meta",), *args, **kwargs)["meta"] - + if do_meta is None: do_meta = True - + if not xarray_enabled() or not do_meta: return wrapped(*args, **kwargs) - - argvars = from_args(wrapped, ("wrfin", "timeidx", "method", + + argvars = from_args(wrapped, ("wrfin", "timeidx", "method", "squeeze", "cache", "units", "meta", - "_key"), + "_key"), *args, **kwargs) - + wrfin = argvars["wrfin"] timeidx = argvars["timeidx"] units = argvars["units"] @@ -101,147 +101,145 @@ def copy_and_set_metadata(copy_varname=None, delete_attrs=None, name=None, _key = argvars["_key"] if cache is None: cache = {} - + # Note: can't modify nonlocal var if (callable(copy_varname)): _copy_varname = copy_varname(wrfin) else: _copy_varname = copy_varname - + # Extract the copy_from argument - var_to_copy = None if cache is None else cache.get(_copy_varname, + 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,), + var_to_copy = extract_vars(wrfin, timeidx, (_copy_varname,), method, squeeze, cache, meta=True, _key=_key)[_copy_varname] - + # Make a copy so we don't modify a user supplied cache - new_cache = dict(cache) + new_cache = dict(cache) new_cache[_copy_varname] = var_to_copy - + # Don't modify the original args/kargs. The args need to be a list # so it can be modified. new_args, cache_argloc = arg_location(wrapped, "cache", args, kwargs) new_args[cache_argloc] = new_cache - + result = wrapped(*new_args) - + outname = "" outdimnames = list() outcoords = OrderedDict() outattrs = OrderedDict() - + if copy_varname is not None: outname = var_to_copy.name - + if dimnames is not None: outdimnames = dimnames outcoords = coords else: outdimnames += var_to_copy.dims outcoords.update(var_to_copy.coords) - + outattrs.update(var_to_copy.attrs) - + if remove_dims is not None: for dimname in remove_dims: outdimnames.remove(dimname) - + try: del outcoords[dimname] except KeyError: pass - - + if name is not None: outname = name - + if units is not None: outattrs["units"] = units - + for argname, val in viewitems(fixed_attrs): outattrs[argname] = val - + if delete_attrs is not None: for attr in delete_attrs: try: del outattrs[attr] except KeyError: pass - + if isinstance(result, ma.MaskedArray): outattrs["_FillValue"] = result.fill_value outattrs["missing_value"] = result.fill_value - - return DataArray(result, name=outname, coords=outcoords, - dims=outdimnames, attrs=outattrs) - + + return DataArray(result, name=outname, coords=outcoords, + dims=outdimnames, attrs=outattrs) + return func_wrapper -def set_wind_metadata(copy_varname, name, description, - wind_ncvar=False, +def set_wind_metadata(copy_varname, name, description, + wind_ncvar=False, two_d=False, wspd_wdir=False): """A decorator that sets the metadata for a wrapped wind function's output. - + This is a special metadata decorator for working with wind functions, which - include wind extraction routines, uvmet routines, and + include wind extraction routines, uvmet routines, and wind speed / wind direction routines. - - If the wrapped function's *meta* argument is False, then this decorator + + If the wrapped function's *meta* argument is False, then this decorator returns the wrapped function output without applying the metadata. - + Args: - + copy_varname (:obj:`str`, optional): The NetCDF variable name to copy. Default is None. - - name (:obj:`str`): The name to use for the + + name (:obj:`str`): The name to use for the :attr:`xarray.DataArray.name` attribute. - - description (:obj:`str`): The description to use for the 'description' + + description (:obj:`str`): The description to use for the 'description' key in the :attr:`xarray.DataArray.attrs` attribute. - - wind_ncvar (:obj:`bool`, optional): Set to True when the wrapped - function is simply extracting a wind variable (U, V, W) from the - NetCDF file. Set to False for other types of wind algorithms + + wind_ncvar (:obj:`bool`, optional): Set to True when the wrapped + function is simply extracting a wind variable (U, V, W) from the + NetCDF file. Set to False for other types of wind algorithms (uvmet, wspd_wdir, etc). Default is False. - - two_d (:obj:`bool`, optional): Set to True if the wind field is + + two_d (:obj:`bool`, optional): Set to True if the wind field is two-dimensional. Set to False for a three-dimensional wind field. Default is False. - - wspd_wdir (:obj:`bool`): Set to True if the wrapped function is a + + wspd_wdir (:obj:`bool`): Set to True if the wrapped function is a wind speed / wind direction algorithm. Otherwise, set to False. Default is False. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - wind function output with or without metadata. If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + wind function output with or without metadata. If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - - + + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): do_meta = from_args(wrapped, ("meta",), *args, **kwargs)["meta"] - + if do_meta is None: do_meta = True - + if not xarray_enabled() or not do_meta: return wrapped(*args, **kwargs) - - argvars = from_args(wrapped, ("wrfin", "timeidx", "units", + + argvars = from_args(wrapped, ("wrfin", "timeidx", "units", "method", "squeeze", "ten_m", "cache", - "_key"), - *args, **kwargs) + "_key"), + *args, **kwargs) wrfin = argvars["wrfin"] timeidx = argvars["timeidx"] units = argvars["units"] @@ -252,35 +250,33 @@ def set_wind_metadata(copy_varname, name, description, _key = argvars["_key"] if cache is None: cache = {} - + if isinstance(copy_varname, either): _copy_varname = copy_varname(wrfin) else: _copy_varname = copy_varname - - copy_var = extract_vars(wrfin, timeidx, _copy_varname, - method, squeeze, cache, + + copy_var = extract_vars(wrfin, timeidx, _copy_varname, + method, squeeze, cache, meta=True, _key=_key)[_copy_varname] - + # Make a copy so we don't modify a user supplied cache - new_cache = dict(cache) + new_cache = dict(cache) new_cache[_copy_varname] = copy_var - + # Don't modify the original args/kargs. The args need to be a list # so it can be modified. new_args, cache_argloc = arg_location(wrapped, "cache", args, kwargs) new_args[cache_argloc] = new_cache - + result = wrapped(*new_args) - + outcoords = OrderedDict() outattrs = OrderedDict() - + outdimnames = list(copy_var.dims) - #outcoords.update(copy_var.coords) outattrs.update(copy_var.attrs) - - + if wind_ncvar: outcoords.update(copy_var.coords) elif not wspd_wdir: @@ -296,70 +292,70 @@ def set_wind_metadata(copy_varname, name, description, else: outdimnames.insert(0, "wspd_wdir") outattrs["MemoryOrder"] = "XY" - + outcoords["wspd_wdir"] = ["wspd", "wdir"] - - if units is not None: + + if units is not None: outattrs["units"] = units - - # 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 + + # 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. 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": outcoords[key] = dataarray.dims, to_np(dataarray) elif key == "Time": outcoords[key] = to_np(dataarray) - + outname = name outattrs["description"] = description - - return DataArray(result, name=outname, coords=outcoords, - dims=outdimnames, attrs=outattrs) - + + return DataArray(result, name=outname, coords=outcoords, + dims=outdimnames, attrs=outattrs) + return func_wrapper def set_cape_metadata(is2d): """A decorator that sets the metadata for a wrapped CAPE function's output. - + This is a special metadata decorator for working with CAPE functions. - - If the wrapped function's *meta* argument is False, then this decorator + + If the wrapped function's *meta* argument is False, then this decorator returns the wrapped function output without applying the metadata. - + Args: - - is2d (:obj:`bool`): Set to True if the wrapped function is for a + + is2d (:obj:`bool`): Set to True if the wrapped function is for a two-dimensional CAPE routine. Set to False for a three-dimensional CAPE routine. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - CAPE function output with or without metadata. If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + CAPE function output with or without metadata. If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): do_meta = from_args(wrapped, ("meta",), *args, **kwargs)["meta"] - + if do_meta is None: do_meta = True - + if not xarray_enabled() or not do_meta: return wrapped(*args, **kwargs) - - argvars = from_args(wrapped, ("wrfin", "timeidx", "method", "squeeze", - "cache", "_key", "missing"), - *args, **kwargs) + + argvars = from_args(wrapped, ("wrfin", "timeidx", "method", "squeeze", + "cache", "_key", "missing"), + *args, **kwargs) wrfin = argvars["wrfin"] timeidx = argvars["timeidx"] method = argvars["method"] @@ -369,27 +365,27 @@ def set_cape_metadata(is2d): _key = argvars["_key"] if cache is None: cache = {} - + _copy_varname = "P" - copy_var = extract_vars(wrfin, timeidx, _copy_varname, method, squeeze, + copy_var = extract_vars(wrfin, timeidx, _copy_varname, method, squeeze, cache, meta=True, _key=_key)[_copy_varname] - + # Make a copy so we don't modify a user supplied cache - new_cache = dict(cache) + new_cache = dict(cache) new_cache[_copy_varname] = copy_var - + # Don't modify the original args/kargs. The args need to be a list # so it can be modified. new_args, cache_argloc = arg_location(wrapped, "cache", args, kwargs) new_args[cache_argloc] = new_cache - + result = wrapped(*new_args) - + outcoords = OrderedDict() outattrs = OrderedDict() outattrs.update(copy_var.attrs) outdimnames = [None] * result.ndim - + if is2d: # Right dims outdimnames[-2:] = copy_var.dims[-2:] @@ -410,69 +406,67 @@ def set_cape_metadata(is2d): outattrs["units"] = "J kg-1 ; J kg-1" outattrs["MemoryOrder"] = "XYZ" outname = "cape_3d" - + 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 + # 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": outcoords[key] = dataarray.dims, to_np(dataarray) elif key == "Time": outcoords[key] = to_np(dataarray) - + if is2d: outcoords["mcape_mcin_lcl_lfc"] = ["mcape", "mcin", "lcl", "lfc"] else: outcoords["cape_cin"] = ["cape", "cin"] - - - return DataArray(result, name=outname, coords=outcoords, - dims=outdimnames, attrs=outattrs) - + + return DataArray(result, name=outname, coords=outcoords, + dims=outdimnames, attrs=outattrs) + return func_wrapper def set_cloudfrac_metadata(): - """A decorator that sets the metadata for a wrapped cloud fraction + """A decorator that sets the metadata for a wrapped cloud fraction function's output. - - This is a special metadata decorator for working with cloud fraction + + This is a special metadata decorator for working with cloud fraction functions. - - If the wrapped function's *meta* argument is False, then this decorator + + If the wrapped function's *meta* argument is False, then this decorator returns the wrapped function output without applying the metadata. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - cloud fraction function output with or without metadata. If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + cloud fraction function output with or without metadata. If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): do_meta = from_args(wrapped, ("meta",), *args, **kwargs)["meta"] - + if do_meta is None: do_meta = True - + if not xarray_enabled() or not do_meta: return wrapped(*args, **kwargs) - - argvars = from_args(wrapped, ("wrfin", "timeidx", "method", "squeeze", - "cache", "_key", "vert_type", - "low_thresh", "mid_thresh", - "high_thresh", "missing"), + + argvars = from_args(wrapped, ("wrfin", "timeidx", "method", "squeeze", + "cache", "_key", "vert_type", + "low_thresh", "mid_thresh", + "high_thresh", "missing"), *args, **kwargs) wrfin = argvars["wrfin"] timeidx = argvars["timeidx"] @@ -485,34 +479,34 @@ def set_cloudfrac_metadata(): mid_thresh = argvars["mid_thresh"] high_thresh = argvars["high_thresh"] missing = argvars["missing"] - + if cache is None: cache = {} - + _copy_varname = "P" - copy_var = extract_vars(wrfin, timeidx, _copy_varname, method, squeeze, + copy_var = extract_vars(wrfin, timeidx, _copy_varname, method, squeeze, cache, meta=True, _key=_key)[_copy_varname] - + # Make a copy so we don't modify a user supplied cache - new_cache = dict(cache) + new_cache = dict(cache) new_cache[_copy_varname] = copy_var - + # Don't modify the original args/kargs. The args need to be a list # so it can be modified. new_args, cache_argloc = arg_location(wrapped, "cache", args, kwargs) new_args[cache_argloc] = new_cache - + result = wrapped(*new_args) - + outcoords = OrderedDict() outattrs = OrderedDict() outattrs.update(copy_var.attrs) outdimnames = [None] * result.ndim - + # For printing units - unitstr = ("Pa" if vert_type.lower() == "pres" + unitstr = ("Pa" if vert_type.lower() == "pres" or vert_type.lower() == "pressure" else "m") - + # For setting the threholds in metdata if vert_type.lower() == "pres" or vert_type.lower() == "pressure": _low_thresh = 97000. if low_thresh is None else low_thresh @@ -522,7 +516,7 @@ def set_cloudfrac_metadata(): _low_thresh = 300. if low_thresh is None else low_thresh _mid_thresh = 2000. if mid_thresh is None else mid_thresh _high_thresh = 6000. if high_thresh is None else high_thresh - + # Right dims outdimnames[-2:] = copy_var.dims[-2:] # Left dims @@ -538,156 +532,156 @@ def set_cloudfrac_metadata(): outattrs["missing_value"] = missing outname = "cloudfrac" - # 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 + # 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": outcoords[key] = dataarray.dims, to_np(dataarray) elif key == "Time": outcoords[key] = to_np(dataarray) - + outcoords["low_mid_high"] = ["low", "mid", "high"] - - return DataArray(result, name=outname, coords=outcoords, - dims=outdimnames, attrs=outattrs) - + + return DataArray(result, name=outname, coords=outcoords, + dims=outdimnames, attrs=outattrs) + return func_wrapper def set_latlon_metadata(xy=False): - """A decorator that sets the metadata for a wrapped latlon function's + """A decorator that sets the metadata for a wrapped latlon function's output. - + This is a special metadata decorator for working with latlon functions. - - If the wrapped function's *meta* argument is False, then this decorator + + If the wrapped function's *meta* argument is False, then this decorator returns the wrapped function output without applying the metadata. - + Args: - - xy (:obj:`bool`, optional): Set to True if the wrapped function returns - xy values (ll_to_xy). Set to False if the wrapped function returns + + xy (:obj:`bool`, optional): Set to True if the wrapped function returns + xy values (ll_to_xy). Set to False if the wrapped function returns latlon values (xy_to_ll). Default is False. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - latlon function output with or without metadata. If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + latlon function output with or without metadata. If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): - + argvars = from_args(wrapped, ("wrfin", "meta"), *args, **kwargs) # If it's a mapping, then this is handled as a special case in g_latlon do_meta = (not is_mapping(argvars["wrfin"]) and argvars["meta"]) if do_meta is None: do_meta = True - + if not xarray_enabled() or not do_meta: return wrapped(*args, **kwargs) - + # Set squeeze to False. Squeeze will be handled in here - new_args, squeeze_argloc = arg_location(wrapped, "squeeze", args, + new_args, squeeze_argloc = arg_location(wrapped, "squeeze", args, kwargs) new_args[squeeze_argloc] = False - + result = wrapped(*new_args) - + # Want to preserve the input coordinate pair in metadata if result.ndim == 1: result = result[:, np.newaxis] - + argnames = ["x", "y"] if not xy else ["latitude", "longitude"] argnames.append("squeeze") outname = "latlon" if not xy else "xy" - + if result.ndim == 2: dimnames = (["lat_lon", "idx"] if not xy else ["x_y", "idx"]) else: - dimnames = (["lat_lon", "domain_idx", "idx"] if not xy + dimnames = (["lat_lon", "domain_idx", "idx"] if not xy else ["x_y", "domain_idx", "idx"]) - + argvars = from_args(wrapped, argnames, *args, **kwargs) - + var1 = argvars[argnames[0]] var2 = argvars[argnames[1]] squeeze = argvars["squeeze"] - + arr1 = np.asarray(var1).ravel() arr2 = np.asarray(var2).ravel() - + coords = {} if not xy: - coords["xy_coord"] = (dimnames[-1], [CoordPair(x=x[0], y=x[1]) - for x in zip(arr1, arr2)]) + coords["xy_coord"] = (dimnames[-1], [CoordPair(x=x[0], y=x[1]) + 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) - + if squeeze: da = da.squeeze() - + return da - + return func_wrapper def set_height_metadata(geopt=False, stag=False): - """A decorator that sets the metadata for a wrapped height function's + """A decorator that sets the metadata for a wrapped height function's output. - + This is a special metadata decorator for working with height functions. - - If the wrapped function's *meta* argument is False, then this decorator + + If the wrapped function's *meta* argument is False, then this decorator returns the wrapped function output without applying the metadata. - + Args: - - geopt (:obj:`bool`, optional): Set to True if the wrapped function - returns geopotential. Set to True if the wrapped function + + geopt (:obj:`bool`, optional): Set to True if the wrapped function + returns geopotential. Set to True if the wrapped function returns geopotential height. Default is False. - - stag (:obj:`bool`, optional): Set to True to use the vertical + + stag (:obj:`bool`, optional): Set to True to use the vertical staggered grid, rather than the mass grid. Default is False. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - height function output with or without metadata. If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + height function output with or without metadata. If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): do_meta = from_args(wrapped, ("meta",), *args, **kwargs)["meta"] - + if do_meta is None: do_meta = True - + if not xarray_enabled() or not do_meta: return wrapped(*args, **kwargs) - - argvars = from_args(wrapped, ("wrfin", "timeidx", "method", - "squeeze", "units", "msl", "cache", - "_key"), - *args, **kwargs) + + argvars = from_args(wrapped, ("wrfin", "timeidx", "method", + "squeeze", "units", "msl", "cache", + "_key"), + *args, **kwargs) wrfin = argvars["wrfin"] timeidx = argvars["timeidx"] units = argvars["units"] @@ -696,10 +690,10 @@ def set_height_metadata(geopt=False, stag=False): msl = argvars["msl"] cache = argvars["cache"] _key = argvars["_key"] - + if cache is None: cache = {} - + is_met_em = False # For height, either copy the met_em GHT variable or copy and modify # pressure (which has the same dims as destaggered height) @@ -707,32 +701,32 @@ def set_height_metadata(geopt=False, stag=False): ht_metadata_varname = either("P", "GHT")(wrfin) else: ht_metadata_varname = either("PH", "GHT")(wrfin) - + if ht_metadata_varname == "GHT": is_met_em = True - - ht_var = extract_vars(wrfin, timeidx, ht_metadata_varname, + + ht_var = extract_vars(wrfin, timeidx, ht_metadata_varname, method, squeeze, cache, meta=True, _key=_key) ht_metadata_var = ht_var[ht_metadata_varname] - + # Make a copy so we don't modify a user supplied cache - new_cache = dict(cache) + new_cache = dict(cache) new_cache[ht_metadata_varname] = ht_metadata_var - + # Don't modify the original args/kargs. The args need to be a list # so it can be modified. new_args, cache_argloc = arg_location(wrapped, "cache", args, kwargs) new_args[cache_argloc] = new_cache - + result = wrapped(*new_args) - + outcoords = OrderedDict() outattrs = OrderedDict() outdimnames = list(ht_metadata_var.dims) outcoords.update(ht_metadata_var.coords) outattrs.update(ht_metadata_var.attrs) - + if geopt: outname = "geopt" outattrs["units"] = "m2 s-2" @@ -742,7 +736,7 @@ def set_height_metadata(geopt=False, stag=False): outattrs["description"] = ("geopotential (vertically " "staggered grid)") else: - outname = "height" if msl else "height_agl" + outname = "height" if msl else "height_agl" outattrs["units"] = units height_type = "MSL" if msl else "AGL" if not stag or is_met_em: @@ -750,88 +744,88 @@ def set_height_metadata(geopt=False, stag=False): "(mass grid)".format(height_type)) else: outattrs["description"] = ("model height - [{}] (vertically " - "staggered grid)".format(height_type)) - - - return DataArray(result, name=outname, - dims=outdimnames, coords=outcoords, attrs=outattrs) + "staggered grid)".format( + height_type)) + + return DataArray(result, name=outname, dims=outdimnames, + coords=outcoords, attrs=outattrs) + return func_wrapper -def _set_horiz_meta(wrapped, instance, args, kwargs): - """A decorator implementation that sets the metadata for a wrapped +def _set_horiz_meta(wrapped, instance, args, kwargs): + """A decorator implementation that sets the metadata for a wrapped horizontal interpolation function. - - If the wrapped function's *meta* argument is False, then this decorator + + If the wrapped function's *meta* argument is False, then this decorator returns the wrapped function output without applying the metadata. - + Args: - - wrapped: The wrapped function which in turns needs to be called by your + + wrapped: The wrapped function which in turns needs to be called by your wrapper function. - - instance: The object to which the wrapped function was bound when it + + instance: The object to which the wrapped function was bound when it was called. - - args: The list of positional arguments supplied when the decorated + + args: The list of positional arguments supplied when the decorated function was called. - - kwargs: The dictionary of keyword arguments supplied when the decorated + + kwargs: The dictionary of keyword arguments supplied when the decorated function was called. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - horiztontal interpolation function output with or without metadata. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + horiztontal interpolation function output with or without metadata. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :mod:`wrapt` - - """ - argvars = from_args(wrapped, ("field3d", "vert", "desiredlev", - "missing", "squeeze"), - *args, **kwargs) - + + """ + argvars = from_args(wrapped, ("field3d", "vert", "desiredlev", + "missing", "squeeze"), + *args, **kwargs) + field3d = argvars["field3d"] z = argvars["vert"] desiredlev = argvars["desiredlev"] _desiredlev = np.asarray(desiredlev) missingval = argvars["missing"] squeeze = argvars["squeeze"] - + result = wrapped(*args, **kwargs) - + levsare2d = _desiredlev.ndim >= 2 multiproduct = field3d.ndim - z.ndim == 1 - + # Defaults, in case the data isn't a DataArray outname = None outdimnames = None outcoords = None outattrs = OrderedDict() - + # Get the vertical level units vert_units = None if isinstance(z, DataArray): vert_units = z.attrs.get("units", None) - - + if isinstance(field3d, DataArray): outcoords = OrderedDict() outdimnames = list(field3d.dims) outcoords.update(field3d.coords) - + del outdimnames[-3] - + try: del outcoords[field3d.dims[-3]] except KeyError: - pass # xarray 0.9 - + pass # xarray 0.9 + if not levsare2d: outdimnames.insert(-2, "level") if _desiredlev.ndim == 0: @@ -847,71 +841,71 @@ def _set_horiz_meta(wrapped, instance, args, kwargs): else: d = field3d.dims[0:-3] + field3d.dims[-2:] outcoords["level"] = d, _desiredlev[:] - + outattrs.update(field3d.attrs) outname = "{0}_interp".format(field3d.name) - + else: outname = "field3d_interp" - + outattrs["missing_value"] = missingval outattrs["_FillValue"] = missingval outattrs["vert_units"] = vert_units - + for key in ("MemoryOrder", "description"): try: del outattrs[key] except KeyError: pass - - da = DataArray(result, name=outname, dims=outdimnames, + + da = DataArray(result, name=outname, dims=outdimnames, coords=outcoords, attrs=outattrs) - + return da.squeeze() if squeeze else da def _set_cross_meta(wrapped, instance, args, kwargs): """A decorator implementation that sets the metadata for a wrapped cross \ section interpolation function. - - If the wrapped function's *meta* argument is False, then this decorator + + If the wrapped function's *meta* argument is False, then this decorator returns the wrapped function output without applying the metadata. - + Args: - - wrapped: The wrapped function which in turns needs to be called by your + + wrapped: The wrapped function which in turns needs to be called by your wrapper function. - - instance: The object to which the wrapped function was bound when it + + instance: The object to which the wrapped function was bound when it was called. - - args: The list of positional arguments supplied when the decorated + + args: The list of positional arguments supplied when the decorated function was called. - - kwargs: The dictionary of keyword arguments supplied when the decorated + + kwargs: The dictionary of keyword arguments supplied when the decorated function was called. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - cross section interpolation function output with or without metadata. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + cross section interpolation function output with or without metadata. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :mod:`wrapt` - - """ - argvars = from_args(wrapped, ("field3d", "vert", "levels", - "latlon", "missing", + + """ + argvars = from_args(wrapped, ("field3d", "vert", "levels", + "latlon", "missing", "wrfin", "timeidx", "stagger", "projection", "ll_point", "pivot_point", "angle", "start_point", "end_point", "autolevels", - "cache"), - *args, **kwargs) - + "cache"), + *args, **kwargs) + field3d = argvars["field3d"] z = argvars["vert"] levels = argvars["levels"] @@ -928,23 +922,23 @@ def _set_cross_meta(wrapped, instance, args, kwargs): end_point = argvars["end_point"] autolevels = argvars["autolevels"] cache = argvars["cache"] - + start_point_xy = None end_point_xy = None pivot_point_xy = None - - if (inc_latlon is True or is_latlon_pair(start_point) or - is_latlon_pair(pivot_point)): - + + if (inc_latlon is True or is_latlon_pair(start_point) or + is_latlon_pair(pivot_point)): + if wrfin is not None: is_moving = is_moving_domain(wrfin) else: is_moving = False - + if timeidx is None: if wrfin is not None: - # Moving nests aren't supported with ALL_TIMES because the - # domain could move outside of the line, which causes + # Moving nests aren't supported with ALL_TIMES because the + # 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 " @@ -956,7 +950,7 @@ def _set_cross_meta(wrapped, instance, args, kwargs): else: # Domain not moving, just use 0 _timeidx = 0 - + # If using grid coordinates, then don't care about lat/lon # coordinates. Just use 0. else: @@ -965,36 +959,37 @@ def _set_cross_meta(wrapped, instance, args, kwargs): if is_moving: _timeidx = timeidx else: - # When using non-moving nests, set the time to 0 + # When using non-moving nests, set the time to 0 # 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, + xy_coords = to_xy_coords(pivot_point, wrfin, _timeidx, stagger, projection, ll_point) pivot_point_xy = (xy_coords.x, xy_coords.y) 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, + xy_coords = to_xy_coords(start_point, wrfin, _timeidx, stagger, projection, ll_point) start_point_xy = (xy_coords.x, xy_coords.y) else: start_point_xy = (start_point.x, start_point.y) - + if end_point.lat is not None and end_point.lon is not None: - xy_coords = to_xy_coords(end_point, wrfin, _timeidx, + xy_coords = to_xy_coords(end_point, wrfin, _timeidx, stagger, projection, ll_point) end_point_xy = (xy_coords.x, xy_coords.y) else: 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: new_cache = dict(cache) @@ -1003,170 +998,167 @@ def _set_cross_meta(wrapped, instance, args, kwargs): new_cache["xy"] = xy new_cache["var2dz"] = var2dz new_cache["z_var2d"] = z_var2d - + # Don't modify the original args/kargs. The args need to be a list # so it can be modified. new_args, cache_argloc = arg_location(wrapped, "cache", args, kwargs) new_args[cache_argloc] = new_cache - + result = wrapped(*new_args) - + # Defaults, in case the data isn't a DataArray outname = None outdimnames = None outcoords = None outattrs = 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) - + if isinstance(field3d, DataArray): 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 - - - # Delete any lat,lon coords + pass # Xarray 0.9 + + # Delete any lat,lon coords delkeys = [key for key in viewkeys(outcoords) if is_coordvar(key)] for key in delkeys: del outcoords[key] - + outdimnames.append("vertical") outdimnames.append("cross_line_idx") outattrs.update(field3d.attrs) - + outname = "{0}_cross".format(field3d.name) - + for key in ("MemoryOrder",): try: del outattrs[key] except KeyError: pass - + # Interpolate to get the lat/lon coords, if desired if inc_latlon: latcoordname, loncoordname = latlon_coordvars(field3d.coords) - + if latcoordname is not None and loncoordname is not None: latcoord = field3d.coords[latcoordname] loncoord = field3d.coords[loncoordname] - + if latcoord.ndim == 2: 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] outdims = extra_dims + xy.shape[-2:-1] - + latlon_loc = np.empty(outdims, np.object_) for left_dims in iter_left_indexes(extra_dims): idxs = left_dims + (slice(None),) 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",) outcoords["xy_loc"] = (loc_dimnames, latlon_loc) - + 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])))) - - else: - 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["vertical"] = z_var2d[:] - + else: if inc_latlon: warnings.warn("'latlon' is set to True, but 'field3d' is " "not of type xarray.DataArray and contains no " "coordinate information") outname = "field3d_cross" - + outattrs["orientation"] = cross_str outattrs["missing_value"] = missingval outattrs["_FillValue"] = missingval - - return DataArray(result, name=outname, dims=outdimnames, - coords=outcoords, attrs=outattrs) - + + return DataArray(result, name=outname, dims=outdimnames, + coords=outcoords, attrs=outattrs) + def _set_line_meta(wrapped, instance, args, kwargs): - """A decorator implementation that sets the metadata for a wrapped line + """A decorator implementation that sets the metadata for a wrapped line interpolation function. - - If the wrapped function's *meta* argument is False, then this decorator + + If the wrapped function's *meta* argument is False, then this decorator returns the wrapped function output without applying the metadata. - + Args: - - wrapped: The wrapped function which in turns needs to be called by your + + wrapped: The wrapped function which in turns needs to be called by your wrapper function. - - instance: The object to which the wrapped function was bound when it + + instance: The object to which the wrapped function was bound when it was called. - - args: The list of positional arguments supplied when the decorated + + args: The list of positional arguments supplied when the decorated function was called. - - kwargs: The dictionary of keyword arguments supplied when the decorated + + kwargs: The dictionary of keyword arguments supplied when the decorated function was called. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - line interpolation function output with or without metadata. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + line interpolation function output with or without metadata. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :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"] timeidx = argvars["timeidx"] @@ -1179,26 +1171,26 @@ def _set_line_meta(wrapped, instance, args, kwargs): end_point = argvars["end_point"] inc_latlon = argvars["latlon"] cache = argvars["cache"] - + if cache is None: cache = {} - + start_point_xy = None end_point_xy = None pivot_point_xy = None - - if (inc_latlon is True or is_latlon_pair(start_point) or - is_latlon_pair(pivot_point)): - + + if (inc_latlon is True or is_latlon_pair(start_point) or + is_latlon_pair(pivot_point)): + if wrfin is not None: is_moving = is_moving_domain(wrfin) else: is_moving = False - + if timeidx is None: if wrfin is not None: - # Moving nests aren't supported with ALL_TIMES because the - # domain could move outside of the line, which causes + # Moving nests aren't supported with ALL_TIMES because the + # 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 " @@ -1210,7 +1202,7 @@ def _set_line_meta(wrapped, instance, args, kwargs): else: # Domain not moving, just use 0 _timeidx = 0 - + # If using grid coordinates, then don't care about lat/lon # coordinates. Just use 0. else: @@ -1219,534 +1211,521 @@ def _set_line_meta(wrapped, instance, args, kwargs): if is_moving: _timeidx = timeidx else: - # When using non-moving nests, set the time to 0 + # When using non-moving nests, set the time to 0 # 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, + xy_coords = to_xy_coords(pivot_point, wrfin, _timeidx, stagger, projection, ll_point) pivot_point_xy = (xy_coords.x, xy_coords.y) else: - pivot_point_xy = (pivot_point.x, pivot_point.y) - - + 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, + xy_coords = to_xy_coords(start_point, wrfin, _timeidx, stagger, projection, ll_point) start_point_xy = (xy_coords.x, xy_coords.y) else: start_point_xy = (start_point.x, start_point.y) - + if end_point.lat is not None and end_point.lon is not None: - xy_coords = to_xy_coords(end_point, wrfin, _timeidx, + xy_coords = to_xy_coords(end_point, wrfin, _timeidx, stagger, projection, ll_point) end_point_xy = (xy_coords.x, xy_coords.y) 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 - new_cache = dict(cache) + new_cache = dict(cache) new_cache["xy"] = xy - + # Don't modify the original args/kargs. The args need to be a list # so it can be modified. new_args, cache_argloc = arg_location(wrapped, "cache", args, kwargs) new_args[cache_argloc] = new_cache - + result = wrapped(*new_args) - + # Defaults, in case the data isn't a DataArray outname = None outdimnames = None outcoords = None outattrs = 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)] for key in delkeys: del outcoords[key] - + outdimnames.append("line_idx") outattrs.update(field2d.attrs) - + outname = "{0}_line".format(field2d.name) - + for key in ("MemoryOrder",): try: del outattrs[key] except KeyError: pass - + # Interpolate to get the lat/lon coords, if desired if inc_latlon: latcoordname, loncoordname = latlon_coordvars(field2d.coords) - + if latcoordname is not None and loncoordname is not None: latcoord = field2d.coords[latcoordname] loncoord = field2d.coords[loncoordname] - + if latcoord.ndim == 2: 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]))) - ) - - # Moving domain + + 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: extra_dims = latcoord.shape[0:-2] outdims = extra_dims + xy.shape[-2:-1] - + latlon_loc = np.empty(outdims, np.object_) for left_dims in iter_left_indexes(extra_dims): idxs = left_dims + (slice(None),) 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])) - )[:] - - + 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",) outcoords["xy_loc"] = (loc_dimnames, latlon_loc) - + 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])))) - - 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: + 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 " "not of type xarray.DataArray and contains no " "coordinate information") outname = "field2d_line" - + outattrs["orientation"] = cross_str - - return DataArray(result, name=outname, dims=outdimnames, - coords=outcoords, attrs=outattrs) - + + return DataArray(result, name=outname, dims=outdimnames, + coords=outcoords, attrs=outattrs) + def _set_vinterp_meta(wrapped, instance, args, kwargs): - """A decorator implementation that sets the metadata for a wrapped + """A decorator implementation that sets the metadata for a wrapped vertical coordinate interpolation function. - - If the wrapped function's *meta* argument is False, then this decorator + + If the wrapped function's *meta* argument is False, then this decorator returns the wrapped function output without applying the metadata. - + Args: - - wrapped: The wrapped function which in turns needs to be called by your + + wrapped: The wrapped function which in turns needs to be called by your wrapper function. - - instance: The object to which the wrapped function was bound when it + + instance: The object to which the wrapped function was bound when it was called. - - args: The list of positional arguments supplied when the decorated + + args: The list of positional arguments supplied when the decorated function was called. - - kwargs: The dictionary of keyword arguments supplied when the decorated + + kwargs: The dictionary of keyword arguments supplied when the decorated function was called. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - vertical coordinate interpolation function output with or without - metadata. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + vertical coordinate interpolation function output with or without + metadata. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :mod:`wrapt` - - """ - argvars = from_args(wrapped, ("wrfin", "field", "vert_coord", + + """ + argvars = from_args(wrapped, ("wrfin", "field", "vert_coord", "interp_levels", "extrapolate", "field_type", "log_p", "timeidx", "method", "squeeze", - "cache"), - *args, **kwargs) - + "cache"), + *args, **kwargs) + field = argvars["field"] vert_coord = argvars["vert_coord"] interp_levels = argvars["interp_levels"] field_type = argvars["field_type"] - + result = wrapped(*args, **kwargs) - + # Defaults, in case the data isn't a DataArray outname = None outdimnames = None outcoords = None outattrs = OrderedDict() - - + if isinstance(field, DataArray): outcoords = OrderedDict() outdimnames = list(field.dims) outcoords.update(field.coords) - + outdimnames.remove(field.dims[-3]) 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: outname = field_type - + outattrs["vert_interp_type"] = vert_coord - - return DataArray(result, name=outname, dims=outdimnames, - coords=outcoords, attrs=outattrs) - - + + return DataArray(result, name=outname, dims=outdimnames, + coords=outcoords, attrs=outattrs) + + def _set_2dxy_meta(wrapped, instance, args, kwargs): - """A decorator implementation that sets the metadata for a wrapped line + """A decorator implementation that sets the metadata for a wrapped line cross section interpolation function. - - If the wrapped function's *meta* argument is False, then this decorator + + If the wrapped function's *meta* argument is False, then this decorator returns the wrapped function output without applying the metadata. - + Args: - - wrapped: The wrapped function which in turns needs to be called by your + + wrapped: The wrapped function which in turns needs to be called by your wrapper function. - - instance: The object to which the wrapped function was bound when it + + instance: The object to which the wrapped function was bound when it was called. - - args: The list of positional arguments supplied when the decorated + + args: The list of positional arguments supplied when the decorated function was called. - - kwargs: The dictionary of keyword arguments supplied when the decorated + + kwargs: The dictionary of keyword arguments supplied when the decorated function was called. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - line cross section interpolation function output with or without - metadata. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + line cross section interpolation function output with or without + metadata. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :mod:`wrapt` - - """ - argvars = from_args(wrapped, ("field3d", "xy"), *args, **kwargs) - + + """ + argvars = from_args(wrapped, ("field3d", "xy"), *args, **kwargs) + field3d = argvars["field3d"] xy = to_np(argvars["xy"]) - + result = wrapped(*args, **kwargs) - + # Use XY to set the cross-section metadata - st_x = xy[0,0] - st_y = xy[0,1] - ed_x = xy[-1,0] - ed_y = xy[-1,1] - - cross_str = "({0},{1}) to ({2},{3})".format(st_x, st_y, - ed_x, ed_y) - + 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) + outname = None outdimnames = None outcoords = None outattrs = OrderedDict() - + # Dims are (...,xy,z) if isinstance(field3d, DataArray): outcoords = OrderedDict() 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: outattrs["description"] = desc - + units = field3d.attrs.get("units", None) if units is not None: outattrs["units"] = units - + 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: del outattrs[key] except KeyError: pass - + else: outname = "field3d_2dxy" - + outattrs["orientation"] = cross_str - - return DataArray(result, name=outname, dims=outdimnames, - coords=outcoords, attrs=outattrs) + + return DataArray(result, name=outname, dims=outdimnames, + coords=outcoords, attrs=outattrs) def _set_1d_meta(wrapped, instance, args, kwargs): - """A decorator implementation that sets the metadata for a wrapped 1D + """A decorator implementation that sets the metadata for a wrapped 1D interpolation function. - - If the wrapped function's *meta* argument is False, then this decorator + + If the wrapped function's *meta* argument is False, then this decorator returns the wrapped function output without applying the metadata. - + Args: - - wrapped: The wrapped function which in turns needs to be called by your + + wrapped: The wrapped function which in turns needs to be called by your wrapper function. - - instance: The object to which the wrapped function was bound when it + + instance: The object to which the wrapped function was bound when it was called. - - args: The list of positional arguments supplied when the decorated + + args: The list of positional arguments supplied when the decorated function was called. - - kwargs: The dictionary of keyword arguments supplied when the decorated + + kwargs: The dictionary of keyword arguments supplied when the decorated function was called. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - 1D interpolation function output with or without metadata. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + 1D interpolation function output with or without metadata. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :mod:`wrapt` - - """ - argvars = from_args(wrapped, ("field", "z_in", "z_out", "missingval"), - *args, **kwargs) - + + """ + argvars = from_args(wrapped, ("field", "z_in", "z_out", "missingval"), + *args, **kwargs) + field = argvars["field"] z_in = argvars["z_in"] z_out = argvars["z_out"] missingval = argvars["missingval"] - + result = wrapped(*args, **kwargs) - + outname = None outdimnames = None outcoords = None outattrs = OrderedDict() - - # Dims are (...,xy,z) + + # Dims are (..., xy, z) if isinstance(field, DataArray): outcoords = OrderedDict() outdimnames = list(field.dims) - + outdimnames.pop(-1) - + for name in outdimnames: try: outcoords[name] = field.coords[name] except KeyError: continue - + outdimnames.append("z") outname = "{0}_z".format(field.name) outcoords["z"] = z_out - + desc = field.attrs.get("description", None) if desc is not None: outattrs["description"] = desc - + units = field.attrs.get("units", None) if units is not None: outattrs["units"] = units - + else: outname = "field_z" - + outattrs["_FillValue"] = missingval outattrs["missing_value"] = missingval - - return DataArray(result, name=outname, dims=outdimnames, + + return DataArray(result, name=outname, dims=outdimnames, coords=outcoords, attrs=outattrs) - + def _set_xy_meta(wrapped, instance, args, kwargs): - """A decorator implementation that sets the metadata for a wrapped xy line + """A decorator implementation that sets the metadata for a wrapped xy line interpolation function. - - If the wrapped function's *meta* argument is False, then this decorator + + If the wrapped function's *meta* argument is False, then this decorator returns the wrapped function output without applying the metadata. - + Args: - - wrapped: The wrapped function which in turns needs to be called by your + + wrapped: The wrapped function which in turns needs to be called by your wrapper function. - - instance: The object to which the wrapped function was bound when it + + instance: The object to which the wrapped function was bound when it was called. - - args: The list of positional arguments supplied when the decorated + + args: The list of positional arguments supplied when the decorated function was called. - - kwargs: The dictionary of keyword arguments supplied when the decorated + + kwargs: The dictionary of keyword arguments supplied when the decorated function was called. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - xy line interpolation function output with or without metadata. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + xy line interpolation function output with or without metadata. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + See Also: - + :mod:`wrapt` - - """ - argvars = from_args(wrapped, ("field", "pivot_point", "angle", - "start_point", "end_point"), - *args, **kwargs) - + + """ + argvars = from_args(wrapped, ("field", "pivot_point", "angle", + "start_point", "end_point"), + *args, **kwargs) + field = argvars["field"] pivot_point = argvars["pivot_point"] angle = argvars["angle"] start_point = argvars["start_point"] end_point = argvars["end_point"] - + result = wrapped(*args, **kwargs) - + if isinstance(field, DataArray): outname = "{0}_xy".format(field.name) else: outname = "xy" - + outdimnames = ["line_idx", "x_y"] outcoords = OrderedDict() outattrs = OrderedDict() - + outcoords["x_y"] = ["x", "y"] - + if pivot_point is not None and angle is not None: outattrs["pivot_point"] = pivot_point outattrs["angle"] = angle - + if start_point is not None and end_point is not None: outattrs["start_point"] = start_point outattrs["end_point"] = end_point - - return DataArray(result, name=outname, dims=outdimnames, - coords=outcoords, attrs=outattrs) - - + + return DataArray(result, name=outname, dims=outdimnames, + coords=outcoords, attrs=outattrs) + + def set_interp_metadata(interp_type): - """A decorator that sets the metadata for a wrapped interpolation + """A decorator that sets the metadata for a wrapped interpolation function. - - If the wrapped function's *meta* argument is False, then this decorator + + If the wrapped function's *meta* argument is False, then this decorator returns the wrapped function output without applying the metadata. - + Args: - + interp_type (:obj:`str`): The type of interpolation routine. Choices - are: 'horiz', 'cross', 'line', 'vinterp', '2dxy', '1d', + are: 'horiz', 'cross', 'line', 'vinterp', '2dxy', '1d', 'xy'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - interpolation function output with or without metadata. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + interpolation function output with or without metadata. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - - """ + + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): do_meta = from_args(wrapped, ("meta"), *args, **kwargs)["meta"] - + if do_meta is None: do_meta = True - + if not xarray_enabled() or not do_meta: return wrapped(*args, **kwargs) - + if interp_type == "horiz": return _set_horiz_meta(wrapped, instance, args, kwargs) elif interp_type == "cross": @@ -1761,104 +1740,102 @@ def set_interp_metadata(interp_type): return _set_1d_meta(wrapped, instance, args, kwargs) elif interp_type == "xy": return _set_xy_meta(wrapped, instance, args, kwargs) - + return func_wrapper -def set_alg_metadata(alg_ndims, refvarname, +def set_alg_metadata(alg_ndims, refvarname, refvarndims=None, missingarg=None, stagdim=None, stagsubvar=None, units=None, description=None): - """A decorator that sets the metadata for a wrapped raw diagnostic + """A decorator that sets the metadata for a wrapped raw diagnostic function. - + Args: - - alg_ndims (:obj:`int`): The number of dimensions returned by the + + alg_ndims (:obj:`int`): The number of dimensions returned by the wrapped function. - - refvarname (:obj:`str`): The wrapped function argument name for the + + refvarname (:obj:`str`): The wrapped function argument name for the reference variable. - - refvarndims (:obj:`int`, optional): The number of right dimensions for - the reference variable. This paramter is required when the - wrapped function result has less dimensions than reference. + + refvarndims (:obj:`int`, optional): The number of right dimensions for + the reference variable. This paramter is required when the + wrapped function result has less dimensions than reference. Default is None. - - missingarg (:obj:`str`, optional): The wrapped function argument name + + missingarg (:obj:`str`, optional): The wrapped function argument name for the missing value variable. Default is None. - - stagdim (:obj`int`, optional): The staggered dimension for the - reference. This is only needed if the reference variable is + + stagdim (:obj`int`, optional): The staggered dimension for the + reference. This is only needed if the reference variable is on a staggered grid. Default is None. - - stagsubvar (:obj:`str`, optional): The wrapped function argument name - to use to supply the unstaggered dimension name for the staggered - dimension in the reference. This is needed if *stagdim* is not + + stagsubvar (:obj:`str`, optional): The wrapped function argument name + to use to supply the unstaggered dimension name for the staggered + dimension in the reference. This is needed if *stagdim* is not None. It is primarily used for absolute vorticity. Default is None. - - units (:obj:`str`, optional): The units to use if if there is no + + units (:obj:`str`, optional): The units to use if if there is no 'units' argument for the wrapped function. Default is None. - - description (:obj:`str`, optional): A description for the wrapped - algorithm, which is stored in the :attr:`xarray.DataArray.attrs` + + description (:obj:`str`, optional): A description for the wrapped + algorithm, which is stored in the :attr:`xarray.DataArray.attrs` attribute under the 'description' key. Default is None. - - + + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - numerical function output with or without metadata. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + numerical function output with or without metadata. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): do_meta = from_args(wrapped, ("meta",), *args, **kwargs)["meta"] - + if do_meta is None: do_meta = True - + if not xarray_enabled() or not do_meta: return wrapped(*args, **kwargs) - - + result = wrapped(*args, **kwargs) - + outname = wrapped.__name__ outattrs = OrderedDict() - + # Default dimension names outdims = ["dim_{}".format(i) for i in py3range(result.ndim)] - + if missingarg is not None: - missingval = from_args(wrapped, (missingarg,), + missingval = from_args(wrapped, (missingarg,), *args, **kwargs)[missingarg] else: missingval = None - + if missingval is not None: outattrs["_FillValue"] = missingval outattrs["missing_value"] = missingval result = np.ma.masked_values(result, missingval) - + if units is not None: if isinstance(units, from_var): _units = units(wrapped, *args, **kwargs) if _units is not None: - outattrs["units"] = _units + outattrs["units"] = _units else: outattrs["units"] = units - + else: # Check for a units argument, if not, just ignore _units = from_args(wrapped, ("units",), *args, **kwargs)["units"] if _units is not None: outattrs["units"] = _units - - + if description is not None: if isinstance(description, from_var): desc = description(wrapped, *args, **kwargs) @@ -1866,37 +1843,36 @@ def set_alg_metadata(alg_ndims, refvarname, outattrs["description"] = desc else: outattrs["description"] = description - - + # Copy the dimnames from the reference variable, otherwise, use # the supplied dimnames if refvarname is not None: - refvar = from_args(wrapped, (refvarname,), + refvar = from_args(wrapped, (refvarname,), *args, **kwargs)[refvarname] else: refvar = None - + if stagsubvar is not None: - stagvar = from_args(wrapped, (stagsubvar,), - *args, **kwargs)[stagsubvar] + stagvar = from_args(wrapped, (stagsubvar,), + *args, **kwargs)[stagsubvar] else: stagvar = None - + if isinstance(refvar, DataArray): - + # Copy the right dims outdims[-alg_ndims:] = refvar.dims[-alg_ndims:] - + # Use the stagsubvar if applicable if stagvar is not None and stagdim is not None: outdims[stagdim] = stagvar.dims[stagdim] - - # Left dims + + # Left dims if refvarndims is None: # Used when result and reference are aligned on right if result.ndim > alg_ndims: result_extra = result.ndim - alg_ndims - + for i in py3range(1, result_extra + 1): idx = -alg_ndims - i if -idx <= refvar.ndim: @@ -1905,48 +1881,48 @@ def set_alg_metadata(alg_ndims, refvarname, continue # When reference and result aren't exactly aligned (slp) # (reference is 3D, result is 2D) - else: + else: 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: continue - + out = DataArray(result, name=outname, dims=outdims, attrs=outattrs) - + return out - + return func_wrapper def set_smooth_metdata(): @wrapt.decorator - def func_wrapper(wrapped, instance, args, kwargs): + def func_wrapper(wrapped, instance, args, kwargs): do_meta = from_args(wrapped, ("meta",), *args, **kwargs)["meta"] - + if do_meta is None: do_meta = True - + if not xarray_enabled() or not do_meta: return wrapped(*args, **kwargs) - - argvars = from_args(wrapped, ("field", "passes", "cenweight"), + + argvars = from_args(wrapped, ("field", "passes", "cenweight"), *args, **kwargs) - + field = argvars["field"] passes = argvars["passes"] cenweight = argvars["cenweight"] - + result = wrapped(*args, **kwargs) - + outname = "smooth2d" outdimnames = ["dim_{}".format(i) for i in py3range(result.ndim)] outcoords = OrderedDict() outattrs = OrderedDict() - + if isinstance(field, DataArray): outname = "smooth_" + field.name outdimnames = list(field.dims) @@ -1954,147 +1930,146 @@ def set_smooth_metdata(): outattrs.update(field.attrs) outattrs["passes"] = passes outattrs["cenweight"] = cenweight - + if isinstance(result, ma.MaskedArray): outattrs["_FillValue"] = result.fill_value outattrs["missing_value"] = result.fill_value - - return DataArray(result, name=outname, coords=outcoords, - dims=outdimnames, attrs=outattrs) - + + return DataArray(result, name=outname, coords=outcoords, + dims=outdimnames, attrs=outattrs) + return func_wrapper - - + + def set_uvmet_alg_metadata(units=None, description="earth rotated u,v", latarg="lat", windarg="u"): - """A decorator that sets the metadata for the wrapped raw UVMET diagnostic + """A decorator that sets the metadata for the wrapped raw UVMET diagnostic function. - + Args: - - units (:obj:`str`, optional): The units to use if if there is no + + units (:obj:`str`, optional): The units to use if if there is no 'units' argument for the wrapped function. Default is None. - - description (:obj:`str`, optional): A description for the wrapped - algorithm, which is stored in the :attr:`xarray.DataArray.attrs` + + description (:obj:`str`, optional): A description for the wrapped + algorithm, which is stored in the :attr:`xarray.DataArray.attrs` attribute under the 'description' key. Default is None. - - latarg (:obj:'str`, optional): The wrapped function argument name for + + latarg (:obj:'str`, optional): The wrapped function argument name for latitude. Default is 'lat'. - - windarg (:obj:`str`, optional): The wrapped function argument name for + + windarg (:obj:`str`, optional): The wrapped function argument name for the u wind component. Default is 'u'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - UVMET function output with or without metadata. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + UVMET function output with or without metadata. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): do_meta = from_args(wrapped, ("meta",), *args, **kwargs)["meta"] - + if do_meta is None: do_meta = True - + if not xarray_enabled() or not do_meta: return wrapped(*args, **kwargs) - + result = wrapped(*args, **kwargs) - + # Default dimension names outdims = ["dim_{}".format(i) for i in py3range(result.ndim)] - + outname = "uvmet" outattrs = OrderedDict() - + if units is not None: outattrs["units"] = units else: _units = from_args(wrapped, ("units",), *args, **kwargs)["units"] if _units is not None: outattrs["units"] = _units - + if description is not None: outattrs["description"] = description - + latvar = from_args(wrapped, latarg, *args, **kwargs)[latarg] uvar = from_args(wrapped, windarg, *args, **kwargs)[windarg] - + if isinstance(uvar, DataArray) and isinstance(latvar, DataArray): # Right dims come from latvar outdims[-2:] = latvar.dims[-2:] - + # Left dims come from u-var outdims[1:-2] = uvar.dims[0:-2] - + # Left-most is always u_v outdims[0] = "u_v" outcoords = {} outcoords["u_v"] = ["u", "v"] - + out = DataArray(result, name=outname, dims=outdims, coords=outcoords, attrs=outattrs) - + return out - + return func_wrapper def set_cape_alg_metadata(is2d, copyarg="pres_hpa"): - """A decorator that sets the metadata for the wrapped raw CAPE diagnostic + """A decorator that sets the metadata for the wrapped raw CAPE diagnostic function. - + Args: - - is2d (:obj:`bool`): Set to True for the two-dimensional CAPE + + is2d (:obj:`bool`): Set to True for the two-dimensional CAPE calculation, False for three-dimensional CAPE. - - copyarg (:obj:`str`): The wrapped function argument to use for + + copyarg (:obj:`str`): The wrapped function argument to use for copying dimension names. Default is 'pres_hpa'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - CAPE function output with or without metadata. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + CAPE function output with or without metadata. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): do_meta = from_args(wrapped, ("meta",), *args, **kwargs)["meta"] - + if do_meta is None: do_meta = True - + if not xarray_enabled() or not do_meta: return wrapped(*args, **kwargs) - + 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"] - + # Note: 2D/3D cape supports using only a single column of data is1d = p.ndim == 1 - + # Need to squeeze the right dimensions for 1D cape if is1d: result = np.squeeze(result) - + # Default dimension names outdims = ["dim_{}".format(i) for i in py3range(result.ndim)] - + outattrs = OrderedDict() - - + if is2d: if is1d: outname = "cape_2d" @@ -2113,8 +2088,7 @@ def set_cape_alg_metadata(is2d, copyarg="pres_hpa"): outattrs["MemoryOrder"] = "Z" outattrs["description"] = "cape; cin" outattrs["units"] = "J kg-1 ; J kg-1" - - + if isinstance(p, DataArray): if is2d: if not is1d: @@ -2130,9 +2104,8 @@ def set_cape_alg_metadata(is2d, copyarg="pres_hpa"): outdims[1:-3] = p.dims[0:-3] else: outdims[1] = p.dims[0] - - - outcoords = {} + + outcoords = {} # Left-most is always cape_cin or cape_cin_lcl_lfc if is2d: outdims[0] = "mcape_mcin_lcl_lfc" @@ -2140,64 +2113,64 @@ def set_cape_alg_metadata(is2d, copyarg="pres_hpa"): else: outdims[0] = "cape_cin" outcoords["cape_cin"] = ["cape", "cin"] - + outattrs["_FillValue"] = missing outattrs["missing_value"] = missing - + out = DataArray(result, name=outname, dims=outdims, coords=outcoords, attrs=outattrs) - + return out - + return func_wrapper def set_cloudfrac_alg_metadata(copyarg="vert"): - """A decorator that sets the metadata for the wrapped raw cloud fraction + """A decorator that sets the metadata for the wrapped raw cloud fraction diagnostic function. - + Args: - - copyarg (:obj:`str`): The wrapped function argument to use for + + copyarg (:obj:`str`): The wrapped function argument to use for copying dimension names. Default is 'vert'. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - cloud fraction function output with or without metadata. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + cloud fraction function output with or without metadata. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - + @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): do_meta = from_args(wrapped, ("meta",), *args, **kwargs)["meta"] - + if do_meta is None: do_meta = True - + if not xarray_enabled() or not do_meta: return wrapped(*args, **kwargs) - + result = wrapped(*args, **kwargs) - - argvals = from_args(wrapped, (copyarg, "low_thresh", - "mid_thresh", "high_thresh", - "missing"), - *args, **kwargs) + + argvals = from_args(wrapped, (copyarg, "low_thresh", + "mid_thresh", "high_thresh", + "missing"), + *args, **kwargs) cp = argvals[copyarg] low_thresh = argvals["low_thresh"] mid_thresh = argvals["mid_thresh"] high_thresh = argvals["high_thresh"] missing = argvals["missing"] - + # Default dimension names outdims = ["dim_{}".format(i) for i in py3range(result.ndim)] - + outattrs = OrderedDict() - + outname = "cloudfrac" outattrs["description"] = "low, mid, high clouds" outattrs["units"] = "%" @@ -2207,76 +2180,75 @@ def set_cloudfrac_alg_metadata(copyarg="vert"): outattrs["high_thresh"] = high_thresh outattrs["_FillValue"] = missing outattrs["missing_value"] = missing - + if isinstance(cp, DataArray): # Right dims outdims[-2:] = cp.dims[-2:] # Left dims outdims[1:-2] = cp.dims[0:-3] - - - outcoords = {} + + outcoords = {} # Left-most is always low_mid_high outdims[0] = "low_mid_high" outcoords["low_mid_high"] = ["low", "mid", "high"] - + out = DataArray(result, name=outname, dims=outdims, coords=outcoords, attrs=outattrs) - + return out - + return func_wrapper def set_destag_metadata(): - """A decorator that sets the metadata for the wrapped raw destaggering + """A decorator that sets the metadata for the wrapped raw destaggering function. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped - destaggering function output with or without metadata. - If xarray is enabled and the *meta* parameter is True, then the result - will be a :class:`xarray.DataArray` object. Otherwise, the result will + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped + destaggering function output with or without metadata. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - + @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): do_meta = from_args(wrapped, ("meta",), *args, **kwargs)["meta"] - + if do_meta is None: do_meta = True - + if not xarray_enabled() or not do_meta: return wrapped(*args, **kwargs) - + result = wrapped(*args, **kwargs) - + # Default dimension names outdims = ["dim{}".format(i) for i in py3range(result.ndim)] - - destag_args = from_args(wrapped, ("var", "stagger_dim"), + + destag_args = from_args(wrapped, ("var", "stagger_dim"), *args, **kwargs) var = destag_args["var"] - destag_dim = destag_args["stagger_dim"] - + destag_dim = destag_args["stagger_dim"] + if isinstance(var, DataArray): - + if var.name is not None: outname = "destag_{}".format(var.name) else: outname = "destag_var" - + outattrs = OrderedDict() outattrs.update(var.attrs) - + outattrs["destag_dim"] = destag_dim - + outdims = [] outdims += var.dims - + destag_dim_name = outdims[destag_dim] if destag_dim_name.find("_stag") >= 0: new_dim_name = destag_dim_name.replace("_stag", "") @@ -2286,16 +2258,11 @@ def set_destag_metadata(): else: dim_num = result.ndim + destag_dim new_dim_name = "dim_{}".format(dim_num) - - outdims[destag_dim] = new_dim_name - - out = DataArray(result, name=outname, dims=outdims, attrs=outattrs) - - return out - - return func_wrapper - + outdims[destag_dim] = new_dim_name + out = DataArray(result, name=outname, dims=outdims, attrs=outattrs) + return out + return func_wrapper diff --git a/src/wrf/projection.py b/src/wrf/projection.py index b7cd2d7..021b7f1 100644 --- a/src/wrf/projection.py +++ b/src/wrf/projection.py @@ -10,74 +10,75 @@ from .py3compat import viewitems if cartopy_enabled(): from cartopy import crs - + if basemap_enabled(): from mpl_toolkits.basemap import Basemap - + if pyngl_enabled(): from Ngl import Resources if cartopy_enabled(): class MercatorWithLatTS(crs.Mercator): - """A :class:`cartopy.crs.Mercator` subclass that adds support for + """A :class:`cartopy.crs.Mercator` subclass that adds support for a latitude of true scale parameter. - + See Also: - + :class:`cartopy.crs.Mercator` - + """ def __init__(self, central_longitude=0.0, latitude_true_scale=0.0, - min_latitude=-80.0, + min_latitude=-80.0, max_latitude=84.0, globe=None): """Initialize a :class:`wrf.MercatorWithLatTS` object. - + Args: - - central_longitude (:obj:`float`, optional): The central + + central_longitude (:obj:`float`, optional): The central longitude. Default is 0.0. - - latitude_true_scale (:obj:`float`, optional): The latitude + + latitude_true_scale (:obj:`float`, optional): The latitude of true scale. Default is 0.0. - - min_latitude (:obj:`float`, optional): The maximum southerly + + min_latitude (:obj:`float`, optional): The maximum southerly extent of the projection. Default is -80.0. - - max_latitude (:obj:`float`, optional): The maximum northerly + + max_latitude (:obj:`float`, optional): The maximum northerly extent of the projection. Default is 84.0. - + globe (:class:`cartopy.crs.Globe`, optional): A globe object. If omitted, a default globe is created. - + """ 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])) - - # When using a latitude of true scale, the min/max x-limits get set + 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 xlimits = limits[..., 0] - + if math.fabs(xlimits[0] - xlimits[1]) < 1e-6: if xlimits[0] < 0: xlimits[1] = -xlimits[1] else: xlimits[0] = -xlimits[0] - + self._xlimits = tuple(xlimits) self._ylimits = tuple(limits[..., 1]) - + # Compatibility with cartopy >= 0.17 self._x_limits = self._xlimits self._y_limits = self._ylimits @@ -87,75 +88,75 @@ if cartopy_enabled(): def _ismissing(val, islat=True): """Return True if a value is None or out of bounds. - + This function is used to check for invalid latitude/longitude values. - + Args: - + val (numeric): A numeric value. - + islat (:obj:`bool`): Set to False if checking for longitude values. - + Returns: - + :obj:`bool`: True if the value is None, or an out of bounds value. - + """ if islat: if val is None: - return True - + return True + if math.fabs(val) > 90.: return True else: if val is None: - return True - + return True + if math.fabs(val) > 360.: return True - + return False class WrfProj(object): """A base class for storing map projection information from WRF data. - - Subclasses of this type will be stored in the 'projection' attribute + + Subclasses of this type will be stored in the 'projection' attribute entry within a :attr:`xarray.DataArray.attrs` dictionary. This base class - contains the methods required to extract the appropriate projection class - for PyNGL, matplotlib basemap, and cartopy. - + contains the methods required to extract the appropriate projection class + for PyNGL, matplotlib basemap, and cartopy. + Attributes: - + map_proj (:obj:`int`): Model projection integer id. - - truelat1 (:obj:`float`): True latitude 1. - - truelat2 (:obj:`float`): True latitude 2. - + + truelat1 (:obj:`float`): True latitude 1. + + truelat2 (:obj:`float`): True latitude 2. + moad_cen_lat (:obj:`float`): Mother of all domains center latitude. - - stand_lon (:obj:`float`): Standard longitude. - + + stand_lon (:obj:`float`): Standard longitude. + pole_lat (:obj:`float`): The pole latitude. - + pole_lon (:obj:`float`): The pole longitude. - + dx (:obj:`float`): The x grid spacing. - + dy (:obj:`float`): The y grid spacing. - - + + """ def __init__(self, **proj_params): """Initialize a :class:`wrf.WrfProj` object. - + Args: - + **proj_params: Map projection optional keyword arguments, that - have the same names as found in WRF output NetCDF global + have the same names as found in WRF output NetCDF global attributes (case insensitive): - + - 'MAP_PROJ': The map projection type as an integer. - 'TRUELAT1': True latitude 1. - 'TRUELAT2': True latitude 2. @@ -165,356 +166,351 @@ class WrfProj(object): - 'POLE_LON': Pole longitude. """ - + up_proj_params = dict_keys_to_upper(proj_params) - + self.map_proj = up_proj_params.get("MAP_PROJ", None) - - # These indicate the center of the nest/domain, not necessarily the + + # These indicate the center of the nest/domain, not necessarily the # center of the projection self._cen_lat = up_proj_params.get("CEN_LAT", None) self._cen_lon = up_proj_params.get("CEN_LON", None) - + self.truelat1 = up_proj_params.get("TRUELAT1", None) self.truelat2 = (up_proj_params.get("TRUELAT2", None) - if not _ismissing(up_proj_params.get("TRUELAT2", - None)) + if not _ismissing(up_proj_params.get("TRUELAT2", + None)) else None) self.moad_cen_lat = up_proj_params.get("MOAD_CEN_LAT", None) self.stand_lon = up_proj_params.get("STAND_LON", None) self.pole_lat = up_proj_params.get("POLE_LAT", None) self.pole_lon = up_proj_params.get("POLE_LON", None) - + self.dx = up_proj_params.get("DX", None) self.dy = up_proj_params.get("DY", None) - + # Just in case... if self.moad_cen_lat is None: self.moad_cen_lat = self._cen_lat - + 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. - + Args: - + x (numeric): A numeric value. - + y (numeric): A numeric value. - + ctx (:class:`decimal.Context`): A decimal Context object. - + Returns: - - :obj:`bool`: True if the values are equal based on the provided + + :obj:`bool`: True if the values are equal based on the provided context, False otherwise. - + """ if x is not None: if y is None: return False - - # Note: The float conversion is because these may come in as + + # Note: The float conversion is because these may come in as # numpy.float32 or numpy.float64, which Decimal does not know # how to handle. - if (Decimal(float(x)).normalize(ctx) != - Decimal(float(y)).normalize(ctx)): + if (Decimal(float(x)).normalize(ctx) != + Decimal(float(y)).normalize(ctx)): return False else: if y is not None: return False - + return True - - + def __eq__(self, other): """Return True if this projection object is the same as *other*. - - Note: WRF can use either floats or doubles, so only going to - guarantee floating point precision equivalence, in case the different + + Note: WRF can use either floats or doubles, so only going to + guarantee floating point precision equivalence, in case the different types are ever compared (or a projection is hand constructed). For WRF domains, 7-digit equivalence should be good enough. - + """ - + if self.map_proj is not None: if self.map_proj != other.map_proj: return False else: if other.map_proj is not None: return False - + # Only checking for floating point equal. ctx = Context(prec=7, rounding=ROUND_HALF_UP) - + 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 - WrfProj._context_equal(self.stand_lon, other.stand_lon, + WrfProj._context_equal(self.moad_cen_lat, other.moad_cen_lat, + ctx) and + WrfProj._context_equal(self.stand_lon, other.stand_lon, ctx) and WrfProj._context_equal(self.pole_lat, other.pole_lat, ctx) and WrfProj._context_equal(self.pole_lon, other.pole_lon, ctx) and WrfProj._context_equal(self.dx, other.dx, ctx) and WrfProj._context_equal(self.dy, other.dy, ctx)) - - + def _basemap(self, geobounds, **kwargs): return None - + def _cf_params(self): return None - + def _cartopy(self): return None - + 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: + else: extents = np.empty(geobounds.shape, np.object) - + for idxs, geobnd_val in np.ndenumerate(geobounds): extents[idxs] = self._calc_extents(geobnd_val) - + return extents - + def _pyngl(self, geobounds): return None - + def _proj4(self): return None - + def _globe(self): - return (None if not cartopy_enabled() + return (None if not cartopy_enabled() else crs.Globe(ellipse=None, semimajor_axis=Constants.WRF_EARTH_RADIUS, semiminor_axis=Constants.WRF_EARTH_RADIUS, nadgrids="@null")) - + def cartopy_xlim(self, geobounds): """Return the x extents in projected coordinates for cartopy. - + Returns: - + :obj:`list`: A pair of [xmin, xmax]. - + See Also: - + :mod:`cartopy`, :mod:`matplotlib` - + """ 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) - + for idxs, extent in np.ndenumerate(extents): x_extents[idxs] = extent[0] - + return x_extents - + def cartopy_ylim(self, geobounds): """Return the y extents in projected coordinates for cartopy. - + Returns: - + :obj:`list`: A pair of [ymin, ymax]. - + See Also: - + :mod:`cartopy`, :mod:`matplotlib` - + """ 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) - + for idxs, extent in np.ndenumerate(extents): y_extents[idxs] = extent[1] - + return y_extents - + def __repr__(self): args = ("stand_lon={}, moad_cen_lat={}, " "truelat1={}, truelat2={}, " - "pole_lat={}, pole_lon={}".format(self.stand_lon, + "pole_lat={}, pole_lon={}".format(self.stand_lon, self.moad_cen_lat, self.truelat1, self.truelat2, self.pole_lat, self.pole_lon)) return "{}({})".format(self.__class__.__name__, args) - + def basemap(self, geobounds, **kwargs): - """Return a :class:`matplotlib.mpl_toolkits.basemap.Basemap` object + """Return a :class:`matplotlib.mpl_toolkits.basemap.Basemap` object for the map projection. - + Args: - - geobounds (:class:`wrf.GeoBounds`, optional): The geobounds to + + geobounds (:class:`wrf.GeoBounds`, optional): The geobounds to get the extents. If set to None and using the *var* parameter, - the geobounds will be taken from the variable. If using a + the geobounds will be taken from the variable. If using a file, then the geobounds will be taken from the native grid. - - **kwargs: Keyword arguments for creating a + + **kwargs: Keyword arguments for creating a :class:`matplotlib.mpl_toolkits.basemap.Basemap`. By default, - the domain bounds will be set to the native projection, the - resolution will be set to 'l', and the other projection + the domain bounds will be set to the native projection, the + resolution will be set to 'l', and the other projection parameters will be set by the information in the file. - + Returns: - + :class:`matplotlib.mpl_toolkits.basemap.Basemap`: A Basemap object for the projection. - + See Also: - + :class:`matplotlib.mpl_toolkits.basemap.Basemap` - + """ if not basemap_enabled(): raise RuntimeError("'mpl_toolkits.basemap' is not " "installed or is disabled") - + return self._basemap(geobounds, **kwargs) - + def cartopy(self): - """Return a :class:`cartopy.crs.Projection` subclass for the + """Return a :class:`cartopy.crs.Projection` subclass for the map projection. - + Returns: - - :class:`cartopy.crs.Projection`: A Projection subclass for the + + :class:`cartopy.crs.Projection`: A Projection subclass for the map projection. - + See Also: - + :class:`cartopy.crs.Projection` - + """ if not cartopy_enabled(): raise RuntimeError("'cartopy' is not " "installed or is disabled") return self._cartopy() - + def pyngl(self, geobounds, **kwargs): """Return a :class:`Ngl.Resources` object for the map projection. - + Args: - - geobounds (:class:`wrf.GeoBounds`, optional): The geobounds to + + geobounds (:class:`wrf.GeoBounds`, optional): The geobounds to get the extents. If set to None and using the *var* parameter, - the geobounds will be taken from the variable. If using a + the geobounds will be taken from the variable. If using a file, then the geobounds will be taken from the native grid. - - **kwargs: Additional PyNGL resources to set while creating the + + **kwargs: Additional PyNGL resources to set while creating the :class:`Ngl.Resources` object. - + Returns: - - :class:`Ngl.Resources`: A dict-like object that contains the + + :class:`Ngl.Resources`: A dict-like object that contains the PyNGL resources for the map projection. - + See Also: - - `PyNGL `_ - + + `PyNGL `_ + """ if not pyngl_enabled(): raise RuntimeError("'pyngl' is not " "installed or is disabled") return self._pyngl(geobounds, **kwargs) - + def proj4(self): """Return the PROJ.4 string for the map projection. - + Returns: - + :obj:`str`: A string suitable for use with the PROJ.4 library. - + See Also: - - PROJ.4 `_ - + + PROJ.4 `_ + """ return self._proj4() - + def cf(self): - """Return a dictionary with the NetCDF CF parameters for the + """Return a dictionary with the NetCDF CF parameters for the projection. - + Returns: - - :obj:`dict`: A dictionary with the NetCDF CF parameter names and + + :obj:`dict`: A dictionary with the NetCDF CF parameter names and projection parameter values. - + """ return self._cf_params() - + # Used for 'missing' projection values during the 'join' method class NullProjection(WrfProj): """A :class:`wrf.WrfProj` subclass for empty projections. - - The :class:`NullProjection` is primarily used for creating missing + + The :class:`NullProjection` is primarily used for creating missing projections when using the 'join' method. - + """ def __init__(self): """Initialize a :class:`wrf.NullProjection` object.""" - pass - + pass + def __repr__(self): return "{}()".format(self.__class__.__name__) - - + + class LambertConformal(WrfProj): """A :class:`wrf.WrfProj` subclass for Lambert Conformal Conic projections. - + See Also: - - :class:`wrf.WrfProj`, :class:`wrf.LatLon`, - :class:`wrf.PolarStereographic`, + + :class:`wrf.WrfProj`, :class:`wrf.LatLon`, + :class:`wrf.PolarStereographic`, :class:`Mercator`, :class:`RotatedLatLon` - + """ def __init__(self, **proj_params): """Initialize a :class:`wrf.LambertConformal` object. - + Args: - + **proj_params: Map projection optional keyword arguments, that - have the same names as found in WRF output NetCDF global + have the same names as found in WRF output NetCDF global attributes: - + - 'TRUELAT1': True latitude 1. - 'TRUELAT2': True latitude 2. - 'MOAD_CEN_LAT': Mother of all domains center latitude. @@ -524,122 +520,118 @@ class LambertConformal(WrfProj): """ super(LambertConformal, self).__init__(**proj_params) - + self._std_parallels = [self.truelat1] 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 _cf_params["semi_major_axis"] = Constants.WRF_EARTH_RADIUS - + 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" _pyngl.mpDataBaseVersion = "MediumRes" _pyngl.mpLambertMeridianF = self.stand_lon _pyngl.mpLambertParallel1F = self.truelat1 _pyngl.mpLambertParallel2F = truelat2 - + _pyngl.mpLimitMode = "Corners" _pyngl.mpLeftCornerLonF = geobounds.bottom_left.lon _pyngl.mpLeftCornerLatF = geobounds.bottom_left.lat _pyngl.mpRightCornerLonF = geobounds.top_right.lon _pyngl.mpRightCornerLatF = geobounds.top_right.lat - + for key, val in viewitems(kwargs): setattr(_pyngl, key, val) - + 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) - + return _basemap - + def _cartopy(self): if not cartopy_enabled(): return None - + # Set cutoff to -30 for NH, +30.0 for SH. 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 - + def _proj4(self): - truelat2 = (self.truelat1 - if _ismissing(self.truelat2) + truelat2 = (self.truelat1 + if _ismissing(self.truelat2) else self.truelat2) - + _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 - - + + class Mercator(WrfProj): """A :class:`wrf.WrfProj` subclass for Mercator projections. - + See Also: - - :class:`wrf.WrfProj`, :class:`wrf.LatLon`, - :class:`wrf.PolarStereographic`, + + :class:`wrf.WrfProj`, :class:`wrf.LatLon`, + :class:`wrf.PolarStereographic`, :class:`RotatedLatLon`, :class:`LambertConformal` - + """ def __init__(self, **proj_params): """Initialize a :class:`wrf.Mercator` object. - + Args: - + **proj_params: Map projection optional keyword arguments, that - have the same names as found in WRF output NetCDF global + have the same names as found in WRF output NetCDF global attributes: - + - 'TRUELAT1': True latitude 1. - 'TRUELAT2': True latitude 2. - 'MOAD_CEN_LAT': Mother of all domains center latitude. @@ -649,117 +641,108 @@ class Mercator(WrfProj): """ super(Mercator, self).__init__(**proj_params) - - 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) + + 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 _cf_params["standard_parallel"] = self.truelat1 - + return _cf_params - - + def _pyngl(self, geobounds, **kwargs): if not pyngl_enabled(): return None - + _pyngl = Resources() _pyngl.mpProjection = "Mercator" _pyngl.mpDataBaseVersion = "MediumRes" _pyngl.mpCenterLatF = 0.0 _pyngl.mpCenterLonF = self._stand_lon - + _pyngl.mpLimitMode = "Corners" _pyngl.mpLeftCornerLonF = geobounds.bottom_left.lon _pyngl.mpLeftCornerLatF = geobounds.bottom_left.lat _pyngl.mpRightCornerLonF = geobounds.top_right.lon _pyngl.mpRightCornerLatF = geobounds.top_right.lat - + for key, val in viewitems(kwargs): setattr(_pyngl, key, val) - + 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={} " "+lon_0={} +lat_ts={} +nadgrids=@null".format( Constants.WRF_EARTH_RADIUS, Constants.WRF_EARTH_RADIUS, self._stand_lon, self._lat_ts)) - + return _proj4 - + + class PolarStereographic(WrfProj): """A :class:`wrf.WrfProj` subclass for Polar Stereographic projections. - + See Also: - - :class:`wrf.WrfProj`, :class:`wrf.LatLon`, - :class:`wrf.RotatedLatLon`, + + :class:`wrf.WrfProj`, :class:`wrf.LatLon`, + :class:`wrf.RotatedLatLon`, :class:`Mercator`, :class:`LambertConformal` - - """ + """ def __init__(self, **proj_params): """Initialize a :class:`wrf.PolarStereographic` object. - + Args: - + **proj_params: Map projection optional keyword arguments, that - have the same names as found in WRF output NetCDF global + have the same names as found in WRF output NetCDF global attributes: - + - 'TRUELAT1': True latitude 1. - 'TRUELAT2': True latitude 2. - 'MOAD_CEN_LAT': Mother of all domains center latitude. @@ -770,11 +753,8 @@ 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 = {} _cf_params["grid_mapping_name"] = "polar_stereographic" @@ -782,68 +762,64 @@ class PolarStereographic(WrfProj): self.stand_lon) _cf_params["standard_parallel"] = self.truelat1 _cf_params["latitude_of_projection_origin"] = self._hemi - + return _cf_params - - + def _pyngl(self, geobounds, **kwargs): if not pyngl_enabled(): return None - + _pyngl = Resources() _pyngl.mpProjection = "Stereographic" _pyngl.mpDataBaseVersion = "MediumRes" - + _pyngl.mpCenterLonF = self.stand_lon if self._hemi > 0: _pyngl.mpCenterLatF = 90.0 else: _pyngl.mpCenterLatF = -90.0 - + _pyngl.mpLimitMode = "Corners" _pyngl.mpLeftCornerLonF = geobounds.bottom_left.lon _pyngl.mpLeftCornerLatF = geobounds.bottom_left.lat _pyngl.mpRightCornerLonF = geobounds.top_right.lon _pyngl.mpRightCornerLatF = geobounds.top_right.lat - + for key, val in viewitems(kwargs): setattr(_pyngl, key, val) - + 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()) + + _cartopy = crs.Stereographic(central_latitude=self._hemi, + 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( @@ -852,30 +828,29 @@ class PolarStereographic(WrfProj): self._hemi, self.stand_lon, self._lat_ts)) - + return _proj4 - - + class LatLon(WrfProj): """A :class:`wrf.WrfProj` subclass for Lat Lon projections. - + See Also: - - :class:`wrf.WrfProj`, :class:`wrf.RotatedLatLon`, - :class:`wrf.PolarStereographic`, + + :class:`wrf.WrfProj`, :class:`wrf.RotatedLatLon`, + :class:`wrf.PolarStereographic`, :class:`Mercator`, :class:`LambertConformal` - + """ def __init__(self, **proj_params): """Initialize a :class:`wrf.LatLon` object. - + Args: - + **proj_params: Map projection optional keyword arguments, that - have the same names as found in WRF output NetCDF global + have the same names as found in WRF output NetCDF global attributes: - + - 'TRUELAT1': True latitude 1. - 'TRUELAT2': True latitude 2. - 'MOAD_CEN_LAT': Mother of all domains center latitude. @@ -885,128 +860,124 @@ 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 - + _pyngl = Resources() _pyngl.mpProjection = "CylindricalEquidistant" _pyngl.mpDataBaseVersion = "MediumRes" _pyngl.mpCenterLonF = self.stand_lon _pyngl.mpCenterLatF = self.moad_cen_lat - + _pyngl.mpLimitMode = "Corners" _pyngl.mpLeftCornerLonF = geobounds.bottom_left.lon _pyngl.mpLeftCornerLatF = geobounds.bottom_left.lat _pyngl.mpRightCornerLonF = geobounds.top_right.lon _pyngl.mpRightCornerLatF = geobounds.top_right.lat - + for key, val in viewitems(kwargs): setattr(_pyngl, key, val) - + 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 - + _cartopy = crs.PlateCarree(central_longitude=self.stand_lon, globe=self._globe()) - + return _cartopy - - + def _cart_extents(self, geobounds): - return ([geobounds.bottom_left.lon, geobounds.top_right.lon], - [geobounds.bottom_left.lat, geobounds.top_right.lat]) - - + 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 -# determine north or south hemisphere. In other words, it determines if +# 1) In WRF, if following the WPS instructions, POLE_LON is mainly used to +# determine north or south hemisphere. In other words, it determines if # the globe is tipped toward or away from you. -# 2) In WRF, POLE_LAT is always positive, but should be negative in the +# 2) In WRF, POLE_LAT is always positive, but should be negative in the # proj4 based systems when using the southern hemisphere projections. -# 3) In cartopy, pole_longitude is used to describe the dateline, which -# is 180 degrees away from the normal central (standard) longitude -# (e.g. center of the projection), according to the cartopy developer. +# 3) In cartopy, pole_longitude is used to describe the dateline, which +# is 180 degrees away from the normal central (standard) longitude +# (e.g. center of the projection), according to the cartopy developer. # 4) In basemap, lon_0 should be set to the central (standard) longitude. # 5) In either cartopy, basemap or pyngl, I'm not sure that projections with -# a pole_lon not equal to 0 or 180 can be plotted. Hopefully people +# a pole_lon not equal to 0 or 180 can be plotted. Hopefully people # follow the WPS instructions, otherwise I need to see a sample file. -# 6) For items in 3 - 4, the "longitude" (lon_0 or pole_longitude) is -# determined by WRF's +# 6) For items in 3 - 4, the "longitude" (lon_0 or pole_longitude) is +# determined by WRF's # STAND_LON values, with the following calculations based on hemisphere: # BASEMAP: NH: -STAND_LON; SH: 180.0 - STAND_LON # CARTOPY: NH: -STAND_LON - 180.; SH: -STAND_LON # 9) For PYNGL/NCL, you only need to set the center lat and center lon, -# Center lat is the offset of the pole from +/- 90 degrees. Center -# lon is -STAND_LON in NH and 180.0 - STAND_LON in SH. -# 10) It also appears that NetCDF CF has no clear documentation on what +# Center lat is the offset of the pole from +/- 90 degrees. Center +# lon is -STAND_LON in NH and 180.0 - STAND_LON in SH. +# 10) It also appears that NetCDF CF has no clear documentation on what # each parameter means. Going to assume it is the same as basemap, since -# basemap appears to mirror the WMO way of doing things (tilt earth, then +# basemap appears to mirror the WMO way of doing things (tilt earth, then # spin globe). -# 11) Basemap and cartopy produce projections that differ in their extent +# 11) Basemap and cartopy produce projections that differ in their extent # calculations by either using negative values or 0-360 (basemap). For # this reason, the proj4 string for this class will use cartopy's values # to keep things in the -180 to 180, -90 to 90 range. -# 12) This projection makes me sad. +# 12) This projection makes me sad. class RotatedLatLon(WrfProj): """A :class:`wrf.WrfProj` subclass for Rotated Lat Lon projections. - + See Also: - - :class:`wrf.WrfProj`, :class:`wrf.LatLon`, - :class:`wrf.PolarStereographic`, + + :class:`wrf.WrfProj`, :class:`wrf.LatLon`, + :class:`wrf.PolarStereographic`, :class:`Mercator`, :class:`LambertConformal` - + """ def __init__(self, **proj_params): """Initialize a :class:`wrf.RotatedLatLon` object. - + Args: - + **proj_params: Map projection optional keyword arguments, that - have the same names as found in WRF output NetCDF global + have the same names as found in WRF output NetCDF global attributes: - + - 'TRUELAT1': True latitude 1. - 'TRUELAT2': True latitude 2. - 'MOAD_CEN_LAT': Mother of all domains center latitude. @@ -1016,9 +987,9 @@ class RotatedLatLon(WrfProj): """ super(RotatedLatLon, self).__init__(**proj_params) - + # Need to determine hemisphere, typically pole_lon is 0 for southern - # hemisphere, 180 for northern hemisphere. If not, going to have + # hemisphere, 180 for northern hemisphere. If not, going to have # to guess based on other parameters, but hopefully people follow # the WPS instructions and this never happens. self._north = True @@ -1032,100 +1003,95 @@ class RotatedLatLon(WrfProj): else: if self.moad_cen_lat is not None and self.moad_cen_lat < 0.0: # Only probably true - self._north = False - + self._north = False + 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) - self._pyngl_cen_lon = (-self.stand_lon if self._north - else 180.0 - self.stand_lon) - self._bm_lon_0 = (-self.stand_lon if self._north + self._pyngl_cen_lat = (90. - self.pole_lat if self._north + else self.pole_lat - 90.0) + self._pyngl_cen_lon = (-self.stand_lon if self._north + 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 ) - # 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 + self._bm_cart_pole_lat = (self.pole_lat if self._north + 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) + self._cart_pole_lon = (-self.stand_lon - 180.0 if self._north + 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) - self._bm_lon_0 = (-self.stand_lon if self._north + self._bm_cart_pole_lat = (90.0 - self.moad_cen_lat if self._north + 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) - - - def _cf_params(self): + self._cart_pole_lon = (-self.stand_lon - 180.0 if self._north + else -self.stand_lon) + + def _cf_params(self): _cf_params = {} # Assuming this follows the same guidelines as cartopy _cf_params["grid_mapping_name"] = "rotated_latitude_longitude" _cf_params["grid_north_pole_latitude"] = self._bm_cart_pole_lat _cf_params["grid_north_pole_longitude"] = self.pole_lon _cf_params["north_pole_grid_longitude"] = self._bm_lon_0 - + return _cf_params - - + def _pyngl(self, geobounds, **kwargs): if not pyngl_enabled(): return None - + _pyngl = Resources() _pyngl.mpProjection = "CylindricalEquidistant" _pyngl.mpDataBaseVersion = "MediumRes" _pyngl.mpCenterLatF = self._pyngl_cen_lat _pyngl.mpCenterLonF = self._pyngl_cen_lon - + _pyngl.mpLimitMode = "Corners" _pyngl.mpLeftCornerLonF = geobounds.bottom_left.lon _pyngl.mpLeftCornerLatF = geobounds.bottom_left.lat _pyngl.mpRightCornerLonF = geobounds.top_right.lon _pyngl.mpRightCornerLatF = geobounds.top_right.lat - + for key, val in viewitems(kwargs): setattr(_pyngl, key, val) - + 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): _proj4 = ("+proj=ob_tran +o_proj=latlon " "+a={} +b={} +to_meter={} +o_lon_p={} +o_lat_p={} " @@ -1135,21 +1101,22 @@ class RotatedLatLon(WrfProj): 180.0 - self.pole_lon, self._bm_cart_pole_lat, 180.0 + self._cart_pole_lon)) - + return _proj4 - + + def getproj(**proj_params): """Return a :class:`wrf.WrfProj` subclass. - - This functions serves as a factory function for returning a + + This functions serves as a factory function for returning a :class:`wrf.WrfProj` subclass from the specified map projection parameters. - + Args: - + **proj_params: Map projection optional keyword arguments, that - have the same names as found in WRF output NetCDF global + have the same names as found in WRF output NetCDF global attributes: - + - 'MAP_PROJ': The map projection type as an integer. - 'TRUELAT1': True latitude 1. - 'TRUELAT2': True latitude 2. @@ -1157,16 +1124,15 @@ def getproj(**proj_params): - 'STAND_LON': Standard longitude. - 'POLE_LAT': Pole latitude. - 'POLE_LON': Pole longitude. - + Returns: - - :class:`wrf.WrfProj`: A :class:`wrf.WrfProj` subclass for the + + :class:`wrf.WrfProj`: A :class:`wrf.WrfProj` subclass for the specified map projection parameters. - + """ - up_proj_params = dict_keys_to_upper(proj_params) - + proj_type = up_proj_params.get("MAP_PROJ", 0) if proj_type == ProjectionTypes.LAMBERT_CONFORMAL: return LambertConformal(**proj_params) @@ -1174,15 +1140,13 @@ def getproj(**proj_params): return PolarStereographic(**proj_params) elif proj_type == ProjectionTypes.MERCATOR: return Mercator(**proj_params) - elif (proj_type == ProjectionTypes.ZERO or + 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.): + if (up_proj_params.get("POLE_LAT", None) == 90. + 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) - - \ No newline at end of file diff --git a/src/wrf/projutils.py b/src/wrf/projutils.py index 5cc2d14..70f2cf1 100644 --- a/src/wrf/projutils.py +++ b/src/wrf/projutils.py @@ -2,16 +2,17 @@ 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. - + Args: - + d (:obj:`dict`): A dictionary. - + Returns: - + :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)} diff --git a/src/wrf/py3compat.py b/src/wrf/py3compat.py index 0c08366..4777388 100644 --- a/src/wrf/py3compat.py +++ b/src/wrf/py3compat.py @@ -3,18 +3,19 @@ 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. - + Args: - + d (:obj:`dict`): A dictionary. - + Returns: - + view method: Either the items or viewitems method. - + """ func = getattr(d, "viewitems", None) if func is None: @@ -24,15 +25,15 @@ def viewitems(d): def viewkeys(d): """Return either the keys or viewkeys method for a dictionary. - + Args: - + d (:obj:`dict`): A dictionary. - + Returns: - + view method: Either the keys or viewkeys method. - + """ func = getattr(d, "viewkeys", None) if func is None: @@ -42,32 +43,33 @@ def viewkeys(d): def viewvalues(d): """Return either the values or viewvalues method for a dictionary. - + Args: - + d (:obj:`dict`): A dictionary. - + Returns: - + view method: Either the values or viewvalues method. - + """ func = getattr(d, "viewvalues", None) if func is None: func = d.values return func() + def isstr(s): """Return True if the object is a string type. - + Args: - + s (string): A string (str, unicode, bytes). - + Returns: - + :obj:`bool`: True if the object is a type of string. Otherwise, False. - + """ try: return isinstance(s, basestring) @@ -75,25 +77,25 @@ def isstr(s): return isinstance(s, str) -# Python 2 rounding behavior +# Python 2 rounding behavior def _round2(x, d=None): - """Return the result of Python 2.x rounding, which is to round the number + """Return the result of Python 2.x rounding, which is to round the number to the nearest integer. - - Python 3.x uses banker's rounding, which is not applicable for nearest + + Python 3.x uses banker's rounding, which is not applicable for nearest neighbor approaches with grid boxes. - + Args: - + x (:obj:`float`): A number, usually a float. - - d (:obj:`int`, optional): The number of digits. Default is None, + + d (:obj:`int`, optional): The number of digits. Default is None, which indicates the nearest integer. - + Returns: - + :obj:`float`: The rounded number. - + """ d = 0 if d is None else d p = 10 ** d @@ -101,69 +103,67 @@ def _round2(x, d=None): def py2round(x, d=None): - """Return the result of Python 2.x rounding, which is to round the number + """Return the result of Python 2.x rounding, which is to round the number to the nearest integer. - - Python 3.x uses banker's rounding, which is not applicable for nearest + + Python 3.x uses banker's rounding, which is not applicable for nearest neighbor approaches with grid boxes. - + Args: - + x (:obj:`float`): A number, usually a float. - - d (:obj:`int`, optional): The number of digits. Default is None, + + d (:obj:`int`, optional): The number of digits. Default is None, which indicates the nearest integer. - + Returns: - + :obj:`float`: The rounded number. - + """ if version_info >= (3,): return _round2(x, d) - + return round(x, d) def py3range(*args): """Return the equivalent of the range function in Python 3.x. - + For Python 2.x, this is the same as the xrange function. - + Args: - + *args: The function arguments for range or xrange. - + Returns: - + iterable: An iterable sequence. - + """ if version_info >= (3,): return range(*args) - + return xrange(*args) def ucode(*args, **kwargs): """Return a Python 3.x unicode string. - + For Python 2.x, this is accomplished by using the unicode function. - + Args: - + *args: The function positional arguments for str or unicode. - + **kwargs: The function keyword arguments for str or unicode. - + Returns: - + string: A unicode string. - + """ if version_info >= (3, ): return str(*args, **kwargs) - - return unicode(*args, **kwargs) - + return unicode(*args, **kwargs) diff --git a/src/wrf/routines.py b/src/wrf/routines.py index aef3697..93727a5 100644 --- a/src/wrf/routines.py +++ b/src/wrf/routines.py @@ -2,8 +2,8 @@ from __future__ import (absolute_import, division, print_function) from .util import (get_iterable, is_standard_wrf_var, extract_vars, viewkeys, get_id) -from .g_cape import (get_2dcape, get_3dcape, get_cape2d_only, - get_cin2d_only, get_lcl, get_lfc, get_3dcape_only, +from .g_cape import (get_2dcape, get_3dcape, get_cape2d_only, + get_cin2d_only, get_lcl, get_lfc, get_3dcape_only, get_3dcin_only) from .g_ctt import get_ctt from .g_dbz import get_dbz, get_max_dbz @@ -16,334 +16,337 @@ 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, +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) +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) from .g_times import get_times, get_xtimes from .g_cloudfrac import (get_cloudfrac, get_low_cloudfrac, get_mid_cloudfrac, get_high_cloudfrac) -# func is the function to call. kargs are required arguments that should +# 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 - + def __str__(self): return self.msg - + + def _undo_alias(alias): actual = _ALIASES.get(alias, None) if actual is None: return 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)) - - -def getvar(wrfin, varname, timeidx=0, - method="cat", squeeze=True, cache=None, meta=True, + + +def getvar(wrfin, varname, timeidx=0, + method="cat", squeeze=True, cache=None, meta=True, **kwargs): - + """Returns basic diagnostics from the WRF ARW model output. - + A table of all available diagnostics is below. - + .. include:: ../../_templates/product_table.txt Args: wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - + varname (:obj:`str`) : The variable name. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - **kwargs: Optional keyword arguments for certain diagnostics. + + **kwargs: Optional keyword arguments for certain diagnostics. See table above. - - + + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - - + + Raises: - :class:`ValueError`: Raised when an invalid diagnostic type or + :class:`ValueError`: Raised when an invalid diagnostic type or keyword argument is passed to the routine. :class:`FortranError`: Raised when a problem occurs during a Fortran calculation. - + See Also: - + :class:`numpy.ndarray`, :class:`xarray.DataArray` - - + + Examples: Using netCDF4 - + .. code-block:: python - + from netCDF4 import Dataset from wrf import getvar - + wrfnc = Dataset("wrfout_d02_2010-06-13_21:00:00") slp = getvar(wrfnc, "slp") - + Using PyNIO - + .. code-block:: python - + from Nio import open_file from wrf import getvar - + wrfnc = open_file("wrfout_d02_2010-06-13_21:00:00"+".nc", "r") slp = getvar(wrfnc, "slp") - + Using Iterables: - + .. code-block:: python - + import os from netCDF4 import Dataset from wrf import getvar - + filedir = "/path/to/wrf/files" - wrfin = [Dataset(f) for f in os.listdir(filedir) + wrfin = [Dataset(f) for f in os.listdir(filedir) if f.startswith("wrfout_d02_")] - + uvmet = getvar(wrfin, "uvmet", timeidx=3, units="kt") - - + + """ - + _key = get_id(wrfin) - + wrfin = get_iterable(wrfin) - + if is_standard_wrf_var(wrfin, varname) and varname != "Times": _check_kargs("default", kwargs) - return extract_vars(wrfin, timeidx, varname, + return extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta, _key)[varname] elif varname == "Times": varname = "times" # Diverting to the get_times routine - + 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, + + return _FUNC_MAP[actual_var](wrfin, timeidx, method, squeeze, cache, meta, _key, **kwargs) - diff --git a/src/wrf/specialdec.py b/src/wrf/specialdec.py index 3845da2..39ee0e1 100644 --- a/src/wrf/specialdec.py +++ b/src/wrf/specialdec.py @@ -2,7 +2,7 @@ from __future__ import (absolute_import, division, print_function) import numpy as np -import wrapt +import wrapt from .util import iter_left_indexes, to_np from .py3compat import py3range @@ -14,28 +14,28 @@ if xarray_enabled(): def uvmet_left_iter(alg_dtype=np.float64): - """A decorator to handle iterating over the leftmost dimensions for the + """A decorator to handle iterating over the leftmost dimensions for the uvmet diagnostic. - + For example, if a wrapped function works with three-dimensional arrays, but - the variables include a 4th leftmost dimension for 'Time', this decorator + the variables include a 4th leftmost dimension for 'Time', this decorator will iterate over all times, call the 3D Fortran routine, and aggregate the results in to a 4D output array. - - It is also important to note that the final output array is allocated - first, and then views are passed to the wrapped function so that values + + It is also important to note that the final output array is allocated + first, and then views are passed to the wrapped function so that values do not need to get copied in to the final output array. - + Args: - - alg_dtype (:class:`np.dtype` or :obj:`str`): The numpy data type used + + alg_dtype (:class:`np.dtype` or :obj:`str`): The numpy data type used in the wrapped function. - + Returns: - - :class:`numpy.ndarray`: The aggregated uvmet output array that includes + + :class:`numpy.ndarray`: The aggregated uvmet output array that includes all extra leftmost dimensions. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): @@ -43,64 +43,62 @@ 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 - + lat_lon_fixed = False if lat.ndim == 2: lat_lon_fixed = True - + if lon.ndim == 2 and not lat_lon_fixed: raise ValueError("'lat' and 'lon' shape mismatch") - + num_left_dims_u = u.ndim - 2 num_left_dims_lat = lat.ndim - 2 - + if (num_left_dims_lat > num_left_dims_u): 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) - + v_arr = to_np(v) - - umissing = default_fill(np.float64) + + umissing = default_fill(np.float64) if isinstance(u_arr, np.ma.MaskedArray): has_missing = True umissing = u_arr.fill_value - - vmissing = default_fill(np.float64) + + vmissing = default_fill(np.float64) if isinstance(v_arr, np.ma.MaskedArray): has_missing = True vmissing = v_arr.fill_value - + uvmetmissing = umissing - + is_stag = 0 if (u.shape[-1] != lat.shape[-1] or u.shape[-2] != lat.shape[-2]): is_stag = 1 # Sanity check if (v.shape[-1] == lat.shape[-1] or v.shape[-2] == lat.shape[-2]): raise ValueError("u is staggered but v is not") - + if (v.shape[-1] != lat.shape[-1] or v.shape[-2] != lat.shape[-2]): is_stag = 1 # Sanity check 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,44 +107,43 @@ 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,) - + outdims += lat.shape[-2:] - + outview_array = np.empty(outdims, alg_dtype) - + # Final Output moves the u_v dimension to left side output_dims = (2,) output_dims += extra_dims output_dims += lat.shape[-2:] output = np.empty(output_dims, orig_dtype) - + for left_idxs in iter_left_indexes(extra_dims): left_and_slice_idxs = left_idxs + (slice(None),) - + if mode == 0: lat_left_and_slice = (slice(None),) elif mode == 1: 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)) - - + 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] new_lon = lon[lat_left_and_slice] outview = outview_array[left_and_slice_idxs] - + # Skip the possible empty/missing arrays for the join method skip_missing = False for arg in (new_u, new_v, new_lat, new_lon): @@ -154,70 +151,69 @@ def uvmet_left_iter(alg_dtype=np.float64): if arg.mask.all(): output[u_output_idxs] = uvmetmissing output[v_output_idxs] = uvmetmissing - + skip_missing = True has_missing = True - + if skip_missing: continue - + # Call the numerical routine result = wrapped(new_u, new_v, new_lat, new_lon, cen_long, cone, - isstag=is_stag, has_missing=has_missing, - umissing=umissing, vmissing=vmissing, + isstag=is_stag, has_missing=has_missing, + umissing=umissing, vmissing=vmissing, uvmetmissing=uvmetmissing, outview=outview) - - # Make sure the result is the same data as what got passed in + + # 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]): + if (result.__array_interface__["data"][0] != + outview.__array_interface__["data"][0]): raise RuntimeError("output array was copied") - + output[u_output_idxs] = ( outview_array[u_view_idxs].astype(orig_dtype)) output[v_output_idxs] = ( outview_array[v_view_idxs].astype(orig_dtype)) - + if has_missing: output = np.ma.masked_values(output, uvmetmissing) - + return output - + return func_wrapper - def cape_left_iter(alg_dtype=np.float64): - """A decorator to handle iterating over the leftmost dimensions for the + """A decorator to handle iterating over the leftmost dimensions for the cape diagnostic. - + For example, if a wrapped function works with three-dimensional arrays, but - the variables include a 4th leftmost dimension for 'Time', this decorator + the variables include a 4th leftmost dimension for 'Time', this decorator will iterate over all times, call the 3D Fortran routine, and aggregate the results in to a 4D output array. - - It is also important to note that the final output array is allocated - first, and then views are passed to the wrapped function so that values + + It is also important to note that the final output array is allocated + first, and then views are passed to the wrapped function so that values do not need to get copied in to the final output array. - + Args: - - alg_dtype (:class:`np.dtype` or :obj:`str`): The numpy data type used + + alg_dtype (:class:`np.dtype` or :obj:`str`): The numpy data type used in the wrapped function. - + Returns: - - :class:`numpy.ndarray`: The aggregated cape output array that includes + + :class:`numpy.ndarray`: The aggregated cape output array that includes all extra leftmost dimensions. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): # The cape calculations use an ascending vertical pressure coordinate - + new_args = list(args) new_kwargs = dict(kwargs) - + p_hpa = args[0] tk = args[1] qv = args[2] @@ -227,19 +223,19 @@ def cape_left_iter(alg_dtype=np.float64): missing = args[6] i3dflag = args[7] ter_follow = args[8] - + is2d = i3dflag == 0 # Note: This should still work with DataArrays is1d = np.isscalar(sfp) or np.size(sfp) == 1 - + # Make sure sfp and terrain are regular floats for 1D case # This should also work with DataArrays if is1d: ter = float(ter) - sfp = float(sfp) - + sfp = float(sfp) + orig_dtype = p_hpa.dtype - + if not is1d: # Need to order in ascending pressure order flip = False @@ -247,48 +243,48 @@ def cape_left_iter(alg_dtype=np.float64): top_idxs = list(bot_idxs) top_idxs[-3] = -1 top_idxs = tuple(top_idxs) - + 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 new_args[3] = ht - + num_left_dims = p_hpa.ndim - 3 else: # Need to order in ascending pressure order flip = False - + if p_hpa[0] > p_hpa[-1]: flip = True p_hpa = np.ascontiguousarray(p_hpa[::-1]) tk = np.ascontiguousarray(tk[::-1]) qv = np.ascontiguousarray(qv[::-1]) ht = np.ascontiguousarray(ht[::-1]) - + # Need to make 3D views for the fortran code. # Going to make these fortran ordered, since the f_contiguous and - # c_contiguous flags are broken in numpy 1.11 (always false). This - # should work across all numpy versions. + # c_contiguous flags are broken in numpy 1.11 (always false). This + # should work across all numpy versions. new_args[0] = p_hpa.reshape((1, 1, p_hpa.shape[0]), order='F') 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 - + # No special left side iteration, build the output from the cape,cin # result if (num_left_dims == 0): cape, cin = wrapped(*new_args, **new_kwargs) - + output_dims = (2,) if not is1d: output_dims += p_hpa.shape[-3:] @@ -296,26 +292,26 @@ def cape_left_iter(alg_dtype=np.float64): output_dims += (p_hpa.shape[0], 1, 1) 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 - - outdims += (2,) # cape_cin - + extra_dims = tuple(outdims) # Copy the left-most dims for iteration + + outdims += (2,) # cape_cin + outdims += p_hpa.shape[-3:] - + outview_array = np.empty(outdims, alg_dtype) - + # Create the output array where the leftmost dim is the product type output_dims = (2,) output_dims += extra_dims @@ -326,14 +322,14 @@ def cape_left_iter(alg_dtype=np.float64): left_and_slice_idxs = left_idxs + (slice(None),) cape_idxs = left_idxs + (0, slice(None)) cin_idxs = left_idxs + (1, slice(None)) - + 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] new_args[1] = tk[left_and_slice_idxs] new_args[2] = qv[left_and_slice_idxs] @@ -342,9 +338,9 @@ def cape_left_iter(alg_dtype=np.float64): new_args[5] = sfp[left_and_slice_idxs] capeview = outview_array[cape_idxs] cinview = outview_array[cin_idxs] - + # Skip the possible empty/missing arrays for the join method - # Note: Masking handled by cape.py or computation.py, so only + # Note: Masking handled by cape.py or computation.py, so only # supply the fill values here. skip_missing = False for arg in (new_args[0:6]): @@ -356,25 +352,24 @@ def cape_left_iter(alg_dtype=np.float64): else: output[cape_output_idxs] = missing output[cin_output_idxs] = missing - + skip_missing = True - + if skip_missing: continue - + # Call the numerical routine new_kwargs["capeview"] = capeview new_kwargs["cinview"] = cinview - + cape, cin = wrapped(*new_args, **new_kwargs) - - # Make sure the result is the same data as what got passed in + + # 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]): + if (cape.__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,82 +377,82 @@ 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 - + return func_wrapper def cloudfrac_left_iter(alg_dtype=np.float64): - """A decorator to handle iterating over the leftmost dimensions for the + """A decorator to handle iterating over the leftmost dimensions for the cloud fraction diagnostic. - + For example, if a wrapped function works with three-dimensional arrays, but - the variables include a 4th leftmost dimension for 'Time', this decorator + the variables include a 4th leftmost dimension for 'Time', this decorator will iterate over all times, call the 3D Fortran routine, and aggregate the results in to a 4D output array. - - It is also important to note that the final output array is allocated - first, and then views are passed to the wrapped function so that values + + It is also important to note that the final output array is allocated + first, and then views are passed to the wrapped function so that values do not need to get copied in to the final output array. - + Args: - - alg_dtype (:class:`np.dtype` or :obj:`str`): The numpy data type used + + alg_dtype (:class:`np.dtype` or :obj:`str`): The numpy data type used in the wrapped function. - + Returns: - - :class:`numpy.ndarray`: The aggregated cloud fraction output array + + :class:`numpy.ndarray`: The aggregated cloud fraction output array that includes all extra leftmost dimensions. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): new_args = list(args) new_kwargs = dict(kwargs) - + vert = args[0] rh = args[1] - + num_left_dims = vert.ndim - 3 orig_dtype = vert.dtype - - # No special left side iteration, build the output from the + + # No special left side iteration, build the output from the # low, mid, high results. if (num_left_dims == 0): low, mid, high = wrapped(*new_args, **new_kwargs) - + output_dims = (3,) 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 - - outdims += (3,) # low_mid_high - + extra_dims = tuple(outdims) # Copy the left-most dims for iteration + + outdims += (3,) # low_mid_high + outdims += vert.shape[-2:] - + outview_array = np.empty(outdims, alg_dtype) - + # Create the output array where the leftmost dim is the cloud type output_dims = (3,) output_dims += extra_dims output_dims += vert.shape[-2:] output = np.empty(output_dims, orig_dtype) - + has_missing = False missing = default_fill(np.float64) for left_idxs in iter_left_indexes(extra_dims): @@ -465,16 +460,16 @@ def cloudfrac_left_iter(alg_dtype=np.float64): low_idxs = left_idxs + (0, slice(None)) mid_idxs = left_idxs + (1, slice(None)) high_idxs = left_idxs + (2, slice(None)) - + low_output_idxs = (0,) + left_idxs + (slice(None),) mid_output_idxs = (1,) + left_idxs + (slice(None),) high_output_idxs = (2,) + left_idxs + (slice(None),) - + new_args[0] = vert[left_and_slice_idxs] new_args[1] = rh[left_and_slice_idxs] - + # Skip the possible empty/missing arrays for the join method - # Note: Masking handled by cloudfrac.py or computation.py, so only + # Note: Masking handled by cloudfrac.py or computation.py, so only # supply the fill values here. skip_missing = False for arg in (new_args[0:2]): @@ -483,41 +478,41 @@ def cloudfrac_left_iter(alg_dtype=np.float64): output[low_output_idxs] = missing output[mid_output_idxs] = missing output[high_output_idxs] = missing - + skip_missing = True has_missing = True - + if skip_missing: continue - + lowview = outview_array[low_idxs] midview = outview_array[mid_idxs] highview = outview_array[high_idxs] - + new_kwargs["lowview"] = lowview new_kwargs["midview"] = midview new_kwargs["highview"] = highview - + low, mid, high = wrapped(*new_args, **new_kwargs) - - # Make sure the result is the same data as what got passed in + + # 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]): + if (low.__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) - + return output - + return func_wrapper @@ -526,95 +521,94 @@ def interplevel_left_iter(is2dlev, alg_dtype=np.float64): def func_wrapper(wrapped, instance, args, kwargs): new_args = list(args) new_kwargs = dict(kwargs) - + field3d = args[0] z = args[1] levels = args[2] - + num_left_dims = z.ndim - 3 orig_dtype = field3d.dtype left_dims = z.shape[0:num_left_dims] multiproduct = True if field3d.ndim - z.ndim == 1 else False - - # No special left side iteration, build the output from the + + # No special left side iteration, build the output from the # low, mid, high results. if (num_left_dims == 0): if multiproduct: if not is2dlev: - outshape = (field3d.shape[0:-3] + levels.shape + + outshape = (field3d.shape[0:-3] + levels.shape + field3d.shape[-2:]) else: outshape = (field3d.shape[0:-3] + field3d.shape[-2:]) - + 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) return output - + if multiproduct: outdims = field3d.shape[0:1] + left_dims else: outdims = left_dims - + extra_dims = tuple(outdims) - + if not is2dlev: outdims += levels.shape - + outdims += z.shape[-2:] - + outview_array = np.empty(outdims, alg_dtype) for left_idxs in iter_left_indexes(extra_dims): - + field_out_slice_idxs = left_idxs + (slice(None),) - + if multiproduct: z_slice_idxs = left_idxs[1:] + (slice(None),) else: z_slice_idxs = left_idxs + (slice(None),) - - + new_args[0] = field3d[field_out_slice_idxs] new_args[1] = z[z_slice_idxs] - + if is2dlev: if levels.ndim > 2: new_args[2] = levels[z_slice_idxs] - + new_kwargs["outview"] = outview_array[field_out_slice_idxs] - + _ = wrapped(*new_args, **new_kwargs) - + output = outview_array.astype(orig_dtype) - + return output - + return func_wrapper - + def check_cape_args(): """A decorator to check that the cape_3d arguments are valid. - + An exception is raised when an invalid argument is found. - + Returns: - + None - + Raises: - + :class:`ValueError`: Raised when an invalid argument is detected. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): - + p_hpa = args[0] tk = args[1] qv = args[2] @@ -624,11 +618,11 @@ def check_cape_args(): missing = args[6] i3dflag = args[7] ter_follow = args[8] - + is2d = False if i3dflag != 0 else True - is1d = ((np.isscalar(sfp) or np.size(sfp) == 1) or + is1d = ((np.isscalar(sfp) or np.size(sfp) == 1) or (np.isscalar(ter) or np.size(ter) == 1)) - + if not (p_hpa.shape == tk.shape == qv.shape == ht.shape): raise ValueError("arguments 0, 1, 2, 3 must be the same shape") @@ -641,41 +635,41 @@ def check_cape_args(): if np.size(ter) != np.size(sfp): raise ValueError("arguments 4 and 5 must both be scalars or " "both be arrays") - + # Only need to test p_hpa since we assured args 0-3 have same ndim if p_hpa.ndim != 1: raise ValueError("arguments 0-3 " "must be 1-dimensional when " "arguments 4 and 5 are scalars") - + return wrapped(*args, **kwargs) - + return func_wrapper def check_interplevel_args(is2dlev): """A decorator to check that the interplevel arguments are valid. - + An exception is raised when an invalid argument is found. - + Returns: - + None - + Raises: - + :class:`ValueError`: Raised when an invalid argument is detected. - + """ @wrapt.decorator def func_wrapper(wrapped, instance, args, kwargs): - + field3d = args[0] z = args[1] levels = args[2] - + multiproduct = True if (field3d.ndim - z.ndim) == 1 else False - + if not multiproduct: if field3d.shape != z.shape: raise ValueError("arguments 0 and 1 must have the same shape") @@ -683,16 +677,15 @@ def check_interplevel_args(is2dlev): if field3d.shape[1:] != z.shape: raise ValueError("argument 0 and 1 must have same rightmost " "dimensions") - + if is2dlev: if levels.ndim != 2: - if (levels.shape[0:-2] != z.shape[0:-3] or - levels.shape[-2:] != z.shape[-2:]): + if (levels.shape[0:-2] != z.shape[0:-3] or + levels.shape[-2:] != z.shape[-2:]): raise ValueError("argument 1 and 2 must have " "the same leftmost and rightmost " "dimensions") - + return wrapped(*args, **kwargs) - - return func_wrapper + return func_wrapper diff --git a/src/wrf/units.py b/src/wrf/units.py index 11420cf..54d0e2d 100755 --- a/src/wrf/units.py +++ b/src/wrf/units.py @@ -4,31 +4,31 @@ from .constants import Constants, ConversionFactors def _apply_conv_fact(var, vartype, var_unit, dest_unit): - """Return the variable converted to different units using a conversion + """Return the variable converted to different units using a conversion factor. - + Args: - - var (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A + + var (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A variable. - - vartype (:obj:`str`): The type of variable. Choices are: 'wind', + + vartype (:obj:`str`): The type of variable. Choices are: 'wind', 'pressure', 'temp', or 'height'. - + var_unit (:obj:`str`): The variable's current units. - + dest_unit (:obj:`str`): The desired units. - + Returns: - + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The variable in - the desired units. - + the desired units. + """ if var_unit == dest_unit: return var - - # Note, case where var_unit and dest_unit are base unit, should be + + # Note, case where var_unit and dest_unit are base unit, should be # handled above if var_unit == _BASE_UNITS[vartype]: return var*(_CONV_FACTORS[vartype]["to_dest"][dest_unit]) @@ -36,62 +36,62 @@ def _apply_conv_fact(var, vartype, var_unit, dest_unit): if dest_unit == _BASE_UNITS[vartype]: 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]) + return var*(_CONV_FACTORS[vartype]["to_base"][var_unit] * + _CONV_FACTORS[vartype]["to_dest"][dest_unit]) def _to_kelvin(var, var_unit): """Return the variable in Kelvin. - + Args: - - var (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A + + var (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A variable. - + var_unit (:obj:`str`): The variable's current units. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The variable in + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The variable in Kelvin. - + """ if var_unit == "c": return var + Constants.CELKEL elif var_unit == "f": return (var - 32.0) * (5.0/9.0) + Constants.CELKEL - - + + def _k_to_c(var): """Return the variable in Celsius. - + Args: - - var (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A + + var (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A variable in units of Kelvin. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The variable in + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The variable in Celsius. - + """ return var - Constants.CELKEL def _k_to_f(var): """Return the variable in Fahrenheit. - + Args: - - var (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A + + var (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A variable in units of Kelvin. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: The variable in + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The variable in Fahrenheit. - + """ return 1.8 * _k_to_c(var) + 32.0 @@ -99,25 +99,25 @@ def _k_to_f(var): def _apply_temp_conv(var, var_unit, dest_unit): """Return the variable converted to different units using a temperature conversion algorithm. - + Args: - - var (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A + + var (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A variable. - + var_unit (:obj:`str`): The variable's current units. - + dest_unit (:obj:`str`): The desired units. - + Returns: - + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The variable in - the desired units. - + the desired units. + """ if dest_unit == var_unit: return var - + if var_unit != _BASE_UNITS["temp"]: tk = _to_kelvin(var, var_unit) if dest_unit == _BASE_UNITS["temp"]: @@ -126,247 +126,237 @@ def _apply_temp_conv(var, var_unit, dest_unit): return (_TEMP_CONV_METHODS[dest_unit])(tk) else: return (_TEMP_CONV_METHODS[dest_unit])(var) - + # 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. - + Args: - + unit (:obj:`str`): The unit name. - + Returns: - + :obj:`str`: A unit name suitable for dictionary key lookups. - + """ cleaned_unit = " ".join(unit.lower().split()) dealiased = _UNIT_ALIASES.get(cleaned_unit, None) - + return cleaned_unit if dealiased is None else dealiased - + def check_units(unit, unit_type): """Raise an exception if the unit name is invalid. - + Args: - + unit (:obj:`str`): The unit name. - + unit_type (:obj:`str`): The type of unit. - + Returns: - + None - + Raises: - + :class:`ValueError`: Raised when the unit name is invalid. - + """ 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): """Return the variable converted to different units. - + Args: - - var (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A + + var (:class:`xarray.DataArray` or :class:`numpy.ndarray`): A variable. - - vartype (:obj:`str`): The type of variable. Choices are: 'wind', + + vartype (:obj:`str`): The type of variable. Choices are: 'wind', 'pressure', 'temp', or 'height'. - + var_unit (:obj:`str`): The variable's current units. - + dest_unit (:obj:`str`): The desired units. - + Returns: - + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The variable in - the desired units. - + the desired units. + """ - u_cleaned = dealias_and_clean_unit(dest_unit) + u_cleaned = dealias_and_clean_unit(dest_unit) if vartype != "temp": return _apply_conv_fact(var, vartype, var_unit.lower(), u_cleaned) else: return _apply_temp_conv(var, var_unit.lower(), u_cleaned) - - - - - diff --git a/src/wrf/util.py b/src/wrf/util.py index 6a297d0..d8f6567 100644 --- a/src/wrf/util.py +++ b/src/wrf/util.py @@ -14,7 +14,7 @@ try: except ImportError: from inspect import getargspec -try: +try: from inspect import getargvalues except ImportError: from inspect import getgeneratorlocals @@ -41,215 +41,215 @@ 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",) def is_time_coord_var(varname): """Return True if the input variable name is a time coordinate. - + Args: - + varname (:obj:`str`): The input variable name. - + Returns: - - :obj:`bool`: True if the input variable is a time coordinate, + + :obj:`bool`: True if the input variable is a time coordinate, otherwise False. - + """ return varname in _TIME_COORD_VARS def get_coord_pairs(coord_varname): - """Return a :obj:`tuple` for the variable names of the coordinate pair used + """Return a :obj:`tuple` for the variable names of the coordinate pair used for the 2D curvilinear coordinate variable. - - For example, the 'XLAT' variable will have coordinate variables of - ('XLAT', 'XLONG') since the 'XLAT' variable itself is two-dimensional. - + + For example, the 'XLAT' variable will have coordinate variables of + ('XLAT', 'XLONG') since the 'XLAT' variable itself is two-dimensional. + Args: - + coord_varname (:obj:`str`): The coordinate variable name. - + Returns: - - :obj:`bool`: True if the time index is :data:`wrf.ALL_TIMES` or + + :obj:`bool`: True if the time index is :data:`wrf.ALL_TIMES` or :obj:`None`, otherwise False. - + """ return _COORD_PAIR_MAP[coord_varname] def is_multi_time_req(timeidx): - """Return True if the requested time index is for :data:`wrf.ALL_TIMES` or + """Return True if the requested time index is for :data:`wrf.ALL_TIMES` or :obj:`None`. - + Args: - - timeidx (:obj:`int`, :data:`wrf.ALL_TIMES`, or :obj:`None`): The + + timeidx (:obj:`int`, :data:`wrf.ALL_TIMES`, or :obj:`None`): The requested time index. - + Returns: - - :obj:`bool`: True if the time index is :data:`wrf.ALL_TIMES` or + + :obj:`bool`: True if the time index is :data:`wrf.ALL_TIMES` or :obj:`None`, otherwise False. - + """ return timeidx is None def is_multi_file(wrfin): """Return True if the input argument is an iterable. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - + Returns: - + :obj:`bool`: True if the input is an iterable. False if the input is a single NetCDF file object. - + """ return (isinstance(wrfin, Iterable) and not isstr(wrfin)) def has_time_coord(wrfnc): - """Return True if the input file or sequence contains the time + """Return True if the input file or sequence contains the time coordinate variable. - + The time coordinate is named 'XTIME'. - + Args: - - wrfnc (:class:`netCDF4.Dataset` or :class:`Nio.NioFile`): A single + + wrfnc (:class:`netCDF4.Dataset` or :class:`Nio.NioFile`): A single NetCDF file object. - + Returns: - - :obj:`bool`: True if the netcdf file contains the time coordinate + + :obj:`bool`: True if the netcdf file contains the time coordinate variable, False otherwise. - + """ return "XTIME" in wrfnc.variables def is_mapping(wrfin): """Return True if the input file or sequence is a mapping type. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - + Returns: - + :obj:`bool`: True if the input is a mapping type, False otherwise. - + """ return isinstance(wrfin, Mapping) def _generator_copy(gen): """Return a copy of a generator. - + This function instantiates a new generator object using the arguments passed to the original. - + Args: - + gen (:class:`types.GeneratorType`): A generator object. - + Note: - + In order for this to work correctly, the generator cannot modify the original construction arguments. - + Returns: - + :class:`types.GeneratorType`: A copy of the generator object. - + """ funcname = gen.__name__ - - # This is for generator expressions. Only solution is to tee the + + # This is for generator expressions. Only solution is to tee the # original generator. if funcname == "": return tee(gen) - + try: argvals = getargvalues(gen.gi_frame) except NameError: argvals = getgeneratorlocals(gen) module = getmodule(gen.gi_frame) - + 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. + # fixed by Python. try: res = module.get(funcname)(**argvals.locals) except AttributeError: - res = getattr(module, funcname)(**argvals.locals) + res = getattr(module, funcname)(**argvals.locals) else: # Created in jupyter or the python interpreter 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: - # This was the old way it used to work, but appears to have + 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) - + return res def test(): - q = [1,2,3] + q = [1, 2, 3] for i in q: yield i - - + + class TestGen(object): def __init__(self, count=3): self._total = count self._i = 0 - + def __iter__(self): return self - + def next(self): if self._i >= self._total: raise StopIteration @@ -257,232 +257,232 @@ class TestGen(object): val = self._i self._i += 1 return val - + # Python 3 def __next__(self): return self.next() def latlon_coordvars(ncvars): - """Return the first found latitude and longitude coordinate names from a + """Return the first found latitude and longitude coordinate names from a NetCDF variable dictionary. - + This function searches the dictionary structure for NetCDF variables and returns the first found latitude and longitude coordinate names (typically 'XLAT' and 'XLONG'). - + Args: - + ncvars (:obj:`dict`): A NetCDF variable dictionary object. - + Returns: - - :obj:`tuple`: The latitude and longitude coordinate name pairs as + + :obj:`tuple`: The latitude and longitude coordinate name pairs as (lat_coord_name, lon_coord_name). - + """ lat_coord = None lon_coord = None - + for name in _LAT_COORDS: if name in viewkeys(ncvars): lat_coord = name break - + for name in _LON_COORDS: if name in viewkeys(ncvars): lon_coord = name break - + return lat_coord, lon_coord def is_coordvar(varname): """Returns True if the variable is a coordinate variable. - + Args: - + varname (:obj:`str`): The variable name. - + Returns: - - :obj:`bool`: True if the variable is a coordinate variable, + + :obj:`bool`: True if the variable is a coordinate variable, otherwise False. - + """ return varname in _COORD_VARS class IterWrapper(Iterable): """A wrapper class for generators and custom iterable classes that returns - a new iterator to the start of the sequence when + a new iterator to the start of the sequence when :meth:`IterWrapper.__iter__` is called. - - If the wrapped object is a generator, a copy of the generator is - constructed and returned when :meth:`IterWrapper.__iter__` is called. - If the wrapped object is a custom type, then the :meth:`copy.copy` is - called and a new instance is returned. In both cases, the original + + If the wrapped object is a generator, a copy of the generator is + constructed and returned when :meth:`IterWrapper.__iter__` is called. + If the wrapped object is a custom type, then the :meth:`copy.copy` is + called and a new instance is returned. In both cases, the original iterable object is unchanged. - + Note: - + Do not increment the wrapped iterable outside of this wrapper. - + """ def __init__(self, wrapped): """Initialize an :class:`wrf.IterWrapper` object. - + Args: - - wrapped (an iterable object): Any iterable object that contains the + + wrapped (an iterable object): Any iterable object that contains the *__iter__* method. - + """ self._wrapped = wrapped - + def __iter__(self): - """Return an iterator to the start of the sequence. - + """Return an iterator to the start of the sequence. + Returns: - + An iterator to the start of the sequence. - + """ if isinstance(self._wrapped, GeneratorType): - + gen_copy = _generator_copy(self._wrapped) # If a tuple comes back, then this is a generator expression, # so store the first tee'd item, then return the other if isinstance(gen_copy, tuple): self._wrapped = gen_copy[0] return gen_copy[1] - + return gen_copy else: obj_copy = copy(self._wrapped) return obj_copy.__iter__() - - + + def get_iterable(wrfseq): - """Returns a resettable iterable object. - - In this context, resettable means that when :meth:`object.__iter__` + """Returns a resettable iterable object. + + In this context, resettable means that when :meth:`object.__iter__` is called, the iterable returned always points to the first element in the sequence, similar to how the list and tuple behave. - + Args: - - wrfseq (iterable): An iterable type, which includes lists, tuples, + + wrfseq (iterable): An iterable type, which includes lists, tuples, dictionaries, generators, and user-defined classes. - + Returns: - + iterable: A resettable iterator object. - + """ if not is_multi_file(wrfseq): return wrfseq else: if not is_mapping(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 def to_np(array): - """Return the :class:`numpy.ndarray` contained in an + """Return the :class:`numpy.ndarray` contained in an :class:`xarray.DataArray` instance. - - If the :class:`xarray.DataArray` instance does not contain a *_FillValue* - or *missing_value* attribute, then this routine simply returns the - :attr:`xarray.DataArray.values` attribute. If the - :class:`xarray.DataArray` object contains a *_FillValue* or *missing_value* - attribute, then this routine returns a :class:`numpy.ma.MaskedArray` - instance, where the NaN values (used by xarray to represent missing data) + + If the :class:`xarray.DataArray` instance does not contain a *_FillValue* + or *missing_value* attribute, then this routine simply returns the + :attr:`xarray.DataArray.values` attribute. If the + :class:`xarray.DataArray` object contains a *_FillValue* or *missing_value* + attribute, then this routine returns a :class:`numpy.ma.MaskedArray` + instance, where the NaN values (used by xarray to represent missing data) are replaced with the fill value. - - If the object passed in to this routine is not an + + If the object passed in to this routine is not an :class:`xarray.DataArray` instance, then this routine simply returns the - passed in object. This is useful in situations where you do not know - if you have an :class:`xarray.DataArray` or a :class:`numpy.ndarray` and - simply want a :class:`numpy.ndarray` returned. + passed in object. This is useful in situations where you do not know + if you have an :class:`xarray.DataArray` or a :class:`numpy.ndarray` and + simply want a :class:`numpy.ndarray` returned. Args: - + array (:class:`xarray.DataArray`, :class:`numpy.ndarray`, or any \ - object): Can be any object type, but is generally + object): Can be any object type, but is generally used with :class:`xarray.DataArray` or :class:`numpy.ndarray`. - + Returns: - - :class:`numpy.ndarray` or :class:`numpy.ma.MaskedArray`: The - extracted array or the *array* object if *array* is not a + + :class:`numpy.ndarray` or :class:`numpy.ma.MaskedArray`: The + extracted array or the *array* object if *array* is not a :class:`xarray.DataArray` object.. - + """ 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) - + return result # Helper utilities for metadata class either(object): - """A callable class that determines which variable is present in the - file. - + """A callable class that determines which variable is present in the + file. + This is used in situations where the same variable type has different names - depending on the type of file used. For example, in a WRF output file, + depending on the type of file used. For example, in a WRF output file, 'P' is used for pressure, whereas in a met_em file, pressure is named - 'PRES'. - + 'PRES'. + Methods: - + __call__(wrfin): Return the variable that is present in the file. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` - or an iterable sequence of the aforementioned types. - + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + or an iterable sequence of the aforementioned types. + Returns: - + :obj:`str`: The variable name that is present in the file. - + Attributes: - + varnames (sequence): A sequence of possible variable names. - + """ def __init__(self, *varnames): """Initialize an :class:`either` object. - + Args: - + *varnames (sequence): A sequence of possible variable names. - + """ self.varnames = varnames - + def __call__(self, wrfin): if is_multi_file(wrfin): if not is_mapping(wrfin): @@ -490,71 +490,71 @@ class either(object): else: entry = wrfin[next(iter(viewkeys(wrfin)))] return self(entry) - + for varname in self.varnames: if varname in wrfin.variables: return varname - + raise ValueError("{} are not valid variable names".format( - self.varnames)) - - + self.varnames)) + + # This should look like: # [(0, (-3,-2)), # variable 1 # (1, -1)] # variable 2 class combine_dims(object): - """A callable class that mixes dimension sizes from different function - arguments. - - This callable object is used for determining the output size for the - extension module functions. The class is initialized with a sequence of - pairs, where the first value is the function argument index. The second - value is the dimension index(es) to use. The second value can be a + """A callable class that mixes dimension sizes from different function + arguments. + + This callable object is used for determining the output size for the + extension module functions. The class is initialized with a sequence of + pairs, where the first value is the function argument index. The second + value is the dimension index(es) to use. The second value can be a single integer or a sequence if multiple dimensions are used. - + Methods: - + __call__(*args): Return a tuple with the combined dimension sizes. - + Args: - - *args: The function arguments from which to extract the + + *args: The function arguments from which to extract the dimensions sizes. - + Returns: - + :obj:`tuple`: The shape for the combined dimensions. - + Attributes: - - pairs (sequence): A sequence representing how to combine the + + pairs (sequence): A sequence representing how to combine the dimensions. - + Example: - + .. code-block:: python - + # Take the -3, and -2 dimension sizes from argument 0 # Then take the -1 dimension size from argument 1 pairs = [(0, (-3, -2), (1, -1)] - + combo = combine_dims(pairs) - + """ - + def __init__(self, pairs): """Initialize a :class:`combine_dims` object. - + Args: - - pairs (sequence): A sequence where each element is a pair - (:obj:`tuple`), with the first element being the function + + pairs (sequence): A sequence where each element is a pair + (:obj:`tuple`), with the first element being the function argument index and the second value being either an integer or sequence for the dimension size indexes to use. - + """ self.pairs = pairs - + def __call__(self, *args): result = [] for pair in self.pairs: @@ -565,170 +565,170 @@ class combine_dims(object): result.append(var.shape[dimidx]) else: result.append(var.shape[dimidxs]) - + return tuple(result) - - + + class from_var(object): """A callable class that retrieves attributes from the function argument. - - If the function argument is not of type :class:`xarray.DataArray`, then + + If the function argument is not of type :class:`xarray.DataArray`, then None will be returned. - + It is assumed that the function has been wrapped using the :mod:`wrapt` module. - + Methods: - + __call__(wrapped, *args, **kwargs): Return the attribute found in \ the function arguments. - + Args: wrapped: The wrapped function, as used by the :mod:`wrapt` module. - + *args: The function arguments. - + **kwargs: The function keyword arguments. - + Returns: - + :obj:`object`: The requested attribute. - + Attributes: - + varname (:obj:`str`): The variable name. - + attribute (:obj:`str`): The attribute name. - + """ def __init__(self, varname, attribute): """Initialize a :class:`from_var` object. - + Args: - + varname (:obj:`str`): The variable name. - + attribute (:obj:`str`): The attribute name. - + """ self.varname = varname self.attribute = attribute - + def __call__(self, wrapped, *args, **kwargs): vard = from_args(wrapped, (self.varname,), *args, **kwargs) - + var = None if vard is not None: var = vard[self.varname] - + try: - return var.attrs.get(self.attribute, None) + return var.attrs.get(self.attribute, None) except AttributeError: return None - + def _corners_moved(wrfnc, first_ll_corner, first_ur_corner, latvar, lonvar): """Return True if the corner points have moved. - + This function is used to test for a moving domain, since the WRF output does not set any flags in the file for this. The test will be performed for all time steps in the NetCDF file. Args: - - wrfnc (:class:`netCDF4.Dataset` or :class:`Nio.NioFile`): A single + + wrfnc (:class:`netCDF4.Dataset` or :class:`Nio.NioFile`): A single NetCDF file object. - + first_ll_corner (:obj:`tuple`): A (latitude, longitude) pair for the lower left corner found in the initial file. - + first_ur_corner (:obj:`tuple`): A (latitude, longitude) pair for the upper right corner found in the initial file. - + latvar (:obj:`str`): The latitude variable name to use. - + lonvar (:obj:`str`: The longitude variable name to use. - - + + Returns: - + :obj:`bool`: True if the corner points have moved, False otherwise. - + """ lats = wrfnc.variables[latvar][:] lons = wrfnc.variables[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): - +def is_moving_domain(wrfin, varname=None, latvar=either("XLAT", "XLAT_M"), + lonvar=either("XLONG", "XLONG_M"), _key=None): + """Return True if the domain is a moving nest. - + This function is used to test for a moving domain, since the WRF output does not set any flags in the file for this. The test will be performed for all files in any sequences and across all times in each file. - - This result is cached internally, so this potentially lengthy check is + + This result is cached internally, so this potentially lengthy check is only done one time for any given *wrfin* parameter. Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - varname (:obj:`str`, optional): A specific NetCDF variable to test, + + varname (:obj:`str`, optional): A specific NetCDF variable to test, which must contain a 'coordinates' attribute. If unspecified, - The *latvar* and *lonvar* parameters are used. Default is None. - + The *latvar* and *lonvar* parameters are used. Default is None. + first_ur_corner (:obj:`tuple`): A (latitude, longitude) pair for the upper right corner found in the initial file. - - latvar (:obj:`str` or :class:`either`, optional): The latitude variable + + latvar (:obj:`str` or :class:`either`, optional): The latitude variable name. Default is :class:`either('XLAT', 'XLAT_M')`. - - lonvar (:obj:`str` or :class:`either`, optional): The latitude variable + + lonvar (:obj:`str` or :class:`either`, optional): The latitude variable name. Default is :class:`either('XLAT', 'XLAT_M')`. - - _key (:obj:`int`, optional): A caching key. This is used for internal + + _key (:obj:`int`, optional): A caching key. This is used for internal purposes only. Default is None. - + Returns: - + :obj:`bool`: True if the domain is a moving nest, False otherwise. - + """ - + if isinstance(latvar, either): latvar = latvar(wrfin) - + if isinstance(lonvar, either): lonvar = lonvar(wrfin) - + # In case it's just a single file if not is_multi_file(wrfin): wrfin = [wrfin] - + # Slow, but safe. Compare the corner points to the first item and see # any move. User iterator protocol in case wrfin is not a list/tuple. if not is_mapping(wrfin): @@ -740,7 +740,7 @@ def is_moving_domain(wrfin, varname=None, latvar=either("XLAT", "XLAT_M"), entry = wrfin[dict_key] key = _key[dict_key] if _key is not None else None return is_moving_domain(entry, varname, latvar, lonvar, key) - + # The long way of checking all lat/lon corner points. Doesn't appear # to be a shortcut in the netcdf files. if varname is not None: @@ -752,48 +752,54 @@ def is_moving_domain(wrfin, varname=None, latvar=either("XLAT", "XLAT_M"), else: coord_names = coord_str.decode().split() except AttributeError: - # Variable doesn't have a coordinates attribute, use the + # Variable doesn't have a coordinates attribute, use the # arguments lon_coord = lonvar lat_coord = latvar - else: - lon_coord = coord_names[0] - lat_coord = coord_names[1] + else: + for name in coord_names: + if name in _LAT_COORDS: + lat_coord = name + continue + + if name in _LON_COORDS: + lon_coord = name + continue else: lon_coord = lonvar lat_coord = latvar - + # See if there is a cached value product = "is_moving_{}_{}".format(lat_coord, lon_coord) moving = get_cached_item(_key, product) if moving is not None: return moving - + # Need to search all the files lats = first_wrfnc.variables[lat_coord][:] lons = first_wrfnc.variables[lon_coord][:] - + zero_idxs = [0]*len(lats.shape) # PyNIO doesn't have ndim last_idxs = list(zero_idxs) last_idxs[-2:] = [-1]*2 - + zero_idxs = tuple(zero_idxs) last_idxs = tuple(last_idxs) - + lat0 = lats[zero_idxs] lat1 = lats[last_idxs] lon0 = lons[zero_idxs] lon1 = lons[last_idxs] - + ll_corner = (lat0, lon0) ur_corner = (lat1, lon1) - - # Need to check if the first file is moving, might be a single + + # Need to check if the first file is moving, might be a single # file with multiple times if _corners_moved(first_wrfnc, ll_corner, ur_corner, lat_coord, lon_coord): cache_item(_key, product, True) return True - + # Now check any additional files while True: try: @@ -801,14 +807,14 @@ def is_moving_domain(wrfin, varname=None, latvar=either("XLAT", "XLAT_M"), except StopIteration: break else: - if _corners_moved(wrfnc, ll_corner, ur_corner, + if _corners_moved(wrfnc, ll_corner, ur_corner, lat_coord, lon_coord): - + cache_item(_key, product, True) return True cache_item(_key, product, False) - + return False @@ -816,80 +822,80 @@ def _get_global_attr(wrfnc, attr): """Return the global attribute. Args: - - wrfnc (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`): A single + + wrfnc (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`): A single WRF NetCDF file object. - - attr (:obj:`str`): The attribute name. - + + attr (:obj:`str`): The attribute name. + Returns: - + :obj:`object`: The global attribute. - + """ val = getattr(wrfnc, attr, None) - + # PyNIO puts single values in to an array if isinstance(val, np.ndarray): if len(val) == 1: - return val[0] + return val[0] return val - - + + def extract_global_attrs(wrfin, attrs): """Return the global attribute(s). - + If the *wrfin* parameter is a sequence, then only the first element is used, so the entire sequence must have the same global attributes. Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - attrs (:obj:`str`, sequence): The attribute name - or a sequence of attribute names. - + + attrs (:obj:`str`, sequence): The attribute name + or a sequence of attribute names. + Returns: - + :obj:`dict`: A mapping of attribute_name to value. - + """ if isstr(attrs): attrlist = [attrs] else: attrlist = attrs - + multifile = is_multi_file(wrfin) - + if multifile: if not is_mapping(wrfin): wrfin = next(iter(wrfin)) else: 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): """Return the dimension size for the specified dimension name. Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - + dim (:obj:`str`): The dimension name. - + Returns: - + :obj:`int`: The dimension size. - + """ if is_multi_file(wrfin): if not is_mapping(wrfin): @@ -897,94 +903,95 @@ def extract_dim(wrfin, dim): else: entry = wrfin[next(iter(viewkeys(wrfin)))] return extract_dim(entry, dim) - + d = wrfin.dimensions[dim] if not isinstance(d, int): try: - return len(d) #netCDF4 - except TypeError: #scipy.io.netcdf - # Scipy can't handled unlimited dimensions, so now we have to + 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") - - return d # PyNIO - - + else: + return s[-4] + + return d # PyNIO + + def _combine_dict(wrfdict, varname, timeidx, method, meta, _key): """Return an array object from a mapping input. - - The resulting array is the combination of all sequences associated with + + The resulting array is the combination of all sequences associated with each key in the dictionary. The leftmost dimension will be the keys. The - rightmost dimensions are the dimensions for the aggregated sequences of - arrays, using either the 'cat' or 'join' *method* parameter value. + rightmost dimensions are the dimensions for the aggregated sequences of + arrays, using either the 'cat' or 'join' *method* parameter value. If dictionaries are nested, then the outermost dictionary keys will be the leftmost dimension, followed by each subsequent dictionary's keys. - - If the order of the keys (and leftmost dimension ordering) matters, it is - recommended that an :class:`OrderedDict` be used instead of a normal - dictionary. Otherwise, the leftmost dimension will be ordered by the + + If the order of the keys (and leftmost dimension ordering) matters, it is + recommended that an :class:`OrderedDict` be used instead of a normal + dictionary. Otherwise, the leftmost dimension will be ordered by the iteration order. - + Args: - - wrfdict (mapping): A mapping of key to an array or + + wrfdict (mapping): A mapping of key to an array or key to a sequence of arrays. - + varname (:obj:`str`) : The variable name. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): Cache key for the coordinate variables. + + _key (:obj:`int`, optional): Cache key for the coordinate variables. This is used for internal purposes only. Default is None. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ keynames = [] - numkeys = len(wrfdict) - + numkeys = len(wrfdict) + key_iter = iter(viewkeys(wrfdict)) first_key = next(key_iter) keynames.append(first_key) - + is_moving = is_moving_domain(wrfdict, varname, _key=_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) - + + first_array = _extract_var(wrfdict[first_key], varname, + 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: try: @@ -994,22 +1001,22 @@ def _combine_dict(wrfdict, varname, timeidx, method, meta, _key): else: keynames.append(key) _cache_key = _key[key] if _key is not None else None - vardata = _extract_var(wrfdict[key], varname, timeidx, - is_moving=is_moving, method=method, + vardata = _extract_var(wrfdict[key], varname, timeidx, + is_moving=is_moving, method=method, squeeze=False, cache=None, meta=meta, _key=_cache_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: outname = str(first_array.name) # Note: assumes that all entries in dict have same coords outcoords = OrderedDict(first_array.coords) - + # First find and store all the existing key coord names/values # This is applicable only if there are nested dictionaries. key_coordnames = [] @@ -1017,90 +1024,88 @@ def _combine_dict(wrfdict, varname, timeidx, method, meta, _key): existing_cnt = 0 while True: key_coord_name = "key_{}".format(existing_cnt) - + if key_coord_name not in first_array.dims: break - + key_coordnames.append(key_coord_name) coord_vals.append(to_np(first_array.coords[key_coord_name])) - + existing_cnt += 1 - + # Now add the key coord name and values for THIS dictionary. - # Put the new key_n name at the bottom, but the new values will + # Put the new key_n name at the bottom, but the new values will # be at the top to be associated with key_0 (left most). This - # effectively shifts the existing 'key_n' coordinate values to the - # right one dimension so *this* dicionary's key coordinate values + # effectively shifts the existing 'key_n' coordinate values to the + # right one dimension so *this* dicionary's key coordinate values # are at 'key_0'. key_coordnames.append(key_coord_name) coord_vals.insert(0, keynames) - + # 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, + + outarr = DataArray(outdata, name=outname, coords=outcoords, dims=outdims, attrs=outattrs) else: outarr = outdata - + return outarr def _find_coord_names(coords): - """Return the coordinate variables names found in a + """Return the coordinate variables names found in a :attr:`xarray.DataArray.coords` mapping. - + Args: - + coords (mapping): A :attr:`xarray.DataArray.coords` mapping object. - + Returns: - + :obj:`tuple`: The latitude, longitude, and xtime variable names used in the coordinate mapping. - + """ try: lat_coord = [name for name in _COORD_VARS[0::2] if name in coords][0] except IndexError: lat_coord = None - + try: lon_coord = [name for name in _COORD_VARS[1::2] if name in coords][0] except IndexError: lon_coord = None - + try: xtime_coord = [name for name in _TIME_COORD_VARS if name in coords][0] except IndexError: xtime_coord = None - + return lat_coord, lon_coord, xtime_coord def _find_max_time_size(wrfseq): - """Return the maximum number of times found in a sequence of + """Return the maximum number of times found in a sequence of WRF files. - + Args: - + wrfseq (sequence): A sequence of WRF NetCDF file objects. - + Returns: - + :obj:`int`: The maximum number of times found in a file. - + """ wrf_iter = iter(wrfseq) - + max_times = 0 while True: try: @@ -1110,12 +1115,12 @@ def _find_max_time_size(wrfseq): else: t = extract_dim(wrfnc, "Time") max_times = t if t >= max_times else max_times - + return max_times def _get_coord_names(wrfin, varname): - + # Need only the first real file if is_multi_file(wrfin): if not is_mapping(wrfin): @@ -1125,28 +1130,28 @@ def _get_coord_names(wrfin, varname): return _get_coord_names(entry, varname) else: wrfnc = wrfin - + lat_coord = None lon_coord = None time_coord = None - + var = wrfnc.variables[varname] - - # WRF variables will have a coordinates attribute. MET_EM files have + + # WRF variables will have a coordinates attribute. MET_EM files have # a stagger attribute which indicates the coordinate variable. try: # WRF files coord_attr = getattr(var, "coordinates") except AttributeError: - + if is_coordvar(varname): # Coordinate variable (most likely XLAT or XLONG) lat_coord, lon_coord = get_coord_pairs(varname) time_coord = None - + if has_time_coord(wrfnc): time_coord = "XTIME" - + elif is_time_coord_var(varname): lon_coord = None lat_coord = None @@ -1158,7 +1163,7 @@ def _get_coord_names(wrfin, varname): except AttributeError: lon_coord = None lat_coord = None - + # Let's just check for xlat and xlong in this case if "XLAT" in wrfnc.variables: lat_coord = "XLAT" @@ -1167,12 +1172,12 @@ def _get_coord_names(wrfin, varname): # For met_em files, use the stagger name to get the lat/lon var lat_coord = "XLAT_{}".format(stag_attr) lon_coord = "XLONG_{}".format(stag_attr) - + # If this coord name is missing, it might be an old WRF file if lat_coord not in wrfnc.variables: lat_coord = None lon_coord = None - + if "XLAT" in wrfnc.variables: lat_coord = "XLAT" lon_coord = "XLONG" @@ -1181,60 +1186,67 @@ def _get_coord_names(wrfin, varname): coord_names = coord_attr.split() else: coord_names = coord_attr.decode().split() - lon_coord = coord_names[0] - lat_coord = coord_names[1] - - try: - time_coord = coord_names[2] - except IndexError: - time_coord = None - else: - # Make sure they time variable wasn't removed + + for name in coord_names: + if name in _LAT_COORDS: + lat_coord = name + continue + + if name in _LON_COORDS: + lon_coord = name + continue + + if name in _TIME_COORD_VARS: + time_coord = name + continue + + if time_coord is not None: + # Make sure the time variable wasn't removed try: _ = wrfnc.variables[time_coord] except KeyError: time_coord = None - + return lat_coord, lon_coord, time_coord - -def _build_data_array(wrfnc, varname, timeidx, is_moving_domain, is_multifile, + +def _build_data_array(wrfnc, varname, timeidx, is_moving_domain, is_multifile, _key): - """Return a :class:`xarray.DataArray` object for the desired variable in - a single NetCDF file object. - + """Return a :class:`xarray.DataArray` object for the desired variable in + a single NetCDF file object. + Args: - - wrfnc (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`): A single + + wrfnc (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`): A single WRF NetCDF file object. - + varname (:obj:`str`) : The variable name. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - is_moving_domain (:obj:`bool`): A boolean type that indicates if the + + is_moving_domain (:obj:`bool`): A boolean type that indicates if the NetCDF file object came from a moving nest. - + is_multifile (:obj:`bool`): A boolean type that indicates if the NetCDF file object came from a sequence. - - _key (:obj:`int`, optional): Cache key for the coordinate variables. + + _key (:obj:`int`, optional): Cache key for the coordinate variables. This is used for internal purposes only. Default is None. - + Returns: - + :class:`xarray.DataArray`: An array object that contains metadata. - + """ - + # Note: wrfnc is always a single netcdf file object - # is_moving_domain and is_multifile are arguments indicating if the + # is_moving_domain and is_multifile are arguments indicating if the # single file came from a sequence, and if that sequence is has a moving - # domain. Both arguments are used mainly for coordinate extraction and + # domain. Both arguments are used mainly for coordinate extraction and # caching. multitime = is_multi_time_req(timeidx) time_idx_or_slice = timeidx if not multitime else slice(None) @@ -1243,45 +1255,44 @@ def _build_data_array(wrfnc, varname, timeidx, is_moving_domain, is_multifile, data = var[time_idx_or_slice, :] else: data = var[time_idx_or_slice] - + # Want to preserve the time dimension if not multitime: if len(var.shape) > 1: data = data[np.newaxis, :] else: data = data[np.newaxis] - + attrs = OrderedDict() 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"): + if dkey in ("data", "_shape", "_size", "_typecode", "_attributes", + "maskandscale", "dimensions"): continue - + _dkey = dkey if isinstance(dkey, str) else dkey.decode() if isstr(val): _val = val else: if isinstance(val, bytes): - _val = val.decode() # scipy.io.netcdf + _val = val.decode() # scipy.io.netcdf else: _val = val - + attrs[_dkey] = _val - + dimnames = var.dimensions[-data.ndim:] - + lat_coord = lon_coord = time_coord = None - + try: if dimnames[-2] == "south_north" and dimnames[-1] == "west_east": lat_coord, lon_coord, time_coord = _get_coord_names(wrfnc, varname) except IndexError: pass - - + coords = OrderedDict() - + # Handle lat/lon coordinates and projection information if available if lon_coord is not None and lat_coord is not None: # Using a cache for coordinate variables so the extraction only happens @@ -1290,124 +1301,124 @@ def _build_data_array(wrfnc, varname, timeidx, is_moving_domain, is_multifile, lon_coord_valkey = lon_coord + "_val" lat_coord_dimkey = lat_coord + "_dim" lat_coord_valkey = lat_coord + "_val" - + lon_coord_dims = get_cached_item(_key, lon_coord_dimkey) lon_coord_vals = get_cached_item(_key, lon_coord_valkey) if lon_coord_dims is None or lon_coord_vals is None: lon_var = wrfnc.variables[lon_coord] lon_coord_dims = lon_var.dimensions lon_coord_vals = lon_var[:] - + # Only cache here if the domain is not moving, otherwise # caching is handled by cat/join if not is_moving_domain: cache_item(_key, lon_coord_dimkey, lon_coord_dims) cache_item(_key, lon_coord_valkey, lon_coord_vals) - + lat_coord_dims = get_cached_item(_key, lat_coord_dimkey) lat_coord_vals = get_cached_item(_key, lat_coord_valkey) if lat_coord_dims is None or lat_coord_vals is None: lat_var = wrfnc.variables[lat_coord] lat_coord_dims = lat_var.dimensions lat_coord_vals = lat_var[:] - + # Only cache here if the domain is not moving, otherwise # caching is done in cat/join if not is_moving_domain: cache_item(_key, lat_coord_dimkey, lat_coord_dims) cache_item(_key, lat_coord_valkey, lat_coord_vals) - + time_coord_vals = None if time_coord is not None: # If not from a multifile sequence, then cache the time # coordinate. Otherwise, handled in cat/join/ if not is_multifile: time_coord_vals = get_cached_item(_key, time_coord) - + if time_coord_vals is None: time_coord_vals = wrfnc.variables[time_coord][:] - + if not is_multifile: cache_item(_key, time_coord, time_coord_vals) else: time_coord_vals = wrfnc.variables[time_coord][:] - + if multitime: if is_moving_domain: # Special case with a moving domain in a multi-time file, # otherwise the projection parameters don't change coords[lon_coord] = lon_coord_dims, lon_coord_vals coords[lat_coord] = lat_coord_dims, lat_coord_vals - + else: - coords[lon_coord] = (lon_coord_dims[1:], - lon_coord_vals[0,:]) - coords[lat_coord] = (lat_coord_dims[1:], - lat_coord_vals[0,:]) - + coords[lon_coord] = (lon_coord_dims[1:], + lon_coord_vals[0, :]) + coords[lat_coord] = (lat_coord_dims[1:], + 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,:]) - coords[lat_coord] = (lat_coord_dims[1:], - lat_coord_vals[timeidx,:]) - + coords[lon_coord] = (lon_coord_dims[1:], + lon_coord_vals[timeidx, :]) + coords[lat_coord] = (lat_coord_dims[1:], + lat_coord_vals[timeidx, :]) + if time_coord is not None: - coords[time_coord] = (lon_coord_dims[0], + coords[time_coord] = (lon_coord_dims[0], [time_coord_vals[timeidx]]) - + proj_params = get_proj_params(wrfnc) proj = getproj(**proj_params) attrs["projection"] = proj - + if dimnames[0] == "Time": t = extract_times(wrfnc, timeidx, meta=False, do_xtime=False) if not multitime: t = [t] coords[dimnames[0]] = t - + data_array = DataArray(data, name=varname, dims=dimnames, coords=coords, attrs=attrs) - + return data_array def _find_forward(wrfseq, varname, timeidx, is_moving, meta, _key): - """Find and return the array object within a sequence for a specific time + """Find and return the array object within a sequence for a specific time index. - + Args: - - wrfseq (iterable): An iterable type, which includes lists, tuples, + + wrfseq (iterable): An iterable type, which includes lists, tuples, dictionaries, generators, and user-defined classes. - + varname (:obj:`str`) : The variable name. - + timeidx (:obj:`int`): The desired time index. Must be positive. - - is_moving (:obj:`bool`): A boolean type that indicates if the + + is_moving (:obj:`bool`): A boolean type that indicates if the sequence is a moving nest. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): Cache key for the coordinate variables. + + _key (:obj:`int`, optional): Cache key for the coordinate variables. This is used for internal purposes only. Default is None. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ wrf_iter = iter(wrfseq) comboidx = 0 - + while True: try: wrfnc = next(wrf_iter) @@ -1415,12 +1426,12 @@ def _find_forward(wrfseq, varname, timeidx, is_moving, meta, _key): break else: numtimes = extract_dim(wrfnc, "Time") - + if timeidx < comboidx + numtimes: filetimeidx = timeidx - comboidx - + if meta: - return _build_data_array(wrfnc, varname, filetimeidx, + return _build_data_array(wrfnc, varname, filetimeidx, is_moving, True, _key) else: var = wrfnc.variables[varname] @@ -1430,57 +1441,57 @@ def _find_forward(wrfseq, varname, timeidx, is_moving, meta, _key): else: result = var[filetimeidx] return result[np.newaxis] # So that nosqueeze works - + else: comboidx += numtimes - + raise IndexError("timeidx {} is out of bounds".format(timeidx)) def _find_reverse(wrfseq, varname, timeidx, is_moving, meta, _key): - """Find and return the array object within a sequence for a specific time + """Find and return the array object within a sequence for a specific time index. - + The sequence is searched in reverse. - + Args: - - wrfseq (iterable): An iterable type, which includes lists, tuples, + + wrfseq (iterable): An iterable type, which includes lists, tuples, dictionaries, generators, and user-defined classes. - + varname (:obj:`str`) : The variable name. - + timeidx (:obj:`int`): The desired time index. Must be negative. - - is_moving (:obj:`bool`): A boolean type that indicates if the + + is_moving (:obj:`bool`): A boolean type that indicates if the sequence is a moving nest. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): Cache key for the coordinate variables. + + _key (:obj:`int`, optional): Cache key for the coordinate variables. This is used for internal purposes only. Default is None. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - + try: revwrfseq = reversed(wrfseq) except TypeError: revwrfseq = reversed(list(wrfseq)) - + wrf_iter = iter(revwrfseq) revtimeidx = -timeidx - 1 comboidx = 0 - + while True: try: wrfnc = next(wrf_iter) @@ -1488,195 +1499,195 @@ def _find_reverse(wrfseq, varname, timeidx, is_moving, meta, _key): break else: numtimes = extract_dim(wrfnc, "Time") - + if revtimeidx < comboidx + numtimes: - # Finds the "forward" sequence index, then counts that - # number back from the back of the ncfile times, + # Finds the "forward" sequence index, then counts that + # number back from the back of the ncfile times, # since the ncfile needs to be iterated backwards as well. filetimeidx = numtimes - (revtimeidx - comboidx) - 1 - + if meta: - return _build_data_array(wrfnc, varname, filetimeidx, + return _build_data_array(wrfnc, varname, filetimeidx, 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 - + raise IndexError("timeidx {} is out of bounds".format(timeidx)) def _find_arr_for_time(wrfseq, varname, timeidx, is_moving, meta, _key): - """Find and return the array object within a sequence for a specific time + """Find and return the array object within a sequence for a specific time index. - + The sequence is searched in forward or reverse based on the time index chosen. - + Args: - - wrfseq (iterable): An iterable type, which includes lists, tuples, + + wrfseq (iterable): An iterable type, which includes lists, tuples, dictionaries, generators, and user-defined classes. - + varname (:obj:`str`) : The variable name. - + timeidx (:obj:`int`): The desired time index. - - is_moving (:obj:`bool`): A boolean type that indicates if the + + is_moving (:obj:`bool`): A boolean type that indicates if the sequence is a moving nest. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): Cache key for the coordinate variables. + + _key (:obj:`int`, optional): Cache key for the coordinate variables. This is used for internal purposes only. Default is None. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ if timeidx >= 0: return _find_forward(wrfseq, varname, timeidx, is_moving, meta, _key) else: return _find_reverse(wrfseq, varname, timeidx, is_moving, meta, _key) - + def _cat_files(wrfseq, varname, timeidx, is_moving, squeeze, meta, _key): """Return an array object from a sequence of files using the concatenate method. - - The concatenate method aggregates all files in the sequence along the - 'Time' dimension, which will be the leftmost dimension. No sorting is + + The concatenate method aggregates all files in the sequence along the + 'Time' dimension, which will be the leftmost dimension. No sorting is performed, so all files in the sequence must be sorted prior to calling this method. - - + + Args: - - wrfseq (iterable): An iterable type, which includes lists, tuples, + + wrfseq (iterable): An iterable type, which includes lists, tuples, dictionaries, generators, and user-defined classes. - + varname (:obj:`str`) : The variable name. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - is_moving (:obj:`bool`): A boolean type that indicates if the + + is_moving (:obj:`bool`): A boolean type that indicates if the sequence is a moving nest. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): Cache key for the coordinate variables. + + _key (:obj:`int`, optional): Cache key for the coordinate variables. This is used for internal purposes only. Default is None. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ if is_moving is None: is_moving = is_moving_domain(wrfseq, varname, _key=_key) - + file_times = extract_times(wrfseq, ALL_TIMES, meta=False, do_xtime=False) - - multitime = is_multi_time_req(timeidx) - - # For single times, just need to find the ncfile and appropriate + + multitime = is_multi_time_req(timeidx) + + # For single times, just need to find the ncfile and appropriate # time index, and return that array if not multitime: 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) - + if xarray_enabled() and meta: - first_var = _build_data_array(next(wrf_iter), varname, + first_var = _build_data_array(next(wrf_iter), varname, ALL_TIMES, is_moving, True, _key) else: first_var = (next(wrf_iter)).variables[varname][:] - + outdims = [len(file_times)] - + # Making a new time dim, so ignore this one outdims += first_var.shape[1:] - + outdata = np.empty(outdims, first_var.dtype) - + numtimes = first_var.shape[0] startidx = 0 endidx = numtimes - + if first_var.ndim > 1: outdata[startidx:endidx, :] = first_var[:] else: outdata[startidx:endidx] = first_var[:] - + if xarray_enabled() and meta: latname, lonname, timename = _find_coord_names(first_var.coords) - + timecached = False latcached = False loncached = False - + outxtimes = None outlats = None outlons = None - + timekey = timename+"_cat" if timename is not None else None latkey = latname + "_cat" if latname is not None else None lonkey = lonname + "_cat" if lonname is not None else None - + if timename is not None: 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 - + if is_moving: - outcoorddims = outdims[0:1] + outdims[-2:] - + outcoorddims = outdims[0:1] + outdims[-2:] + if latname is not None: # Try to pull from the coord cache 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 - + if lonname is not None: 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: @@ -1685,100 +1696,100 @@ def _cat_files(wrfseq, varname, timeidx, is_moving, squeeze, meta, _key): break else: vardata = wrfnc.variables[varname][:] - + numtimes = vardata.shape[0] - + endidx = startidx + numtimes - + if vardata.ndim > 1: outdata[startidx:endidx, :] = vardata[:] else: outdata[startidx:endidx] = vardata[:] - + if xarray_enabled() and meta: if timename is not None and not timecached: xtimedata = wrfnc.variables[timename][:] outxtimes[startidx:endidx] = xtimedata[:] - + if is_moving: if latname is not None and not latcached: latdata = wrfnc.variables[latname][:] outlats[startidx:endidx, :] = latdata[:] - + if lonname is not None and not loncached: londata = wrfnc.variables[lonname][:] outlons[startidx:endidx, :] = londata[:] - + startidx = endidx - + if xarray_enabled() and meta: - + # Cache the coords if applicable - if not latcached and outlats is not None: + if not latcached and outlats is not None: cache_item(_key, latkey, outlats) if not loncached and outlons is not None: cache_item(_key, lonkey, outlons) if not timecached and outxtimes is not None: cache_item(_key, timekey, outxtimes) - + outname = first_var.name outattrs = OrderedDict(first_var.attrs) outcoords = OrderedDict(first_var.coords) outdimnames = list(first_var.dims) - + if "Time" not in outdimnames: outdimnames.insert(0, "Time") - + if not multitime: file_times = [file_times[timeidx]] - + outcoords[outdimnames[0]] = file_times - + outcoords["datetime"] = outdimnames[0], file_times - + if timename is not None: outxtimes = outxtimes[:] outcoords[timename] = outdimnames[0], outxtimes - + # If the domain is moving, need to create the lat/lon coords # since they can't be copied if is_moving: outlatdims = [outdimnames[0]] + outdimnames[-2:] - + if latname is not None: outlats = outlats[:] outcoords[latname] = outlatdims, outlats if lonname is not None: outlons = outlons[:] outcoords[lonname] = outlatdims, outlons - + outdata = outdata[:] - - outarr = DataArray(outdata, name=outname, coords=outcoords, + + outarr = DataArray(outdata, name=outname, coords=outcoords, dims=outdimnames, attrs=outattrs) - + else: outdata = outdata[:] outarr = outdata - + return outarr def _get_numfiles(wrfseq): """Return the number of files in the sequence. - + This function will first try to call the builtin :meth:`len` function, but if that fails, the entire squence will be iterated over and counted. - + Args: - - wrfseq (iterable): An iterable type, which includes lists, tuples, + + wrfseq (iterable): An iterable type, which includes lists, tuples, dictionaries, generators, and user-defined classes. - + Returns: - + :obj:`int`: The number of files in the sequence. - + """ try: return len(wrfseq) @@ -1790,59 +1801,59 @@ def _get_numfiles(wrfseq): def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key): """Return an array object from a sequence of files using the join method. - - The join method creates a new leftmost dimension for the file/sequence - index. In situations where there are multiple files with multiple times, + + The join method creates a new leftmost dimension for the file/sequence + index. In situations where there are multiple files with multiple times, and the last file contains less times than the previous files, the - remaining arrays will be arrays filled with missing values. There are + remaining arrays will be arrays filled with missing values. There are checks in place within the wrf-python algorithms to look for these missing arrays, but be careful when calling compiled routines outside of wrf-python. - - In general, join is rarely used, so the concatenate method should be used + + In general, join is rarely used, so the concatenate method should be used for most cases. - + Args: - - wrfseq (iterable): An iterable type, which includes lists, tuples, + + wrfseq (iterable): An iterable type, which includes lists, tuples, dictionaries, generators, and user-defined classes. - + varname (:obj:`str`) : The variable name. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - is_moving (:obj:`bool`): A boolean type that indicates if the + + is_moving (:obj:`bool`): A boolean type that indicates if the sequence is a moving nest. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): Cache key for the coordinate variables. + + _key (:obj:`int`, optional): Cache key for the coordinate variables. This is used for internal purposes only. Default is None. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ if is_moving is None: is_moving = is_moving_domain(wrfseq, varname, _key=_key) multitime = is_multi_time_req(timeidx) numfiles = _get_numfiles(wrfseq) maxtimes = _find_max_time_size(wrfseq) - + time_idx_or_slice = timeidx if not multitime else slice(None) file_times_less_than_max = False file_idx = 0 @@ -1851,83 +1862,83 @@ def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key): wrf_iter = iter(wrfseq) wrfnc = next(wrf_iter) numtimes = extract_dim(wrfnc, "Time") - + if xarray_enabled() and meta: - first_var = _build_data_array(wrfnc, varname, ALL_TIMES, is_moving, + first_var = _build_data_array(wrfnc, varname, ALL_TIMES, is_moving, True, _key) - time_coord = np.full((numfiles, maxtimes), np.datetime64("NaT"), + time_coord = np.full((numfiles, maxtimes), np.datetime64("NaT"), "datetime64[ns]") time_coord[file_idx, 0:numtimes] = first_var.coords["Time"][:] else: first_var = wrfnc.variables[varname][:] - + if numtimes < maxtimes: file_times_less_than_max = True - - # Out dimensions will be the number of files, maxtimes, then the + + # Out dimensions will be the number of files, maxtimes, then the # non-time shapes from the first variable outdims = [numfiles] outdims += [maxtimes] outdims += first_var.shape[1:] - + # For join, always need to start with full masked values outdata = np.full(outdims, default_fill(first_var.dtype), first_var.dtype) if first_var.ndim > 1: outdata[file_idx, 0:numtimes, :] = first_var[:] else: outdata[file_idx, 0:numtimes] = first_var[:] - + # Create the secondary coordinate arrays if xarray_enabled() and meta: latname, lonname, timename = _find_coord_names(first_var.coords) outcoorddims = outdims[0:2] + outdims[-2:] - + timecached = False latcached = False loncached = False - + outxtimes = None outlats = None outlons = None - + timekey = timename+"_join" if timename is not None else None latkey = latname + "_join" if latname is not None else None lonkey = lonname + "_join" if lonname is not None else None - + if timename is not None: outxtimes = get_cached_item(_key, timekey) if outxtimes is None: - outxtimes = np.full(outdims[0:2], - default_fill(first_var.dtype), + outxtimes = np.full(outdims[0:2], + default_fill(first_var.dtype), first_var.dtype) outxtimes[file_idx, 0:numtimes] = first_var.coords[timename][:] else: timecached = True - + if is_moving: if latname is not None: outlats = get_cached_item(_key, latkey) if outlats is None: - outlats = np.full(outcoorddims, - default_fill(first_var.dtype), + outlats = np.full(outcoorddims, + default_fill(first_var.dtype), first_var.dtype) outlats[file_idx, 0:numtimes, :] = ( first_var.coords[latname][:]) else: latcached = True - + if lonname is not None: outlons = get_cached_item(_key, lonkey) if outlons is None: - outlons = np.full(outcoorddims, - default_fill(first_var.dtype), + outlons = np.full(outcoorddims, + default_fill(first_var.dtype), first_var.dtype) outlons[file_idx, 0:numtimes, :] = ( first_var.coords[lonname][:]) else: loncached = True - - file_idx=1 + + file_idx = 1 while True: try: wrfnc = next(wrf_iter) @@ -1938,83 +1949,83 @@ def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key): if numtimes < maxtimes: file_times_less_than_max = True outvar = wrfnc.variables[varname][:] - + if not multitime: outvar = outvar[np.newaxis, :] - - if outvar.ndim > 1: + + if outvar.ndim > 1: outdata[file_idx, 0:numtimes, :] = outvar[:] else: outdata[file_idx, 0:numtimes] = outvar[:] - + if xarray_enabled() and meta: # For join, the times are a function of fileidx - file_times = extract_times(wrfnc, ALL_TIMES, meta=False, + 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][:] outxtimes[file_idx, 0:numtimes] = xtimedata[:] - + if is_moving: if latname is not None and not latcached: latdata = wrfnc.variables[latname][:] outlats[file_idx, 0:numtimes, :] = latdata[:] - + if lonname is not None and not loncached: londata = wrfnc.variables[lonname][:] outlons[file_idx, 0:numtimes, :] = londata[:] - + # Need to update coords here file_idx += 1 - + # If any of the output files contain less than the max number of times, - # then a mask array is needed to flag all the missing arrays with + # then a mask array is needed to flag all the missing arrays with # missing values if file_times_less_than_max: outdata = np.ma.masked_values(outdata, default_fill(outdata.dtype)) - + if xarray_enabled() and meta: # Cache the coords if applicable - if not latcached and outlats is not None: + if not latcached and outlats is not None: cache_item(_key, latkey, outlats) if not loncached and outlons is not None: cache_item(_key, lonkey, outlons) if not timecached and outxtimes is not None: cache_item(_key, timekey, outxtimes) - + outname = first_var.name outcoords = OrderedDict(first_var.coords) outattrs = OrderedDict(first_var.attrs) # New dimensions outdimnames = ["file"] + list(first_var.dims) outcoords["file"] = [i for i in py3range(numfiles)] - + # Time needs to be multi dimensional, so use the default dimension del outcoords["Time"] - + time_coord = time_coord[:, time_idx_or_slice] if not multitime: time_coord = time_coord[:, np.newaxis] outcoords["datetime"] = outdimnames[0:2], time_coord - + if isinstance(outdata, np.ma.MaskedArray): outattrs["_FillValue"] = default_fill(outdata.dtype) outattrs["missing_value"] = default_fill(outdata.dtype) - + if timename is not None: outxtimes = outxtimes[:, time_idx_or_slice] if not multitime: outxtimes = outxtimes[:, np.newaxis] outcoords[timename] = outdimnames[0:2], outxtimes[:] - + # If the domain is moving, need to create the lat/lon coords # since they can't be copied if is_moving: outlatdims = outdimnames[0:2] + outdimnames[-2:] - + if latname is not None: outlats = outlats[:, time_idx_or_slice, :] if not multitime: @@ -2025,159 +2036,159 @@ def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key): if not multitime: outlons = outlons[:, np.newaxis, :] outcoords[lonname] = outlatdims, outlons - + if not multitime: outdata = outdata[:, timeidx, :] outdata = outdata[:, np.newaxis, :] - - outarr = DataArray(outdata, name=outname, coords=outcoords, + + outarr = DataArray(outdata, name=outname, coords=outcoords, dims=outdimnames, attrs=outattrs) - + else: if not multitime: outdata = outdata[:, timeidx, :] outdata = outdata[:, np.newaxis, :] - + outarr = outdata - + return outarr def combine_files(wrfin, varname, timeidx, is_moving=None, - method="cat", squeeze=True, meta=True, + method="cat", squeeze=True, meta=True, _key=None): - """Combine and return an array object for the sequence of WRF output + """Combine and return an array object for the sequence of WRF output files. - + Two aggregation methodologies are available to combine the sequence: - - - 'cat': Concatenate the files along the 'Time' dimension. The Time - dimension will be the leftmost dimension. No sorting is performed, - so files must be properly ordered in the sequence prior to calling + + - 'cat': Concatenate the files along the 'Time' dimension. The Time + dimension will be the leftmost dimension. No sorting is performed, + so files must be properly ordered in the sequence prior to calling this function. - - - 'join': Join the files by creating a new leftmost dimension for the - file index. In situations where there are multiple files with - multiple times, and the last file contains less times than the - previous files, the remaining arrays will be arrays filled with - missing values. There are checks in place within the wrf-python - algorithms to look for these missing arrays, but be careful when + + - 'join': Join the files by creating a new leftmost dimension for the + file index. In situations where there are multiple files with + multiple times, and the last file contains less times than the + previous files, the remaining arrays will be arrays filled with + missing values. There are checks in place within the wrf-python + algorithms to look for these missing arrays, but be careful when calling compiled routines outside of wrf-python. - - + + Args: - - wrfin (iterable): An iterable type, which includes lists, tuples, + + wrfin (iterable): An iterable type, which includes lists, tuples, dictionaries, generators, and user-defined classes. - + varname (:obj:`str`) : The variable name. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - is_moving (:obj:`bool`): A boolean type that indicates if the + + is_moving (:obj:`bool`): A boolean type that indicates if the sequence is a moving nest. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): Cache key for the coordinate variables. + + _key (:obj:`int`, optional): Cache key for the coordinate variables. This is used for internal purposes only. Default is None. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ - + # Handles generators, single files, lists, tuples, custom classes wrfseq = get_iterable(wrfin) - + # Dictionary is unique if is_mapping(wrfseq): outarr = _combine_dict(wrfseq, varname, timeidx, method, meta, _key) elif method.lower() == "cat": - outarr = _cat_files(wrfseq, varname, timeidx, is_moving, + outarr = _cat_files(wrfseq, varname, timeidx, is_moving, squeeze, meta, _key) elif method.lower() == "join": outarr = _join_files(wrfseq, varname, timeidx, is_moving, meta, _key) else: raise ValueError("method must be 'cat' or 'join'") - + return outarr.squeeze() if squeeze else outarr -def _extract_var(wrfin, varname, timeidx, is_moving, +def _extract_var(wrfin, varname, timeidx, is_moving, method, squeeze, cache, meta, _key): """Extract a variable from a NetCDF file object or a sequence of NetCDF file objects. - + Args: - - wrfin (iterable): An iterable type, which includes lists, tuples, + + wrfin (iterable): An iterable type, which includes lists, tuples, dictionaries, generators, and user-defined classes. - + varname (:obj:`str`) : The variable name. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - is_moving (:obj:`bool`): A boolean type that indicates if the + + is_moving (:obj:`bool`): A boolean type that indicates if the sequence is a moving nest. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): Cache key for the coordinate variables. + + _key (:obj:`int`, optional): Cache key for the coordinate variables. This is used for internal purposes only. Default is None. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is - enabled and the *meta* parameter is True, then the result will be a - :class:`xarray.DataArray` object. Otherwise, the result will be a + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: If xarray is + enabled and the *meta* parameter is True, then the result will be a + :class:`xarray.DataArray` object. Otherwise, the result will be a :class:`numpy.ndarray` object with no metadata. - + """ if cache is not None: @@ -2188,16 +2199,16 @@ def _extract_var(wrfin, varname, timeidx, is_moving, else: if not meta: return to_np(cache_var) - + return cache_var - + multitime = is_multi_time_req(timeidx) multifile = is_multi_file(wrfin) - + if is_time_coord_var(varname): - return extract_times(wrfin, timeidx, method, squeeze, cache, + return extract_times(wrfin, timeidx, method, squeeze, cache, meta, do_xtime=True) - + if not multifile: if xarray_enabled() and meta: if is_moving is None: @@ -2206,334 +2217,332 @@ 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: # Squeeze handled in this routine, so just return it - return combine_files(wrfin, varname, timeidx, is_moving, + return combine_files(wrfin, varname, timeidx, is_moving, method, squeeze, meta, _key) - + return result.squeeze() if squeeze else result -def extract_vars(wrfin, timeidx, varnames, method="cat", squeeze=True, +def extract_vars(wrfin, timeidx, varnames, method="cat", squeeze=True, cache=None, meta=True, _key=None): """Extract variables from a NetCDF file object or a sequence of NetCDF file objects. - + Args: - - wrfin (iterable): An iterable type, which includes lists, tuples, + + wrfin (iterable): An iterable type, which includes lists, tuples, dictionaries, generators, and user-defined classes. - + varnames (sequence of :obj:`str`) : A sequence of variable names. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. The default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - meta (:obj:`bool`, optional): Set to False to disable metadata and - return :class:`numpy.ndarray` instead of + + meta (:obj:`bool`, optional): Set to False to disable metadata and + return :class:`numpy.ndarray` instead of :class:`xarray.DataArray`. Default is True. - - _key (:obj:`int`, optional): Cache key for the coordinate variables. + + _key (:obj:`int`, optional): Cache key for the coordinate variables. This is used for internal purposes only. Default is None. - + Returns: - - :obj:`dict`: A mapping of variable name to an array object. If xarray - is enabled and the *meta* parameter is True, then the array object will - be a :class:`xarray.DataArray` object. Otherwise, the array object + + :obj:`dict`: A mapping of variable name to an array object. If xarray + is enabled and the *meta* parameter is True, then the array object will + be a :class:`xarray.DataArray` object. Otherwise, the array object will be a :class:`numpy.ndarray` object with no metadata. - + """ if isstr(varnames): varlist = [varnames] 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} def npbytes_to_str(var): """Return a :obj:`bytes` object for the raw character array. - + Args: - + var (:class:`numpy.ndarray`): An array of characters. - + Returns: - + :obj:`bytes`: A string of bytes. - + """ return (bytes(c).decode("utf-8") for c in var[:]) def _make_time(timearr): """Return a :class:`datetime.datetime` object for the array of characters. - + Args: - + timearr (:class:`numpy.ndarray`): An array of characters. - + Returns: - + :class:`datetime.datetime`: A datetime object. - + """ try: - return dt.datetime.strptime("".join(npbytes_to_str(timearr)), - "%Y-%m-%d_%H:%M:%S") + return dt.datetime.strptime("".join(npbytes_to_str(timearr)), + "%Y-%m-%d_%H:%M:%S") except ValueError: return np.datetime64("NaT") def _file_times(wrfin, do_xtime): """Yield a time object for the times found in a sequence of files. - - If *do_xtime* to True, a :class:`datetime.datetime` object is yielded. + + If *do_xtime* to True, a :class:`datetime.datetime` object is yielded. Otherwise, a :obj:`float` object is yielded. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - do_xtime (:obj:`bool`): Set to True to parse the 'XTIME' variable + + do_xtime (:obj:`bool`): Set to True to parse the 'XTIME' variable instead of the 'Times' variable. - + Yields: - - :class:`datetime.datetime` or :obj:`float`: A - :class:`datetime.datetime` object if *do_xtime* is False, + + :class:`datetime.datetime` or :obj:`float`: A + :class:`datetime.datetime` object if *do_xtime* is False, otherwise a :obj:`float`. - + """ 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]): yield xtimes[i] - + def _extract_time_map(wrfin, timeidx, do_xtime, meta=False): """Return a mapping of key to a sequence of time objects. - + This function is used when *wrfin* is a mapping. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. - - do_xtime (:obj:`bool`): Set to True to parse the 'XTIME' variable + + do_xtime (:obj:`bool`): Set to True to parse the 'XTIME' variable instead of the 'Times' variable. - + meta (:obj:`bool`, optional): Set to False to disable metadata. - + Returns: - - :obj:`dict`: A mapping of key to a sequence of time objects. If + + :obj:`dict`: A mapping of key to a sequence of time objects. If *meta* is True, the sequence will be of type :class:`xarray.DataArray`, 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)} - -def extract_times(wrfin, timeidx, method="cat", squeeze=True, cache=None, + +def extract_times(wrfin, timeidx, method="cat", squeeze=True, cache=None, meta=False, do_xtime=False): - + """Return a sequence of time objects. - - If *do_xtime* is False, the 'XTIME' variable is used and each time object - is a :obj:`float`. Otherwise, the 'Times' variable is used, and each - time object is a :class:`datetime.datetime` object. - + + If *do_xtime* is False, the 'XTIME' variable is used and each time object + is a :obj:`float`. Otherwise, the 'Times' variable is used, and each + time object is a :class:`datetime.datetime` object. + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - + meta (:obj:`bool`, optional): Set to False to disable metadata. - - do_xtime (:obj:`bool`): Set to True to parse the 'XTIME' variable + + do_xtime (:obj:`bool`): Set to True to parse the 'XTIME' variable instead of the 'Times' variable. Default is False. - + Returns: - - :class:`xarray.DataArray` or :class:`numpy.ndarray`: A sequence of time - objects. If *meta* is True, the sequence will be of type - :class:`xarray.DataArray`, otherwise the sequence is + + :class:`xarray.DataArray` or :class:`numpy.ndarray`: A sequence of time + objects. If *meta* is True, the sequence will be of type + :class:`xarray.DataArray`, otherwise the sequence is :class:`numpy.ndarray`. - + """ if is_mapping(wrfin): return _extract_time_map(wrfin, timeidx, do_xtime) - + multitime = is_multi_time_req(timeidx) multi_file = is_multi_file(wrfin) if not multi_file: wrf_list = [wrfin] else: wrf_list = wrfin - + dt = "datetime64[ns]" if not do_xtime else np.float64 - fill_value = (np.datetime64('NaT') if not do_xtime else + fill_value = (np.datetime64('NaT') if not do_xtime else default_fill(np.float64)) - + try: if method.lower() == "cat": - time_list = [file_time - for wrf_file in wrf_list + time_list = [file_time + for wrf_file in wrf_list for file_time in _file_times(wrf_file, do_xtime)] time_arr = np.asarray(time_list, dtype=dt) - + elif method.lower() == "join": - time_list = [[file_time + time_list = [[file_time for file_time in _file_times(wrf_file, do_xtime)] for wrf_file in wrf_list] - + num_rows = len(time_list) 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() outcoords = None - + if method.lower() == "cat": outdimnames = ["Time"] else: outdimnames = ["fileidx", "Time"] outattrs["missing_value"] = fill_value outattrs["_FillValue"] = fill_value - + if not do_xtime: outname = "times" outattrs["description"] = "model times [np.datetime64]" - + else: ncfile = next(iter(wrf_list)) var = ncfile.variables["XTIME"] outattrs.update(var.__dict__) - + outname = "XTIME" - - - outarr = DataArray(time_arr, name=outname, coords=outcoords, + + outarr = DataArray(time_arr, name=outname, coords=outcoords, dims=outdimnames, attrs=outattrs) - else: outarr = time_arr - + if not multitime: return outarr[timeidx] - + return outarr - - + + def is_standard_wrf_var(wrfin, varname): - """Return True if the variable is a standard WRF variable and not a + """Return True if the variable is a standard WRF variable and not a diagnostic. - + If *wrfin* is a sequence, only the first file is used. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - + varname (:obj:`str`): The variable name. - + Returns: - + :obj:`bool`: True if the variable is a standard WRF variable, otherwise False. - + """ multifile = is_multi_file(wrfin) if multifile: @@ -2542,272 +2551,273 @@ def is_standard_wrf_var(wrfin, varname): else: entry = wrfin[next(iter(viewkeys(wrfin)))] return is_standard_wrf_var(entry, varname) - + return varname in wrfin.variables def is_staggered(wrfin, var): """Return True if the variable is on a staggered grid. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - var (array): An array object which contains a :attr:`shape` + + var (array): An array object which contains a :attr:`shape` attribute. - + Returns: - - :obj:`bool`: True if the variable is on a staggered grid, otherwise + + :obj:`bool`: True if the variable is on a staggered grid, otherwise False. - + """ - + we = extract_dim(wrfin, "west_east") sn = extract_dim(wrfin, "south_north") bt = extract_dim(wrfin, "bottom_top") - + if (var.shape[-1] != we or var.shape[-2] != sn or var.shape[-3] != bt): return True - + return False def get_left_indexes(var, expected_dims): """Returns a tuple for the extra leftmost dimension sizes. - - For example, if an algorithm expects a 3 dimensional variable, but the - variable includes an additional left dimension for Time, and + + For example, if an algorithm expects a 3 dimensional variable, but the + variable includes an additional left dimension for Time, and this Time dimension has 3 values, then this function will return (3,). - + Args: - - var (array): An array object that contains the :attr:`ndim` + + var (array): An array object that contains the :attr:`ndim` and :attr:`shape` attributes. - + expected_dims (:obj:`int`): The expected number of dimensions (usually for a computational algorithm). - + Returns: - + :obj:`tuple`: The shape for the extra leftmost dimensions. - + """ extra_dim_num = var.ndim - expected_dims - + if (extra_dim_num == 0): return [] - - return var.shape[0:extra_dim_num] + + return var.shape[0:extra_dim_num] def iter_left_indexes(dims): """Yield the iteration tuples for a sequence of dimensions sizes. - + For example, if *dims* is (2,2), then this will yield: - + (0,0), (0,1), (1,0), (1,1) - + This is primarily used to iterate over the leftmost index values. - + Args: - + dims (indexable sequence): A sequence of dimension sizes. - + Yields: - + :obj:`tuple`: The leftmost indexing iteration sizes. - + """ arg = [py3range(dim) for dim in dims] for idxs in product(*arg): yield idxs - - + + def get_right_slices(var, right_ndims, fixed_val=0): - """Return an indexing tuple where the left dimensions are held to a + """Return an indexing tuple where the left dimensions are held to a fixed value and the right dimensions are set to slice objects. - - For example, if *var* is a 5D variable, and the desired indexing sequence - for a numpy array is (0,0,0,:,:), then *right_ndims* should be set to 2 + + For example, if *var* is a 5D variable, and the desired indexing sequence + for a numpy array is (0,0,0,:,:), then *right_ndims* should be set to 2 and *fixed_val* set to 0. - + Args: - + var (:class:`numpy.ndarray`): A numpy array. - + right_ndims (:obj:`int`): The number of right dimensions to be sliced. - + fixed_val (:obj:`int`): The value to hold the left dimensions to. - + Returns: - - :obj:`tuple`: An indexing tuple that can be used to index a + + :obj:`tuple`: An indexing tuple that can be used to index a :class:`numpy.ndarray`. - + """ extra_dim_num = var.ndim - right_ndims if extra_dim_num == 0: return [slice(None)] * right_ndims - - return tuple([fixed_val]*extra_dim_num + + + return tuple([fixed_val]*extra_dim_num + [slice(None)]*right_ndims) -def get_proj_params(wrfin):#, timeidx=0, varname=None): - """Return a tuple of latitude, longitude, and projection parameters from +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. - + Args: - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` or an iterable sequence of the aforementioned types. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. Default is 0. - - varname (:obj:`str`, optional): The variable name to extract the - coordinate variable names from. Default is None, which will + + varname (:obj:`str`, optional): The variable name to extract the + coordinate variable names from. Default is None, which will use the default coordinate variable names ('XLAT', 'XLONG'). - + Returns: - - :obj:`tuple`: A tuple of the latitude coordinate variable, - 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")) - + + :obj:`tuple`: A tuple of the latitude coordinate variable, + 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")) + return proj_params - + 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 \ - desired argument value. If the argument has not been passed in, the value + + 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. - + This func is usually called from within a decorator. - + Note: - - This function currently does not work with functions that contain - \*args or \*\*kwargs arguments. - + + This function currently does not work with functions that contain + variable length args or kwargs arguments. + Args: - - func (function): The function to examine (usually the function that is + + func (function): The function to examine (usually the function that is wrapped). - + argnames (iterable): An iterable sequence of argument names. - + *args: The positional arguments. - + **kwargs: The keyword arguments. - + Returns: - + :obj:`dict`: A mapping of argument name to argument value. - + """ if isstr(argnames): arglist = [argnames] else: arglist = argnames - + result = OrderedDict() for argname in arglist: arg_loc = arg_location(func, argname, args, kwargs) - + if arg_loc is not None: - result[argname] = arg_loc[0][arg_loc[1]] + result[argname] = arg_loc[0][arg_loc[1]] else: result[argname] = None - + return result def _args_to_list2(func, args, kwargs): """Return all of the function arguments, including defaults, as a list. - - The result can then be passed to the function via *result. This version + + The result can then be passed to the function via *result. This version uses :meth:`inspect.argspec`, so is only applicable for Python 2.7. - + Note: - - This function currently does not work with functions that contain - *args or **kwargs arguments. - + + This function currently does not work with functions that contain + variable length args or kwargs arguments. + Args: - - func (function): The function to examine (usually the function + + func (function): The function to examine (usually the function that is wrapped). - + args (:obj:`tuple`): The positional arguments. - + kwargs (:obj:`dict`): The keyword arguments. - + Returns: - + :obj:`list`: A list of all argument values, including defaults. - + """ - argspec = getargspec(func) - + argspec = getargspec(func) + # 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): + + # Fill in the supplied kargs + for argname, val in viewitems(kwargs): argidx = argspec.args.index(argname) outargs[argidx] = val - + return outargs -# For Python 3.4, this will run the BoundArguments.apply_defaults method that +# For Python 3.4, this will run the BoundArguments.apply_defaults method that # was introduced in Python 3.5. def _apply_defaults(bound): """Set default values for missing arguments. - + For variable-positional arguments (*args) the default is an empty tuple. - + For variable-keyword arguments (**kwargs) the default is an empty dict. - + Args: - + bound (:class:`inspect.BoundArguments`): A BoundArguments object. - + Returns: - + None - + """ arguments = bound.arguments - + new_arguments = [] for name, param in bound._signature.parameters.items(): try: @@ -2824,34 +2834,34 @@ def _apply_defaults(bound): # Signature.bind_partial(). continue new_arguments.append((name, val)) - + bound.arguments = OrderedDict(new_arguments) - - + + def _args_to_list3(func, args, kwargs): """Return all of the function arguments, including defaults, as a list. - - The result can then be passed to the function via *result. This version + + The result can then be passed to the function via *result. This version uses :meth:`inspect.signature`, so is only applicable for Python 3.4+. - + Note: - - This function currently does not work with functions that contain - *args or **kwargs arguments. - + + This function currently does not work with functions that contain + variable length args or kwargs arguments. + Args: - - func (function): The function to examine (usually the function + + func (function): The function to examine (usually the function that is wrapped). - + args (:obj:`tuple`): The positional arguments. - + kwargs (:obj:`dict`): The keyword arguments. - + Returns: - + :obj:`list`: A list of all argument values, including defaults. - + """ sig = signature(func) bound = sig.bind(*args, **kwargs) @@ -2859,180 +2869,194 @@ def _args_to_list3(func, args, kwargs): bound.apply_defaults() except AttributeError: _apply_defaults(bound) - + return [x for x in bound.arguments.values()] - - + + # Note: Doesn't allow for **kwargs or *args def args_to_list(func, args, kwargs): """Return all of the function arguments, including defaults, as a list. - + The result can then be passed to the function via *result*. - + Note: - - This function currently does not work with functions that contain - \*args or \*\*kwargs arguments. - + + This function currently does not work with functions that contain + variable length args or kwargs arguments. + Args: - - func (function): The function to examine (usually the function + + func (function): The function to examine (usually the function that is wrapped). - + args (:obj:`tuple`): The positional arguments. - + kwargs (:obj:`dict`): The keyword arguments. - + Returns: - + :obj:`list`: A list of all argument values, including defaults. - + """ if version_info > (3,): _args_to_list = _args_to_list3 else: _args_to_list = _args_to_list2 - + return _args_to_list(func, args, kwargs) - + def _arg_location2(func, argname, args, kwargs): - """Return the function arguments as a single list along with the + """Return the function arguments as a single list along with the index within that list for a specified argument name. - - This function parses the args, kargs and signature looking for the - location of *argname*, and returns a list containing all arguments, along + + This function parses the args, kargs and signature looking for the + location of *argname*, and returns a list containing all arguments, along with the argument location in that list. - - This function requires :meth:`inspect.getargspec`, so it is only + + This function requires :meth:`inspect.getargspec`, so it is only applicable for Python 2.7. - + Args: - - func (function): The function to examine (usually the function + + func (function): The function to examine (usually the function that is wrapped). - + argname (:obj:`str`): The argument name to locate. - + args (:obj:`tuple`): The positional arguments. - + kwargs (:obj:`dict`): The keyword arguments. - + Returns: - + :obj:`tuple`: A tuple containing the list of all argument values along with the index for location of *argname*. - + """ argspec = getargspec(func) - + list_args = _args_to_list2(func, args, kwargs) - + # Return the new sequence and location if argname not in argspec.args and argname not in kwargs: return None - + result_idx = argspec.args.index(argname) - + return list_args, result_idx def _arg_location3(func, argname, args, kwargs): - """Return the function arguments as a single list along with the + """Return the function arguments as a single list along with the index within that list for a specified argument name. - - This function parses the args, kargs and signature looking for the - location of *argname*, and returns a list containing all arguments, along + + This function parses the args, kargs and signature looking for the + location of *argname*, and returns a list containing all arguments, along with the argument location in that list. - - This function requires :meth:`inspect.signature`, so it is only + + This function requires :meth:`inspect.signature`, so it is only applicable for Python 3.4 and higher. - + Args: - - func (function): The function to examine (usually the function + + func (function): The function to examine (usually the function that is wrapped). - + argname (:obj:`str`): The argument name to locate. - + args (:obj:`tuple`): The positional arguments. - + kwargs (:obj:`dict`): The keyword arguments. - + Returns: - + :obj:`tuple`: A tuple containing the list of all argument values along with the index for location of *argname*. - + """ sig = signature(func) params = list(sig.parameters.keys()) - + list_args = _args_to_list3(func, args, kwargs) - + try: - result_idx = params.index(argname) + result_idx = params.index(argname) except ValueError: return None - + return list_args, result_idx - - + + def arg_location(func, argname, args, kwargs): - """Return the function arguments as a single list along with the + """Return the function arguments as a single list along with the index within that list for a specified argument name. - - This function parses the args, kargs and signature looking for the - location of *argname*, and returns a list containing all arguments, along + + This function parses the args, kargs and signature looking for the + location of *argname*, and returns a list containing all arguments, along with the argument location in that list. - + Args: - - func (function): The function to examine (usually the function + + func (function): The function to examine (usually the function that is wrapped). - + argname (:obj:`str`): The argument name to locate. - + args (:obj:`tuple`): The positional arguments. - + kwargs (:obj:`dict`): The keyword arguments. - + Returns: - + :obj:`tuple`: A tuple containing the list of all argument values along with the index for location of *argname*. - + """ if version_info > (3,): _arg_location = _arg_location3 else: _arg_location = _arg_location2 - + return _arg_location(func, argname, args, kwargs) def psafilepath(): """Return the full path to the 'psadilookup.dat' file. - - The 'psadilookup.dat' file contains the lookup table for the cape + + The 'psadilookup.dat' file contains the lookup table for the cape routines. - + Returns: - + :obj:`str`: The full path to the 'psadilookup.dat' file. - + """ return os.path.join(os.path.dirname(__file__), "data", "psadilookup.dat") 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) @@ -3040,122 +3064,123 @@ def get_filepath(obj): path = "wrfout_{}".format(str(t)) found = True break - - if not found: + + if not found: raise ValueError("file contains no path information") - + return path + def get_id(obj, prefix=''): """Return the cache id. - + The cache id is used as a caching key for various routines. If the - object type is a mapping, then the result will also be a + object type is a mapping, then the result will also be a mapping of each key to the object id for the value. - + Args: - + obj (:obj:`object`): Any object type. - + prefix (:obj:`str`): A string to help with recursive calls. - + Returns: - - :obj:`int` or :obj:`dict`: If the *obj* parameter is not a mapping, - then the object id is returned. Otherwise, a mapping of each + + :obj:`int` or :obj:`dict`: If the *obj* parameter is not a mapping, + then the object id is returned. Otherwise, a mapping of each key to the object id for the value is returned. - + """ if not is_multi_file(obj): return hash(prefix + get_filepath(obj)) - - # For sequences, the hashing string will be the list ID and the + + # For sequences, the hashing string will be the list ID and the # path for the first file in the sequence if not is_mapping(obj): _obj = get_iterable(obj) _next = next(iter(_obj)) return get_id(_next, prefix + str(id(obj))) - + # 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 - must contain latitude and longitude coordinates. If these coordinate - dimensions are greater than two dimensions, then an array of - :class:`wrf.GeoBounds` objects will be returned with the same shape as the + must contain latitude and longitude coordinates. If these coordinate + dimensions are greater than two dimensions, then an array of + :class:`wrf.GeoBounds` objects will be returned with the same shape as the leftmost dimensions of the coordinate arrays. - - When using a WRF file, or sequence of WRF files, by supplying the - *wrfin* parameter, an array of :class:`wrf.GeoBounds` objects will be - returned if the domain is moving and :data:`wrf.ALL_TIMES` is selected as - the *timeidx* parameter when using *wrfin*. Otherwise, a single + + When using a WRF file, or sequence of WRF files, by supplying the + *wrfin* parameter, an array of :class:`wrf.GeoBounds` objects will be + returned if the domain is moving and :data:`wrf.ALL_TIMES` is selected as + the *timeidx* parameter when using *wrfin*. Otherwise, a single :class:`wrf.GeoBounds` object is returned. - + Args: - - var (:class:`xarray.DataArray`, optional): A :class:`xarray.DataArray` + + var (:class:`xarray.DataArray`, optional): A :class:`xarray.DataArray` variable that includes latitude,longitude coordinate information. If not used, then *wrfin* must be provided. - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable, optional): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` - or an iterable sequence of the aforementioned types. If not used, + iterable, optional): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + or an iterable sequence of the aforementioned types. If not used, then *var* must be provided. - + varname (:obj:`str`, optional): If using *wrfin*, then this will be the - variable name to use to determine the geobounds. The variable - can be a coordinate variable, or a regular variable that contains - coordinate attributes. If None, - then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables + variable name to use to determine the geobounds. The variable + can be a coordinate variable, or a regular variable that contains + coordinate attributes. If None, + then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables will be used. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index when *wrfin* is not None. This value can be a - positive integer, negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return - all times in the file or sequence. Default is 0. This value is + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index when *wrfin* is not None. This value can be a + positive integer, negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return + all times in the file or sequence. Default is 0. This value is ignored when *var* is used. - - method (:obj:`str`, optional): The aggregation method to use for - sequences when *wrfin* is not None. Must be either 'cat' or - 'join'. 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences when *wrfin* is not None. Must be either 'cat' or + 'join'. 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Only used when *wrfin* is used. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using large sequences of files. Only used when *wrfin* is used. Default is None. - + Returns: - + :class:`wrf.GeoBounds`: The domain geographic bounds. - + """ - + if var is None and wrfin is None: raise ValueError("'var' or 'wrfin' parameter is required") - + # Getting lat/lon from xarray coordinates if var is not None: if not xarray_enabled(): raise ValueError("xarray is not installed or is disabled") - + is_moving = None try: var_coords = var.coords @@ -3174,17 +3199,17 @@ def geo_bounds(var=None, wrfin=None, varname=None, timeidx=0, method="cat", except KeyError: raise ValueError("'var' object does not contain a longitude " "coordinate") - + # Getting lat/lon from the file elif wrfin is not None: _key = get_id(wrfin) - is_moving = is_moving_domain(wrfin, varname=varname, - latvar=either("XLAT", "XLAT_M"), - lonvar=either("XLONG", "XLONG_M"), + is_moving = is_moving_domain(wrfin, varname=varname, + latvar=either("XLAT", "XLAT_M"), + lonvar=either("XLONG", "XLONG_M"), _key=_key) if varname is not None: if xarray_enabled(): - var = extract_vars(wrfin, timeidx, varname, method, squeeze, + var = extract_vars(wrfin, timeidx, varname, method, squeeze, cache, meta=True, _key=_key)[varname] return geo_bounds(var) else: @@ -3192,94 +3217,95 @@ def geo_bounds(var=None, wrfin=None, varname=None, timeidx=0, method="cat", else: lat_coord = either("XLAT", "XLAT_M")(wrfin) lon_coord = either("XLONG", "XLONG_M")(wrfin) - - # If requesting all times but the domain isn't moving, just + + # If requesting all times but the domain isn't moving, just # extract one time _timeidx = timeidx if timeidx is None and not is_moving: _timeidx = 0 - - coord_data = extract_vars(wrfin, _timeidx, (lat_coord, lon_coord), - method, squeeze, cache, meta=False, + + coord_data = extract_vars(wrfin, _timeidx, (lat_coord, lon_coord), + method, squeeze, cache, meta=False, _key=_key) lats = coord_data[lat_coord] lons = coord_data[lon_coord] - + # Moving domains if lats.ndim > 2: # Requesting all times, works for 'cat' and 'join' data # and always for xarray data extra_dims = lats.shape[0:-2] out_geo = np.full(extra_dims, NullGeoBounds(), np.object) - + for left_idxs in iter_left_indexes(extra_dims): latlon_idx = left_idxs + (slice(None),) out_geo[left_idxs] = GeoBounds(lats=lats[latlon_idx], lons=lons[latlon_idx]) return out_geo - + # Non-moving domains - return GeoBounds(lats=lats, lons=lons) + return GeoBounds(lats=lats, lons=lons) + -def _get_wrf_proj_geobnds(var, wrfin, varname, timeidx, method, squeeze, +def _get_wrf_proj_geobnds(var, wrfin, varname, timeidx, method, squeeze, cache): """Return the :class:`wrf.WrfProj` subclass and :class:`wrf.GeoBounds`. - + Args: - - var (:class:`xarray.DataArray`): A :class:`xarray.DataArray` + + var (:class:`xarray.DataArray`): A :class:`xarray.DataArray` variable that includes latitude,longitude coordinate information. If not used, then *wrfin* must be provided. - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` - or an iterable sequence of the aforementioned types. If not used, + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + or an iterable sequence of the aforementioned types. If not used, then *var* must be provided. - + varname (:obj:`str`): If using *wrfin*, then this will be the - variable name to use to determine the geobounds. The variable - can be a coordinate variable, or a regular variable that contains - coordinate attributes. If None, - then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables + variable name to use to determine the geobounds. The variable + can be a coordinate variable, or a regular variable that contains + coordinate attributes. If None, + then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables will be used. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. Default is 0. - - method (:obj:`str`): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - + Returns: - - :obj:`tuple`: A tuple of :class:`wrf.WrfProj` + + :obj:`tuple`: A tuple of :class:`wrf.WrfProj` and :class:`wrf.GeoBounds` - + """ # Using a variable if var is not None: if not xarray_enabled(): raise ValueError("xarray is not installed or is disabled") - + geobnds = geo_bounds(var) try: wrf_proj = var.attrs["projection"] @@ -3288,123 +3314,123 @@ 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) - + return wrf_proj, geobnds -def _get_proj_obj(ob_type, var, wrfin, varname, timeidx, method, squeeze, +def _get_proj_obj(ob_type, var, wrfin, varname, timeidx, method, squeeze, cache, **kwargs): """Return the desired mapping object for the plotting type. - + Args: - + ob_type (:obj:`str`): Must be 'cartopy', 'basemap', or 'pyngl'. - - var (:class:`xarray.DataArray`): A :class:`xarray.DataArray` + + var (:class:`xarray.DataArray`): A :class:`xarray.DataArray` variable that includes latitude,longitude coordinate information. If not used, then *wrfin* must be provided. - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` - or an iterable sequence of the aforementioned types. If not used, + iterable): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + or an iterable sequence of the aforementioned types. If not used, then *var* must be provided. - + varname (:obj:`str`): If using *wrfin*, then this will be the - variable name to use to determine the geobounds. The variable - can be a coordinate variable, or a regular variable that contains - coordinate attributes. If None, - then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables + variable name to use to determine the geobounds. The variable + can be a coordinate variable, or a regular variable that contains + coordinate attributes. If None, + then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables will be used. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. Default is 0. - - method (:obj:`str`): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - + **kwargs: Additional keyword arguments for the plotting type. - + Returns: - - mapping object: Will be either :class:`cartopy.crs.Projection`, - :class:`matplotlib.mpl_toolkits.basemap.Basemap` or + + mapping object: Will be either :class:`cartopy.crs.Projection`, + :class:`matplotlib.mpl_toolkits.basemap.Basemap` or :class:`Ngl.Resources`. - + """ - - wrf_proj, geobnds = _get_wrf_proj_geobnds(var, wrfin, varname, timeidx, + + wrf_proj, geobnds = _get_wrf_proj_geobnds(var, wrfin, varname, timeidx, method, squeeze, cache) - + if ob_type == "cartopy": proj_obj = wrf_proj.cartopy() 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: + else: proj_obj = np.empty(geobnds.shape, np.object) - + for idxs, geobnd_val in np.ndenumerate(geobnds): proj_obj[idxs] = wrf_proj.basemap(geobnd_val, **kwargs) 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: + else: proj_obj = np.empty(geobnds.shape, np.object) - + for idxs, geobnd_val in np.ndenumerate(geobnds): proj_obj[idxs] = wrf_proj.pyngl(geobnd_val, **kwargs) - + return proj_obj def latlon_coords(var, as_np=False): - """Return the latitude and longitude coordinates from a + """Return the latitude and longitude coordinates from a :class:`xarray.DataArray` object. - + Args: - + var (:class:`xarray.DataArray`): A variable. - - as_np (:obj:`bool`): Set to True to return the coordinates as - :class:`numpy.ndarray` objects instead of + + as_np (:obj:`bool`): Set to True to return the coordinates as + :class:`numpy.ndarray` objects instead of :class:`xarray.DataArray` objects. - + Returns: - + :obj:`tuple`: The latitude and longitude coordinate variables. - + """ - + if not xarray_enabled(): raise ValueError("xarray is not installed or is disabled") - + try: var_coords = var.coords except AttributeError: @@ -3422,395 +3448,397 @@ def latlon_coords(var, as_np=False): except KeyError: raise ValueError("'var' object does not contain a longitude " "coordinate") - + if as_np: return to_np(lats), to_np(lons) - + return lats, lons - - + + def get_cartopy(var=None, wrfin=None, varname=None, timeidx=0, method="cat", - squeeze=True, cache=None): - """Return a :class:`cartopy.crs.Projection` subclass for the + squeeze=True, cache=None): + """Return a :class:`cartopy.crs.Projection` subclass for the map projection. - + Args: - - var (:class:`xarray.DataArray`, optional): A :class:`xarray.DataArray` + + var (:class:`xarray.DataArray`, optional): A :class:`xarray.DataArray` variable that includes latitude,longitude coordinate information. If not used, then *wrfin* must be provided. - - geobounds (:class:`wrf.GeoBounds`, optional): The geobounds to + + geobounds (:class:`wrf.GeoBounds`, optional): The geobounds to get the extents. If set to None and using the *var* parameter, - the geobounds will be taken from the variable. If using a + the geobounds will be taken from the variable. If using a file, then the geobounds will be taken from the native grid. - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable, optional): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` - or an iterable sequence of the aforementioned types. If not used, + iterable, optional): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + or an iterable sequence of the aforementioned types. If not used, then *var* must be provided. - + varname (:obj:`str`, optional): If using *wrfin*, then this will be the - variable name to use to determine the geobounds. The variable - can be a coordinate variable, or a regular variable that contains - coordinate attributes. If None, - then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables + variable name to use to determine the geobounds. The variable + can be a coordinate variable, or a regular variable that contains + coordinate attributes. If None, + then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables will be used. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. Default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - + Returns: - - :class:`cartopy.crs.Projection`: A Projection subclass for the + + :class:`cartopy.crs.Projection`: A Projection subclass for the map projection. - + See Also: - + :class:`cartopy.crs.Projection` - + """ - return _get_proj_obj("cartopy", var, wrfin, varname, timeidx, method, + return _get_proj_obj("cartopy", var, wrfin, varname, timeidx, method, squeeze, cache) - + def get_basemap(var=None, wrfin=None, varname=None, timeidx=0, method="cat", - squeeze=True, cache=None, **kwargs): - """Return a :class:`matplotlib.mpl_toolkits.basemap.Basemap` object + squeeze=True, cache=None, **kwargs): + """Return a :class:`matplotlib.mpl_toolkits.basemap.Basemap` object for the map projection. - + Args: - - var (:class:`xarray.DataArray`, optional): A :class:`xarray.DataArray` + + var (:class:`xarray.DataArray`, optional): A :class:`xarray.DataArray` variable that includes latitude,longitude coordinate information. If not used, then *wrfin* must be provided. - - geobounds (:class:`wrf.GeoBounds`, optional): The geobounds to + + geobounds (:class:`wrf.GeoBounds`, optional): The geobounds to get the extents. If set to None and using the *var* parameter, - the geobounds will be taken from the variable. If using a + the geobounds will be taken from the variable. If using a file, then the geobounds will be taken from the native grid. - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable, optional): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` - or an iterable sequence of the aforementioned types. If not used, + iterable, optional): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + or an iterable sequence of the aforementioned types. If not used, then *var* must be provided. - + varname (:obj:`str`, optional): If using *wrfin*, then this will be the - variable name to use to determine the geobounds. The variable - can be a coordinate variable, or a regular variable that contains - coordinate attributes. If None, - then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables + variable name to use to determine the geobounds. The variable + can be a coordinate variable, or a regular variable that contains + coordinate attributes. If None, + then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables will be used. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. Default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - **kwargs: Keyword arguments for creating a + + **kwargs: Keyword arguments for creating a :class:`matplotlib.mpl_toolkits.basemap.Basemap`. By default, - the domain bounds will be set to the native projection, the - resolution will be set to 'l', and the other projection + the domain bounds will be set to the native projection, the + resolution will be set to 'l', and the other projection parameters will be set by the information in the file. - + Returns: - - :class:`cartopy.crs.Projection`: A Projection subclass for the + + :class:`cartopy.crs.Projection`: A Projection subclass for the map projection. - + Returns: - + :class:`matplotlib.mpl_toolkits.basemap.Basemap`: A Basemap object for the projection. - + See Also: - + :class:`matplotlib.mpl_toolkits.basemap.Basemap` - + """ - return _get_proj_obj("basemap", var, wrfin, varname, timeidx, method, + return _get_proj_obj("basemap", var, wrfin, varname, timeidx, method, squeeze, cache, **kwargs) - + def get_pyngl(var=None, wrfin=None, varname=None, timeidx=0, method="cat", squeeze=True, cache=None, **kwargs): """Return a :class:`Ngl.Resources` object for the map projection. - + Args: - - var (:class:`xarray.DataArray`, optional): A :class:`xarray.DataArray` + + var (:class:`xarray.DataArray`, optional): A :class:`xarray.DataArray` variable that includes latitude,longitude coordinate information. If not used, then *wrfin* must be provided. - - geobounds (:class:`wrf.GeoBounds`, optional): The geobounds to + + geobounds (:class:`wrf.GeoBounds`, optional): The geobounds to get the extents. If set to None and using the *var* parameter, - the geobounds will be taken from the variable. If using a + the geobounds will be taken from the variable. If using a file, then the geobounds will be taken from the native grid. - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable, optional): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` - or an iterable sequence of the aforementioned types. If not used, + iterable, optional): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + or an iterable sequence of the aforementioned types. If not used, then *var* must be provided. - + varname (:obj:`str`, optional): If using *wrfin*, then this will be the - variable name to use to determine the geobounds. The variable - can be a coordinate variable, or a regular variable that contains - coordinate attributes. If None, - then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables + variable name to use to determine the geobounds. The variable + can be a coordinate variable, or a regular variable that contains + coordinate attributes. If None, + then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables will be used. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. Default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - - **kwargs: Additional PyNGL resources to set while creating the + + **kwargs: Additional PyNGL resources to set while creating the :class:`Ngl.Resources` object. - + Returns: - - :class:`Ngl.Resources`: A dict-like object that contains the + + :class:`Ngl.Resources`: A dict-like object that contains the PyNGL resources for the map projection. - + See Also: - - `PyNGL `_ + + `PyNGL `_ """ - return _get_proj_obj("pyngl", var, wrfin, varname, timeidx, method, + return _get_proj_obj("pyngl", var, wrfin, varname, timeidx, method, squeeze, cache) - -def cartopy_xlim(var=None, geobounds=None, wrfin=None, varname=None, timeidx=0, + +def cartopy_xlim(var=None, geobounds=None, wrfin=None, varname=None, timeidx=0, method="cat", squeeze=True, cache=None): """Return the x-axis limits in the projected coordinates. - - For some map projections, like :class`wrf.RotatedLatLon`, the - :meth:`cartopy.GeoAxes.set_extent` method does not work correctly. This + + For some map projections, like :class`wrf.RotatedLatLon`, the + :meth:`cartopy.GeoAxes.set_extent` method does not work correctly. This method is equivalent to: - + .. code-block:: python - + pc = crs.PlateCarree() xs, ys, _ = self._cartopy().transform_points(pc, - np.array([geobounds.bottom_left.lon, + 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)[0] - + Args: - - var (:class:`xarray.DataArray`, optional): A :class:`xarray.DataArray` + + var (:class:`xarray.DataArray`, optional): A :class:`xarray.DataArray` variable that includes latitude,longitude coordinate information. If not used, then *wrfin* must be provided. - - geobounds (:class:`wrf.GeoBounds`, optional): The geobounds to + + geobounds (:class:`wrf.GeoBounds`, optional): The geobounds to get the extents. If set to None and using the *var* parameter, - the geobounds will be taken from the variable. If using a + the geobounds will be taken from the variable. If using a file, then the geobounds will be taken from the native grid. - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable, optional): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` - or an iterable sequence of the aforementioned types. If not used, + iterable, optional): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + or an iterable sequence of the aforementioned types. If not used, then *var* must be provided. - + varname (:obj:`str`, optional): If using *wrfin*, then this will be the - variable name to use to determine the geobounds. The variable - can be a coordinate variable, or a regular variable that contains - coordinate attributes. If None, - then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables + variable name to use to determine the geobounds. The variable + can be a coordinate variable, or a regular variable that contains + coordinate attributes. If None, + then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables will be used. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. Default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - + Returns: - + :obj:`list`: A list of [start_x, end_x] in the projected coordinate system. - + """ - wrf_proj, native_geobnds = _get_wrf_proj_geobnds(var, wrfin, varname, - timeidx, method, squeeze, cache) + wrf_proj, native_geobnds = _get_wrf_proj_geobnds(var, wrfin, varname, + timeidx, method, squeeze, + cache) if geobounds is not None: return wrf_proj.cartopy_xlim(geobounds) return wrf_proj.cartopy_xlim(native_geobnds) - - -def cartopy_ylim(var=None, geobounds=None, wrfin=None, varname=None, timeidx=0, + + +def cartopy_ylim(var=None, geobounds=None, wrfin=None, varname=None, timeidx=0, method="cat", squeeze=True, cache=None): """Return the y-axis limits in the projected coordinates. - - For some map projections, like :class`wrf.RotatedLatLon`, the - :meth:`cartopy.GeoAxes.set_extent` method does not work correctly. This + + For some map projections, like :class`wrf.RotatedLatLon`, the + :meth:`cartopy.GeoAxes.set_extent` method does not work correctly. This method is equivalent to: - + .. code-block:: python - + pc = crs.PlateCarree() xs, ys, _ = self._cartopy().transform_points(pc, - np.array([geobounds.bottom_left.lon, + 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)[1] - + Args: - - var (:class:`xarray.DataArray`, optional): A :class:`xarray.DataArray` + + var (:class:`xarray.DataArray`, optional): A :class:`xarray.DataArray` variable that includes latitude,longitude coordinate information. If not used, then *wrfin* must be provided. - - geobounds (:class:`wrf.GeoBounds`, optional): The geobounds to + + geobounds (:class:`wrf.GeoBounds`, optional): The geobounds to get the extents. If set to None and using the *var* parameter, - the geobounds will be taken from the variable. If using a + the geobounds will be taken from the variable. If using a file, then the geobounds will be taken from the native grid. - + wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ - iterable, optional): WRF-ARW NetCDF - data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` - or an iterable sequence of the aforementioned types. If not used, + iterable, optional): WRF-ARW NetCDF + data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile` + or an iterable sequence of the aforementioned types. If not used, then *var* must be provided. - + varname (:obj:`str`, optional): If using *wrfin*, then this will be the - variable name to use to determine the geobounds. The variable - can be a coordinate variable, or a regular variable that contains - coordinate attributes. If None, - then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables + variable name to use to determine the geobounds. The variable + can be a coordinate variable, or a regular variable that contains + coordinate attributes. If None, + then the 'XLAT', 'XLAT_M', 'XLONG', 'XLONG_M' variables will be used. - - timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The - desired time index. This value can be a positive integer, - negative integer, or - :data:`wrf.ALL_TIMES` (an alias for None) to return + + timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The + desired time index. This value can be a positive integer, + negative integer, or + :data:`wrf.ALL_TIMES` (an alias for None) to return all times in the file or sequence. Default is 0. - - method (:obj:`str`, optional): The aggregation method to use for - sequences. Must be either 'cat' or 'join'. - 'cat' combines the data along the Time dimension. - 'join' creates a new dimension for the file index. + + method (:obj:`str`, optional): The aggregation method to use for + sequences. Must be either 'cat' or 'join'. + 'cat' combines the data along the Time dimension. + 'join' creates a new dimension for the file index. The default is 'cat'. - - squeeze (:obj:`bool`, optional): Set to False to prevent dimensions - with a size of 1 from being automatically removed from the shape + + squeeze (:obj:`bool`, optional): Set to False to prevent dimensions + with a size of 1 from being automatically removed from the shape of the output. Default is True. - - cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) - that can be used to supply pre-extracted NetCDF variables to the - computational routines. It is primarily used for internal - purposes, but can also be used to improve performance by - eliminating the need to repeatedly extract the same variables - used in multiple diagnostics calculations, particularly when using - large sequences of files. + + cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) + that can be used to supply pre-extracted NetCDF variables to the + computational routines. It is primarily used for internal + purposes, but can also be used to improve performance by + eliminating the need to repeatedly extract the same variables + used in multiple diagnostics calculations, particularly when using + large sequences of files. Default is None. - + Returns: - + :obj:`list`: A list of [start_y, end_y] in the projected coordinate system. - + """ - wrf_proj, native_geobnds = _get_wrf_proj_geobnds(var, wrfin, varname, - timeidx, method, squeeze, cache) + wrf_proj, native_geobnds = _get_wrf_proj_geobnds(var, wrfin, varname, + timeidx, method, squeeze, + cache) if geobounds is not None: return wrf_proj.cartopy_ylim(geobounds) @@ -3819,108 +3847,81 @@ def cartopy_ylim(var=None, geobounds=None, wrfin=None, varname=None, timeidx=0, def ll_points(lat, lon): """Return the lower left latitude and longitude point(s). - + This functions extracts the lower left corner points and returns the result - as either a single :class:`CoordPair` object, or a list of + as either a single :class:`CoordPair` object, or a list of :class:`CoordPair` objects. - + This is primarily used for testing or constructing the corner point objects from the XLAT and XLONG variables. - + Args: - - lat (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The latitude + + lat (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The latitude array. Must be at least two dimensions. - - lon (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The + + lon (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The longitude array. Must be at least two dimensions. - + Returns: - - :class:`wrf.CoordPair` or :obj:`list`: A single :class:`wrf.CoordPair` + + :class:`wrf.CoordPair` or :obj:`list`: A single :class:`wrf.CoordPair` 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)) else: - return [CoordPair(lat=latvals[i], lon=lonvals[i]) + return [CoordPair(lat=latvals[i], lon=lonvals[i]) for i in py3range(latvals.shape[0])] def pairs_to_latlon(pairs): """Return latitude and longitude arrays from a sequence of \ :class:`wrf.CoordPair` objects. - - This function converts a sequence of :class:`wrf.CoordPair` objects into - lists of latitude and longitude points. If the *pairs* argument is a - single :class:`wrf.CoordPair` object, then a single latitude and + + This function converts a sequence of :class:`wrf.CoordPair` objects into + lists of latitude and longitude points. If the *pairs* argument is a + single :class:`wrf.CoordPair` object, then a single latitude and longitude value is returned. - + Args: - - pairs (:class:`wrf.CoordPair` or sequence): A single + + pairs (:class:`wrf.CoordPair` or sequence): A single :class:`wrf.CoordPair` or sequence of :class:`wrf.CoordPair`. - + Returns: - - :obj:`tuple`: A tuple of (lat, lon), where lat and lon are single - values or lists of values. - + + :obj:`tuple`: A tuple of (lat, lon), where lat and lon are single + values or lists of values. + """ - + if isinstance(pairs, CoordPair): return (pairs.lat, pairs.lon) else: lats = [pair.lat for pair in pairs] lons = [pair.lon for pair in pairs] - + return lats, lons - + def is_latlon_pair(pair): """Return True if the :class:`wrf.CoordPair` is a lat/lon pair - + Args: - + pair (:class:`wrf.CoordPair`): A single :class:`wrf.CoordPair` object. - + Returns: - + :obj:`bool`: True if the pair is a lat/lon pair. - + """ if pair is not None: return (pair.lat is not None and pair.lon is not None) else: return False - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/wrf/version.py b/src/wrf/version.py index a700854..9c73af2 100644 --- a/src/wrf/version.py +++ b/src/wrf/version.py @@ -1,2 +1 @@ __version__ = "1.3.1" -