Browse Source

Fixed issue with the wspd_wdir diagnostic not working with sequences of data. Added WRF Workshop instructions for the upcoming tutorial. Made new fortran functions for wspd and wdir. Fixes #19, fixes #21, fixes #22, fixes #23.

main
Bill Ladwig 8 years ago
parent
commit
62ea6c6b74
  1. 10
      doc/source/_templates/product_table.txt
  2. 1
      doc/source/index.rst
  3. 8
      doc/source/new.rst
  4. 302
      doc/source/workshop.rst
  5. 48
      fortran/wrf_wind.f90
  6. 17
      fortran/wrffortran.pyf
  7. 1
      setup.py
  8. 42
      src/wrf/extension.py
  9. 55
      src/wrf/specialdec.py
  10. 7
      src/wrf/uvmet.py
  11. 2
      src/wrf/version.py
  12. 22
      src/wrf/wind.py

10
doc/source/_templates/product_table.txt

@ -183,7 +183,7 @@
| | | | | | | | | |
| | | ft s-1 | | | | | ft s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+
| wspd_wdir | Wind Speed and Direction | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. | | wspd_wdir | Wind Speed and Direction (wind_from_direction) | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. |
| | | | | | | | | |
| | in Grid Coordinates | km h-1 | | | | in Grid Coordinates | km h-1 | |
| | | | | | | | | |
@ -193,7 +193,7 @@
| | | | | | | | | |
| | | ft s-1 | | | | | ft s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+
| wspd_wdir10 | 10m Wind Speed and Direction | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. | | wspd_wdir10 | 10m Wind Speed and Direction (wind_from_direction) | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. |
| | | | | | | | | |
| | in Grid Coordinates | km h-1 | | | | in Grid Coordinates | km h-1 | |
| | | | | | | | | |
@ -203,7 +203,7 @@
| | | | | | | | | |
| | | ft s-1 | | | | | ft s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+
| uvmet_wspd_wdir | Wind Speed and Direction | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. | | uvmet_wspd_wdir | Wind Speed and Direction (wind_from_direction) | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. |
| | | | | | | | | |
| | Rotated to Earth Coordinates | km h-1 | | | | Rotated to Earth Coordinates | km h-1 | |
| | | | | | | | | |
@ -213,7 +213,7 @@
| | | | | | | | | |
| | | ft s-1 | | | | | ft s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+
| uvmet10_wspd_wdir | 10m Wind Speed and Direction | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. | | uvmet10_wspd_wdir | 10m Wind Speed and Direction (wind_from_direction) | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. |
| | | | | | | | | |
| | Rotated to Earth Coordinates | km h-1 | | | | Rotated to Earth Coordinates | km h-1 | |
| | | | | | | | | |
@ -223,7 +223,7 @@
| | | | | | | | | |
| | | ft s-1 | | | | | ft s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+
| z/height | Full Model Height | m | **msl** (boolean): Set to False to return AGL values. True is for MSL. Default is *True*. | | z/height | Full Model Height on Mass Levels | m | **msl** (boolean): Set to False to return AGL values. True is for MSL. Default is *True*. |
| | | | | | | | | |
| | | km | **units** (str) : Set to desired units. Default is *'m'*. | | | | km | **units** (str) : Set to desired units. Default is *'m'*. |
| | | | | | | | | |

1
doc/source/index.rst

@ -46,6 +46,7 @@ Documentation
./faq ./faq
./support ./support
./license ./license
./workshop
Indices and tables Indices and tables

8
doc/source/new.rst

@ -4,6 +4,14 @@ What's New
Releases Releases
------------- -------------
v1.0.2
^^^^^^^^^^^^^^
- Release 1.0.2
- Fixed issue with the wspd_wdir product types when sequences of files are
used.
v1.0.1 v1.0.1
^^^^^^^^^^^^^ ^^^^^^^^^^^^^

302
doc/source/workshop.rst

