Browse Source

Merge branch 'release/1.3.2'

main 1.3.2
Bill Ladwig 6 years ago
parent
commit
5682aa5007
  1. 3
      .circleci/conda_env.yml
  2. 7
      .circleci/config.yml
  3. 10
      README.md
  4. 5
      build_scripts/gnu_no_omp.sh
  5. 7
      build_scripts/gnu_omp.sh
  6. 2
      build_scripts/win_msvc_mingw_no_omp.bat
  7. 2
      build_scripts/win_msvc_mingw_omp.bat
  8. 79
      chey_intel.py
  9. 10
      doc/source/_templates/product_table.txt
  10. 63
      doc/source/contrib.rst
  11. 10
      doc/source/index.rst
  12. 3
      doc/source/internal_api/index.rst
  13. 12
      doc/source/new.rst
  14. 62
      fortran/build_help/sub_sizes.py
  15. 8
      fortran/rip_cape.f90
  16. 36
      fortran/wrf_wind.f90
  17. 144
      setup.py
  18. 21
      src/wrf/__init__.py
  19. 55
      src/wrf/api.py
  20. 139
      src/wrf/cache.py
  21. 2349
      src/wrf/computation.py
  22. 104
      src/wrf/config.py
  23. 43
      src/wrf/constants.py
  24. 243
      src/wrf/coordpair.py
  25. 456
      src/wrf/decorators.py
  26. 56
      src/wrf/destag.py
  27. 1281
      src/wrf/extension.py
  28. 809
      src/wrf/g_cape.py
  29. 688
      src/wrf/g_cloudfrac.py
  30. 149
      src/wrf/g_ctt.py
  31. 228
      src/wrf/g_dbz.py
  32. 191
      src/wrf/g_dewpoint.py
  33. 533
      src/wrf/g_geoht.py
  34. 233
      src/wrf/g_helicity.py
  35. 816
      src/wrf/g_latlon.py
  36. 87
      src/wrf/g_omega.py
  37. 12
      src/wrf/g_precip.py
  38. 183
      src/wrf/g_pressure.py
  39. 95
      src/wrf/g_pw.py
  40. 176
      src/wrf/g_rh.py
  41. 106
      src/wrf/g_slp.py
  42. 623
      src/wrf/g_temp.py
  43. 97
      src/wrf/g_terrain.py
  44. 161
      src/wrf/g_times.py
  45. 1007
      src/wrf/g_uvmet.py
  46. 179
      src/wrf/g_vorticity.py
  47. 989
      src/wrf/g_wind.py
  48. 71
      src/wrf/geobnds.py
  49. 945
      src/wrf/interp.py
  50. 454
      src/wrf/interputils.py
  51. 547
      src/wrf/latlonutils.py
  52. 1841
      src/wrf/metadecorators.py
  53. 988
      src/wrf/projection.py
  54. 13
      src/wrf/projutils.py
  55. 118
      src/wrf/py3compat.py
  56. 494
      src/wrf/routines.py
  57. 463
      src/wrf/specialdec.py
  58. 440
      src/wrf/units.py
  59. 3505
      src/wrf/util.py
  60. 3
      src/wrf/version.py
  61. 32
      test/cachetest.py
  62. 123
      test/ci_tests/make_test_file.py
  63. 208
      test/ci_tests/utests.py
  64. 536
      test/comp_utest.py
  65. 17
      test/ctt_test.py
  66. 10
      test/generator_test.py
  67. 40
      test/misc/extract_one_time.py
  68. 70
      test/misc/loop_and_fill_meta.py
  69. 43
      test/misc/mocktest.py
  70. 188
      test/misc/projtest.py
  71. 58
      test/misc/quiver_test.py
  72. 14
      test/misc/reduce_file.py
  73. 29
      test/misc/snippet.py
  74. 34
      test/misc/varcache.py
  75. 19
      test/misc/viewtest.py
  76. 230
      test/misc/wps.py
  77. 0
      test/ncl/listBug.ncl
  78. 30
      test/ncl/ncl_get_var.ncl
  79. 92
      test/ncl/ncl_vertcross.ncl
  80. 81
      test/ncl/refl10_cross.ncl
  81. 26
      test/ncl/rotated_test.ncl
  82. 21
      test/ncl/test_this.ncl
  83. 0
      test/ncl/test_vinterp.ncl
  84. 416
      test/ncl/wrf_user_vertcross.ncl
  85. 30
      test/snippet.py
  86. 80
      test/test_filevars.py
  87. 103
      test/test_inputs.py
  88. 42
      test/test_multi_cache.py
  89. 91
      test/test_omp.py
  90. 454
      test/test_proj_params.py
  91. 33
      test/test_units.py
  92. 1200
      test/utests.py

3
.circleci/conda_env.yml

@ -2,7 +2,8 @@ name: wrf-python @@ -2,7 +2,8 @@ name: wrf-python
channels:
- conda-forge
dependencies:
- gcc
- gcc_linux-64
- gfortran_linux-64
- setuptools
- python
- numpy

7
.circleci/config.yml

@ -46,11 +46,14 @@ jobs: @@ -46,11 +46,14 @@ jobs:
name: build wrf-python
command: |
source ~/miniconda3/bin/activate wrf-python
unset FFLAGS
unset LDFLAGS
unset CFLAGS
cd fortran/build_help
gfortran -o sizes -fopenmp omp_sizes.f90
$FC -o sizes -fopenmp omp_sizes.f90
LD_LIBRARY_PATH=~/miniconda3/envs/wrf-python/lib python sub_sizes.py
cd ..
gfortran -E ompgen.F90 -fopenmp -cpp -o omp.f90
$FC -E ompgen.F90 -fopenmp -cpp -o omp.f90
cd ..
python setup.py config_fc --f90flags="-mtune=generic -fopenmp" build_ext --libraries="gomp" build
python setup.py install --single-version-externally-managed --record=record.txt

10
README.md

@ -23,3 +23,13 @@ Citation @@ -23,3 +23,13 @@ Citation
Ladwig, W. (2017). wrf-python (Version x.x.x) [Software]. Boulder, Colorado: UCAR/NCAR. https://doi.org/10.5065/D6W094P1
Note: The version number x.x.x should be set to the version of wrf-python that you are using.
--------------------
*The National Center for Atmospheric Research is sponsored by the National
Science Foundation. Any opinions, findings and conclusions or recommendations
expressed in this material do not necessarily reflect the views of the
National Science Foundation.*

5
build_scripts/gnu_no_omp.sh

@ -1,8 +1,9 @@ @@ -1,8 +1,9 @@
#!/bin/bash
unset LDFLAGS
cd ../fortran
gfortran -E ompgen.F90 -cpp -o omp.f90
#f2py *.f90 -m _wrffortran -h wrffortran.pyf --overwrite-signature
$FC -E ompgen.F90 -cpp -o omp.f90
cd ..
python setup.py clean --all

7
build_scripts/gnu_omp.sh

@ -1,12 +1,13 @@ @@ -1,12 +1,13 @@
#!/bin/bash
unset LDFLAGS
cd ../fortran/build_help
gfortran -o sizes -fopenmp omp_sizes.f90
$FC -o sizes -fopenmp omp_sizes.f90
python sub_sizes.py
cd ..
gfortran -E ompgen.F90 -fopenmp -cpp -o omp.f90
#f2py *.f90 -m _wrffortran -h wrffortran.pyf --overwrite-signature
$FC -E ompgen.F90 -fopenmp -cpp -o omp.f90
cd ..
python setup.py clean --all

2
build_scripts/win_msvc_mingw_no_omp.bat

@ -1,7 +1,5 @@ @@ -1,7 +1,5 @@
cd ../fortran
CALL gfortran -E ompgen.F90 -cpp -o omp.f90
REM Wildcards not working on Windows for some reason
REM CALL f2py -m _wrffortran -h wrffortran.pyf --overwrite-signature wrf_constants.f90 wrf_testfunc.f90 wrf_user.f90 rip_cape.f90 wrf_cloud_fracf.f90 wrf_fctt.f90 wrf_user_dbz.f90 wrf_relhl.f90 calc_uh.f90 wrf_user_latlon_routines.f90 wrf_pvo.f90 eqthecalc.f90 wrf_rip_phys_routines.f90 wrf_pw.f90 wrf_vinterp.f90 wrf_wind.f90 omp.f90
cd ..
CALL python setup.py clean --all

2
build_scripts/win_msvc_mingw_omp.bat

@ -4,8 +4,6 @@ CALL python sub_sizes.py @@ -4,8 +4,6 @@ CALL python sub_sizes.py
cd ..
CALL gfortran -E ompgen.F90 -cpp -fopenmp -o omp.f90
REM Wildcards not working on Windows for some reason
REM CALL f2py -m _wrffortran -h wrffortran.pyf --overwrite-signature wrf_constants.f90 wrf_testfunc.f90 wrf_user.f90 rip_cape.f90 wrf_cloud_fracf.f90 wrf_fctt.f90 wrf_user_dbz.f90 wrf_relhl.f90 calc_uh.f90 wrf_user_latlon_routines.f90 wrf_pvo.f90 eqthecalc.f90 wrf_rip_phys_routines.f90 wrf_pw.f90 wrf_vinterp.f90 wrf_wind.f90 omp.f90
cd ..
CALL python setup.py clean --all

79
chey_intel.py

@ -13,7 +13,8 @@ compilers = ['IntelFCompiler', 'IntelVisualFCompiler', @@ -13,7 +13,8 @@ compilers = ['IntelFCompiler', 'IntelVisualFCompiler',
def intel_version_match(type):
# Match against the important stuff in the version string
return simple_version_match(start=r'Intel.*?Fortran.*?(?:%s).*?Version' % (type,))
return simple_version_match(
start=r'Intel.*?Fortran.*?(?:%s).*?Version'.format(type,))
class BaseIntelFCompiler(FCompiler):
@ -36,13 +37,13 @@ class IntelFCompiler(BaseIntelFCompiler): @@ -36,13 +37,13 @@ class IntelFCompiler(BaseIntelFCompiler):
possible_executables = ['ifort', 'ifc']
executables = {
'version_cmd' : None, # set by update_executables
'compiler_f77' : [None, "-72", "-w90", "-w95"],
'compiler_f90' : [None],
'compiler_fix' : [None, "-FI"],
'linker_so' : ["<F90>", "-shared"],
'archiver' : ["ar", "-cr"],
'ranlib' : ["ranlib"]
'version_cmd': None, # set by update_executables
'compiler_f77': [None, "-72", "-w90", "-w95"],
'compiler_f90': [None],
'compiler_fix': [None, "-FI"],
'linker_so': ["<F90>", "-shared"],
'archiver': ["ar", "-cr"],
'ranlib': ["ranlib"]
}
pic_flags = ['-fPIC']
@ -89,13 +90,13 @@ class IntelItaniumFCompiler(IntelFCompiler): @@ -89,13 +90,13 @@ class IntelItaniumFCompiler(IntelFCompiler):
possible_executables = ['ifort', 'efort', 'efc']
executables = {
'version_cmd' : None,
'compiler_f77' : [None, "-FI", "-w90", "-w95"],
'compiler_fix' : [None, "-FI"],
'compiler_f90' : [None],
'linker_so' : ['<F90>', "-shared"],
'archiver' : ["ar", "-cr"],
'ranlib' : ["ranlib"]
'version_cmd': None,
'compiler_f77': [None, "-FI", "-w90", "-w95"],
'compiler_fix': [None, "-FI"],
'compiler_f90': [None],
'linker_so': ['<F90>', "-shared"],
'archiver': ["ar", "-cr"],
'ranlib': ["ranlib"]
}
@ -104,18 +105,19 @@ class IntelEM64TFCompiler(IntelFCompiler): @@ -104,18 +105,19 @@ class IntelEM64TFCompiler(IntelFCompiler):
compiler_aliases = ()
description = 'Intel Fortran Compiler for 64-bit apps'
version_match = intel_version_match('EM64T-based|Intel\\(R\\) 64|64|IA-64|64-bit')
version_match = intel_version_match(
'EM64T-based|Intel\\(R\\) 64|64|IA-64|64-bit')
possible_executables = ['ifort', 'efort', 'efc']
executables = {
'version_cmd' : None,
'compiler_f77' : [None, "-FI"],
'compiler_fix' : [None, "-FI"],
'compiler_f90' : [None],
'linker_so' : ['<F90>', "-shared"],
'archiver' : ["ar", "-cr"],
'ranlib' : ["ranlib"]
'version_cmd': None,
'compiler_f77': [None, "-FI"],
'compiler_fix': [None, "-FI"],
'compiler_f90': [None],
'linker_so': ['<F90>', "-shared"],
'archiver': ["ar", "-cr"],
'ranlib': ["ranlib"]
}
def get_flags(self):
@ -147,13 +149,13 @@ class IntelVisualFCompiler(BaseIntelFCompiler): @@ -147,13 +149,13 @@ class IntelVisualFCompiler(BaseIntelFCompiler):
possible_executables = ['ifort', 'ifl']
executables = {
'version_cmd' : None,
'compiler_f77' : [None],
'compiler_fix' : [None],
'compiler_f90' : [None],
'linker_so' : [None],
'archiver' : [ar_exe, "/verbose", "/OUT:"],
'ranlib' : None
'version_cmd': None,
'compiler_f77': [None],
'compiler_fix': [None],
'compiler_f90': [None],
'linker_so': [None],
'archiver': [ar_exe, "/verbose", "/OUT:"],
'ranlib': None
}
compile_switch = '/c '
@ -163,7 +165,8 @@ class IntelVisualFCompiler(BaseIntelFCompiler): @@ -163,7 +165,8 @@ class IntelVisualFCompiler(BaseIntelFCompiler):
module_include_switch = '/I'
def get_flags(self):
opt = ['/nologo', '/MD', '/nbs', '/names:lowercase', '/assume:underscore']
opt = ['/nologo', '/MD', '/nbs', '/names:lowercase',
'/assume:underscore']
return opt
def get_flags_free(self):
@ -192,13 +195,13 @@ class IntelItaniumVisualFCompiler(IntelVisualFCompiler): @@ -192,13 +195,13 @@ class IntelItaniumVisualFCompiler(IntelVisualFCompiler):
ar_exe = IntelVisualFCompiler.ar_exe
executables = {
'version_cmd' : None,
'compiler_f77' : [None, "-FI", "-w90", "-w95"],
'compiler_fix' : [None, "-FI", "-4L72", "-w"],
'compiler_f90' : [None],
'linker_so' : ['<F90>', "-shared"],
'archiver' : [ar_exe, "/verbose", "/OUT:"],
'ranlib' : None
'version_cmd': None,
'compiler_f77': [None, "-FI", "-w90", "-w95"],
'compiler_fix': [None, "-FI", "-4L72", "-w"],
'compiler_f90': [None],
'linker_so': ['<F90>', "-shared"],
'archiver': [ar_exe, "/verbose", "/OUT:"],
'ranlib': None
}

10
doc/source/_templates/product_table.txt

@ -245,6 +245,16 @@ @@ -245,6 +245,16 @@
| | | | |
| | | mi | |
+--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| height_agl | Model Height for Mass Grid (AGL) | m | **units** (str) : Set to desired units. Default is *'m'*. |
| | | | |
| | | km | |
| | | | |
| | | dm | |
| | | | |
| | | ft | |
| | | | |
| | | mi | |
+--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| zstag | Model Height for Vertically Staggered Grid | 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'*. |

63
doc/source/contrib.rst

@ -0,0 +1,63 @@ @@ -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

10
doc/source/index.rst

@ -13,6 +13,14 @@ @@ -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 @@ -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 @@ -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.*

3
doc/source/internal_api/index.rst

@ -23,6 +23,9 @@ The routines below are called internally by :meth:`wrf.getvar`. @@ -23,6 +23,9 @@ The routines below are called internally by :meth:`wrf.getvar`.
wrf.g_dewpoint.get_dp_2m
wrf.g_geoht.get_geopt
wrf.g_geoht.get_height
wrf.g_geoht.get_height_agl
wrf.g_geoht.get_stag_geopt
wrf.g_geoht.get_stag_height
wrf.g_helicity.get_srh
wrf.g_helicity.get_uh
wrf.g_omega.get_omega

12
doc/source/new.rst

@ -4,6 +4,18 @@ What's New @@ -4,6 +4,18 @@ What's New
Releases
-------------
v1.3.2 (February 2019)
^^^^^^^^^^^^^^^^^^^^^^^^^
- Release 1.3.2
- Coordinate name index positions are no longer assumed and are searched
instead. Some users use xarray to rewrite WRF output files, and xarray
might reorder the coordinate name positions.
- Fixed a segfault issue with CAPE when more than 150 vertical levels are
used (e.g. LES runs).
- setup.py will now bootstrap the numpy installation (thanks bbonenfant!).
v1.3.1 (January 2019)
^^^^^^^^^^^^^^^^^^^^^^^^^

62
fortran/build_help/sub_sizes.py

@ -3,55 +3,55 @@ import os @@ -3,55 +3,55 @@ import os
from string import Template
import sys
def main():
print ("Running sub_sizes")
print("Running sub_sizes")
try:
result = subprocess.check_output(["./sizes"])
except:
except OSError:
result = subprocess.check_output(["sizes.exe"])
split_result = result.split()
if sys.version_info >= (3, ):
if split_result[0].strip().decode() != "SIZES":
raise ValueError("First line is not SIZES")
subs = {"FOMP_SCHED_KIND" : split_result[1].strip().decode(),
"FOMP_LOCK_KIND" : split_result[2].strip().decode(),
"FOMP_NEST_LOCK_KIND" : split_result[3].strip().decode(),
"FOMP_SCHED_STATIC" : split_result[4].strip().decode(),
"FOMP_SCHED_DYNAMIC" : split_result[5].strip().decode(),
"FOMP_SCHED_GUIDED" : split_result[6].strip().decode(),
"FOMP_SCHED_AUTO" : split_result[7].strip().decode()
subs = {"FOMP_SCHED_KIND": split_result[1].strip().decode(),
"FOMP_LOCK_KIND": split_result[2].strip().decode(),
"FOMP_NEST_LOCK_KIND": split_result[3].strip().decode(),
"FOMP_SCHED_STATIC": split_result[4].strip().decode(),
"FOMP_SCHED_DYNAMIC": split_result[5].strip().decode(),
"FOMP_SCHED_GUIDED": split_result[6].strip().decode(),
"FOMP_SCHED_AUTO": split_result[7].strip().decode()
}
else:
if split_result[0].strip() != "SIZES":
raise ValueError("First line is not SIZES")
subs = {"FOMP_SCHED_KIND" : split_result[1].strip(),
"FOMP_LOCK_KIND" : split_result[2].strip(),
"FOMP_NEST_LOCK_KIND" : split_result[3].strip(),
"FOMP_SCHED_STATIC" : split_result[4].strip(),
"FOMP_SCHED_DYNAMIC" : split_result[5].strip(),
"FOMP_SCHED_GUIDED" : split_result[6].strip(),
"FOMP_SCHED_AUTO" : split_result[7].strip()
subs = {"FOMP_SCHED_KIND": split_result[1].strip(),
"FOMP_LOCK_KIND": split_result[2].strip(),
"FOMP_NEST_LOCK_KIND": split_result[3].strip(),
"FOMP_SCHED_STATIC": split_result[4].strip(),
"FOMP_SCHED_DYNAMIC": split_result[5].strip(),
"FOMP_SCHED_GUIDED": split_result[6].strip(),
"FOMP_SCHED_AUTO": split_result[7].strip()
}
ompgen_temp_path = os.path.join("..", "ompgen.F90.template")
ompgen_out_path = os.path.join("..", "ompgen.F90")
with open(ompgen_temp_path, "r") as ompgen_in:
ompgen_template = Template(ompgen_in.read())
ompgen_string = ompgen_template.substitute(subs)
with open(ompgen_out_path, "w") as ompgen_out:
ompgen_out.write(ompgen_string)
print ("End sub_sizes")
print("End sub_sizes")
if __name__ == "__main__":
main()
main()

8
fortran/rip_cape.f90

@ -316,7 +316,9 @@ SUBROUTINE DCAPECALC3D(prs,tmk,qvp,ght,ter,sfp,cape,cin,& @@ -316,7 +316,9 @@ SUBROUTINE DCAPECALC3D(prs,tmk,qvp,ght,ter,sfp,cape,cin,&
REAL(KIND=8) :: facden, qvplift, tmklift, tvenv, tvlift, ghtlift
REAL(KIND=8) :: eslift, tmkenv, qvpenv, tonpsadiabat
REAL(KIND=8) :: benamin, dz
REAL(KIND=8), DIMENSION(150) :: buoy, zrel, benaccum
! Set a safety factor of 2*mkzh + 1 instead of previously chosen
! 150 levels
REAL(KIND=8), DIMENSION(2*mkzh + 1) :: buoy, zrel, benaccum
REAL(KIND=8), DIMENSION(150) :: psadithte, psadiprs
REAL(KIND=8), DIMENSION(150,150) :: psaditmk
LOGICAL :: elfound
@ -646,7 +648,9 @@ SUBROUTINE DCAPECALC2D(prs,tmk,qvp,ght,ter,sfp,cape,cin,& @@ -646,7 +648,9 @@ SUBROUTINE DCAPECALC2D(prs,tmk,qvp,ght,ter,sfp,cape,cin,&
REAL(KIND=8) :: facden, qvplift, tmklift, tvenv, tvlift, ghtlift
REAL(KIND=8) :: eslift, tmkenv, qvpenv, tonpsadiabat
REAL(KIND=8) :: benamin, dz, pup, pdn
REAL(KIND=8), DIMENSION(150) :: buoy, zrel, benaccum
! Set a safety factor of 2*mkzh + 1 instead of previously chosen
! 150 levels
REAL(KIND=8), DIMENSION(2*mkzh + 1) :: buoy, zrel, benaccum
REAL(KIND=8), DIMENSION(150) :: psadithte, psadiprs
REAL(KIND=8), DIMENSION(150,150) :: psaditmk
LOGICAL :: elfound

36
fortran/wrf_wind.f90

@ -1,23 +1,21 @@ @@ -1,23 +1,21 @@
! NCLFORTSTART
SUBROUTINE DCOMPUTEWSPD(wspd, u, v, nx, ny)
SUBROUTINE DCOMPUTEWSPD(wspd, u, v, n)
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
INTEGER, INTENT(IN) :: n
REAL(KIND=8), DIMENSION(n), INTENT(OUT) :: wspd
REAL(KIND=8), DIMENSION(n), INTENT(IN) :: u, v
! NCLEND
INTEGER i, j
INTEGER i
!$OMP PARALLEL DO COLLAPSE(2) SCHEDULE(runtime)
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
!$OMP PARALLEL DO SCHEDULE(runtime)
DO i = 1,n
wspd(i) = SQRT(u(i)*u(i) + v(i)*v(i))
END DO
!$OMP END PARALLEL DO
@ -25,7 +23,7 @@ END SUBROUTINE DCOMPUTEWSPD @@ -25,7 +23,7 @@ END SUBROUTINE DCOMPUTEWSPD
! NCLFORTSTART
SUBROUTINE DCOMPUTEWDIR(wdir, u, v, nx, ny)
SUBROUTINE DCOMPUTEWDIR(wdir, u, v, n)
USE wrf_constants, ONLY : DEG_PER_RAD
IMPLICIT NONE
@ -33,18 +31,16 @@ SUBROUTINE DCOMPUTEWDIR(wdir, u, v, nx, ny) @@ -33,18 +31,16 @@ SUBROUTINE DCOMPUTEWDIR(wdir, u, v, nx, ny)
!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
INTEGER, INTENT(IN) :: n
REAL(KIND=8), DIMENSION(n), INTENT(OUT) :: wdir
REAL(KIND=8), DIMENSION(n), INTENT(IN) :: u, v
! NCLEND
INTEGER i, j
INTEGER i
!$OMP PARALLEL DO COLLAPSE(2) SCHEDULE(runtime)
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
!$OMP PARALLEL DO SCHEDULE(runtime)
DO i = 1,n
wdir(i) = MOD(270.0 - ATAN2(v(i), u(i)) * DEG_PER_RAD, 360.)
END DO
!$OMP END PARALLEL DO

144
setup.py

@ -3,13 +3,21 @@ import sys @@ -3,13 +3,21 @@ import sys
import setuptools
import socket
# Bootstrap a numpy installation before trying to import it.
import imp
try:
imp.find_module('numpy')
except ImportError:
import subprocess
subprocess.call([sys.executable, '-m', 'pip', 'install', 'numpy'])
if not socket.gethostname().startswith("cheyenne"):
import numpy.distutils.core
else:
import chey_intel
import numpy.distutils.core
import numpy.distutils.fcompiler.intel
numpy.distutils.fcompiler.intel.IntelFCompiler = chey_intel.IntelFCompiler
numpy.distutils.fcompiler.intel.IntelVisualFCompiler = (
chey_intel.IntelVisualFCompiler)
@ -23,33 +31,33 @@ else: @@ -23,33 +31,33 @@ else:
chey_intel.IntelEM64TFCompiler)
ext1 = numpy.distutils.core.Extension(
name = "wrf._wrffortran",
sources = ["fortran/wrf_constants.f90",
"fortran/wrf_testfunc.f90",
"fortran/wrf_user.f90",
"fortran/rip_cape.f90",
"fortran/wrf_cloud_fracf.f90",
"fortran/wrf_fctt.f90",
"fortran/wrf_user_dbz.f90",
"fortran/wrf_relhl.f90",
"fortran/calc_uh.f90",
"fortran/wrf_user_latlon_routines.f90",
"fortran/wrf_pvo.f90",
"fortran/eqthecalc.f90",
"fortran/wrf_rip_phys_routines.f90",
"fortran/wrf_pw.f90",
"fortran/wrf_vinterp.f90",
"fortran/wrf_wind.f90",
"fortran/omp.f90"]
name="wrf._wrffortran",
sources=["fortran/wrf_constants.f90",
"fortran/wrf_testfunc.f90",
"fortran/wrf_user.f90",
"fortran/rip_cape.f90",
"fortran/wrf_cloud_fracf.f90",
"fortran/wrf_fctt.f90",
"fortran/wrf_user_dbz.f90",
"fortran/wrf_relhl.f90",
"fortran/calc_uh.f90",
"fortran/wrf_user_latlon_routines.f90",
"fortran/wrf_pvo.f90",
"fortran/eqthecalc.f90",
"fortran/wrf_rip_phys_routines.f90",
"fortran/wrf_pw.f90",
"fortran/wrf_vinterp.f90",
"fortran/wrf_wind.f90",
"fortran/omp.f90"]
)
with open("src/wrf/version.py") as f:
with open("src/wrf/version.py") as f:
exec(f.read())
on_rtd = os.environ.get("READTHEDOCS", None) == "True"
#on_rtd=True
# on_rtd=True
if on_rtd:
if sys.version_info < (3,3):
if sys.version_info < (3, 3):
requirements = ["mock"] # for python2 and python < 3.3
else:
requirements = [] # for >= python3.3
@ -59,53 +67,53 @@ else: @@ -59,53 +67,53 @@ else:
# Place install_requires into the text file "requirements.txt"
with open("requirements.txt") as f2:
requirements = f2.read().strip().splitlines()
#if sys.version_info < (3,3):
# requirements.append("mock")
# if sys.version_info < (3,3):
# requirements.append("mock")
ext_modules = [ext1]
numpy.distutils.core.setup(
author = "Bill Ladwig",
author_email = "ladwig@ucar.edu",
description = "Diagnostic and interpolation routines for WRF-ARW data.",
long_description = ("A collection of diagnostic and interpolation routines "
"to be used with WRF-ARW data.\n\n"
"GitHub Repository:\n\n"
"https://github.com/NCAR/wrf-python\n\n"
"Documentation:\n\n"
"http://wrf-python.rtfd.org\n"),
url = "https://github.com/NCAR/wrf-python",
keywords = ["python", "wrf-python", "wrf", "forecast", "model",
"weather research and forecasting", "interpolation",
"plotting", "plots", "meteorology", "nwp",
"numerical weather prediction", "diagnostic",
"science", "numpy"],
install_requires = requirements,
classifiers = ["Development Status :: 5 - Production/Stable",
"Intended Audience :: Science/Research",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Fortran",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Topic :: Scientific/Engineering :: Atmospheric Science",
"Topic :: Software Development",
"Operating System :: POSIX",
"Operating System :: Unix",
"Operating System :: MacOS",
"Operating System :: Microsoft :: Windows"],
name = "wrf-python",
platforms = ["any"],
license = "Apache License 2.0",
version = __version__,
packages = setuptools.find_packages("src"),
ext_modules = ext_modules,
package_dir = {"" : "src"},
download_url = "http://python.org/pypi/wrf-python",
package_data={"wrf" : ["data/psadilookup.dat"]},
numpy.distutils.core.setup(
author="Bill Ladwig",
author_email="ladwig@ucar.edu",
description="Diagnostic and interpolation routines for WRF-ARW data.",
long_description=("A collection of diagnostic and interpolation "
"routines to be used with WRF-ARW data.\n\n"
"GitHub Repository:\n\n"
"https://github.com/NCAR/wrf-python\n\n"
"Documentation:\n\n"
"http://wrf-python.rtfd.org\n"),
url="https://github.com/NCAR/wrf-python",
keywords=["python", "wrf-python", "wrf", "forecast", "model",
"weather research and forecasting", "interpolation",
"plotting", "plots", "meteorology", "nwp",
"numerical weather prediction", "diagnostic",
"science", "numpy"],
install_requires=requirements,
classifiers=["Development Status :: 5 - Production/Stable",
"Intended Audience :: Science/Research",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Fortran",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Topic :: Scientific/Engineering :: Atmospheric Science",
"Topic :: Software Development",
"Operating System :: POSIX",
"Operating System :: Unix",
"Operating System :: MacOS",
"Operating System :: Microsoft :: Windows"],
name="wrf-python",
platforms=["any"],
license="Apache License 2.0",
version=__version__,
packages=setuptools.find_packages("src"),
ext_modules=ext_modules,
package_dir={"": "src"},
download_url="http://python.org/pypi/wrf-python",
package_data={"wrf": ["data/psadilookup.dat"]},
scripts=[]
)
)

21
src/wrf/__init__.py

@ -2,19 +2,24 @@ from __future__ import (absolute_import, division, print_function) @@ -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__)

55
src/wrf/api.py

@ -3,24 +3,24 @@ from .config import (xarray_enabled, disable_xarray, enable_xarray, @@ -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, @@ -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", @@ -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", @@ -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"] @@ -110,4 +110,3 @@ __all__ += ["CoordPair"]
__all__ += ["to_xy_coords"]
__all__ += ["cache_item", "get_cached_item"]
__all__ += ["__version__"]

139
src/wrf/cache.py

@ -11,158 +11,153 @@ _local_storage = local() @@ -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)

2349
src/wrf/computation.py

File diff suppressed because it is too large Load Diff

104
src/wrf/config.py

@ -3,42 +3,43 @@ from __future__ import (absolute_import, division, print_function) @@ -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(): @@ -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(): @@ -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(): @@ -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(): @@ -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(): @@ -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(): @@ -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)

43
src/wrf/constants.py

@ -10,10 +10,12 @@ from ._wrffortran import wrf_constants, omp_constants @@ -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): @@ -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): @@ -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: @@ -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)

243
src/wrf/coordpair.py

@ -1,265 +1,254 @@ @@ -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))