@ -0,0 +1,302 @@
WRF Workshop 2017
=====================
Welcome wrf-python tutorial attendees!
The instructions below should be completed prior to arriving at the tutorial.
There will not be enough time to do this during the tutorial.
Prerequisites
---------------
This tutorial assumes that you have basic knowledge of how to type commands
in to a command terminal using your preferred operating system. The student
should know some basic directory commands like *cd*, *mkdir*, *cp*, *mv*.
Regarding Python, to understand the examples in this tutorial, the student
should have some experience with Python basics. This includes:
- Opening a Python interpreter and entering commands.
- Importing packages via the import statement.
- Using the basic Python types: str, list, tuple, dict, boolean, numeric, None.
- Creating a list, tuple, or dict with "[ ]", "( )", "{ }" syntax.
- Accessing dict/list/tuple items with the "x[ ]" syntax.
- Slicing str/list/tuple with the ":" syntax.
- Using object methods and attributes with the "x.y" syntax.
- Familiarity with numpy would be helpful, as only a very brief introduction
is provided.
- Familiarity with matplotlib would be helpful, as only a very brief
introduction is provided.
If a student is completely new to Python, that shouldn't be a problem, since
most of the examples consist of basic container types and function calls. It
would be helpful to look at some introductory material before arriving at the
tutorial. If you've programmed before, picking up Python is fairly easy.
Here are some links:
https://www.learnpython.org/
https://developers.google.com/edu/python/
Step 1: Open a Command Terminal
--------------------------------
To begin, you will first need to know how to open a command line terminal for
your operating system.
For Windows:
.. code-block:: none
WINDOWS + r
type cmd in the run window
For Mac:
.. code-block:: none
Finder -> Applications -> Utilities -> Terminal
For Linux:
.. code-block:: none
Try one of the following:
CTRL + ALT + T
CTRL + ALT + F2
Step 2: Download Miniconda
----------------------------
For this tutorial, you will need to download and install Miniconda. We are
going to use Python 2.7, but it should also work with Python 3.5+. However,
due to limitations with open source compilers on conda-forge, only Python 2.7
is available for Windows.
**What is Miniconda?**
If you have used the Anaconda distribution for Python before, then you will be
familiar with Miniconda. The Anaconda Python distribution includes numerous
scientific packages out of box, which can be difficult for users to build and
install. More importantly, Anaconda includes the conda package manager.
The conda package manager is a utility (similar to yum or apt-get) that installs
packages from a repository of pre-compiled Python packages. These repositories
are called channels. Conda makes it easy for Python users to install and
uninstall packages, and also can be used to create isolated Python environments
(more on that later).
Miniconda is a bare bones implementation of Anaconda and only includes the
conda package manager. Since we are going to use the conda-forge channel to
install our scientific packages, Miniconda avoids any complications between
packages provided by Anaconda and conda-forge.
Please use the appropriate link below to download Miniconda for your operating
system.
.. note::
64-bit OS recommended
`Win64 <https://repo.continuum.io/miniconda/Miniconda2-latest-Windows-x86_64.exe>`_
`Mac <https://repo.continuum.io/miniconda/Miniconda2-latest-MacOSX-x86_64.sh>`_
`Linux <https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh>`_
For more information, see: https://conda.io/miniconda.html
Step 3: Install Miniconda
----------------------------
Windows:
1. Browse to the directory where you downloaded Miniconda2-latest-Windows-x86_64.exe.
2. Double click on Miniconda2-latest-Windows-x86_64.exe.
3. Follow the instructions.
4. Restart your command terminal.
Mac and Linux:
For Mac and Linux, the installer is a bash script.
1. Using a terminal, you need to execute the shell script that you downloaded by
doing::
bash /path/to/Miniconda2-latest-MacOSX-x86_64.sh [Mac]
bash /path/to/Miniconda2-latest-Linux-x86_64.sh [Linux]
2. Follow the instructions.
3. At the end of the installation, it will ask if you want to add the
miniconda2 path to your bash environment. If you are unsure what to do,
you should say "yes". If you say "no", we're going to assume you know
what you are doing.
If you said "yes", then once you restart your shell, the miniconda2 Python
will be found instead of the system Python when you type the "python"
command. If you want to undo this later, then you can edit
either ~/.bash_profile or ~/.bashrc (depending on OS used) and
comment out the line that looks similar to::
# added by Miniconda2 4.1.11 installer
export PATH="/path/to/miniconda2/bin:$PATH"
4. Restart your command terminal.
.. note::
If you have already installed another Python distribution, like Enthought
Canopy, you will need to comment out any PATH entries for that distribution
in your .bashrc or .bash_profile. Otherwise, your shell environment may
pick to wrong Python installation. You can use the command "which python"
to verify the Python installation being used.
Step 4: Set Up the Conda Environment
--------------------------------------
If you are new to the conda package manager, one of the nice features of conda
is that you can create isolated Python environments that prevent package
incompatibilities. This is similar to the virtualenv package that some
Python users may be familiar with. However, conda is not compatible with
virtualenv, so only use conda environments when working with conda.
The name of our conda environment for this tutorial is: **tutorial_2017**.
Follow the instructions below to create the tutorial_2017 environment.
1. Open a command terminal if you haven't done so.
2. [Linux and Mac Users Only] The conda package manager only works with bash,
so if bash is not your current shell, type::
bash
3. Add the conda-forge channel to your conda package manager.
Type or copy this command in to your command terminal::
conda config --add channels conda-forge
.. note::
Conda-forge is a community driven collection of packages that are
continually tested to ensure compatibility. We highly recommend using
conda-forge when working with conda. See https://conda-forge.github.io/
for more details on this excellent project.
4. Create the conda environment for the tutorial.
Type or copy this command in to your command terminal::
conda create -n tutorial_2017 python=2.7 matplotlib=1.5.3 cartopy netcdf4 jupyter git wrf-python
Type "y" when prompted. It will take several minutes to install everything.
This command creates an isolated Python environment named *tutorial_2017*, and installs
the python interpreter, matplotlib, cartopy, netcdf4, jupyter, git, and wrf-python
packages.
.. note::
In this tutorial, we need to use matplotlib v1.5.3 due to some issues with cartopy, which
should be fixed in a later version of cartopy. Be sure to supply the version number as
indicated in the command above.
5. Activate the conda environment.
To activate the tutorial_2017 Python environment, type the following
in to the command terminal::
source activate tutorial_2017.
You should see (tutorial_2017) on your command prompt.
To deactivate your conda environment, type the following in to the
command terminal::
source deactivate
Step 5: Download the Student Workbook
---------------------------------------
The student workbook for the tutorial is available on GitHub. The tutorial_2017
conda environment includes the git application needed to download the repository.
These instructions download the tutorial in to your home directory. If you want
to place the tutorial in to another directory, we're going to assume you know
how to do this yourself.
To download the student workbook, follow these instructions:
1. Activate the tutorial_2017 conda environment following the instructions
in the previous step (*source activate tutorial_2017*).
2. Change your working directory to the home directory by typing the
following command in to the command terminal:
For Linux and Mac::
cd ~
For Windows::
cd %HOMEPATH%
3. Download the git repository for the tutorial by typing the following
in to the command terminal::
git checkout https://github.com/NCAR/wrf_python_tutorial
4. There may be additional changes to the tutorial after you have downloaded
it. To pull down the latest changes, type the following in to the
command terminal:
For Linux and Mac::
source activate tutorial_2017
cd ~/wrf_python_tutorial
git pull
For Windows::
source activate tutorial_2017
cd %HOMEPATH%\wrf_python_tutorial
git pull
Step 6: Obtain WRF Output Files
----------------------------------
For this tutorial, we strongly recommend that you use your own WRF output files.
The tutorial includes an easy way to point to your own data files. The WRF
output files should all be from the same WRF run and use the same domain.
If your files are located on another system (e.g. yellowstone), then copy 2 or
3 of these files to your local computer prior to the tutorial.
If you do not have any of your own WRF output files, then you can download the
instructor data files from a link that should have been provided to you in an
email prior to the tutorial.
Getting Help
----------------
If you experience problems during this installation, please send a question
to the :ref:`google-group` support mailing list.
We look forward to seeing you at the tutorial!

48
fortran/wrf_wind.f90

@ -0,0 +1,48 @@
! NCLFORTSTART
SUBROUTINE DCOMPUTEWSPD(wspd, u, v, nx, ny)
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: wspd
INTEGER, INTENT(IN) :: nx, ny
REAL(KIND=8), DIMENSION(nx,ny), INTENT(OUT) :: wspd
REAL(KIND=8), DIMENSION(nx,ny), INTENT(IN) :: u, v
! NCLEND
INTEGER i, j
DO j = 1,ny
DO i = 1,nx
wspd(i,j) = SQRT(u(i,j)*u(i,j) + v(i,j)*v(i,j))
END DO
END DO
END SUBROUTINE DCOMPUTEWSPD
! NCLFORTSTART
SUBROUTINE DCOMPUTEWDIR(wdir, u, v, nx, ny)
USE wrf_constants, ONLY : DEG_PER_RAD
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: wdir
INTEGER, INTENT(IN) :: nx, ny
REAL(KIND=8), DIMENSION(nx,ny), INTENT(OUT) :: wdir
REAL(KIND=8), DIMENSION(nx,ny), INTENT(IN) :: u, v
! NCLEND
INTEGER i, j
DO j = 1,ny
DO i = 1,nx
wdir(i,j) = MOD(270.0 - ATAN2(v(i,j), u(i,j)) * DEG_PER_RAD, 360.)
END DO
END DO
END SUBROUTINE DCOMPUTEWDIR