456
src/wrf/decorators.py

@ -2,7 +2,7 @@ from __future__ import (absolute_import, division, print_function) @@ -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 @@ -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, @@ -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, @@ -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, @@ -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, @@ -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

56
src/wrf/destag.py

@ -8,57 +8,55 @@ from .metadecorators import set_destag_metadata @@ -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
return result

1281
src/wrf/extension.py

File diff suppressed because it is too large Load Diff

809
src/wrf/g_cape.py

File diff suppressed because it is too large Load Diff

688
src/wrf/g_cloudfrac.py

@ -11,142 +11,142 @@ from .g_geoht import _get_geoht @@ -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, @@ -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

149
src/wrf/g_ctt.py

@ -3,11 +3,10 @@ from __future__ import (absolute_import, division, print_function) @@ -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 @@ -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", @@ -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)

228
src/wrf/g_dbz.py

@ -2,82 +2,81 @@ from __future__ import (absolute_import, division, print_function) @@ -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", @@ -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)

191
src/wrf/g_dewpoint.py

@ -1,164 +1,163 @@ @@ -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

533
src/wrf/g_geoht.py

@ -8,79 +8,80 @@ from .decorators import convert_units @@ -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, @@ -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, @@ -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, @@ -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,141 @@ def get_stag_geopt(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, @@ -320,75 +321,141 @@ 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)
@set_height_metadata(geopt=False, stag=False)
@convert_units("height", "m")
def get_height_agl(wrfin, timeidx=0, method="cat", squeeze=True,
cache=None, meta=True, _key=None, units="m"):
"""Return the geopotential height (AGL).
The geopotential height is returned as Above Ground Level (AGL) by
subtracting the terrain height.
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`
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
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.
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
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.
Default is None.
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
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 'height_agl'.
Default is 'm'.
Returns:
: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
be a :class:`numpy.ndarray` object with no metadata.
"""
return _get_geoht(wrfin, timeidx, method, squeeze, cache, meta, _key,
True, False)

233
src/wrf/g_helicity.py

@ -9,87 +9,88 @@ from .util import extract_vars, extract_global_attrs, either @@ -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, @@ -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
return uh

816
src/wrf/g_latlon.py

File diff suppressed because it is too large Load Diff

87
src/wrf/g_omega.py

@ -7,64 +7,64 @@ from .util import extract_vars @@ -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, @@ -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

12
src/wrf/g_precip.py

@ -2,29 +2,29 @@ from __future__ import (absolute_import, division, print_function) @@ -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

183
src/wrf/g_pressure.py

@ -5,144 +5,141 @@ from .metadecorators import copy_and_set_metadata @@ -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")

95
src/wrf/g_pw.py

@ -1,91 +1,86 @@ @@ -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)

176
src/wrf/g_rh.py

@ -1,156 +1,154 @@ @@ -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

106
src/wrf/g_slp.py

@ -1,6 +1,5 @@ @@ -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 @@ -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

623
src/wrf/g_temp.py

@ -7,70 +7,70 @@ from .metadecorators import copy_and_set_metadata @@ -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, @@ -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")

97
src/wrf/g_terrain.py

@ -6,73 +6,70 @@ from .util import extract_vars, either @@ -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]

161
src/wrf/g_times.py

@ -3,119 +3,118 @@ from __future__ import (absolute_import, division, print_function) @@ -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)

1007
src/wrf/g_uvmet.py

File diff suppressed because it is too large Load Diff

179
src/wrf/g_vorticity.py

@ -5,69 +5,69 @@ from .util import extract_vars, extract_global_attrs @@ -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, @@ -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, @@ -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, @@ -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)

989
src/wrf/g_wind.py

File diff suppressed because it is too large Load Diff

71
src/wrf/geobnds.py

@ -2,46 +2,47 @@ from __future__ import (absolute_import, division, print_function) @@ -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): @@ -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__)

945
src/wrf/interp.py

File diff suppressed because it is too large Load Diff

454
src/wrf/interputils.py

@ -14,165 +14,164 @@ from .util import pairs_to_latlon @@ -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, @@ -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, @@ -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])]

547
src/wrf/latlonutils.py

@ -6,36 +6,36 @@ import numpy as np @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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, @@ -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, @@ -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, @@ -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

1841
src/wrf/metadecorators.py

File diff suppressed because it is too large Load Diff

988
src/wrf/projection.py

File diff suppressed because it is too large Load Diff

13
src/wrf/projutils.py

@ -2,16 +2,17 @@ from __future__ import (absolute_import, division, print_function) @@ -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)}

118
src/wrf/py3compat.py

@ -3,18 +3,19 @@ from __future__ import (absolute_import, division, print_function) @@ -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): @@ -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): @@ -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): @@ -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): @@ -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)

494
src/wrf/routines.py

@ -2,13 +2,14 @@ from __future__ import (absolute_import, division, print_function) @@ -2,13 +2,14 @@ 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
from .g_dewpoint import get_dp, get_dp_2m
from .g_geoht import get_geopt, get_height, get_stag_geopt, get_stag_height
from .g_geoht import (get_geopt, get_height, get_stag_geopt, get_stag_height,
get_height_agl)
from .g_helicity import get_srh, get_uh
from .g_latlon import get_lat, get_lon
from .g_omega import get_omega
@ -16,334 +17,339 @@ from .g_pressure import get_pressure, get_pressure_hpa @@ -16,334 +17,339 @@ 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,
"height_agl": get_height_agl,
# 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"],
"height_agl": ["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)

463
src/wrf/specialdec.py

@ -2,7 +2,7 @@ from __future__ import (absolute_import, division, print_function) @@ -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(): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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(): @@ -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(): @@ -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): @@ -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

440
src/wrf/units.py

@ -4,31 +4,31 @@ from .constants import Constants, ConversionFactors @@ -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): @@ -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): @@ -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): @@ -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)

3505
src/wrf/util.py

File diff suppressed because it is too large Load Diff

3
src/wrf/version.py

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