17
fortran/wrffortran.pyf

@ -556,6 +556,23 @@ python module _wrffortran ! in
integer intent(inout) :: errstat integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg character*(*) intent(inout) :: errmsg
end subroutine wrf_vintrp end subroutine wrf_vintrp
subroutine dcomputewspd(wspd,u,v,nx,ny) ! in :_wrffortran:wrf_wind.f90
threadsafe
real(kind=8) dimension(nx,ny),intent(out,in) :: wspd
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: u
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: v
integer, optional,intent(in),check(shape(wspd,0)==nx),depend(wspd) :: nx=shape(wspd,0)
integer, optional,intent(in),check(shape(wspd,1)==ny),depend(wspd) :: ny=shape(wspd,1)
end subroutine dcomputewspd
subroutine dcomputewdir(wdir,u,v,nx,ny) ! in :_wrffortran:wrf_wind.f90
threadsafe
use wrf_constants, only: deg_per_rad
real(kind=8) dimension(nx,ny),intent(out,in) :: wdir
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: u
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: v
integer, optional,intent(in),check(shape(wdir,0)==nx),depend(wdir) :: nx=shape(wdir,0)
integer, optional,intent(in),check(shape(wdir,1)==ny),depend(wdir) :: ny=shape(wdir,1)
end subroutine dcomputewdir
end interface end interface
end python module _wrffortran end python module _wrffortran

1
setup.py

@ -21,6 +21,7 @@ ext1 = numpy.distutils.core.Extension(
"fortran/wrf_rip_phys_routines.f90", "fortran/wrf_rip_phys_routines.f90",
"fortran/wrf_pw.f90", "fortran/wrf_pw.f90",
"fortran/wrf_vinterp.f90", "fortran/wrf_vinterp.f90",
"fortran/wrf_wind.f90",
"fortran/wrffortran.pyf"] "fortran/wrffortran.pyf"]
) )

42
src/wrf/extension.py

@ -11,7 +11,8 @@ from ._wrffortran import (dcomputetk, dinterp3dz, dinterp2dxy, dinterp1d,
calcdbz, dcalrelhl, dcalcuh, dcomputepv, calcdbz, dcalrelhl, dcalcuh, dcomputepv,
dcomputeabsvort, dlltoij, dijtoll, deqthecalc, dcomputeabsvort, dlltoij, dijtoll, deqthecalc,
omgcalc, virtual_temp, wetbulbcalc, dcomputepw, omgcalc, virtual_temp, wetbulbcalc, dcomputepw,
wrf_monotonic, wrf_vintrp) wrf_monotonic, wrf_vintrp, dcomputewspd,
dcomputewdir)
from .decorators import (left_iteration, cast_type, from .decorators import (left_iteration, cast_type,
extract_and_transpose, check_args) extract_and_transpose, check_args)
@ -859,4 +860,43 @@ def _vintrp(field, pres, tk, qvp, ght, terrain, sfp, smsfp,
return result return result
@check_args(0, 2, (2,2))
@left_iteration(2, 2, ref_var_idx=0)
@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))
@left_iteration(2, 2, ref_var_idx=0)
@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

55
src/wrf/specialdec.py

@ -151,6 +151,20 @@ def uvmet_left_iter(alg_dtype=np.float64):
new_lon = lon[lat_left_and_slice] new_lon = lon[lat_left_and_slice]
outview = outview_array[left_and_slice_idxs] 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):
if isinstance(arg, np.ma.MaskedArray):
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 # Call the numerical routine
result = wrapped(new_u, new_v, new_lat, new_lon, cen_long, cone, result = wrapped(new_u, new_v, new_lat, new_lon, cen_long, cone,
isstag=is_stag, has_missing=has_missing, isstag=is_stag, has_missing=has_missing,
@ -324,6 +338,25 @@ def cape_left_iter(alg_dtype=np.float64):
capeview = outview_array[cape_idxs] capeview = outview_array[cape_idxs]
cinview = outview_array[cin_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
# supply the fill values here.
skip_missing = False
for arg in (new_args[0:6]):
if isinstance(arg, np.ma.MaskedArray):
if arg.mask.all():
if flip and not is2d:
output[cape_output_idxs] = missing
output[cin_output_idxs] = missing
else:
output[cape_output_idxs] = missing
output[cin_output_idxs] = missing
skip_missing = True
if skip_missing:
continue
# Call the numerical routine # Call the numerical routine
new_kwargs["capeview"] = capeview new_kwargs["capeview"] = capeview
new_kwargs["cinview"] = cinview new_kwargs["cinview"] = cinview
@ -420,6 +453,8 @@ def cloudfrac_left_iter(alg_dtype=np.float64):
output_dims += p.shape[-2:] output_dims += p.shape[-2:]
output = np.empty(output_dims, orig_dtype) output = np.empty(output_dims, orig_dtype)
has_missing = False
missing = Constants.DEFAULT_FILL
for left_idxs in iter_left_indexes(extra_dims): for left_idxs in iter_left_indexes(extra_dims):
left_and_slice_idxs = left_idxs + (slice(None),) left_and_slice_idxs = left_idxs + (slice(None),)
low_idxs = left_idxs + (0, slice(None)) low_idxs = left_idxs + (0, slice(None))
@ -433,6 +468,23 @@ def cloudfrac_left_iter(alg_dtype=np.float64):
new_args[0] = p[left_and_slice_idxs] new_args[0] = p[left_and_slice_idxs]
new_args[1] = rh[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 cape.py or computation.py, so only
# supply the fill values here.
skip_missing = False
for arg in (new_args[0:2]):
if isinstance(arg, np.ma.MaskedArray):
if arg.mask.all():
output[low_output_idxs] = missing
output[med_output_idxs] = missing
output[high_output_idxs] = missing
skip_missing = True
has_missing = True
if skip_missing:
continue
lowview = outview_array[low_idxs] lowview = outview_array[low_idxs]
medview = outview_array[med_idxs] medview = outview_array[med_idxs]
highview = outview_array[high_idxs] highview = outview_array[high_idxs]
@ -456,6 +508,9 @@ def cloudfrac_left_iter(alg_dtype=np.float64):
output[high_output_idxs] = ( 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 output
return func_wrapper return func_wrapper

7
src/wrf/uvmet.py

@ -135,8 +135,15 @@ def _get_uvmet(wrfin, timeidx=0, method="cat", squeeze=True,
idx0 = (0,) + (Ellipsis,) + (slice(None),)*(-end_idx) idx0 = (0,) + (Ellipsis,) + (slice(None),)*(-end_idx)
idx1 = (1,) + (Ellipsis,) + (slice(None),)*(-end_idx) idx1 = (1,) + (Ellipsis,) + (slice(None),)*(-end_idx)
try:
fill = u.fill_value
except AttributeError:
result[idx0] = u[:] result[idx0] = u[:]
result[idx1] = v[:] result[idx1] = v[:]
else:
result[idx0] = np.ma.filled(u[:], fill)
result[idx1] = np.ma.filled(v[:], fill)
result = np.ma.masked_values(result, fill)
return result return result
elif map_proj in (1,2): elif map_proj in (1,2):

2
src/wrf/version.py

@ -1,2 +1,2 @@
__version__ = "1.0.1" __version__ = "1.0.2"

22
src/wrf/wind.py

@ -3,7 +3,7 @@ from __future__ import (absolute_import, division, print_function,
import numpy as np import numpy as np
from .constants import Constants from .extension import _wspd, _wdir
from .destag import destagger from .destag import destagger
from .util import extract_vars, either from .util import extract_vars, either
from .decorators import convert_units from .decorators import convert_units
@ -29,7 +29,7 @@ def _calc_wspd(u, v, units="m s-1"):
:class:`numpy.ndarray`: The wind speed. :class:`numpy.ndarray`: The wind speed.
""" """
return np.sqrt(u**2 + v**2) return _wspd(u, v)
def _calc_wdir(u, v): def _calc_wdir(u, v):
@ -46,8 +46,7 @@ def _calc_wdir(u, v):
:class:`numpy.ndarray`: The wind direction. :class:`numpy.ndarray`: The wind direction.
""" """
wdir = 270.0 - np.arctan2(v,u) * (180.0/Constants.PI) return _wdir(u, v)
return np.remainder(wdir, 360.0)
def _calc_wspd_wdir(u, v, two_d, units): def _calc_wspd_wdir(u, v, two_d, units):
@ -79,26 +78,35 @@ def _calc_wspd_wdir(u, v, two_d, units):
leftmost dimension is 2 (0=WSPD, 1=WDIR). leftmost dimension is 2 (0=WSPD, 1=WDIR).
""" """
wspd = _calc_wspd(u, v, units) wspd = _calc_wspd(u, v, units)
wdir = _calc_wdir(u, v) wdir = _calc_wdir(u, v)
try:
fill = wspd.fill_value
except AttributeError:
fill = None
idx_end = -2 if two_d else -3 idx_end = -2 if two_d else -3
outdims = list(wspd.shape[0:idx_end]) + [2] + list(wspd.shape[idx_end:]) outdims = [2] + list(wspd.shape[0:idx_end]) + list(wspd.shape[idx_end:])
result = np.zeros(outdims, wspd.dtype) result = np.zeros(outdims, wspd.dtype)
idxs0 = ((0,Ellipsis, slice(None), slice(None), slice(None)) idxs0 = ((0,Ellipsis, slice(None), slice(None), slice(None))
if not two_d else if not two_d else
(1, Ellipsis, slice(None), slice(None))) (0, Ellipsis, slice(None), slice(None)))
idxs1 = ((1, Ellipsis, slice(None), slice(None), slice(None)) idxs1 = ((1, Ellipsis, slice(None), slice(None), slice(None))
if not two_d else if not two_d else
(0, Ellipsis, slice(None), slice(None))) (1, Ellipsis, slice(None), slice(None)))
result[idxs0] = wspd[:] result[idxs0] = wspd[:]
result[idxs1] = wdir[:] result[idxs1] = wdir[:]
if fill is not None:
result = np.ma.masked_equal(result, fill)
return result return result

Loading…
Cancel
Save