32
test/cachetest.py

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
from __future__ import (absolute_import, division, print_function,
from __future__ import (absolute_import, division, print_function,
unicode_literals)
from threading import Thread
@ -9,7 +9,7 @@ except ImportError: @@ -9,7 +9,7 @@ except ImportError:
from collections import OrderedDict
import unittest as ut
import numpy.testing as nt
import numpy.testing as nt
from wrf.cache import cache_item, get_cached_item, _get_cache
from wrf.config import get_cache_size
@ -20,49 +20,49 @@ class TestThread(Thread): @@ -20,49 +20,49 @@ class TestThread(Thread):
self.num = num
self.q = q
super(TestThread, self).__init__()
def run(self):
for i in range(get_cache_size() + 10):
key = "A" + str(i)
cache_item(key, "test", i * self.num)
item = get_cached_item(key, "test")
if item != i * self.num:
raise RuntimeError("cache is bogus")
cache = OrderedDict(_get_cache())
self.q.put(cache)
class CacheTest(ut.TestCase):
longMessage = True
def test_thread_local(self):
q1 = Queue()
q2 = Queue()
thread1 = TestThread(2, q1)
thread2 = TestThread(40, q2)
thread1.start()
thread2.start()
result1 = q1.get(True, 1)
result2 = q2.get(True, 1)
thread1.join()
thread2.join()
print(result1)
print(result2)
# Result 1 and 2 shoudl be different
self.assertNotEqual(result1, result2)
# This thread should have no cache
self.assertIsNone(_get_cache())
if __name__ == "__main__":
ut.main()

123
test/ci_tests/make_test_file.py

@ -9,19 +9,19 @@ from netCDF4 import Dataset @@ -9,19 +9,19 @@ from netCDF4 import Dataset
from wrf import (getvar, interplevel, interpline, vertcross, vinterp, py2round,
CoordPair, ll_to_xy, xy_to_ll, to_np)
VARS_TO_KEEP = ("Times", "XLAT", "XLONG", "XLAT_U", "XLAT_V", "XLONG_U",
"XLONG_V", "U", "V", "W", "PH", "PHB", "T", "P", "PB", "Q2",
"T2", "PSFC", "U10", "V10", "XTIME", "QVAPOR", "QCLOUD",
VARS_TO_KEEP = ("Times", "XLAT", "XLONG", "XLAT_U", "XLAT_V", "XLONG_U",
"XLONG_V", "U", "V", "W", "PH", "PHB", "T", "P", "PB", "Q2",
"T2", "PSFC", "U10", "V10", "XTIME", "QVAPOR", "QCLOUD",
"QGRAUP", "QRAIN", "QSNOW", "QICE", "MAPFAC_M", "MAPFAC_U",
"MAPFAC_V", "F", "HGT", "RAINC", "RAINSH", "RAINNC")
DIMS_TO_TRIM = ("west_east", "south_north", "bottom_top", "bottom_top_stag",
"west_east_stag", "south_north_stag")
WRF_DIAGS = ["avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz",
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure",
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc",
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va",
WRF_DIAGS = ["avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz",
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure",
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc",
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va",
"wa", "uvmet10", "uvmet", "z", "cfrac", "zstag"]
INTERP_METHS = ["interplevel", "vertcross", "interpline", "vinterp"]
@ -33,56 +33,56 @@ def copy_and_reduce(opts): @@ -33,56 +33,56 @@ def copy_and_reduce(opts):
infilename = opts.filename
outfilename = os.path.expanduser(
os.path.join(opts.outdir, "ci_test_file.nc"))
with Dataset(infilename) as infile, Dataset(outfilename, "w") as outfile:
# Copy the global attributes
outfile.setncatts(infile.__dict__)
# Copy Dimensions
for name, dimension in infile.dimensions.iteritems():
if name in DIMS_TO_TRIM:
if name.find("_stag") > 0:
dimsize = (len(dimension) / 2
if len(dimension) % 2 == 0
dimsize = (len(dimension) / 2
if len(dimension) % 2 == 0
else (len(dimension) + 1) / 2)
else:
dimsize = (len(dimension) / 2
if len(dimension) % 2 == 0
dimsize = (len(dimension) / 2
if len(dimension) % 2 == 0
else (len(dimension) - 1) / 2)
else:
dimsize = len(dimension)
outfile.createDimension(name, dimsize)
# Copy Variables
# Copy Variables
for name, variable in infile.variables.iteritems():
if name not in VARS_TO_KEEP:
if name not in VARS_TO_KEEP:
continue
outvar = outfile.createVariable(name, variable.datatype,
variable.dimensions, zlib=True)
outvar = outfile.createVariable(name, variable.datatype,
variable.dimensions, zlib=True)
in_slices = tuple(slice(0, dimsize) for dimsize in outvar.shape)
outvar[:] = variable[in_slices]
outvar.setncatts(infile.variables[name].__dict__)
def add_to_ncfile(outfile, var, varname):
dim_d = dict(zip(var.dims, var.shape))
for dimname, dimsize in dim_d.items():
if dimname not in outfile.dimensions:
outfile.createDimension(dimname, dimsize)
fill_value = None
if "_FillValue" in var.attrs:
fill_value = var.attrs["_FillValue"]
ncvar = outfile.createVariable(varname, var.dtype, var.dims,
zlib=True, fill_value=fill_value)
var_vals = to_np(var)
ncvar[:] = var_vals[:]
@ -92,78 +92,79 @@ def make_result_file(opts): @@ -92,78 +92,79 @@ def make_result_file(opts):
os.path.join(opts.outdir, "ci_test_file.nc"))
outfilename = os.path.expanduser(
os.path.join(opts.outdir, "ci_result_file.nc"))
with Dataset(infilename) as infile, Dataset(outfilename, "w") as outfile:
for varname in WRF_DIAGS:
var = getvar(infile, varname)
add_to_ncfile(outfile, var, varname)
for interptype in INTERP_METHS:
if interptype == "interpline":
hts = getvar(infile, "z")
p = getvar(infile, "pressure")
hts_850 = interplevel(hts, p, 850.)
add_to_ncfile(outfile, hts_850, "interplevel")
if interptype == "vertcross":
hts = getvar(infile, "z")
p = getvar(infile, "pressure")
pivot_point = CoordPair(hts.shape[-1] // 2, hts.shape[-2] // 2)
ht_cross = vertcross(hts, p, pivot_point=pivot_point,
pivot_point = CoordPair(hts.shape[-1] // 2, hts.shape[-2] // 2)
ht_cross = vertcross(hts, p, pivot_point=pivot_point,
angle=90.)
add_to_ncfile(outfile, ht_cross, "vertcross")
if interptype == "interpline":
t2 = getvar(infile, "T2")
pivot_point = CoordPair(t2.shape[-1] // 2, t2.shape[-2] // 2)
t2_line = interpline(t2, pivot_point=pivot_point, angle=90.0)
add_to_ncfile(outfile, t2_line, "interpline")
if interptype == "vinterp":
tk = getvar(infile, "temp", units="k")
interp_levels = [200,300,500,1000]
field = vinterp(infile,
field=tk,
vert_coord="theta",
interp_levels=interp_levels,
extrapolate=True,
interp_levels = [200, 300, 500, 1000]
field = vinterp(infile,
field=tk,
vert_coord="theta",
interp_levels=interp_levels,
extrapolate=True,
field_type="tk",
log_p=True)
add_to_ncfile(outfile, field, "vinterp")
for latlonmeth in LATLON_METHS:
if latlonmeth == "xy":
# Hardcoded values from other unit tests
lats = [22.0, 25.0, 27.0]
lons = [-90.0, -87.5, -83.75]
xy = ll_to_xy(infile, lats[0], lons[0])
add_to_ncfile(outfile, xy, "xy")
else:
# Hardcoded from other unit tests
x_s = np.asarray([10, 50, 90], int)
y_s = np.asarray([10, 50, 90], int)
ll = xy_to_ll(infile, x_s[0], y_s[0])
add_to_ncfile(outfile, ll, "ll")
def main(opts):
copy_and_reduce(opts)
make_result_file(opts)
if __name__ == "__main__":
DEFAULT_FILE = ("/Users/ladwig/Documents/wrf_files/"
"wrf_vortex_multi/moving_nest/"
@ -171,10 +172,10 @@ if __name__ == "__main__": @@ -171,10 +172,10 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate conda test files "
"for unit testing.")
parser.add_argument("-f", "--filename", required=False,
default=DEFAULT_FILE,
default=DEFAULT_FILE,
help="the WRF test file")
parser.add_argument("-o", "--outdir", required=False, default="./",
help="the location for the output files")
opts = parser.parse_args()
main(opts)
main(opts)

208
test/ci_tests/utests.py

@ -1,14 +1,15 @@ @@ -1,14 +1,15 @@
import unittest as ut
import numpy.testing as nt
import numpy.testing as nt
import numpy as np
import numpy.ma as ma
import os, sys
import os
import sys
import subprocess
from wrf import (getvar, interplevel, interpline, vertcross, vinterp,
disable_xarray, xarray_enabled, to_np,
xy_to_ll, ll_to_xy, xy_to_ll_proj, ll_to_xy_proj,
extract_global_attrs, viewitems, CoordPair,
extract_global_attrs, viewitems, CoordPair,
omp_get_num_procs, omp_set_num_threads)
from wrf.util import is_multi_file
@ -20,82 +21,82 @@ REF_FILE = "ci_result_file.nc" @@ -20,82 +21,82 @@ REF_FILE = "ci_result_file.nc"
if sys.version_info > (3,):
xrange = range
# Using helpful information at:
# Using helpful information at:
# http://eli.thegreenplace.net/2014/04/02/dynamically-generating-python-test-cases
def make_test(varname, wrf_in, referent, multi=False, repeat=3, pynio=False):
def test(self):
from netCDF4 import Dataset as NetCDF
timeidx = 0
in_wrfnc = NetCDF(wrf_in)
refnc = NetCDF(referent)
# These have a left index that defines the product type
multiproduct = varname in ("uvmet", "uvmet10", "cape_2d", "cape_3d",
multiproduct = varname in ("uvmet", "uvmet10", "cape_2d", "cape_3d",
"cfrac")
ref_vals = refnc.variables[varname][:]
if (varname == "tc"):
my_vals = getvar(in_wrfnc, "temp", timeidx=timeidx, units="c")
tol = 1/100.
atol = .1 # Note: NCL uses 273.16 as conversion for some reason
atol = .1 # Note: NCL uses 273.16 as conversion for some reason
nt.assert_allclose(to_np(my_vals), ref_vals, tol, atol)
elif (varname == "pw"):
my_vals = getvar(in_wrfnc, "pw", timeidx=timeidx)
tol = .5/100.0
atol = 0 # NCL uses different constants and doesn't use same
# handrolled virtual temp in method
atol = 0
nt.assert_allclose(to_np(my_vals), ref_vals, tol, atol)
elif (varname == "cape_2d"):
cape_2d = getvar(in_wrfnc, varname, timeidx=timeidx)
tol = 0/100.
atol = 200.0
# Let's only compare CAPE values until the F90 changes are
# Let's only compare CAPE values until the F90 changes are
# merged back in to NCL. The modifications to the R and CP
# changes TK enough that non-lifting parcels could lift, thus
# causing wildly different values in LCL
nt.assert_allclose(to_np(cape_2d[0,:]), ref_vals[0,:], tol, atol)
nt.assert_allclose(to_np(cape_2d[0, :]), ref_vals[0, :], tol, atol)
elif (varname == "cape_3d"):
cape_3d = getvar(in_wrfnc, varname, timeidx=timeidx)
# Changing the R and CP constants, while keeping TK within
# 2%, can lead to some big changes in CAPE. Tolerances
# 2%, can lead to some big changes in CAPE. Tolerances
# have been set wide when comparing the with the original
# NCL. Change back when the F90 code is merged back with
# NCL. Change back when the F90 code is merged back with
# NCL
tol = 0/100.
atol = 200.0
#print np.amax(np.abs(to_np(cape_3d[0,:]) - ref_vals[0,:]))
# print np.amax(np.abs(to_np(cape_3d[0,:]) - ref_vals[0,:]))
nt.assert_allclose(to_np(cape_3d), ref_vals, tol, atol)
else:
my_vals = getvar(in_wrfnc, varname, timeidx=timeidx)
tol = 2/100.
atol = 0.1
#print (np.amax(np.abs(to_np(my_vals) - ref_vals)))
# print (np.amax(np.abs(to_np(my_vals) - ref_vals)))
nt.assert_allclose(to_np(my_vals), ref_vals, tol, atol)
return test
def _get_refvals(referent, varname, repeat, multi):
from netCDF4 import Dataset as NetCDF
refnc = NetCDF(referent)
ref_vals = refnc.variables[varname][:]
return ref_vals
def make_interp_test(varname, wrf_in, referent, multi=False,
def make_interp_test(varname, wrf_in, referent, multi=False,
repeat=3, pynio=False):
def test(self):
from netCDF4 import Dataset as NetCDF
timeidx = 0
in_wrfnc = NetCDF(wrf_in)
if (varname == "interplevel"):
ref_ht_850 = _get_refvals(referent, "interplevel", repeat, multi)
hts = getvar(in_wrfnc, "z", timeidx=timeidx)
@ -103,168 +104,165 @@ def make_interp_test(varname, wrf_in, referent, multi=False, @@ -103,168 +104,165 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
# Check that it works with numpy arrays
hts_850 = interplevel(to_np(hts), p, 850)
#print (hts_850)
# print (hts_850)
hts_850 = interplevel(hts, p, 850)
nt.assert_allclose(to_np(hts_850), ref_ht_850)
elif (varname == "vertcross"):
ref_ht_cross = _get_refvals(referent, "vertcross", repeat, multi)
hts = getvar(in_wrfnc, "z", timeidx=timeidx)
p = getvar(in_wrfnc, "pressure", timeidx=timeidx)
pivot_point = CoordPair(hts.shape[-1] // 2, hts.shape[-2] // 2)
pivot_point = CoordPair(hts.shape[-1] // 2, hts.shape[-2] // 2)
# Check that it works with numpy arrays
ht_cross = vertcross(to_np(hts), to_np(p),
ht_cross = vertcross(to_np(hts), to_np(p),
pivot_point=pivot_point, angle=90.)
#print (ht_cross)
# print (ht_cross)
ht_cross = vertcross(hts, p, pivot_point=pivot_point, angle=90.)
nt.assert_allclose(to_np(ht_cross), ref_ht_cross, rtol=.01)
elif (varname == "interpline"):
ref_t2_line = _get_refvals(referent, "interpline", repeat, multi)
t2 = getvar(in_wrfnc, "T2", timeidx=timeidx)
pivot_point = CoordPair(t2.shape[-1] // 2, t2.shape[-2] // 2)
# Check that it works with numpy arrays
t2_line1 = interpline(to_np(t2), pivot_point=pivot_point,
t2_line1 = interpline(to_np(t2), pivot_point=pivot_point,
angle=90.0)
#print (t2_line1)
# print (t2_line1)
t2_line1 = interpline(t2, pivot_point=pivot_point, angle=90.0)
nt.assert_allclose(to_np(t2_line1), ref_t2_line)
elif (varname == "vinterp"):
# Tk to theta
fld_tk_theta = _get_refvals(referent, "vinterp", repeat, multi)
fld_tk_theta = np.squeeze(fld_tk_theta)
tk = getvar(in_wrfnc, "temp", timeidx=timeidx, units="k")
interp_levels = [200,300,500,1000]
interp_levels = [200, 300, 500, 1000]
# Check that it works with numpy arrays
field = vinterp(in_wrfnc,
field=to_np(tk),
vert_coord="theta",
interp_levels=interp_levels,
extrapolate=True,
field = vinterp(in_wrfnc,
field=to_np(tk),
vert_coord="theta",
interp_levels=interp_levels,
extrapolate=True,
field_type="tk",
timeidx=timeidx,
timeidx=timeidx,
log_p=True)
#print (field)
field = vinterp(in_wrfnc,
field=tk,
vert_coord="theta",
interp_levels=interp_levels,
extrapolate=True,
# print (field)
field = vinterp(in_wrfnc,
field=tk,
vert_coord="theta",
interp_levels=interp_levels,
extrapolate=True,
field_type="tk",
timeidx=timeidx,
timeidx=timeidx,
log_p=True)
tol = 5/100.
atol = 0.0001
field = np.squeeze(field)
nt.assert_allclose(to_np(field), fld_tk_theta, tol, atol)
return test
def make_latlon_test(testid, wrf_in, referent, single, multi=False, repeat=3,
def make_latlon_test(testid, wrf_in, referent, single, multi=False, repeat=3,
pynio=False):
def test(self):
from netCDF4 import Dataset as NetCDF
timeidx = 0
in_wrfnc = NetCDF(wrf_in)
refnc = NetCDF(referent)
if testid == "xy":
# Since this domain is not moving, the reference values are the
# Since this domain is not moving, the reference values are the
# same whether there are multiple or single files
ref_vals = refnc.variables["xy"][:]
# Lats/Lons taken from NCL script, just hard-coding for now
lats = [22.0, 25.0, 27.0]
lons = [-90.0, -87.5, -83.75]
xy = ll_to_xy(in_wrfnc, lats[0], lons[0])
nt.assert_allclose(to_np(xy), ref_vals)
else:
# Since this domain is not moving, the reference values are the
# Since this domain is not moving, the reference values are the
# same whether there are multiple or single files
ref_vals = refnc.variables["ll"][:]
# i_s, j_s taken from NCL script, just hard-coding for now
# NCL uses 1-based indexing for this, so need to subtract 1
# i_s, j_s taken from NCL script, just hard-coding for now
# NCL uses 1-based indexing for this, so need to subtract 1
x_s = np.asarray([10, 50, 90], int)
y_s = np.asarray([10, 50, 90], int)
ll = xy_to_ll(in_wrfnc, x_s[0], y_s[0])
nt.assert_allclose(to_np(ll), ref_vals)
return test
class WRFVarsTest(ut.TestCase):
longMessage = True
class WRFInterpTest(ut.TestCase):
longMessage = True
class WRFLatLonTest(ut.TestCase):
longMessage = True
if __name__ == "__main__":
ignore_vars = [] # Not testable yet
wrf_vars = ["avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz",
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure",
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc",
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va",
wrf_vars = ["avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz",
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure",
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc",
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va",
"wa", "uvmet10", "uvmet", "z", "cfrac", "zstag"]
interp_methods = ["interplevel", "vertcross", "interpline", "vinterp"]
latlon_tests = ["xy", "ll"]
import netCDF4
for var in wrf_vars:
if var in ignore_vars:
continue
test_func1 = make_test(var, TEST_FILE, REF_FILE)
setattr(WRFVarsTest, 'test_{0}'.format(var), test_func1)
for method in interp_methods:
test_interp_func1 = make_interp_test(method, TEST_FILE,
test_interp_func1 = make_interp_test(method, TEST_FILE,
REF_FILE)
setattr(WRFInterpTest, 'test_{0}'.format(method),
setattr(WRFInterpTest, 'test_{0}'.format(method),
test_interp_func1)
for testid in latlon_tests:
for single in (True,):
for multi in (False,):
test_ll_func = make_latlon_test(testid, TEST_FILE,
REF_FILE,
single=single, multi=multi,
test_ll_func = make_latlon_test(testid, TEST_FILE,
REF_FILE,
single=single, multi=multi,
repeat=3, pynio=False)
multistr = "" if not multi else "_multi"
singlestr = "_nosingle" if not single else "_single"
test_name = "test_{}{}{}".format(testid, singlestr,
multistr)
test_name = "test_{}{}{}".format(testid, singlestr, multistr)
setattr(WRFLatLonTest, test_name, test_ll_func)
ut.main()

536
test/comp_utest.py

@ -1,57 +1,68 @@ @@ -1,57 +1,68 @@
from math import fabs, log, tan, sin, cos
import unittest as ut
import numpy.testing as nt
import numpy.testing as nt
import numpy as np
import numpy.ma as ma
import os, sys
import os
import sys
import subprocess
from netCDF4 import Dataset as nc
from wrf import *
NCL_EXE = "/Users/ladwig/nclbuild/6.3.0/bin/ncl"
TEST_FILE = "/Users/ladwig/Documents/wrf_files/wrfout_d01_2010-06-13_21:00:00"
TEST_FILE = ("/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/moving_nest/"
"wrfout_d02_2005-08-28_00:00:00")
OUT_NC_FILE = "/tmp/wrftest.nc"
NCFILE = nc(TEST_FILE)
NCGROUP = [NCFILE, NCFILE, NCFILE]
GROUP_FILES = [
("/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/moving_nest/"
"wrfout_d02_2005-08-28_00:00:00"),
("/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/moving_nest/"
"wrfout_d02_2005-08-28_12:00:00"),
("/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/moving_nest/"
"wrfout_d02_2005-08-29_00:00:00")]
NCGROUP = [nc(file) for file in GROUP_FILES]
# Python 3
if sys.version_info > (3,):
xrange = range
ROUTINE_MAP = {"avo": avo,
"eth": eth,
"cape_2d": cape_2d,
"cape_3d": cape_3d,
"ctt": ctt,
"dbz": dbz,
"helicity": srhel,
"omg": omega,
"pvo": pvo,
"pw": pw,
"rh": rh,
"slp": slp,
"td": td,
"tk": tk,
"tv": tvirtual,
"twb": wetbulb,
"updraft_helicity": udhel,
"uvmet": uvmet,
"cloudfrac": cloudfrac}
ROUTINE_MAP = {"avo" : avo,
"eth" : eth,
"cape_2d" : cape_2d,
"cape_3d" : cape_3d,
"ctt" : ctt,
"dbz" : dbz,
"helicity" : srhel,
"omg" : omega,
"pvo" : pvo,
"pw" : pw,
"rh" : rh,
"slp" : slp,
"td" : td,
"tk" : tk,
"tv" : tvirtual,
"twb" : wetbulb,
"updraft_helicity" : udhel,
"uvmet" : uvmet,
"cloudfrac" : cloudfrac}
class ProjectionError(RuntimeError):
pass
def get_args(varname, wrfnc, timeidx, method, squeeze):
if varname == "avo":
ncvars = extract_vars(wrfnc, timeidx, ("U", "V", "MAPFAC_U",
"MAPFAC_V", "MAPFAC_M",
"F"),
method, squeeze, cache=None, meta=True)
varnames = ("U", "V", "MAPFAC_U", "MAPFAC_V", "MAPFAC_M", "F")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
attrs = extract_global_attrs(wrfnc, attrs=("DX", "DY"))
u = ncvars["U"]
v = ncvars["V"]
@ -59,20 +70,20 @@ def get_args(varname, wrfnc, timeidx, method, squeeze): @@ -59,20 +70,20 @@ def get_args(varname, wrfnc, timeidx, method, squeeze):
msfv = ncvars["MAPFAC_V"]
msfm = ncvars["MAPFAC_M"]
cor = ncvars["F"]
dx = attrs["DX"]
dy = attrs["DY"]
return (u, v, msfu, msfv, msfm, cor, dx, dy)
if varname == "pvo":
ncvars = extract_vars(wrfnc, timeidx, ("U", "V", "T", "P",
"PB", "MAPFAC_U",
"MAPFAC_V", "MAPFAC_M",
"F"),
method, squeeze, cache=None, meta=True)
varnames = ("U", "V", "T", "P", "PB", "MAPFAC_U", "MAPFAC_V",
"MAPFAC_M", "F")
ncvars = extract_vars(wrfnc, timeidx,
varnames,
method, squeeze, cache=None, meta=True)
attrs = extract_global_attrs(wrfnc, attrs=("DX", "DY"))
u = ncvars["U"]
v = ncvars["V"]
t = ncvars["T"]
@ -82,35 +93,35 @@ def get_args(varname, wrfnc, timeidx, method, squeeze): @@ -82,35 +93,35 @@ def get_args(varname, wrfnc, timeidx, method, squeeze):
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 (u, v, full_t, full_p, msfu, msfv, msfm, cor, dx, dy)
if varname == "eth":
varnames=("T", "P", "PB", "QVAPOR")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
varnames = ("T", "P", "PB", "QVAPOR")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
t = ncvars["T"]
p = ncvars["P"]
pb = ncvars["PB"]
qv = ncvars["QVAPOR"]
full_t = t + Constants.T_BASE
full_p = p + pb
tkel = tk(full_p, full_t, meta=False)
return (qv, tkel, full_p)
if varname == "cape_2d":
varnames = ("T", "P", "PB", "QVAPOR", "PH","PHB", "HGT", "PSFC")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
varnames = ("T", "P", "PB", "QVAPOR", "PH", "PHB", "HGT", "PSFC")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
t = ncvars["T"]
p = ncvars["P"]
pb = ncvars["PB"]
@ -119,27 +130,27 @@ def get_args(varname, wrfnc, timeidx, method, squeeze): @@ -119,27 +130,27 @@ def get_args(varname, wrfnc, timeidx, method, squeeze):
phb = ncvars["PHB"]
ter = ncvars["HGT"]
psfc = ncvars["PSFC"]
full_t = t + Constants.T_BASE
full_p = p + pb
tkel = tk(full_p, full_t, meta=False)
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
return (p_hpa, tkel, qv, z, ter, psfc_hpa, ter_follow)
if varname == "cape_3d":
varnames = ("T", "P", "PB", "QVAPOR", "PH", "PHB", "HGT", "PSFC")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
t = ncvars["T"]
p = ncvars["P"]
@ -149,27 +160,27 @@ def get_args(varname, wrfnc, timeidx, method, squeeze): @@ -149,27 +160,27 @@ def get_args(varname, wrfnc, timeidx, method, squeeze):
phb = ncvars["PHB"]
ter = ncvars["HGT"]
psfc = ncvars["PSFC"]
full_t = t + Constants.T_BASE
full_p = p + pb
tkel = tk(full_p, full_t, meta=False)
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
return (p_hpa, tkel, qv, z, ter, psfc_hpa, ter_follow)
if varname == "ctt":
varnames = ("T", "P", "PB", "PH", "PHB", "HGT", "QVAPOR")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
t = ncvars["T"]
p = ncvars["P"]
@ -177,382 +188,389 @@ def get_args(varname, wrfnc, timeidx, method, squeeze): @@ -177,382 +188,389 @@ def get_args(varname, wrfnc, timeidx, method, squeeze):
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(wrfnc, timeidx, "QICE",
icevars = extract_vars(wrfnc, timeidx, "QICE",
method, squeeze, cache=None, meta=False)
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(wrfnc, timeidx, "QCLOUD",
cldvars = extract_vars(wrfnc, timeidx, "QCLOUD",
method, squeeze, cache=None, meta=False)
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
tkel = tk(full_p, full_t, meta=False)
geopt = ph + phb
geopt_unstag = destagger(geopt, -3)
ght = geopt_unstag / Constants.G
return (p_hpa, tkel, qv, qcld, ght, ter, qice)
if varname == "dbz":
varnames = ("T", "P", "PB", "QVAPOR", "QRAIN")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
t = ncvars["T"]
p = ncvars["P"]
pb = ncvars["PB"]
qv = ncvars["QVAPOR"]
qr = ncvars["QRAIN"]
try:
snowvars = extract_vars(wrfnc, timeidx, "QSNOW",
snowvars = extract_vars(wrfnc, timeidx, "QSNOW",
method, squeeze, cache=None, meta=False)
except KeyError:
qs = np.zeros(qv.shape, qv.dtype)
else:
qs = snowvars["QSNOW"]
try:
graupvars = extract_vars(wrfnc, timeidx, "QGRAUP",
graupvars = extract_vars(wrfnc, timeidx, "QGRAUP",
method, squeeze, cache=None, meta=False)
except KeyError:
qg = np.zeros(qv.shape, qv.dtype)
else:
qg = graupvars["QGRAUP"]
full_t = t + Constants.T_BASE
full_p = p + pb
tkel = tk(full_p, full_t, meta=False)
return (full_p, tkel, qv, qr, qs, qg)
if varname == "helicity":
# Top can either be 3000 or 1000 (for 0-1 srh or 0-3 srh)
ncvars = extract_vars(wrfnc, timeidx, ("HGT", "PH", "PHB"),
method, squeeze, cache=None, meta=True)
ter = ncvars["HGT"]
ph = ncvars["PH"]
phb = ncvars["PHB"]
# As coded in NCL, but not sure this is possible
varname = "U"
u_vars = extract_vars(wrfnc, timeidx, varname, method, squeeze,
u_vars = extract_vars(wrfnc, timeidx, varname, method, squeeze,
cache=None, meta=False)
u = destagger(u_vars[varname], -1)
u = destagger(u_vars[varname], -1)
varname = "V"
v_vars = extract_vars(wrfnc, timeidx, varname, method, squeeze,
v_vars = extract_vars(wrfnc, timeidx, varname, method, squeeze,
cache=None, meta=False)
v = destagger(v_vars[varname], -2)
geopt = ph + phb
geopt_unstag = destagger(geopt, -3)
z = geopt_unstag / Constants.G
return (u, v, z, ter)
if varname == "updraft_helicity":
ncvars = extract_vars(wrfnc, timeidx, ("W", "PH", "PHB", "MAPFAC_M"),
method, squeeze, cache=None, meta=True)
varnames = ("W", "PH", "PHB", "MAPFAC_M")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
wstag = ncvars["W"]
ph = ncvars["PH"]
phb = ncvars["PHB"]
mapfct = ncvars["MAPFAC_M"]
attrs = extract_global_attrs(wrfnc, attrs=("DX", "DY"))
attrs = extract_global_attrs(wrfnc, attrs=("DX", "DY"))
dx = attrs["DX"]
dy = attrs["DY"]
# As coded in NCL, but not sure this is possible
varname = "U"
u_vars = extract_vars(wrfnc, timeidx, varname, method, squeeze,
u_vars = extract_vars(wrfnc, timeidx, varname, method, squeeze,
cache=None, meta=True)
u = destagger(u_vars[varname], -1, meta=True)
u = destagger(u_vars[varname], -1, meta=True)
varname = "V"
v_vars = extract_vars(wrfnc, timeidx, varname, method, squeeze,
v_vars = extract_vars(wrfnc, timeidx, varname, method, squeeze,
cache=None, meta=True)
v = destagger(v_vars[varname], -2, meta=True)
zstag = ph + phb
v = destagger(v_vars[varname], -2, meta=True)
zstag = (ph + phb) / Constants.G
return (zstag, mapfct, u, v, wstag, dx, dy)
if varname == "omg":
varnames=("T", "P", "W", "PB", "QVAPOR")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
varnames = ("T", "P", "W", "PB", "QVAPOR")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
t = ncvars["T"]
p = ncvars["P"]
w = ncvars["W"]
pb = ncvars["PB"]
qv = ncvars["QVAPOR"]
wa = destagger(w, -3)
full_t = t + Constants.T_BASE
full_p = p + pb
tkel = tk(full_p, full_t, meta=False)
return (qv, tkel, wa, full_p)
if varname == "pw":
varnames=("T", "P", "PB", "PH", "PHB", "QVAPOR")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
varnames = ("T", "P", "PB", "PH", "PHB", "QVAPOR")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
t = ncvars["T"]
p = ncvars["P"]
pb = ncvars["PB"]
ph = ncvars["PH"]
phb = ncvars["PHB"]
qv = ncvars["QVAPOR"]
# Change this to use real virtual temperature!
full_p = p + pb
ht = (ph + phb)/Constants.G
full_t = t + Constants.T_BASE
full_t = t + Constants.T_BASE
tkel = tk(full_p, full_t, meta=False)
return (full_p, tkel, qv, ht)
if varname == "rh":
varnames=("T", "P", "PB", "QVAPOR")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
varnames = ("T", "P", "PB", "QVAPOR")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
t = ncvars["T"]
p = ncvars["P"]
pb = ncvars["PB"]
qvapor = to_np(ncvars["QVAPOR"])
full_t = t + Constants.T_BASE
full_p = p + pb
qvapor[qvapor < 0] = 0
tkel = tk(full_p, full_t, meta=False)
return (qvapor, full_p, tkel)
if varname == "slp":
varnames=("T", "P", "PB", "QVAPOR", "PH", "PHB")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
varnames = ("T", "P", "PB", "QVAPOR", "PH", "PHB")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
t = ncvars["T"]
p = ncvars["P"]
pb = ncvars["PB"]
qvapor = to_np(ncvars["QVAPOR"])
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)
tkel = tk(full_p, full_t, meta=False)
return (destag_ph, tkel, full_p, qvapor)
if varname == "td":
varnames=("P", "PB", "QVAPOR")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
varnames = ("P", "PB", "QVAPOR")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
p = ncvars["P"]
pb = ncvars["PB"]
qvapor = to_np(ncvars["QVAPOR"])
# Algorithm requires hPa
full_p = .01*(p + pb)
qvapor[qvapor < 0] = 0
return (full_p, qvapor)
if varname == "tk":
varnames=("T", "P", "PB")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
varnames = ("T", "P", "PB")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
t = ncvars["T"]
p = ncvars["P"]
pb = ncvars["PB"]
full_t = t + Constants.T_BASE
full_p = p + pb
return (full_p, full_t)
if varname == "tv":
varnames=("T", "P", "PB", "QVAPOR")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
varnames = ("T", "P", "PB", "QVAPOR")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
t = ncvars["T"]
p = ncvars["P"]
pb = ncvars["PB"]
qv = ncvars["QVAPOR"]
full_t = t + Constants.T_BASE
full_p = p + pb
tkel = tk(full_p, full_t)
return (tkel, qv)
if varname == "twb":
varnames=("T", "P", "PB", "QVAPOR")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
varnames = ("T", "P", "PB", "QVAPOR")
ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
t = ncvars["T"]
p = ncvars["P"]
pb = ncvars["PB"]
qv = ncvars["QVAPOR"]
full_t = t + Constants.T_BASE
full_p = p + pb
tkel = tk(full_p, full_t)
return (full_p, tkel, qv)
if varname == "uvmet":
varname = "U"
u_vars = extract_vars(wrfnc, timeidx, varname, method, squeeze,
u_vars = extract_vars(wrfnc, timeidx, varname, method, squeeze,
cache=None, meta=True)
u = destagger(u_vars[varname], -1, meta=True)
varname = "V"
v_vars = extract_vars(wrfnc, timeidx, varname, method, squeeze,
v_vars = extract_vars(wrfnc, timeidx, varname, method, squeeze,
cache=None, meta=True)
v = destagger(v_vars[varname], -2, meta=True)
map_proj_attrs = extract_global_attrs(wrfnc, attrs="MAP_PROJ")
map_proj = map_proj_attrs["MAP_PROJ"]
if map_proj in (0,3,6):
if map_proj in (0, 3, 6):
raise ProjectionError("Map projection does not need rotation")
elif map_proj in (1,2):
elif map_proj in (1, 2):
lat_attrs = extract_global_attrs(wrfnc, 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(wrfnc, attrs="STAND_LON")
except AttributeError:
try:
cen_lon_attrs = extract_global_attrs(wrfnc, attrs="CEN_LON")
cen_lon_attrs = extract_global_attrs(wrfnc,
attrs="CEN_LON")
except AttributeError:
raise RuntimeError("longitude attributes not found in NetCDF")
raise RuntimeError("longitude attributes not found in "
"NetCDF")
else:
cen_lon = cen_lon_attrs["CEN_LON"]
else:
cen_lon = lon_attrs["STAND_LON"]
varname = "XLAT"
xlat_var = extract_vars(wrfnc, timeidx, varname,
xlat_var = extract_vars(wrfnc, timeidx, varname,
method, squeeze, cache=None, meta=True)
lat = xlat_var[varname]
varname = "XLONG"
xlon_var = extract_vars(wrfnc, timeidx, varname,
xlon_var = extract_vars(wrfnc, timeidx, varname,
method, squeeze, cache=None, meta=True)
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)
cone = sin(fabs(true_lat1) * radians_per_degree)
else:
cone = 1
return (u, v, lat, lon, cen_lon, cone)
if varname == "cloudfrac":
from wrf.g_geoht import get_height
vars = extract_vars(wrfnc, timeidx, ("P", "PB", "QVAPOR", "T"),
method, squeeze, cache=None, meta=True)
varnames = ("P", "PB", "QVAPOR", "T")
vars = extract_vars(wrfnc, timeidx, varnames, method, squeeze,
cache=None, meta=True)
p = vars["P"]
pb = vars["PB"]
qv = vars["QVAPOR"]
t = vars["T"]
geoht_agl = get_height(wrfnc, timeidx, method, squeeze,
geoht_agl = get_height(wrfnc, timeidx, method, squeeze,
cache=None, meta=True, msl=False)
full_p = p + pb
full_t = t + Constants.T_BASE
tkel = tk(full_p, full_t)
relh = rh(qv, full_p, tkel)
return (geoht_agl, relh, 1, 300., 2000., 6000.)
class WRFVarsTest(ut.TestCase):
longMessage = True
def make_func(varname, wrfnc, timeidx, method, squeeze, meta):
def func(self):
try:
args = get_args(varname, wrfnc, timeidx, method, squeeze)
except ProjectionError: # Don't fail for this
except ProjectionError: # Don't fail for this
return
routine = ROUTINE_MAP[varname]
kwargs = {"meta" : meta}
kwargs = {"meta": meta}
result = routine(*args, **kwargs)
ref = getvar(wrfnc, varname, timeidx, method, squeeze, cache=None,
ref = getvar(wrfnc, varname, timeidx, method, squeeze, cache=None,
meta=meta)
nt.assert_allclose(to_np(result), to_np(ref))
if meta:
self.assertEqual(result.dims, ref.dims)
return func
def test_cape3d_1d(wrfnc):
def func(self):
varnames = ("T", "P", "PB", "QVAPOR", "PH", "PHB", "HGT", "PSFC")
ncvars = extract_vars(wrfnc, 0, varnames, method="cat", squeeze=True,
ncvars = extract_vars(wrfnc, 0, varnames, method="cat", squeeze=True,
cache=None, meta=True)
t = ncvars["T"]
p = ncvars["P"]
pb = ncvars["PB"]
@ -561,9 +579,9 @@ def test_cape3d_1d(wrfnc): @@ -561,9 +579,9 @@ def test_cape3d_1d(wrfnc):
phb = ncvars["PHB"]
ter = ncvars["HGT"]
psfc = ncvars["PSFC"]
col_idxs = (slice(None), t.shape[-2]//2, t.shape[-1]//2)
t = t[col_idxs]
p = p[col_idxs]
pb = pb[col_idxs]
@ -572,40 +590,40 @@ def test_cape3d_1d(wrfnc): @@ -572,40 +590,40 @@ def test_cape3d_1d(wrfnc):
phb = phb[col_idxs]
ter = float(ter[col_idxs[1:]])
psfc = float(psfc[col_idxs[1:]])
full_t = t + Constants.T_BASE
full_p = p + pb
tkel = tk(full_p, full_t, meta=False)
geopt = ph + phb
geopt_unstag = destagger(geopt, -1)
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
result = cape_3d(p_hpa, tkel, qv, z, ter, psfc_hpa, ter_follow)
ref = getvar(wrfnc, "cape_3d")
ref = ref[(slice(None),) + col_idxs]
nt.assert_allclose(to_np(result), to_np(ref))
return func
def test_cape2d_1d(wrfnc):
def func(self):
varnames = ("T", "P", "PB", "QVAPOR", "PH", "PHB", "HGT", "PSFC")
ncvars = extract_vars(wrfnc, 0, varnames, method="cat", squeeze=True,
ncvars = extract_vars(wrfnc, 0, varnames, method="cat", squeeze=True,
cache=None, meta=True)
t = ncvars["T"]
p = ncvars["P"]
pb = ncvars["PB"]
@ -614,9 +632,9 @@ def test_cape2d_1d(wrfnc): @@ -614,9 +632,9 @@ def test_cape2d_1d(wrfnc):
phb = ncvars["PHB"]
ter = ncvars["HGT"]
psfc = ncvars["PSFC"]
col_idxs = (slice(None), t.shape[-2]//2, t.shape[-1]//2)
t = t[col_idxs]
p = p[col_idxs]
pb = pb[col_idxs]
@ -625,82 +643,74 @@ def test_cape2d_1d(wrfnc): @@ -625,82 +643,74 @@ def test_cape2d_1d(wrfnc):
phb = phb[col_idxs]
ter = float(ter[col_idxs[1:]])
psfc = float(psfc[col_idxs[1:]])
full_t = t + Constants.T_BASE
full_p = p + pb
tkel = tk(full_p, full_t, meta=False)
geopt = ph + phb
geopt_unstag = destagger(geopt, -1)
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
result = cape_2d(p_hpa, tkel, qv, z, ter, psfc_hpa, ter_follow)
ref = getvar(wrfnc, "cape_2d")
ref = ref[(slice(None),) + col_idxs[1:]]
nt.assert_allclose(to_np(result), to_np(ref))
return func
if __name__ == "__main__":
from wrf import (omp_set_num_threads, omp_set_schedule, omp_get_schedule,
from wrf import (omp_set_num_threads, omp_set_schedule, omp_get_schedule,
omp_set_dynamic, omp_get_num_procs, OMP_SCHED_STATIC)
omp_set_num_threads(omp_get_num_procs()//2)
omp_set_schedule(OMP_SCHED_STATIC, 0)
omp_set_dynamic(False)
varnames = ["avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz",
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure",
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc",
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va",
"wa", "uvmet10", "uvmet", "z", "cloudfrac"]
#varnames = ["helicity"]
varnames=["avo", "pvo", "eth", "dbz", "helicity", "updraft_helicity",
"omg", "pw", "rh", "slp", "td", "tk", "tv", "twb", "uvmet",
"cloudfrac", "ctt"]
omp_set_num_threads(omp_get_num_procs()-1)
omp_set_schedule(OMP_SCHED_STATIC, 0)
omp_set_dynamic(False)
# Turn this one off when not needed, since it's slow
varnames += ["cape_2d", "cape_3d"]
for varname in varnames:
for i,wrfnc in enumerate((NCFILE, NCGROUP)):
for j,timeidx in enumerate((0, ALL_TIMES)):
for i, wrfnc in enumerate((NCFILE, NCGROUP)):
for j, timeidx in enumerate((0, ALL_TIMES)):
for method in ("cat", "join"):
for squeeze in (True, False):
for meta in (True, False):
func = make_func(varname, wrfnc, timeidx, method,
squeeze, meta)
func = make_func(varname, wrfnc, timeidx, method,
squeeze, meta)
ncname = "single" if i == 0 else "multi"
timename = "t0" if j == 0 else "all"
squeeze_name = "squeeze" if squeeze else "nosqueeze"
squeeze_name = ("squeeze" if squeeze
else "nosqueeze")
meta_name = "meta" if meta else "nometa"
test_name = "test_{}_{}_{}_{}_{}_{}".format(varname,
ncname, timename, method,
squeeze_name, meta_name)
test_name = "test_{}_{}_{}_{}_{}_{}".format(
varname, ncname, timename, method,
squeeze_name, meta_name)
setattr(WRFVarsTest, test_name, func)
func = test_cape3d_1d(wrfnc)
setattr(WRFVarsTest, "test_cape3d_1d", func)
func = test_cape2d_1d(wrfnc)
setattr(WRFVarsTest, "test_cape2d_1d", func)
ut.main()

17
test/ctt_test.py

@ -4,10 +4,12 @@ from matplotlib.cm import get_cmap @@ -4,10 +4,12 @@ from matplotlib.cm import get_cmap
import cartopy.crs as crs
from cartopy.feature import NaturalEarthFeature
from wrf import to_np, getvar, smooth2d, get_cartopy, cartopy_xlim, cartopy_ylim, latlon_coords
from wrf import (to_np, getvar, smooth2d, get_cartopy, cartopy_xlim,
cartopy_ylim, latlon_coords)
# Open the NetCDF file
ncfile = Dataset("/Users/ladwig/Documents/wrf_files/problem_files/cfrac_bug/wrfout_d02_1987-10-01_00:00:00")
ncfile = Dataset("/Users/ladwig/Documents/wrf_files/"
"problem_files/cfrac_bug/wrfout_d02_1987-10-01_00:00:00")
# Get the sea level pressure
ctt = getvar(ncfile, "ctt")
@ -19,20 +21,23 @@ lats, lons = latlon_coords(ctt) @@ -19,20 +21,23 @@ lats, lons = latlon_coords(ctt)
cart_proj = get_cartopy(ctt)
# Create a figure
fig = plt.figure(figsize=(12,9))
fig = plt.figure(figsize=(12, 9))
# Set the GeoAxes to the projection used by WRF
ax = plt.axes(projection=cart_proj)
# Download and add the states and coastlines
states = NaturalEarthFeature(category='cultural', scale='50m', facecolor='none',
states = NaturalEarthFeature(category='cultural', scale='50m',
facecolor='none',
name='admin_1_states_provinces_shp')
ax.add_feature(states, linewidth=.5)
ax.coastlines('50m', linewidth=0.8)
# Make the contour outlines and filled contours for the smoothed sea level pressure.
# Make the contour outlines and filled contours for the smoothed sea level
# pressure.
plt.contour(to_np(lons), to_np(lats), to_np(ctt), 10, colors="black",
transform=crs.PlateCarree())
plt.contourf(to_np(lons), to_np(lats), to_np(ctt), 10, transform=crs.PlateCarree(),
plt.contourf(to_np(lons), to_np(lats), to_np(ctt), 10,
transform=crs.PlateCarree(),
cmap=get_cmap("jet"))
# Add a color bar

10
test/generator_test.py

@ -1,17 +1,19 @@ @@ -1,17 +1,19 @@
from __future__ import (absolute_import, division, print_function, unicode_literals)
from __future__ import (absolute_import, division, print_function,
unicode_literals)
from wrf import getvar
from netCDF4 import Dataset as nc
#ncfile = nc("/Users/ladwig/Documents/wrf_files/wrfout_d01_2016-02-25_18_00_00")
ncfile = nc("/Users/ladwig/Documents/wrf_files/wrfout_d01_2016-10-07_00_00_00")
def gen_seq():
wrfseq = [ncfile, ncfile, ncfile]
for wrf in wrfseq:
yield wrf
p_gen = getvar(gen_seq(), "P", method="join")
print(p_gen)
del p_gen

40
test/misc/extract_one_time.py

@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
from netCDF4 import Dataset
VARS_TO_KEEP = ("Times", "XLAT", "XLONG", "XLAT_U", "XLAT_V", "XLONG_U",
"XLONG_V", "U", "V", "W", "PH", "PHB", "T", "P", "PB", "Q2",
"T2", "PSFC", "U10", "V10", "XTIME", "QVAPOR", "QCLOUD",
"QGRAUP", "QRAIN", "QSNOW", "QICE", "MAPFAC_M", "MAPFAC_U",
"MAPFAC_V", "F", "HGT", "RAINC", "RAINSH", "RAINNC",
"I_RAINC", "I_RAINNC")
INPUT_FILE = "wrfout_d02_2005-08-28_00:00:00"
OUTPUT_FILE = "wrfout_problem_file"
DESIRED_TIME_INDEX = 0
with Dataset(INPUT_FILE) as infile, Dataset(OUTPUT_FILE, mode="w") as outfile:
# Copy the global attributes
outfile.setncatts(infile.__dict__)
# Copy Dimensions
for name, dimension in infile.dimensions.items():
if name != "Time":
dimsize = len(dimension)
outfile.createDimension(name, dimsize)
else:
outfile.createDimension(name, 1)
# Copy Variables
for name, variable in infile.variables.iteritems():
if name not in VARS_TO_KEEP:
continue
outvar = outfile.createVariable(name, variable.datatype,
variable.dimensions, zlib=True)
if len(variable.dimensions) > 1:
outvar[:] = variable[DESIRED_TIME_INDEX, :]
else:
outvar[:] = variable[DESIRED_TIME_INDEX]
outvar.setncatts(variable.__dict__)

70
test/misc/loop_and_fill_meta.py

@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
from __future__ import print_function, division
import os
import numpy as np
from netCDF4 import Dataset
from wrf import getvar, ALL_TIMES, to_np
import xarray
filename_list = ["/Users/ladwig/Documents/wrf_files/"
"wrf_vortex_single/wrfout_d02_2005-08-28_00:00:00",
"/Users/ladwig/Documents/wrf_files/wrf_vortex_single/"
"wrfout_d02_2005-08-28_03:00:00",
"/Users/ladwig/Documents/wrf_files/wrf_vortex_single/"
"wrfout_d02_2005-08-28_06:00:00",
"/Users/ladwig/Documents/wrf_files/wrf_vortex_single/"
"wrfout_d02_2005-08-28_09:00:00"]
result_shape = (4, 1, 96, 96)
# Let's get the first time so we can copy the metadata later
f = Dataset(filename_list[0])
# By setting squeeze to False, you'll get all the dimension names.
z1 = getvar(f, "T2", 0, squeeze=False)
xlat = getvar(f, "XLAT", 0)
xlong = getvar(f, "XLONG", 0)
z_final = np.empty(result_shape, np.float32)
# Modify this number if using more than 1 time per file
times_per_file = 1
data_times = []
xtimes = []
for timeidx in range(result_shape[0]):
# Compute the file index and the time index inside the file
fileidx = timeidx // times_per_file
file_timeidx = timeidx % times_per_file
f = Dataset(filename_list[fileidx])
z = getvar(f, "T2", file_timeidx)
t = getvar(f, "Times", file_timeidx)
xt = getvar(f, "xtimes", file_timeidx)
data_times.append(to_np(t))
xtimes.append(to_np(xt))
z_final[timeidx, :] = z[:]
f.close()
# Let's make the metadata. Dimension names should copy easily if you set
# sqeeze to False, otherwise you can just set them yourself is a tuple of
# dimension names. Since you wanted
# to keep the bottom_top dimension for this 2D variable (which is normally
# removed), I'm doing this manually.
z_dims = ["Time", "bottom_top", "south_north", "west_east"]
# Xarray doesn't copy coordinates easily (it always complains about shape
# mismatches), so do this manually
z_coords = {}
z_coords["Time"] = data_times
z_coords["XTIME"] = ("Time",), xtimes
z_coords["XLAT"] = ("south_north", "west_east"), xlat
z_coords["XLONG"] = ("south_north", "west_east"), xlong
z_name = "T2"
# Attributes copy nicely
z_attrs = {}
z_attrs.update(z1.attrs)
z_with_meta = xarray.DataArray(z_final, coords=z_coords, dims=z_dims,
attrs=z_attrs, name=z_name)

43
test/mocktest.py → test/misc/mocktest.py

@ -6,39 +6,48 @@ try: @@ -6,39 +6,48 @@ try:
except ImportError:
from mock import Mock as MagicMock
class Mock(MagicMock):
@classmethod
def __getattr__(cls, name):
return Mock()
MOCK_MODULES = ["numpy", "numpy.ma", "xarray", "cartopy",
MOCK_MODULES = ["numpy", "numpy.ma", "xarray", "cartopy",
"pandas", "matplotlib", "netCDF4", "mpl_toolkits.basemap",
"wrf._wrffortran"]
sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES)
consts = {"DEFAULT_FILL" : 9.9692099683868690E36,
"DEFAULT_FILL_INT8" : -127,
"DEFAULT_FILL_INT16" : -32767,
"DEFAULT_FILL_INT32" : -2147483647,
"DEFAULT_FILL_INT64" : -9223372036854775806,
"DEFAULT_FILL_FLOAT" : 9.9692099683868690E36,
"DEFAULT_FILL_DOUBLE" : 9.9692099683868690E36,
"fomp_sched_static" : 1,
"fomp_sched_dynamic" : 2,
"fomp_sched_guided" : 3,
"fomp_sched_auto" : 4}
consts = {"DEFAULT_FILL": 9.9692099683868690E36,
"DEFAULT_FILL_INT8": -127,
"DEFAULT_FILL_INT16": -32767,
"DEFAULT_FILL_INT32": -2147483647,
"DEFAULT_FILL_INT64": -9223372036854775806,
"DEFAULT_FILL_FLOAT": 9.9692099683868690E36,
"DEFAULT_FILL_DOUBLE": 9.9692099683868690E36,
"fomp_sched_static": 1,
"fomp_sched_dynamic": 2,
"fomp_sched_guided": 3,
"fomp_sched_auto": 4}
class MockWrfConstants(object):
def __init__(self):
self.__dict__ = consts
def mock_asscalar(val):
return float(val)
return float(val)
sys.modules["wrf._wrffortran"].wrf_constants = MockWrfConstants()
sys.modules["wrf._wrffortran"].omp_constants = MockWrfConstants()
sys.modules["numpy"].asscalar = mock_asscalar
import wrf
print (wrf.get_coord_pairs.__doc__)
try:
import wrf
except ImportError:
pass
print(wrf.get_coord_pairs.__doc__)

188
test/projtest.py → test/misc/projtest.py

@ -7,13 +7,15 @@ import matplotlib.cm as cm @@ -7,13 +7,15 @@ import matplotlib.cm as cm
from netCDF4 import Dataset as NetCDF
from wrf import get_proj_params
from wrf.projection import getproj, RotatedLatLon, PolarStereographic
PYNGL = True
try:
import Ngl
except ImportError:
PYNGL = False
BASEMAP = True
try:
import mpl_toolkits.basemap
@ -25,19 +27,15 @@ try: @@ -25,19 +27,15 @@ try:
from cartopy import crs, feature
except ImportError:
CARTOPY = False
from wrf import get_proj_params
from wrf.projection import getproj, RotatedLatLon, PolarStereographic
FILE_DIR = "/Users/ladwig/Documents/wrf_files/"
WRF_FILES = [
join(FILE_DIR, "norway", "geo_em.d01.nc"),
join(FILE_DIR, "rotated_pole", "EAS_geo_em.d01.nc"),
join(FILE_DIR, "rotated_pole", "EUR_geo_em.d01.nc"),
join(FILE_DIR,"wrfout_d01_2016-02-25_18_00_00"),
join(FILE_DIR, "wrfout_d01_2008-09-29_23-30-00"),
join(FILE_DIR, "wrfout_d01_2010-06-13_21:00:00")]
WRF_FILES = [join(FILE_DIR, "norway", "geo_em.d01.nc"),
join(FILE_DIR, "rotated_pole", "EAS_geo_em.d01.nc"),
join(FILE_DIR, "rotated_pole", "EUR_geo_em.d01.nc"),
join(FILE_DIR, "wrfout_d01_2016-02-25_18_00_00"),
join(FILE_DIR, "wrfout_d01_2008-09-29_23-30-00"),
join(FILE_DIR, "wrfout_d01_2010-06-13_21:00:00")]
def nz_proj():
@ -45,65 +43,68 @@ def nz_proj(): @@ -45,65 +43,68 @@ def nz_proj():
[-32.669853, -32.669853]])
lons = np.array([[163.839595, -179.693502],
[163.839595, -179.693502]])
params = {"MAP_PROJ" : 6,
"CEN_LAT" : -41.814869,
"CEN_LON" : 179.693502,
"TRUELAT1" : 0,
params = {"MAP_PROJ": 6,
"CEN_LAT": -41.814869,
"CEN_LON": 179.693502,
"TRUELAT1": 0,
"TRUELAT2": 0,
"MOAD_CEN_LAT" : -41.814869,
"STAND_LON" : 180.0 - 179.693502,
"POLE_LAT" : 48.185131,
"POLE_LON" : 0.0}
"MOAD_CEN_LAT": -41.814869,
"STAND_LON": 180.0 - 179.693502,
"POLE_LAT": 48.185131,
"POLE_LON": 0.0}
return lats, lons, RotatedLatLon(lats=lats, lons=lons, **params)
def argentina_proj():
lats = np.array([[-57.144064, -57.144064],
[-21.154470, -21.154470]])
lons = np.array([[-86.893797, -37.089724],
[-86.893797, -37.089724]])
params = {"MAP_PROJ" : 6,
"CEN_LAT" : -39.222954,
"CEN_LON" : -65.980109,
"TRUELAT1" : 0,
params = {"MAP_PROJ": 6,
"CEN_LAT": -39.222954,
"CEN_LON": -65.980109,
"TRUELAT1": 0,
"TRUELAT2": 0,
"MOAD_CEN_LAT" : -39.222954,
"STAND_LON" : 180.0 - -65.980109,
"POLE_LAT" : 90 + -39.222954,
"POLE_LON" : 0.0}
"MOAD_CEN_LAT": -39.222954,
"STAND_LON": 180.0 - -65.980109,
"POLE_LAT": 90 + -39.222954,
"POLE_LON": 0.0}
return lats, lons, RotatedLatLon(lats=lats, lons=lons, **params)
def south_polar_proj():
lats = np.array([[-30.0,-30.0],
[-30.0,-30.0]])
lats = np.array([[-30.0, -30.0],
[-30.0, -30.0]])
lons = np.array([[-120, 60],
[-120, 60]])
params = {"MAP_PROJ" : 2,
"CEN_LAT" : -90.0,
"CEN_LON" : 0,
"TRUELAT1" : -10.0,
"MOAD_CEN_LAT" : -90.0,
"STAND_LON" : 0}
params = {"MAP_PROJ": 2,
"CEN_LAT": -90.0,
"CEN_LON": 0,
"TRUELAT1": -10.0,
"MOAD_CEN_LAT": -90.0,
"STAND_LON": 0}
return lats, lons, PolarStereographic(lats=lats, lons=lons, **params)
def north_polar_proj():
lats = np.array([[30.0,30.0],
[30.0,30.0]])
lats = np.array([[30.0, 30.0],
[30.0, 30.0]])
lons = np.array([[-45, 140],
[-45, 140]])
params = {"MAP_PROJ" : 2,
"CEN_LAT" : 90.0,
"CEN_LON" : 10,
"TRUELAT1" : 10.0,
"MOAD_CEN_LAT" : 90.0,
"STAND_LON" : 10}
params = {"MAP_PROJ": 2,
"CEN_LAT": 90.0,
"CEN_LON": 10,
"TRUELAT1": 10.0,
"MOAD_CEN_LAT": 90.0,
"STAND_LON": 10}
return lats, lons, PolarStereographic(lats=lats, lons=lons, **params)
@ -112,21 +113,23 @@ def dateline_rot_proj(): @@ -112,21 +113,23 @@ def dateline_rot_proj():
[71.717521, 71.717521]])
lons = np.array([[170.332771, -153.456292],
[170.332771, -153.456292]])
params = {"MAP_PROJ" : 6,
"CEN_LAT" : 66.335764,
"CEN_LON" : -173.143792,
"TRUELAT1" : 0,
params = {"MAP_PROJ": 6,
"CEN_LAT": 66.335764,
"CEN_LON": -173.143792,
"TRUELAT1": 0,
"TRUELAT2": 0,
"MOAD_CEN_LAT" : 66.335764,
"STAND_LON" : 173.143792,
"POLE_LAT" : 90.0 - 66.335764,
"POLE_LON" : 180.0}
"MOAD_CEN_LAT": 66.335764,
"STAND_LON": 173.143792,
"POLE_LAT": 90.0 - 66.335764,
"POLE_LON": 180.0}
return lats, lons, RotatedLatLon(lats=lats, lons=lons, **params)
class WRFProjTest(ut.TestCase):
longMessage = True
def make_test(wrf_file=None, fixed_case=None):
if wrf_file is not None:
ncfile = NetCDF(wrf_file)
@ -144,75 +147,76 @@ def make_test(wrf_file=None, fixed_case=None): @@ -144,75 +147,76 @@ def make_test(wrf_file=None, fixed_case=None):
elif fixed_case == "north_polar":
lats, lons, proj = north_polar_proj()
elif fixed_case == "dateline_rot":
lats,lons,proj = dateline_rot_proj()
print ("wrf proj4: {}".format(proj.proj4()))
lats, lons, proj = dateline_rot_proj()
print("wrf proj4: {}".format(proj.proj4()))
if PYNGL:
# PyNGL plotting
wks_type = bytes("png")
wks = Ngl.open_wks(wks_type,bytes("pyngl_{}".format(name_suffix)))
wks = Ngl.open_wks(wks_type, bytes("pyngl_{}".format(name_suffix)))
mpres = proj.pyngl()
map = Ngl.map(wks,mpres)
map = Ngl.map(wks, mpres)
Ngl.delete_wks(wks)
if BASEMAP:
if BASEMAP:
# Basemap plotting
fig = plt.figure(figsize=(10,10))
ax = fig.add_axes([0.1,0.1,0.8,0.8])
fig = plt.figure(figsize=(10, 10))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
# Define and plot the meridians and parallels
min_lat = np.amin(lats)
max_lat = np.amax(lats)
min_lon = np.amin(lons)
max_lon = np.amax(lons)
parallels = np.arange(np.floor(min_lat), np.ceil(max_lat),
parallels = np.arange(np.floor(min_lat), np.ceil(max_lat),
(max_lat - min_lat)/5.0)
meridians = np.arange(np.floor(min_lon), np.ceil(max_lon),
meridians = np.arange(np.floor(min_lon), np.ceil(max_lon),
(max_lon - min_lon)/5.0)
bm = proj.basemap()
bm.drawcoastlines(linewidth=.5)
#bm.drawparallels(parallels,labels=[1,1,1,1],fontsize=10)
#bm.drawmeridians(meridians,labels=[1,1,1,1],fontsize=10)
print ("basemap proj4: {}".format(bm.proj4string))
# bm.drawparallels(parallels,labels=[1,1,1,1],fontsize=10)
# bm.drawmeridians(meridians,labels=[1,1,1,1],fontsize=10)
print("basemap proj4: {}".format(bm.proj4string))
plt.savefig("basemap_{}.png".format(name_suffix))
plt.close(fig)
if CARTOPY:
# Cartopy plotting
fig = plt.figure(figsize=(10,10))
ax = plt.axes([0.1,0.1,0.8,0.8], projection=proj.cartopy())
print ("cartopy proj4: {}".format(proj.cartopy().proj4_params))
fig = plt.figure(figsize=(10, 10))
ax = plt.axes([0.1, 0.1, 0.8, 0.8], projection=proj.cartopy())
print("cartopy proj4: {}".format(proj.cartopy().proj4_params))
ax.coastlines('50m', linewidth=0.8)
#print proj.x_extents()
#print proj.y_extents()
# print proj.x_extents()
# print proj.y_extents()
ax.set_xlim(proj.cartopy_xlim())
ax.set_ylim(proj.cartopy_ylim())
ax.gridlines()
plt.savefig("cartopy_{}.png".format(name_suffix))
plt.close(fig)
if __name__ == "__main__":
for wrf_file in WRF_FILES:
test_func = make_test(wrf_file=wrf_file)
setattr(WRFProjTest, "test_proj", test_func)
test_func2 = make_test(fixed_case="south_rot")
setattr(WRFProjTest, "test_south_rot", test_func2)
test_func3 = make_test(fixed_case="arg_rot")
setattr(WRFProjTest, "test_arg_rot", test_func3)
test_func4 = make_test(fixed_case="south_polar")
setattr(WRFProjTest, "test_south_polar", test_func4)
test_func5 = make_test(fixed_case="north_polar")
setattr(WRFProjTest, "test_north_polar", test_func5)
test_func6 = make_test(fixed_case="dateline_rot")
setattr(WRFProjTest, "test_dateline_rot", test_func6)
ut.main()
ut.main()

58
test/misc/quiver_test.py

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
from netCDF4 import Dataset
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.cm import get_cmap
import cartopy.crs as crs
from cartopy.feature import NaturalEarthFeature
from wrf import (getvar, interplevel, to_np, latlon_coords, get_cartopy,
cartopy_xlim, cartopy_ylim)
# Open the NetCDF file
ncfile = Dataset("wrfout_d01_2016-10-07_00_00_00")
# Extract the pressure and wind variables
p = getvar(ncfile, "pressure")
# Note: This is m/s.
ua = getvar(ncfile, "ua")
va = getvar(ncfile, "va")
# Interpolate u, and v winds to 950 hPa
u_950 = interplevel(ua, p, 950)
v_950 = interplevel(va, p, 950)
# Get the lat/lon coordinates
lats, lons = latlon_coords(u_950)
# Get the map projection information
cart_proj = get_cartopy(u_950)
# Create the figure
fig = plt.figure(figsize=(12, 9))
ax = plt.axes(projection=cart_proj)
# Download and add the states and coastlines
states = NaturalEarthFeature(category='cultural', scale='50m',
facecolor='none',
name='admin_1_states_provinces_shp')
ax.add_feature(states, linewidth=0.5)
ax.coastlines('50m', linewidth=0.8)
# Add the 950 hPa wind barbs, only plotting every 'thin'ed barb. Adjust thin
# as needed. Also, no scaling is done for the arrows, so you might need to
# mess with the scale argument.
thin = 50
plt.quiver(to_np(lons[::thin, ::thin]), to_np(lats[::thin, ::thin]),
to_np(u_950[::thin, ::thin]), to_np(v_950[::thin, ::thin]),
transform=crs.PlateCarree())
# Set the map bounds
ax.set_xlim(cartopy_xlim(u_950))
ax.set_ylim(cartopy_ylim(v_950))
ax.gridlines()
plt.title("Arrows")
plt.show()

14
test/reduce_file.py → test/misc/reduce_file.py

@ -13,22 +13,22 @@ for att_name in in_nc.ncattrs(): @@ -13,22 +13,22 @@ for att_name in in_nc.ncattrs():
# Copy Dimensions, but modify the vertical dimensions
for dimname, dim in in_nc.dimensions.iteritems():
out_nc.createDimension(dimname, len(dim))
# Copy Variables and their Attributes, using the reduced vertical dimension
for varname, var in in_nc.variables.iteritems():
if varname in ("T2", "XLAT", "XLONG", "XTIME"):
datatype = var.datatype
dimensions = var.dimensions
shape = var.shape
new_shape = shape
new_var = out_nc.createVariable(varname, datatype, dimensions)
new_var[:] = var[:]
for att_name in var.ncattrs():
setattr(new_var, att_name, getattr(var, att_name))
in_nc.close()
out_nc.close()
out_nc.close()

29
test/misc/snippet.py

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
def main():
bm = Basemap(projection="rotpole",
o_lat_p=36.0,
o_lon_p=180.0,
llcrnrlat=-10.590603,
urcrnrlat=46.591976,
llcrnrlon=-139.08585,
urcrnrlon=22.661009,
lon_0=-106.0,
rsphere=6370000,
resolution='l')
fig = plt.figure(figsize=(8, 8))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
bm.drawcoastlines(linewidth=.5)
print(bm.proj4string)
plt.savefig("basemap_map.png")
plt.close(fig)
if __name__ == "__main__":
main()

34
test/varcache.py → test/misc/varcache.py

@ -4,33 +4,37 @@ import time @@ -4,33 +4,37 @@ import time
from netCDF4 import Dataset
from wrf import getvar, ALL_TIMES, extract_vars
wrf_filenames = ["/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/moving_nest/wrfout_d02_2005-08-28_00:00:00",
"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/moving_nest/wrfout_d02_2005-08-28_12:00:00",
"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/moving_nest/wrfout_d02_2005-08-29_00:00:00"]
wrf_filenames = ["/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/"
"moving_nest/wrfout_d02_2005-08-28_00:00:00",
"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/"
"moving_nest/wrfout_d02_2005-08-28_12:00:00",
"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/"
"moving_nest/wrfout_d02_2005-08-29_00:00:00"]
wrfin = [Dataset(x) for x in wrf_filenames]
my_cache = extract_vars(wrfin, ALL_TIMES, ("P", "PB", "PH", "PHB", "T", "QVAPOR", "HGT", "U", "V", "W", "PSFC"))
my_cache = extract_vars(wrfin, ALL_TIMES,
("P", "PB", "PH", "PHB", "T", "QVAPOR", "HGT", "U",
"V", "W", "PSFC"))
start = time.time()
for var in ("avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz",
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure",
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc",
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va",
for var in ("avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz",
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure",
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc",
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va",
"wa", "uvmet10", "uvmet", "z", "cfrac", "zstag", "geopt_stag"):
v = getvar(wrfin, var, ALL_TIMES)
end = time.time()
print ("Time taken without variable cache: ", (end-start))
print("Time taken without variable cache: ", (end-start))
start = time.time()
for var in ("avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz",
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure",
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc",
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va",
for var in ("avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz",
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure",
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc",
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va",
"wa", "uvmet10", "uvmet", "z", "cfrac", "zstag", "geopt_stag"):
v = getvar(wrfin, var, ALL_TIMES, cache=my_cache)
end = time.time()
print ("Time taken with variable cache: ", (end-start))
print("Time taken with variable cache: ", (end-start))

19
test/viewtest.py → test/misc/viewtest.py

@ -1,26 +1,25 @@ @@ -1,26 +1,25 @@
# Test snippet for f2py
import numpy as np
import wrf._wrffortran
errlen = int(wrf._wrffortran.constants.errlen)
a = np.ones((3,3,3))
b = np.zeros((3,3,3,3))
a = np.ones((3, 3, 3))
b = np.zeros((3, 3, 3, 3))
c = np.zeros(errlen, "c")
errstat = np.array(0)
errmsg = np.zeros(errlen, "c")
c[:] = "Test String"
for i in xrange(2):
outview = b[i,:]
outview = b[i, :]
outview = outview.T
q = wrf._wrffortran.testfunc(a,outview,c,errstat=errstat,errmsg=errmsg)
print errstat
q = wrf._wrffortran.testfunc(a, outview, c, errstat=errstat,
errmsg=errmsg)
print(errstat)
str_bytes = (bytes(char).decode("utf-8") for char in errmsg[:])
print repr(errmsg)
print "".join(str_bytes).strip()
print(repr(errmsg))
print("".join(str_bytes).strip())

230
test/misc/wps.py

@ -0,0 +1,230 @@ @@ -0,0 +1,230 @@
# Hastily made script to read WPS intermediate files
from __future__ import print_function
import struct
import numpy as np
# Number of bytes used at the start and end of a fortran record to
# indicate the record size
SIZE_BYTES = 4
class WPSData(object):
def __init__(self, ifv=None, hdate=None, xfcst=None, map_source=None,
field=None, units=None, desc=None, xlvl=None, nx=None,
ny=None, iproj=None, startloc=None, startlat=None,
startlon=None, deltalat=None, deltalon=None, nlats=None,
dx=None, dy=None, xlonc=None, truelat1=None, truelat2=None,
earth_radius=None, is_wind_earth_rel=None, slab=None):
self.ifv = ifv
self.hdate = hdate
self.xfcst = xfcst
self.map_source = map_source
self.field = field
self.units = units
self.desc = desc
self.xlvl = xlvl
self.nx = nx
self.ny = ny
self.iproj = iproj
self.startloc = startloc
self.startlat = startlat
self.startlon = startlon
self.deltalat = deltalat
self.deltalon = deltalon
self.nlats = nlats
self.dx = dx
self.dy = dy
self.xlonc = xlonc
self.truelat1 = truelat1
self.truelat2 = truelat2
self.earth_radius = earth_radius
self.is_wind_earth_rel = is_wind_earth_rel
self.slab = slab
def _parse_record1(data):
result = {}
result["ifv"] = struct.unpack(">i", data)
return result
def _parse_record2(data):
result = {}
parsed = struct.unpack(">24sf32s9s25s46sfiii", data)
result["hdate"] = parsed[0]
result["xfcst"] = parsed[1]
result["map_source"] = parsed[2]
result["field"] = parsed[3]
result["units"] = parsed[4]
result["desc"] = parsed[5]
result["xlvl"] = parsed[6]
result["nx"] = parsed[7]
result["ny"] = parsed[8]
result["iproj"] = parsed[9]
return result
def _parse_record3(data, iproj):
result = {}
if iproj == 0:
fmt = ">8sfffff"
parsed = struct.unpack(fmt, data)
result["startloc"] = parsed[0]
result["startlat"] = parsed[1]
result["startlon"] = parsed[2]
result["deltalat"] = parsed[3]
result["deltalon"] = parsed[4]
result["earth_radius"] = parsed[5]
elif iproj == 1:
fmt = ">8sffffff"
parsed = struct.unpack(fmt, data)
result["startloc"] = parsed[0]
result["startlat"] = parsed[1]
result["startlon"] = parsed[2]
result["dx"] = parsed[3]
result["dy"] = parsed[4]
result["truelat1"] = parsed[5]
result["earth_radius"] = parsed[6]
elif iproj == 3:
fmt = ">8sffffffff"
parsed = struct.unpack(fmt, data)
result["startloc"] = parsed[0]
result["startlat"] = parsed[1]
result["startlon"] = parsed[2]
result["dx"] = parsed[3]
result["dy"] = parsed[4]
result["xlonc"] = parsed[5]
result["truelat1"] = parsed[6]
result["truelat2"] = parsed[7]
result["earth_radius"] = parsed[8]
elif iproj == 4:
fmt = ">8sfffff"
parsed = struct.unpack(fmt, data)
result["startloc"] = parsed[0]
result["startlat"] = parsed[1]
result["startlon"] = parsed[2]
result["nlats"] = parsed[3]
result["deltalon"] = parsed[4]
result["earth_radius"] = parsed[5]
elif iproj == 5:
fmt = ">8sfffffff"
parsed = struct.unpack(fmt, data)
result["startloc"] = parsed[0]
result["startlat"] = parsed[1]
result["startlon"] = parsed[2]
result["dx"] = parsed[3]
result["dy"] = parsed[4]
result["xlonc"] = parsed[5]
result["truelat1"] = parsed[6]
result["earth_radius"] = parsed[7]
return result
def _parse_record4(data):
result = {}
result["is_wind_earth_rel"] = struct.unpack(">i", data)
return result
def _parse_record5(data, nx, ny):
result = {}
size = nx * ny
fmt = ">{}f".format(size)
parsed = struct.unpack(fmt, data)
arr = np.array(parsed, dtype=np.float32)
result["slab"] = arr.reshape((nx, ny), order="F")
return result
_PARSE_MAP = {0: _parse_record1,
1: _parse_record2,
2: _parse_record3,
3: _parse_record4,
4: _parse_record5}
def parse_record(record_idx, data, iproj=None, nx=None, ny=None):
if record_idx == 0 or record_idx == 1 or record_idx == 3:
return _PARSE_MAP[record_idx](data)
elif record_idx == 2:
return _PARSE_MAP[record_idx](data, iproj)
elif record_idx == 4:
return _PARSE_MAP[record_idx](data, nx, ny)
def read_wps(wps_file, field=None):
with open(wps_file, "rb") as f:
wps_params = {}
record_list = []
raw_data = f.read()
record_size_idx = 0
end_of_file_idx = len(raw_data) - 1
while True:
iproj = None
nx = None
ny = None
keep_record = True
for record_idx in range(5):
# Each record has the size (in SIZE_BYTES bytes) at the
# start and end of each record. This might be compiler
# dependent though, so this might need to be modified.
# Also, the WPS files are stored big endian.
record_size = struct.unpack(
">i",
raw_data[record_size_idx: record_size_idx + SIZE_BYTES])
record_start = record_size_idx + SIZE_BYTES
record_end = record_start + record_size[0]
record_data = raw_data[record_start:record_end]
parsed_record = parse_record(record_idx, record_data, iproj,
nx, ny)
try:
field_name = parsed_record["field"].strip()
except KeyError:
pass
else:
if field is not None:
if field_name != field:
keep_record = False
try:
iproj = parsed_record["iproj"]
except KeyError:
pass
try:
nx = parsed_record["nx"]
except KeyError:
pass
try:
ny = parsed_record["ny"]
except KeyError:
pass
wps_params.update(parsed_record)
record_size_idx = record_end + SIZE_BYTES
if keep_record:
record_list.append(WPSData(**wps_params))
# Repeat for all record slabs
if record_end + SIZE_BYTES > end_of_file_idx:
break
return record_list

0
test/listBug.ncl → test/ncl/listBug.ncl

30
test/ncl_get_var.ncl → test/ncl/ncl_get_var.ncl

@ -32,7 +32,9 @@ @@ -32,7 +32,9 @@
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure", \
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc", \
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va", \
"wa", "uvmet10", "uvmet", "z", "cfrac", "height_agl" /]
"wa", "uvmet10", "uvmet", "z", "cfrac", "height_agl", \
"wspd_wdir", "wspd_wdir10", "uvmet_wspd_wdir", \
"uvmet10_wspd_wdir" /]
unique_dimname_list = NewList("fifo")
unique_dimsize_list = NewList("fifo")
@ -87,7 +89,7 @@ @@ -87,7 +89,7 @@
xopt@timeidx = time
xopt@linecoords = True
ht_vertcross1 = wrf_user_vertcross(z, p, pivot, xopt)
ht_vertcross1 = wrf_user_vert_cross(z, p, pivot, xopt)
fout->ht_vertcross1 = ht_vertcross1
@ -100,7 +102,7 @@ @@ -100,7 +102,7 @@
xopt@timeidx = time
xopt@linecoords = True
ht_vertcross2 = wrf_user_vertcross(z, p, pivot, xopt)
ht_vertcross2 = wrf_user_vert_cross(z, p, pivot, xopt)
ht_vertcross2!1 = "vertical2"
ht_vertcross2!2 = "cross_line_idx2"
@ -131,7 +133,7 @@ @@ -131,7 +133,7 @@
xopt@linecoords = True
xopt@autolevels = 1000
ht_vertcross3 = wrf_user_vertcross(z, p, start_end, xopt)
ht_vertcross3 = wrf_user_vert_cross(z, p, start_end, xopt)
ht_vertcross3!0 = "Time"
ht_vertcross3!1 = "vertical3"
@ -150,7 +152,7 @@ @@ -150,7 +152,7 @@
p_var := p(i,:,:,:)
z_var := z(i,:,:,:)
ht_vertcross := wrf_user_vertcross(z_var, p_var, start_end, xopt)
ht_vertcross := wrf_user_vert_cross(z_var, p_var, start_end, xopt)
dim0name = sprinti("vertical_t%i",i)
dim1name = sprinti("cross_line_idx_t%i",i)
@ -190,8 +192,8 @@ @@ -190,8 +192,8 @@
plev := 500. ; 500 MB
hlev := 5000 ; 5000 m
z2_500 = wrf_user_interplevel(z,p,plev,False)
p2_5000 = wrf_user_interplevel(p,z,hlev,False)
z2_500 = wrf_user_interp_level(z,p,plev,False)
p2_5000 = wrf_user_interp_level(p,z,hlev,False)
fout->z2_500 = z2_500
fout->p2_5000 = p2_5000
@ -199,8 +201,8 @@ @@ -199,8 +201,8 @@
plev := (/1000., 850., 500., 250./)
hlev := (/500., 2500., 5000., 10000. /)
z2_multi = wrf_user_interplevel(z,p,plev,False)
p2_multi = wrf_user_interplevel(p,z,hlev,False)
z2_multi = wrf_user_interp_level(z,p,plev,False)
p2_multi = wrf_user_interp_level(p,z,hlev,False)
fout->z2_multi = z2_multi
fout->p2_multi = p2_multi
@ -208,7 +210,7 @@ @@ -208,7 +210,7 @@
pblh = wrf_user_getvar(input_file, "PBLH", time)
opts := False
opts@inc2dlevs = True
p_lev2d = wrf_user_interplevel(p, z, pblh, opts)
p_lev2d = wrf_user_interp_level(p, z, pblh, opts)
fout->p_lev2d = p_lev2d
@ -234,7 +236,7 @@ @@ -234,7 +236,7 @@
xopt@timeidx = 0
xopt@linecoords = True
t2_line2 = wrf_user_interpline(t2, pivot, xopt)
t2_line2 = wrf_user_interp_line(t2, pivot, xopt)
fout->t2_line2 = t2_line2
@ -257,7 +259,7 @@ @@ -257,7 +259,7 @@
xopt@timeidx = 0
xopt@linecoords = True
t2_line3 = wrf_user_interpline(t2, start_end, xopt)
t2_line3 = wrf_user_interp_line(t2, start_end, xopt)
t2_line3!1 = "line_idx_t2_line3"
fout->t2_line3 = t2_line3
@ -270,7 +272,7 @@ @@ -270,7 +272,7 @@
name = sprinti("t2_line_t%i", i)
dim0name = sprinti("lineidx_t%i",i)
var := t2(i,:,:)
t2_line := wrf_user_interpline(var, start_end, xopt)
t2_line := wrf_user_interp_line(var, start_end, xopt)
t2_line!0 = dim0name
fout->$name$ = t2_line
end do
@ -286,7 +288,7 @@ @@ -286,7 +288,7 @@
xopt@timeidx = 0
xopt@linecoords = True
t2_line4 = wrf_user_interpline(t2, start_end, xopt)
t2_line4 = wrf_user_interp_line(t2, start_end, xopt)
t2_line4!0 = "t2_line4_idx"
fout->t2_line4 = t2_line4

92
test/ncl/ncl_vertcross.ncl

@ -0,0 +1,92 @@ @@ -0,0 +1,92 @@
input_file = addfile("/Users/ladwig/Documents/wrf_files/wrfout_d02_2010-06-13_21:00:00.nc", "r")
z = wrf_user_getvar(input_file, "z", 0) ; grid point height
p = wrf_user_getvar(input_file, "pressure", 0) ; total pressure
dimsz = dimsizes(z)
pivot = (/ (dimsz(2)-1)/2, (dimsz(1)-1)/2 /) ; pivot point is center of domain
; For the new cross section routine
xopt = True
xopt@use_pivot = True
xopt@angle = 45.0
;xopt@levels =
;xopt@latlon =
xopt@file_handle = input_file
;xopt@timeidx =
xopt@linecoords = True
ht_vertcross = wrf_user_vertcross(z, p, pivot, xopt)
printVarSummary(ht_vertcross)
print(min(ht_vertcross@lats))
print(min(ht_vertcross@lons))
print(max(ht_vertcross@lats))
print(max(ht_vertcross@lons))
xopt@use_pivot = False
xopt@angle = 0.0
;xopt@levels =
xopt@latlon = True
xopt@file_handle = input_file
xopt@timeidx = 0
xopt@linecoords = True
loc_param = (/-104.3632, 32.8562, -95.15308, 40.06575 /) ; pivot point is center of domain
ht_vertcross2 = wrf_user_vertcross(z, p, loc_param, xopt)
printVarSummary(ht_vertcross2)
print(min(ht_vertcross2@lats))
print(min(ht_vertcross2@lons))
print(max(ht_vertcross2@lats))
print(max(ht_vertcross2@lons))
print(ht_vertcross2@lats(190))
print(ht_vertcross2@lons(190))
xopt@use_pivot = True
xopt@angle = 45.0
;xopt@levels =
xopt@latlon = True
xopt@file_handle = input_file
xopt@timeidx = 0
xopt@linecoords = True
loc_param := (/-99.98572, 36.54949 /) ; pivot point is center of domain
ht_vertcross3 = wrf_user_vertcross(z, p, loc_param, xopt)
printVarSummary(ht_vertcross3)
print(min(ht_vertcross3@lats))
print(min(ht_vertcross3@lons))
print(max(ht_vertcross3@lats))
print(max(ht_vertcross3@lons))
xopt@use_pivot = True
xopt@angle = 45.0
xopt@levels = (/1000., 850., 700., 500., 250. /)
xopt@latlon = True
xopt@file_handle = input_file
xopt@timeidx = 0
xopt@linecoords = True
loc_param := (/-99.98572, 36.54949 /) ; pivot point is center of domain
ht_vertcross4 = wrf_user_vertcross(z, p, loc_param, xopt)
printVarSummary(ht_vertcross4)
print(min(ht_vertcross4@lats))
print(min(ht_vertcross4@lons))
print(max(ht_vertcross4@lats))
print(max(ht_vertcross4@lons))
o = True
o@returnInt = False
o@useTime = 0
l = wrf_user_ll_to_xy(input_file, -99.98572, 36.54949, o)
print(l)
l1 = wrf_user_xy_to_ll(input_file, l(1), l(0), o)
print(l1)

81
test/ncl/refl10_cross.ncl

@ -0,0 +1,81 @@ @@ -0,0 +1,81 @@
a = addfile("wrfout_d03_2017-04-03_06:00:00_ctrl","r")
time = 0
refl_10cm = wrf_user_getvar(a,"REFL_10CM",time)
z = wrf_user_getvar(a, "z", time)
lat = wrf_user_getvar(a, "lat", time)
lon = wrf_user_getvar(a, "lon", time)
; convert the lat/lon to x,y
start_lat = 20.9
start_lon = 92.5
end_lat = 29.2
end_lon = 92.5
opt = True
start_ij = wrf_user_ll_to_ij(a, start_lon, start_lat, opt)
start_ij = start_ij - 1
end_ij = wrf_user_ll_to_ij(a, end_lon, end_lat, opt)
end_ij = end_ij - 1
start_end = (/start_ij(0), start_ij(1), end_ij(0), end_ij(1)/)
lat_line = wrf_user_intrp2d(lat,start_end,0.0,True)
nlat = dimsizes(lat_line)
lon_line = wrf_user_intrp2d(lon,start_end,0.0,True)
refl_cross = wrf_user_intrp3d(refl_10cm,z,"v",start_end,0.,True)
; Need to make a vertical coordinate by using the same code as the
; cross section
; Currently, the vertical coordinate is not set, so let's do it
; manually. This will be fixed in the next version of NCL.
; If you want to set these levels yourself, you'll need to copy the
; code I sent before and manually set the levels in the cross section
; routine, then do it again here.
z_max = max(z)
z_min = 0.
dz = 0.01 * z_max
nlevels = tointeger( z_max/dz )
z_var2d = new( (/nlevels/), typeof(z))
z_var2d(0) = z_min
do i=1, nlevels-1
z_var2d(i) = z_var2d(0)+i*dz
end do
refl_cross&Vertical = z_var2d
wks = gsn_open_wks("png","cross")
cmap := read_colormap_file("BlAqGrYeOrReVi200")
cmap(0,:) = (/0,0,0,0/) ; make first color fully transparent
resx = True
resx@gsnMaximize = True
resx@lbLabelAutoStride = True ; default v6.1.0
resx@cnFillOn = True ; turn on color fill
resx@cnLinesOn = False ; turn lines on/off ; True is default
resx@cnLineLabelsOn = False ; turn line labels on/off ; True is default
resx@cnFillPalette = cmap
nLabels = 8 ; arbitrary
resx@tmXBLabels = new(nLabels,"string")
resx@tmXBMode = "Explicit"
resx@tmXBValues := toint(fspan(0,nlat-1,nLabels))
do i=0,nLabels-1
x = lon_line(i)
y = lat_line(i)
resx@tmXBLabels(i) = sprintf("%5.1f", y)+"~C~"+sprintf("%5.1f", x)
end do
resx@tiMainString = "Full South-North Grid Line X-Section"
plot1 = gsn_csm_contour(wks, refl_cross, resx )

26
test/ncl/rotated_test.ncl

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
;---Open file and calculate slp.
a = addfile("/Users/ladwig/Documents/wrf_files/rotated_pole_test.nc","r")
t2 = wrf_user_getvar(a,"T2",0)
;---Start the graphics
wks = gsn_open_wks("x11","wrf")
;---Set some graphical resources
res = True
res@gsnMaximize = True
res@cnFillOn = True
res@tfDoNDCOverlay = True ; This is necessary if you don't
; set sfXArray/sfYArray
;---Add additional map resources
res = wrf_map_resources(a,res)
;---Change some of the resources that were set (these were set to "gray")
res@mpGeophysicalLineColor = "black"
res@mpNationalLineColor = "black"
res@mpUSStateLineColor = "black"
plot = gsn_csm_contour_map(wks,t2,res)

21
test/ncl/test_this.ncl

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
ifils = systemfunc ("ls /Users/ladwig/Documents/wrf_files/wrf_vortex_single/wrfout_d02_*")
print(ifils)
a = addfiles(ifils, "r")
;a = addfile("/Users/ladwig/Documents/wrf_files/wrfout_d01_2010-06-13_21:00:00.nc", "r")
lats := (/22.0, 25.0, 27.0 /)
lons := (/-90.0, -87.5, -83.75 /)
opt = True
opt@useTime = -1
opt@returnI = False
xy = wrf_user_ll_to_xy(a, lons, lats, opt)
print(xy)
x_s = (/10, 50, 90 /)
y_s = (/10, 50, 90 /)
ll = wrf_user_xy_to_ll(a, x_s, y_s, opt)
print(ll)

0
test/test_vinterp.ncl → test/ncl/test_vinterp.ncl

416
test/ncl/wrf_user_vertcross.ncl

@ -0,0 +1,416 @@ @@ -0,0 +1,416 @@
;--------------------------------------------------------------------------------
undef("wrf_user_ll_to_xy")
function wrf_user_ll_to_xy( file_handle, longitude:numeric, latitude:numeric, \
opts_args:logical )
; This is the same as wrf_user_ll_to_ij, but returns 0-based indexes
begin
;
; As of NCL V6.0.0, wrf_user_ll_to_ij can now handle a file
; or a list of files.
;
if(typeof(file_handle).eq."file") then
ISFILE = True
nc_file = file_handle
elseif(typeof(file_handle).eq."list") then
ISFILE = False
nc_file = file_handle[0]
else
print("wrf_user_ll_to_xy: Error: the first argument must be a file or a list of files opened with addfile or addfiles")
return
end if
opts = opts_args
useT = get_res_value(opts,"useTime",0)
returnI= get_res_value(opts,"returnInt",True)
res = True
res@MAP_PROJ = nc_file@MAP_PROJ
res@TRUELAT1 = nc_file@TRUELAT1
res@TRUELAT2 = nc_file@TRUELAT2
res@STAND_LON = nc_file@STAND_LON
res@DX = nc_file@DX
res@DY = nc_file@DY
if (res@MAP_PROJ .eq. 6) then
res@POLE_LAT = nc_file@POLE_LAT
res@POLE_LON = nc_file@POLE_LON
res@LATINC = (res@DY*360.)/2.0/3.141592653589793/6370000.
res@LONINC = (res@DX*360.)/2.0/3.141592653589793/6370000.
else
res@POLE_LAT = 90.0
res@POLE_LON = 0.0
res@LATINC = 0.0
res@LONINC = 0.0
end if
if(isfilevar(nc_file,"XLAT"))
if(ISFILE) then
XLAT = nc_file->XLAT(useT,:,:)
XLONG = nc_file->XLONG(useT,:,:)
else
XLAT = file_handle[:]->XLAT
XLONG = file_handle[:]->XLONG
end if
else
if(ISFILE) then
XLAT = nc_file->XLAT_M(useT,:,:)
XLONG = nc_file->XLONG_M(useT,:,:)
else
XLAT = file_handle[:]->XLAT_M
XLONG = file_handle[:]->XLONG_M
end if
end if
if(dimsizes(dimsizes(XLAT)).eq.2) then
; Rank 2
res@REF_LAT = XLAT(0,0)
res@REF_LON = XLONG(0,0)
else
; Rank 3
res@REF_LAT = XLAT(useT,0,0)
res@REF_LON = XLONG(useT,0,0)
end if
res@KNOWNI = 1.0
res@KNOWNJ = 1.0
loc = wrf_ll_to_ij (longitude, latitude, res)
loc = loc - 1
if (dimsizes(dimsizes(loc)) .eq. 1) then
loc!0 = "x_y"
elseif (dimsizes(dimsizes(loc)) .eq. 2) then
loc!0 = "x_y"
loc!1 = "idx"
else ; Not currently supported
loc!0 = "x_y"
loc!1 = "domain_idx"
loc!2 = "idx"
end if
if ( returnI ) then
loci = new(dimsizes(loc),integer)
;loci@_FillValue = default_fillvalue("integer") ; was -999
loci = tointeger(loc + .5)
loci!0 = loc!0
return(loci)
else
return(loc)
end if
end
;--------------------------------------------------------------------------------
undef("wrf_user_xy_to_ll")
function wrf_user_xy_to_ll( file_handle, x:numeric, y:numeric, \
opts_args:logical )
begin
;
; As of NCL V6.0.0, wrf_user_ll_to_ij can now handle a file
; or a list of files.
;
if(typeof(file_handle).eq."file") then
ISFILE = True
nc_file = file_handle
elseif(typeof(file_handle).eq."list") then
ISFILE = False
nc_file = file_handle[0]
else
print("wrf_user_xy_to_ll: Error: the first argument must be a file or a list of files opened with addfile or addfiles")
return
end if
opts = opts_args
useT = get_res_value(opts,"useTime",0)
res = True
res@MAP_PROJ = nc_file@MAP_PROJ
res@TRUELAT1 = nc_file@TRUELAT1
res@TRUELAT2 = nc_file@TRUELAT2
res@STAND_LON = nc_file@STAND_LON
res@DX = nc_file@DX
res@DY = nc_file@DY
if (res@MAP_PROJ .eq. 6) then
res@POLE_LAT = nc_file@POLE_LAT
res@POLE_LON = nc_file@POLE_LON
res@LATINC = (res@DY*360.)/2.0/3.141592653589793/6370000.
res@LONINC = (res@DX*360.)/2.0/3.141592653589793/6370000.
else
res@POLE_LAT = 90.0
res@POLE_LON = 0.0
res@LATINC = 0.0
res@LONINC = 0.0
end if
if(isfilevar(nc_file,"XLAT")) then
if(ISFILE) then
XLAT = nc_file->XLAT(useT,:,:)
XLONG = nc_file->XLONG(useT,:,:)
else
XLAT = file_handle[:]->XLAT
XLONG = file_handle[:]->XLONG
end if
else
if(ISFILE) then
XLAT = nc_file->XLAT_M(useT,:,:)
XLONG = nc_file->XLONG_M(useT,:,:)
else
XLAT = file_handle[:]->XLAT_M
XLONG = file_handle[:]->XLONG_M
end if
end if
if(dimsizes(dimsizes(XLAT)).eq.2) then
; Rank 2
res@REF_LAT = XLAT(0,0)
res@REF_LON = XLONG(0,0)
else
; Rank 3
res@REF_LAT = XLAT(useT,0,0)
res@REF_LON = XLONG(useT,0,0)
end if
res@KNOWNI = 1.0
res@KNOWNJ = 1.0
; Convert to 1-based indexes for Fortran
new_x = x + 1
new_y = y + 1
loc = wrf_ij_to_ll (new_x,new_y,res)
if (dimsizes(dimsizes(loc)) .eq. 1) then
loc!0 = "lon_lat"
elseif (dimsizes(dimsizes(loc)) .eq. 2) then
loc!0 = "lon_lat"
loc!1 = "idx"
else ; Not currently supported
loc!0 = "lon_lat"
loc!1 = "domain_idx"
loc!2 = "idx"
end if
return(loc)
end
;--------------------------------------------------------------------------------
undef("wrf_user_vertcross")
function wrf_user_vertcross(var3d:numeric, z_in:numeric, \
loc_param:numeric, opts:logical )
; var3d - 3d field to interpolate (all input fields must be unstaggered)
; z_in - interpolate to this field (either p/z)
; loc_param - an array of 4 values representing the start point and end point
; for the cross section (start_x, start_y, end_x, end_y) OR a single
; point when opt@use_pivot is True representing the pivot point.
; The values can be in grid coordinates or lat/lon coordinates
; (start_x = start_lon, start_y = start_lat, ...). If using
; lat/lon coordinates, then opt@latlon must be True.
; opts - optional arguments
; use_pivot - set to True to indicate that loc_param and angle are used,
; otherwise loc_param is set to 4 values to indicate a start and
; end point
; angle - an angle for vertical plots - 90 represent a WE cross section,
; ignored if use_pivot is False.
; levels - the vertical levels to use in the same units as z_in. Set to
; False to automatically generate the number of levels specified
; by autolevels.
; latlon - set to True if the values in loc_param are latitude and longitude
; values rather than grid values
; file_handle - must be set to a file handle when latlon is True or
; linecoords is True, otherwise this is ignored.
; timeidx - the time index to use for moving nests when latlon is True. Set
; to 0 if the nest is not moving.
; linecoords - set to True to include the latitude and longitude coordinates
; for the cross section line in the output attributes.
; autolevels - set to the desired number of levels when levels are
; selected automatically (default 100).
begin
use_pivot = get_res_value(opts, "use_pivot", False)
angle = get_res_value(opts, "angle", 0.0)
levels = get_res_value(opts, "levels", new(1,integer))
latlon = get_res_value(opts, "latlon", False)
file_handle = get_res_value(opts, "file_handle", 0)
timeidx = get_res_value(opts, "timeidx", 0)
linecoords = get_res_value(opts, "linecoords", False)
nlevels = get_res_value(opts, "autolevels", 100)
dims = dimsizes(var3d)
nd = dimsizes(dims)
dimX = dims(nd-1)
dimY = dims(nd-2)
dimZ = dims(nd-3)
if ( nd .eq. 4 ) then
z = z_in(0,:,:,:)
else
z = z_in
end if
; Convert latlon to xy coordinates
if (use_pivot) then
if (latlon) then
opt = True
opt@returnInt = True
opt@useTime = timeidx
ij := wrf_user_ll_to_xy(file_handle, loc_param(0), loc_param(1), opt)
start_x = ij(0)
start_y = ij(1)
else
start_x = loc_param(0)
start_y = loc_param(1)
end if
else
if (latlon) then
opt = True
opt@returnInt = True
opt@useTime = timeidx
ij := wrf_user_ll_to_xy(file_handle, (/ loc_param(0), loc_param(2) /), (/ loc_param(1), loc_param(3) /), opt)
start_x = ij(0,0)
start_y = ij(1,0)
end_x = ij(0,1)
end_y = ij(1,1)
else
start_x = loc_param(0)
start_y = loc_param(1)
end_x = loc_param(2)
end_y = loc_param(3)
end if
end if
; get the lat/lons along the cross section line if requested
; set the cross section line coordinates if requested
if (linecoords) then
latname = "XLAT"
lonname = "XLONG"
if(.not. isfilevar(file_handle,"XLAT")) then
if(isfilevar(file_handle,"XLAT_M")) then
latname = "XLAT_M"
lonname = "XLONG_M"
end if
end if
latvar = _get_wrf_var(file_handle, latname, timeidx)
lonvar = _get_wrf_var(file_handle, lonname, timeidx)
if (use_pivot) then
loc := (/start_x, start_y/)
linelats = wrf_user_intrp2d(latvar, loc, angle, False)
linelons = wrf_user_intrp2d(lonvar, loc, angle, False)
else
loc := (/start_x, start_y, end_x, end_y /)
linelats = wrf_user_intrp2d(latvar, loc, angle, True)
linelons = wrf_user_intrp2d(lonvar, loc, angle, True)
end if
end if
; set vertical cross section
; Note for wrf_user_set_xy, opt is False when pivot and angle used.
if (use_pivot) then
xy = wrf_user_set_xy( z, start_x, start_y, \ ; assumes 0-based indexing in v6.5.0
0.0, 0.0, angle, False )
else
xy = wrf_user_set_xy( z, start_x, start_y, \ ; assumes 0-based indexing in v6.5.0
end_x, end_y, \
angle, True)
end if
xp = dimsizes(xy)
; first we interp z
var2dz = wrf_interp_2d_xy( z, xy)
; interp to constant z grid
if (all(ismissing(levels))) then
if(var2dz(0,0) .gt. var2dz(1,0) ) then ; monotonically decreasing coordinate
z_max = floor(max(z)/10)*10 ; bottom value
z_min = ceil(min(z)/10)*10 ; top value
dz = (1.0/nlevels) * (z_max - z_min)
;nlevels = tointeger( (z_max-z_min)/dz)
z_var2d = new( (/nlevels/), typeof(z))
z_var2d(0) = z_max
dz = -dz
else
z_max = max(z)
z_min = 0.
dz = (1.0/nlevels) * z_max
;nlevels = tointeger( z_max/dz )
z_var2d = new( (/nlevels/), typeof(z))
z_var2d(0) = z_min
end if
do i=1, nlevels-1
z_var2d(i) = z_var2d(0)+i*dz
end do
else
z_var2d = levels
nlevels = dimsizes(z_var2d)
end if
; interp the variable
if ( dimsizes(dims) .eq. 4 ) then
var2d = new( (/dims(0), nlevels, xp(0)/), typeof(var2dz))
do it = 0,dims(0)-1
var2dtmp = wrf_interp_2d_xy( var3d(it,:,:,:), xy)
do i=0,xp(0)-1
var2d(it,:,i) = wrf_interp_1d( var2dtmp(:,i), var2dz(:,i), z_var2d)
end do
end do
var2d!0 = var3d!0
var2d!1 = "vertical"
var2d!2 = "cross_line_idx"
else
var2d = new( (/nlevels, xp(0)/), typeof(var2dz))
var2dtmp = wrf_interp_2d_xy( var3d, xy)
do i=0,xp(0)-1
var2d(:,i) = wrf_interp_1d( var2dtmp(:,i), var2dz(:,i), z_var2d)
end do
var2d!0 = "vertical"
var2d!1 = "cross_line_idx"
end if
st_x = tointeger(xy(0,0)) ; + 1 (removed 1-based indexing in 6.5.0)
st_y = tointeger(xy(0,1)) ; + 1
ed_x = tointeger(xy(xp(0)-1,0)) ; + 1
ed_y = tointeger(xy(xp(0)-1,1)) ; + 1
if (.not. use_pivot) then
var2d@Orientation = "Cross-Section: (" + \
st_x + "," + st_y + ") to (" + \
ed_x + "," + ed_y + ")"
else
var2d@Orientation = "Cross-Section: (" + \
st_x + "," + st_y + ") to (" + \
ed_x + "," + ed_y + ") ; center=(" + \
start_x + "," + start_y + \
") ; angle=" + angle
end if
if (linecoords) then
var2d@lats = linelats
var2d@lons = linelons
end if
var2d&vertical = z_var2d
return(var2d)
end

30
test/snippet.py

@ -1,30 +0,0 @@ @@ -1,30 +0,0 @@
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
def main():
bm = Basemap(projection = "rotpole",
o_lat_p = 36.0,
o_lon_p = 180.0,
llcrnrlat = -10.590603,
urcrnrlat = 46.591976,
llcrnrlon = -139.08585,
urcrnrlon = 22.661009,
lon_0 = -106.0,
rsphere = 6370000,
resolution = 'l')
fig = plt.figure(figsize=(8,8))
ax = fig.add_axes([0.1,0.1,0.8,0.8])
bm.drawcoastlines(linewidth=.5)
print bm.proj4string
plt.savefig("basemap_map.png")
plt.close(fig)
if __name__ == "__main__":
main()

80
test/test_filevars.py

@ -1,77 +1,79 @@ @@ -1,77 +1,79 @@
import unittest as ut
import numpy.testing as nt
import numpy.testing as nt
import numpy as np
import numpy.ma as ma
import os, sys
import os
import sys
import subprocess
from wrf import getvar, ALL_TIMES
TEST_DIR = "/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/moving_nest"
TEST_FILENAMES = ["wrfout_d02_2005-08-28_00:00:00",
"wrfout_d02_2005-08-28_12:00:00",
"wrfout_d02_2005-08-29_00:00:00"]
"wrfout_d02_2005-08-28_12:00:00",
"wrfout_d02_2005-08-29_00:00:00"]
TEST_FILES = [os.path.join(TEST_DIR, x) for x in TEST_FILENAMES]
# Python 3
if sys.version_info > (3,):
xrange = range
class WRFFileVarsTest(ut.TestCase):
longMessage = True
def make_test(ncfiles, varname):
def test(self):
#import time
#very_start = time.time()
#start = time.time()
# import time
# very_start = time.time()
# start = time.time()
t1 = getvar(ncfiles, varname, 0)
#end = time.time()
#print ("t1: ", start-end)
#start = time.time()
# end = time.time()
# print("t1: ", start-end)
# start = time.time()
t2 = getvar(ncfiles, varname, 0, meta=False)
#end = time.time()
#print ("t2: ", start-end)
#start = time.time()
# end = time.time()
# print("t2: ", start-end)
# start = time.time()
t3 = getvar(ncfiles, varname, ALL_TIMES)
#end = time.time()
#print ("t3: ", start-end)
#start = time.time()
# end = time.time()
# print("t3: ", start-end)
# start = time.time()
t4 = getvar(ncfiles, varname, ALL_TIMES, meta=False)
#end = time.time()
#print ("t4: ", start-end)
#start = time.time()
# end = time.time()
# print("t4: ", start-end)
# start = time.time()
t5 = getvar(ncfiles, varname, ALL_TIMES, method="join")
#end = time.time()
#print ("t5: ", start-end)
#start = time.time()
# end = time.time()
# print("t5: ", start-end)
# start = time.time()
t6 = getvar(ncfiles, varname, ALL_TIMES, method="join", meta=False)
#end = time.time()
#print ("t6: ", start-end)
#start = time.time()
#print ("Total Time: ", (end-start))
# end = time.time()
# print("t6: ", start-end)
# start = time.time()
# print("Total Time: ", (end-start))
return test
if __name__ == "__main__":
from netCDF4 import Dataset
ncfiles = [Dataset(x) for x in TEST_FILES]
#import scipy.io
#ncfiles = [scipy.io.netcdf.netcdf_file(x) for x in TEST_FILES]
# import scipy.io
# ncfiles = [scipy.io.netcdf.netcdf_file(x) for x in TEST_FILES]
file_vars = ncfiles[0].variables.keys()
ignore_vars = []
for var in file_vars:
if var in ignore_vars:
continue
test_func1 = make_test(ncfiles, var)
setattr(WRFFileVarsTest, 'test_{0}'.format(var), test_func1)
ut.main()
ut.main()

103
test/test_inputs.py

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import unittest as ut
import numpy.testing as nt
import numpy.testing as nt
import numpy as np
import numpy.ma as ma
import os
@ -17,20 +17,21 @@ TEST_FILES = [os.path.join(IN_DIR, "wrfout_d02_2005-08-28_00:00:00"), @@ -17,20 +17,21 @@ TEST_FILES = [os.path.join(IN_DIR, "wrfout_d02_2005-08-28_00:00:00"),
os.path.join(IN_DIR, "wrfout_d02_2005-08-28_12:00:00"),
os.path.join(IN_DIR, "wrfout_d02_2005-08-29_00:00:00")]
def wrfin_gen(wrf_in):
for x in wrf_in:
yield x
class wrf_in_iter_class(object):
def __init__(self, wrf_in):
self._wrf_in = wrf_in
self._total = len(wrf_in)
self._i = 0
def __iter__(self):
return self
def next(self):
if self._i >= self._total:
raise StopIteration
@ -38,7 +39,7 @@ class wrf_in_iter_class(object): @@ -38,7 +39,7 @@ class wrf_in_iter_class(object):
result = self._wrf_in[self._i]
self._i += 1
return result
# Python 3
def __next__(self):
return self.next()
@ -48,34 +49,34 @@ def make_test(varname, wrf_in): @@ -48,34 +49,34 @@ def make_test(varname, wrf_in):
def test(self):
x = getvar(wrf_in, varname, 0)
xa = getvar(wrf_in, varname, None)
return test
def make_interp_test(varname, wrf_in):
def test(self):
# Only testing vinterp since other interpolation just use variables
if (varname == "vinterp"):
for timeidx in (0, None):
eth = getvar(wrf_in, "eth", timeidx=timeidx)
interp_levels = [850,500,5]
field = vinterp(wrf_in,
field=eth,
vert_coord="pressure",
interp_levels=interp_levels,
extrapolate=True,
field_type="theta-e",
timeidx=timeidx,
interp_levels = [850, 500, 5]
field = vinterp(wrf_in,
field=eth,
vert_coord="pressure",
interp_levels=interp_levels,
extrapolate=True,
field_type="theta-e",
timeidx=timeidx,
log_p=True)
else:
pass
return test
def make_latlon_test(testid, wrf_in):
def test(self):
def test(self):
if testid == "xy_out":
# Lats/Lons taken from NCL script, just hard-coding for now
lats = [-55, -60, -65]
@ -87,42 +88,44 @@ def make_latlon_test(testid, wrf_in): @@ -87,42 +88,44 @@ def make_latlon_test(testid, wrf_in):
j_s = np.asarray([10, 100, 150], int)
ll = xy_to_ll(wrf_in, i_s, j_s, timeidx=0)
ll = xy_to_ll(wrf_in, i_s, j_s, timeidx=None)
return test
class WRFVarsTest(ut.TestCase):
longMessage = True
class WRFInterpTest(ut.TestCase):
longMessage = True
class WRFLatLonTest(ut.TestCase):
longMessage = True
if __name__ == "__main__":
from wrf import (omp_set_num_threads, omp_set_schedule, omp_get_schedule,
from wrf import (omp_set_num_threads, omp_set_schedule, omp_get_schedule,
omp_set_dynamic, omp_get_num_procs, OMP_SCHED_STATIC)
omp_set_num_threads(omp_get_num_procs()-1)
omp_set_schedule(OMP_SCHED_STATIC, 0)
omp_set_dynamic(False)
ignore_vars = [] # Not testable yet
wrf_vars = ["avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz",
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure",
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc",
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va",
wrf_vars = ["avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz",
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure",
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc",
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va",
"wa", "uvmet10", "uvmet", "z", "cfrac", "zstag", "geopt_stag"]
interp_methods = ["interplevel", "vertcross", "interpline", "vinterp"]
latlon_tests = ["xy_out", "ll_out"]
for nc_lib in ("netcdf4", "pynio", "scipy"):
if nc_lib == "netcdf4":
try:
from netCDF4 import Dataset
except ImportError:
print ("netcdf4-python not installed")
print("netcdf4-python not installed")
continue
else:
test_in = [Dataset(x) for x in TEST_FILES]
@ -130,52 +133,46 @@ if __name__ == "__main__": @@ -130,52 +133,46 @@ if __name__ == "__main__":
try:
from Nio import open_file
except ImportError:
print ("PyNIO not installed")
print("PyNIO not installed")
continue
else:
test_in = [open_file(x +".nc", "r") for x in TEST_FILES]
test_in = [open_file(x + ".nc", "r") for x in TEST_FILES]
elif nc_lib == "scipy":
try:
from scipy.io.netcdf import netcdf_file
except ImportError:
print ("scipy.io.netcdf not installed")
print("scipy.io.netcdf not installed")
else:
test_in = [netcdf_file(x, mmap=False) for x in TEST_FILES]
input0 = test_in[0]
input1 = test_in
input2 = tuple(input1)
input3 = wrfin_gen(test_in)
input4 = wrf_in_iter_class(test_in)
input5 = {"A" : input1,
"B" : input2}
input6 = {"A" : {"AA" : input1},
"B" : {"BB" : input2}}
for i,input in enumerate((input0, input1, input2,
input5 = {"A": input1,
"B": input2}
input6 = {"A": {"AA": input1},
"B": {"BB": input2}}
for i, input in enumerate((input0, input1, input2,
input3, input4, input5, input6)):
for var in wrf_vars:
if var in ignore_vars:
continue
test_func1 = make_test(var, input)
setattr(WRFVarsTest, "test_{0}_input{1}_{2}".format(nc_lib,
i, var),
test_func1)
setattr(WRFVarsTest, "test_{0}_input{1}_{2}".format(
nc_lib, i, var), test_func1)
for method in interp_methods:
test_interp_func1 = make_interp_test(method, input)
setattr(WRFInterpTest,
"test_{0}_input{1}_{2}".format(nc_lib,
i, method),
test_interp_func1)
setattr(WRFInterpTest, "test_{0}_input{1}_{2}".format(
nc_lib, i, method), test_interp_func1)
for testid in latlon_tests:
test_ll_func = make_latlon_test(testid, input)
test_name = "test_{0}_input{1}_{2}".format(nc_lib, i, testid)
setattr(WRFLatLonTest, test_name, test_ll_func)
ut.main()

42
test/test_multi_cache.py

@ -3,56 +3,60 @@ from wrf.cache import _get_cache @@ -3,56 +3,60 @@ from wrf.cache import _get_cache
from wrf import getvar
from netCDF4 import Dataset as nc
#a = nc("/Users/ladwig/Documents/wrf_files/wrf_vortex_single/wrfout_d02_2005-08-28_00:00:00")
#b = nc("/Users/ladwig/Documents/wrf_files/wrf_vortex_single/wrfout_d02_2005-08-28_03:00:00")
a = nc("/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/moving_nest/wrfout_d02_2005-08-28_00:00:00")
b = nc("/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/moving_nest/wrfout_d02_2005-08-28_12:00:00")
q = {"outoutoutout" : {"outoutout" : {"outout" : {"out1" : {"blah" : [a,b], "blah2" : [a,b]}, "out2" : {"blah" : [a,b], "blah2" : [a,b]} } } } }
a = nc("/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/moving_nest/"
"wrfout_d02_2005-08-28_00:00:00")
b = nc("/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/moving_nest/"
"wrfout_d02_2005-08-28_12:00:00")
q = {"outoutoutout":
{"outoutout":
{"outout":
{"out1": {"blah": [a, b], "blah2": [a, b]},
"out2": {"blah": [a, b], "blah2": [a, b]}}}}}
t1 = time.time()
c = getvar(q, "rh", method="cat", timeidx=None, squeeze=True)
t2 = time.time()
print (c)
print ("time taken: {}".format((t2-t1)*1000.))
print(c)
print("time taken: {}".format((t2-t1)*1000.))
t1 = time.time()
c = getvar(q, "rh", method="cat", timeidx=None, squeeze=False)
t2 = time.time()
print (c)
print ("time taken: {}".format((t2-t1)*1000.))
print(c)
print("time taken: {}".format((t2-t1)*1000.))
t1 = time.time()
c = getvar(q, "rh", method="cat", timeidx=1, squeeze=True)
t2 = time.time()
print (c)
print ("time taken: {}".format((t2-t1)*1000.))
print(c)
print("time taken: {}".format((t2-t1)*1000.))
t1 = time.time()
c = getvar(q, "rh", method="cat", timeidx=1, squeeze=False)
t2 = time.time()
print(c)
print ("time taken: {}".format((t2-t1)*1000.))
print("time taken: {}".format((t2-t1)*1000.))
t1 = time.time()
c = getvar(q, "rh", method="join", timeidx=None, squeeze=True)
t2 = time.time()
print (c)
print ("time taken: {}".format((t2-t1)*1000.))
print(c)
print("time taken: {}".format((t2-t1)*1000.))
t1 = time.time()
c = getvar(q, "rh", method="join", timeidx=None, squeeze=False)
t2 = time.time()
print(c)
print ("time taken: {}".format((t2-t1)*1000.))
print("time taken: {}".format((t2-t1)*1000.))
t1 = time.time()
c = getvar(q, "rh", method="join", timeidx=1, squeeze=True)
t2 = time.time()
print (c)
print ("time taken: {}".format((t2-t1)*1000.))
print(c)
print("time taken: {}".format((t2-t1)*1000.))
t1 = time.time()
c = getvar(q, "rh", method="join", timeidx=1, squeeze=False)
t2 = time.time()
print (c)
print ("time taken: {}".format((t2-t1)*1000.))
print(c)
print("time taken: {}".format((t2-t1)*1000.))

91
test/test_omp.py

@ -1,16 +1,16 @@ @@ -1,16 +1,16 @@
from __future__ import (absolute_import, division, print_function,
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import unittest as ut
import numpy.testing as nt
import numpy.testing as nt
from wrf import (omp_set_num_threads, omp_get_num_threads,
from wrf import (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,
@ -20,103 +20,102 @@ from wrf import (omp_set_num_threads, omp_get_num_threads, @@ -20,103 +20,102 @@ from wrf import (omp_set_num_threads, omp_get_num_threads,
omp_unset_lock, omp_unset_nest_lock,
omp_test_lock, omp_test_nest_lock,
omp_get_wtime, omp_get_wtick,
OMP_SCHED_STATIC, OMP_SCHED_DYNAMIC,
OMP_SCHED_GUIDED, OMP_SCHED_AUTO)
OMP_SCHED_STATIC, OMP_SCHED_DYNAMIC,
OMP_SCHED_GUIDED, OMP_SCHED_AUTO)
class OmpTest(ut.TestCase):
longMessage = True
def test_locks(self):
l = omp_init_lock()
omp_set_lock(l)
omp_unset_lock(l)
omp_test_lock(l)
omp_destroy_lock(l)
lk = omp_init_lock()
omp_set_lock(lk)
omp_unset_lock(lk)
omp_test_lock(lk)
omp_destroy_lock(lk)
nl = omp_init_nest_lock()
omp_set_nest_lock(nl)
omp_unset_nest_lock(nl)
omp_test_nest_lock(nl)
omp_destroy_nest_lock(nl)
def test_thread_set(self):
omp_set_num_threads(4)
max_threads = omp_get_max_threads()
self.assertEqual(max_threads, 4)
num_threads = omp_get_num_threads()
self.assertEqual(num_threads, 1) # Always 1 outside of parallel region
# Always 1 outside of parallel region
self.assertEqual(num_threads, 1)
thread_num = omp_get_thread_num()
self.assertEqual(thread_num, 0) # Always 0 outside of parallel region
# Always 0 outside of parallel region
self.assertEqual(thread_num, 0)
num_procs = omp_get_num_procs()
in_parallel = omp_in_parallel()
self.assertFalse(in_parallel) # Always False outside of parallel region
# Always False outside of parallel region
self.assertFalse(in_parallel)
limit = omp_get_thread_limit()
def test_dynamic(self):
omp_set_dynamic(True)
dynamic = omp_get_dynamic()
self.assertTrue(dynamic)
omp_set_dynamic(False)
dynamic = omp_get_dynamic()
self.assertFalse(dynamic)
def test_nested(self):
omp_set_nested(True)
nested = omp_get_nested()
self.assertTrue(nested)
omp_set_nested(False)
nested = omp_get_nested()
self.assertFalse(nested)
def test_schedule(self):
omp_set_schedule(OMP_SCHED_STATIC, 100000)
kind, modifier = omp_get_schedule()
self.assertEqual(kind, OMP_SCHED_STATIC)
self.assertEqual(modifier, 100000)
omp_set_schedule(OMP_SCHED_DYNAMIC, 10000)
kind, modifier = omp_get_schedule()
self.assertEqual(kind, OMP_SCHED_DYNAMIC)
self.assertEqual(modifier, 10000)
omp_set_schedule(OMP_SCHED_GUIDED, 100)
omp_set_schedule(OMP_SCHED_GUIDED, 100)
kind, modifier = omp_get_schedule()
self.assertEqual(kind, OMP_SCHED_GUIDED)
self.assertEqual(modifier, 100)
omp_set_schedule(OMP_SCHED_AUTO, 10)
omp_set_schedule(OMP_SCHED_AUTO, 10)
kind, modifier = omp_get_schedule()
self.assertEqual(kind, OMP_SCHED_AUTO)
self.assertNotEqual(modifier, 10) # The modifier argument is ignored,
# so it will be set to the previous
# value of 100.
# The modifier argument is ignored,
# so it will be set to the previous
# value of 100.
self.assertNotEqual(modifier, 10)
def test_team_level(self):
omp_set_max_active_levels(10)
active_levels = omp_get_max_active_levels()
self.assertEqual(active_levels, 10)
level = omp_get_level()
ancestor_thread = omp_get_ancestor_thread_num(level)
team_size = omp_get_team_size(level)
active_level = omp_get_active_level()
in_final = omp_in_final()
def test_time(self):
wtime = omp_get_wtime()
wtick = omp_get_wtick()
if __name__ == "__main__":
ut.main()

454
test/test_proj_params.py

@ -1,314 +1,302 @@ @@ -1,314 +1,302 @@
import unittest as ut
import numpy.testing as nt
import numpy.testing as nt
import numpy as np
import numpy.ma as ma
import os, sys
import os
import sys
import subprocess
from wrf import xy_to_ll_proj, ll_to_xy_proj, to_np
class WRFLatLonProjTest(ut.TestCase):
longMessage = True
def make_test(xy_or_ll_out):
def test(self):
# Python 3
if sys.version_info > (3,):
if sys.version_info > (3, ):
assert_raises_regex = self.assertRaisesRegex
xrange = range
else:
assert_raises_regex = self.assertRaisesRegexp
if xy_or_ll_out == "xy":
# Test the required failures
with assert_raises_regex(ValueError, ".*map_proj.*" ):
ll_to_xy_proj(30,-110)
with assert_raises_regex(ValueError, ".*ref_lat.*" ):
ll_to_xy_proj(30,-110, map_proj=1)
with assert_raises_regex(ValueError, ".*ref_lon.*" ):
ll_to_xy_proj(30,-110, map_proj=1, ref_lat=45)
with assert_raises_regex(ValueError, ".*known_x.*" ):
ll_to_xy_proj(30,-110, map_proj=1, ref_lat=45.0,
ref_lon=-120.)
with assert_raises_regex(ValueError, ".*known_y.*" ):
ll_to_xy_proj(30,-110, map_proj=1, ref_lat=45.0,
with assert_raises_regex(ValueError, ".*map_proj.*"):
ll_to_xy_proj(30, -110)
with assert_raises_regex(ValueError, ".*ref_lat.*"):
ll_to_xy_proj(30, -110, map_proj=1)
with assert_raises_regex(ValueError, ".*ref_lon.*"):
ll_to_xy_proj(30, -110, map_proj=1, ref_lat=45)
with assert_raises_regex(ValueError, ".*known_x.*"):
ll_to_xy_proj(30, -110, map_proj=1, ref_lat=45.0,
ref_lon=-120.)
with assert_raises_regex(ValueError, ".*known_y.*"):
ll_to_xy_proj(30, -110, map_proj=1, ref_lat=45.0,
ref_lon=-120., known_x=1)
with assert_raises_regex(ValueError, ".*dx.*" ):
ll_to_xy_proj(30,-110, map_proj=1, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0)
####### Now test the projections
with assert_raises_regex(ValueError, ".*dx.*"):
ll_to_xy_proj(30, -110, map_proj=1, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0)
# Now test the projections
# Lambert Conformal - truelat1, stand_lon required
with assert_raises_regex(ValueError, ".*truelat1.*" ):
ll_to_xy_proj(30,-110, map_proj=1, ref_lat=45.0,
with assert_raises_regex(ValueError, ".*truelat1.*"):
ll_to_xy_proj(30, -110, map_proj=1, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
dx=3000.)
with assert_raises_regex(ValueError, ".*stand_lon.*" ):
ll_to_xy_proj(30,-110, map_proj=1, ref_lat=45.0,
dx=3000.)
with assert_raises_regex(ValueError, ".*stand_lon.*"):
ll_to_xy_proj(30, -110, map_proj=1, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
dx=3000.,
truelat1=60.)
truelat1=60.)
# Make sure it runs with all params set vs not
p_all = ll_to_xy_proj(28., -89., map_proj=1, ref_lat=17.803,
ref_lon=-100.7747, known_x=0, known_y=0,
dx=30000., truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=90., pole_lon=0.)
p_def = ll_to_xy_proj(28., -89., map_proj=1, ref_lat=17.803,
ref_lon=-100.7747, known_x=0, known_y=0,
dx=30000., truelat1=30.,
stand_lon=-89.)
p_all = ll_to_xy_proj(28., -89., map_proj=1, ref_lat=17.803,
ref_lon=-100.7747, known_x=0, known_y=0,
dx=30000., truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=90., pole_lon=0.)
p_def = ll_to_xy_proj(28., -89., map_proj=1, ref_lat=17.803,
ref_lon=-100.7747, known_x=0, known_y=0,
dx=30000., truelat1=30., stand_lon=-89.)
nt.assert_allclose(to_np(p_all), to_np(p_def))
# Polar Stereographic - truelat1, stand_lon
with assert_raises_regex(ValueError, ".*truelat1.*" ):
ll_to_xy_proj(30,-110, map_proj=2, ref_lat=45.0,
with assert_raises_regex(ValueError, ".*truelat1.*"):
ll_to_xy_proj(30, -110, map_proj=2, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
dx=3000.)
with assert_raises_regex(ValueError, ".*stand_lon.*" ):
ll_to_xy_proj(30,-110, map_proj=2, ref_lat=45.0,
dx=3000.)
with assert_raises_regex(ValueError, ".*stand_lon.*"):
ll_to_xy_proj(30, -110, map_proj=2, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
dx=3000.,
truelat1=60.)
p_all = ll_to_xy_proj(28., -89., map_proj=2, ref_lat=17.933,
ref_lon=-100.0735, known_x=0, known_y=0,
dx=30000., truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=90., pole_lon=0.)
p_def = ll_to_xy_proj(28., -89., map_proj=2, ref_lat=17.933,
ref_lon=-100.0735, known_x=0, known_y=0,
dx=30000., truelat1=30.,
stand_lon=-89.)
truelat1=60.)
p_all = ll_to_xy_proj(28., -89., map_proj=2, ref_lat=17.933,
ref_lon=-100.0735, known_x=0, known_y=0,
dx=30000., truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=90., pole_lon=0.)
p_def = ll_to_xy_proj(28., -89., map_proj=2, ref_lat=17.933,
ref_lon=-100.0735, known_x=0, known_y=0,
dx=30000., truelat1=30., stand_lon=-89.)
nt.assert_allclose(to_np(p_all), to_np(p_def))
# Mercator - truelat1
with assert_raises_regex(ValueError, ".*truelat1.*" ):
ll_to_xy_proj(30,-110, map_proj=2, ref_lat=45.0,
with assert_raises_regex(ValueError, ".*truelat1.*"):
ll_to_xy_proj(30, -110, map_proj=2, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
dx=3000.)
p_all = ll_to_xy_proj(28., -89., map_proj=3, ref_lat=19.1075,
ref_lon=-101.008, known_x=0, known_y=0,
dx=30000., truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=90., pole_lon=0.)
p_def = ll_to_xy_proj(28., -89., map_proj=3, ref_lat=19.1075,
ref_lon=-101.008, known_x=0, known_y=0,
dx=30000., truelat1=30.)
dx=3000.)
p_all = ll_to_xy_proj(28., -89., map_proj=3, ref_lat=19.1075,
ref_lon=-101.008, known_x=0, known_y=0,
dx=30000., truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=90., pole_lon=0.)
p_def = ll_to_xy_proj(28., -89., map_proj=3, ref_lat=19.1075,
ref_lon=-101.008, known_x=0, known_y=0,
dx=30000., truelat1=30.)
nt.assert_allclose(to_np(p_all), to_np(p_def))
# Lat/lon - stand_lon, dy, pole_lat, pole_lon
with assert_raises_regex(ValueError, ".*stand_lon.*" ):
ll_to_xy_proj(30,-110, map_proj=6, ref_lat=45.0,
with assert_raises_regex(ValueError, ".*stand_lon.*"):
ll_to_xy_proj(30, -110, map_proj=6, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
dx=.2698388)
with assert_raises_regex(ValueError, ".*dy.*" ):
ll_to_xy_proj(30,-110, map_proj=6, ref_lat=45.0,
dx=.2698388)
with assert_raises_regex(ValueError, ".*dy.*"):
ll_to_xy_proj(30, -110, map_proj=6, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
stand_lon=89.0,
dx=.2698388)
with assert_raises_regex(ValueError, ".*pole_lat.*" ):
ll_to_xy_proj(30,-110, map_proj=6, ref_lat=45.0,
dx=.2698388)
with assert_raises_regex(ValueError, ".*pole_lat.*"):
ll_to_xy_proj(30, -110, map_proj=6, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
stand_lon=89.0,
dx=.2698388, dy=.2698388)
with assert_raises_regex(ValueError, ".*pole_lon.*" ):
ll_to_xy_proj(30,-110, map_proj=6, ref_lat=45.0,
dx=.2698388, dy=.2698388)
with assert_raises_regex(ValueError, ".*pole_lon.*"):
ll_to_xy_proj(30, -110, map_proj=6, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
stand_lon=89.0,
dx=.2698388, dy=.2698388,
pole_lat=62.0)
p_all = ll_to_xy_proj(28.,-89., map_proj=6, ref_lat=17.6759,
ref_lon=-101.4286, known_x=0, known_y=0,
dx=30000, dy=30000,
truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=62.0,
pole_lon=180.)
p_def = ll_to_xy_proj(28., -89., map_proj=6, ref_lat=17.6759,
ref_lon=-101.4286, known_x=0, known_y=0,
stand_lon=-89.,
dx=30000, dy=30000, pole_lat=62.0,
pole_lon=180.)
pole_lat=62.0)
p_all = ll_to_xy_proj(28., -89., map_proj=6, ref_lat=17.6759,
ref_lon=-101.4286, known_x=0, known_y=0,
dx=30000, dy=30000,
truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=62.0,
pole_lon=180.)
p_def = ll_to_xy_proj(28., -89., map_proj=6, ref_lat=17.6759,
ref_lon=-101.4286, known_x=0, known_y=0,
stand_lon=-89.,
dx=30000, dy=30000, pole_lat=62.0,
pole_lon=180.)
nt.assert_allclose(to_np(p_all), to_np(p_def))
if xy_or_ll_out == "ll":
# Test the required failures
with assert_raises_regex(ValueError, ".*map_proj.*" ):
with assert_raises_regex(ValueError, ".*map_proj.*"):
xy_to_ll_proj(45, 50)
with assert_raises_regex(ValueError, ".*ref_lat.*" ):
xy_to_ll_proj(45, 50, map_proj=1)
with assert_raises_regex(ValueError, ".*ref_lon.*" ):
with assert_raises_regex(ValueError, ".*ref_lat.*"):
xy_to_ll_proj(45, 50, map_proj=1)
with assert_raises_regex(ValueError, ".*ref_lon.*"):
xy_to_ll_proj(45, 50, map_proj=1, ref_lat=45)
with assert_raises_regex(ValueError, ".*known_x.*" ):
xy_to_ll_proj(45, 50, map_proj=1, ref_lat=45.0,
ref_lon=-120.)
with assert_raises_regex(ValueError, ".*known_y.*" ):
xy_to_ll_proj(45, 50, map_proj=1, ref_lat=45.0,
with assert_raises_regex(ValueError, ".*known_x.*"):
xy_to_ll_proj(45, 50, map_proj=1, ref_lat=45.0,
ref_lon=-120.)
with assert_raises_regex(ValueError, ".*known_y.*"):
xy_to_ll_proj(45, 50, map_proj=1, ref_lat=45.0,
ref_lon=-120., known_x=1)
with assert_raises_regex(ValueError, ".*dx.*" ):
xy_to_ll_proj(45, 50, map_proj=1, ref_lat=45.0,
with assert_raises_regex(ValueError, ".*dx.*"):
xy_to_ll_proj(45, 50, map_proj=1, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0)
####### Now test the projections
# Now test the projections
# Lambert Conformal - truelat1, stand_lon required
with assert_raises_regex(ValueError, ".*truelat1.*" ):
xy_to_ll_proj(45, 50, map_proj=1, ref_lat=45.0,
with assert_raises_regex(ValueError, ".*truelat1.*"):
xy_to_ll_proj(45, 50, map_proj=1, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
dx=3000.)
with assert_raises_regex(ValueError, ".*stand_lon.*" ):
xy_to_ll_proj(45, 50, map_proj=1, ref_lat=45.0,
dx=3000.)
with assert_raises_regex(ValueError, ".*stand_lon.*"):
xy_to_ll_proj(45, 50, map_proj=1, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
dx=3000.,
truelat1=60.)
truelat1=60.)
# Make sure it runs with all params set vs not
p_all = xy_to_ll_proj(45, 50, map_proj=1, ref_lat=17.803,
ref_lon=-100.7747, known_x=0, known_y=0,
dx=30000., truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=90., pole_lon=0.)
p_def = xy_to_ll_proj(45, 50, map_proj=1, ref_lat=17.803,
ref_lon=-100.7747, known_x=0, known_y=0,
dx=30000., truelat1=30.,
stand_lon=-89.)
p_all = xy_to_ll_proj(45, 50, map_proj=1, ref_lat=17.803,
ref_lon=-100.7747, known_x=0, known_y=0,
dx=30000., truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=90., pole_lon=0.)
p_def = xy_to_ll_proj(45, 50, map_proj=1, ref_lat=17.803,
ref_lon=-100.7747, known_x=0, known_y=0,
dx=30000., truelat1=30.,
stand_lon=-89.)
nt.assert_allclose(to_np(p_all), to_np(p_def))
# Polar Stereographic - truelat1, stand_lon
with assert_raises_regex(ValueError, ".*truelat1.*" ):
xy_to_ll_proj(45, 50, map_proj=2, ref_lat=45.0,
with assert_raises_regex(ValueError, ".*truelat1.*"):
xy_to_ll_proj(45, 50, map_proj=2, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
dx=3000.)
with assert_raises_regex(ValueError, ".*stand_lon.*" ):
xy_to_ll_proj(45, 50, map_proj=2, ref_lat=45.0,
dx=3000.)
with assert_raises_regex(ValueError, ".*stand_lon.*"):
xy_to_ll_proj(45, 50, map_proj=2, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
dx=3000.,
truelat1=60.)
p_all = xy_to_ll_proj(45, 50, map_proj=2, ref_lat=17.933,
ref_lon=-100.0735, known_x=0, known_y=0,
dx=30000., truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=90., pole_lon=0.)
p_def = xy_to_ll_proj(45, 50, map_proj=2, ref_lat=17.933,
ref_lon=-100.0735, known_x=0, known_y=0,
dx=30000., truelat1=30.,
stand_lon=-89.)
truelat1=60.)
p_all = xy_to_ll_proj(45, 50, map_proj=2, ref_lat=17.933,
ref_lon=-100.0735, known_x=0, known_y=0,
dx=30000., truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=90., pole_lon=0.)
p_def = xy_to_ll_proj(45, 50, map_proj=2, ref_lat=17.933,
ref_lon=-100.0735, known_x=0, known_y=0,
dx=30000., truelat1=30.,
stand_lon=-89.)
nt.assert_allclose(to_np(p_all), to_np(p_def))
# Mercator - truelat1
with assert_raises_regex(ValueError, ".*truelat1.*" ):
xy_to_ll_proj(45, 50, map_proj=2, ref_lat=45.0,
with assert_raises_regex(ValueError, ".*truelat1.*"):
xy_to_ll_proj(45, 50, map_proj=2, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
dx=3000.)
p_all = xy_to_ll_proj(45, 50, map_proj=3, ref_lat=19.1075,
ref_lon=-101.008, known_x=0, known_y=0,
dx=30000., truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=90., pole_lon=0.)
p_def = xy_to_ll_proj(45, 50, map_proj=3, ref_lat=19.1075,
ref_lon=-101.008, known_x=0, known_y=0,
dx=30000., truelat1=30.)
dx=3000.)
p_all = xy_to_ll_proj(45, 50, map_proj=3, ref_lat=19.1075,
ref_lon=-101.008, known_x=0, known_y=0,
dx=30000., truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=90., pole_lon=0.)
p_def = xy_to_ll_proj(45, 50, map_proj=3, ref_lat=19.1075,
ref_lon=-101.008, known_x=0, known_y=0,
dx=30000., truelat1=30.)
nt.assert_allclose(to_np(p_all), to_np(p_def))
# Lat/lon - stand_lon, dy, pole_lat, pole_lon
with assert_raises_regex(ValueError, ".*stand_lon.*" ):
xy_to_ll_proj(45, 50, map_proj=6, ref_lat=45.0,
with assert_raises_regex(ValueError, ".*stand_lon.*"):
xy_to_ll_proj(45, 50, map_proj=6, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
dx=.2698388)
with assert_raises_regex(ValueError, ".*dy.*" ):
xy_to_ll_proj(45, 50, map_proj=6, ref_lat=45.0,
dx=.2698388)
with assert_raises_regex(ValueError, ".*dy.*"):
xy_to_ll_proj(45, 50, map_proj=6, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
stand_lon=89.0,
dx=.2698388)
with assert_raises_regex(ValueError, ".*pole_lat.*" ):
xy_to_ll_proj(45, 50, map_proj=6, ref_lat=45.0,
dx=.2698388)
with assert_raises_regex(ValueError, ".*pole_lat.*"):
xy_to_ll_proj(45, 50, map_proj=6, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
stand_lon=89.0,
dx=.2698388, dy=.2698388)
with assert_raises_regex(ValueError, ".*pole_lon.*" ):
xy_to_ll_proj(45, 50, map_proj=6, ref_lat=45.0,
dx=.2698388, dy=.2698388)
with assert_raises_regex(ValueError, ".*pole_lon.*"):
xy_to_ll_proj(45, 50, map_proj=6, ref_lat=45.0,
ref_lon=-120., known_x=0, known_y=0,
stand_lon=89.0,
dx=.2698388, dy=.2698388,
pole_lat=62.0)
p_all = xy_to_ll_proj(64, 40, map_proj=6, ref_lat=17.6759,
ref_lon=-101.4286, known_x=0, known_y=0,
dx=30000, dy=30000,
truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=62.0,
pole_lon=180.)
p_def = xy_to_ll_proj(64, 40, map_proj=6, ref_lat=17.6759,
ref_lon=-101.4286, known_x=0, known_y=0,
stand_lon=-89.,
dx=30000, dy=30000, pole_lat=62.0,
pole_lon=180.)
pole_lat=62.0)
p_all = xy_to_ll_proj(64, 40, map_proj=6, ref_lat=17.6759,
ref_lon=-101.4286, known_x=0, known_y=0,
dx=30000, dy=30000,
truelat1=30., truelat2=30.,
stand_lon=-89., pole_lat=62.0,
pole_lon=180.)
p_def = xy_to_ll_proj(64, 40, map_proj=6, ref_lat=17.6759,
ref_lon=-101.4286, known_x=0, known_y=0,
stand_lon=-89.,
dx=30000, dy=30000, pole_lat=62.0,
pole_lon=180.)
nt.assert_allclose(to_np(p_all), to_np(p_def))
return test
if __name__ == "__main__":
for v in ("xy", "ll"):
test_func = make_test(v)
setattr(WRFLatLonProjTest, 'test_{0}'.format(v), test_func)
ut.main()

33
test/test_units.py

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
import sys
import unittest as ut
import numpy.testing as nt
import numpy.testing as nt
import numpy as np
import numpy.ma as ma
from netCDF4 import Dataset as nc
@ -13,44 +13,43 @@ TEST_FILE = "/Users/ladwig/Documents/wrf_files/wrfout_d01_2010-06-13_21:00:00" @@ -13,44 +13,43 @@ TEST_FILE = "/Users/ladwig/Documents/wrf_files/wrfout_d01_2010-06-13_21:00:00"
# Python 3
if sys.version_info > (3,):
xrange = range
class TestUnits(ut.TestCase):
longMessage = True
def test_temp_units(self):
wrfnc = nc(TEST_FILE)
for units in ("K", "degC", "degF"):
var = getvar(wrfnc, "temp", units=units)
self.assertEqual(var.attrs["units"], units)
def test_wind_units(self):
wrfnc = nc(TEST_FILE)
for units in ("m s-1", "kt", "mi h-1", "km h-1", "ft s-1"):
var = getvar(wrfnc, "uvmet", units=units)
self.assertEqual(var.attrs["units"], units)
def test_pres_units(self):
wrfnc = nc(TEST_FILE)
for units in ("Pa", "hPa", "mb", "torr", "mmHg", "atm"):
var = getvar(wrfnc, "slp", units=units)
self.assertEqual(var.attrs["units"], units)
def test_height_units(self):
wrfnc = nc(TEST_FILE)
for units in ("m", "km", "dam", "ft", "mi"):
var = getvar(wrfnc, "z", units=units)
self.assertEqual(var.attrs["units"], units)
if __name__ == "__main__":
ut.main()
ut.main()

1200
test/utests.py

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save