Browse Source

Merge branch 'release/1.1.0'

main
Bill Ladwig 7 years ago
parent
commit
3bafbe84e7
  1. 6
      .gitignore
  2. 2
      MANIFEST.in
  3. 16
      README.md
  4. 10
      build_scripts/gnu_no_omp.sh
  5. 11
      build_scripts/gnu_omp.sh
  6. 15
      build_scripts/win_mingw_no_omp.bat
  7. 17
      build_scripts/win_mingw_omp.bat
  8. 14
      build_scripts/win_msvc_mingw_no_omp.bat
  9. 16
      build_scripts/win_msvc_mingw_omp.bat
  10. 17
      conda_recipe/bld.bat
  11. 8
      conda_recipe/build.sh
  12. 22
      conda_recipe/meta.yaml
  13. 58
      conda_recipe/meta.yaml.develop
  14. 58
      conda_recipe/meta.yaml.release
  15. 114
      doc/source/_templates/product_table.txt
  16. 509
      doc/source/basic_usage.rst
  17. 26
      doc/source/citation.rst
  18. 17
      doc/source/conf.py
  19. 7
      doc/source/faq.rst
  20. 3
      doc/source/index.rst
  21. 58
      doc/source/installation.rst
  22. 80
      doc/source/internal_api/index.rst
  23. 48
      doc/source/new.rst
  24. 25
      doc/source/tutorial.rst
  25. 81
      doc/source/tutorials/tutorial_03_2018.rst
  26. 0
      doc/source/tutorials/wrf_workshop_2017.rst
  27. 88
      doc/source/user_api/index.rst
  28. 17
      fortran/calc_uh.f90
  29. 5
      fortran/eqthecalc.f90
  30. 465
      fortran/omp.f90
  31. 753
      fortran/ompgen.F90
  32. 687
      fortran/rip_cape.f90
  33. 100
      fortran/wrf_cloud_fracf.f90
  34. 10
      fortran/wrf_constants.f90
  35. 45
      fortran/wrf_fctt.f90
  36. 28
      fortran/wrf_pvo.f90
  37. 7
      fortran/wrf_pw.f90
  38. 9
      fortran/wrf_relhl.f90
  39. 108
      fortran/wrf_rip_phys_routines.f90
  40. 214
      fortran/wrf_user.f90
  41. 13
      fortran/wrf_user_dbz.f90
  42. 131
      fortran/wrf_vinterp.f90
  43. 4
      fortran/wrf_wind.f90
  44. 254
      fortran/wrffortran.pyf
  45. 3
      requirements.txt
  46. 1
      setup.py
  47. 13
      src/wrf/__init__.py
  48. 55
      src/wrf/api.py
  49. 88
      src/wrf/cloudfrac.py
  50. 57
      src/wrf/computation.py
  51. 92
      src/wrf/config.py
  52. 48
      src/wrf/constants.py
  53. 8
      src/wrf/decorators.py
  54. 749
      src/wrf/extension.py
  55. 10
      src/wrf/g_cape.py
  56. 164
      src/wrf/g_cloudfrac.py
  57. 0
      src/wrf/g_ctt.py
  58. 0
      src/wrf/g_dbz.py
  59. 0
      src/wrf/g_dewpoint.py
  60. 154
      src/wrf/g_geoht.py
  61. 0
      src/wrf/g_helicity.py
  62. 0
      src/wrf/g_latlon.py
  63. 0
      src/wrf/g_omega.py
  64. 0
      src/wrf/g_precip.py
  65. 0
      src/wrf/g_pressure.py
  66. 0
      src/wrf/g_pw.py
  67. 0
      src/wrf/g_rh.py
  68. 0
      src/wrf/g_slp.py
  69. 0
      src/wrf/g_temp.py
  70. 0
      src/wrf/g_terrain.py
  71. 0
      src/wrf/g_times.py
  72. 2
      src/wrf/g_uvmet.py
  73. 0
      src/wrf/g_vorticity.py
  74. 0
      src/wrf/g_wind.py
  75. 78
      src/wrf/interp.py
  76. 42
      src/wrf/interputils.py
  77. 6
      src/wrf/latlonutils.py
  78. 153
      src/wrf/metadecorators.py
  79. 8
      src/wrf/projection.py
  80. 47
      src/wrf/routines.py
  81. 54
      src/wrf/specialdec.py
  82. 286
      src/wrf/util.py
  83. 2
      src/wrf/version.py
  84. 5
      test/cachetest.py
  85. BIN
      test/ci_tests/ci_result_file.nc
  86. BIN
      test/ci_tests/ci_test_file.nc
  87. 17
      test/ci_tests/make_test_file.py
  88. 28
      test/ci_tests/utests.py
  89. 10
      test/comp_utest.py
  90. 17
      test/generator_test.py
  91. 332
      test/ipynb/Doc_Examples.ipynb
  92. 376
      test/ipynb/WRF_python_demo.ipynb
  93. 12
      test/listBug.ncl
  94. 44
      test/mocktest.py
  95. 77
      test/test_filevars.py
  96. 122
      test/test_omp.py
  97. 97
      test/utests.py
  98. 36
      test/varcache.py

6
.gitignore vendored

@ -46,4 +46,10 @@ doc/build
doc/source/internal_api/generated doc/source/internal_api/generated
doc/source/user_api/generated doc/source/user_api/generated
test/ipynb/.ipynb_checkpoints test/ipynb/.ipynb_checkpoints
fortran/omp.f90
fortran/wrffortran.pyf
fortran/*.mod
build
.settings
src/wrf_python.egg-info

2
MANIFEST.in

@ -4,6 +4,8 @@ include requirements.txt
include fortran/*.f90 include fortran/*.f90
include fortran/*.pyf include fortran/*.pyf
include build_scripts/*.sh
include build_scripts/*.bat
include setup.py include setup.py
recursive-include doc/source * recursive-include doc/source *

16
README.md

@ -1,15 +1,25 @@
# wrf-python wrf-python
==============
A collection of diagnostic and interpolation routines for use with output from the Weather Research and Forecasting (WRF-ARW) Model. A collection of diagnostic and interpolation routines for use with output from the Weather Research and Forecasting (WRF-ARW) Model.
This package provides over 30 diagnostic calculations, several interpolation routines, and utilities to help with plotting via cartopy, basemap, or PyNGL. The functionality is similar to what is provided by the NCL WRF package. This package provides over 30 diagnostic calculations, several interpolation routines, and utilities to help with plotting via cartopy, basemap, or PyNGL. The functionality is similar to what is provided by the NCL WRF package.
Installation via conda: Installation
----------------------------
conda install -c conda-forge wrf-python conda install -c conda-forge wrf-python
Documentation is available at: Documentation
----------------------------------
http://wrf-python.rtfd.org http://wrf-python.rtfd.org
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.

10
build_scripts/gnu_no_omp.sh

@ -0,0 +1,10 @@
#!/bin/bash
cd ../fortran
gfortran -E ompgen.F90 -cpp -o omp.f90
f2py *.f90 -m _wrffortran -h wrffortran.pyf --overwrite-signature
cd ..
python setup.py clean --all
python setup.py config_fc --f90flags="-mtune=generic" build_ext build
pip install .

11
build_scripts/gnu_omp.sh

@ -0,0 +1,11 @@
#!/bin/bash
cd ../fortran
gfortran -E ompgen.F90 -fopenmp -cpp -o omp.f90
f2py *.f90 -m _wrffortran -h wrffortran.pyf --overwrite-signature
cd ..
python setup.py clean --all
python setup.py config_fc --f90flags="-mtune=generic -fopenmp" build_ext --libraries="gomp" build
pip install .

15
build_scripts/win_mingw_no_omp.bat

@ -0,0 +1,15 @@
cd ../fortran
CALL gfortran -E ompgen.F90 -cpp -o omp.f90
REM Wildcards not working on Windows for some reason
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
IF %PROCESSOR_ARCHITECTURE% == AMD64 (
CALL python setup.py config_fc --f90flags="-O2 -mtune=generic" build --compiler=mingw32 --fcompiler=gnu95
) ELSE (
CALL python setup.py config_fc --f90flags="-O2 -mtune=generic -mincoming-stack-boundary=2" build --compiler=mingw32 --fcompiler=gnu95
)
CALL pip install .

17
build_scripts/win_mingw_omp.bat

@ -0,0 +1,17 @@
cd ../fortran
CALL gfortran -E ompgen.F90 -cpp -fopenmp -o omp.f90
REM Wildcards not working on Windows for some reason
CALLf2py -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
IF %PROCESSOR_ARCHITECTURE% == AMD64 (
CALL python setup.py config_fc --f90flags="-O2 -mtune=generic -fopenmp" build_ext --libraries="gomp" build --compiler=mingw32 --fcompiler=gnu95
) ELSE (
CALL python setup.py config_fc --f90flags="-O2 -mtune=generic -fopenmp -mincoming-stack-boundary=2" build_ext --libraries="gomp" build --compiler=mingw32 --fcompiler=gnu95
)
CALL pip install .

14
build_scripts/win_msvc_mingw_no_omp.bat

@ -0,0 +1,14 @@
cd ../fortran
CALL gfortran -E ompgen.F90 -cpp -o omp.f90
REM Wildcards not working on Windows for some reason
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
IF %PROCESSOR_ARCHITECTURE% == AMD64 (
CALL python setup.py config_fc --f90flags="-O2 -mtune=generic" build --compiler=mingw32 --fcompiler=gnu95
) ELSE (
CALL python setup.py config_fc --f90flags="-O2 -mtune=generic -mincoming-stack-boundary=2" build --compiler=msvc --fcompiler=gnu95
)
CALL pip install .

16
build_scripts/win_msvc_mingw_omp.bat

@ -0,0 +1,16 @@
cd ../fortran
CALL gfortran -E ompgen.F90 -cpp -fopenmp -o omp.f90
REM Wildcards not working on Windows for some reason
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
IF %PROCESSOR_ARCHITECTURE% == AMD64 (
CALL python setup.py config_fc --f90flags="-O2 -mtune=generic -fopenmp" build_ext --libraries="gomp" build --compiler=msvc --fcompiler=gnu95
) ELSE (
CALL python setup.py config_fc --f90flags="-O2 -mtune=generic -fopenmp -mincoming-stack-boundary=2" build_ext --libraries="gomp" build --compiler=msvc --fcompiler=gnu95
)
CALL pip install .

17
conda_recipe/bld.bat

@ -1,8 +1,15 @@
cd ./fortran
CALL gfortran -E ompgen.F90 -cpp -fopenmp -o omp.f90
REM Wildcards not working on Windows for some reason
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 ..
%ARCH% == 64 ( IF %ARCH% == 64 (
%PYTHON% setup.py config_fc --f90flags="-O2 -mtune=generic -mfpmath=sse -msse2" build --compiler=mingw32 --fcompiler=gnu95 CALL %PYTHON% setup.py config_fc --f90flags="-O2 -mtune=generic -fopenmp" build_ext --libraries="gomp" build --compiler=msvc --fcompiler=gnu95
) else ( ) ELSE (
%PYTHON% setup.py config_fc --f90flags="-O2 -mtune=generic -mfpmath=sse -msse2 -mincoming-stack-boundary=2" build --compiler=mingw32 --fcompiler=gnu95 CALL %PYTHON% setup.py config_fc --f90flags="-O2 -mtune=generic -fopenmp -mincoming-stack-boundary=2" build_ext --libraries="gomp" build --compiler=msvc --fcompiler=gnu95
) )
%PYTHON% setup.py install --single-version-externally-managed --record=record.txt
CALL %PYTHON% setup.py install --single-version-externally-managed --record=record.txt

8
conda_recipe/build.sh

@ -1,10 +1,16 @@
#!/bin/bash #!/bin/bash
cd ./fortran
gfortran -E ompgen.F90 -fopenmp -cpp -o omp.f90
f2py *.f90 -m _wrffortran -h wrffortran.pyf --overwrite-signature
cd ..
if [ `uname` == Darwin ]; then if [ `uname` == Darwin ]; then
LDFLAGS="$LDFLAGS -undefined dynamic_lookup -bundle" LDFLAGS="$LDFLAGS -undefined dynamic_lookup -bundle"
fi fi
$PYTHON setup.py config_fc --f90flags="-mtune=generic -mfpmath=sse" build $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 $PYTHON setup.py install --single-version-externally-managed --record=record.txt

22
conda_recipe/meta.yaml

@ -1,38 +1,40 @@
{% set version = "1.0.4" %} {% set version = "1.1.0" %}
package: package:
name: wrf-python name: wrf-python
version: {{ version }} version: {{ version }}
source: source:
fn: wrf-python-{{ version }}.tar.gz git_url: https://github.com/NCAR/wrf-python
url: https://github.com/NCAR/wrf-python/archive/{{ version }}.tar.gz git_branch: develop
sha256: 303da6607ac66f49b6d011c32c0bf3af9b5ea5cb6563448daafafb8ec9a078d1
build: build:
number: 0 number: 0
detect_binary_files_with_prefix: true detect_binary_files_with_prefix: true
skip: True # [(win and py>=35)]
requirements: requirements:
build: build:
- setuptools - setuptools
- numpy x.x - python
- numpy 1.11.* # [unix]
- numpy 1.14.* # [win]
- wrapt - wrapt
- mingwpy # [win] - m2w64-toolchain # [win]
- gcc # [unix] - gcc # [unix]
- python
run: run:
- numpy x.x - setuptools
- numpy >=1.11
- python - python
- wrapt - wrapt
- mingwpy # [win] - m2w64-gcc-libs # [win]
- libgfortran # [unix] - libgfortran # [unix]
- libgcc # [unix] - libgcc # [unix]
- xarray - xarray
test: test:
requires: requires:
- setuptools
- netcdf4 - netcdf4
- xarray - xarray
source_files: source_files:

58
conda_recipe/meta.yaml.develop

@ -0,0 +1,58 @@
{% set version = "1.1.0" %}
package:
name: wrf-python
version: {{ version }}
source:
git_url: https://github.com/NCAR/wrf-python
git_branch: develop
build:
number: 0
detect_binary_files_with_prefix: true
requirements:
build:
- setuptools
- numpy 1.11.* # [unix]
- numpy 1.14.* # [win]
- wrapt
- m2w64-toolchain # [win]
- gcc # [unix]
- python
run:
- setuptools
- numpy >=1.11
- python
- wrapt
- m2w64-gcc-libs # [win]
- libgfortran # [unix]
- libgcc # [unix]
- xarray
test:
requires:
- setuptools
- netcdf4
- xarray
source_files:
- test/ci_tests
imports:
- wrf
commands:
- cd test/ci_tests && python utests.py
about:
home: https://github.com/NCAR/wrf-python
license: "UCAR"
license_file: '{{ environ["RECIPE_DIR"] }}/LICENSE'
summary: "Diagnostic and interpolation routines for WRF-ARW data."
extra:
recipe-maintainers:
- bladwig1
- marylhaley
- david-ian-brown
- khallock

58
conda_recipe/meta.yaml.release

@ -0,0 +1,58 @@
{% set version = "1.1.0" %}
package:
name: wrf-python
version: {{ version }}
source:
fn: wrf-python-{{ version }}.tar.gz
url: https://github.com/NCAR/wrf-python/archive/{{ version }}.tar.gz
sha256: ea2202e1d8237c65b9d77a91f00da0f2e7a37ed6214ddd976872b619b9647b33
build:
number: 0
detect_binary_files_with_prefix: true
requirements:
build:
- setuptools
- numpy 1.11.* # [unix]
- numpy 1.14.* # [win]
- wrapt
- m2w64-toolchain # [win]
- gcc # [unix]
- python
run:
- setuptools
- numpy >=1.11
- python
- wrapt
- m2w64-gcc-libs # [win]
- libgfortran # [unix]
- libgcc # [unix]
- xarray
test:
requires:
- setuptools
- netcdf4
- xarray
source_files:
- test/ci_tests
imports:
- wrf
commands:
- cd test/ci_tests && python utests.py
about:
home: https://github.com/NCAR/wrf-python
license: "UCAR"
license_file: '{{ environ["RECIPE_DIR"] }}/LICENSE'
summary: "Diagnostic and interpolation routines for WRF-ARW data."
extra:
recipe-maintainers:
- bladwig1
- marylhaley
- david-ian-brown
- khallock

114
doc/source/_templates/product_table.txt

@ -1,44 +1,52 @@
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| Variable Name | Description | Available Units | Additional Keyword Arguments | | Variable Name | Description | Available Units | Additional Keyword Arguments |
+====================+===============================================================+=============================+===============================================================================================+ +====================+===============================================================+=============================+=========================================================================================================================================================+
| avo | Absolute Vorticity | 10-5 s-1 | | | avo | Absolute Vorticity | 10-5 s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| eth/theta_e | Equivalent Potential Temperature | K | **units** (str) : Set to desired units. Default is *'K'*. | | eth/theta_e | Equivalent Potential Temperature | K | **units** (str) : Set to desired units. Default is *'K'*. |
| | | | | | | | | |
| | | degC | | | | | degC | |
| | | | | | | | | |
| | | degF | | | | | degF | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| cape_2d | 2D cape (mcape/mcin/lcl/lfc) | J kg-1 ; J kg-1 ; m ; m | **missing** (float): Fill value for output only | | cape_2d | 2D cape (mcape/mcin/lcl/lfc) | J kg-1 ; J kg-1 ; m ; m | **missing** (float): Fill value for output only |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| cape_3d | 3D cape and cin | J kg-1 | **missing** (float): Fill value for output only | | cape_3d | 3D cape and cin | J kg-1 | **missing** (float): Fill value for output only |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| ctt | Cloud Top Temperature | degC | **units** (str) : Set to desired units. Default is *'degC'*. | | ctt | Cloud Top Temperature | degC | **units** (str) : Set to desired units. Default is *'degC'*. |
| | | | | | | | | |
| | | K | | | | | K | |
| | | | | | | | | |
| | | degF | | | | | degF | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| cloudfrac | Cloud Fraction | % | | | cloudfrac | Cloud Fraction | % | **vert_type** (str): The vertical coordinate type for the cloud thresholds. Must be 'height_agl', 'height_msl', or 'pres'. Default is 'height_agl'. |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ | | | | |
| | | | **low_thresh** (float): The low cloud threshold (meters for 'height_agl' and 'height_msl', pascals for 'pres'). Default is 300 m (97000 Pa) |
| | | | |
| | | | **mid_thresh** (float): The mid cloud threshold (meters for 'height_agl' and 'height_msl', pascals for 'pres'). Default is 2000 m (80000 Pa) |
| | | | |
| | | | **high_thresh** (float): The high cloud threshold (meters for 'height_agl' and 'height_msl', pascals for 'pres'). Default is 6000 m (45000 Pa) |
+--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| dbz | Reflectivity | dBZ | **do_variant** (boolean): Set to True to enable variant calculation. Default is *False*. | | dbz | Reflectivity | dBZ | **do_variant** (boolean): Set to True to enable variant calculation. Default is *False*. |
| | | | | | | | | |
| | | | **do_liqskin** (boolean): Set to True to enable liquid skin calculation. Default is *False*. | | | | | **do_liqskin** (boolean): Set to True to enable liquid skin calculation. Default is *False*. |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| mdbz | Maximum Reflectivity | dBZ | **do_variant** (boolean): Set to True to enable variant calculation. Default is *False*. | | mdbz | Maximum Reflectivity | dBZ | **do_variant** (boolean): Set to True to enable variant calculation. Default is *False*. |
| | | | | | | | | |
| | | | **do_liqskin** (boolean): Set to True to enable liquid skin calculation. Default is *False*. | | | | | **do_liqskin** (boolean): Set to True to enable liquid skin calculation. Default is *False*. |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| geopt/geopotential | Full Model Geopotential | m2 s-2 | | | geopt/geopotential | Geopotential for the Mass Grid | m2 s-2 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| geopt_stag | Geopotential for the Vertically Staggered Grid | m2 s-2 | |
+--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| helicity | Storm Relative Helicity | m2 s-2 | **top** (float): The top level for the calculation in meters. Default is *3000.0*. | | helicity | Storm Relative Helicity | m2 s-2 | **top** (float): The top level for the calculation in meters. Default is *3000.0*. |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| lat | Latitude | decimal degrees | | | lat | Latitude | decimal degrees | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| lon | Longitude | decimal degrees | | | lon | Longitude | decimal degrees | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| omg/omega | Omega | Pa s-1 | | | omg/omega | Omega | Pa s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| p/pres | Full Model Pressure | Pa | **units** (str) : Set to desired units. Default is *'Pa'*. | | p/pres | Full Model Pressure | Pa | **units** (str) : Set to desired units. Default is *'Pa'*. |
| | | | | | | | | |
| | (in specified units) | hPa | | | | (in specified units) | hPa | |
@ -50,17 +58,17 @@
| | | mmhg | | | | | mmhg | |
| | | | | | | | | |
| | | atm | | | | | atm | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| pressure | Full Model Pressure (hPa) | hPa | | | pressure | Full Model Pressure (hPa) | hPa | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| pvo | Potential Vorticity | PVU | | | pvo | Potential Vorticity | PVU | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| pw | Precipitable Water | kg m-2 | | | pw | Precipitable Water | kg m-2 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| rh | Relative Humidity | % | | | rh | Relative Humidity | % | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| rh2 | 2m Relative Humidity | % | | | rh2 | 2m Relative Humidity | % | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| slp | Sea Level Pressure | hPa | **units** (str) : Set to desired units. Default is *'hPa'*. | | slp | Sea Level Pressure | hPa | **units** (str) : Set to desired units. Default is *'hPa'*. |
| | | | | | | | | |
| | | hPa | | | | | hPa | |
@ -72,7 +80,7 @@
| | | mmhg | | | | | mmhg | |
| | | | | | | | | |
| | | atm | | | | | atm | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| ter | Model Terrain Height | m | **units** (str) : Set to desired units. Default is *'m'*. | | ter | Model Terrain Height | m | **units** (str) : Set to desired units. Default is *'m'*. |
| | | | | | | | | |
| | | km | | | | | km | |
@ -82,59 +90,59 @@
| | | ft | | | | | ft | |
| | | | | | | | | |
| | | mi | | | | | mi | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| td2 | 2m Dew Point Temperature | degC | **units** (str) : Set to desired units. Default is *'degC'*. | | td2 | 2m Dew Point Temperature | degC | **units** (str) : Set to desired units. Default is *'degC'*. |
| | | | | | | | | |
| | | K | | | | | K | |
| | | | | | | | | |
| | | degF | | | | | degF | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| td | Dew Point Temperature | degC | **units** (str) : Set to desired units. Default is *'degC'*. | | td | Dew Point Temperature | degC | **units** (str) : Set to desired units. Default is *'degC'*. |
| | | | | | | | | |
| | | K | | | | | K | |
| | | | | | | | | |
| | | degF | | | | | degF | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| tc | Temperature in Celsius | degC | | | tc | Temperature in Celsius | degC | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| th/theta | Potential Temperature | K | **units** (str) : Set to desired units. Default is *'K'*. | | th/theta | Potential Temperature | K | **units** (str) : Set to desired units. Default is *'K'*. |
| | | | | | | | | |
| | | degC | | | | | degC | |
| | | | | | | | | |
| | | degF | | | | | degF | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| temp | Temperature (in specified units) | K | **units** (str) : Set to desired units. Default is *'K'*. | | temp | Temperature (in specified units) | K | **units** (str) : Set to desired units. Default is *'K'*. |
| | | | | | | | | |
| | | degC | | | | | degC | |
| | | | | | | | | |
| | | degF | | | | | degF | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| tk | Temperature in Kelvin | K | | | tk | Temperature in Kelvin | K | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| times | Times in the File or Sequence | | | | times | Times in the File or Sequence | | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| xtimes | XTIME Coordinate | minutes since | | | xtimes | XTIME Coordinate | minutes since | |
| | | | | | | | | |
| | (if applicable) | start of | | | | (if applicable) | start of | |
| | | | | | | | | |
| | | model run | | | | | model run | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| tv | Virtual Temperature | K | **units** (str) : Set to desired units. Default is *'K'*. | | tv | Virtual Temperature | K | **units** (str) : Set to desired units. Default is *'K'*. |
| | | | | | | | | |
| | | degC | | | | | degC | |
| | | | | | | | | |
| | | degF | | | | | degF | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| twb | Wet Bulb Temperature | K | **units** (str) : Set to desired units. Default is *'K'*. | | twb | Wet Bulb Temperature | K | **units** (str) : Set to desired units. Default is *'K'*. |
| | | | | | | | | |
| | | degC | | | | | degC | |
| | | | | | | | | |
| | | degF | | | | | degF | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| updraft_helicity | Updraft Helicity | m2 s-2 | **bottom** (float): The bottom level for the calculation in meters. Default is *2000.0*. | | updraft_helicity | Updraft Helicity | m2 s-2 | **bottom** (float): The bottom level for the calculation in meters. Default is *2000.0*. |
| | | | | | | | | |
| | | | **top** (float): The top level for the calculation in meters. Default is *5000.0*. | | | | | **top** (float): The top level for the calculation in meters. Default is *5000.0*. |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| ua | U-component of Wind on Mass Points | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. | | ua | U-component of Wind on Mass Points | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. |
| | | | | | | | | |
| | | km h-1 | | | | | km h-1 | |
@ -144,7 +152,7 @@
| | | kt | | | | | kt | |
| | | | | | | | | |
| | | ft s-1 | | | | | ft s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| va | V-component of Wind on Mass Points | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. | | va | V-component of Wind on Mass Points | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. |
| | | | | | | | | |
| | | km h-1 | | | | | km h-1 | |
@ -154,7 +162,7 @@
| | | kt | | | | | kt | |
| | | | | | | | | |
| | | ft s-1 | | | | | ft s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| wa | W-component of Wind on Mass Points | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. | | wa | W-component of Wind on Mass Points | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. |
| | | | | | | | | |
| | | km h-1 | | | | | km h-1 | |
@ -164,7 +172,7 @@
| | | kt | | | | | kt | |
| | | | | | | | | |
| | | ft s-1 | | | | | ft s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| uvmet10 | 10 m U and V Components of Wind | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. | | uvmet10 | 10 m U and V Components of Wind | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. |
| | | | | | | | | |
| | Rotated to Earth Coordinates | km h-1 | | | | Rotated to Earth Coordinates | km h-1 | |
@ -174,7 +182,7 @@
| | | kt | | | | | kt | |
| | | | | | | | | |
| | | ft s-1 | | | | | ft s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| uvmet | U and V Components of Wind | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. | | uvmet | U and V Components of Wind | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. |
| | | | | | | | | |
| | Rotated to Earth Coordinates | km h-1 | | | | Rotated to Earth Coordinates | km h-1 | |
@ -184,7 +192,7 @@
| | | kt | | | | | kt | |
| | | | | | | | | |
| | | ft s-1 | | | | | ft s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| wspd_wdir | Wind Speed and Direction (wind_from_direction) | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. | | wspd_wdir | Wind Speed and Direction (wind_from_direction) | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. |
| | | | | | | | | |
| | in Grid Coordinates | km h-1 | | | | in Grid Coordinates | km h-1 | |
@ -194,7 +202,7 @@
| | | kt | | | | | kt | |
| | | | | | | | | |
| | | ft s-1 | | | | | ft s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| wspd_wdir10 | 10m Wind Speed and Direction (wind_from_direction) | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. | | wspd_wdir10 | 10m Wind Speed and Direction (wind_from_direction) | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. |
| | | | | | | | | |
| | in Grid Coordinates | km h-1 | | | | in Grid Coordinates | km h-1 | |
@ -204,7 +212,7 @@
| | | kt | | | | | kt | |
| | | | | | | | | |
| | | ft s-1 | | | | | ft s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| uvmet_wspd_wdir | Wind Speed and Direction (wind_from_direction) | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. | | uvmet_wspd_wdir | Wind Speed and Direction (wind_from_direction) | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. |
| | | | | | | | | |
| | Rotated to Earth Coordinates | km h-1 | | | | Rotated to Earth Coordinates | km h-1 | |
@ -214,7 +222,7 @@
| | | kt | | | | | kt | |
| | | | | | | | | |
| | | ft s-1 | | | | | ft s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| uvmet10_wspd_wdir | 10m Wind Speed and Direction (wind_from_direction) | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. | | uvmet10_wspd_wdir | 10m Wind Speed and Direction (wind_from_direction) | m s-1 | **units** (str) : Set to desired units. Default is *'m s-1'*. |
| | | | | | | | | |
| | Rotated to Earth Coordinates | km h-1 | | | | Rotated to Earth Coordinates | km h-1 | |
@ -224,8 +232,8 @@
| | | kt | | | | | kt | |
| | | | | | | | | |
| | | ft s-1 | | | | | ft s-1 | |
+--------------------+---------------------------------------------------------------+-----------------------------+-----------------------------------------------------------------------------------------------+ +--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| z/height | Full Model Height on Mass Levels | m | **msl** (boolean): Set to False to return AGL values. True is for MSL. Default is *True*. | | z/height | Model Height for Mass 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'*. | | | | km | **units** (str) : Set to desired units. Default is *'m'*. |
| | | | | | | | | |
@ -234,7 +242,15 @@
| | | ft | | | | | ft | |
| | | | | | | | | |
| | | mi | | | | | 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'*. |
| | | | |
| | | dm | |
| | | | |
| | | ft | |
| | | | |
| | | mi | |
+--------------------+---------------------------------------------------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+

509
doc/source/basic_usage.rst

@ -1,6 +1,36 @@
How To Use How To Use
============ ============
Introduction
---------------
The API for wrf-python can be summarized as a variable computation/extraction
routine, several interpolation routines, and a few plotting helper utilities.
The API is kept as simple as possible to help minimize the
learning curve for new programmers, students, and scientists. In the future,
we plan to extend xarray for programmers desiring a more object oriented API,
but this remains a work in progress.
The five most commonly used routines can be summarized as:
- :meth:`wrf.getvar` - Extracts WRF-ARW NetCDF variables and
computes diagnostic variables that WRF does not compute (e.g. storm
relative helicity). This is the routine that you will use most often.
- :meth:`wrf.interplevel` - Interpolates a three-dimensional field to a
horizontal plane at a specified level using simple (fast) linear
interpolation (e.g. 850 hPa temperature).
- :meth:`wrf.vertcross` - Interpolates a three-dimensional field to a vertical
plane through a user-specified horizontal line (i.e. a cross section).
- :meth:`wrf.interpline` - Interpolates a two-dimensional field to a
user-specified line.
- :meth:`wrf.vinterp` - Interpolates a three-dimensional field to
user-specified 'surface' levels (e.g. theta-e levels). This is a smarter,
albeit slower, version of :meth:`wrf.interplevel`.
Basic Usage Basic Usage
---------------- ----------------
@ -10,8 +40,8 @@ Computing Diagnostic Variables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The primary use for the :meth:`wrf.getvar` function is to return diagnostic The primary use for the :meth:`wrf.getvar` function is to return diagnostic
variables that require a calculation, since WRF does not produce these variables variables that require a calculation, since WRF does not produce these
natively. These diagnostics include CAPE, storm relative helicity, variables natively. These diagnostics include CAPE, storm relative helicity,
omega, sea level pressure, etc. A table of all available diagnostics can be omega, sea level pressure, etc. A table of all available diagnostics can be
found here: :ref:`diagnostic-table`. found here: :ref:`diagnostic-table`.
@ -355,9 +385,9 @@ Result:
pole_lon=0.0) pole_lon=0.0)
Note how the 'Time' dimension was replaced with the 'file' dimension, due to the Note how the 'Time' dimension was replaced with the 'file' dimension, due to
numpy's automatic squeezing of the single 'Time' dimension. To maintain the numpy's automatic squeezing of the single element 'Time' dimension. To maintain
'Time' dimension, set the *squeeze* parameter to False. the 'Time' dimension, set the *squeeze* parameter to False.
.. code-block:: python .. code-block:: python
@ -706,8 +736,9 @@ Example Using Lat/Lon Coordinates
start_point = CoordPair(lat=start_lat, lon=start_lon) start_point = CoordPair(lat=start_lat, lon=start_lon)
end_point = CoordPair(lat=end_lat, lon=end_lon) end_point = CoordPair(lat=end_lat, lon=end_lon)
# When using lat/lon coordinates, you must supply a netcdf file object, or a # When using lat/lon coordinates, you must supply a WRF netcdf file object,
# projection object. # or a projection object with the lower left latitude and lower left
# longitude points.
p_vert = vertcross(p, z, wrfin=ncfile, start_point=start_point, end_point=end_point, latlon=True) p_vert = vertcross(p, z, wrfin=ncfile, start_point=start_point, end_point=end_point, latlon=True)
print(p_vert) print(p_vert)
@ -953,8 +984,11 @@ Example Using Lat/Lon Coordinates
start_point = CoordPair(lat=start_lat, lon=start_lon) start_point = CoordPair(lat=start_lat, lon=start_lon)
end_point = CoordPair(lat=end_lat, lon=end_lon) end_point = CoordPair(lat=end_lat, lon=end_lon)
# Calculate the vertical cross section. By setting latlon to True, this # Calculate the interpolated line. To use latitude and longitude points,
# also calculates the latitude and longitude coordinates along the line # you must supply a WRF NetCDF file object, or a projection object along
# with the lower left latitude and lower left longitude points.
# Also, by setting latlon to True, this routine will
# also calculate the latitude and longitude coordinates along the line
# and adds them to the metadata to help with plotting labels. # and adds them to the metadata to help with plotting labels.
t2_line = interpline(t2, wrfin=ncfile, start_point=start_point, end_point=end_point, latlon=True) t2_line = interpline(t2, wrfin=ncfile, start_point=start_point, end_point=end_point, latlon=True)
@ -1614,3 +1648,460 @@ Result:
<Ngl.Resources instance at 0x11d318a70> <Ngl.Resources instance at 0x11d318a70>
<Ngl.Resources instance at 0x11d318710>] <Ngl.Resources instance at 0x11d318710>]
.. _using_omp:
Using OpenMP
-------------------------
Beginning in version 1.1, the Fortran computational routines in wrf-python make
use of OpenMP directives. OpenMP enables the calculations to use multiple CPU
cores, which can improve performance. In order to use OpenMP features,
wrf-python has to be compiled with OpenMP enabled (most pre-built binary
installations will have this enabled).
The Fortran computational routines have all been built using runtime
scheduling, instead of compile time scheduling, so that the user can choose the
scheduler type within their Python application. By default, the scheduling
type is set to :data:`wrf.OMP_SCHED_STATIC` using only 1 CPU core, so
wrf-python will behave similarly to the non-OpenMP built versions. For the most
part, the difference between the scheduling types is minimal, with the exception
being the :data:`wrf.OMP_SCHED_DYNAMIC` scheduler that is much slower due to
the additional overhead associated with it. For new users, using the default
scheduler should be sufficient.
Verifying that OpenMP is Enabled
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To take advantage of the performance improvements offered by OpenMP, wrf-python
needs to have been compiled with OpenMP features enabled. The example below
shows how you can determine if OpenMP is enabled in your build of wrf-python.
.. code-block:: python
from __future__ import print_function
from wrf import omp_enabled
print(omp_enabled())
Result:
.. code-block:: none
True
Determining the Number of Available Processors
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The example below shows how you can get the maximum number of processors
that are available on your system.
.. code-block:: python
from __future__ import print_function
from wrf import omp_get_num_procs
print(omp_get_num_procs())
Result:
.. code-block:: none
8
Specifying the Number of Threads
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To enable multicore support via OpenMP, specifying the maximum number
of OpenMP threads (i.e. CPU cores) is the only step that you need to take.
In the example below, :meth:`wrf.omp_set_num_threads` is used to set the
maximum number of threads to use, and :meth:`wrf.omp_get_max_threads` is used
to retrieve (and print) the maximum number of threads used.
.. note::
Although there is an OpenMP routine named :meth:`wrf.omp_get_num_threads`,
this routine will always return 1 when called from the sequential part of
the program. Use :meth:`wrf.omp_get_max_threads` to return the value set by
:meth:`wrf.omp_set_num_threads`.
.. code-block:: python
from __future__ import print_function
from wrf import omp_set_num_threads, omp_get_max_threads
omp_set_num_threads(4)
print (omp_get_max_threads())
Result:
.. code-block:: none
4
Setting a Different Scheduler Type
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When an OpenMP directive is encountered in the Fortran code, a scheduler is
used to determine how the work is divided among the threads. All of the
Fortran routines are compiled to use a 'runtime' scheduler, which indicates
that the scheduler type (from the four listed below) is to be chosen at
runtime (i.e. inside a Python script)
By default, the scheduler chosen is the :data:`wrf.OMP_SCHED_STATIC` scheduler,
which should be sufficient for most users. However, OpenMP and wrf-python
include the following options for the scheduler type:
- :data:`wrf.OMP_SCHED_STATIC`
- :data:`wrf.OMP_SCHED_DYNAMIC`
- :data:`wrf.OMP_SCHED_GUIDED`
- :data:`wrf.OMP_SCHED_AUTO`
Refer to the
`OpenMP Specification <http://www.openmp.org/wp-content/uploads/openmp-4.5.pdf>`_.
for more information about these scheduler types. In local testing,
:data:`wrf.OMP_SCHED_GUIDED` produced the best results, but
differences between :data:`wrf.OMP_SCHED_STATIC`,
:data:`wrf.OMP_SCHED_GUIDED`, and
:data:`wrf.OMP_SCHED_AUTO` were minor. However,
:data:`wrf.OMP_SCHED_DYNAMIC` produced noticeably slower results
due to the overhead of using a dynamic scheduler.
When setting a scheduler type, the :meth:`wrf.omp_set_schedule` takes two
arguments. The first is the scheduler type (one from the list above), and the
second optional argument is a modifier, which is usually referred as the chunk
size. If the modifier/chunk_size is set to 0, then the OpenMP default
implementation is used. For :data:`wrf.OMP_SCHED_AUTO`, the
modifier is ignored.
If you are new to OpenMP and all this sounds confusing, don't worry about
setting a scheduler type. The default static scheduler will be good enough.
In the example below, the scheduler type is set to
:data:`wrf.OMP_SCHED_GUIDED` and uses the default chunk size of 0. The
scheduler type is then read back using :meth:`wrf.omp_get_schedule`
and printed.
.. code-block:: python
from __future__ import print_function
from wrf import omp_set_schedule, omp_get_schedule, OMP_SCHED_GUIDED
omp_set_schedule(OMP_SCHED_GUIDED, 0)
sched, modifier = omp_get_schedule()
print(sched, modifier)
Result:
.. code-block:: none
3 1
Notice that the printed scheduler type (*sched* variable) is set to a
value of 3, which is the actual integer constant value for the
:data:`wrf.OMP_SCHED_GUIDED` scheduler type. The *modifier* is returned as a
value of 1, which is different than the 0 that was supplied to the
:meth:`wrf.omp_set_schedule` routine. This is because the 0 tells OpenMP to use
its own default value for the scheduler, which is 1 for this type of scheduler.
.. _performance:
Performance Tips
--------------------
Memory Issues with :data:`wrf.ALL_TIMES`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The use of :data:`wrf.ALL_TIMES` for the *timeidx* parameter to
:meth:`wrf.getvar` is convenient for computing diagnostic variables across
multiple files/times, but there is something that users should be aware of.
When :data:`wrf.ALL_TIMES` is set as the *timeidx* argument, all arrays used
in the computation are extracted for all times before the computation
is started. This can cause serious memory issues on smaller hardware systems
like laptops.
In this example, the user wants to use a data set that is 289 x 39 x 300 x 300
and compute z for the entire data set. The user is using a laptop with
8 GB of memory.
.. code-block:: python
from netCDF4 import Dataset
from wrf import getvar, ALL_TIMES
file_list = [Dataset("/path/to/file1"), Dataset("/path/to/file2"),...]
z = getvar(file_list, "z", ALL_TIMES)
Five hours later, the computation finished. What happened?
In wrf-python, all of the computational routines use 8-byte REAL variables so
that both the 4-byte and 8-byte version of WRF output can be used. The
calculation for z extracts three variables (P, PHB, and HGT) and returns a
fourth array (RESULT). The RESULT will get cut in half to 4-byte REALs
after the computation, but needs an 8-byte REAL when the result is computed.
Let's look at the approximate amount memory needed:
**P**: 289 x 39 x 300 x 300 x 8 = 8,115,120,000 bytes (~8 GB!)
**PHB**: 289 x 39 x 300 x 300 x 8 = 8,115,120,000 bytes (~8 GB!)
**HGT**: 289 x 300 x 300 x 8 = 208,080,000 (~208 MB)
**RESULT**: 289 x 39 x 300 x 300 x 8 = 8,115,120,000 bytes (~8 GB!)
Yikes! So, in order to do this calculation using :data:`wrf.ALL_TIMES` as
the *timeidx*, over 24.2 GB are needed for this one calculation. When the
laptop runs out of memory, it begins using the hard drive for swap memory,
which runs hundreds of times slower than real memory.
To fix this situation, it is better to allocate the output array yourself and
run the calculation for each time step in a loop
("loop-and-fill"). The required memory requirements change to:
(Note: only need to store the result in a 4-byte REAL)
**FINAL_RESULT**: 289 x 39 x 300 x 300 x 4 = 4,057560,000 bytes (~4 GB)
(Note: the numbers below are for each loop iteration)
**P**: 39 x 300 x 300 x 8 = 28,080,000 bytes (~28 MB)
**PHB**: 39 x 300 x 300 x 8 = 28,080,000 bytes (~28 MB)
**HGT**: 300 x 300 x 8 = 720,000 bytes (720 KB)
**RESULT**: 39 x 300 x 300 x 8 = 28,080,000 bytes (~28 MB)
Since the memory for the computation is deleted after each
loop iteration, the total memory usage drops to approximately 4.1 GB.
The moral of the story is that you need to make sure that your system has
enough memory to extract everything it needs up front if you want to use
:data:`wrf.ALL_TIMES`, otherwise it is better to "loop-and-fill" yourself.
Here is an example of the "loop-and-fill" technique:
.. code-block:: python
from __future__ import print_function, division
import numpy as np
from netCDF4 import Dataset
from wrf import getvar, ALL_TIMES
filename_list = ["/path/to/file1", "/path/to/file2",...]
# Result shape (hard coded for this example)
result_shape = (289, 39, 300, 300)
# Only need 4-byte floats
z_final = np.empty(result_shape, np.float32)
# Modify this number if using more than 1 time per file
times_per_file = 1
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, "z", file_timeidx)
z_final[timeidx,:] = z[:]
f.close()
The *cache* Argument for :meth:`wrf.getvar`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you have read through the documentation, you may have noticed that the
:meth:`wrf.getvar` routine contains a *cache* argument. What is this for?
Internally, if metadata is turned on, a variable is extracted from the NetCDF
file and its metadata is copied to form the result's metadata. Often this
variable is one of the computation's function arguments, so rather than
spend time extracting the variable again for the computation, it is placed
in a cache (dictionary) and passed on to the computational function.
What isn't widely known is that this cache argument can also be supplied by
end users wishing to speed up their application. This can be useful in
situations where numerous calculations are being performed on the same
data set. For many algorithms, the time needed to extract the arrays from the
NetCDF file is on par with the time needed to perform the calculation. If you
are computing numerous diagnostics, extracting the variables up front allows
you to only pay this extraction penalty once, rather than inside of each call
to :meth:`wrf.getvar`.
The cache is nothing more than a dictionary where each key is the variable
name (e.g. "P") and the value is the :class:`xarray.DataArray` or
:class:`numpy.ndarray` variable. Creating the cache dictionary is easy,
since the :meth:`wrf.extract_vars` routine returns a dictionary for a
sequence of variables.
.. note::
The *timeidx* parameter supplied to :meth:`extract_vars`
must be the same *timeidx* parameter that you plan to use for
:meth:`wrf.getvar`. Otherwise, it will crash with dimension mismatch errors.
Some common variables that you can use to create an effective cache are: P, PB,
PH, PHB, T, QVAPOR, HGT, PSFC, U, V, W.
Below is an example showing the same computation done with and without the
cache. The execution time is printed. The hardware used is a 2.8 GHz Intel Core
i7, which contains 4 CPU cores with 2 hyper threads (8 total threads). This
will be interpreted as 8 CPUs for OpenMP.
.. code-block:: python
from __future__ import print_function
import time
from netCDF4 import Dataset
from wrf import getvar, ALL_TIMES, extract_vars
# The first two files contain four times, the last file contains only one.
wrf_filenames = ["/path/to/wrfout_d02_2005-08-28_00:00:00",
"/path/to/wrfout_d02_2005-08-28_12:00:00",
"/path/to/wrfout_d02_2005-08-29_00:00:00"]
wrfin = [Dataset(x) for x in wrf_filenames]
start = time.time()
my_cache = extract_vars(wrfin, ALL_TIMES, ("P", "PSFC", "PB", "PH", "PHB",
"T", "QVAPOR", "HGT", "U", "V",
"W"))
end = time.time()
print ("Time taken to build cache: ", (end-start), "s")
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")
# No cache
start = time.time()
for var in vars:
v = getvar(wrfin, var, ALL_TIMES)
end = time.time()
no_cache_time = (end-start)
print ("Time taken without variable cache: ", no_cache_time, "s")
# With a cache
start = time.time()
for var in vars:
v = getvar(wrfin, var, ALL_TIMES, cache=my_cache)
end = time.time()
cache_time = (end-start)
print ("Time taken with variable cache: ", cache_time, "s")
improvement = ((no_cache_time-cache_time)/no_cache_time) * 100
print ("The cache decreased computation time by: ", improvement, "%")
Result:
.. code-block:: none
Time taken to build cache: 0.28154706955 s
Time taken without variable cache: 11.0905270576 s
Time taken with variable cache: 8.25931215286 s
The cache decreased computation time by: 25.5282268378 %
By removing the repeated extraction of common variables in the
:meth:`wrf.getvar` routine, for the single threaded case, the computation
time has been reduced by 25.5% in this particular example.
Things get more interesting when OpenMP is turned on and set to use the
maximum number of processors (in this case 8 threads are used).
.. code-block:: python
from __future__ import print_function
import time
from netCDF4 import Dataset
from wrf import (getvar, ALL_TIMES, extract_vars,
omp_set_num_threads, omp_get_num_procs)
# The first two files contain four times, the last file contains only one.
wrf_filenames = ["/path/to/wrfout_d02_2005-08-28_00:00:00",
"/path/to/wrfout_d02_2005-08-28_12:00:00",
"/path/to/wrfout_d02_2005-08-29_00:00:00"]
wrfin = [Dataset(x) for x in wrf_filenames]
start = time.time()
my_cache = extract_vars(wrfin, ALL_TIMES, ("P", "PSFC", "PB", "PH", "PHB",
"T", "QVAPOR", "HGT", "U", "V",
"W"))
end = time.time()
print ("Time taken to build cache: ", (end-start), "s")
omp_set_num_threads(omp_get_num_procs())
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")
# No cache
start = time.time()
for var in vars:
v = getvar(wrfin, var, ALL_TIMES)
end = time.time()
no_cache_time = (end-start)
print ("Time taken without variable cache: ", no_cache_time, "s")
# With a cache
start = time.time()
for var in vars:
v = getvar(wrfin, var, ALL_TIMES, cache=my_cache)
end = time.time()
cache_time = (end-start)
print ("Time taken with variable cache: ", cache_time, "s")
improvement = ((no_cache_time-cache_time)/no_cache_time) * 100
print ("The cache decreased computation time by: ", improvement, "%")
Result:
.. code-block:: none
Time taken to build cache: 0.2700548172 s
Time taken without variable cache: 6.02652812004 s
Time taken with variable cache: 3.27777099609 s
The cache decreased computation time by: 45.6109565772 %
In this example, 4 CPU cores (8 total threads) are used. When the cache is
used, the computation time drops by 45%, so almost half the time was spent
simply extracting variables from the NetCDF file. When compared to the
11.09 s needed to compute the single threaded case with no variable cache, the
computation time drops by roughly 70% (compared to 45% with 8 threads but
no cache).
In summary, if you are computing a lot of diagnostic variables, consider using
the *cache* argument to improve performance, particularly if you want to
maximize your multithreaded performance with OpenMP.

26
doc/source/citation.rst

@ -0,0 +1,26 @@
.. _citation:
Citation
=================
WRF-Python has a Digital Object Identifier (DOI), which is a persistent
identifier for web-based resources. The wrf-python DOI, when used in URL form,
https://doi.org/10.5065/D6W094P1, provides a persistent link to the wrf-python
Github page. The benefit of DOIs is that they are widely accepted by academic
publishers as citable locators for scholarly objects.
If you author a paper that involves data analysis with wrf-python, or
visualizations created with wrf-python, we would like to ask you to please
cite wrf-python. This helps us better understand the impact of the software on
the scientific community, which in turns helps us maintain support for the
effort.
You can cite wrf-python using the following citation:
.. code-block:: none
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.

17
doc/source/conf.py

@ -23,14 +23,24 @@ except ImportError:
class Mock(MagicMock): class Mock(MagicMock):
@classmethod @classmethod
def __getattr__(cls, name): def __getattr__(cls, name):
return Mock() return MagicMock()
MOCK_MODULES = ["numpy", "numpy.ma", "xarray", "cartopy", MOCK_MODULES = ["numpy", "numpy.ma", "xarray", "cartopy",
"pandas", "matplotlib", "netCDF4", "mpl_toolkits.basemap", "pandas", "matplotlib", "netCDF4", "mpl_toolkits.basemap",
"wrf._wrffortran"] "wrf._wrffortran"]
sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES) sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES)
consts = {"DEFAULT_FILL" : 9.9692099683868690E36} 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): class MockWrfConstants(object):
def __init__(self): def __init__(self):
@ -40,6 +50,8 @@ def mock_asscalar(val):
return float(val) return float(val)
sys.modules["wrf._wrffortran"].wrf_constants = MockWrfConstants() sys.modules["wrf._wrffortran"].wrf_constants = MockWrfConstants()
sys.modules["wrf._wrffortran"].omp_constants = MockWrfConstants()
sys.modules["numpy"].asscalar = mock_asscalar sys.modules["numpy"].asscalar = mock_asscalar
@ -106,6 +118,7 @@ author = u'Bill Ladwig'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
import wrf import wrf
version = wrf.__version__ version = wrf.__version__
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.

7
doc/source/faq.rst

@ -61,6 +61,13 @@ In a future release of wrf-python, direct support for Dataset objects will
be added and this will no longer be necessary. be added and this will no longer be necessary.
Why is wrf-python taking hours to run?
---------------------------------------------
The most likely culprit is insufficient memory for the calculation you are
trying to perform.
See :ref:`performance` for more information.

3
doc/source/index.rst

@ -45,8 +45,9 @@ Documentation
./api ./api
./faq ./faq
./support ./support
./citation
./license ./license
./workshop ./tutorial
Indices and tables Indices and tables

58
doc/source/installation.rst

@ -4,9 +4,10 @@ Installation
Required Dependencies Required Dependencies
---------------------- ----------------------
- Python 2.7, 3.4, or 3.5 - Python 2.7, 3.4, or 3.5+
- numpy (1.9 or later) - numpy (1.11 or later; 1.14 required to build on Windows)
- wrapt (1.10 or later) - wrapt (1.10 or later)
- setuptools (38.0 or later)
Highly Recommended Packages Highly Recommended Packages
@ -81,13 +82,52 @@ The source code is available via github:
https://github.com/NCAR/wrf-python https://github.com/NCAR/wrf-python
To install, change to the wrf-python directory and run:: Or PyPI:
https://pypi.python.org/pypi/wrf-python
To install, if you do not need OpenMP support, change your working directory
to the wrf-python source directory and run::
$ pip install . $ pip install .
Note that building on Win64 with Python 3.5+ and the mingw-64 compiler Beginning with wrf-python 1.1, OpenMP is supported, but preprocessing the
is very difficult, due to incompatibilities with the runtime libraries and ompgen.F90 file is required, which also requires running f2py to
lack of support from numpy's distutils. Improved support for these build the .pyf file. To simplify this process, you can use the build scripts in
configurations, along with numpy distutils support, should take place this the *build_scripts* directory as a guide, or just call the script directly.
year. But for now, visual studio and the intel compiler may be required.
Otherwise, Python 2.7 or Python 3.4 is recommended. Below is a sample from a build script for GNU compiler with OpenMP enabled:
.. code-block:: none
cd ../fortran
gfortran -E ompgen.F90 -fopenmp -cpp -o omp.f90
f2py *.f90 -m _wrffortran -h wrffortran.pyf --overwrite-signature
cd ..
python setup.py clean --all
python setup.py config_fc --f90flags="-mtune=generic -fopenmp" build_ext --libraries="gomp" build
pip install .
Beginning with numpy 1.14, f2py extensions can now be built using the MSVC
compiler and mingw gfortran compiler. Numpy 1.14 is required to build
wrf-python for Python 3.5+.
.. note::
If you are building on a supercomputer and receiving linker related
errors (e.g. missing symbols, undefined references, etc), you probably
need to unset the LDFLAGS environment variable. System administrators on
supercomputing systems often define LDFLAGS for you so that you don't need
to worry about where libraries like NetCDF are installed. Unfortunately,
this can cause problems with the numpy.distutils build system. To fix,
using the build command from above::
$ unset LDFLAGS python setup.py config_fc --f90flags="-mtune=generic -fopenmp" build_ext --libraries="gomp" build

80
doc/source/internal_api/index.rst

@ -13,46 +13,46 @@ The routines below are called internally by :meth:`wrf.getvar`.
:nosignatures: :nosignatures:
:toctree: ./generated/ :toctree: ./generated/
wrf.cape.get_2dcape wrf.g_cape.get_2dcape
wrf.cape.get_3dcape wrf.g_cape.get_3dcape
wrf.cloudfrac.get_cloudfrac wrf.g_cloudfrac.get_cloudfrac
wrf.ctt.get_ctt wrf.g_ctt.get_ctt
wrf.dbz.get_dbz wrf.g_dbz.get_dbz
wrf.dbz.get_max_dbz wrf.g_dbz.get_max_dbz
wrf.dewpoint.get_dp wrf.g_dewpoint.get_dp
wrf.dewpoint.get_dp_2m wrf.g_dewpoint.get_dp_2m
wrf.geoht.get_geopt wrf.g_geoht.get_geopt
wrf.geoht.get_height wrf.g_geoht.get_height
wrf.helicity.get_srh wrf.g_helicity.get_srh
wrf.helicity.get_uh wrf.g_helicity.get_uh
wrf.omega.get_omega wrf.g_omega.get_omega
wrf.pressure.get_pressure wrf.g_pressure.get_pressure
wrf.pressure.get_pressure_hpa wrf.g_pressure.get_pressure_hpa
wrf.pw.get_pw wrf.g_pw.get_pw
wrf.rh.get_rh wrf.g_rh.get_rh
wrf.rh.get_rh_2m wrf.g_rh.get_rh_2m
wrf.slp.get_slp wrf.g_slp.get_slp
wrf.temp.get_theta wrf.g_temp.get_theta
wrf.temp.get_temp wrf.g_temp.get_temp
wrf.temp.get_eth wrf.g_temp.get_eth
wrf.temp.get_tv wrf.g_temp.get_tv
wrf.temp.get_tw wrf.g_temp.get_tw
wrf.temp.get_tk wrf.g_temp.get_tk
wrf.temp.get_tc wrf.g_temp.get_tc
wrf.terrain.get_terrain wrf.g_terrain.get_terrain
wrf.times.get_times wrf.g_times.get_times
wrf.times.get_xtimes wrf.g_times.get_xtimes
wrf.uvmet.get_uvmet wrf.g_uvmet.get_uvmet
wrf.uvmet.get_uvmet10 wrf.g_uvmet.get_uvmet10
wrf.uvmet.get_uvmet_wspd_wdir wrf.g_uvmet.get_uvmet_wspd_wdir
wrf.uvmet.get_uvmet10_wspd_wdir wrf.g_uvmet.get_uvmet10_wspd_wdir
wrf.vorticity.get_avo wrf.g_vorticity.get_avo
wrf.vorticity.get_pvo wrf.g_vorticity.get_pvo
wrf.wind.get_u_destag wrf.g_wind.get_u_destag
wrf.wind.get_v_destag wrf.g_wind.get_v_destag
wrf.wind.get_w_destag wrf.g_wind.get_w_destag
wrf.wind.get_destag_wspd_wdir wrf.g_wind.get_destag_wspd_wdir
wrf.wind.get_destag_wspd_wdir10 wrf.g_wind.get_destag_wspd_wdir10
------------------------- -------------------------

48
doc/source/new.rst

@ -4,6 +4,54 @@ What's New
Releases Releases
------------- -------------
v1.1.0
^^^^^^^^^^^^^^
- Release 1.1.0
- Computational routines now support multiple cores using OpenMP. See
:ref:`using_omp` for details on how to use this new feature.
- The CAPE routines should be noticeably faster, even in the single threaded
case (thank you supreethms1809!).
- :meth:`wrf.getvar` now works correctly with non-gridded NetCDF variables
- The cloud fraction diagnostic has changed:
- Users can now select their own cloud threshold levels, and can choose
between a vertical coordinate defined as height (AGL), height (MSL), or
pressure.
- The default vertical coordinate type has been changed to be height (AGL).
This ensures that clouds appear over mountainous regions. If you need
the old behavior, set the *vert_type* argument to 'pressure'.
- Fixed a bug involving the cloud threshold search algorithm, where if the
surface was higher than the threshold for a cloud level, the algorithm
would use whatever was there before (uninitialized variable bug). This
caused some interesting visualization issues when plotted. Now, whenever
the surface is above a cloud level threshold, a fill value is used to
indicate that data is unavailable for that location.
- The cartopy object for LambertConformal should now work correctly in the
southern hemisphere.
- Fixed a bug with the PolarStereographic projection missing a geobounds
argument (thank you hanschen!).
- Renamed the modules containing the 'get_product' routines used
by :meth:`wrf.getvar` to avoid naming conflicts with the raw computational
routine names. Users should be using :meth:`wrf.getvar` instead of these
routines, but for those that imported the 'get_product' routines
directly, you will need to modify your code.
- Fixed a uniqueness issue with the internal coordinate cache that was causing
crashes when input data is changed to a different file in a jupyter notebook
cell.
- Added code to better support building wheels on Windows (thank you letmaik!)
- Improved support for scipy.io.netcdf objects.
- Added a new 'zstag' diagnostic that returns the height values for the
vertically staggered grid.
- A DOI is now available for wrf-python. Please cite wrf-python if you are
using it for your research. (See :ref:`citation`)
- Fixed issue with vertcross and interpline not working correctly when a
projection object is used. Users will now have to supply the lower left
latitude and longitude corner point.
- Beginning with numpy 1.14, wrf-python can be built using the MSVC
compiler with gfortran. WRF-Python can now be built for Python 3.5+ on
services like AppVeyor.
v1.0.5 v1.0.5
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^

25
doc/source/tutorial.rst

@ -0,0 +1,25 @@
Tutorials
=============
NCAR occasionally provides tutorials for wrf-python at various times
throughout the year.
Below are the links to the upcoming and past tutorials.
Upcoming Tutorials
---------------------
.. toctree::
:maxdepth: 1
tutorials/tutorial_03_2018.rst
Past Tutorials
------------------
.. toctree::
:maxdepth: 1
tutorials/wrf_workshop_2017.rst

81
doc/source/tutorials/tutorial_03_2018.rst

@ -0,0 +1,81 @@
WRF-Python Tutorial 2018
=========================
NCAR will be providing a four hour tutorial for wrf-python on Wednesday, March
7, 2018 from 8 AM to 12 PM. The tutorial is free, but seating is limited to
only 16 students, so registration is required.
The tutorial will take place at NCAR's corporate training center in Boulder,
Colorado.
`Corporate Technical Training Center <https://www2.fin.ucar.edu/it/about-cttc>`_
3085 Center Green Drive, Building CG-2, Room #3024
Boulder, Colorado
Overview
--------------
This tutorial provides an introduction to wrf-python. The tutorial is beginner
friendly for new users of wrf-python, but this is not an introduction to the Python
programming language (see :ref:`prereq`). Due to limited seating, if you
do not have any previous experience with Python, please do not register
for this tutorial.
Computers will be provided, but feel free to use your own laptop if you prefer.
We will be covering how to install wrf-python via conda as part of the
tutorial.
Students are encouraged to bring their own data sets, but data will be provided
if this is not an option. Students will be provided a jupyter notebook workbook
which can be modified to accommodate their data.
Topics include:
- How to install wrf-python via conda
- A brief introduction to jupyter notebook
- Overview of WRF data files
- WRF-Python basics
- Plotting with cartopy
- Overview of OpenMP features and other performance tips
- Open lab for students
Registration
---------------
Please register prior to February 21, 2018. The registration form is here:
`Registration Form <https://goo.gl/forms/is5VExf3w4bFGXUb2>`_
Registration consists of a brief survey, which will help give the instructors
a brief overview of your background and will help tailor the tutorial to
your expectations.
.. _prereq:
Prerequisites
---------------
This tutorial assumes that you have basic knowledge of how to type commands
in to a terminal window using your preferred operating system. You
should know some basic directory commands like *cd*, *mkdir*, *cp*, *mv*.
This tutorial assumes that you have prior experience programming in Python.
Below is a list of some Python concepts that you will see in the examples,
but don't worry if you aren't familiar with everything.
- Opening a Python interpreter and entering commands.
- Importing packages via the import statement.
- Familiarity with some of the basic Python types: str, list, tuple, dict, bool, float, int, None.
- Creating a list, tuple, or dict with "[ ]", "( )", "{ }" syntax (e.g. my_list = [1,2,3,4,5]).
- Accessing dict/list/tuple items with the "x[ ]" syntax (e.g. my_list_item = my_list[0]).
- Slicing str/list/tuple with the ":" syntax (e.g. my_slice = my_list[1:3]).
- Using object methods and attributes with the "x.y" syntax (e.g. my_list.append(6)).
- Calling functions (e.g. result = some_function(x, y))
- Familiarity with numpy would be helpful, as only a very brief introduction
is provided.
- Familiarity with matplotlib would be helpful, as only a very brief
introduction is provided.

0
doc/source/workshop.rst → doc/source/tutorials/wrf_workshop_2017.rst

88
doc/source/user_api/index.rst

@ -75,7 +75,6 @@ the array object to a compiled extension.
wrf.to_np wrf.to_np
Variable Extraction Routines Variable Extraction Routines
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -154,6 +153,82 @@ sure they are removed before calling these routines.
wrf.omega wrf.omega
wrf.pw wrf.pw
OpenMP Runtime Library Routines
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The routines below are the OpenMP runtime libraries that have been wrapped
for wrf-python. The entire library (OpenMP 3.x) has been wrapped, but many of
the routines are only useful inside of an OpenMP thread, so they aren't useful
from inside the Python interpreter. Also, the Fortran code in wrf-python is
fairly simple in terms of threading, so features like nested threads aren't
used. The documentation below is split in to the useful OpenMP functions and
the less useful functions.
The documentation for each routine was taken directly from the
`OpenMP Specification <http://www.openmp.org/wp-content/uploads/openmp-4.5.pdf>`_.
Read the specification for more details about these routines.
Useful OpenMP Routines
*****************************
The routines below are useful when called from within a Python program. These
routines handle setting the number of threads, setting up the scheduler,
and timing.
It is also important to note that the OpenMP directives within the Fortran
code all specify a runtime scheduler. This means that the user can control
the type of scheduling to use from within their Python application by using the
routines below.
.. autosummary::
:nosignatures:
:toctree: ./generated/
wrf.omp_enabled
wrf.omp_set_num_threads
wrf.omp_get_max_threads
wrf.omp_get_num_procs
wrf.omp_set_dynamic
wrf.omp_get_dynamic
wrf.omp_set_schedule
wrf.omp_get_schedule
wrf.omp_get_thread_limit
wrf.omp_get_wtime
wrf.omp_get_wtick
Less Useful OpenMP Routines
*******************************
The routines below are less useful because wrf-python does not use nested
parallelism and some of the routines are only applicable when called from
within an OpenMP thread.
.. autosummary::
:nosignatures:
:toctree: ./generated/
wrf.omp_get_num_threads
wrf.omp_get_thread_num
wrf.omp_in_parallel
wrf.omp_set_nested
wrf.omp_get_nested
wrf.omp_set_max_active_levels
wrf.omp_get_max_active_levels
wrf.omp_get_level
wrf.omp_get_ancestor_thread_num
wrf.omp_get_team_size
wrf.omp_get_active_level
wrf.omp_in_final
wrf.omp_init_lock
wrf.omp_init_nest_lock
wrf.omp_destroy_lock
wrf.omp_destroy_nest_lock
wrf.omp_set_lock
wrf.omp_set_nest_lock
wrf.omp_unset_lock
wrf.omp_unset_nest_lock
wrf.omp_test_lock
wrf.omp_test_nest_lock
Configuration Routines Configuration Routines
^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^
@ -182,6 +257,7 @@ in one place.
wrf.disable_pyngl wrf.disable_pyngl
wrf.set_cache_size wrf.set_cache_size
wrf.get_cache_size wrf.get_cache_size
wrf.omp_enabled
Miscellaneous Routines Miscellaneous Routines
@ -216,6 +292,8 @@ them helpful for other purposes.
wrf.getproj wrf.getproj
wrf.cache_item wrf.cache_item
wrf.get_cached_item wrf.get_cached_item
wrf.ll_points
wrf.pairs_to_latlon
------------------------ ------------------------
@ -247,7 +325,7 @@ use a single point for an (x, y) or (lat, lon) location.
wrf.CoordPair wrf.CoordPair
CoordPair Methods CoordPair Methods
~~~~~~~~~~~~~~~~~~~~~~~ ************************
.. autosummary:: .. autosummary::
:nosignatures: :nosignatures:
@ -274,7 +352,7 @@ The classes below are used to hold the projection information in the
'projection' entry within a :attr:`xarray.DataArray.attrs` attribute. 'projection' entry within a :attr:`xarray.DataArray.attrs` attribute.
Projection Base Class Projection Base Class
~~~~~~~~~~~~~~~~~~~~~~~~ ******************************
The base class for all map projection types. The base class for all map projection types.
@ -285,7 +363,7 @@ The base class for all map projection types.
wrf.WrfProj wrf.WrfProj
Projection Base Class Methods Projection Base Class Methods
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ***********************************
The class methods for all projection types. The class methods for all projection types.
@ -303,7 +381,7 @@ The class methods for all projection types.
Projection Subclasses Projection Subclasses
~~~~~~~~~~~~~~~~~~~~~~~~ *****************************
See :class:`wrf.WrfProj` for methods and attributes. See :class:`wrf.WrfProj` for methods and attributes.

17
fortran/calc_uh.f90

@ -47,7 +47,7 @@ SUBROUTINE DCALCUH(nx, ny, nz, nzp1, zp, mapfct, dx, dy, uhmnhgt, uhmxhgt, us, &
! Misc local variables ! Misc local variables
INTEGER :: i, j, k, kbot, ktop INTEGER :: i, j, k, kbot, ktop
REAL(KIND=8) :: twodx, twody, wgtlw, sum, wmean, wsum, wavg REAL(KIND=8) :: twodx, twody, wgtlw, sum, wmean, wsum !,wavg
REAL(KIND=8) :: helbot, heltop, wbot, wtop REAL(KIND=8) :: helbot, heltop, wbot, wtop
REAL(KIND=8) :: zbot, ztop REAL(KIND=8) :: zbot, ztop
@ -61,21 +61,29 @@ SUBROUTINE DCALCUH(nx, ny, nz, nzp1, zp, mapfct, dx, dy, uhmnhgt, uhmxhgt, us, &
twodx = 2.0*dx twodx = 2.0*dx
twody = 2.0*dy twody = 2.0*dy
!$OMP PARALLEL
!$OMP DO COLLAPSE(3) SCHEDULE(runtime)
DO k=2,nz-2 DO k=2,nz-2
DO j=2,ny-1 DO j=2,ny-1
DO i=2,nx-1 DO i=2,nx-1
wavg = 0.5*(w(i,j,k)+w(i,j,k+1)) !wavg = 0.5*(w(i,j,k)+w(i,j,k+1))
tem1(i,j,k) = wavg*((vs(i+1,j,k) - vs(i-1,j,k))/(twodx*mapfct(i,j)) - & tem1(i,j,k) = (0.5*(w(i,j,k)+w(i,j,k+1)))*((vs(i+1,j,k) - &
vs(i-1,j,k))/(twodx*mapfct(i,j)) - &
(us(i,j+1,k) - us(i,j-1,k))/(twody*mapfct(i,j))) (us(i,j+1,k) - us(i,j-1,k))/(twody*mapfct(i,j)))
tem2(i,j,k) = 0.5*(zp(i,j,k) + zp(i,j,k+1)) tem2(i,j,k) = 0.5*(zp(i,j,k) + zp(i,j,k+1))
END DO END DO
END DO END DO
END DO END DO
!$OMP END DO
! Integrate over depth uhminhgt to uhmxhgt AGL ! Integrate over depth uhminhgt to uhmxhgt AGL
! !
! WRITE(6,'(a,f12.1,a,f12.1,a)') & ! WRITE(6,'(a,f12.1,a,f12.1,a)') &
! 'Calculating UH from ',uhmnhgt,' to ',uhmxhgt,' m AGL' ! 'Calculating UH from ',uhmnhgt,' to ',uhmxhgt,' m AGL'
!$OMP DO COLLAPSE(2) PRIVATE(i, j, k, zbot, ztop, kbot, ktop, &
!$OMP wgtlw, wbot, wtop, wsum, wmean, sum, helbot, heltop) SCHEDULE(runtime)
DO j=2,ny-2 DO j=2,ny-2
DO i=2,nx-2 DO i=2,nx-2
zbot = zp(i,j,2) + uhmnhgt zbot = zp(i,j,2) + uhmnhgt
@ -142,6 +150,9 @@ SUBROUTINE DCALCUH(nx, ny, nz, nzp1, zp, mapfct, dx, dy, uhmnhgt, uhmxhgt, us, &
END IF END IF
END DO END DO
END DO END DO
!$OMP END DO
!$OMP END PARALLEL
uh = uh*1000. ! Scale according to Kain et al. (2008) uh = uh*1000. ! Scale according to Kain et al. (2008)

5
fortran/eqthecalc.f90

@ -32,6 +32,8 @@ SUBROUTINE DEQTHECALC(qvp, tmk, prs, eth, miy, mjx, mkzh)
REAL(KIND=8) :: tlcl REAL(KIND=8) :: tlcl
INTEGER :: i, j, k INTEGER :: i, j, k
!$OMP PARALLEL DO COLLAPSE(3) PRIVATE(i, j, k, q, t, p, e, tlcl) &
!$OMP SCHEDULE(runtime)
DO k = 1,mkzh DO k = 1,mkzh
DO j = 1,mjx DO j = 1,mjx
DO i = 1,miy DO i = 1,miy
@ -40,11 +42,12 @@ SUBROUTINE DEQTHECALC(qvp, tmk, prs, eth, miy, mjx, mkzh)
p = prs(i,j,k)/100. p = prs(i,j,k)/100.
e = q*p/(EPS + q) e = q*p/(EPS + q)
tlcl = TLCLC1/(LOG(t**TLCLC2/e) - TLCLC3) + TLCLC4 tlcl = TLCLC1/(LOG(t**TLCLC2/e) - TLCLC3) + TLCLC4
eth(i,j,k) = t*(1000.D0/p)**(GAMMA*(1.D0 + GAMMAMD*q))* & eth(i,j,k) = tmk(i,j,k)*(1000.D0/p)**(GAMMA*(1.D0 + GAMMAMD*q))* &
EXP((THTECON1/tlcl - THTECON2)*q*(1.D0 + THTECON3*q)) EXP((THTECON1/tlcl - THTECON2)*q*(1.D0 + THTECON3*q))
END DO END DO
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN

465
fortran/omp.f90

@ -0,0 +1,465 @@
MODULE omp_constants
INTEGER, PARAMETER :: fomp_sched_kind = 4
INTEGER, PARAMETER :: fomp_lock_kind = 4
INTEGER, PARAMETER :: fomp_nest_lock_kind = 8
INTEGER(KIND=fomp_sched_kind), PARAMETER :: fomp_sched_static = 1
INTEGER(KIND=fomp_sched_kind), PARAMETER :: fomp_sched_dynamic = 2
INTEGER(KIND=fomp_sched_kind), PARAMETER :: fomp_sched_guided = 3
INTEGER(KIND=fomp_sched_kind), PARAMETER :: fomp_sched_auto = 4
END MODULE omp_constants
FUNCTION fomp_enabled()
IMPLICIT NONE
!f2py threadsafe
LOGICAL :: fomp_enabled
fomp_enabled = .FALSE.
END FUNCTION fomp_enabled
SUBROUTINE fomp_set_num_threads(num_threads)
IMPLICIT NONE
!f2py threadsafe
INTEGER, INTENT(IN) :: num_threads
IF (.FALSE.) PRINT *, num_threads
END SUBROUTINE fomp_set_num_threads
FUNCTION fomp_get_num_threads()
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_num_threads
fomp_get_num_threads = -1
END FUNCTION fomp_get_num_threads
FUNCTION fomp_get_max_threads()
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_max_threads
fomp_get_max_threads = -1
END FUNCTION fomp_get_max_threads
FUNCTION fomp_get_thread_num()
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_thread_num
fomp_get_thread_num = -1
END FUNCTION fomp_get_thread_num
FUNCTION fomp_get_num_procs()
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_num_procs
fomp_get_num_procs = -1
END FUNCTION fomp_get_num_procs
FUNCTION fomp_in_parallel()
IMPLICIT NONE
!f2py threadsafe
LOGICAL :: fomp_in_parallel
fomp_in_parallel = .FALSE.
END FUNCTION fomp_in_parallel
SUBROUTINE fomp_set_dynamic(dynamic_threads)
IMPLICIT NONE
!f2py threadsafe
LOGICAL, INTENT(IN) :: dynamic_threads
IF (.FALSE.) PRINT *, dynamic_threads
END SUBROUTINE fomp_set_dynamic
FUNCTION fomp_get_dynamic()
IMPLICIT NONE
!f2py threadsafe
LOGICAL :: fomp_get_dynamic
fomp_get_dynamic = .FALSE.
END FUNCTION fomp_get_dynamic
SUBROUTINE fomp_set_nested(nested)
IMPLICIT NONE
!f2py threadsafe
LOGICAL, INTENT(IN) :: nested
IF (.FALSE.) PRINT *, nested
END SUBROUTINE fomp_set_nested
FUNCTION fomp_get_nested()
IMPLICIT NONE
!f2py threadsafe
LOGICAL :: fomp_get_nested
fomp_get_nested = .FALSE.
END FUNCTION fomp_get_nested
SUBROUTINE fomp_set_schedule(kind, modifier)
USE omp_constants, ONLY : fomp_sched_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_sched_kind), INTENT(IN) :: kind
INTEGER, INTENT(IN) :: modifier
IF (.FALSE.) PRINT *, kind, modifier
END SUBROUTINE fomp_set_schedule
SUBROUTINE fomp_get_schedule(kind, modifier)
USE omp_constants, ONLY : fomp_sched_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_sched_kind), INTENT(OUT) :: kind
INTEGER, INTENT(OUT) :: modifier
kind = -1
modifier = -1
END SUBROUTINE fomp_get_schedule
FUNCTION fomp_get_thread_limit()
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_thread_limit
fomp_get_thread_limit = -1
END FUNCTION fomp_get_thread_limit
SUBROUTINE fomp_set_max_active_levels(max_levels)
IMPLICIT NONE
!f2py threadsafe
INTEGER, INTENT(IN) :: max_levels
IF (.FALSE.) PRINT *, max_levels
END SUBROUTINE fomp_set_max_active_levels
FUNCTION fomp_get_max_active_levels()
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_max_active_levels
fomp_get_max_active_levels = -1
END FUNCTION fomp_get_max_active_levels
FUNCTION fomp_get_level()
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_level
fomp_get_level = -1
END FUNCTION fomp_get_level
FUNCTION fomp_get_ancestor_thread_num(level)
IMPLICIT NONE
!f2py threadsafe
INTEGER, INTENT(IN) :: level
INTEGER :: fomp_get_ancestor_thread_num
IF (.FALSE.) PRINT *, level
fomp_get_ancestor_thread_num = -1
END FUNCTION fomp_get_ancestor_thread_num
FUNCTION fomp_get_team_size(level)
IMPLICIT NONE
!f2py threadsafe
INTEGER, INTENT(IN) :: level
INTEGER :: fomp_get_team_size
IF (.FALSE.) PRINT *, level
fomp_get_team_size = -1
END FUNCTION fomp_get_team_size
FUNCTION fomp_get_active_level()
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_active_level
fomp_get_active_level = -1
END FUNCTION fomp_get_active_level
FUNCTION fomp_in_final()
IMPLICIT NONE
!f2py threadsafe
LOGICAL :: fomp_in_final
fomp_in_final = .FALSE.
END FUNCTION fomp_in_final
SUBROUTINE fomp_init_lock(svar)
USE omp_constants, ONLY : fomp_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_lock_kind), INTENT(OUT) :: svar
svar = -1
END SUBROUTINE fomp_init_lock
SUBROUTINE fomp_init_nest_lock(nvar)
USE omp_constants, ONLY : fomp_nest_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_nest_lock_kind), INTENT(OUT) :: nvar
nvar = -1
END SUBROUTINE fomp_init_nest_lock
SUBROUTINE fomp_destroy_lock(svar)
USE omp_constants, ONLY : fomp_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_lock_kind), INTENT(INOUT) :: svar
IF (.FALSE.) PRINT *, svar
END SUBROUTINE fomp_destroy_lock
SUBROUTINE fomp_destroy_nest_lock(nvar)
USE omp_constants, ONLY : fomp_nest_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_nest_lock_kind), INTENT(INOUT) :: nvar
IF (.FALSE.) PRINT *, nvar
END SUBROUTINE fomp_destroy_nest_lock
SUBROUTINE fomp_set_lock(svar)
USE omp_constants, ONLY : fomp_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_lock_kind), INTENT(INOUT) :: svar
IF (.FALSE.) PRINT *, svar
END SUBROUTINE fomp_set_lock
SUBROUTINE fomp_set_nest_lock(nvar)
USE omp_constants, ONLY : fomp_nest_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_nest_lock_kind), INTENT(INOUT) :: nvar
IF (.FALSE.) PRINT *, nvar
END SUBROUTINE fomp_set_nest_lock
SUBROUTINE fomp_unset_lock(svar)
USE omp_constants, ONLY : fomp_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_lock_kind), INTENT(INOUT) :: svar
IF (.FALSE.) PRINT *, svar
END SUBROUTINE fomp_unset_lock
SUBROUTINE fomp_unset_nest_lock(nvar)
USE omp_constants, ONLY : fomp_nest_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_nest_lock_kind), INTENT(INOUT) :: nvar
IF (.FALSE.) PRINT *, nvar
END SUBROUTINE fomp_unset_nest_lock
FUNCTION fomp_test_lock(svar)
USE omp_constants, ONLY : fomp_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_lock_kind), INTENT(INOUT) :: svar
LOGICAL :: fomp_test_lock
IF (.FALSE.) PRINT *, svar
fomp_test_lock = .FALSE.
END FUNCTION fomp_test_lock
FUNCTION fomp_test_nest_lock(nvar)
USE omp_constants, ONLY : fomp_nest_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_nest_lock_kind), INTENT(INOUT) :: nvar
INTEGER :: fomp_test_nest_lock
IF (.FALSE.) PRINT *, nvar
fomp_test_nest_lock = -1
END FUNCTION fomp_test_nest_lock
FUNCTION fomp_get_wtime()
IMPLICIT NONE
!f2py threadsafe
REAL (KIND=8) :: fomp_get_wtime
fomp_get_wtime = -1
END FUNCTION fomp_get_wtime
FUNCTION fomp_get_wtick()
IMPLICIT NONE
!f2py threadsafe
REAL (KIND=8) :: fomp_get_wtick
fomp_get_wtick = -1
END FUNCTION fomp_get_wtick

753
fortran/ompgen.F90

@ -0,0 +1,753 @@
MODULE omp_constants
#ifdef _OPENMP
USE omp_lib
! f2py can't figure this out without me making a map of these kinds to
! c types, so we're going to have to hard code the kinds below.
!INTEGER, PARAMETER :: fomp_sched_kind = omp_sched_kind
!INTEGER, PARAMETER :: fomp_nest_lock_kind = omp_nest_lock_kind
!INTEGER, PARAMETER :: fomp_lock_kind = omp_lock_kind
! Note: Defining these specifically is the only way I can get f2py to
! work without doing the same thing in a mapping file. The values below
! are for GNU on 64bit. This may not be entirely correct for non-GNU
! compilers. In particular, it will be the locks that segfault/crash if
! this is wrong.
#if defined(__GFORTRAN__)
#if (__SIZEOF_POINTER__ == 8)
INTEGER, PARAMETER :: fomp_sched_kind = 4
INTEGER, PARAMETER :: fomp_lock_kind = 8
INTEGER, PARAMETER :: fomp_nest_lock_kind = 8
#else
INTEGER, PARAMETER :: fomp_sched_kind = 4
INTEGER, PARAMETER :: fomp_lock_kind = 4
INTEGER, PARAMETER :: fomp_nest_lock_kind = 4
#endif
#elif defined(__INTEL_COMPILER_BUILD_DATE)
#if defined(__x86_64__) || defined(_M_X64)
INTEGER, PARAMETER :: fomp_sched_kind = 4
INTEGER, PARAMETER :: fomp_lock_kind = 8
INTEGER, PARAMETER :: fomp_nest_lock_kind = 8
#else
INTEGER, PARAMETER :: fomp_sched_kind = 4
INTEGER, PARAMETER :: fomp_lock_kind = 4
INTEGER, PARAMETER :: fomp_nest_lock_kind = 4
#endif
#elif defined(__PGI)
#if defined(__x86_64__)
INTEGER, PARAMETER :: fomp_sched_kind = 4
INTEGER, PARAMETER :: fomp_lock_kind = 8
INTEGER, PARAMETER :: fomp_nest_lock_kind = 8
#else
INTEGER, PARAMETER :: fomp_sched_kind = 4
INTEGER, PARAMETER :: fomp_lock_kind = 4
INTEGER, PARAMETER :: fomp_nest_lock_kind = 4
#endif
#endif
INTEGER(KIND=fomp_sched_kind), PARAMETER :: fomp_sched_static = omp_sched_static
INTEGER(KIND=fomp_sched_kind), PARAMETER :: fomp_sched_dynamic = omp_sched_dynamic
INTEGER(KIND=fomp_sched_kind), PARAMETER :: fomp_sched_guided = omp_sched_guided
INTEGER(KIND=fomp_sched_kind), PARAMETER :: fomp_sched_auto = omp_sched_auto
#else
INTEGER, PARAMETER :: fomp_sched_kind = 4
INTEGER, PARAMETER :: fomp_lock_kind = 4
INTEGER, PARAMETER :: fomp_nest_lock_kind = 8
INTEGER(KIND=fomp_sched_kind), PARAMETER :: fomp_sched_static = 1
INTEGER(KIND=fomp_sched_kind), PARAMETER :: fomp_sched_dynamic = 2
INTEGER(KIND=fomp_sched_kind), PARAMETER :: fomp_sched_guided = 3
INTEGER(KIND=fomp_sched_kind), PARAMETER :: fomp_sched_auto = 4
#endif
END MODULE omp_constants
FUNCTION fomp_enabled()
IMPLICIT NONE
!f2py threadsafe
LOGICAL :: fomp_enabled
#ifdef _OPENMP
fomp_enabled = .TRUE.
#else
fomp_enabled = .FALSE.
#endif
END FUNCTION fomp_enabled
SUBROUTINE fomp_set_num_threads(num_threads)
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
INTEGER, INTENT(IN) :: num_threads
#ifdef _OPENMP
CALL omp_set_num_threads(num_threads)
#else
IF (.FALSE.) PRINT *, num_threads
#endif
END SUBROUTINE fomp_set_num_threads
FUNCTION fomp_get_num_threads()
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_num_threads
#ifdef _OPENMP
fomp_get_num_threads = omp_get_num_threads()
#else
fomp_get_num_threads = -1
#endif
END FUNCTION fomp_get_num_threads
FUNCTION fomp_get_max_threads()
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_max_threads
#ifdef _OPENMP
fomp_get_max_threads = omp_get_max_threads()
#else
fomp_get_max_threads = -1
#endif
END FUNCTION fomp_get_max_threads
FUNCTION fomp_get_thread_num()
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_thread_num
#ifdef _OPENMP
fomp_get_thread_num = omp_get_thread_num()
#else
fomp_get_thread_num = -1
#endif
END FUNCTION fomp_get_thread_num
FUNCTION fomp_get_num_procs()
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_num_procs
#ifdef _OPENMP
fomp_get_num_procs = omp_get_num_procs()
#else
fomp_get_num_procs = -1
#endif
END FUNCTION fomp_get_num_procs
FUNCTION fomp_in_parallel()
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
LOGICAL :: fomp_in_parallel
#ifdef _OPENMP
fomp_in_parallel = omp_in_parallel()
#else
fomp_in_parallel = .FALSE.
#endif
END FUNCTION fomp_in_parallel
SUBROUTINE fomp_set_dynamic(dynamic_threads)
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
LOGICAL, INTENT(IN) :: dynamic_threads
#ifdef _OPENMP
CALL omp_set_dynamic(dynamic_threads)
#else
IF (.FALSE.) PRINT *, dynamic_threads
#endif
END SUBROUTINE fomp_set_dynamic
FUNCTION fomp_get_dynamic()
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
LOGICAL :: fomp_get_dynamic
#ifdef _OPENMP
fomp_get_dynamic = omp_get_dynamic()
#else
fomp_get_dynamic = .FALSE.
#endif
END FUNCTION fomp_get_dynamic
SUBROUTINE fomp_set_nested(nested)
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
LOGICAL, INTENT(IN) :: nested
#ifdef _OPENMP
CALL omp_set_nested(nested)
#else
IF (.FALSE.) PRINT *, nested
#endif
END SUBROUTINE fomp_set_nested
FUNCTION fomp_get_nested()
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
LOGICAL :: fomp_get_nested
#ifdef _OPENMP
fomp_get_nested = omp_get_nested()
#else
fomp_get_nested = .FALSE.
#endif
END FUNCTION fomp_get_nested
SUBROUTINE fomp_set_schedule(kind, modifier)
#ifdef _OPENMP
USE omp_lib
#endif
USE omp_constants, ONLY : fomp_sched_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_sched_kind), INTENT(IN) :: kind
INTEGER, INTENT(IN) :: modifier
#ifdef _OPENMP
CALL omp_set_schedule(kind, modifier)
#else
IF (.FALSE.) PRINT *, kind, modifier
#endif
END SUBROUTINE fomp_set_schedule
SUBROUTINE fomp_get_schedule(kind, modifier)
#ifdef _OPENMP
USE omp_lib
#endif
USE omp_constants, ONLY : fomp_sched_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_sched_kind), INTENT(OUT) :: kind
INTEGER, INTENT(OUT) :: modifier
#ifdef _OPENMP
CALL omp_get_schedule(kind, modifier)
#else
kind = -1
modifier = -1
#endif
END SUBROUTINE fomp_get_schedule
FUNCTION fomp_get_thread_limit()
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_thread_limit
#ifdef _OPENMP
fomp_get_thread_limit = omp_get_thread_limit()
#else
fomp_get_thread_limit = -1
#endif
END FUNCTION fomp_get_thread_limit
SUBROUTINE fomp_set_max_active_levels(max_levels)
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
INTEGER, INTENT(IN) :: max_levels
#ifdef _OPENMP
CALL omp_set_max_active_levels(max_levels)
#else
IF (.FALSE.) PRINT *, max_levels
#endif
END SUBROUTINE fomp_set_max_active_levels
FUNCTION fomp_get_max_active_levels()
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_max_active_levels
#ifdef _OPENMP
fomp_get_max_active_levels = omp_get_max_active_levels()
#else
fomp_get_max_active_levels = -1
#endif
END FUNCTION fomp_get_max_active_levels
FUNCTION fomp_get_level()
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_level
#ifdef _OPENMP
fomp_get_level = omp_get_level()
#else
fomp_get_level = -1
#endif
END FUNCTION fomp_get_level
FUNCTION fomp_get_ancestor_thread_num(level)
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
INTEGER, INTENT(IN) :: level
INTEGER :: fomp_get_ancestor_thread_num
#ifdef _OPENMP
fomp_get_ancestor_thread_num = omp_get_ancestor_thread_num(level)
#else
IF (.FALSE.) PRINT *, level
fomp_get_ancestor_thread_num = -1
#endif
END FUNCTION fomp_get_ancestor_thread_num
FUNCTION fomp_get_team_size(level)
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
INTEGER, INTENT(IN) :: level
INTEGER :: fomp_get_team_size
#ifdef _OPENMP
fomp_get_team_size = omp_get_team_size(level)
#else
IF (.FALSE.) PRINT *, level
fomp_get_team_size = -1
#endif
END FUNCTION fomp_get_team_size
FUNCTION fomp_get_active_level()
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
INTEGER :: fomp_get_active_level
#ifdef _OPENMP
fomp_get_active_level = omp_get_active_level()
#else
fomp_get_active_level = -1
#endif
END FUNCTION fomp_get_active_level
FUNCTION fomp_in_final()
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
LOGICAL :: fomp_in_final
#ifdef _OPENMP
fomp_in_final = omp_in_final()
#else
fomp_in_final = .FALSE.
#endif
END FUNCTION fomp_in_final
SUBROUTINE fomp_init_lock(svar)
#ifdef _OPENMP
USE omp_lib
#endif
USE omp_constants, ONLY : fomp_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_lock_kind), INTENT(OUT) :: svar
#ifdef _OPENMP
CALL omp_init_lock(svar)
#else
svar = -1
#endif
END SUBROUTINE fomp_init_lock
SUBROUTINE fomp_init_nest_lock(nvar)
#ifdef _OPENMP
USE omp_lib
#endif
USE omp_constants, ONLY : fomp_nest_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_nest_lock_kind), INTENT(OUT) :: nvar
#ifdef _OPENMP
CALL omp_init_nest_lock(nvar)
#else
nvar = -1
#endif
END SUBROUTINE fomp_init_nest_lock
SUBROUTINE fomp_destroy_lock(svar)
#ifdef _OPENMP
USE omp_lib
#endif
USE omp_constants, ONLY : fomp_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_lock_kind), INTENT(INOUT) :: svar
#ifdef _OPENMP
CALL omp_destroy_lock(svar)
#else
IF (.FALSE.) PRINT *, svar
#endif
END SUBROUTINE fomp_destroy_lock
SUBROUTINE fomp_destroy_nest_lock(nvar)
#ifdef _OPENMP
USE omp_lib
#endif
USE omp_constants, ONLY : fomp_nest_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_nest_lock_kind), INTENT(INOUT) :: nvar
#ifdef _OPENMP
CALL omp_destroy_nest_lock(nvar)
#else
IF (.FALSE.) PRINT *, nvar
#endif
END SUBROUTINE fomp_destroy_nest_lock
SUBROUTINE fomp_set_lock(svar)
#ifdef _OPENMP
USE omp_lib
#endif
USE omp_constants, ONLY : fomp_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_lock_kind), INTENT(INOUT) :: svar
#ifdef _OPENMP
CALL omp_set_lock(svar)
#else
IF (.FALSE.) PRINT *, svar
#endif
END SUBROUTINE fomp_set_lock
SUBROUTINE fomp_set_nest_lock(nvar)
#ifdef _OPENMP
USE omp_lib
#endif
USE omp_constants, ONLY : fomp_nest_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_nest_lock_kind), INTENT(INOUT) :: nvar
#ifdef _OPENMP
CALL omp_set_nest_lock(nvar)
#else
IF (.FALSE.) PRINT *, nvar
#endif
END SUBROUTINE fomp_set_nest_lock
SUBROUTINE fomp_unset_lock(svar)
#ifdef _OPENMP
USE omp_lib
#endif
USE omp_constants, ONLY : fomp_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_lock_kind), INTENT(INOUT) :: svar
#ifdef _OPENMP
CALL omp_unset_lock(svar)
#else
IF (.FALSE.) PRINT *, svar
#endif
END SUBROUTINE fomp_unset_lock
SUBROUTINE fomp_unset_nest_lock(nvar)
#ifdef _OPENMP
USE omp_lib
#endif
USE omp_constants, ONLY : fomp_nest_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_nest_lock_kind), INTENT(INOUT) :: nvar
#ifdef _OPENMP
CALL omp_unset_nest_lock(nvar)
#else
IF (.FALSE.) PRINT *, nvar
#endif
END SUBROUTINE fomp_unset_nest_lock
FUNCTION fomp_test_lock(svar)
#ifdef _OPENMP
USE omp_lib
#endif
USE omp_constants, ONLY : fomp_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_lock_kind), INTENT(INOUT) :: svar
LOGICAL :: fomp_test_lock
#ifdef _OPENMP
fomp_test_lock = omp_test_lock(svar)
#else
IF (.FALSE.) PRINT *, svar
fomp_test_lock = .FALSE.
#endif
END FUNCTION fomp_test_lock
FUNCTION fomp_test_nest_lock(nvar)
#ifdef _OPENMP
USE omp_lib
#endif
USE omp_constants, ONLY : fomp_nest_lock_kind
IMPLICIT NONE
!f2py threadsafe
INTEGER(KIND=fomp_nest_lock_kind), INTENT(INOUT) :: nvar
INTEGER :: fomp_test_nest_lock
#ifdef _OPENMP
fomp_test_nest_lock = omp_test_nest_lock(nvar)
#else
IF (.FALSE.) PRINT *, nvar
fomp_test_nest_lock = -1
#endif
END FUNCTION fomp_test_nest_lock
FUNCTION fomp_get_wtime()
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
REAL (KIND=8) :: fomp_get_wtime
#ifdef _OPENMP
fomp_get_wtime = omp_get_wtime()
#else
fomp_get_wtime = -1
#endif
END FUNCTION fomp_get_wtime
FUNCTION fomp_get_wtick()
#ifdef _OPENMP
USE omp_lib
#endif
IMPLICIT NONE
!f2py threadsafe
REAL (KIND=8) :: fomp_get_wtick
#ifdef _OPENMP
fomp_get_wtick = omp_get_wtick()
#else
fomp_get_wtick = -1
#endif
END FUNCTION fomp_get_wtick

687
fortran/rip_cape.f90

@ -37,9 +37,9 @@ END FUNCTION TVIRTUAL
REAL(KIND=8) FUNCTION TONPSADIABAT(thte, prs, psadithte, psadiprs, psaditmk, gamma,& REAL(KIND=8) FUNCTION TONPSADIABAT(thte, prs, psadithte, psadiprs, psaditmk, gamma,&
errstat, errmsg) errstat, errmsg)
USE wrf_constants, ONLY : ALGERR USE wrf_constants, ONLY : ALGERR
!!$OMP DECLARE SIMD (TONPSADIABAT)
!!uniform(thte,prs,psadithte,psadiprs,psaditmk)
!f2py threadsafe !f2py threadsafe
!f2py intent(in,out) :: cape, cin
IMPLICIT NONE IMPLICIT NONE
REAL(KIND=8), INTENT(IN) :: thte REAL(KIND=8), INTENT(IN) :: thte
@ -58,7 +58,8 @@ REAL(KIND=8) FUNCTION TONPSADIABAT(thte, prs, psadithte, psadiprs, psaditmk, gam
REAL(KIND=8) :: fracip REAL(KIND=8) :: fracip
REAL(KIND=8) :: fracip2 REAL(KIND=8) :: fracip2
INTEGER :: ip, ipch, jt, jtch INTEGER :: l1, h1, mid1, rang1, l2, h2, mid2, rang2
INTEGER :: ip, jt
! This function gives the temperature (in K) on a moist adiabat ! This function gives the temperature (in K) on a moist adiabat
! (specified by thte in K) given pressure in hPa. It uses a ! (specified by thte in K) given pressure in hPa. It uses a
@ -78,22 +79,53 @@ REAL(KIND=8) FUNCTION TONPSADIABAT(thte, prs, psadithte, psadiprs, psaditmk, gam
! Otherwise, look for the given thte/prs point in the lookup table. ! Otherwise, look for the given thte/prs point in the lookup table.
jt = -1 jt = -1
DO jtch = 1, 150-1 l1 = 1
IF (thte .GE. psadithte(jtch) .AND. thte .LT. psadithte(jtch+1)) THEN h1 = 149
jt = jtch rang1 = h1 - l1
EXIT mid1 = (h1 + l1) / 2
!GO TO 213 DO WHILE(rang1 .GT. 1)
IF (thte .GE. psadithte(mid1)) THEN
l1 = mid1
ELSE
h1 = mid1
END IF END IF
rang1 = h1 - l1
mid1 = (h1 + l1) / 2
END DO END DO
jt = l1
! DO jtch = 1, 150-1
! IF (thte .GE. psadithte(jtch) .AND. thte .LT. psadithte(jtch+1)) THEN
! jt = jtch
! EXIT
! !GO TO 213
! END IF
! END DO
ip = -1 ip = -1
DO ipch = 1, 150-1 l2 = 1
IF (prs .LE. psadiprs(ipch) .AND. prs .GT. psadiprs(ipch+1)) THEN h2 = 149
ip = ipch rang2 = h2 - l2
EXIT mid2 = (h2 + l2) / 2
!GO TO 215 DO WHILE(rang2 .GT. 1)
IF (prs .LE. psadiprs(mid2)) THEN
l2 = mid2
ELSE
h2 = mid2
END IF END IF
rang2 = h2 - l2
mid2 = (h2 + l2) / 2
END DO END DO
ip = l2
! ip = -1
! DO ipch = 1, 150-1
! IF (prs .LE. psadiprs(ipch) .AND. prs .GT. psadiprs(ipch+1)) THEN
! ip = ipch
! EXIT
! !GO TO 215
! END IF
! END DO
IF (jt .EQ. -1 .OR. ip .EQ. -1) THEN IF (jt .EQ. -1 .OR. ip .EQ. -1) THEN
! Set the error and return ! Set the error and return
@ -185,35 +217,36 @@ END SUBROUTINE DLOOKUP_TABLE
! which case it assumes the lower bounding pressure level is as far ! which case it assumes the lower bounding pressure level is as far
! below the lowest vertical level as the upper bounding pressure ! below the lowest vertical level as the upper bounding pressure
! level is above. ! level is above.
SUBROUTINE DPFCALC(prs, sfp, pf, miy, mjx, mkzh, ter_follow) SUBROUTINE DPFCALC(prs, sfp, pf, mix, mjy, mkzh, ter_follow)
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(IN) :: prs REAL(KIND=8), DIMENSION(mkzh,mix,mjy), INTENT(IN) :: prs
REAL(KIND=8), DIMENSION(miy,mjx), INTENT(IN) :: sfp REAL(KIND=8), DIMENSION(mix,mjy), INTENT(IN) :: sfp
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(OUT) :: pf REAL(KIND=8), DIMENSION(mkzh,mix,mjy), INTENT(OUT) :: pf
INTEGER, INTENT(IN) :: ter_follow,miy,mjx,mkzh INTEGER, INTENT(IN) :: ter_follow,mix,mjy,mkzh
INTEGER :: i,j,k INTEGER :: i,j,k
! do j=1,mjx-1 Artifact of MM5 !$OMP PARALLEL DO COLLAPSE(3) SCHEDULE(runtime)
DO j = 1,mjx DO j = 1,mjy
! do i=1,miy-1 staggered grid DO i = 1,mix
DO i = 1,miy
DO k = 1,mkzh DO k = 1,mkzh
IF (k .EQ. mkzh) THEN IF (k .EQ. mkzh) THEN
! terrain-following data ! terrain-following data
IF (ter_follow .EQ. 1) THEN IF (ter_follow .EQ. 1) THEN
pf(i,j,k) = sfp(i,j) pf(k,i,j) = sfp(i,j)
! pressure-level data ! pressure-level data
ELSE ELSE
pf(i,j,k) = .5D0 * (3.D0*prs(i,j,k) - prs(i,j,k-1)) pf(k,i,j) = .5D0 * (3.D0*prs(k,i,j) - prs(k-1,i,j))
END IF END IF
ELSE ELSE
pf(i,j,k) = .5D0 * (prs(i,j,k+1) + prs(i,j,k)) pf(k,i,j) = .5D0 * (prs(k+1,i,j) + prs(k,i,j))
END IF END IF
END DO END DO
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN
END SUBROUTINE DPFCALC END SUBROUTINE DPFCALC
@ -224,50 +257,367 @@ END SUBROUTINE DPFCALC
! !
! !DESCRIPTION: ! !DESCRIPTION:
! !
! If i3dflag=1, this routine calculates CAPE and CIN (in m**2/s**2, ! This routine calculates CAPE and CIN (in m**2/s**2,
! or J/kg) for every grid point in the entire 3D domain (treating ! or J/kg) for every grid point in the entire 3D domain (treating
! each grid point as a parcel). If i3dflag=0, then it ! each grid point as a parcel).
! calculates CAPE and CIN only for the parcel with max theta-e in !
! Important! The z-indexes must be arranged so that mkzh (max z-index) is the
! surface pressure. So, pressure must be ordered in ascending order before
! calling this routine. Other variables must be ordered the same (p,tk,q,z).
! Also, be advised that missing data values are not checked during the computation.
! Also also, Pressure must be hPa
! NCLFORTSTART
SUBROUTINE DCAPECALC3D(prs,tmk,qvp,ght,ter,sfp,cape,cin,&
cmsg,mix,mjy,mkzh,ter_follow,&
psafile, errstat, errmsg)
USE wrf_constants, ONLY : CELKEL, G, EZERO, ESLCON1, ESLCON2, &
EPS, RD, CP, GAMMA, CPMD, RGASMD, GAMMAMD, TLCLC1, &
TLCLC2, TLCLC3, TLCLC4, THTECON1, THTECON2, THTECON3
!USE omp_lib
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: cape, cin
INTEGER, INTENT(IN) :: mix, mjy, mkzh, ter_follow
REAL(KIND=8), DIMENSION(mix,mjy,mkzh), INTENT(IN) :: prs
REAL(KIND=8), DIMENSION(mix,mjy,mkzh), INTENT(IN) :: tmk
REAL(KIND=8), DIMENSION(mix,mjy,mkzh), INTENT(IN) :: qvp
REAL(KIND=8), DIMENSION(mix,mjy,mkzh), INTENT(IN) :: ght
REAL(KIND=8), DIMENSION(mix,mjy), INTENT(IN) :: ter
REAL(KIND=8), DIMENSION(mix,mjy), INTENT(IN) ::sfp
REAL(KIND=8), DIMENSION(mix,mjy,mkzh), INTENT(OUT) :: cape
REAL(KIND=8), DIMENSION(mix,mjy,mkzh), INTENT(OUT) :: cin
REAL(KIND=8), INTENT(IN) :: cmsg
CHARACTER(LEN=*), INTENT(IN) :: psafile
INTEGER, INTENT(INOUT) :: errstat
CHARACTER(LEN=*), INTENT(INOUT) :: errmsg
! NCLFORTEND
! local variables
INTEGER :: i, j, k, ilcl, kel, kk, klcl, klev, klfc, kmax, kpar
REAL(KIND=8) :: tlcl, zlcl
REAL(KIND=8) :: ethpari, qvppari, tmkpari
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
REAL(KIND=8), DIMENSION(mkzh,mix,mjy) :: prsf
REAL(KIND=8), DIMENSION(150) :: psadithte, psadiprs
REAL(KIND=8), DIMENSION(150,150) :: psaditmk
LOGICAL :: elfound
REAL(KIND=8), DIMENSION(mkzh,mix,mjy) :: prs_new
REAL(KIND=8), DIMENSION(mkzh,mix,mjy) :: tmk_new
REAL(KIND=8), DIMENSION(mkzh,mix,mjy) :: qvp_new
REAL(KIND=8), DIMENSION(mkzh,mix,mjy) :: ght_new
! To remove compiler warnings
tmkpari = 0
qvppari = 0
klev = 0
klcl = 0
kel = 0
IF (.FALSE.) PRINT *,ter
! the comments were taken from a mark stoelinga email, 23 apr 2007,
! in response to a user getting the "outside of lookup table bounds"
! error message.
! tmkpari - initial temperature of parcel, k
! values of 300 okay. (not sure how much from this you can stray.)
! prspari - initial pressure of parcel, hpa
! values of 980 okay. (not sure how much from this you can stray.)
! thtecon1, thtecon2, thtecon3
! these are all constants, the first in k and the other two have
! no units. values of 3376, 2.54, and 0.81 were stated as being
! okay.
! tlcl - the temperature at the parcel's lifted condensation level, k
! should be a reasonable atmospheric temperature around 250-300 k
! (398 is "way too high")
! qvppari - the initial water vapor mixing ratio of the parcel,
! kg/kg (should range from 0.000 to 0.025)
!
! calculated the pressure at full sigma levels (a set of pressure
! levels that bound the layers represented by the vertical grid points)
!$OMP PARALLEL DO COLLAPSE(3) SCHEDULE(runtime)
DO j = 1,mjy
DO i = 1,mix
DO k = 1,mkzh
prs_new(k,i,j) = prs(i,j,k)
tmk_new(k,i,j) = tmk(i,j,k)
qvp_new(k,i,j) = qvp(i,j,k)
ght_new(k,i,j) = ght(i,j,k)
END DO
END DO
END DO
!$OMP END PARALLEL DO
CALL DPFCALC(prs_new, sfp, prsf, mix, mjy, mkzh, ter_follow)
! before looping, set lookup table for getting temperature on
! a pseudoadiabat.
CALL DLOOKUP_TABLE(psadithte, psadiprs, psaditmk, psafile, errstat, errmsg)
IF (errstat .NE. 0) THEN
RETURN
END IF
!$OMP PARALLEL DO COLLAPSE(2) PRIVATE(tlcl, ethpari, &
!$OMP zlcl, kk, ilcl, klcl, tmklift, tvenv, tvlift, ghtlift, &
!$OMP facden, tmkenv, qvpenv, eslift, qvplift, buoy, benamin, &
!$OMP benaccum, zrel, kmax, dz, elfound, &
!$OMP kel, klfc, &
!$OMP i, j, k, kpar) SCHEDULE(runtime)
DO j = 1,mjy
DO i = 1,mix
cape(i,j,1) = 0.D0
cin(i,j,1) = 0.D0
!!$OMP SIMD
DO kpar = 2, mkzh
! Calculate temperature and moisture properties of parcel
! (note, qvppari and tmkpari already calculated above for 2d case.)
tlcl = TLCLC1/(LOG(tmk_new(kpar,i,j)**TLCLC2/(MAX(1.D-20,qvp_new(kpar,i,j)*prs_new(kpar,i,j)/ &
(EPS + qvp_new(kpar,i,j))))) - TLCLC3) + TLCLC4
ethpari = tmk_new(kpar,i,j)*(1000.D0/prs_new(kpar,i,j))**(GAMMA*(1.D0 + GAMMAMD*qvp_new(kpar,i,j)))* &
EXP((THTECON1/tlcl - THTECON2)*qvp_new(kpar,i,j)*(1.D0 + THTECON3*qvp_new(kpar,i,j)))
zlcl = ght_new(kpar,i,j) + (tmk_new(kpar,i,j) - tlcl)/(G/CP * (1.D0 + CPMD*qvp_new(kpar,i,j)))
! Calculate buoyancy and relative height of lifted parcel at
! all levels, and store in bottom up arrays. add a level at the lcl,
! and at all points where buoyancy is zero.
!
! For arrays that go bottom to top
kk = 0
ilcl = 0
IF (ght_new(kpar,i,j) .GE. zlcl) THEN
! Initial parcel already saturated or supersaturated.
ilcl = 2
klcl = 1
END IF
!!$OMP SIMD lastprivate(qvplift,tmklift,ghtlift,tvlift,tmkenv,qvpenv,tvenv,eslift,facden)
DO k = kpar,1,-1
! For arrays that go bottom to top
kk = kk + 1
! Model level is below lcl
IF (ght_new(k,i,j) .LT. zlcl) THEN
tmklift = tmk_new(kpar,i,j) - G/(CP * (1.D0 + CPMD*qvp_new(kpar,i,j)))*&
(ght_new(k,i,j) - ght_new(kpar,i,j))
tvenv = tmk_new(k,i,j)*(EPS + qvp_new(k,i,j))/(EPS*(1.D0 + qvp_new(k,i,j)))
tvlift = tmklift*(EPS + qvp_new(kpar,i,j))/(EPS*(1.D0 + qvp_new(kpar,i,j)))
ghtlift = ght_new(k,i,j)
ELSE IF (ght(i,j,k) .GE. zlcl .AND. ilcl .EQ. 0) THEN
! This model level and previous model level straddle the lcl,
! so first create a new level in the bottom-up array, at the lcl.
facden = 1.0/(ght_new(k,i,j) - ght_new(k+1,i,j))
tmkenv = tmk_new(k+1,i,j)*((ght_new(k,i,j)-zlcl)*facden) + tmk_new(k,i,j)*&
((zlcl-ght_new(k+1,i,j))*facden)
qvpenv = qvp_new(k+1,i,j)*((ght_new(k,i,j)-zlcl)*facden) + qvp_new(k,i,j)*&
((zlcl-ght_new(k+1,i,j))*facden)
tvenv = tmkenv* (EPS + qvpenv) / (EPS * (1.D0 + qvpenv))
tvlift = tlcl* (EPS + qvp_new(kpar,i,j)) / (EPS *(1.D0 + qvp_new(kpar,i,j)))
ghtlift = zlcl
ilcl = 1
ELSE
tmklift = TONPSADIABAT(ethpari, prs_new(k,i,j), psadithte, psadiprs,&
psaditmk, GAMMA, errstat, errmsg)
eslift = EZERO*EXP(ESLCON1*(tmklift - CELKEL)/(tmklift - ESLCON2))
qvplift = EPS*eslift/(prs_new(k,i,j) - eslift)
tvenv = tmk_new(k,i,j) * (EPS + qvp_new(k,i,j)) / (EPS * (1.D0 + qvp_new(k,i,j)))
tvlift = tmklift*(EPS + qvplift) / (EPS * (1.D0 + qvplift))
ghtlift = ght_new(k,i,j)
END IF
! Buoyancy
buoy(kk) = G*(tvlift - tvenv)/tvenv
zrel(kk) = ghtlift - ght_new(kpar,i,j)
IF ((kk .GT. 1) .AND. (buoy(kk)*buoy(kk-1) .LT. 0.0D0)) THEN
! Parcel ascent curve crosses sounding curve, so create a new level
! in the bottom-up array at the crossing.
kk = kk + 1
buoy(kk) = buoy(kk-1)
zrel(kk) = zrel(kk-1)
buoy(kk-1) = 0.D0
zrel(kk-1) = zrel(kk-2) + buoy(kk-2)/&
(buoy(kk-2) - buoy(kk))*(zrel(kk) - zrel(kk-2))
END IF
IF (ilcl .EQ. 1) THEN
klcl = kk
ilcl = 2
CYCLE
END IF
END DO
kmax = kk
! IF (kmax .GT. 150) THEN
! print *,'kmax got too big'
! errstat = ALGERR
! WRITE(errmsg, *) 'capecalc3d: kmax got too big. kmax=',kmax
! RETURN
! END IF
! If no lcl was found, set klcl to kmax. it is probably not really
! at kmax, but this will make the rest of the routine behave
! properly.
IF (ilcl .EQ. 0) klcl=kmax
! Get the accumulated buoyant energy from the parcel's starting
! point, at all levels up to the top level.
benaccum(1) = 0.0D0
benamin = 9d9
DO k = 2,kmax
dz = zrel(k) - zrel(k-1)
benaccum(k) = benaccum(k-1) + .5D0*dz*(buoy(k-1) + buoy(k))
IF (benaccum(k) .LT. benamin) THEN
benamin = benaccum(k)
END IF
END DO
! Determine equilibrium level (el), which we define as the highest
! level of non-negative buoyancy above the lcl. note, this may be
! the top level if the parcel is still buoyant there.
elfound = .FALSE.
DO k = kmax,klcl,-1
IF (buoy(k) .GE. 0.D0) THEN
! k of equilibrium level
kel = k
elfound = .TRUE.
EXIT
END IF
END DO
! If we got through that loop, then there is no non-negative
! buoyancy above the lcl in the sounding. in these situations,
! both cape and cin will be set to -0.1 j/kg. (see below about
! missing values in v6.1.0). also, where cape is
! non-zero, cape and cin will be set to a minimum of +0.1 j/kg, so
! that the zero contour in either the cin or cape fields will
! circumscribe regions of non-zero cape.
! In v6.1.0 of ncl, we added a _fillvalue attribute to the return
! value of this function. at that time we decided to change -0.1
! to a more appropriate missing value, which is passed into this
! routine as cmsg.
IF (.NOT. elfound) THEN
!print *,'el not found'
cape(i,j,kpar) = cmsg
cin(i,j,kpar) = cmsg
klfc = kmax
CYCLE
END IF
! If there is an equilibrium level, then cape is positive. we'll
! define the level of free convection (lfc) as the point below the
! el, but at or above the lcl, where accumulated buoyant energy is a
! minimum. the net positive area (accumulated buoyant energy) from
! the lfc up to the el will be defined as the cape, and the net
! negative area (negative of accumulated buoyant energy) from the
! parcel starting point to the lfc will be defined as the convective
! inhibition (cin).
! First get the lfc according to the above definition.
benamin = 9D9
klfc = kmax
DO k = klcl,kel
IF (benaccum(k) .LT. benamin) THEN
benamin = benaccum(k)
klfc = k
END IF
END DO
! Now we can assign values to cape and cin
cape(i,j,kpar) = MAX(benaccum(kel)-benamin, 0.1D0)
cin(i,j,kpar) = MAX(-benamin, 0.1D0)
! cin is uninteresting when cape is small (< 100 j/kg), so set
! cin to -0.1 (see note about missing values in v6.1.0) in
! that case.
! In v6.1.0 of ncl, we added a _fillvalue attribute to the return
! value of this function. at that time we decided to change -0.1
! to a more appropriate missing value, which is passed into this
! routine as cmsg.
IF (cape(i,j,kpar) .LT. 100.D0) cin(i,j,kpar) = cmsg
END DO
END DO
END DO
!$OMP END PARALLEL DO
RETURN
END SUBROUTINE DCAPECALC3D
!======================================================================
!
! !IROUTINE: capecalc2d -- Calculate CAPE and CIN
!
! !DESCRIPTION:
!
! Calculates CAPE and CIN only for the parcel with max theta-e in
! the column, (i.e. something akin to Colman's MCAPE). By "parcel", ! the column, (i.e. something akin to Colman's MCAPE). By "parcel",
! we mean a 500-m deep parcel, with actual temperature and moisture ! we mean a 500-m deep parcel, with actual temperature and moisture
! averaged over that depth. ! averaged over that depth.
! !
! In the case of i3dflag=0,
! CAPE and CIN are 2D fields that are placed in the k=mkzh slabs of ! CAPE and CIN are 2D fields that are placed in the k=mkzh slabs of
! the cape and cin arrays. Also, if i3dflag=0, LCL and LFC heights ! the cape and cin arrays. Also, LCL and LFC heights
! are put in the k=mkzh-1 and k=mkzh-2 slabs of the cin array. ! are put in the k=mkzh-1 and k=mkzh-2 slabs of the cin array.
! !
! Important! The z-indexes must be arranged so that mkzh (max z-index) is the ! Important! The z-indexes must be arranged so that mkzh (max z-index) is the
! surface pressure. So, pressure must be ordered in ascending order before ! surface pressure. So, pressure must be ordered in ascending order before
! calling this routine. Other variables must be ordered the same (p,tk,q,z). ! calling this routine. Other variables must be ordered the same (p,tk,q,z).
! Also, be advised that missing data values are not checked during the computation. ! Also, be advised that missing data values are not checked during the
! computation.
! Also also, Pressure must be hPa ! Also also, Pressure must be hPa
! NCLFORTSTART ! NCLFORTSTART
SUBROUTINE DCAPECALC3D(prs,tmk,qvp,ght,ter,sfp,cape,cin,& SUBROUTINE DCAPECALC2D(prs,tmk,qvp,ght,ter,sfp,cape,cin,&
cmsg,miy,mjx,mkzh,i3dflag,ter_follow,& cmsg,mix,mjy,mkzh,ter_follow,&
psafile, errstat, errmsg) psafile, errstat, errmsg)
USE wrf_constants, ONLY : ALGERR, CELKEL, G, EZERO, ESLCON1, ESLCON2, & USE wrf_constants, ONLY : CELKEL, G, EZERO, ESLCON1, ESLCON2, &
EPS, RD, CP, GAMMA, CPMD, RGASMD, GAMMAMD, TLCLC1, & EPS, RD, CP, GAMMA, CPMD, RGASMD, GAMMAMD, TLCLC1, &
TLCLC2, TLCLC3, TLCLC4, THTECON1, THTECON2, THTECON3 TLCLC2, TLCLC3, TLCLC4, THTECON1, THTECON2, THTECON3
!USE omp_lib
IMPLICIT NONE IMPLICIT NONE
!f2py threadsafe !f2py threadsafe
!f2py intent(in,out) :: cape, cin !f2py intent(in,out) :: cape, cin
INTEGER, INTENT(IN) :: miy, mjx, mkzh, i3dflag, ter_follow INTEGER, INTENT(IN) :: mix, mjy, mkzh, ter_follow
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(IN) :: prs REAL(KIND=8), DIMENSION(mix,mjy,mkzh), INTENT(IN) :: prs
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(IN) :: tmk REAL(KIND=8), DIMENSION(mix,mjy,mkzh), INTENT(IN) :: tmk
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(IN) :: qvp REAL(KIND=8), DIMENSION(mix,mjy,mkzh), INTENT(IN) :: qvp
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(IN) :: ght REAL(KIND=8), DIMENSION(mix,mjy,mkzh), INTENT(IN) :: ght
REAL(KIND=8), DIMENSION(miy,mjx), INTENT(IN) :: ter REAL(KIND=8), DIMENSION(mix,mjy), INTENT(IN) :: ter
REAL(KIND=8), DIMENSION(miy,mjx), INTENT(IN) ::sfp REAL(KIND=8), DIMENSION(mix,mjy), INTENT(IN) ::sfp
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(OUT) :: cape REAL(KIND=8), DIMENSION(mix,mjy,mkzh), INTENT(OUT) :: cape
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(OUT) :: cin REAL(KIND=8), DIMENSION(mix,mjy,mkzh), INTENT(OUT) :: cin
REAL(KIND=8), INTENT(IN) :: cmsg REAL(KIND=8), INTENT(IN) :: cmsg
CHARACTER(LEN=*), INTENT(IN) :: psafile CHARACTER(LEN=*), INTENT(IN) :: psafile
INTEGER, INTENT(INOUT) :: errstat INTEGER, INTENT(INOUT) :: errstat
@ -275,26 +625,34 @@ SUBROUTINE DCAPECALC3D(prs,tmk,qvp,ght,ter,sfp,cape,cin,&
! NCLFORTEND ! NCLFORTEND
! local variables ! local variables
INTEGER :: i, j, k, ilcl, kel, kk, klcl, klev, klfc, kmax, kpar, kpar1, kpar2 INTEGER :: i, j, k, ilcl, kel, kk, klcl, klev, klfc, kmax, kpar, kpar1, kpar2
REAL(KIND=8) :: davg, ethmax, q, t, p, e, eth, tlcl, zlcl REAL(KIND=8) :: ethmax, p, e, tlcl, zlcl
REAL(KIND=8) :: pavg, tvirtual, p1, p2, pp1, pp2, th, totthe, totqvp, totprs REAL(KIND=8) :: pavg, tvirtual, p1, p2, pp1, pp2, th, totthe, totqvp, totprs
REAL(KIND=8) :: cpm, deltap, ethpari, gammam, ghtpari, qvppari, prspari, tmkpari REAL(KIND=8) :: cpm, deltap, ethpari, gammam, qvppari, tmkpari
REAL(KIND=8) :: facden, fac1, fac2, qvplift, tmklift, tvenv, tvlift, ghtlift REAL(KIND=8) :: facden, qvplift, tmklift, tvenv, tvlift, ghtlift
REAL(KIND=8) :: eslift, tmkenv, qvpenv, tonpsadiabat REAL(KIND=8) :: eslift, tmkenv, qvpenv, tonpsadiabat
REAL(KIND=8) :: benamin, dz, pup, pdn REAL(KIND=8) :: benamin, dz, pup, pdn
REAL(KIND=8), DIMENSION(150) :: buoy, zrel, benaccum REAL(KIND=8), DIMENSION(150) :: buoy, zrel, benaccum
REAL(KIND=8), DIMENSION(miy,mjx,mkzh) :: prsf REAL(KIND=8), DIMENSION(mkzh,mix,mjy) :: prsf
REAL(KIND=8), DIMENSION(150) :: psadithte, psadiprs REAL(KIND=8), DIMENSION(150) :: psadithte, psadiprs
REAL(KIND=8), DIMENSION(150,150) :: psaditmk REAL(KIND=8), DIMENSION(150,150) :: psaditmk
LOGICAL :: elfound LOGICAL :: elfound
REAL(KIND=8), DIMENSION(mkzh) :: eth_temp
REAL(KIND=8), DIMENSION(mkzh,mix,mjy) :: prs_new
REAL(KIND=8), DIMENSION(mkzh,mix,mjy) :: tmk_new
REAL(KIND=8), DIMENSION(mkzh,mix,mjy) :: qvp_new
REAL(KIND=8), DIMENSION(mkzh,mix,mjy) :: ght_new
! To remove compiler warnings ! To remove compiler warnings
errstat = 0
tmkpari = 0 tmkpari = 0
qvppari = 0 qvppari = 0
klev = 0 klev = 0
klcl = 0 klcl = 0
kel = 0 kel = 0
deltap = 0
! the comments were taken from a mark stoelinga email, 23 apr 2007, ! the comments were taken from a mark stoelinga email, 23 apr 2007,
@ -320,10 +678,23 @@ SUBROUTINE DCAPECALC3D(prs,tmk,qvp,ght,ter,sfp,cape,cin,&
! kg/kg (should range from 0.000 to 0.025) ! kg/kg (should range from 0.000 to 0.025)
! !
!$OMP PARALLEL DO COLLAPSE(3) SCHEDULE(runtime)
DO j = 1,mjy
DO i = 1,mix
DO k = 1,mkzh
prs_new(k,i,j) = prs(i,j,k)
tmk_new(k,i,j) = tmk(i,j,k)
qvp_new(k,i,j) = qvp(i,j,k)
ght_new(k,i,j) = ght(i,j,k)
END DO
END DO
END DO
!$OMP END PARALLEL DO
! calculated the pressure at full sigma levels (a set of pressure ! calculated the pressure at full sigma levels (a set of pressure
! levels that bound the layers represented by the vertical grid points) ! levels that bound the layers represented by the vertical grid points)
CALL DPFCALC(prs_new, sfp, prsf, mix, mjy, mkzh, ter_follow)
CALL DPFCALC(prs, sfp, prsf, miy, mjx, mkzh, ter_follow)
! before looping, set lookup table for getting temperature on ! before looping, set lookup table for getting temperature on
! a pseudoadiabat. ! a pseudoadiabat.
@ -334,148 +705,144 @@ SUBROUTINE DCAPECALC3D(prs,tmk,qvp,ght,ter,sfp,cape,cin,&
RETURN RETURN
END IF END IF
! do j=1,mjx-1 !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(tlcl, ethpari, &
DO j = 1,mjx !$OMP zlcl, kk, ilcl, klcl, tmklift, tvenv, tvlift, ghtlift, &
! do i=1,miy-1 !$OMP facden, tmkenv, qvpenv, eslift, qvplift, buoy, benamin, &
DO i = 1,miy !$OMP benaccum, zrel, kmax, dz, elfound, &
cape(i,j,1) = 0.d0 !$OMP kel, klfc, pavg, p2, p1, totthe, totqvp, totprs, &
cin(i,j,1) = 0.d0 !$OMP i, j, k, kpar, kpar1, kpar2, qvppari, tmkpari, p, pup, pdn, th, &
!$OMP pp1, pp2, ethmax, eth_temp, klev) SCHEDULE(runtime)
IF (i3dflag .EQ. 1) THEN DO j = 1,mjy
kpar1 = 2 DO i = 1,mix
kpar2 = mkzh cape(i,j,1) = 0.D0
ELSE cin(i,j,1) = 0.D0
! find parcel with max theta-e in lowest 3 km agl. ! find parcel with max theta-e in lowest 3 km agl.
ethmax = -1.d0 ethmax = -1.D0
DO k = mkzh,1,-1 eth_temp = -1.D0
IF (ght(i,j,k)-ter(i,j) .LT. 3000.d0) THEN DO k = 1, mkzh
q = MAX(qvp(i,j,k), 1.d-15) IF (ght_new(k,i,j)-ter(i,j) .LT. 3000.D0) THEN
t = tmk(i,j,k) tlcl = TLCLC1 / (LOG(tmk_new(k,i,j)**TLCLC2/&
p = prs(i,j,k) (MAX(qvp_new(k,i,j), 1.d-15)*prs_new(k,i,j)/(EPS+MAX(qvp_new(k,i,j), 1.d-15))))-TLCLC3)+&
e = q*p/(EPS + q) TLCLC4
tlcl = TLCLC1 / (LOG(t**TLCLC2/e)-TLCLC3) + TLCLC4 eth_temp(k) = tmk_new(k,i,j) * (1000.D0/prs_new(k,i,j))**&
eth = t * (1000.d0/p)**(GAMMA*(1.d0 + GAMMAMD*q))*& (GAMMA*(1.D0 + GAMMAMD*(MAX(qvp_new(k,i,j), 1.d-15))))*&
EXP((THTECON1/tlcl - THTECON2)*q*(1.d0 + THTECON3*q)) EXP((THTECON1/tlcl - THTECON2)*(MAX(qvp_new(k,i,j), 1.d-15))*&
IF (eth .GT. ethmax) THEN (1.D0 + THTECON3*(MAX(qvp_new(k,i,j), 1.d-15))))
klev = k
ethmax = eth
END IF END IF
END DO
klev = mkzh
DO k = 1,mkzh
IF (eth_temp(k) .GT. ethmax) THEN
klev = k
ethmax = eth_temp(k)
END IF END IF
END DO END DO
kpar1 = klev kpar1 = klev
kpar2 = klev kpar2 = klev
! Establish average properties of that parcel ! Establish average properties of that parcel
! (over depth of approximately davg meters) ! (over depth of approximately davg meters)
! davg=.1 !davg = 500.D0
davg = 500.d0 pavg = 500.D0 * prs_new(kpar1,i,j)*&
pavg = davg*prs(i,j,kpar1)*& G/(RD*tvirtual(tmk_new(kpar1,i,j), qvp_new(kpar1,i,j)))
G/(RD*tvirtual(tmk(i,j,kpar1), qvp(i,j,kpar1))) p2 = MIN(prs_new(kpar1,i,j)+.5d0*pavg, prsf(mkzh,i,j))
p2 = MIN(prs(i,j,kpar1)+.5d0*pavg, prsf(i,j,mkzh))
p1 = p2 - pavg p1 = p2 - pavg
totthe = 0.D0 totthe = 0.D0
totqvp = 0.D0 totqvp = 0.D0
totprs = 0.D0 totprs = 0.D0
DO k = mkzh,2,-1 DO k = mkzh,2,-1
IF (prsf(i,j,k) .LE. p1) EXIT !GOTO 35 IF (prsf(k,i,j) .LE. p1) EXIT !GOTO 35
IF (prsf(i,j,k-1) .GE. p2) CYCLE !GOTO 34 IF (prsf(k-1,i,j) .GE. p2) CYCLE !GOTO 34
p = prs(i,j,k) p = prs_new(k,i,j)
pup = prsf(i,j,k) pup = prsf(k,i,j)
pdn = prsf(i,j,k-1) pdn = prsf(k-1,i,j)
q = MAX(qvp(i,j,k),1.D-15) !q = MAX(qvp_new(k,i,j),1.D-15)
th = tmk(i,j,k)*(1000.D0/p)**(GAMMA*(1.D0 + GAMMAMD*q)) th = tmk_new(k,i,j)*(1000.D0/prs_new(k,i,j))**(GAMMA*(1.D0 + GAMMAMD*MAX(qvp_new(k,i,j),1.D-15)))
pp1 = MAX(p1,pdn) pp1 = MAX(p1,pdn)
pp2 = MIN(p2,pup) pp2 = MIN(p2,pup)
IF (pp2 .GT. pp1) THEN IF (pp2 .GT. pp1) THEN
deltap = pp2 - pp1 ! deltap = pp2 - pp1
totqvp = totqvp + q*deltap totqvp = totqvp + MAX(qvp_new(k,i,j),1.D-15)*(pp2 - pp1)
totthe = totthe + th*deltap totthe = totthe + th*(pp2 - pp1)
totprs = totprs + deltap totprs = totprs + (pp2 - pp1)
END IF END IF
! 34 CONTINUE
END DO END DO
! 35 CONTINUE
qvppari = totqvp/totprs qvppari = totqvp/totprs
tmkpari = (totthe/totprs)*& tmkpari = (totthe/totprs)*&
(prs(i,j,kpar1)/1000.D0)**(GAMMA*(1.D0+GAMMAMD*qvp(i,j,kpar1))) (prs_new(kpar1,i,j)/1000.D0)**(GAMMA*(1.D0+GAMMAMD*qvp_new(kpar1,i,j)))
END IF
DO kpar = kpar1, kpar2 DO kpar = kpar1, kpar2
! Calculate temperature and moisture properties of parcel ! Calculate temperature and moisture properties of parcel
! (note, qvppari and tmkpari already calculated above for 2d case.) ! (note, qvppari and tmkpari already calculated above for 2d
! case.)
IF (i3dflag .EQ. 1) THEN !prspari = prs_new(kpar,i,j)
qvppari = qvp(i,j,kpar) !ghtpari = ght_new(kpar,i,j)
tmkpari = tmk(i,j,kpar)
END IF
prspari = prs(i,j,kpar)
ghtpari = ght(i,j,kpar)
gammam = GAMMA * (1.D0 + GAMMAMD*qvppari) gammam = GAMMA * (1.D0 + GAMMAMD*qvppari)
cpm = CP * (1.D0 + CPMD*qvppari) cpm = CP * (1.D0 + CPMD*qvppari)
e = MAX(1.D-20,qvppari*prspari/(EPS + qvppari)) e = MAX(1.D-20,qvppari*prs_new(kpar,i,j)/(EPS + qvppari))
tlcl = TLCLC1/(LOG(tmkpari**TLCLC2/e) - TLCLC3) + TLCLC4 tlcl = TLCLC1/(LOG(tmkpari**TLCLC2/e) - TLCLC3) + TLCLC4
ethpari = tmkpari*(1000.D0/prspari)**(GAMMA*(1.D0 + GAMMAMD*qvppari))*& ethpari = tmkpari*(1000.D0/prs_new(kpar,i,j))**(GAMMA*(1.D0 + GAMMAMD*qvppari))*&
EXP((THTECON1/tlcl - THTECON2)*qvppari*(1.D0 + THTECON3*qvppari)) EXP((THTECON1/tlcl - THTECON2)*qvppari*(1.D0 + THTECON3*qvppari))
zlcl = ghtpari + (tmkpari - tlcl)/(G/cpm) zlcl = ght_new(kpar,i,j) + (tmkpari - tlcl)/(G/cpm)
! Calculate buoyancy and relative height of lifted parcel at ! Calculate buoyancy and relative height of lifted parcel at
! all levels, and store in bottom up arrays. add a level at the lcl, ! all levels, and store in bottom up arrays. add a level at the
! lcl,
! and at all points where buoyancy is zero. ! and at all points where buoyancy is zero.
! !
!
! For arrays that go bottom to top ! For arrays that go bottom to top
kk = 0 kk = 0
ilcl = 0 ilcl = 0
IF (ghtpari .GE. zlcl) THEN IF (ght_new(kpar,i,j) .GE. zlcl) THEN
! Initial parcel already saturated or supersaturated. ! Initial parcel already saturated or supersaturated.
ilcl = 2 ilcl = 2
klcl = 1 klcl = 1
END IF END IF
k = kpar k = kpar
DO WHILE (k .GE. 1)!k = kpar, 1, -1 DO k = kpar,1,-1
!DO k = kpar, 1, -1
! For arrays that go bottom to top ! For arrays that go bottom to top
! 33 kk = kk + 1
kk = kk + 1 kk = kk + 1
! Model level is below lcl ! Model level is below lcl
IF (ght(i,j,k) .LT. zlcl) THEN IF (ght_new(k,i,j) .LT. zlcl) THEN
qvplift = qvppari tmklift = tmk_new(kpar,i,j) - G/(CP * (1.D0 + CPMD*qvp_new(kpar,i,j)))*&
tmklift = tmkpari - G/cpm*(ght(i,j,k) - ghtpari) (ght_new(k,i,j) - ght_new(kpar,i,j))
tvenv = tvirtual(tmk(i,j,k), qvp(i,j,k)) tvenv = tmk_new(k,i,j)*(EPS + qvp_new(k,i,j))/(EPS*(1.D0 + qvp_new(k,i,j)))
tvlift = tvirtual(tmklift, qvplift) tvlift = tmklift*(EPS + qvp_new(kpar,i,j))/(EPS*(1.D0 + qvp_new(kpar,i,j)))
ghtlift = ght(i,j,k) ghtlift = ght_new(k,i,j)
ELSE IF (ght(i,j,k) .GE. zlcl .AND. ilcl .EQ. 0) THEN ELSE IF (ght(i,j,k) .GE. zlcl .AND. ilcl .EQ. 0) THEN
! This model level and previous model level straddle the lcl, ! This model level and previous model level straddle the lcl,
! so first create a new level in the bottom-up array, at the lcl. ! so first create a new level in the bottom-up array, at the lcl.
tmklift = tlcl facden = 1/(ght_new(k,i,j) - ght_new(k+1,i,j))
qvplift = qvppari tmkenv = tmk_new(k+1,i,j)*((ght_new(k,i,j)-zlcl)*facden) + tmk_new(k,i,j)*&
facden = ght(i,j,k) - ght(i,j,k+1) ((zlcl-ght_new(k+1,i,j))*facden)
fac1 = (zlcl-ght(i,j,k+1))/facden qvpenv = qvp_new(k+1,i,j)*((ght_new(k,i,j)-zlcl)*facden) + qvp_new(k,i,j)*&
fac2 = (ght(i,j,k)-zlcl)/facden ((zlcl-ght_new(k+1,i,j))*facden)
tmkenv = tmk(i,j,k+1)*fac2 + tmk(i,j,k)*fac1 tvenv = tmkenv* (EPS + qvpenv) / (EPS * (1.D0 + qvpenv))
qvpenv = qvp(i,j,k+1)*fac2 + qvp(i,j,k)*fac1 tvlift = tlcl* (EPS + qvp_new(kpar,i,j)) / (EPS *(1.D0 + qvp_new(kpar,i,j)))
tvenv = tvirtual(tmkenv, qvpenv)
tvlift = tvirtual(tmklift, qvplift)
ghtlift = zlcl ghtlift = zlcl
ilcl = 1 ilcl = 1
ELSE ELSE
tmklift = TONPSADIABAT(ethpari, prs(i,j,k), psadithte, psadiprs,& tmklift = TONPSADIABAT(ethpari, prs_new(k,i,j), psadithte, psadiprs,&
psaditmk, GAMMA, errstat, errmsg) psaditmk, GAMMA, errstat, errmsg)
eslift = EZERO*EXP(ESLCON1*(tmklift - CELKEL)/(tmklift - ESLCON2)) eslift = EZERO*EXP(ESLCON1*(tmklift - CELKEL)/(tmklift - ESLCON2))
qvplift = EPS*eslift/(prs(i,j,k) - eslift) qvplift = EPS*eslift/(prs_new(k,i,j) - eslift)
tvenv = tvirtual(tmk(i,j,k), qvp(i,j,k)) tvenv = tmk_new(k,i,j) * (EPS + qvp_new(k,i,j)) / (EPS * (1.D0 + qvp_new(k,i,j)))
tvlift = tvirtual(tmklift, qvplift) tvlift = tmklift*(EPS + qvplift) / (EPS * (1.D0 + qvplift))
ghtlift = ght(i,j,k) ghtlift = ght_new(k,i,j)
END IF END IF
! Buoyancy ! Buoyancy
buoy(kk) = G*(tvlift - tvenv)/tvenv buoy(kk) = G*(tvlift - tvenv)/tvenv
zrel(kk) = ghtlift - ghtpari zrel(kk) = ghtlift - ght_new(kpar,i,j)
IF ((kk .GT. 1) .AND. (buoy(kk)*buoy(kk-1) .LT. 0.0D0)) THEN IF ((kk .GT. 1) .AND. (buoy(kk)*buoy(kk-1) .LT. 0.0D0)) THEN
! Parcel ascent curve crosses sounding curve, so create a new level ! Parcel ascent curve crosses sounding curve, so create a new level
! in the bottom-up array at the crossing. ! in the bottom-up array at the crossing.
@ -486,25 +853,22 @@ SUBROUTINE DCAPECALC3D(prs,tmk,qvp,ght,ter,sfp,cape,cin,&
zrel(kk-1) = zrel(kk-2) + buoy(kk-2)/& zrel(kk-1) = zrel(kk-2) + buoy(kk-2)/&
(buoy(kk-2) - buoy(kk))*(zrel(kk) - zrel(kk-2)) (buoy(kk-2) - buoy(kk))*(zrel(kk) - zrel(kk-2))
END IF END IF
IF (ilcl .EQ. 1) THEN IF (ilcl .EQ. 1) THEN
klcl = kk klcl = kk
ilcl = 2 ilcl = 2
!GOTO 33
CYCLE CYCLE
END IF END IF
k = k - 1
END DO END DO
kmax = kk kmax = kk
IF (kmax .GT. 150) THEN ! IF (kmax .GT. 150) THEN
errstat = ALGERR ! errstat = ALGERR
WRITE(errmsg, *) 'capecalc3d: kmax got too big. kmax=',kmax ! WRITE(errmsg, *) 'capecalc3d: kmax got too big. kmax=',kmax
RETURN ! RETURN
END IF ! END IF
! If no lcl was found, set klcl to kmax. it is probably not really ! If no lcl was found, set klcl to kmax. it is probably not
! really
! at kmax, but this will make the rest of the routine behave ! at kmax, but this will make the rest of the routine behave
! properly. ! properly.
IF (ilcl .EQ. 0) klcl=kmax IF (ilcl .EQ. 0) klcl=kmax
@ -520,7 +884,6 @@ SUBROUTINE DCAPECALC3D(prs,tmk,qvp,ght,ter,sfp,cape,cin,&
benamin = benaccum(k) benamin = benaccum(k)
END IF END IF
END DO END DO
! Determine equilibrium level (el), which we define as the highest ! Determine equilibrium level (el), which we define as the highest
! level of non-negative buoyancy above the lcl. note, this may be ! level of non-negative buoyancy above the lcl. note, this may be
! the top level if the parcel is still buoyant there. ! the top level if the parcel is still buoyant there.
@ -532,7 +895,6 @@ SUBROUTINE DCAPECALC3D(prs,tmk,qvp,ght,ter,sfp,cape,cin,&
kel = k kel = k
elfound = .TRUE. elfound = .TRUE.
EXIT EXIT
!GOTO 50
END IF END IF
END DO END DO
@ -543,14 +905,11 @@ SUBROUTINE DCAPECALC3D(prs,tmk,qvp,ght,ter,sfp,cape,cin,&
! non-zero, cape and cin will be set to a minimum of +0.1 j/kg, so ! non-zero, cape and cin will be set to a minimum of +0.1 j/kg, so
! that the zero contour in either the cin or cape fields will ! that the zero contour in either the cin or cape fields will
! circumscribe regions of non-zero cape. ! circumscribe regions of non-zero cape.
! In v6.1.0 of ncl, we added a _fillvalue attribute to the return ! In v6.1.0 of ncl, we added a _fillvalue attribute to the return
! value of this function. at that time we decided to change -0.1 ! value of this function. at that time we decided to change -0.1
! to a more appropriate missing value, which is passed into this ! to a more appropriate missing value, which is passed into this
! routine as cmsg. ! routine as cmsg.
! cape(i,j,kpar) = -0.1D0
! cin(i,j,kpar) = -0.1D0
IF (.NOT. elfound) THEN IF (.NOT. elfound) THEN
cape(i,j,kpar) = cmsg cape(i,j,kpar) = cmsg
cin(i,j,kpar) = cmsg cin(i,j,kpar) = cmsg
@ -558,17 +917,20 @@ SUBROUTINE DCAPECALC3D(prs,tmk,qvp,ght,ter,sfp,cape,cin,&
CYCLE CYCLE
END IF END IF
! GOTO 102
! 50 CONTINUE
! If there is an equilibrium level, then cape is positive. we'll ! If there is an equilibrium level, then cape is positive.
! define the level of free convection (lfc) as the point below the ! we'll
! el, but at or above the lcl, where accumulated buoyant energy is a ! define the level of free convection (lfc) as the point below
! minimum. the net positive area (accumulated buoyant energy) from ! the
! el, but at or above the lcl, where accumulated buoyant energy
! is a
! minimum. the net positive area (accumulated buoyant energy)
! from
! the lfc up to the el will be defined as the cape, and the net ! the lfc up to the el will be defined as the cape, and the net
! negative area (negative of accumulated buoyant energy) from the ! negative area (negative of accumulated buoyant energy) from
! parcel starting point to the lfc will be defined as the convective ! the
! parcel starting point to the lfc will be defined as the
! convective
! inhibition (cin). ! inhibition (cin).
! First get the lfc according to the above definition. ! First get the lfc according to the above definition.
@ -595,23 +957,20 @@ SUBROUTINE DCAPECALC3D(prs,tmk,qvp,ght,ter,sfp,cape,cin,&
! to a more appropriate missing value, which is passed into this ! to a more appropriate missing value, which is passed into this
! routine as cmsg. ! routine as cmsg.
! IF (cape(i,j,kpar).lt.100.D0) cin(i,j,kpar) = -0.1D0
IF (cape(i,j,kpar) .LT. 100.D0) cin(i,j,kpar) = cmsg IF (cape(i,j,kpar) .LT. 100.D0) cin(i,j,kpar) = cmsg
! 102 CONTINUE
END DO END DO
IF (i3dflag .EQ. 0) THEN
cape(i,j,mkzh) = cape(i,j,kpar1) cape(i,j,mkzh) = cape(i,j,kpar1)
cin(i,j,mkzh) = cin(i,j,kpar1) cin(i,j,mkzh) = cin(i,j,kpar1)
! meters agl ! meters agl
cin(i,j,mkzh-1) = zrel(klcl) + ghtpari - ter(i,j) cin(i,j,mkzh-1) = zrel(klcl) + ght_new(kpar1,i,j) - ter(i,j)
! meters agl ! meters agl
cin(i,j,mkzh-2) = zrel(klfc) + ghtpari - ter(i,j) cin(i,j,mkzh-2) = zrel(klfc) + ght_new(kpar1,i,j) - ter(i,j)
ENDIF
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN
END SUBROUTINE DCAPECALC3D END SUBROUTINE DCAPECALC2D

100
fortran/wrf_cloud_fracf.f90

@ -18,7 +18,12 @@ SUBROUTINE DCLOUDFRAC(pres, rh, lowc, midc, highc, nz, ns, ew)
kchi = 0 kchi = 0
kcmi = 0 kcmi = 0
kclo = 0 kclo = 0
lowc = 0
midc = 0
highc = 0
!$OMP PARALLEL DO COLLAPSE(2) PRIVATE(i, j, k, kchi, kcmi, kclo) &
!$OMP SCHEDULE(runtime)
DO j = 1,ns DO j = 1,ns
DO i = 1,ew DO i = 1,ew
DO k = 1,nz-1 DO k = 1,nz-1
@ -50,7 +55,102 @@ SUBROUTINE DCLOUDFRAC(pres, rh, lowc, midc, highc, nz, ns, ew)
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN
END SUBROUTINE DCLOUDFRAC END SUBROUTINE DCLOUDFRAC
! NCLFORTSTART
SUBROUTINE DCLOUDFRAC2(vert, rh, vert_inc_w_height, low_thresh, mid_thresh, &
high_thresh, msg, lowc, midc, highc, nz, ns, ew)
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: lowc, midc, highc
INTEGER nz, ns, ew
REAL(KIND=8), DIMENSION(ew, ns, nz), INTENT(IN) :: rh, vert
REAL(KIND=8), INTENT(IN) :: low_thresh, mid_thresh, high_thresh, msg
INTEGER, INTENT(IN) :: vert_inc_w_height
REAL(KIND=8), DIMENSION(ew, ns), INTENT(OUT) :: lowc, midc, highc
! NCLEND
INTEGER i, j, k
INTEGER kchi, kcmi, kclo
! Initialize the output
lowc = 0
midc = 0
highc = 0
!$OMP PARALLEL DO COLLAPSE(2) PRIVATE(i, j, k, kchi, kcmi, kclo) &
!$OMP SCHEDULE(runtime)
DO j = 1,ns
DO i = 1,ew
! A value of -1 means 'not found'. This is needed to handle
! the mountains, where the level thresholds are below the lowest
! model level.
kchi = -1
kcmi = -1
kclo = -1
IF (vert_inc_w_height .NE. 0) THEN ! Vert coord increase with height
DO k = 1,nz
IF (vert(i,j,k) .LT. low_thresh) kclo=k
IF (vert(i,j,k) .LT. mid_thresh) kcmi=k
IF (vert(i,j,k) .LT. high_thresh) kchi=k
END DO
ELSE ! Vert coord decrease with height
DO k = 1,nz
IF (vert(i,j,k) .GT. low_thresh) kclo=k
IF (vert(i,j,k) .GT. mid_thresh) kcmi=k
IF (vert(i,j,k) .GT. high_thresh) kchi=k
END DO
ENDIF
DO k = 1,nz
IF (k .GE. kclo .AND. k .LT. kcmi) THEN
lowc(i,j) = MAX(rh(i,j,k), lowc(i,j))
ELSE IF (k .GE. kcmi .AND. k .LT. kchi) THEN ! mid cloud
midc(i,j) = MAX(rh(i,j,k), midc(i,j))
ELSE if (k .GE. kchi) THEN ! high cloud
highc(i,j) = MAX(rh(i,j,k), highc(i,j))
END IF
END DO
! Only do this when a cloud threshold is in the model vertical
! domain, otherwise it will be set to missing
IF (kclo .GE. 1) THEN
lowc(i,j) = 4.0*lowc(i,j)/100. - 3.0
lowc(i,j) = MIN(lowc(i,j), 1.0)
lowc(i,j) = MAX(lowc(i,j), 0.0)
ELSE
lowc(i,j) = msg
END IF
IF (kcmi .GE. 1) THEN
midc(i,j) = 4.0*midc(i,j)/100. - 3.0
midc(i,j) = MIN(midc(i,j), 1.0)
midc(i,j) = MAX(midc(i,j), 0.0)
ELSE
midc(i,j) = msg
END IF
IF (kchi .GE. 1) THEN
highc(i,j) = 2.5*highc(i,j)/100. - 1.5
highc(i,j) = MIN(highc(i,j), 1.0)
highc(i,j) = MAX(highc(i,j), 0.0)
ELSE
highc(i,j) = msg
END IF
END DO
END DO
!$OMP END PARALLEL DO
RETURN
END SUBROUTINE DCLOUDFRAC2

10
fortran/wrf_constants.f90

@ -9,7 +9,15 @@ MODULE wrf_constants
REAL(KIND=8), PARAMETER :: PI = 3.1415926535897932384626433D0 REAL(KIND=8), PARAMETER :: PI = 3.1415926535897932384626433D0
REAL(KIND=8), PARAMETER :: RAD_PER_DEG = PI/180.D0 REAL(KIND=8), PARAMETER :: RAD_PER_DEG = PI/180.D0
REAL(KIND=8), PARAMETER :: DEG_PER_RAD = 180.D0/PI REAL(KIND=8), PARAMETER :: DEG_PER_RAD = 180.D0/PI
REAL(KIND=8), PARAMETER :: DEFAULT_FILL = 9.9692099683868690D36 REAL(KIND=8), PARAMETER :: DEFAULT_FILL = 9.9692099683868690E36
INTEGER(KIND=1), PARAMETER :: DEFAULT_FILL_INT8 = -127
INTEGER(KIND=2), PARAMETER :: DEFAULT_FILL_INT16 = -32767
INTEGER(KIND=4), PARAMETER :: DEFAULT_FILL_INT32 = -2147483647
INTEGER(KIND=8), PARAMETER :: DEFAULT_FILL_INT64 = INT(-9223372036854775806D0, KIND=8)
REAL(KIND=4), PARAMETER :: DEFAULT_FILL_FLOAT = 9.9692099683868690E36
REAL(KIND=8), PARAMETER :: DEFAULT_FILL_DOUBLE = 9.9692099683868690E36
CHARACTER(LEN=1), PARAMETER :: DEFAULT_FILL_CHAR = ACHAR(0)
REAL(KIND=8), PARAMETER :: P1000MB = 100000.D0 REAL(KIND=8), PARAMETER :: P1000MB = 100000.D0
! j/k/kg ! j/k/kg

45
fortran/wrf_fctt.f90

@ -18,23 +18,15 @@ SUBROUTINE wrfcttcalc(prs, tk, qci, qcw, qvp, ght, ter, ctt, haveqci, nz, ns, ew
! LOCAL VARIABLES ! LOCAL VARIABLES
INTEGER i,j,k,ripk INTEGER i,j,k,ripk
!INTEGER :: mjx,miy,mkzh REAL(KIND=8) :: opdepthu, opdepthd, dp, arg1, fac, prsctt, ratmix
REAL(KIND=8) :: vt, opdepthu, opdepthd, dp REAL(KIND=8) :: arg2, agl_hgt, vt
REAL(KIND=8) :: ratmix, arg1, arg2, agl_hgt
REAL(KIND=8) :: fac, prsctt
!REAL(KIND=8) :: eps,ussalr,rgas,grav,abscoefi,abscoef,celkel,wrfout
!REAL(KIND=8) :: ght(ew,ns,nz),stuff(ew,ns)
!REAL(KIND=8), DIMENSION(ew,ns,nz) :: pf(ns,ew,nz),p1,p2
REAL(KIND=8), DIMENSION(ew,ns,nz) :: pf REAL(KIND=8), DIMENSION(ew,ns,nz) :: pf
REAL(KIND=8) :: p1, p2 REAL(KIND=8) :: p1, p2
!mjx = ew !$OMP PARALLEL
!miy = ns
!mkzh = nz
prsctt = 0 ! removes the warning ! Calculate the surface pressure
!$OMP DO COLLAPSE(2) SCHEDULE(runtime)
! Calculate the surface pressure
DO j=1,ns DO j=1,ns
DO i=1,ew DO i=1,ew
ratmix = .001D0*qvp(i,j,1) ratmix = .001D0*qvp(i,j,1)
@ -46,7 +38,9 @@ SUBROUTINE wrfcttcalc(prs, tk, qci, qcw, qvp, ght, ter, ctt, haveqci, nz, ns, ew
pf(i,j,nz) = prs(i,j,1)*(vt/(vt + USSALR*(agl_hgt)))**(arg1) pf(i,j,nz) = prs(i,j,1)*(vt/(vt + USSALR*(agl_hgt)))**(arg1)
END DO END DO
END DO END DO
!$OMP END DO
!$OMP DO COLLAPSE(3) SCHEDULE(runtime)
DO k=1,nz-1 DO k=1,nz-1
DO j=1,ns DO j=1,ns
DO i=1,ew DO i=1,ew
@ -55,26 +49,27 @@ SUBROUTINE wrfcttcalc(prs, tk, qci, qcw, qvp, ght, ter, ctt, haveqci, nz, ns, ew
END DO END DO
END DO END DO
END DO END DO
!$OMP END DO
!$OMP DO COLLAPSE(2) PRIVATE(i, j, k, ripk, opdepthd, opdepthu, &
!$OMP prsctt, dp, p1, p2, fac, arg1) SCHEDULE(runtime)
DO j=1,ns DO j=1,ns
DO i=1,ew DO i=1,ew
opdepthd = 0.D0 opdepthd = 0.D0
k = 0 k = 0
prsctt = 0
! Integrate downward from model top, calculating path at full ! Integrate downward from model top, calculating path at full
! model vertical levels. ! model vertical levels.
!20 opdepthu=opdepthd
DO k=1, nz DO k=1, nz
opdepthu = opdepthd opdepthu = opdepthd
!k=k+1
ripk = nz - k + 1 ripk = nz - k + 1
IF (k .EQ. 1) THEN IF (k .NE. 1) THEN
dp = 200.D0*(pf(i,j,1) - prs(i,j,nz)) ! should be in Pa
ELSE
dp = 100.D0*(pf(i,j,k) - pf(i,j,k-1)) ! should be in Pa dp = 100.D0*(pf(i,j,k) - pf(i,j,k-1)) ! should be in Pa
ELSE
dp = 200.D0*(pf(i,j,1) - prs(i,j,nz)) ! should be in Pa
END IF END IF
IF (haveqci .EQ. 0) then IF (haveqci .EQ. 0) then
@ -89,7 +84,6 @@ SUBROUTINE wrfcttcalc(prs, tk, qci, qcw, qvp, ght, ter, ctt, haveqci, nz, ns, ew
END IF END IF
IF (opdepthd .LT. 1. .AND. k .LT. nz) THEN IF (opdepthd .LT. 1. .AND. k .LT. nz) THEN
!GOTO 20
CYCLE CYCLE
ELSE IF (opdepthd .LT. 1. .AND. k .EQ. nz) THEN ELSE IF (opdepthd .LT. 1. .AND. k .EQ. nz) THEN
@ -111,15 +105,14 @@ SUBROUTINE wrfcttcalc(prs, tk, qci, qcw, qvp, ght, ter, ctt, haveqci, nz, ns, ew
fac = (prsctt - p1)/(p2 - p1) fac = (prsctt - p1)/(p2 - p1)
arg1 = fac*(tk(i,j,ripk) - tk(i,j,ripk+1)) - CELKEL arg1 = fac*(tk(i,j,ripk) - tk(i,j,ripk+1)) - CELKEL
ctt(i,j) = tk(i,j,ripk+1) + arg1 ctt(i,j) = tk(i,j,ripk+1) + arg1
!GOTO 40
EXIT EXIT
END IF END IF
END DO END DO
END DO END DO
END DO END DO
! 30 CONTINUE !$OMP END DO
! 40 CONTINUE
! 190 CONTINUE !$OMP END PARALLEL
RETURN RETURN
END SUBROUTINE wrfcttcalc END SUBROUTINE wrfcttcalc

28
fortran/wrf_pvo.f90

@ -23,29 +23,29 @@ SUBROUTINE DCOMPUTEABSVORT(av, u, v, msfu, msfv, msft, cor, dx, dy, nx, ny, nz,&
REAL(KIND=8) :: dsy, dsx, dudy, dvdx, avort REAL(KIND=8) :: dsy, dsx, dudy, dvdx, avort
REAL(KIND=8) :: mm REAL(KIND=8) :: mm
! PRINT*,'nx,ny,nz,nxp1,nyp1' !$OMP PARALLEL DO COLLAPSE(3) PRIVATE(i, j, k, jp1, jm1, ip1, im1, &
! PRINT*,nx,ny,nz,nxp1,nyp1 !$OMP dsx, dsy, mm, dudy, dvdx, avort) SCHEDULE(runtime)
DO k = 1,nz DO k = 1,nz
DO j = 1,ny DO j = 1,ny
DO i = 1,nx
jp1 = MIN(j+1, ny) jp1 = MIN(j+1, ny)
jm1 = MAX(j-1, 1) jm1 = MAX(j-1, 1)
DO i = 1,nx
ip1 = MIN(i+1, nx) ip1 = MIN(i+1, nx)
im1 = MAX(i-1, 1) im1 = MAX(i-1, 1)
! PRINT *,jp1,jm1,ip1,im1
dsx = (ip1 - im1) * dx dsx = (ip1 - im1) * dx
dsy = (jp1 - jm1) * dy dsy = (jp1 - jm1) * dy
mm = msft(i,j)*msft(i,j) mm = msft(i,j)*msft(i,j)
! PRINT *,j,i,u(i,jp1,k),msfu(i,jp1),u(i,jp1,k)/msfu(i,jp1)
dudy = 0.5D0*(u(i,jp1,k)/msfu(i,jp1) + u(i+1,jp1,k)/msfu(i+1,jp1) - & dudy = 0.5D0*(u(i,jp1,k)/msfu(i,jp1) + u(i+1,jp1,k)/msfu(i+1,jp1) - &
u(i,jm1,k)/msfu(i,jm1) - u(i+1,jm1,k)/msfu(i+1,jm1))/dsy*mm u(i,jm1,k)/msfu(i,jm1) - u(i+1,jm1,k)/msfu(i+1,jm1))/dsy*mm
dvdx = 0.5D0*(v(ip1,j,k)/msfv(ip1,j) + v(ip1,j+1,k)/msfv(ip1,j+1) - & dvdx = 0.5D0*(v(ip1,j,k)/msfv(ip1,j) + v(ip1,j+1,k)/msfv(ip1,j+1) - &
v(im1,j,k)/msfv(im1,j) - v(im1,j+1,k)/msfv(im1,j+1))/dsx*mm v(im1,j,k)/msfv(im1,j) - v(im1,j+1,k)/msfv(im1,j+1))/dsx*mm
avort = dvdx - dudy + cor(i,j) avort = dvdx - dudy + cor(i,j)
av(i,j,k) = avort*1.D5 av(i,j,k) = avort*1.D5
END DO END DO
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN
@ -80,22 +80,23 @@ SUBROUTINE DCOMPUTEPV(pv, u, v, theta, prs, msfu, msfv, msft, cor, dx, dy, nx, &
REAL(KIND=8) :: dsy, dsx, dp, dudy, dvdx, dudp, dvdp, dthdp, avort REAL(KIND=8) :: dsy, dsx, dp, dudy, dvdx, dudp, dvdp, dthdp, avort
REAL(KIND=8) :: dthdx, dthdy, mm REAL(KIND=8) :: dthdx, dthdy, mm
! PRINT*,'nx,ny,nz,nxp1,nyp1' !$OMP PARALLEL DO COLLAPSE(3) PRIVATE(i, j, k, kp1, km1, jp1, jm1, ip1, &
! PRINT*,nx,ny,nz,nxp1,nyp1 !$OMP im1, dsx, dsy, mm, dudy, dvdx, avort, &
!$OMP dp, dudp, dvdp, dthdp, dthdx, dthdy) SCHEDULE(runtime)
DO k = 1,nz DO k = 1,nz
DO J = 1,ny
DO i = 1,nx
kp1 = MIN(k+1, nz) kp1 = MIN(k+1, nz)
km1 = MAX(k-1, 1) km1 = MAX(k-1, 1)
DO J = 1,ny
jp1 = MIN(j+1, ny) jp1 = MIN(j+1, ny)
jm1 = MAX(j-1, 1) jm1 = MAX(j-1, 1)
DO i = 1,nx
ip1 = MIN(i+1, nx) ip1 = MIN(i+1, nx)
im1 = MAX(i-1, 1) im1 = MAX(i-1, 1)
! PRINT *,jp1,jm1,ip1,im1
dsx = (ip1 - im1)*dx dsx = (ip1 - im1)*dx
dsy = (jp1 - jm1)*dy dsy = (jp1 - jm1)*dy
mm = msft(i,j)*msft(i,j) mm = msft(i,j)*msft(i,j)
! PRINT *,j,i,u(i,jp1,k),msfu(i,jp1),u(i,jp1,k)/msfu(i,jp1)
dudy = 0.5D0*(u(i,jp1,k)/msfu(i,jp1) + u(i+1,jp1,k)/msfu(i+1,jp1) - & dudy = 0.5D0*(u(i,jp1,k)/msfu(i,jp1) + u(i+1,jp1,k)/msfu(i+1,jp1) - &
u(i,jm1,k)/msfu(i,jm1) - u(i+1,jm1,k)/msfu(i+1,jm1))/dsy*mm u(i,jm1,k)/msfu(i,jm1) - u(i+1,jm1,k)/msfu(i+1,jm1))/dsy*mm
dvdx = 0.5D0*(v(ip1,j,k)/msfv(ip1,j) + v(ip1,j+1,k)/msfv(ip1,j+1) - & dvdx = 0.5D0*(v(ip1,j,k)/msfv(ip1,j) + v(ip1,j+1,k)/msfv(ip1,j+1) - &
@ -108,14 +109,11 @@ SUBROUTINE DCOMPUTEPV(pv, u, v, theta, prs, msfu, msfv, msft, cor, dx, dy, nx, &
dthdx = (theta(ip1,j,k) - theta(im1,j,k))/dsx*msft(i,j) dthdx = (theta(ip1,j,k) - theta(im1,j,k))/dsx*msft(i,j)
dthdy = (theta(i,jp1,k) - theta(i,jm1,k))/dsy*msft(i,j) dthdy = (theta(i,jp1,k) - theta(i,jm1,k))/dsy*msft(i,j)
pv(i,j,k) = -G*(dthdp*avort - dvdp*dthdx + dudp*dthdy)*10000.D0 pv(i,j,k) = -G*(dthdp*avort - dvdp*dthdx + dudp*dthdy)*10000.D0
! if(i.eq.300 .and. j.eq.300) then
! PRINT*,'avort,dudp,dvdp,dthdp,dthdx,dthdy,pv'
! PRINT*,avort,dudp,dvdp,dthdp,dthdx,dthdy,pv(i,j,k)
! endif
pv(i,j,k) = pv(i,j,k)*1.D2 pv(i,j,k) = pv(i,j,k)*1.D2
END DO END DO
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN

7
fortran/wrf_pw.f90

@ -18,14 +18,21 @@ SUBROUTINE DCOMPUTEPW(p, tv, qv, ht, pw, nx, ny, nz, nzh)
!REAL(KIND=8),PARAMETER :: R=287.06 !REAL(KIND=8),PARAMETER :: R=287.06
pw = 0 pw = 0
!$OMP PARALLEL
DO k=1,nz DO k=1,nz
!$OMP DO COLLAPSE(2) SCHEDULE(runtime)
DO j=1,ny DO j=1,ny
DO i=1,nx DO i=1,nx
pw(i,j) = pw(i,j) + ((p(i,j,k)/(RD*tv(i,j,k)))*qv(i,j,k)*(ht(i,j,k+1) - ht(i,j,k))) pw(i,j) = pw(i,j) + ((p(i,j,k)/(RD*tv(i,j,k)))*qv(i,j,k)*(ht(i,j,k+1) - ht(i,j,k)))
END DO END DO
END DO END DO
!$OMP END DO
END DO END DO
!$OMP END PARALLEL
RETURN RETURN
END SUBROUTINE DCOMPUTEPW END SUBROUTINE DCOMPUTEPW

9
fortran/wrf_relhl.f90

@ -56,10 +56,10 @@ SUBROUTINE DCALRELHL(u, v, ght, ter, top, sreh, miy, mjx, mkzh)
INTEGER :: i, j, k, k10, k3, ktop INTEGER :: i, j, k, k10, k3, ktop
!REAL(KIND=8), PARAMETER :: DTR=PI/180.d0, DPR=180.d0/PI !REAL(KIND=8), PARAMETER :: DTR=PI/180.d0, DPR=180.d0/PI
!DO j = 1, mjx-1 !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(i,j,k,k10,k3,ktop, cu, cv, x, &
!$OMP sum, dh, sdh, su, sv, ua, va, asp, adr, bsp, bdr) SCHEDULE(runtime)
DO j=1, mjx DO j=1, mjx
DO i=1, miy DO i=1, miy
!DO i=1, miy-1
sdh = 0.D0 sdh = 0.D0
su = 0.D0 su = 0.D0
sv = 0.D0 sv = 0.D0
@ -82,12 +82,14 @@ SUBROUTINE DCALRELHL(u, v, ght, ter, top, sreh, miy, mjx, mkzh)
IF (k10 .EQ. 0) THEN IF (k10 .EQ. 0) THEN
k10 = 2 k10 = 2
ENDIF ENDIF
DO k = k3, k10, -1 DO k = k3, k10, -1
dh = ght(i,j,k-1) - ght(i,j,k) dh = ght(i,j,k-1) - ght(i,j,k)
sdh = sdh + dh sdh = sdh + dh
su = su + 0.5D0*dh*(u(i,j,k-1) + u(i,j,k)) su = su + 0.5D0*dh*(u(i,j,k-1) + u(i,j,k))
sv = sv + 0.5D0*dh*(v(i,j,k-1) + v(i,j,k)) sv = sv + 0.5D0*dh*(v(i,j,k-1) + v(i,j,k))
END DO END DO
ua = su/sdh ua = su/sdh
va = sv/sdh va = sv/sdh
asp = SQRT(ua*ua + va*va) asp = SQRT(ua*ua + va*va)
@ -96,11 +98,13 @@ SUBROUTINE DCALRELHL(u, v, ght, ter, top, sreh, miy, mjx, mkzh)
ELSE ELSE
adr = DEG_PER_RAD * (PI + ATAN2(ua,va)) adr = DEG_PER_RAD * (PI + ATAN2(ua,va))
ENDIF ENDIF
bsp = 0.75D0*asp bsp = 0.75D0*asp
bdr = adr + 30.D0 bdr = adr + 30.D0
IF (bdr .GT. 360.D0) THEN IF (bdr .GT. 360.D0) THEN
bdr = bdr - 360.D0 bdr = bdr - 360.D0
ENDIF ENDIF
cu = -bsp*SIN(bdr * RAD_PER_DEG) cu = -bsp*SIN(bdr * RAD_PER_DEG)
cv = -bsp*COS(bdr * RAD_PER_DEG) cv = -bsp*COS(bdr * RAD_PER_DEG)
sum = 0.D0 sum = 0.D0
@ -112,6 +116,7 @@ SUBROUTINE DCALRELHL(u, v, ght, ter, top, sreh, miy, mjx, mkzh)
sreh(i,j) = -sum sreh(i,j) = -sum
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN

108
fortran/wrf_rip_phys_routines.f90

@ -50,13 +50,23 @@ SUBROUTINE WETBULBCALC(prs, tmk, qvp, twb, nx, ny, nz, psafile, errstat, errmsg)
!NCLEND !NCLEND
INTEGER :: i, j, k INTEGER :: i, j, k
INTEGER :: jtch, jt, ipch, ip INTEGER :: jt, ip
REAL(KIND=8) :: q, t, p, e, tlcl, eth REAL(KIND=8) :: q, t, p, e, tlcl, eth
REAL(KIND=8) :: fracip, fracip2, fracjt, fracjt2 REAL(KIND=8) :: fracip, fracip2, fracjt, fracjt2
REAL(KIND=8), DIMENSION(150) :: PSADITHTE, PSADIPRS REAL(KIND=8), DIMENSION(150) :: PSADITHTE, PSADIPRS
REAL(KIND=8), DIMENSION(150,150) :: PSADITMK REAL(KIND=8), DIMENSION(150,150) :: PSADITMK
REAL(KIND=8) :: tonpsadiabat REAL(KIND=8) :: tonpsadiabat
INTEGER :: l1, h1, mid1, rang1, l2, h2, mid2, rang2
INTEGER :: errcnt1, errcnt2, bad_i, bad_j, bad_k
REAL(KIND=8) :: bad_p, bad_eth
!INTEGER :: ip, ipch, jt, jtch
errcnt1 = 0
errcnt2 = 0
bad_i = -1
bad_j = -1
bad_k = -1
! Before looping, set lookup table for getting temperature on ! Before looping, set lookup table for getting temperature on
! a pseudoadiabat. ! a pseudoadiabat.
@ -67,6 +77,10 @@ SUBROUTINE WETBULBCALC(prs, tmk, qvp, twb, nx, ny, nz, psafile, errstat, errmsg)
RETURN RETURN
END IF END IF
!$OMP PARALLEL DO COLLAPSE(3) PRIVATE (i, j, k, jt, ip, q, t, p, e, tlcl, &
!$OMP eth, fracip, fracip2, fracjt, fracjt2, l1, h1, mid1, rang1, l2, h2, &
!$OMP mid2, rang2, tonpsadiabat) REDUCTION(+:errcnt1, errcnt2) &
!$OMP SCHEDULE(runtime)
DO k=1,nz DO k=1,nz
DO j=1,ny DO j=1,ny
DO i=1,nx DO i=1,nx
@ -92,26 +106,51 @@ SUBROUTINE WETBULBCALC(prs, tmk, qvp, twb, nx, ny, nz, psafile, errstat, errmsg)
tonpsadiabat = eth*(p/1000.)**GAMMA tonpsadiabat = eth*(p/1000.)**GAMMA
ELSE ELSE
! Otherwise, look for the given thte/prs point in the lookup table. ! Otherwise, look for the given thte/prs point in the lookup table.
jt=-1 jt = -1
DO jtch=1,150-1 l1 = 1
IF (eth .GE. PSADITHTE(jtch) .AND. eth .LT. PSADITHTE(jtch+1)) THEN h1 = 149
jt = jtch rang1 = h1 - l1
EXIT mid1 = (h1 + l1) / 2
ENDIF DO WHILE(rang1 .GT. 1)
IF (eth .GE. psadithte(mid1)) THEN
l1 = mid1
ELSE
h1 = mid1
END IF
rang1 = h1 - l1
mid1 = (h1 + l1) / 2
END DO END DO
jt = l1
ip=-1
DO ipch=1,150-1 ip = -1
IF (p .LE. PSADIPRS(ipch) .AND. p .GT. PSADIPRS(ipch+1)) THEN l2 = 1
ip = ipch h2 = 149
EXIT rang2 = h2 - l2
ENDIF mid2 = (h2 + l2) / 2
DO WHILE(rang2 .GT. 1)
IF (p .LE. psadiprs(mid2)) THEN
l2 = mid2
ELSE
h2 = mid2
END IF
rang2 = h2 - l2
mid2 = (h2 + l2) / 2
END DO END DO
ip = l2
IF (jt .EQ. -1 .OR. ip .EQ. -1) THEN IF (jt .EQ. -1 .OR. ip .EQ. -1) THEN
errstat = ALGERR errcnt1 = errcnt1 + 1
WRITE(errmsg, *) "Outside of lookup table bounds. prs,thte=", p, eth !$OMP CRITICAL
RETURN ! Only do this the first time
IF (bad_i .EQ. -1) THEN
bad_i = i
bad_j = j
bad_k = k
bad_p = p
bad_eth = eth
END IF
!$OMP END CRITICAL
CYCLE
ENDIF ENDIF
fracjt = (eth - PSADITHTE(jt))/(PSADITHTE(jt+1) - PSADITHTE(jt)) fracjt = (eth - PSADITHTE(jt))/(PSADITHTE(jt+1) - PSADITHTE(jt))
@ -119,12 +158,21 @@ SUBROUTINE WETBULBCALC(prs, tmk, qvp, twb, nx, ny, nz, psafile, errstat, errmsg)
fracip = (PSADIPRS(ip) - p)/(PSADIPRS(ip) - PSADIPRS(ip+1)) fracip = (PSADIPRS(ip) - p)/(PSADIPRS(ip) - PSADIPRS(ip+1))
fracip2 = 1. - fracip fracip2 = 1. - fracip
IF (PSADITMK(ip,jt) .GT. 1e9 .OR. PSADITMK(ip+1,jt) .GT. 1e9 .OR. & IF (PSADITMK(ip,jt) .GT. 1e9 .OR. PSADITMK(ip+1,jt) .GT. 1e9 .OR. &
PSADITMK(ip,jt+1) .GT. 1e9 .OR. PSADITMK(ip+1,jt+1) .GT. 1e9) THEN PSADITMK(ip,jt+1) .GT. 1e9 .OR. PSADITMK(ip+1,jt+1) .GT. 1e9) THEN
!PRINT*,'Tried to access missing tmperature in lookup table.' errcnt2 = errcnt2 + 1
errstat = ALGERR !$OMP CRITICAL
WRITE(errmsg, *) "Prs and Thte probably unreasonable. prs, thte=", p, eth ! Only do this the first time
RETURN IF (bad_i .EQ. -1) THEN
bad_i = i
bad_j = j
bad_k = k
bad_p = p
bad_eth = eth
END IF
!$OMP END CRITICAL
CYCLE
ENDIF ENDIF
tonpsadiabat = fracip2*fracjt2*PSADITMK(ip,jt) + & tonpsadiabat = fracip2*fracjt2*PSADITMK(ip,jt) + &
@ -139,6 +187,20 @@ SUBROUTINE WETBULBCALC(prs, tmk, qvp, twb, nx, ny, nz, psafile, errstat, errmsg)
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
IF (errcnt1 > 0) THEN
errstat = ALGERR
WRITE(errmsg, *) "Outside of lookup table bounds. i=", bad_i, ",j=", bad_j, ",k=", bad_k, ",p=", bad_p, ",eth=", bad_eth
RETURN
END IF
IF (errcnt2 > 0) THEN
errstat = ALGERR
WRITE(errmsg, *) "PRS and THTE unreasonable. i=", bad_i, ",j=", bad_j, ",k=", bad_k, ",p=", bad_p, ",eth=", bad_eth
RETURN
END IF
RETURN RETURN
END SUBROUTINE WETBULBCALC END SUBROUTINE WETBULBCALC
@ -195,6 +257,7 @@ SUBROUTINE OMGCALC(qvp, tmk, www, prs, omg, mx, my, mz)
INTEGER :: i, j, k INTEGER :: i, j, k
!REAL(KIND=8), PARAMETER :: GRAV=9.81, RGAS=287.04, EPS=0.622 !REAL(KIND=8), PARAMETER :: GRAV=9.81, RGAS=287.04, EPS=0.622
!$OMP PARALLEL DO COLLAPSE(3) SCHEDULE(runtime)
DO k=1,mz DO k=1,mz
DO j=1,my DO j=1,my
DO i=1,mx DO i=1,mx
@ -204,6 +267,7 @@ SUBROUTINE OMGCALC(qvp, tmk, www, prs, omg, mx, my, mz)
END DO END DO
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN
@ -255,6 +319,7 @@ SUBROUTINE VIRTUAL_TEMP(temp, ratmix, tv, nx, ny, nz)
INTEGER :: i,j,k INTEGER :: i,j,k
!REAL(KIND=8),PARAMETER :: EPS = 0.622D0 !REAL(KIND=8),PARAMETER :: EPS = 0.622D0
!$OMP PARALLEL DO COLLAPSE(3) SCHEDULE(runtime)
DO k=1,nz DO k=1,nz
DO j=1,ny DO j=1,ny
DO i=1,nx DO i=1,nx
@ -262,6 +327,7 @@ SUBROUTINE VIRTUAL_TEMP(temp, ratmix, tv, nx, ny, nz)
END DO END DO
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN

214
fortran/wrf_user.f90

@ -16,6 +16,7 @@ SUBROUTINE DCOMPUTEPI(pi, pressure, nx, ny, nz)
!REAL(KIND=8), PARAMETER :: P1000MB=100000.D0, R_D=287.D0, CP=7.D0*R_D/2.D0 !REAL(KIND=8), PARAMETER :: P1000MB=100000.D0, R_D=287.D0, CP=7.D0*R_D/2.D0
!$OMP PARALLEL DO COLLAPSE(3) SCHEDULE(runtime)
DO k = 1,nz DO k = 1,nz
DO j = 1,ny DO j = 1,ny
DO i = 1,nx DO i = 1,nx
@ -23,6 +24,7 @@ SUBROUTINE DCOMPUTEPI(pi, pressure, nx, ny, nz)
END DO END DO
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
END SUBROUTINE DCOMPUTEPI END SUBROUTINE DCOMPUTEPI
@ -37,7 +39,7 @@ SUBROUTINE DCOMPUTETK(tk, pressure, theta, nx)
!f2py intent(in,out) :: tk !f2py intent(in,out) :: tk
INTEGER, INTENT(IN) :: nx INTEGER, INTENT(IN) :: nx
REAL(KIND=8) :: pi !REAL(KIND=8) :: pi
REAL(KIND=8), DIMENSION(nx), INTENT(IN) :: pressure REAL(KIND=8), DIMENSION(nx), INTENT(IN) :: pressure
REAL(KIND=8), DIMENSION(nx), INTENT(IN) :: theta REAL(KIND=8), DIMENSION(nx), INTENT(IN) :: theta
REAL(KIND=8), DIMENSION(nx), INTENT(OUT) :: tk REAL(KIND=8), DIMENSION(nx), INTENT(OUT) :: tk
@ -48,10 +50,13 @@ SUBROUTINE DCOMPUTETK(tk, pressure, theta, nx)
!REAL(KIND=8), PARAMETER :: P1000MB=100000.D0, RD=287.D0, CP=7.D0*RD/2.D0 !REAL(KIND=8), PARAMETER :: P1000MB=100000.D0, RD=287.D0, CP=7.D0*RD/2.D0
!$OMP PARALLEL DO SCHEDULE(runtime)
DO i = 1,nx DO i = 1,nx
pi = (pressure(i)/P1000MB)**(RD/CP) !pi = (pressure(i)/P1000MB)**(RD/CP)
tk(i) = pi*theta(i) !tk(i) = pi * theta(i)
tk(i) = (pressure(i)/P1000MB)**(RD/CP) * theta(i)
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN
@ -76,9 +81,7 @@ SUBROUTINE DINTERP3DZ(data3d, out2d, zdata, desiredloc, nx, ny, nz, missingval)
INTEGER :: i,j,kp,ip,im INTEGER :: i,j,kp,ip,im
LOGICAL :: dointerp LOGICAL :: dointerp
REAL(KIND=8) :: height,w1,w2 REAL(KIND=8) :: w1,w2
height = desiredloc
! does vertical coordinate increase or decrease with increasing k? ! does vertical coordinate increase or decrease with increasing k?
! set offset appropriately ! set offset appropriately
@ -90,6 +93,8 @@ SUBROUTINE DINTERP3DZ(data3d, out2d, zdata, desiredloc, nx, ny, nz, missingval)
im = 0 im = 0
END IF END IF
!$OMP PARALLEL DO COLLAPSE(2) PRIVATE(i,j,kp,dointerp,w1,w2) &
!$OMP FIRSTPRIVATE(ip,im) SCHEDULE(runtime)
DO i = 1,nx DO i = 1,nx
DO j = 1,ny DO j = 1,ny
! Initialize to missing. Was initially hard-coded to -999999. ! Initialize to missing. Was initially hard-coded to -999999.
@ -98,17 +103,17 @@ SUBROUTINE DINTERP3DZ(data3d, out2d, zdata, desiredloc, nx, ny, nz, missingval)
kp = nz kp = nz
DO WHILE ((.NOT. dointerp) .AND. (kp >= 2)) DO WHILE ((.NOT. dointerp) .AND. (kp >= 2))
IF (((zdata(i,j,kp-im) < height) .AND. (zdata(i,j,kp-ip) > height))) THEN IF (((zdata(i,j,kp-im) < desiredloc) .AND. (zdata(i,j,kp-ip) > desiredloc))) THEN
w2 = (height - zdata(i,j,kp-im))/(zdata(i,j,kp-ip) - zdata(i,j,kp-im)) w2 = (desiredloc - zdata(i,j,kp-im))/(zdata(i,j,kp-ip) - zdata(i,j,kp-im))
w1 = 1.D0 - w2 w1 = 1.D0 - w2
out2d(i,j) = w1*data3d(i,j,kp-im) + w2*data3d(i,j,kp-ip) out2d(i,j) = w1*data3d(i,j,kp-im) + w2*data3d(i,j,kp-ip)
dointerp = .TRUE. dointerp = .TRUE.
END IF END IF
kp = kp - 1 kp = kp - 1
END DO END DO
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN
@ -195,6 +200,8 @@ SUBROUTINE DINTERP2DXY(v3d, v2d, xy, nx, ny, nz, nxy)
INTEGER :: i, j, k, ij INTEGER :: i, j, k, ij
REAL(KIND=8) :: w11, w12, w21, w22, wx, wy REAL(KIND=8) :: w11, w12, w21, w22, wx, wy
!$OMP PARALLEL DO PRIVATE(i,j,k,ij,w11,w12,w21,w22,wx,wy) &
!$OMP SCHEDULE(runtime)
DO ij = 1,nxy DO ij = 1,nxy
i = MAX(1,MIN(nx-1,INT(xy(1,ij)+1))) i = MAX(1,MIN(nx-1,INT(xy(1,ij)+1)))
j = MAX(1,MIN(ny-1,INT(xy(2,ij)+1))) j = MAX(1,MIN(ny-1,INT(xy(2,ij)+1)))
@ -209,6 +216,7 @@ SUBROUTINE DINTERP2DXY(v3d, v2d, xy, nx, ny, nz, nxy)
w12*v3d(i,j+1,k) + w22*v3d(i+1,j+1,k) w12*v3d(i,j+1,k) + w22*v3d(i+1,j+1,k)
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN
@ -245,6 +253,8 @@ SUBROUTINE DINTERP1D(v_in, v_out, z_in, z_out, vmsg, nz_in, nz_out)
im = 0 im = 0
END IF END IF
!$OMP PARALLEL DO PRIVATE(kp, k, interp, height, w1, w2) &
!$OMP FIRSTPRIVATE(ip, im) SCHEDULE(runtime)
DO k = 1,nz_out DO k = 1,nz_out
v_out(k) = vmsg v_out(k) = vmsg
@ -262,6 +272,7 @@ SUBROUTINE DINTERP1D(v_in, v_out, z_in, z_out, vmsg, nz_in, nz_out)
kp = kp - 1 kp = kp - 1
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN
@ -316,10 +327,12 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, &
INTEGER :: i, j, k INTEGER :: i, j, k
INTEGER :: klo, khi INTEGER :: klo, khi
INTEGER :: errcnt, bad_i, bad_j
REAL(KIND=8) :: bad_sfp
REAL(KIND=8) :: plo, phi, tlo, thi, zlo, zhi REAL(KIND=8) :: plo, phi, tlo, thi, zlo, zhi
REAL(KIND=8) :: p_at_pconst, t_at_pconst, z_at_pconst REAL(KIND=8) :: p_at_pconst, t_at_pconst, z_at_pconst
REAL(KIND=8) :: z_half_lowest !REAL(KIND=8) :: z_half_lowest
LOGICAL :: l1, l2, l3, found LOGICAL :: l1, l2, l3, found
@ -329,7 +342,13 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, &
! heating cycle in the pressure field. ! heating cycle in the pressure field.
errstat = 0 errstat = 0
errcnt = 0
bad_i = -1
bad_j = -1
bad_sfp = -1
!$OMP PARALLEL DO COLLAPSE(2) PRIVATE(i,j,k,found) REDUCTION(+:errcnt) &
!$OMP SCHEDULE(runtime)
DO j = 1,ny DO j = 1,ny
DO i = 1,nx DO i = 1,nx
level(i,j) = -1 level(i,j) = -1
@ -345,22 +364,31 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, &
END DO END DO
IF (level(i,j) == -1) THEN IF (level(i,j) == -1) THEN
errstat = ALGERR errcnt = errcnt + 1
errmsg = "Error in finding 100 hPa up" !$OMP CRITICAL
RETURN ! Only do this the first time
IF (bad_i .EQ. -1) THEN
!PRINT '(A,I4,A)','Troubles finding level ', NINT(PCONST)/100,' above ground.' bad_i = i
!PRINT '(A,I4,A,I4,A)','Problems first occur at (',I,',',J,')' bad_j = j
!PRINT '(A,F6.1,A)','Surface pressure = ',p(i,j,1)/100,' hPa.' bad_sfp = p(i,j,1) / 100.
!STOP 'Error in finding 100 hPa up' END IF
!$OMP END CRITICAL
END IF END IF
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
IF (errcnt > 0) THEN
errstat = ALGERR
WRITE(errmsg,*) "Error in finding 100 hPa up. i=", bad_i, "j=", bad_j, "sfc_p=", bad_sfp
RETURN
END IF
! Get temperature PCONST Pa above surface. Use this to extrapolate ! Get temperature PCONST Pa above surface. Use this to extrapolate
! the temperature at the surface and down to sea level. ! the temperature at the surface and down to sea level.
!$OMP PARALLEL DO COLLAPSE(2) PRIVATE(i,j,klo,khi,plo, &
!$OMP phi,tlo,thi,zlo,zhi,p_at_pconst,t_at_pconst,z_at_pconst) &
!$OMP REDUCTION(+:errcnt) SCHEDULE(runtime)
DO j = 1,ny DO j = 1,ny
DO i = 1,nx DO i = 1,nx
@ -368,39 +396,43 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, &
khi = MIN(klo+1, nz-1) khi = MIN(klo+1, nz-1)
IF (klo == khi) THEN IF (klo == khi) THEN
errstat = ALGERR errcnt = errcnt + 1
errmsg = "Error trapping levels" !$OMP CRITICAL
RETURN IF (bad_i .EQ. -1) THEN
bad_i = i
!PRINT '(A)','Trapping levels are weird.' bad_j = j
!PRINT '(A,I3,A,I3,A)','klo = ',klo,', khi = ',khi,': and they should not be equal.' END IF
!STOP 'Error trapping levels' !$OMP END CRITICAL
END IF END IF
plo = p(i,j,klo) plo = p(i,j,klo)
phi = p(i,j,khi) phi = p(i,j,khi)
tlo = t(i,j,klo)*(1.D0 + 0.608D0*q(i,j,klo)) tlo = t(i,j,klo)*(1.D0 + 0.608D0*q(i,j,klo))
thi = t(i,j,khi)*(1.D0 + 0.608D0*q(i,j,khi)) thi = t(i,j,khi)*(1.D0 + 0.608D0*q(i,j,khi))
! zlo = zetahalf(klo)/ztop*(ztop-terrain(i,j))+terrain(i,j)
! zhi = zetahalf(khi)/ztop*(ztop-terrain(i,j))+terrain(i,j)
zlo = z(i,j,klo) zlo = z(i,j,klo)
zhi = z(i,j,khi) zhi = z(i,j,khi)
p_at_pconst = p(i,j,1) - PCONST p_at_pconst = p(i,j,1) - PCONST
t_at_pconst = thi - (thi-tlo)*LOG(p_at_pconst/phi)*LOG(plo/phi) t_at_pconst = thi - (thi-tlo)*LOG(p_at_pconst/phi)*LOG(plo/phi)
z_at_pconst = zhi - (zhi-zlo)*LOG(p_at_pconst/phi)*LOG(plo/phi) z_at_pconst = zhi - (zhi-zlo)*LOG(p_at_pconst/phi)*LOG(plo/phi)
!
t_surf(i,j) = t_at_pconst * (p(i,j,1)/p_at_pconst)**(USSALR*RD/G) t_surf(i,j) = t_at_pconst * (p(i,j,1)/p_at_pconst)**(USSALR*RD/G)
t_sea_level(i,j) = t_at_pconst + USSALR*z_at_pconst t_sea_level(i,j) = t_at_pconst + USSALR*z_at_pconst
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
IF (errcnt > 0) THEN
errstat = ALGERR
WRITE(errmsg,*) "Error trapping levels at i=", bad_i, "j=", bad_j
RETURN
END IF
! If we follow a traditional computation, there is a correction to the ! If we follow a traditional computation, there is a correction to the
! sea level temperature if both the surface and sea level ! sea level temperature if both the surface and sea level
! temperatures are *too* hot. ! temperatures are *too* hot.
IF (ridiculous_mm5_test) THEN IF (ridiculous_mm5_test) THEN
!$OMP PARALLEL DO COLLAPSE(2) PRIVATE(l1,l2,l3) SCHEDULE(runtime)
DO j = 1,ny DO j = 1,ny
DO i = 1,nx DO i = 1,nx
l1 = t_sea_level(i,j) < TC l1 = t_sea_level(i,j) < TC
@ -413,21 +445,23 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, &
END IF END IF
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
END IF END IF
! The grand finale: ta da! ! The grand finale: ta da!
!$OMP PARALLEL DO COLLAPSE(2) SCHEDULE(runtime)
DO j = 1,ny DO j = 1,ny
DO i = 1,nx DO i = 1,nx
! z_half_lowest=zetahalf(1)/ztop*(ztop-terrain(i,j))+terrain(i,j) !z_half_lowest = z(i,j,1)
z_half_lowest = z(i,j,1)
! Convert to hPa in this step, by multiplying by 0.01. The original ! Convert to hPa in this step, by multiplying by 0.01. The original
! Fortran routine didn't do this, but the NCL script that called it ! Fortran routine didn't do this, but the NCL script that called it
! did, so we moved it here. ! did, so we moved it here.
sea_level_pressure(i,j) = 0.01*(p(i,j,1)*EXP((2.D0*G*z_half_lowest)/& sea_level_pressure(i,j) = 0.01*(p(i,j,1)*EXP((2.D0*G*z(i,j,1))/&
(RD*(t_sea_level(i,j) + t_surf(i,j))))) (RD*(t_sea_level(i,j) + t_surf(i,j)))))
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
! PRINT *,'sea pres input at weird location i=20,j=1,k=1' ! PRINT *,'sea pres input at weird location i=20,j=1,k=1'
! PRINT *,'t=',t(20,1,1),t(20,2,1),t(20,3,1) ! PRINT *,'t=',t(20,1,1),t(20,2,1),t(20,3,1)
@ -464,12 +498,15 @@ SUBROUTINE DFILTER2D(a, b, nx, ny, it, missing)
INTEGER :: i, j, iter INTEGER :: i, j, iter
DO iter=1,it DO iter=1,it
!$OMP PARALLEL DO COLLAPSE(2) SCHEDULE(runtime)
DO j=1,ny DO j=1,ny
DO i = 1,nx DO i = 1,nx
b(i,j) = a(i,j) b(i,j) = a(i,j)
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
!$OMP PARALLEL DO COLLAPSE(2) SCHEDULE(runtime)
DO j=2,ny-1 DO j=2,ny-1
DO i=1,nx DO i=1,nx
IF (b(i,j-1) .EQ. missing .OR. b(i,j) .EQ. missing .OR. & IF (b(i,j-1) .EQ. missing .OR. b(i,j) .EQ. missing .OR. &
@ -480,7 +517,9 @@ SUBROUTINE DFILTER2D(a, b, nx, ny, it, missing)
END IF END IF
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
!$OMP PARALLEL DO COLLAPSE(2) SCHEDULE(runtime)
DO j=1,ny DO j=1,ny
DO i=2,nx-1 DO i=2,nx-1
IF (b(i-1,j) .EQ. missing .OR. b(i,j) .EQ. missing .OR. & IF (b(i-1,j) .EQ. missing .OR. b(i,j) .EQ. missing .OR. &
@ -491,6 +530,7 @@ SUBROUTINE DFILTER2D(a, b, nx, ny, it, missing)
END IF END IF
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
! do j=1,ny ! do j=1,ny
! do i=1,nx ! do i=1,nx
! b(i,j) = a(i,j) ! b(i,j) = a(i,j)
@ -533,13 +573,18 @@ SUBROUTINE FILTER2D(a, b, nx, ny, it, missing)
INTEGER :: i, j, iter INTEGER :: i, j, iter
!$OMP PARALLEL
DO iter=1,it DO iter=1,it
!$OMP DO COLLAPSE(2) SCHEDULE(runtime)
DO j=1,ny DO j=1,ny
DO i = 1,nx DO i = 1,nx
b(i,j) = a(i,j) b(i,j) = a(i,j)
END DO END DO
END DO END DO
!$OMP END DO
!$OMP DO COLLAPSE(2) SCHEDULE(runtime)
DO j=2,ny-1 DO j=2,ny-1
DO i=1,nx DO i=1,nx
IF (b(i,j-1) .EQ. missing .OR. b(i,j) .EQ. missing .OR. & IF (b(i,j-1) .EQ. missing .OR. b(i,j) .EQ. missing .OR. &
@ -550,7 +595,9 @@ SUBROUTINE FILTER2D(a, b, nx, ny, it, missing)
END IF END IF
END DO END DO
END DO END DO
!$OMP END DO
!$OMP DO COLLAPSE(2) SCHEDULE(runtime)
DO j=1,ny DO j=1,ny
DO i=2,nx-1 DO i=2,nx-1
IF (b(i-1,j) .EQ. missing .OR. b(i,j) .EQ. missing .OR. & IF (b(i-1,j) .EQ. missing .OR. b(i,j) .EQ. missing .OR. &
@ -561,6 +608,7 @@ SUBROUTINE FILTER2D(a, b, nx, ny, it, missing)
END IF END IF
END DO END DO
END DO END DO
!$OMP END DO
! do j=1,ny ! do j=1,ny
! do i=1,nx ! do i=1,nx
! b(i,j) = a(i,j) ! b(i,j) = a(i,j)
@ -578,6 +626,8 @@ SUBROUTINE FILTER2D(a, b, nx, ny, it, missing)
! enddo ! enddo
END DO END DO
!$OMP END PARALLEL
RETURN RETURN
END SUBROUTINE FILTER2D END SUBROUTINE FILTER2D
@ -601,6 +651,7 @@ SUBROUTINE DCOMPUTERH(qv, p, t, rh, nx)
INTEGER :: i INTEGER :: i
REAL(KIND=8) :: qvs,es,pressure,temperature REAL(KIND=8) :: qvs,es,pressure,temperature
!$OMP PARALLEL DO PRIVATE(qvs, es, pressure, temperature) SCHEDULE(runtime)
DO i = 1,nx DO i = 1,nx
pressure = p(i) pressure = p(i)
temperature = t(i) temperature = t(i)
@ -612,6 +663,7 @@ SUBROUTINE DCOMPUTERH(qv, p, t, rh, nx)
! rh(i) = 100.*qv(i)/qvs ! rh(i) = 100.*qv(i)/qvs
rh(i) = 100.D0*MAX(MIN(qv(i)/qvs, 1.0D0), 0.0D0) rh(i) = 100.D0*MAX(MIN(qv(i)/qvs, 1.0D0), 0.0D0)
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN
@ -707,11 +759,14 @@ SUBROUTINE DCOMPUTEUVMET(u, v, uvmet, longca,longcb,flong,flat, &
! NCLEND ! NCLEND
INTEGER :: i,j INTEGER :: i,j
REAL(KIND=8) :: uk, vk !REAL(KIND=8) :: uk, vk
! msg stands for missing value in this code ! msg stands for missing value in this code
! WRITE (6,FMT=*) ' in compute_uvmet ',NX,NY,NXP1,NYP1,ISTAG ! WRITE (6,FMT=*) ' in compute_uvmet ',NX,NY,NXP1,NYP1,ISTAG
!$OMP PARALLEL
!$OMP DO COLLAPSE(2) SCHEDULE(runtime)
DO j = 1,ny DO j = 1,ny
DO i = 1,nx DO i = 1,nx
@ -733,34 +788,81 @@ SUBROUTINE DCOMPUTEUVMET(u, v, uvmet, longca,longcb,flong,flat, &
END DO END DO
END DO END DO
!$OMP END DO
! WRITE (6,FMT=*) " computing velocities " ! Note: Intentionally removed as many IF statements as possible from loops
! to improve vectorization.
IF (istag .EQ. 0) THEN ! Not staggered
IF (.NOT. is_msg_val) THEN ! No missing values used
!$OMP DO COLLAPSE(2) SCHEDULE(runtime)
DO j = 1,ny DO j = 1,ny
DO i = 1,nx DO i = 1,nx
IF (istag.EQ.1) THEN uvmet(i,j,1) = v(i,j)*longcb(i,j) + u(i,j)*longca(i,j)
IF (is_msg_val .AND. (u(i,j) .EQ. umsg .OR. v(i,j) .EQ. vmsg & uvmet(i,j,2) = v(i,j)*longca(i,j) - u(i,j)*longcb(i,j)
.OR. u(i+1,j) .EQ. umsg .OR. v(i,j+1) .EQ. vmsg)) THEN END DO
END DO
!$OMP END DO
ELSE ! Missing values used
!$OMP DO COLLAPSE(2) SCHEDULE(runtime)
DO j = 1,ny
DO i = 1,nx
IF ((u(i,j) .NE. umsg .AND. v(i,j) .NE. vmsg)) THEN
uvmet(i,j,1) = v(i,j)*longcb(i,j) + u(i,j)*longca(i,j)
uvmet(i,j,2) = v(i,j)*longca(i,j) - u(i,j)*longcb(i,j)
ELSE
uvmet(i,j,1) = uvmetmsg uvmet(i,j,1) = uvmetmsg
uvmet(i,j,2) = uvmetmsg uvmet(i,j,2) = uvmetmsg
ELSE
uk = 0.5D0*(u(i,j) + u(i+1,j))
vk = 0.5D0*(v(i,j) + v(i,j+1))
uvmet(i,j,1) = vk*longcb(i,j) + uk*longca(i,j)
uvmet(i,j,2) = vk*longca(i,j) - uk*longcb(i,j)
END IF END IF
END DO
END DO
!$OMP END DO
END IF
ELSE ! Staggered
IF (.NOT. is_msg_val) THEN ! No missing values used
!$OMP DO COLLAPSE(2) SCHEDULE(runtime)
DO j = 1,ny
DO i = 1,nx
! This is the more readable version.
!uk = 0.5D0*(u(i,j) + u(i+1,j))
!vk = 0.5D0*(v(i,j) + v(i,j+1))
!uvmet(i,j,1) = vk*longcb(i,j) + uk*longca(i,j)
!uvmet(i,j,2) = vk*longca(i,j) - uk*longcb(i,j)
uvmet(i,j,1) = (0.5D0*(v(i,j) + v(i,j+1)))*longcb(i,j) + &
(0.5D0*(u(i,j) + u(i+1,j)))*longca(i,j)
uvmet(i,j,2) = (0.5D0*(v(i,j) + v(i,j+1)))*longca(i,j) - &
(0.5D0*(u(i,j) + u(i+1,j)))*longcb(i,j)
END DO
END DO
!$OMP END DO
ELSE ! Missing values used
!$OMP DO COLLAPSE(2) SCHEDULE(runtime)
DO j = 1,ny
DO i = 1,nx
IF (u(i,j) .NE. umsg .AND. v(i,j) .NE. vmsg .AND. u(i+1,j) .NE. umsg .AND. v(i,j+1) .NE. vmsg) THEN
! This is the more readable version.
!uk = 0.5D0*(u(i,j) + u(i+1,j))
!vk = 0.5D0*(v(i,j) + v(i,j+1))
!uvmet(i,j,1) = vk*longcb(i,j) + uk*longca(i,j)
!uvmet(i,j,2) = vk*longca(i,j) - uk*longcb(i,j)
uvmet(i,j,1) = (0.5D0*(v(i,j) + v(i,j+1)))*longcb(i,j) + &
(0.5D0*(u(i,j) + u(i+1,j)))*longca(i,j)
uvmet(i,j,2) = (0.5D0*(v(i,j) + v(i,j+1)))*longca(i,j) - &
(0.5D0*(u(i,j) + u(i+1,j)))*longcb(i,j)
ELSE ELSE
IF (is_msg_val .AND. (u(i,j) .EQ. umsg .OR. v(i,j) .EQ. vmsg)) THEN
uvmet(i,j,1) = uvmetmsg uvmet(i,j,1) = uvmetmsg
uvmet(i,j,2) = uvmetmsg uvmet(i,j,2) = uvmetmsg
ELSE
uk = u(i,j)
vk = v(i,j)
uvmet(i,j,1) = vk*longcb(i,j) + uk*longca(i,j)
uvmet(i,j,2) = vk*longca(i,j) - uk*longcb(i,j)
END IF
END IF END IF
END DO END DO
END DO END DO
!$OMP END DO
END IF
END IF
!$OMP END PARALLEL
RETURN RETURN
@ -791,6 +893,7 @@ SUBROUTINE DCOMPUTETD(td, pressure, qv_in, nx)
INTEGER :: i INTEGER :: i
!$OMP PARALLEL DO PRIVATE(i,qv,tdc) SCHEDULE(runtime)
DO i = 1,nx DO i = 1,nx
qv = MAX(qv_in(i), 0.D0) qv = MAX(qv_in(i), 0.D0)
! vapor pressure ! vapor pressure
@ -800,6 +903,7 @@ SUBROUTINE DCOMPUTETD(td, pressure, qv_in, nx)
tdc = MAX(tdc, 0.001D0) tdc = MAX(tdc, 0.001D0)
td(i) = (243.5D0*LOG(tdc) - 440.8D0)/(19.48D0 - LOG(tdc)) td(i) = (243.5D0*LOG(tdc) - 440.8D0)/(19.48D0 - LOG(tdc))
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN
@ -825,11 +929,7 @@ SUBROUTINE DCOMPUTEICLW(iclw, pressure, qc_in, nx, ny, nz)
REAL(KIND=8), PARAMETER :: GG = 1000.D0/G REAL(KIND=8), PARAMETER :: GG = 1000.D0/G
INTEGER i,j,k INTEGER i,j,k
DO j = 1,ny iclw = 0
DO i = 1,nx
iclw(i,j) = 0.D0
END DO
END DO
DO j = 3,ny - 2 DO j = 3,ny - 2
DO i = 3,nx - 2 DO i = 3,nx - 2

13
fortran/wrf_user_dbz.f90

@ -77,7 +77,10 @@ SUBROUTINE CALCDBZ(prs, tmk, qvp, qra, qsn, qgr, sn0, ivarint, iliqskin, dbz, nx
REAL(KIND=8), PARAMETER :: RN0_S = 2.D7 REAL(KIND=8), PARAMETER :: RN0_S = 2.D7
REAL(KIND=8), PARAMETER :: RN0_G = 4.D6 REAL(KIND=8), PARAMETER :: RN0_G = 4.D6
!$OMP PARALLEL
! Force all Q arrays to be 0.0 or greater. ! Force all Q arrays to be 0.0 or greater.
!$OMP DO COLLAPSE(3) SCHEDULE(runtime)
DO k = 1,nz DO k = 1,nz
DO j = 1,ny DO j = 1,ny
DO i = 1,nx DO i = 1,nx
@ -96,10 +99,12 @@ SUBROUTINE CALCDBZ(prs, tmk, qvp, qra, qsn, qgr, sn0, ivarint, iliqskin, dbz, nx
END DO END DO
END DO END DO
END DO END DO
!$OMP END DO
! Input pressure is Pa, but we need hPa in calculations ! Input pressure is Pa, but we need hPa in calculations
IF (sn0 .EQ. 0) THEN IF (sn0 .EQ. 0) THEN
!$OMP DO COLLAPSE(3) SCHEDULE(runtime)
DO k = 1,nz DO k = 1,nz
DO j = 1,ny DO j = 1,ny
DO i = 1,nx DO i = 1,nx
@ -110,12 +115,17 @@ SUBROUTINE CALCDBZ(prs, tmk, qvp, qra, qsn, qgr, sn0, ivarint, iliqskin, dbz, nx
END DO END DO
END DO END DO
END DO END DO
!$OMP END DO
END IF END IF
factor_r = GAMMA_SEVEN*1.D18*(1.D0/(PI*RHO_R))**1.75D0 factor_r = GAMMA_SEVEN*1.D18*(1.D0/(PI*RHO_R))**1.75D0
factor_s = GAMMA_SEVEN*1.D18*(1.D0/(PI*RHO_S))**1.75D0*(RHO_S/RHOWAT)**2*ALPHA factor_s = GAMMA_SEVEN*1.D18*(1.D0/(PI*RHO_S))**1.75D0*(RHO_S/RHOWAT)**2*ALPHA
factor_g = GAMMA_SEVEN*1.D18*(1.D0/(PI*RHO_G))**1.75D0*(RHO_G/RHOWAT)**2*ALPHA factor_g = GAMMA_SEVEN*1.D18*(1.D0/(PI*RHO_G))**1.75D0*(RHO_G/RHOWAT)**2*ALPHA
!$OMP DO COLLAPSE(3) PRIVATE(i, j, k, temp_c, virtual_t, gonv, ronv, sonv, &
!$OMP factorb_g, factorb_s, rhoair, z_e) &
!$OMP FIRSTPRIVATE(factor_r, factor_s, factor_g) SCHEDULE(runtime)
DO k = 1,nz DO k = 1,nz
DO j = 1,ny DO j = 1,ny
DO i = 1,nx DO i = 1,nx
@ -171,6 +181,9 @@ SUBROUTINE CALCDBZ(prs, tmk, qvp, qra, qsn, qgr, sn0, ivarint, iliqskin, dbz, nx
END DO END DO
END DO END DO
END DO END DO
!$OMP END DO
!$OMP END PARALLEL
RETURN RETURN

131
fortran/wrf_vinterp.f90

@ -14,17 +14,19 @@ SUBROUTINE wrf_monotonic(out, in, lvprs, cor, idir, delta, ew, ns, nz, icorsw)
REAL(KIND=8), INTENT(IN) :: delta REAL(KIND=8), INTENT(IN) :: delta
REAL(KIND=8), DIMENSION(ew,ns,nz), INTENT(INOUT) :: in REAL(KIND=8), DIMENSION(ew,ns,nz), INTENT(INOUT) :: in
REAL(KIND=8), DIMENSION(ew,ns,nz), INTENT(OUT) :: out REAL(KIND=8), DIMENSION(ew,ns,nz), INTENT(OUT) :: out
REAL(KIND=8), DIMENSION(ew,ns,nz) :: lvprs REAL(KIND=8), DIMENSION(ew,ns,nz), INTENT(IN) :: lvprs
REAL(KIND=8), DIMENSION(ew,ns) :: cor REAL(KIND=8), DIMENSION(ew,ns), INTENT(IN) :: cor
!NCLEND
INTEGER :: i, j, k, ripk, k300 !NCLEND
k300 = 1 ! removes the warning INTEGER :: i, j, k, k300
!$OMP PARALLEL DO COLLAPSE(2) PRIVATE(i, j, k, k300) SCHEDULE(runtime)
DO j=1,ns DO j=1,ns
DO i=1,ew DO i=1,ew
k300 = -1
IF (icorsw .EQ. 1 .AND. cor(i,j) .LT. 0.) THEN IF (icorsw .EQ. 1 .AND. cor(i,j) .LT. 0.) THEN
DO k=1,nz DO k=1,nz
in(i,j,k) = -in(i,j,k) in(i,j,k) = -in(i,j,k)
@ -33,14 +35,19 @@ SUBROUTINE wrf_monotonic(out, in, lvprs, cor, idir, delta, ew, ns, nz, icorsw)
! First find k index that is at or below (height-wise) ! First find k index that is at or below (height-wise)
! the 300 hPa level. ! the 300 hPa level.
DO k = 1,nz DO k = 1,nz-1
ripk = nz-k+1
IF (lvprs(i,j,k) .LE. 300.D0) THEN IF (lvprs(i,j,k) .LE. 300.D0) THEN
k300 = k k300 = k
EXIT EXIT
END IF END IF
END DO END DO
! If the search fails for some reason, use the second to last
! k index
IF (k300 .EQ. -1) THEN
k300 = nz-1
END IF
DO k = k300,1,-1 DO k = k300,1,-1
IF (idir .EQ. 1) THEN IF (idir .EQ. 1) THEN
out(i,j,k) = MIN(in(i,j,k), in(i,j,k+1) + delta) out(i,j,k) = MIN(in(i,j,k), in(i,j,k+1) + delta)
@ -58,6 +65,7 @@ SUBROUTINE wrf_monotonic(out, in, lvprs, cor, idir, delta, ew, ns, nz, icorsw)
END DO END DO
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
RETURN RETURN
@ -65,7 +73,7 @@ END SUBROUTINE wrf_monotonic
!NCLFORTSTART !NCLFORTSTART
FUNCTION wrf_intrp_value(wvalp0, wvalp1, vlev, vcp0, vcp1, icase, errstat, errmsg) FUNCTION wrf_intrp_value(wvalp0, wvalp1, vlev, vcp0, vcp1, icase, errstat)
USE wrf_constants, ONLY : ALGERR, SCLHT USE wrf_constants, ONLY : ALGERR, SCLHT
IMPLICIT NONE IMPLICIT NONE
@ -75,7 +83,6 @@ FUNCTION wrf_intrp_value(wvalp0, wvalp1, vlev, vcp0, vcp1, icase, errstat, errms
INTEGER, INTENT(IN) :: icase INTEGER, INTENT(IN) :: icase
REAL(KIND=8), INTENT(IN) :: wvalp0, wvalp1, vlev, vcp0, vcp1 REAL(KIND=8), INTENT(IN) :: wvalp0, wvalp1, vlev, vcp0, vcp1
INTEGER, INTENT(INOUT) :: errstat INTEGER, INTENT(INOUT) :: errstat
CHARACTER(LEN=*), INTENT(INOUT) :: errmsg
REAL(KIND=8) :: wrf_intrp_value REAL(KIND=8) :: wrf_intrp_value
!NCLEND !NCLEND
@ -83,10 +90,6 @@ FUNCTION wrf_intrp_value(wvalp0, wvalp1, vlev, vcp0, vcp1, icase, errstat, errms
REAL(KIND=8) :: valp0, valp1, rvalue REAL(KIND=8) :: valp0, valp1, rvalue
REAL(KIND=8) :: chkdiff REAL(KIND=8) :: chkdiff
!REAL(KIND=8), PARAMETER :: RGAS=287.04d0
!REAL(KIND=8), PARAMETER :: USSALR=0.0065d0
!REAL(KIND=8), PARAMETER :: SCLHT=RGAS*256.d0/9.81d0
errstat = 0 errstat = 0
valp0 = wvalp0 valp0 = wvalp0
@ -99,7 +102,7 @@ FUNCTION wrf_intrp_value(wvalp0, wvalp1, vlev, vcp0, vcp1, icase, errstat, errms
chkdiff = vcp1 - vcp0 chkdiff = vcp1 - vcp0
IF(chkdiff .EQ. 0) THEN IF(chkdiff .EQ. 0) THEN
errstat = ALGERR errstat = ALGERR
errmsg = "bad difference in vcp's" !errmsg = "bad difference in vcp's"
wrf_intrp_value = 0 wrf_intrp_value = 0
RETURN RETURN
!PRINT *,"bad difference in vcp's" !PRINT *,"bad difference in vcp's"
@ -152,6 +155,7 @@ SUBROUTINE wrf_vintrp(datain, dataout, pres, tk, qvp, ght, terrain,&
INTEGER :: nreqlvs, ripk !njx,niy INTEGER :: nreqlvs, ripk !njx,niy
INTEGER :: i, j, k, kupper !itriv INTEGER :: i, j, k, kupper !itriv
INTEGER :: ifound, isign !miy,mjx INTEGER :: ifound, isign !miy,mjx
INTEGER :: log_errcnt, interp_errcnt, interp_errstat
REAL(KIND=8), DIMENSION(ew,ns) :: tempout REAL(KIND=8), DIMENSION(ew,ns) :: tempout
REAL(KIND=8) :: rlevel, vlev, diff REAL(KIND=8) :: rlevel, vlev, diff
REAL(KIND=8) :: tmpvlev REAL(KIND=8) :: tmpvlev
@ -166,33 +170,15 @@ SUBROUTINE wrf_vintrp(datain, dataout, pres, tk, qvp, ght, terrain,&
REAL(KIND=8) :: tlcl, gammam REAL(KIND=8) :: tlcl, gammam
CHARACTER(LEN=1) :: cvcord CHARACTER(LEN=1) :: cvcord
!REAL(KIND=8), PARAMETER :: RGAS = 287.04d0 !J/K/kg
!REAL(KIND=8), PARAMETER :: RGASMD = .608d0
!REAL(KIND=8), PARAMETER :: USSALR = .0065d0 ! deg C per m
!REAL(KIND=8), PARAMETER :: SCLHT = RGAS*256.d0/9.81d0
!REAL(KIND=8), PARAMETER :: EPS = 0.622d0
!REAL(KIND=8), PARAMETER :: RCONST = -9.81d0/(RGAS * USSALR)
!REAL(KIND=8), PARAMETER :: EXPON = RGAS*USSALR/9.81d0
!REAL(KIND=8), PARAMETER :: EXPONI = 1./EXPON
!REAL(KIND=8), PARAMETER :: TLCLC1 = 2840.d0
!REAL(KIND=8), PARAMETER :: TLCLC2 = 3.5d0
!REAL(KIND=8), PARAMETER :: TLCLC3 = 4.805d0
!REAL(KIND=8), PARAMETER :: TLCLC4 = 55.d0
!REAL(KIND=8), PARAMETER :: THTECON1 = 3376.d0 ! K
!REAL(KIND=8), PARAMETER :: THTECON2 = 2.54d0
!REAL(KIND=8), PARAMETER :: THTECON3 = 0.81d0
!REAL(KIND=8), PARAMETER :: CP = 1004.d0
!REAL(KIND=8), PARAMETER :: CPMD = 0.887d0
!REAL(KIND=8), PARAMETER :: GAMMA = RGAS/CP
!REAL(KIND=8), PARAMETER :: GAMMAMD = RGASMD-CPMD
!REAL(KIND=8), PARAMETER :: CELKEL = 273.16d0
! Removes the warnings for uninitialized variables ! Removes the warnings for uninitialized variables
cvcord = '' cvcord = ''
plev = 0 plev = 0
zlev = 0 zlev = 0
vlev = 0 vlev = 0
errstat = 0 errstat = 0
interp_errcnt = 0
interp_errstat = 0
log_errcnt = 0
IF (vcor .EQ. 1) THEN IF (vcor .EQ. 1) THEN
cvcord = 'p' cvcord = 'p'
@ -202,17 +188,6 @@ SUBROUTINE wrf_vintrp(datain, dataout, pres, tk, qvp, ght, terrain,&
cvcord = 't' cvcord = 't'
END IF END IF
!miy = ns
!mjx = ew
!njx = ew
!niy = ns
DO j = 1,ns
DO i = 1,ew
tempout(i,j) = rmsg
END DO
END DO
DO nreqlvs = 1,numlevels DO nreqlvs = 1,numlevels
IF (cvcord .EQ. 'z') THEN IF (cvcord .EQ. 'z') THEN
! Convert rlevel to meters from km ! Convert rlevel to meters from km
@ -224,8 +199,16 @@ SUBROUTINE wrf_vintrp(datain, dataout, pres, tk, qvp, ght, terrain,&
vlev = interp_levels(nreqlvs) vlev = interp_levels(nreqlvs)
END IF END IF
!$OMP PARALLEL DO COLLAPSE(2) PRIVATE(i, j, k, ifound, &
!$OMP ripk, vcp1, vcp0, valp0, valp1, tmpvlev, interp_errstat, &
!$OMP vclhsl, vctophsl, diff, isign, plhsl, zlhsl, ezlhsl, tlhsl, &
!$OMP zsurf, qvapor, psurf, psurfsm, ezsurf, plev, ezlev, zlev, &
!$OMP ptarget, dpmin, kupper, pbot, zbot, pratio, tbotextrap, &
!$OMP vt, tlev, gammam, e, tlcl) REDUCTION (+:log_errcnt, interp_errcnt) &
!$OMP SCHEDULE(runtime)
DO j=1,ns DO j=1,ns
DO i=1,ew DO i=1,ew
tempout(i,j) = rmsg
! Get the interpolated value that is within the model domain ! Get the interpolated value that is within the model domain
ifound = 0 ifound = 0
DO k = 1,nz-1 DO k = 1,nz-1
@ -245,35 +228,34 @@ SUBROUTINE wrf_vintrp(datain, dataout, pres, tk, qvp, ght, terrain,&
IF (logp .EQ. 1) THEN IF (logp .EQ. 1) THEN
vcp1 = LOG(vcp1) vcp1 = LOG(vcp1)
vcp0 = LOG(vcp0) vcp0 = LOG(vcp0)
IF (vlev .EQ. 0.0D0) THEN IF (vlev .NE. 0.0D0) THEN
errstat = ALGERR
WRITE(errmsg, *) "Pres=0. Unable to take log of 0."
RETURN
!PRINT *,"Pressure value = 0"
!PRINT *,"Unable to take log of 0"
!STOP
END IF
tmpvlev = LOG(vlev) tmpvlev = LOG(vlev)
ELSE
log_errcnt = log_errcnt + 1
tmpvlev = rmsg
END IF
ELSE ELSE
tmpvlev = vlev tmpvlev = vlev
END IF END IF
IF (tmpvlev .NE. rmsg) THEN
tempout(i,j) = wrf_intrp_value(valp0, valp1, tmpvlev, vcp0, & tempout(i,j) = wrf_intrp_value(valp0, valp1, tmpvlev, vcp0, &
vcp1, icase, errstat, errmsg) vcp1, icase, interp_errstat)
IF (errstat .NE. 0) THEN
RETURN IF (interp_errstat .NE. 0) THEN
tempout(i,j) = rmsg
interp_errcnt = interp_errcnt + 1
END IF END IF
! print *,"one ",i,j,tempout(i,j)
ifound = 1 ifound = 1
END IF END IF
!GOTO 115 ! EXIT END IF
EXIT EXIT
END IF END IF
END DO !end for the k loop END DO !end for the k loop
!115 CONTINUE
IF (ifound .EQ. 1) THEN !Grid point is in the model domain IF (ifound .EQ. 1) THEN !Grid point is in the model domain
!GOTO 333 ! CYCLE
CYCLE CYCLE
END IF END IF
@ -281,7 +263,6 @@ SUBROUTINE wrf_vintrp(datain, dataout, pres, tk, qvp, ght, terrain,&
!all values above or below the model level to rmsg. !all values above or below the model level to rmsg.
IF (extrap .EQ. 0) THEN IF (extrap .EQ. 0) THEN
tempout(i,j) = rmsg tempout(i,j) = rmsg
!GOTO 333 ! CYCLE
CYCLE CYCLE
END IF END IF
@ -296,8 +277,6 @@ SUBROUTINE wrf_vintrp(datain, dataout, pres, tk, qvp, ght, terrain,&
IF (isign*vlev .GE. isign*vctophsl) THEN IF (isign*vlev .GE. isign*vctophsl) THEN
! Assign the highest model level to the out array ! Assign the highest model level to the out array
tempout(i,j) = datain(i,j,nz) tempout(i,j) = datain(i,j,nz)
! print *,"at warn",i,j,tempout(i,j)
!GOTO 333 ! CYCLE
CYCLE CYCLE
END IF END IF
@ -307,7 +286,6 @@ SUBROUTINE wrf_vintrp(datain, dataout, pres, tk, qvp, ght, terrain,&
IF (datain(i,j,1) .EQ. rmsg) THEN IF (datain(i,j,1) .EQ. rmsg) THEN
tempout(i,j) = rmsg tempout(i,j) = rmsg
!GOTO 333 ! CYCLE
CYCLE CYCLE
END IF END IF
@ -351,7 +329,6 @@ SUBROUTINE wrf_vintrp(datain, dataout, pres, tk, qvp, ght, terrain,&
zlev = -SCLHT*LOG(ezlev) zlev = -SCLHT*LOG(ezlev)
IF (icase .EQ. 2) THEN IF (icase .EQ. 2) THEN
tempout(i,j) = zlev tempout(i,j) = zlev
!GOTO 333 ! CYCLE
CYCLE CYCLE
END IF END IF
@ -362,7 +339,6 @@ SUBROUTINE wrf_vintrp(datain, dataout, pres, tk, qvp, ght, terrain,&
psurf + (ezsurf - ezlev)*plhsl)/(ezsurf - ezlhsl) psurf + (ezsurf - ezlev)*plhsl)/(ezsurf - ezlhsl)
IF (icase .EQ. 1) THEN IF (icase .EQ. 1) THEN
tempout(i,j) = plev tempout(i,j) = plev
!GOTO 333 ! CYCLE
CYCLE CYCLE
END IF END IF
END IF END IF
@ -374,12 +350,11 @@ SUBROUTINE wrf_vintrp(datain, dataout, pres, tk, qvp, ght, terrain,&
ripk = nz-k+1 ripk = nz-k+1
dp = ABS((pres(i,j,ripk) * 0.01D0) - ptarget) dp = ABS((pres(i,j,ripk) * 0.01D0) - ptarget)
IF (dp .GT. dpmin) THEN IF (dp .GT. dpmin) THEN
!GOTO 334 ! EXIT
EXIT EXIT
END IF END IF
dpmin = MIN(dpmin, dp) dpmin = MIN(dpmin, dp)
END DO END DO
!334
kupper = k-1 kupper = k-1
ripk = nz - kupper + 1 ripk = nz - kupper + 1
@ -394,7 +369,6 @@ SUBROUTINE wrf_vintrp(datain, dataout, pres, tk, qvp, ght, terrain,&
zlev = zbot + vt/USSALR*(1. - (vlev/pbot)**EXPON) zlev = zbot + vt/USSALR*(1. - (vlev/pbot)**EXPON)
IF (icase .EQ. 2) THEN IF (icase .EQ. 2) THEN
tempout(i,j) = zlev tempout(i,j) = zlev
!GOTO 333 ! CYCLE
CYCLE CYCLE
END IF END IF
ELSE IF (cvcord .EQ. 'z') THEN ELSE IF (cvcord .EQ. 'z') THEN
@ -402,7 +376,6 @@ SUBROUTINE wrf_vintrp(datain, dataout, pres, tk, qvp, ght, terrain,&
plev = pbot*(1. + USSALR/vt*(zbot - zlev))**EXPONI plev = pbot*(1. + USSALR/vt*(zbot - zlev))**EXPONI
IF (icase .EQ. 1) THEN IF (icase .EQ. 1) THEN
tempout(i,j) = plev tempout(i,j) = plev
!GOTO 333 ! CYCLE
CYCLE CYCLE
END IF END IF
END IF END IF
@ -434,13 +407,27 @@ SUBROUTINE wrf_vintrp(datain, dataout, pres, tk, qvp, ght, terrain,&
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
IF (log_errcnt > 0) THEN
errstat = ALGERR
WRITE(errmsg, *) "Pres=0. Unable to take log of 0."
RETURN
END IF
IF (interp_errcnt > 0) THEN
errstat = ALGERR
WRITE(errmsg, *) "bad difference in vcp's"
RETURN
END IF
! print *,"----done----",interp_levels(nreqlvs) !$OMP PARALLEL DO COLLAPSE(2) SCHEDULE(runtime)
DO j = 1,ns DO j = 1,ns
DO i = 1,ew DO i = 1,ew
dataout(i,j,nreqlvs) = tempout(i,j) dataout(i,j,nreqlvs) = tempout(i,j)
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
END DO !end for the nreqlvs END DO !end for the nreqlvs

4
fortran/wrf_wind.f90

@ -13,11 +13,13 @@ SUBROUTINE DCOMPUTEWSPD(wspd, u, v, nx, ny)
INTEGER i, j INTEGER i, j
!$OMP PARALLEL DO COLLAPSE(2) SCHEDULE(runtime)
DO j = 1,ny DO j = 1,ny
DO i = 1,nx DO i = 1,nx
wspd(i,j) = SQRT(u(i,j)*u(i,j) + v(i,j)*v(i,j)) wspd(i,j) = SQRT(u(i,j)*u(i,j) + v(i,j)*v(i,j))
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
END SUBROUTINE DCOMPUTEWSPD END SUBROUTINE DCOMPUTEWSPD
@ -38,11 +40,13 @@ SUBROUTINE DCOMPUTEWDIR(wdir, u, v, nx, ny)
INTEGER i, j INTEGER i, j
!$OMP PARALLEL DO COLLAPSE(2) SCHEDULE(runtime)
DO j = 1,ny DO j = 1,ny
DO i = 1,nx DO i = 1,nx
wdir(i,j) = MOD(270.0 - ATAN2(v(i,j), u(i,j)) * DEG_PER_RAD, 360.) wdir(i,j) = MOD(270.0 - ATAN2(v(i,j), u(i,j)) * DEG_PER_RAD, 360.)
END DO END DO
END DO END DO
!$OMP END PARALLEL DO
END SUBROUTINE DCOMPUTEWDIR END SUBROUTINE DCOMPUTEWDIR

254
fortran/wrffortran.pyf

@ -33,6 +33,165 @@ python module _wrffortran ! in
integer, optional,intent(in),check(shape(qvp,1)==mjx),depend(qvp) :: mjx=shape(qvp,1) integer, optional,intent(in),check(shape(qvp,1)==mjx),depend(qvp) :: mjx=shape(qvp,1)
integer, optional,intent(in),check(shape(qvp,2)==mkzh),depend(qvp) :: mkzh=shape(qvp,2) integer, optional,intent(in),check(shape(qvp,2)==mkzh),depend(qvp) :: mkzh=shape(qvp,2)
end subroutine deqthecalc end subroutine deqthecalc
module omp_constants ! in :_wrffortran:omp.f90
integer, parameter,optional :: fomp_nest_lock_kind=8
integer(kind=4), parameter,optional :: fomp_sched_dynamic=2
integer(kind=4), parameter,optional :: fomp_sched_guided=3
integer, parameter,optional :: fomp_sched_kind=4
integer(kind=4), parameter,optional :: fomp_sched_static=1
integer, parameter,optional :: fomp_lock_kind=4
integer(kind=4), parameter,optional :: fomp_sched_auto=4
end module omp_constants
function fomp_enabled() ! in :_wrffortran:omp.f90
threadsafe
logical :: fomp_enabled
end function fomp_enabled
subroutine fomp_set_num_threads(num_threads) ! in :_wrffortran:omp.f90
threadsafe
integer intent(in) :: num_threads
end subroutine fomp_set_num_threads
function fomp_get_num_threads() ! in :_wrffortran:omp.f90
threadsafe
integer :: fomp_get_num_threads
end function fomp_get_num_threads
function fomp_get_max_threads() ! in :_wrffortran:omp.f90
threadsafe
integer :: fomp_get_max_threads
end function fomp_get_max_threads
function fomp_get_thread_num() ! in :_wrffortran:omp.f90
threadsafe
integer :: fomp_get_thread_num
end function fomp_get_thread_num
function fomp_get_num_procs() ! in :_wrffortran:omp.f90
threadsafe
integer :: fomp_get_num_procs
end function fomp_get_num_procs
function fomp_in_parallel() ! in :_wrffortran:omp.f90
threadsafe
logical :: fomp_in_parallel
end function fomp_in_parallel
subroutine fomp_set_dynamic(dynamic_threads) ! in :_wrffortran:omp.f90
threadsafe
logical intent(in) :: dynamic_threads
end subroutine fomp_set_dynamic
function fomp_get_dynamic() ! in :_wrffortran:omp.f90
threadsafe
logical :: fomp_get_dynamic
end function fomp_get_dynamic
subroutine fomp_set_nested(nested) ! in :_wrffortran:omp.f90
threadsafe
logical intent(in) :: nested
end subroutine fomp_set_nested
function fomp_get_nested() ! in :_wrffortran:omp.f90
threadsafe
logical :: fomp_get_nested
end function fomp_get_nested
subroutine fomp_set_schedule(kind,modifier) ! in :_wrffortran:omp.f90
threadsafe
use omp_constants, only: fomp_sched_kind
integer(kind=4) intent(in) :: kind
integer intent(in) :: modifier
end subroutine fomp_set_schedule
subroutine fomp_get_schedule(kind,modifier) ! in :_wrffortran:omp.f90
threadsafe
use omp_constants, only: fomp_sched_kind
integer(kind=4) intent(out) :: kind
integer intent(out) :: modifier
end subroutine fomp_get_schedule
function fomp_get_thread_limit() ! in :_wrffortran:omp.f90
threadsafe
integer :: fomp_get_thread_limit
end function fomp_get_thread_limit
subroutine fomp_set_max_active_levels(max_levels) ! in :_wrffortran:omp.f90
threadsafe
integer intent(in) :: max_levels
end subroutine fomp_set_max_active_levels
function fomp_get_max_active_levels() ! in :_wrffortran:omp.f90
threadsafe
integer :: fomp_get_max_active_levels
end function fomp_get_max_active_levels
function fomp_get_level() ! in :_wrffortran:omp.f90
threadsafe
integer :: fomp_get_level
end function fomp_get_level
function fomp_get_ancestor_thread_num(level) ! in :_wrffortran:omp.f90
threadsafe
integer intent(in) :: level
integer :: fomp_get_ancestor_thread_num
end function fomp_get_ancestor_thread_num
function fomp_get_team_size(level) ! in :_wrffortran:omp.f90
threadsafe
integer intent(in) :: level
integer :: fomp_get_team_size
end function fomp_get_team_size
function fomp_get_active_level() ! in :_wrffortran:omp.f90
threadsafe
integer :: fomp_get_active_level
end function fomp_get_active_level
function fomp_in_final() ! in :_wrffortran:omp.f90
threadsafe
logical :: fomp_in_final
end function fomp_in_final
subroutine fomp_init_lock(svar) ! in :_wrffortran:omp.f90
threadsafe
use omp_constants, only: fomp_lock_kind
integer(kind=4) intent(out) :: svar
end subroutine fomp_init_lock
subroutine fomp_init_nest_lock(nvar) ! in :_wrffortran:omp.f90
threadsafe
use omp_constants, only: fomp_nest_lock_kind
integer(kind=8) intent(out) :: nvar
end subroutine fomp_init_nest_lock
subroutine fomp_destroy_lock(svar) ! in :_wrffortran:omp.f90
threadsafe
use omp_constants, only: fomp_lock_kind
integer(kind=4) intent(inout) :: svar
end subroutine fomp_destroy_lock
subroutine fomp_destroy_nest_lock(nvar) ! in :_wrffortran:omp.f90
threadsafe
use omp_constants, only: fomp_nest_lock_kind
integer(kind=8) intent(inout) :: nvar
end subroutine fomp_destroy_nest_lock
subroutine fomp_set_lock(svar) ! in :_wrffortran:omp.f90
threadsafe
use omp_constants, only: fomp_lock_kind
integer(kind=4) intent(inout) :: svar
end subroutine fomp_set_lock
subroutine fomp_set_nest_lock(nvar) ! in :_wrffortran:omp.f90
threadsafe
use omp_constants, only: fomp_nest_lock_kind
integer(kind=8) intent(inout) :: nvar
end subroutine fomp_set_nest_lock
subroutine fomp_unset_lock(svar) ! in :_wrffortran:omp.f90
threadsafe
use omp_constants, only: fomp_lock_kind
integer(kind=4) intent(inout) :: svar
end subroutine fomp_unset_lock
subroutine fomp_unset_nest_lock(nvar) ! in :_wrffortran:omp.f90
threadsafe
use omp_constants, only: fomp_nest_lock_kind
integer(kind=8) intent(inout) :: nvar
end subroutine fomp_unset_nest_lock
function fomp_test_lock(svar) ! in :_wrffortran:omp.f90
threadsafe
use omp_constants, only: fomp_lock_kind
integer(kind=4) intent(inout) :: svar
logical :: fomp_test_lock
end function fomp_test_lock
function fomp_test_nest_lock(nvar) ! in :_wrffortran:omp.f90
threadsafe
use omp_constants, only: fomp_nest_lock_kind
integer(kind=8) intent(inout) :: nvar
integer :: fomp_test_nest_lock
end function fomp_test_nest_lock
function fomp_get_wtime() ! in :_wrffortran:omp.f90
threadsafe
real(kind=8) :: fomp_get_wtime
end function fomp_get_wtime
function fomp_get_wtick() ! in :_wrffortran:omp.f90
threadsafe
real(kind=8) :: fomp_get_wtick
end function fomp_get_wtick
function tvirtual(temp,ratmix) ! in :_wrffortran:rip_cape.f90 function tvirtual(temp,ratmix) ! in :_wrffortran:rip_cape.f90
threadsafe threadsafe
use wrf_constants, only: eps use wrf_constants, only: eps
@ -63,36 +222,55 @@ python module _wrffortran ! in
integer intent(inout) :: errstat integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg character*(*) intent(inout) :: errmsg
end subroutine dlookup_table end subroutine dlookup_table
subroutine dpfcalc(prs,sfp,pf,miy,mjx,mkzh,ter_follow) ! in :_wrffortran:rip_cape.f90 subroutine dpfcalc(prs,sfp,pf,mix,mjy,mkzh,ter_follow) ! in :_wrffortran:rip_cape.f90
real(kind=8) dimension(miy,mjx,mkzh),intent(in) :: prs real(kind=8) dimension(mkzh,mix,mjy),intent(in) :: prs
real(kind=8) dimension(miy,mjx),intent(in),depend(miy,mjx) :: sfp real(kind=8) dimension(mix,mjy),intent(in),depend(mix,mjy) :: sfp
real(kind=8) dimension(miy,mjx,mkzh),intent(out),depend(miy,mjx,mkzh) :: pf real(kind=8) dimension(mkzh,mix,mjy),intent(out),depend(mkzh,mix,mjy) :: pf
integer, optional,intent(in),check(shape(prs,0)==miy),depend(prs) :: miy=shape(prs,0) integer, optional,intent(in),check(shape(prs,1)==mix),depend(prs) :: mix=shape(prs,1)
integer, optional,intent(in),check(shape(prs,1)==mjx),depend(prs) :: mjx=shape(prs,1) integer, optional,intent(in),check(shape(prs,2)==mjy),depend(prs) :: mjy=shape(prs,2)
integer, optional,intent(in),check(shape(prs,2)==mkzh),depend(prs) :: mkzh=shape(prs,2) integer, optional,intent(in),check(shape(prs,0)==mkzh),depend(prs) :: mkzh=shape(prs,0)
integer intent(in) :: ter_follow integer intent(in) :: ter_follow
end subroutine dpfcalc end subroutine dpfcalc
subroutine dcapecalc3d(prs,tmk,qvp,ght,ter,sfp,cape,cin,cmsg,miy,mjx,mkzh,i3dflag,ter_follow,psafile,errstat,errmsg) ! in :_wrffortran:rip_cape.f90 subroutine dcapecalc3d(prs,tmk,qvp,ght,ter,sfp,cape,cin,cmsg,mix,mjy,mkzh,ter_follow,psafile,errstat,errmsg) ! in :_wrffortran:rip_cape.f90
threadsafe threadsafe
use wrf_constants, only: tlclc2,gamma,tlclc1,rgasmd,tlclc4,g,tlclc3,thtecon3,eps,rd,cpmd,celkel,gammamd,eslcon2,eslcon1,cp,thtecon1,algerr,ezero,thtecon2 use wrf_constants, only: tlclc2,gamma,tlclc1,rgasmd,tlclc4,g,tlclc3,thtecon3,eps,rd,cpmd,celkel,gammamd,eslcon2,eslcon1,cp,thtecon1,ezero,thtecon2
real(kind=8) dimension(miy,mjx,mkzh),intent(in) :: prs real(kind=8) dimension(mix,mjy,mkzh),intent(in) :: prs
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: tmk real(kind=8) dimension(mix,mjy,mkzh),intent(in),depend(mix,mjy,mkzh) :: tmk
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: qvp real(kind=8) dimension(mix,mjy,mkzh),intent(in),depend(mix,mjy,mkzh) :: qvp
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: ght real(kind=8) dimension(mix,mjy,mkzh),intent(in),depend(mix,mjy,mkzh) :: ght
real(kind=8) dimension(miy,mjx),intent(in),depend(miy,mjx) :: ter real(kind=8) dimension(mix,mjy),intent(in),depend(mix,mjy) :: ter
real(kind=8) dimension(miy,mjx),intent(in),depend(miy,mjx) :: sfp real(kind=8) dimension(mix,mjy),intent(in),depend(mix,mjy) :: sfp
real(kind=8) dimension(miy,mjx,mkzh),intent(out,in),depend(miy,mjx,mkzh) :: cape real(kind=8) dimension(mix,mjy,mkzh),intent(out,in),depend(mix,mjy,mkzh) :: cape
real(kind=8) dimension(miy,mjx,mkzh),intent(out,in),depend(miy,mjx,mkzh) :: cin real(kind=8) dimension(mix,mjy,mkzh),intent(out,in),depend(mix,mjy,mkzh) :: cin
real(kind=8) intent(in) :: cmsg real(kind=8) intent(in) :: cmsg
integer, optional,intent(in),check(shape(prs,0)==miy),depend(prs) :: miy=shape(prs,0) integer, optional,intent(in),check(shape(prs,0)==mix),depend(prs) :: mix=shape(prs,0)
integer, optional,intent(in),check(shape(prs,1)==mjx),depend(prs) :: mjx=shape(prs,1) integer, optional,intent(in),check(shape(prs,1)==mjy),depend(prs) :: mjy=shape(prs,1)
integer, optional,intent(in),check(shape(prs,2)==mkzh),depend(prs) :: mkzh=shape(prs,2) integer, optional,intent(in),check(shape(prs,2)==mkzh),depend(prs) :: mkzh=shape(prs,2)
integer intent(in) :: i3dflag
integer intent(in) :: ter_follow integer intent(in) :: ter_follow
character*(*) intent(in) :: psafile character*(*) intent(in) :: psafile
integer intent(inout) :: errstat integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg character*(*) intent(inout) :: errmsg
end subroutine dcapecalc3d end subroutine dcapecalc3d
subroutine dcapecalc2d(prs,tmk,qvp,ght,ter,sfp,cape,cin,cmsg,mix,mjy,mkzh,ter_follow,psafile,errstat,errmsg) ! in :_wrffortran:rip_cape.f90
threadsafe
use wrf_constants, only: tlclc2,gamma,tlclc1,rgasmd,tlclc4,g,tlclc3,thtecon3,eps,rd,cpmd,celkel,gammamd,eslcon2,eslcon1,cp,thtecon1,ezero,thtecon2
real(kind=8) dimension(mix,mjy,mkzh),intent(in) :: prs
real(kind=8) dimension(mix,mjy,mkzh),intent(in),depend(mix,mjy,mkzh) :: tmk
real(kind=8) dimension(mix,mjy,mkzh),intent(in),depend(mix,mjy,mkzh) :: qvp
real(kind=8) dimension(mix,mjy,mkzh),intent(in),depend(mix,mjy,mkzh) :: ght
real(kind=8) dimension(mix,mjy),intent(in),depend(mix,mjy) :: ter
real(kind=8) dimension(mix,mjy),intent(in),depend(mix,mjy) :: sfp
real(kind=8) dimension(mix,mjy,mkzh),intent(out,in),depend(mix,mjy,mkzh) :: cape
real(kind=8) dimension(mix,mjy,mkzh),intent(out,in),depend(mix,mjy,mkzh) :: cin
real(kind=8) intent(in) :: cmsg
integer, optional,intent(in),check(shape(prs,0)==mix),depend(prs) :: mix=shape(prs,0)
integer, optional,intent(in),check(shape(prs,1)==mjy),depend(prs) :: mjy=shape(prs,1)
integer, optional,intent(in),check(shape(prs,2)==mkzh),depend(prs) :: mkzh=shape(prs,2)
integer intent(in) :: ter_follow
character*(*) intent(in) :: psafile
integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg
end subroutine dcapecalc2d
subroutine dcloudfrac(pres,rh,lowc,midc,highc,nz,ns,ew) ! in :_wrffortran:wrf_cloud_fracf.f90 subroutine dcloudfrac(pres,rh,lowc,midc,highc,nz,ns,ew) ! in :_wrffortran:wrf_cloud_fracf.f90
threadsafe threadsafe
real(kind=8) dimension(ew,ns,nz),intent(in) :: pres real(kind=8) dimension(ew,ns,nz),intent(in) :: pres
@ -104,8 +282,27 @@ python module _wrffortran ! in
integer, optional,check(shape(pres,1)==ns),depend(pres) :: ns=shape(pres,1) integer, optional,check(shape(pres,1)==ns),depend(pres) :: ns=shape(pres,1)
integer, optional,check(shape(pres,0)==ew),depend(pres) :: ew=shape(pres,0) integer, optional,check(shape(pres,0)==ew),depend(pres) :: ew=shape(pres,0)
end subroutine dcloudfrac end subroutine dcloudfrac
subroutine dcloudfrac2(vert,rh,vert_inc_w_height,low_thresh,mid_thresh,high_thresh,msg,lowc,midc,highc,nz,ns,ew) ! in :_wrffortran:wrf_cloud_fracf.f90
threadsafe
real(kind=8) dimension(ew,ns,nz),intent(in) :: vert
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: rh
integer intent(in) :: vert_inc_w_height
real(kind=8) intent(in) :: low_thresh
real(kind=8) intent(in) :: mid_thresh
real(kind=8) intent(in) :: high_thresh
real(kind=8) intent(in) :: msg
real(kind=8) dimension(ew,ns),intent(out,in),depend(ew,ns) :: lowc
real(kind=8) dimension(ew,ns),intent(out,in),depend(ew,ns) :: midc
real(kind=8) dimension(ew,ns),intent(out,in),depend(ew,ns) :: highc
integer, optional,check(shape(vert,2)==nz),depend(vert) :: nz=shape(vert,2)
integer, optional,check(shape(vert,1)==ns),depend(vert) :: ns=shape(vert,1)
integer, optional,check(shape(vert,0)==ew),depend(vert) :: ew=shape(vert,0)
end subroutine dcloudfrac2
module wrf_constants ! in :_wrffortran:wrf_constants.f90 module wrf_constants ! in :_wrffortran:wrf_constants.f90
real(kind=4), parameter,optional :: default_fill_float=9.96920996839e+36
integer(kind=8), parameter,optional :: default_fill_int64=int(-9223372036854775806d0, kind=8)
real(kind=8), parameter,optional :: wrf_earth_radius=6370000.d0 real(kind=8), parameter,optional :: wrf_earth_radius=6370000.d0
character(len=1), parameter,optional :: default_fill_char=achar(0)
real(kind=8), parameter,optional :: rhowat=1000.d0 real(kind=8), parameter,optional :: rhowat=1000.d0
real(kind=8), parameter,optional :: t_base=300.0d0 real(kind=8), parameter,optional :: t_base=300.0d0
real(kind=8), parameter,optional :: cp=1004.5d0 real(kind=8), parameter,optional :: cp=1004.5d0
@ -115,6 +312,7 @@ python module _wrffortran ! in
real(kind=8), parameter,optional :: p1000mb=100000.d0 real(kind=8), parameter,optional :: p1000mb=100000.d0
real(kind=8), parameter,optional :: rv=461.6d0 real(kind=8), parameter,optional :: rv=461.6d0
real(kind=8), parameter,optional,depend(pi) :: rad_per_deg=pi/180.d0 real(kind=8), parameter,optional,depend(pi) :: rad_per_deg=pi/180.d0
real(kind=8), parameter,optional :: default_fill_double=9.96920996839e+36
real(kind=8), parameter,optional :: rd=287.d0 real(kind=8), parameter,optional :: rd=287.d0
real(kind=8), parameter,optional :: abscoef=.145d0 real(kind=8), parameter,optional :: abscoef=.145d0
real(kind=8), parameter,optional :: celkel=273.15d0 real(kind=8), parameter,optional :: celkel=273.15d0
@ -122,16 +320,18 @@ python module _wrffortran ! in
real(kind=8), parameter,optional :: eslcon2=29.65d0 real(kind=8), parameter,optional :: eslcon2=29.65d0
real(kind=8), parameter,optional :: eslcon1=17.67d0 real(kind=8), parameter,optional :: eslcon1=17.67d0
real(kind=8), parameter,optional :: pi=3.1415926535897932384626433d0 real(kind=8), parameter,optional :: pi=3.1415926535897932384626433d0
integer(kind=1), parameter,optional :: default_fill_int8=-127
real(kind=8), parameter,optional :: tlclc2=3.5d0 real(kind=8), parameter,optional :: tlclc2=3.5d0
real(kind=8), parameter,optional :: tlclc3=4.805d0 real(kind=8), parameter,optional :: tlclc3=4.805d0
real(kind=8), parameter,optional :: rho_g=400.d0 real(kind=8), parameter,optional :: rho_g=400.d0
real(kind=8), parameter,optional :: tlclc1=2840.d0 real(kind=8), parameter,optional :: tlclc1=2840.d0
real(kind=8), parameter,optional :: tlclc4=55.d0 real(kind=8), parameter,optional :: tlclc4=55.d0
integer(kind=2), parameter,optional :: default_fill_int16=-32767
real(kind=8), parameter,optional,depend(pi) :: deg_per_rad=180.d0/pi real(kind=8), parameter,optional,depend(pi) :: deg_per_rad=180.d0/pi
real(kind=8), parameter,optional :: cpmd=.887d0 real(kind=8), parameter,optional :: cpmd=.887d0
real(kind=8), parameter,optional,depend(rd,g) :: sclht=rd*256.d0/g real(kind=8), parameter,optional,depend(rd,g) :: sclht=rd*256.d0/g
real(kind=8), parameter,optional :: ussalr=0.0065d0 real(kind=8), parameter,optional :: ussalr=0.0065d0
real(kind=8), parameter,optional :: default_fill=9.9692099683868690d36 real(kind=8), parameter,optional :: default_fill=9.96920996839e+36
real(kind=8), parameter,optional :: rho_s=100.d0 real(kind=8), parameter,optional :: rho_s=100.d0
real(kind=8), parameter,optional,depend(rhowat) :: rho_r=1000.0 real(kind=8), parameter,optional,depend(rhowat) :: rho_r=1000.0
real(kind=8), parameter,optional :: alpha=0.224d0 real(kind=8), parameter,optional :: alpha=0.224d0
@ -141,9 +341,10 @@ python module _wrffortran ! in
real(kind=8), parameter,optional :: rgasmd=.608d0 real(kind=8), parameter,optional :: rgasmd=.608d0
real(kind=8), parameter,optional :: g=9.81d0 real(kind=8), parameter,optional :: g=9.81d0
integer, optional :: errlen=512 integer, optional :: errlen=512
real(kind=8), parameter,optional :: eps=0.622d0 integer(kind=4), parameter,optional :: default_fill_int32=-2147483647
real(kind=8), parameter,optional :: gamma_seven=720.d0 real(kind=8), parameter,optional :: gamma_seven=720.d0
real(kind=8), parameter,optional,depend(cpmd,rgasmd) :: gammamd=-0.279 real(kind=8), parameter,optional,depend(cpmd,rgasmd) :: gammamd=-0.279
real(kind=8), parameter,optional :: eps=0.622d0
integer, optional :: algerr=64 integer, optional :: algerr=64
real(kind=8), parameter,optional,depend(cp,rd) :: gamma=0.285714285714 real(kind=8), parameter,optional,depend(cp,rd) :: gamma=0.285714285714
real(kind=8), parameter,optional,depend(expon,rd,ussalr,g) :: exponi=5.25864379523 real(kind=8), parameter,optional,depend(expon,rd,ussalr,g) :: exponi=5.25864379523
@ -508,8 +709,8 @@ python module _wrffortran ! in
threadsafe threadsafe
real(kind=8) dimension(ew,ns,nz),intent(out,in) :: out real(kind=8) dimension(ew,ns,nz),intent(out,in) :: out
real(kind=8) dimension(ew,ns,nz),intent(inout),depend(ew,ns,nz) :: in real(kind=8) dimension(ew,ns,nz),intent(inout),depend(ew,ns,nz) :: in
real(kind=8) dimension(ew,ns,nz),depend(ew,ns,nz) :: lvprs real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: lvprs
real(kind=8) dimension(ew,ns),depend(ew,ns) :: cor real(kind=8) dimension(ew,ns),intent(in),depend(ew,ns) :: cor
integer intent(in) :: idir integer intent(in) :: idir
real(kind=8) intent(in) :: delta real(kind=8) intent(in) :: delta
integer, optional,intent(in),check(shape(out,0)==ew),depend(out) :: ew=shape(out,0) integer, optional,intent(in),check(shape(out,0)==ew),depend(out) :: ew=shape(out,0)
@ -517,7 +718,7 @@ python module _wrffortran ! in
integer, optional,intent(in),check(shape(out,2)==nz),depend(out) :: nz=shape(out,2) integer, optional,intent(in),check(shape(out,2)==nz),depend(out) :: nz=shape(out,2)
integer intent(in) :: icorsw integer intent(in) :: icorsw
end subroutine wrf_monotonic end subroutine wrf_monotonic
function wrf_intrp_value(wvalp0,wvalp1,vlev,vcp0,vcp1,icase,errstat,errmsg) ! in :_wrffortran:wrf_vinterp.f90 function wrf_intrp_value(wvalp0,wvalp1,vlev,vcp0,vcp1,icase,errstat) ! in :_wrffortran:wrf_vinterp.f90
threadsafe threadsafe
use wrf_constants, only: sclht,algerr use wrf_constants, only: sclht,algerr
real(kind=8) intent(in) :: wvalp0 real(kind=8) intent(in) :: wvalp0
@ -527,7 +728,6 @@ python module _wrffortran ! in
real(kind=8) intent(in) :: vcp1 real(kind=8) intent(in) :: vcp1
integer intent(in) :: icase integer intent(in) :: icase
integer intent(inout) :: errstat integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg
real(kind=8) :: wrf_intrp_value real(kind=8) :: wrf_intrp_value
end function wrf_intrp_value end function wrf_intrp_value
subroutine wrf_vintrp(datain,dataout,pres,tk,qvp,ght,terrain,sfp,smsfp,vcarray,interp_levels,numlevels,icase,ew,ns,nz,extrap,vcor,logp,rmsg,errstat,errmsg) ! in :_wrffortran:wrf_vinterp.f90 subroutine wrf_vintrp(datain,dataout,pres,tk,qvp,ght,terrain,sfp,smsfp,vcarray,interp_levels,numlevels,icase,ew,ns,nz,extrap,vcor,logp,rmsg,errstat,errmsg) ! in :_wrffortran:wrf_vinterp.f90

3
requirements.txt

@ -1,2 +1,3 @@
numpy>=1.10 numpy>=1.11
wrapt>=1.10 wrapt>=1.10
setuptools>=38.0

1
setup.py

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

13
src/wrf/__init__.py

@ -1,5 +1,18 @@
from __future__ import (absolute_import, division, print_function, from __future__ import (absolute_import, division, print_function,
unicode_literals) unicode_literals)
import os
import pkg_resources
# For gfortran+msvc combination, extra shared libraries may exist (stored by numpy.distutils)
if os.name == "nt":
try:
req = pkg_resources.Requirement.parse("wrf-python")
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 . import api
from .api import * from .api import *

55
src/wrf/api.py

@ -2,17 +2,36 @@ from .config import (xarray_enabled, disable_xarray, enable_xarray,
cartopy_enabled, disable_cartopy, enable_cartopy, cartopy_enabled, disable_cartopy, enable_cartopy,
basemap_enabled, disable_basemap, enable_basemap, basemap_enabled, disable_basemap, enable_basemap,
pyngl_enabled, enable_pyngl, disable_pyngl, pyngl_enabled, enable_pyngl, disable_pyngl,
set_cache_size, get_cache_size) set_cache_size, get_cache_size, omp_enabled)
from .constants import ALL_TIMES, Constants, ConversionFactors, ProjectionTypes from .constants import (ALL_TIMES, Constants, ConversionFactors,
ProjectionTypes, default_fill,
OMP_SCHED_STATIC, OMP_SCHED_DYNAMIC,
OMP_SCHED_GUIDED, OMP_SCHED_AUTO)
from .destag import destagger from .destag import destagger
from .routines import getvar 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, uvmet, smooth2d, cape_2d, cape_3d, cloudfrac, ctt,
dbz, srhel, udhel, avo, pvo, eth, wetbulb, tvirtual, dbz, srhel, udhel, avo, pvo, eth, wetbulb, tvirtual,
omega, pw) omega, pw)
from .extension import DiagnosticError 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_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_max_active_levels, omp_get_level,
omp_get_ancestor_thread_num, omp_get_team_size,
omp_get_active_level, omp_in_final,
omp_init_lock, omp_init_nest_lock,
omp_destroy_lock, omp_destroy_nest_lock,
omp_set_lock, omp_set_nest_lock,
omp_unset_lock, omp_unset_nest_lock,
omp_test_lock, omp_test_nest_lock,
omp_get_wtime, omp_get_wtick)
from .interp import (interplevel, vertcross, interpline, vinterp) from .interp import (interplevel, vertcross, interpline, vinterp)
from .latlon import (xy_to_ll, ll_to_xy, xy_to_ll_proj, ll_to_xy_proj) 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) py3range, ucode)
from .util import (to_np, extract_global_attrs, is_standard_wrf_var, from .util import (to_np, extract_global_attrs, is_standard_wrf_var,
@ -26,7 +45,7 @@ from .util import (to_np, extract_global_attrs, is_standard_wrf_var,
has_time_coord, is_multi_file, is_multi_time_req, 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, get_cartopy, get_basemap, get_pyngl, cartopy_xlim,
cartopy_ylim, latlon_coords) cartopy_ylim, latlon_coords, ll_points, pairs_to_latlon)
from .geobnds import GeoBounds, NullGeoBounds from .geobnds import GeoBounds, NullGeoBounds
from .projection import (WrfProj, NullProjection, LambertConformal, Mercator, from .projection import (WrfProj, NullProjection, LambertConformal, Mercator,
PolarStereographic, LatLon, RotatedLatLon, PolarStereographic, LatLon, RotatedLatLon,
@ -41,15 +60,33 @@ __all__ += ["xarray_enabled", "disable_xarray", "enable_xarray",
"cartopy_enabled", "disable_cartopy", "enable_cartopy", "cartopy_enabled", "disable_cartopy", "enable_cartopy",
"basemap_enabled", "disable_basemap", "enable_basemap", "basemap_enabled", "disable_basemap", "enable_basemap",
"pyngl_enabled", "enable_pyngl", "disable_pyngl", "pyngl_enabled", "enable_pyngl", "disable_pyngl",
"set_cache_size", "get_cache_size"] "set_cache_size", "get_cache_size", "omp_enabled"]
__all__ += ["ALL_TIMES", "Constants", "ConversionFactors", "ProjectionTypes"] __all__ += ["ALL_TIMES", "Constants", "ConversionFactors", "ProjectionTypes",
"default_fill", "OMP_SCHED_STATIC", "OMP_SCHED_DYNAMIC",
"OMP_SCHED_GUIDED", "OMP_SCHED_AUTO"]
__all__ += ["destagger"] __all__ += ["destagger"]
__all__ += ["getvar"] __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", "rh", "uvmet", "smooth2d", "cape_2d", "cape_3d", "cloudfrac",
"ctt", "dbz", "srhel", "udhel", "avo", "pvo", "eth", "wetbulb", "ctt", "dbz", "srhel", "udhel", "avo", "pvo", "eth", "wetbulb",
"tvirtual", "omega", "pw"] "tvirtual", "omega", "pw"]
__all__ += ["DiagnosticError"] __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_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_max_active_levels", "omp_get_level",
"omp_get_ancestor_thread_num", "omp_get_team_size",
"omp_get_active_level", "omp_in_final",
"omp_init_lock", "omp_init_nest_lock",
"omp_destroy_lock", "omp_destroy_nest_lock",
"omp_set_lock", "omp_set_nest_lock",
"omp_unset_lock", "omp_unset_nest_lock",
"omp_test_lock", "omp_test_nest_lock",
"omp_get_wtime", "omp_get_wtick"]
__all__ += ["interplevel", "vertcross", "interpline", "vinterp"] __all__ += ["interplevel", "vertcross", "interpline", "vinterp"]
__all__ += ["xy_to_ll", "ll_to_xy", "xy_to_ll_proj", "ll_to_xy_proj"] __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",
@ -65,7 +102,7 @@ __all__ += ["to_np", "extract_global_attrs", "is_standard_wrf_var",
"has_time_coord", "is_multi_file", "is_multi_time_req", "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", "get_cartopy", "get_basemap", "get_pyngl", "cartopy_xlim",
"cartopy_ylim", "latlon_coords"] "cartopy_ylim", "latlon_coords", "ll_points", "pairs_to_latlon"]
__all__ += ["GeoBounds", "NullGeoBounds"] __all__ += ["GeoBounds", "NullGeoBounds"]
__all__ += ["WrfProj", "NullProjection", "LambertConformal", "Mercator", __all__ += ["WrfProj", "NullProjection", "LambertConformal", "Mercator",
"PolarStereographic", "LatLon", "RotatedLatLon", "getproj"] "PolarStereographic", "LatLon", "RotatedLatLon", "getproj"]

88
src/wrf/cloudfrac.py

@ -1,88 +0,0 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
from .constants import Constants
from .extension import _tk, _rh, _cloudfrac
from .metadecorators import set_cloudfrac_metadata
from .util import extract_vars
@set_cloudfrac_metadata()
def get_cloudfrac(wrfin, timeidx=0, method="cat", squeeze=True,
cache=None, meta=True, _key=None):
"""Return the cloud fraction.
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
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.
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
be a :class:`numpy.ndarray` object with no metadata.
"""
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)
return _cloudfrac(full_p, rh)

57
src/wrf/computation.py

@ -4,7 +4,7 @@ from __future__ import (absolute_import, division, print_function,
import numpy as np import numpy as np
import numpy.ma as ma import numpy.ma as ma
from .constants import Constants from .constants import default_fill
from .extension import (_interpz3d, _interp2dxy, _interp1d, _slp, _tk, _td, from .extension import (_interpz3d, _interp2dxy, _interp1d, _slp, _tk, _td,
_rh, _uvmet, _smooth2d, _cape, _cloudfrac, _ctt, _dbz, _rh, _uvmet, _smooth2d, _cape, _cloudfrac, _ctt, _dbz,
_srhel, _udhel, _avo, _pvo, _eth, _wetbulb, _tv, _srhel, _udhel, _avo, _pvo, _eth, _wetbulb, _tv,
@ -104,7 +104,7 @@ def xy(field, pivot_point=None, angle=None, start_point=None, end_point=None,
@set_interp_metadata("1d") @set_interp_metadata("1d")
def interp1d(field, z_in, z_out, missing=Constants.DEFAULT_FILL, def interp1d(field, z_in, z_out, missing=default_fill(np.float64),
meta=True): meta=True):
"""Return the linear interpolation of a one-dimensional variable. """Return the linear interpolation of a one-dimensional variable.
@ -128,7 +128,7 @@ def interp1d(field, z_in, z_out, missing=Constants.DEFAULT_FILL,
to. Must be the same type as *z_in*. to. Must be the same type as *z_in*.
missing (:obj:`float`, optional): The fill value to use for the missing (:obj:`float`, optional): The fill value to use for the
output. Default is :data:`wrf.Constants.DEFAULT_FILL`. output. Default is :data:`wrf.default_fill(np.float64)`.
meta (:obj:`bool`, optional): Set to False to disable metadata and meta (:obj:`bool`, optional): Set to False to disable metadata and
return :class:`numpy.ndarray` instead of return :class:`numpy.ndarray` instead of
@ -251,7 +251,7 @@ def interp2dxy(field3d, xy, meta=True):
@set_interp_metadata("horiz") @set_interp_metadata("horiz")
def interpz3d(field3d, vert, desiredlev, missing=Constants.DEFAULT_FILL, def interpz3d(field3d, vert, desiredlev, missing=default_fill(np.float64),
meta=True): meta=True):
"""Return the field interpolated to a specified pressure or height level. """Return the field interpolated to a specified pressure or height level.
@ -280,7 +280,7 @@ def interpz3d(field3d, vert, desiredlev, missing=Constants.DEFAULT_FILL,
Must be in the same units as the *vert* parameter. Must be in the same units as the *vert* parameter.
missing (:obj:`float`): The fill value to use for the output. missing (:obj:`float`): The fill value to use for the output.
Default is :data:`wrf.Constants.DEFAULT_FILL`. Default is :data:`wrf.default_fill(numpy.float64)`.
meta (:obj:`bool`): Set to False to disable metadata and return meta (:obj:`bool`): Set to False to disable metadata and return
:class:`numpy.ndarray` instead of :class:`numpy.ndarray` instead of
@ -713,7 +713,7 @@ def smooth2d(field, passes, meta=True):
@set_cape_alg_metadata(is2d=True, copyarg="pres_hpa") @set_cape_alg_metadata(is2d=True, copyarg="pres_hpa")
def cape_2d(pres_hpa, tkel, qv, height, terrain, psfc_hpa, ter_follow, def cape_2d(pres_hpa, tkel, qv, height, terrain, psfc_hpa, ter_follow,
missing=Constants.DEFAULT_FILL, meta=True): missing=default_fill(np.float64), meta=True):
"""Return the two-dimensional CAPE, CIN, LCL, and LFC. """Return the two-dimensional CAPE, CIN, LCL, and LFC.
This function calculates the maximum convective available potential This function calculates the maximum convective available potential
@ -790,7 +790,7 @@ def cape_2d(pres_hpa, tkel, qv, height, terrain, psfc_hpa, ter_follow,
False for pressure level data. False for pressure level data.
missing (:obj:`float`, optional): The fill value to use for the missing (:obj:`float`, optional): The fill value to use for the
output. Default is :data:`wrf.Constants.DEFAULT_FILL`. output. Default is :data:`wrf.default_fill(numpy.float64)`.
meta (:obj:`bool`): Set to False to disable metadata and return meta (:obj:`bool`): Set to False to disable metadata and return
:class:`numpy.ndarray` instead of :class:`numpy.ndarray` instead of
@ -843,7 +843,7 @@ def cape_2d(pres_hpa, tkel, qv, height, terrain, psfc_hpa, ter_follow,
@set_cape_alg_metadata(is2d=False, copyarg="pres_hpa") @set_cape_alg_metadata(is2d=False, copyarg="pres_hpa")
def cape_3d(pres_hpa, tkel, qv, height, terrain, psfc_hpa, ter_follow, def cape_3d(pres_hpa, tkel, qv, height, terrain, psfc_hpa, ter_follow,
missing=Constants.DEFAULT_FILL, meta=True): missing=default_fill(np.float64), meta=True):
"""Return the three-dimensional CAPE and CIN. """Return the three-dimensional CAPE and CIN.
This function calculates the maximum convective available potential This function calculates the maximum convective available potential
@ -926,7 +926,7 @@ def cape_3d(pres_hpa, tkel, qv, height, terrain, psfc_hpa, ter_follow,
False for pressure level data. False for pressure level data.
missing (:obj:`float`, optional): The fill value to use for the missing (:obj:`float`, optional): The fill value to use for the
output. Default is :data:`wrf.Constants.DEFAULT_FILL`. output. Default is :data:`wrf.default_fill(numpy.float64)`.
meta (:obj:`bool`): Set to False to disable metadata and return meta (:obj:`bool`): Set to False to disable metadata and return
:class:`numpy.ndarray` instead of :class:`numpy.ndarray` instead of
@ -962,8 +962,9 @@ def cape_3d(pres_hpa, tkel, qv, height, terrain, psfc_hpa, ter_follow,
return ma.masked_values(cape_cin, missing) return ma.masked_values(cape_cin, missing)
@set_cloudfrac_alg_metadata(copyarg="pres") @set_cloudfrac_alg_metadata(copyarg="vert")
def cloudfrac(pres, relh, meta=True): def cloudfrac(vert, relh, vert_inc_w_height, low_thresh, mid_thresh,
high_thresh, missing=default_fill(np.float64), meta=True):
"""Return the cloud fraction. """Return the cloud fraction.
The leftmost dimension of the returned array represents three different The leftmost dimension of the returned array represents three different
@ -973,14 +974,22 @@ def cloudfrac(pres, relh, meta=True):
- return_val[1,...] will contain MID level cloud fraction - return_val[1,...] will contain MID level cloud fraction
- return_val[2,...] will contain HIGH level cloud fraction - return_val[2,...] will contain HIGH level cloud fraction
The *low_thresh*, *mid_thresh*, and *high_threshold* paramters specify the
low, mid, and high cloud levels in the same units as *vert*.
In mountainous regions, there is a possibility
that the lowest WRF level will be higher than the low_cloud or mid_cloud
threshold. When this happens, a fill value will be used in the output at
that location.
This is the raw computational algorithm and does not extract any variables This is the raw computational algorithm and does not extract any variables
from WRF output files. Use :meth:`wrf.getvar` to both extract and compute from WRF output files. Use :meth:`wrf.getvar` to both extract and compute
diagnostic variables. diagnostic variables.
Args: Args:
pres (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Full vert (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The
pressure (perturbation + base state pressure) in [Pa], with the vertical coordinate variable (usually pressure or height) with the
rightmost dimensions as bottom_top x south_north x west_east rightmost dimensions as bottom_top x south_north x west_east
Note: Note:
@ -990,8 +999,21 @@ def cloudfrac(pres, relh, meta=True):
dimension names to the output. Otherwise, default names will dimension names to the output. Otherwise, default names will
be used. be used.
relh (:class:`xarray.DataArray` or :class:`numpy.ndarray`) Relative relh (:class:`xarray.DataArray` or :class:`numpy.ndarray`): Relative
humidity with the same dimensionality as *pres* humidity with the same dimensionality as *vert*
vert_inc_w_height (:obj:`int`): Set to 1 if the vertical coordinate
values increase with height (height values). Set to 0 if the
vertical coordinate values decrease with height (pressure values).
low_thresh (:obj:`float`): The bottom vertical threshold for what is
considered a low cloud.
mid_thresh (:obj:`float`): The bottom vertical threshold for what is
considered a mid level cloud.
high_thresh (:obj:`float`): The bottom vertical threshold for what is
considered a high cloud.
meta (:obj:`bool`): Set to False to disable metadata and return meta (:obj:`bool`): Set to False to disable metadata and return
:class:`numpy.ndarray` instead of :class:`numpy.ndarray` instead of
@ -1016,7 +1038,10 @@ def cloudfrac(pres, relh, meta=True):
:meth:`wrf.getvar`, :meth:`wrf.rh` :meth:`wrf.getvar`, :meth:`wrf.rh`
""" """
return _cloudfrac(pres, relh) cfrac = _cloudfrac(vert, relh, vert_inc_w_height, low_thresh, mid_thresh,
high_thresh, missing)
return ma.masked_values(cfrac, missing)
@set_alg_metadata(2, "pres_hpa", refvarndims=3, @set_alg_metadata(2, "pres_hpa", refvarndims=3,

92
src/wrf/config.py

@ -2,35 +2,68 @@ from __future__ import (absolute_import, division, print_function,
unicode_literals) unicode_literals)
from threading import local from threading import local
import wrapt
from ._wrffortran import (fomp_enabled, fomp_set_num_threads,
fomp_set_schedule, fomp_set_dynamic,
omp_constants)
_local_config = local() _local_config = local()
_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
try: 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 from xarray import DataArray
except ImportError: except ImportError:
_local_config.xarray_enabled = False _local_config.xarray_enabled = False
try: try:
from cartopy import crs from cartopy import crs
except ImportError: except ImportError:
_local_config.cartopy_enabled = False _local_config.cartopy_enabled = False
try: try:
from mpl_toolkits.basemap import Basemap from mpl_toolkits.basemap import Basemap
except ImportError: except ImportError:
_local_config.basemap_enabled = False _local_config.basemap_enabled = False
try: try:
from Ngl import Resources from Ngl import Resources
except ImportError: except ImportError:
_local_config.pyngl_enabled = False _local_config.pyngl_enabled = False
# Initialize the main thread's configuration
_init_local()
def init_local():
"""A decorator that initializes thread local data if necessary."""
@wrapt.decorator
def func_wrapper(wrapped, instance, args, kwargs):
global _local_config
try:
init = _local_config.init
except AttributeError:
_init_local()
else:
if not init:
_init_local()
return wrapped(*args, **kwargs)
return func_wrapper
@init_local()
def xarray_enabled(): def xarray_enabled():
"""Return True if xarray is installed and enabled. """Return True if xarray is installed and enabled.
@ -43,18 +76,21 @@ def xarray_enabled():
return _local_config.xarray_enabled return _local_config.xarray_enabled
@init_local()
def disable_xarray(): def disable_xarray():
"""Disable xarray.""" """Disable xarray."""
global _local_config global _local_config
_local_config.xarray_enabled = False _local_config.xarray_enabled = False
@init_local()
def enable_xarray(): def enable_xarray():
"""Enable xarray.""" """Enable xarray."""
global _local_config global _local_config
_local_config.xarray_enabled = True _local_config.xarray_enabled = True
@init_local()
def cartopy_enabled(): def cartopy_enabled():
"""Return True if cartopy is installed and enabled. """Return True if cartopy is installed and enabled.
@ -67,18 +103,21 @@ def cartopy_enabled():
return _local_config.cartopy_enabled return _local_config.cartopy_enabled
@init_local()
def enable_cartopy(): def enable_cartopy():
"""Enable cartopy.""" """Enable cartopy."""
global _local_config global _local_config
_local_config.cartopy_enabled = True _local_config.cartopy_enabled = True
@init_local()
def disable_cartopy(): def disable_cartopy():
"""Disable cartopy.""" """Disable cartopy."""
global _local_config global _local_config
_local_config.cartopy_enabled = True _local_config.cartopy_enabled = True
@init_local()
def basemap_enabled(): def basemap_enabled():
"""Return True if basemap is installed and enabled. """Return True if basemap is installed and enabled.
@ -91,17 +130,21 @@ def basemap_enabled():
return _local_config.basemap_enabled return _local_config.basemap_enabled
@init_local()
def enable_basemap(): def enable_basemap():
"""Enable basemap.""" """Enable basemap."""
global _local_config global _local_config
_local_config.basemap_enabled = True _local_config.basemap_enabled = True
@init_local()
def disable_basemap(): def disable_basemap():
"""Disable basemap.""" """Disable basemap."""
global _local_config global _local_config
_local_config.basemap_enabled = True _local_config.basemap_enabled = True
@init_local()
def pyngl_enabled(): def pyngl_enabled():
"""Return True if pyngl is installed and enabled. """Return True if pyngl is installed and enabled.
@ -114,18 +157,21 @@ def pyngl_enabled():
return _local_config.pyngl_enabled return _local_config.pyngl_enabled
@init_local()
def enable_pyngl(): def enable_pyngl():
"""Enable pyngl.""" """Enable pyngl."""
global _local_config global _local_config
_local_config.pyngl_enabled = True _local_config.pyngl_enabled = True
@init_local()
def disable_pyngl(): def disable_pyngl():
"""Disable pyngl.""" """Disable pyngl."""
global _local_config global _local_config
_local_config.pyngl_enabled = True _local_config.pyngl_enabled = True
@init_local()
def set_cache_size(size): def set_cache_size(size):
"""Set the maximum number of items that the threadlocal cache can retain. """Set the maximum number of items that the threadlocal cache can retain.
@ -144,6 +190,7 @@ def set_cache_size(size):
_local_config.cache_size = size _local_config.cache_size = size
@init_local()
def get_cache_size(): 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.
@ -156,4 +203,23 @@ def get_cache_size():
return int(_local_config.cache_size) 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
# circular import problems in the future.
fomp_set_num_threads(1)
fomp_set_schedule(omp_constants.fomp_sched_static, 0)
fomp_set_dynamic(False)

48
src/wrf/constants.py

@ -1,10 +1,12 @@
from __future__ import (absolute_import, division, print_function, from __future__ import (absolute_import, division, print_function,
unicode_literals) unicode_literals)
from sys import version_info
import struct
import numpy as np import numpy as np
from .py3compat import viewitems from .py3compat import viewitems
from wrf._wrffortran import wrf_constants from ._wrffortran import wrf_constants, omp_constants
#: Indicates that all times should be used in a diagnostic routine. #: Indicates that all times should be used in a diagnostic routine.
ALL_TIMES = None ALL_TIMES = None
@ -15,6 +17,12 @@ class Constants(object):
for key,val in viewitems(wrf_constants.__dict__): for key,val in viewitems(wrf_constants.__dict__):
setattr(Constants, key.upper(), np.asscalar(val)) setattr(Constants, key.upper(), np.asscalar(val))
OMP_SCHED_STATIC = omp_constants.fomp_sched_static
OMP_SCHED_DYNAMIC = omp_constants.fomp_sched_dynamic
OMP_SCHED_GUIDED = omp_constants.fomp_sched_guided
OMP_SCHED_AUTO = omp_constants.fomp_sched_auto
class ConversionFactors(object): class ConversionFactors(object):
PA_TO_HPA = .01 PA_TO_HPA = .01
PA_TO_TORR = 760.0/101325.0 PA_TO_TORR = 760.0/101325.0
@ -29,6 +37,7 @@ class ConversionFactors(object):
M_TO_FT = 3.28084 M_TO_FT = 3.28084
M_TO_MILES = .000621371 M_TO_MILES = .000621371
class ProjectionTypes(object): class ProjectionTypes(object):
ZERO = 0 ZERO = 0
LAMBERT_CONFORMAL = 1 LAMBERT_CONFORMAL = 1
@ -36,4 +45,41 @@ class ProjectionTypes(object):
MERCATOR = 3 MERCATOR = 3
LAT_LON = 6 LAT_LON = 6
# 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
}
if version_info >= (3, ):
_DEFAULT_FILL_MAP[np.int_] = Constants.DEFAULT_FILL_INT64
else:
_DEFAULT_FILL_MAP[np.int_] = Constants.DEFAULT_FILL_INT32
if (struct.calcsize("P") == 8):
_DEFAULT_FILL_MAP[np.intp] = Constants.DEFAULT_FILL_INT64
else:
_DEFAULT_FILL_MAP[np.intp] = Constants.DEFAULT_FILL_INT32
# Add the integers based on python 2.x or 3.x
def default_fill(dtype=None):
dt = np.dtype(dtype) if dtype is not None else None
return _DEFAULT_FILL_MAP.get(dt, 0)

8
src/wrf/decorators.py

@ -11,7 +11,7 @@ from .units import do_conversion, check_units, dealias_and_clean_unit
from .util import iter_left_indexes, from_args, to_np, combine_dims from .util import iter_left_indexes, from_args, to_np, combine_dims
from .py3compat import viewitems, viewvalues, isstr from .py3compat import viewitems, viewvalues, isstr
from .config import xarray_enabled from .config import xarray_enabled
from .constants import Constants from .constants import default_fill
if xarray_enabled(): if xarray_enabled():
from xarray import DataArray from xarray import DataArray
@ -201,7 +201,7 @@ def left_iteration(ref_var_expected_dims,
if all_masked: if all_masked:
for output in viewvalues(outd): for output in viewvalues(outd):
output[left_and_slice_idxs] = ( output[left_and_slice_idxs] = (
Constants.DEFAULT_FILL) default_fill(np.float64))
skip_missing = True skip_missing = True
mask_output = True mask_output = True
break break
@ -240,9 +240,9 @@ def left_iteration(ref_var_expected_dims,
# Mostly when used with join # Mostly when used with join
if mask_output: if mask_output:
if isinstance(output, np.ndarray): if isinstance(output, np.ndarray):
output = ma.masked_values(output, Constants.DEFAULT_FILL) output = ma.masked_values(output, default_fill(np.float64))
else: else:
output = tuple(ma.masked_values(arr, Constants.DEFAULT_FILL) output = tuple(ma.masked_values(arr, default_fill(np.float64))
for arr in output) for arr in output)
return output return output

749
src/wrf/extension.py

@ -3,16 +3,32 @@ from __future__ import (absolute_import, division, print_function,
import numpy as np import numpy as np
from .constants import Constants from .constants import Constants, default_fill
from ._wrffortran import (dcomputetk, dinterp3dz, dinterp2dxy, dinterp1d, from wrf._wrffortran import (dcomputetk, dinterp3dz, dinterp2dxy, dinterp1d,
dcomputeseaprs, dfilter2d, dcomputerh, dcomputeuvmet, dcomputeseaprs, dfilter2d, dcomputerh, dcomputeuvmet,
dcomputetd, dcapecalc3d, dcloudfrac, wrfcttcalc, dcomputetd, dcapecalc2d, dcapecalc3d, dcloudfrac2,
calcdbz, dcalrelhl, dcalcuh, dcomputepv, wrfcttcalc, calcdbz, dcalrelhl, dcalcuh, dcomputepv,
dcomputeabsvort, dlltoij, dijtoll, deqthecalc, dcomputeabsvort, dlltoij, dijtoll, deqthecalc,
omgcalc, virtual_temp, wetbulbcalc, dcomputepw, omgcalc, virtual_temp, wetbulbcalc, dcomputepw,
wrf_monotonic, wrf_vintrp, dcomputewspd, wrf_monotonic, wrf_vintrp, dcomputewspd,
dcomputewdir) dcomputewdir,
fomp_set_num_threads, fomp_get_num_threads,
fomp_get_max_threads, fomp_get_thread_num,
fomp_get_num_procs, fomp_in_parallel,
fomp_set_dynamic, fomp_get_dynamic, fomp_set_nested,
fomp_get_nested, fomp_set_schedule,
fomp_get_schedule, fomp_get_thread_limit,
fomp_set_max_active_levels,
fomp_get_max_active_levels, fomp_get_level,
fomp_get_ancestor_thread_num, fomp_get_team_size,
fomp_get_active_level, fomp_in_final,
fomp_init_lock, fomp_init_nest_lock,
fomp_destroy_lock, fomp_destroy_nest_lock,
fomp_set_lock, fomp_set_nest_lock,
fomp_unset_lock, fomp_unset_nest_lock,
fomp_test_lock, fomp_test_nest_lock,
fomp_get_wtime, fomp_get_wtick, fomp_enabled)
from .decorators import (left_iteration, cast_type, from .decorators import (left_iteration, cast_type,
extract_and_transpose, check_args) extract_and_transpose, check_args)
@ -24,7 +40,7 @@ from .specialdec import (uvmet_left_iter, cape_left_iter,
class DiagnosticError(Exception): class DiagnosticError(Exception):
"""Raised when an error occurs in a diagnostic routine.""" """Raised when an error occurs in a diagnostic routine."""
def __init__(self, message=None): def __init__(self, message=None):
"""Initialize a :class:`wrf.DiagnosticError` objection. """Initialize a :class:`wrf.DiagnosticError` object.
Args: Args:
@ -365,8 +381,8 @@ def _eth(qv, tk, p, outview=None):
@cast_type(arg_idxs=(0,1,2,3)) @cast_type(arg_idxs=(0,1,2,3))
@extract_and_transpose() @extract_and_transpose()
def _uvmet(u, v, lat, lon, cen_long, cone, isstag=0, has_missing=False, def _uvmet(u, v, lat, lon, cen_long, cone, isstag=0, has_missing=False,
umissing=Constants.DEFAULT_FILL, vmissing=Constants.DEFAULT_FILL, umissing=default_fill(np.float64), vmissing=default_fill(np.float64),
uvmetmissing=Constants.DEFAULT_FILL, outview=None): uvmetmissing=default_fill(np.float64), outview=None):
"""Wrapper for dcomputeuvmet. """Wrapper for dcomputeuvmet.
Located in wrf_user.f90. Located in wrf_user.f90.
@ -597,8 +613,13 @@ def _cape(p_hpa, tk, qv, ht, ter, sfp, missing, i3dflag, ter_follow,
errstat = np.array(0) errstat = np.array(0)
errmsg = np.zeros(Constants.ERRLEN, "c") errmsg = np.zeros(Constants.ERRLEN, "c")
if i3dflag:
cape_routine = dcapecalc3d
else:
cape_routine = dcapecalc2d
# note that p_hpa, tk, qv, and ht have the vertical flipped # note that p_hpa, tk, qv, and ht have the vertical flipped
result = dcapecalc3d(p_hpa, result = cape_routine(p_hpa,
tk, tk,
qv, qv,
ht, ht,
@ -607,7 +628,6 @@ def _cape(p_hpa, tk, qv, ht, ter, sfp, missing, i3dflag, ter_follow,
capeview, capeview,
cinview, cinview,
missing, missing,
i3dflag,
ter_follow, ter_follow,
psafile, psafile,
errstat, errstat,
@ -620,27 +640,33 @@ def _cape(p_hpa, tk, qv, ht, ter, sfp, missing, i3dflag, ter_follow,
@check_args(0, 3, (3,3)) @check_args(0, 3, (3,3))
@cloudfrac_left_iter() @cloudfrac_left_iter()
@cast_type(arg_idxs=(0, 1), outviews=("lowview", "medview", "highview")) @cast_type(arg_idxs=(0, 1), outviews=("lowview", "midview", "highview"))
@extract_and_transpose(outviews=("lowview", "medview", "hightview")) @extract_and_transpose(outviews=("lowview", "midview", "highview"))
def _cloudfrac(p, rh, lowview=None, medview=None, highview=None): def _cloudfrac(vert, rh, vert_inc_w_height, low_thresh, mid_thresh,
"""Wrapper for dcloudfrace. high_thresh, missing, lowview=None, midview=None, highview=None):
"""Wrapper for dcloudfrac2.
Located in wrf_cloud_fracf.f90. Located in wrf_cloud_fracf.f90.
""" """
if lowview is None: if lowview is None:
lowview = np.zeros(p.shape[0:2], p.dtype, order="F") lowview = np.zeros(vert.shape[0:2], vert.dtype, order="F")
if medview is None: if midview is None:
medview = np.zeros(p.shape[0:2], p.dtype, order="F") midview = np.zeros(vert.shape[0:2], vert.dtype, order="F")
if highview is None: if highview is None:
highview = np.zeros(p.shape[0:2], p.dtype, order="F") highview = np.zeros(vert.shape[0:2], vert.dtype, order="F")
result = dcloudfrac(p, result = dcloudfrac2(vert,
rh, rh,
vert_inc_w_height,
low_thresh,
mid_thresh,
high_thresh,
missing,
lowview, lowview,
medview, midview,
highview) highview)
return result return result
@ -769,7 +795,7 @@ def _smooth2d(field, passes, outview=None):
if isinstance(field, np.ma.MaskedArray): if isinstance(field, np.ma.MaskedArray):
missing = field.fill_value missing = field.fill_value
else: else:
missing = Constants.DEFAULT_FILL missing = default_fill(np.float64)
if outview is None: if outview is None:
outview = field.copy(order="A") outview = field.copy(order="A")
@ -900,3 +926,684 @@ def _wdir(u, v, outview=None):
return result return result
# OpenMP runtime wrappers
def omp_set_num_threads(num_threads):
"""Specify the number of threads to use.
The omp_set_num_threads routine affects the number of threads to be used
for subsequent parallel regions that do not specify a num_threads
clause, by setting the value of the first element of the nthreads-var
ICV of the current task.
Args:
num_threads (a positive :obj:`int`): The number of threads. Must be
positive.
Returns:
None.
"""
if num_threads < 0 and fomp_enabled():
raise ValueError("'num_threads' must be a positive integer.")
fomp_set_num_threads(num_threads)
def omp_get_num_threads():
"""Return the number of threads in the current team.
The omp_get_num_threads routine returns the number of threads in the
team executing the parallel region to which the routine region binds.
If called from the sequential part of a program, this routine returns 1.
Note:
This function always returns 1 when called from within Python.
Returns:
:obj:`int`: The number of threads in the current team.
See Also:
:meth:`wrf.omp_get_max_threads`, :meth:`wrf.omp_set_num_threads`
"""
return fomp_get_num_threads()
def omp_get_max_threads():
"""Return the maximum number of threads that can be used in a parallel \
region.
The omp_get_max_threads routine returns an upper bound on the number of
threads that could be used to form a new team if a parallel construct
without a num_threads clause were encountered after execution returns from
this routine.
Returns:
:obj:`int`: The number of threads in the current team.
See Also:
:meth:`wrf.omp_set_num_threads`
"""
return fomp_get_max_threads()
def omp_get_thread_num():
"""Return the thread number, within the current team, of the \
calling thread.
The omp_get_thread_num routine returns the thread number of the calling
thread, within the team executing the parallel region to which the routine
region binds. The thread number is an integer between 0 and one less than
the value returned by omp_get_num_threads, inclusive. The thread number of
the master thread of the team is 0. The routine returns 0 if it is called
from the sequential part of a program.
Note:
This function always returns 0 when called from within Python.
Returns:
:obj:`int`: The thread number.
See Also:
:meth:`wrf.omp_get_num_procs`
"""
return fomp_get_thread_num()
def omp_get_num_procs():
"""Return the number of processors on the device.
The omp_get_num_procs routine returns the number of processors that are
available to the device at the time the routine is called. This value may
change between the time that it is determined by the omp_get_num_procs
routine and the time that it is read in the calling context due to system
actions outside the control of the OpenMP implementation.
Returns:
:obj:`int`: The number of processors.
"""
return fomp_get_num_procs()
def omp_in_parallel():
"""Return 1 if the active-levels-var ICV is greater than zero; \
otherwise, return 0.
The effect of the omp_in_parallel routine is to return 1 if the current
task is enclosed by an active parallel region, and the parallel region is
enclosed by the outermost initial task region on the device; otherwise it
returns 0.
Note:
This function always returns 0 when called from within Python.
Returns:
:obj:`int`: Returns 1 if the active-levels-var ICV is greater than
zero. Otherwise, it returns 0.
"""
return fomp_in_parallel()
def omp_set_dynamic(dynamic_threads):
"""Enable or disable dynamic adjustment of the number of threads \
available for the execution of subsequent parallel regions by setting the \
value of the dyn-var ICV.
For implementations that support dynamic adjustment of the number of
threads, if the argument to omp_set_dynamic evaluates to True, dynamic
adjustment is enabled for the current task; otherwise, dynamic adjustment
is disabled for the current task. For implementations that do not support
dynamic adjustment of the number of threads this routine has no effect:
the value of dyn-var remains false.
Args:
dynamic_threads (:obj:`bool`): Set to True to support the dynamic
adjustment of the number of threads. Otherwise, set to False.
Returns:
None.
See Also:
:meth:`wrf.omp_get_dynamic`
"""
fomp_set_dynamic(dynamic_threads)
def omp_get_dynamic():
"""Return the value of the dyn-var ICV, which determines whether \
dynamic adjustment of the number of threads is enabled or disabled.
This routine returns 1 if dynamic adjustment of the number of threads
is enabled for the current task; it returns 0, otherwise. If an
implementation does not support dynamic adjustment of the
number of threads, then this routine always returns 0.
Returns:
:obj:`int`: Returns 1 if dynamic thread adjustment is enabled, 0
if disabled.
See Also:
:meth:`wrf.omp_set_dynamic`
"""
return fomp_get_dynamic()
def omp_set_nested(nested):
"""Enable or disable nested parallelism, by setting the nest-var ICV
For implementations that support nested parallelism, if the argument to
omp_set_nested evaluates to True, nested parallelism is enabled for the
current task; otherwise, nested parallelism is disabled for the current
task. For implementations that do not support nested parallelism, this
routine has no effect: the value of nest-var remains False.
Args:
dynamic_threads (:obj:`bool`): Set to True to support nested
parallelism, otherwise False.
Returns:
None
See Also:
:meth:`wrf.omp_get_nested`
"""
fomp_set_nested(nested)
def omp_get_nested():
"""Return the value of the nest-var ICV, which determines if nested \
parallelism is enabled or disabled
This routine returns 1 if nested parallelism is enabled for the current
task; it returns 0, otherwise. If an implementation does not support
nested parallelism, this routine always returns 0.
Returns:
:obj:`int`: Returns 1 if nested parallelism is enabled, otherwise 0.
See Also:
:meth:`wrf.omp_set_nested`
"""
return fomp_get_nested()
def omp_set_schedule(kind, modifier=0):
"""Set the schedule that is applied when *runtime* is used as \
schedule kind, by setting the value of the run-sched-var ICV.
The effect of this routine is to set the value of the run-sched-var ICV
of the current task to the values specified in the two arguments. The
schedule is set to the schedule type specified by the first argument kind.
It can be any of the standard schedule types or any other implementation
specific one. For the schedule types static, dynamic, and guided the
chunk_size is set to the value of the second argument, or to the default
chunk_size if the value of the second argument is less than 1; for the
schedule type auto the second argument has no meaning; for implementation
specific schedule types, the values and associated meanings of the second
argument are implementation defined.
Args:
kind (:obj:`int`): Must be :data:`wrf.OMP_SCHED_STATIC`,
:data:`wrf.OMP_SCHED_DYNAMIC`, :data:`wrf.OMP_SCHED_GUIDED`,
or :data:`wrf.OMP_SCHED_AUTO`.
modifier(:obj:`int`): An implementation specific value, depending on
the choice for *kind*. This parameter is alternatively named
chunk_size in some OpenMP documentation. Default is 0, which
means the OpenMP implementation will use its default value.
Returns:
None
See Also:
:meth:`wrf.omp_get_schedule`
"""
fomp_set_schedule(kind, modifier)
def omp_get_schedule():
"""Return the schedule that is applied when the runtime schedule is used.
This routine returns the run-sched-var ICV in the task to which the routine
binds. The first item is the schedule kind, which will be one of
:data:`wrf.OMP_SCHED_STATIC`, :data:`wrf.OMP_SCHED_DYNAMIC`,
:data:`wrf.OMP_SCHED_GUIDED`, or :data:`wrf.OMP_SCHED_AUTO`. The second
item returned is the modifier, which is often named chunk_size in
OpenMP documentation.
Returns:
:obj:`tuple`: The first item is an :obj:`int` for the schedule *kind*.
The second items is :obj:`int` for the *modifier* (chunk_size).
See Also:
:meth:`wrf.omp_set_schedule`
"""
return fomp_get_schedule()
def omp_get_thread_limit():
"""Return the maximum number of OpenMP threads available to participate \
in the current contention group.
The omp_get_thread_limit routine returns the value of the thread-limit-var
ICV.
Returns:
:obj:`int`: The number of OpenMP threads available to participate in
the current contention group.
See Also:
:meth:`wrf.omp_get_max_threads`
"""
return fomp_get_thread_limit()
def omp_set_max_active_levels(max_levels):
"""Limit the number of nested active parallel regions on the device, \
by setting the max-active-levels-var ICV.
The effect of this routine is to set the value of the max-active-levels-var
ICV to the value specified in the argument. If the number of parallel
levels requested exceeds the number of levels of parallelism supported by
the implementation, the value of the max-active-levels-var ICV will be set
to the number of parallel levels supported by the implementation. This
routine has the described effect only when called from a sequential part
of the program. When called from within an explicit parallel region, the
effect of this routine is implementation defined.
Args:
max_levels (:obj:`int`): The maximum number of nested active parallel
regions.
Returns:
None.
See Also:
:meth:`wrf.omp_get_max_active_levels`
"""
fomp_set_max_active_levels(max_levels)
def omp_get_max_active_levels():
"""Return the value of the max-active-levels-var ICV, which determines \
the maximum number of nested active parallel regions on the device
The omp_get_max_active_levels routine returns the value of the
max-active-levels-var ICV, which determines the maximum number of nested
active parallel regions on the device.
Returns:
:obj:`int`: The maximum number of nested active parallel regions.
See Also:
:meth:`wrf.omp_set_max_active_levels`
"""
return fomp_get_max_active_levels()
def omp_get_level():
"""Return the value of the levels-var ICV.
The effect of the omp_get_level routine is to return the number of nested
parallel regions (whether active or inactive) enclosing the current task
such that all of the parallel regions are enclosed by the outermost initial
task region on the current device.
Returns:
:obj:`int`: The number of nested parallel regions.
See Also:
:meth:`wrf.omp_get_active_level`
"""
return fomp_get_level()
def omp_get_ancestor_thread_num(level):
"""Return, for a given nested level of the current thread, the thread \
number of the ancestor of the current thread.
The omp_get_ancestor_thread_num routine returns the thread number of the
ancestor at a given nest level of the current thread or the thread number
of the current thread. If the requested nest level is outside the range of
0 and the nest level of the current thread, as returned by the
omp_get_level routine, the routine returns -1.
Args:
level (:obj:`int`): The nested level of the current thread.
Returns:
:obj:`int`: The thread number of the ancestor at a given nest level
of the current thread.
See Also:
:meth:`wrf.omp_get_max_active_levels`, :meth:`wrf.omp_get_level`
"""
return fomp_get_ancestor_thread_num(level)
def omp_get_team_size(level):
"""Return, for a given nested level of the current thread, the size \
of the thread team to which the ancestor or the current thread belongs
The omp_get_team_size routine returns the size of the thread team to which
the ancestor or the current thread belongs. If the requested nested level
is outside the range of 0 and the nested level of the current thread, as
returned by the omp_get_level routine, the routine returns -1. Inactive
parallel regions are regarded like active parallel regions executed with
one thread.
Args:
level (:obj:`int`): The nested level of the current thread.
Returns:
:obj:`int`: The size of the thread team.
See Also:
:meth:`wrf.omp_get_ancestor_thread_num`
"""
return fomp_get_team_size(level)
def omp_get_active_level():
"""Return the value of the active-level-vars ICV.
The effect of the omp_get_active_level routine is to return the number of
nested, active parallel regions enclosing the current task such that all
of the parallel regions are enclosed by the outermost initial task region
on the current device.
Returns:
:obj:`int`: The number of nested activate parallel regions.
See Also:
:meth:`wrf.omp_get_team_size`
"""
return fomp_get_active_level()
def omp_in_final():
"""Return 1 (True) if the routine is executed in a final task region; \
otherwise, it returns 0 (False).
Returns:
:obj:`int`: Return 1 if the routine is executed in a final task
region, 0 otherwise.
"""
return fomp_in_final()
def omp_init_lock():
"""Initialize a simple OpenMP lock.
Returns:
:obj:`int`: An integer representing the lock.
See Also:
:meth:`wrf.omp_init_nest_lock`, :meth:`wrf.omp_destroy_lock`
"""
return fomp_init_lock()
def omp_init_nest_lock():
"""Initialize a nestable OpenMP lock.
Returns:
:obj:`int`: An integer representing the nestable lock.
See Also:
:meth:`wrf.omp_init_lock`
"""
return fomp_init_nest_lock()
def omp_destroy_lock(svar):
"""Destroy a simple OpenMP lock.
This sets the lock to an uninitialized state.
Args:
svar (:obj:`int`): An integer representing the lock.
See Also:
:meth:`wrf.omp_destroy_nest_lock`, :meth:`wrf.omp_init_lock`
"""
fomp_destroy_lock(svar)
def omp_destroy_nest_lock(nvar):
"""Destroy a nestable OpenMP lock.
This sets the lock to an uninitialized state.
Args:
nvar (:obj:`int`): An integer representing the nestable lock.
See Also:
:meth:`wrf.omp_destroy_lock`, :meth:`wrf.omp_init_nest_lock`
"""
fomp_destroy_nest_lock(nvar)
def omp_set_lock(svar):
"""Set a simple OpenMP lock.
Args:
svar (:obj:`int`): An integer representing the lock.
See Also:
:meth:`wrf.omp_unset_lock`, :meth:`wrf.omp_set_nest_lock`
"""
fomp_set_lock(svar)
def omp_set_nest_lock(nvar):
"""Set a nestable OpenMP lock.
Args:
nvar (:obj:`int`): An integer representing the nestable lock.
See Also:
:meth:`wrf.omp_unset_nest_lock`, :meth:`wrf.omp_set_lock`
"""
fomp_set_nest_lock(nvar)
def omp_unset_lock(svar):
"""Unset a simple OpenMP lock.
Args:
svar (:obj:`int`): An integer representing the simple lock.
See Also:
:meth:`wrf.omp_unset_nest_lock`, :meth:`wrf.omp_set_lock`
"""
fomp_unset_lock(svar)
def omp_unset_nest_lock(nvar):
"""Unset a nestable OpenMP lock.
Args:
nvar (:obj:`int`): An integer representing the nestable lock.
See Also:
:meth:`wrf.omp_set_nest_lock`, :meth:`wrf.omp_unset_lock`
"""
fomp_unset_nest_lock(nvar)
def omp_test_lock(svar):
"""Test a simple OpenMP lock.
This method attempts to set the lock, but does not suspend execution.
Args:
svar (:obj:`int`): An integer representing the simple lock.
Returns:
:obj:`int`: Returns 1 (True) if the lock is successfully set,
otherwise 0 (False).
See Also:
:meth:`wrf.test_nest_lock`, :meth:`wrf.omp_set_lock`
"""
return fomp_test_lock(svar)
def omp_test_nest_lock(nvar):
"""Test a nestable OpenMP lock.
This method attempts to set the lock, but does not suspend execution.
Args:
nvar (:obj:`int`): An integer representing the simple lock.
Returns:
:obj:`int`: Returns the nesting count if successful,
otherwise 0 (False).
See Also:
:meth:`wrf.test_lock`, :meth:`wrf.omp_set_nest_lock`
"""
return fomp_test_nest_lock(nvar)
def omp_get_wtime():
"""Return elapsed wall clock time in seconds.
The omp_get_wtime routine returns a value equal to the elapsed wall clock
time in seconds since some time in the past. The actual
time in the past is arbitrary, but it is guaranteed not to change during
the execution of the application program. The time returned is a
per-thread time, so it is not required to be globally consistent across
all threads participating in an application.
Returns:
:obj:`float`: Returns the wall clock time in seconds.
See Also:
:meth:`wrf.omp_get_wtick`
"""
return fomp_get_wtime()
def omp_get_wtick():
"""Return the precision of the timer used by :meth:`wrf.omp_get_wtime`.
The omp_get_wtick routine returns a value equal to the number of
seconds between successive clock ticks of the timer used by
:meth:`wrf.omp_get_wtime`.
Returns:
:obj:`float`: Returns the precision of the timer.
See Also:
:meth:`wrf.omp_get_wtime`
"""
return fomp_get_wtick()

10
src/wrf/cape.py → src/wrf/g_cape.py

@ -6,13 +6,13 @@ import numpy.ma as ma
from .extension import _tk, _cape from .extension import _tk, _cape
from .destag import destagger from .destag import destagger
from .constants import Constants, ConversionFactors from .constants import default_fill, Constants, ConversionFactors
from .util import extract_vars from .util import extract_vars
from .metadecorators import set_cape_metadata from .metadecorators import set_cape_metadata
@set_cape_metadata(is2d=True) @set_cape_metadata(is2d=True)
def get_2dcape(wrfin, timeidx=0, method="cat", squeeze=True, cache=None, def get_2dcape(wrfin, timeidx=0, method="cat", squeeze=True, cache=None,
meta=True, _key=None, missing=Constants.DEFAULT_FILL): meta=True, _key=None, missing=default_fill(np.float64)):
"""Return the 2d fields of CAPE, CIN, LCL, and LFC. """Return the 2d fields of CAPE, CIN, LCL, and LFC.
The leftmost dimension of the returned array represents four different The leftmost dimension of the returned array represents four different
@ -66,7 +66,7 @@ def get_2dcape(wrfin, timeidx=0, method="cat", squeeze=True, cache=None,
purposes only. Default is None. purposes only. Default is None.
missing (:obj:`float`): The fill value to use for the output. missing (:obj:`float`): The fill value to use for the output.
Default is :data:`wrf.Constants.DEFAULT_FILL`. Default is :data:`wrf.default_fill(np.float64)`.
Returns: Returns:
:class:`xarray.DataArray` or :class:`numpy.ndarray`: The :class:`xarray.DataArray` or :class:`numpy.ndarray`: The
@ -130,7 +130,7 @@ def get_2dcape(wrfin, timeidx=0, method="cat", squeeze=True, cache=None,
@set_cape_metadata(is2d=False) @set_cape_metadata(is2d=False)
def get_3dcape(wrfin, timeidx=0, method="cat", def get_3dcape(wrfin, timeidx=0, method="cat",
squeeze=True, cache=None, meta=True, squeeze=True, cache=None, meta=True,
_key=None, missing=Constants.DEFAULT_FILL): _key=None, missing=default_fill(np.float64)):
"""Return the three-dimensional CAPE and CIN. """Return the three-dimensional CAPE and CIN.
The leftmost dimension of the returned array represents two different The leftmost dimension of the returned array represents two different
@ -182,7 +182,7 @@ def get_3dcape(wrfin, timeidx=0, method="cat",
purposes only. Default is None. purposes only. Default is None.
missing (:obj:`float`): The fill value to use for the output. missing (:obj:`float`): The fill value to use for the output.
Default is :data:`wrf.Constants.DEFAULT_FILL`. Default is :data:`wrf.default_fill(np.float64)`.
Returns: Returns:
:class:`xarray.DataArray` or :class:`numpy.ndarray`: The :class:`xarray.DataArray` or :class:`numpy.ndarray`: The

164
src/wrf/g_cloudfrac.py

@ -0,0 +1,164 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import numpy as np
import numpy.ma as ma
from .constants import Constants, default_fill
from .extension import _tk, _rh, _cloudfrac
from .metadecorators import set_cloudfrac_metadata
from .util import extract_vars
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)):
"""Return the cloud fraction for low, mid, and high level clouds.
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
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:
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
(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
happens, a fill value will be used in the output.
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.
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.
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
be a :class:`numpy.ndarray` object with no metadata.
"""
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"
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,
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
_high_thresh = 6000. if high_thresh is None else high_thresh
vert_inc_w_height = 1
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)
return ma.masked_values(cfrac, missing)

0
src/wrf/ctt.py → src/wrf/g_ctt.py

0
src/wrf/dbz.py → src/wrf/g_dbz.py

0
src/wrf/dewpoint.py → src/wrf/g_dewpoint.py

154
src/wrf/geoht.py → src/wrf/g_geoht.py

@ -1,6 +1,8 @@
from __future__ import (absolute_import, division, print_function, from __future__ import (absolute_import, division, print_function,
unicode_literals) unicode_literals)
import warnings
from .constants import Constants from .constants import Constants
from .destag import destagger from .destag import destagger
from .decorators import convert_units from .decorators import convert_units
@ -9,7 +11,7 @@ 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, cache=None, meta=True, _key=None,
height=True, msl=True): height=True, msl=True, stag=False):
"""Return the geopotential or geopotential height. """Return the geopotential or geopotential height.
If *height* is False, then geopotential is returned in units of If *height* is False, then geopotential is returned in units of
@ -68,6 +70,9 @@ def _get_geoht(wrfin, timeidx, method="cat", squeeze=True,
geopotential height as Above Ground Level (AGL) by subtracting geopotential height as Above Ground Level (AGL) by subtracting
the terrain height. Default is True. the terrain height. Default is True.
stag (:obj:`bool`, optional): Set to True to use the vertical
staggered grid, rather than the mass grid. Default is False.
Returns: Returns:
:class:`xarray.DataArray` or :class:`numpy.ndarray`: The :class:`xarray.DataArray` or :class:`numpy.ndarray`: The
geopotential or geopotential height. geopotential or geopotential height.
@ -86,7 +91,10 @@ def _get_geoht(wrfin, timeidx, method="cat", squeeze=True,
phb = ph_vars["PHB"] phb = ph_vars["PHB"]
hgt = ph_vars["HGT"] hgt = ph_vars["HGT"]
geopt = ph + phb geopt = ph + phb
if not stag:
geopt_unstag = destagger(geopt, -3) geopt_unstag = destagger(geopt, -3)
else:
geopt_unstag = geopt
else: else:
ght_vars = extract_vars(wrfin, timeidx, ("GHT", "HGT_M"), ght_vars = extract_vars(wrfin, timeidx, ("GHT", "HGT_M"),
method, squeeze, cache, meta=False, method, squeeze, cache, meta=False,
@ -94,6 +102,10 @@ def _get_geoht(wrfin, timeidx, method="cat", squeeze=True,
geopt_unstag = ght_vars["GHT"] * Constants.G geopt_unstag = ght_vars["GHT"] * Constants.G
hgt = ght_vars["HGT_M"] hgt = ght_vars["HGT_M"]
if stag:
warnings.warn("file contains no vertically staggered geopotential "
"height variable, returning unstaggered result "
"instead" )
if height: if height:
if msl: if msl:
return geopt_unstag / Constants.G return geopt_unstag / Constants.G
@ -110,7 +122,7 @@ def _get_geoht(wrfin, timeidx, method="cat", squeeze=True,
return geopt_unstag return geopt_unstag
@set_height_metadata(geopt=True) @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): meta=True, _key=None):
"""Return the geopotential. """Return the geopotential.
@ -171,7 +183,7 @@ def get_geopt(wrfin, timeidx=0, method="cat", squeeze=True, cache=None,
False, True) False, True)
@set_height_metadata(geopt=False) @set_height_metadata(geopt=False, stag=False)
@convert_units("height", "m") @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, cache=None, meta=True, _key=None,
@ -245,3 +257,139 @@ def get_height(wrfin, timeidx=0, method="cat", squeeze=True,
return _get_geoht(wrfin, timeidx, method, squeeze, cache, meta, _key, return _get_geoht(wrfin, timeidx, method, squeeze, cache, meta, _key,
True, msl) 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):
"""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
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.
Returns:
: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
be a :class:`numpy.ndarray` object with no metadata.
"""
return _get_geoht(wrfin, timeidx, method, squeeze, cache, meta, _key,
False, True, stag=True)
@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"):
"""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
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.
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
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
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, msl, stag=True)

0
src/wrf/helicity.py → src/wrf/g_helicity.py

0
src/wrf/latlon.py → src/wrf/g_latlon.py

0
src/wrf/omega.py → src/wrf/g_omega.py

0
src/wrf/precip.py → src/wrf/g_precip.py

0
src/wrf/pressure.py → src/wrf/g_pressure.py

0
src/wrf/pw.py → src/wrf/g_pw.py

0
src/wrf/rh.py → src/wrf/g_rh.py

0
src/wrf/slp.py → src/wrf/g_slp.py

0
src/wrf/temp.py → src/wrf/g_temp.py

0
src/wrf/terrain.py → src/wrf/g_terrain.py

0
src/wrf/times.py → src/wrf/g_times.py

2
src/wrf/uvmet.py → src/wrf/g_uvmet.py

@ -9,7 +9,7 @@ import numpy as np
from .extension import _uvmet from .extension import _uvmet
from .destag import destagger from .destag import destagger
from .constants import Constants from .constants import Constants
from .wind import _calc_wspd_wdir from .g_wind import _calc_wspd_wdir
from .decorators import convert_units from .decorators import convert_units
from .metadecorators import set_wind_metadata from .metadecorators import set_wind_metadata
from .util import extract_vars, extract_global_attrs, either from .util import extract_vars, extract_global_attrs, either

0
src/wrf/vorticity.py → src/wrf/g_vorticity.py

0
src/wrf/wind.py → src/wrf/g_wind.py

78
src/wrf/interp.py

@ -11,16 +11,16 @@ from .metadecorators import set_interp_metadata
from .util import extract_vars, is_staggered, get_id, to_np from .util import extract_vars, is_staggered, get_id, to_np
from .py3compat import py3range from .py3compat import py3range
from .interputils import get_xy, get_xy_z_params, to_xy_coords from .interputils import get_xy, get_xy_z_params, to_xy_coords
from .constants import Constants, ConversionFactors from .constants import Constants, default_fill, ConversionFactors
from .terrain import get_terrain from wrf.g_terrain import get_terrain
from .geoht import get_height from wrf.g_geoht import get_height
from .temp import get_theta, get_temp, get_eth from wrf.g_temp import get_theta, get_temp, get_eth
from .pressure import get_pressure from wrf.g_pressure import get_pressure
# Note: Extension decorator is good enough to handle left dims # Note: Extension decorator is good enough to handle left dims
@set_interp_metadata("horiz") @set_interp_metadata("horiz")
def interplevel(field3d, vert, desiredlev, missing=Constants.DEFAULT_FILL, def interplevel(field3d, vert, desiredlev, missing=default_fill(np.float64),
meta=True): meta=True):
"""Return the three-dimensional field interpolated to a horizontal plane """Return the three-dimensional field interpolated to a horizontal plane
at the specified vertical level. at the specified vertical level.
@ -40,7 +40,7 @@ def interplevel(field3d, vert, desiredlev, missing=Constants.DEFAULT_FILL,
Must be in the same units as the *vert* parameter. Must be in the same units as the *vert* parameter.
missing (:obj:`float`): The fill value to use for the output. missing (:obj:`float`): The fill value to use for the output.
Default is :data:`wrf.Constants.DEFAULT_FILL`. Default is :data:`wrf.default_fill(numpy.float64)`.
meta (:obj:`bool`): Set to False to disable metadata and return meta (:obj:`bool`): Set to False to disable metadata and return
:class:`numpy.ndarray` instead of :class:`numpy.ndarray` instead of
@ -90,8 +90,9 @@ def interplevel(field3d, vert, desiredlev, missing=Constants.DEFAULT_FILL,
@set_interp_metadata("cross") @set_interp_metadata("cross")
def vertcross(field3d, vert, levels=None, missing=Constants.DEFAULT_FILL, def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64),
wrfin=None, timeidx=0, stagger=None, projection=None, wrfin=None, timeidx=0, stagger=None, projection=None,
ll_point=None,
pivot_point=None, angle=None, pivot_point=None, angle=None,
start_point=None, end_point=None, start_point=None, end_point=None,
latlon=False, cache=None, meta=True): latlon=False, cache=None, meta=True):
@ -133,7 +134,7 @@ def vertcross(field3d, vert, levels=None, missing=Constants.DEFAULT_FILL,
Default is None. Default is None.
missing (:obj:`float`): The fill value to use for the output. missing (:obj:`float`): The fill value to use for the output.
Default is :data:`wrf.Constants.DEFAULT_FILL`. Default is :data:`wrf.default_fill(numpy.float64)`.
wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \ wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \
iterable, optional): WRF-ARW NetCDF iterable, optional): WRF-ARW NetCDF
@ -165,6 +166,12 @@ def vertcross(field3d, vert, levels=None, missing=Constants.DEFAULT_FILL,
coordinates, and must be specified if *wrfin* is None. Default coordinates, and must be specified if *wrfin* is None. Default
is None. 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
a sequence of :class:`wrf.CoordPair`. Default is None.
pivot_point (:class:`wrf.CoordPair`, optional): A coordinate pair for pivot_point (:class:`wrf.CoordPair`, optional): A coordinate pair for
the pivot point, which indicates the location through which the pivot point, which indicates the location through which
the plane will pass. Must also specify *angle*. The coordinate the plane will pass. Must also specify *angle*. The coordinate
@ -199,6 +206,15 @@ def vertcross(field3d, vert, levels=None, missing=Constants.DEFAULT_FILL,
horizontal line and include this information in the metadata horizontal line and include this information in the metadata
(if enabled). This can be helpful for plotting. Default is False. (if enabled). This can be helpful for plotting. Default is False.
Note:
Currently, *field3d* must be of type :class:`xarray.DataArray`
and contain coordinate information in order to generate the
latitude and longitude coordinates along the line if
*latlon* is set to True. Otherwise, a warning will be issued,
and the latitude and longitude information will not be
present.
cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) cache (:obj:`dict`, optional): A dictionary of (varname, ndarray)
that can be used to supply pre-extracted NetCDF variables to the that can be used to supply pre-extracted NetCDF variables to the
computational routines. It is primarily used for internal computational routines. It is primarily used for internal
@ -242,7 +258,7 @@ def vertcross(field3d, vert, levels=None, missing=Constants.DEFAULT_FILL,
if pivot_point is not None: if pivot_point is not None:
if pivot_point.lat is not None and pivot_point.lon is not None: if pivot_point.lat is not None and pivot_point.lon is not None:
xy_coords = to_xy_coords(pivot_point, wrfin, timeidx, xy_coords = to_xy_coords(pivot_point, wrfin, timeidx,
stagger, projection) stagger, projection, ll_point)
pivot_point_xy = (xy_coords.x, xy_coords.y) pivot_point_xy = (xy_coords.x, xy_coords.y)
else: else:
pivot_point_xy = (pivot_point.x, pivot_point.y) pivot_point_xy = (pivot_point.x, pivot_point.y)
@ -250,14 +266,14 @@ def vertcross(field3d, vert, levels=None, missing=Constants.DEFAULT_FILL,
if start_point is not None and end_point is not None: if start_point is not None and end_point is not None:
if start_point.lat is not None and start_point.lon is not None: if start_point.lat is not None and start_point.lon is not None:
xy_coords = to_xy_coords(start_point, wrfin, timeidx, xy_coords = to_xy_coords(start_point, wrfin, timeidx,
stagger, projection) stagger, projection, ll_point)
start_point_xy = (xy_coords.x, xy_coords.y) start_point_xy = (xy_coords.x, xy_coords.y)
else: else:
start_point_xy = (start_point.x, start_point.y) start_point_xy = (start_point.x, start_point.y)
if end_point.lat is not None and end_point.lon is not None: if end_point.lat is not None and end_point.lon is not None:
xy_coords = to_xy_coords(end_point, wrfin, timeidx, xy_coords = to_xy_coords(end_point, wrfin, timeidx,
stagger, projection) stagger, projection, ll_point)
end_point_xy = (xy_coords.x, xy_coords.y) end_point_xy = (xy_coords.x, xy_coords.y)
else: else:
end_point_xy = (end_point.x, end_point.y) end_point_xy = (end_point.x, end_point.y)
@ -282,6 +298,7 @@ def vertcross(field3d, vert, levels=None, missing=Constants.DEFAULT_FILL,
@set_interp_metadata("line") @set_interp_metadata("line")
def interpline(field2d, pivot_point=None, def interpline(field2d, pivot_point=None,
wrfin=None, timeidx=0, stagger=None, projection=None, wrfin=None, timeidx=0, stagger=None, projection=None,
ll_point=None,
angle=None, start_point=None, angle=None, start_point=None,
end_point=None, latlon=False, end_point=None, latlon=False,
cache=None, meta=True): cache=None, meta=True):
@ -331,6 +348,12 @@ def interpline(field2d, pivot_point=None,
not be used when working with x,y coordinates. Default not be used when working with x,y coordinates. Default
is None. 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
a sequence of :class:`wrf.CoordPair`. Default is None.
pivot_point (:class:`wrf.CoordPair`, optional): A coordinate pair for pivot_point (:class:`wrf.CoordPair`, optional): A coordinate pair for
the pivot point, which indicates the location through which the pivot point, which indicates the location through which
the plane will pass. Must also specify *angle*. The coordinate the plane will pass. Must also specify *angle*. The coordinate
@ -365,6 +388,15 @@ def interpline(field2d, pivot_point=None,
horizontal line and include this information in the metadata horizontal line and include this information in the metadata
(if enabled). This can be helpful for plotting. Default is False. (if enabled). This can be helpful for plotting. Default is False.
Note:
Currently, *field2d* must be of type :class:`xarray.DataArray`
and contain coordinate information in order to generate the
latitude and longitude coordinates along the line if
*latlon* is set to True. Otherwise, a warning will be issued,
and the latitude and longitude information will not be
present.
cache (:obj:`dict`, optional): A dictionary of (varname, ndarray) cache (:obj:`dict`, optional): A dictionary of (varname, ndarray)
that can be used to supply pre-extracted NetCDF variables to the that can be used to supply pre-extracted NetCDF variables to the
computational routines. It is primarily used for internal computational routines. It is primarily used for internal
@ -402,7 +434,7 @@ def interpline(field2d, pivot_point=None,
if pivot_point is not None: if pivot_point is not None:
if pivot_point.lat is not None and pivot_point.lon is not None: if pivot_point.lat is not None and pivot_point.lon is not None:
xy_coords = to_xy_coords(pivot_point, wrfin, timeidx, xy_coords = to_xy_coords(pivot_point, wrfin, timeidx,
stagger, projection) stagger, projection, ll_point)
pivot_point_xy = (xy_coords.x, xy_coords.y) pivot_point_xy = (xy_coords.x, xy_coords.y)
else: else:
pivot_point_xy = (pivot_point.x, pivot_point.y) pivot_point_xy = (pivot_point.x, pivot_point.y)
@ -410,14 +442,14 @@ def interpline(field2d, pivot_point=None,
if start_point is not None and end_point is not None: if start_point is not None and end_point is not None:
if start_point.lat is not None and start_point.lon is not None: if start_point.lat is not None and start_point.lon is not None:
xy_coords = to_xy_coords(start_point, wrfin, timeidx, xy_coords = to_xy_coords(start_point, wrfin, timeidx,
stagger, projection) stagger, projection, ll_point)
start_point_xy = (xy_coords.x, xy_coords.y) start_point_xy = (xy_coords.x, xy_coords.y)
else: else:
start_point_xy = (start_point.x, start_point.y) start_point_xy = (start_point.x, start_point.y)
if end_point.lat is not None and end_point.lon is not None: if end_point.lat is not None and end_point.lon is not None:
xy_coords = to_xy_coords(end_point, wrfin, timeidx, xy_coords = to_xy_coords(end_point, wrfin, timeidx,
stagger, projection) stagger, projection, ll_point)
end_point_xy = (xy_coords.x, xy_coords.y) end_point_xy = (xy_coords.x, xy_coords.y)
else: else:
end_point_xy = (end_point.x, end_point.y) end_point_xy = (end_point.x, end_point.y)
@ -584,9 +616,6 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False,
terht = get_terrain(wrfin, timeidx, units="m", terht = get_terrain(wrfin, timeidx, units="m",
method=method, squeeze=squeeze, cache=cache, method=method, squeeze=squeeze, cache=cache,
meta=False, _key=_key) meta=False, _key=_key)
t = get_theta(wrfin, timeidx, units="k",
method=method, squeeze=squeeze, cache=cache,
meta=False, _key=_key)
tk = get_temp(wrfin, timeidx, units="k", tk = get_temp(wrfin, timeidx, units="k",
method=method, squeeze=squeeze, cache=cache, method=method, squeeze=squeeze, cache=cache,
meta=False, _key=_key) meta=False, _key=_key)
@ -596,9 +625,6 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False,
ght = get_height(wrfin, timeidx, msl=True, units="m", ght = get_height(wrfin, timeidx, msl=True, units="m",
method=method, squeeze=squeeze, cache=cache, method=method, squeeze=squeeze, cache=cache,
meta=False, _key=_key) meta=False, _key=_key)
ht_agl = get_height(wrfin, timeidx, msl=False, units="m",
method=method, squeeze=squeeze, cache=cache,
meta=False, _key=_key)
smsfp = _smooth2d(sfp, 3) smsfp = _smooth2d(sfp, 3)
@ -613,10 +639,18 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False,
vcord_array = np.exp(-ght/sclht) vcord_array = np.exp(-ght/sclht)
elif vert_coord == "ght_agl": elif vert_coord == "ght_agl":
ht_agl = get_height(wrfin, timeidx, msl=False, units="m",
method=method, squeeze=squeeze, cache=cache,
meta=False, _key=_key)
vcor = 3 vcor = 3
vcord_array = np.exp(-ht_agl/sclht) vcord_array = np.exp(-ht_agl/sclht)
elif vert_coord in ("theta", "th"): elif vert_coord in ("theta", "th"):
t = get_theta(wrfin, timeidx, units="k",
method=method, squeeze=squeeze, cache=cache,
meta=False, _key=_key)
vcor = 4 vcor = 4
idir = 1 idir = 1
icorsw = 0 icorsw = 0
@ -651,7 +685,7 @@ def vinterp(wrfin, field, vert_coord, interp_levels, extrapolate=False,
if isinstance(field, ma.MaskedArray): if isinstance(field, ma.MaskedArray):
missing = field.fill_value missing = field.fill_value
else: else:
missing = Constants.DEFAULT_FILL missing = default_fill(np.float64)
if (field.shape != p.shape): if (field.shape != p.shape):
raise ValueError("'field' shape does not match other variable shapes. " raise ValueError("'field' shape does not match other variable shapes. "

42
src/wrf/interputils.py

@ -2,7 +2,6 @@ from __future__ import (absolute_import, division, print_function,
unicode_literals) unicode_literals)
from math import floor, ceil from math import floor, ceil
from collections import Iterable
import numpy as np import numpy as np
@ -11,6 +10,7 @@ from .py3compat import py3range
from .coordpair import CoordPair from .coordpair import CoordPair
from .constants import Constants, ProjectionTypes from .constants import Constants, ProjectionTypes
from .latlonutils import _ll_to_xy from .latlonutils import _ll_to_xy
from .util import pairs_to_latlon
def to_positive_idxs(shape, coord): def to_positive_idxs(shape, coord):
@ -158,23 +158,24 @@ def _calc_xy(xdim, ydim, pivot_point=None, angle=None,
raise ValueError("end_point {} is outside of domain " raise ValueError("end_point {} is outside of domain "
"with shape {}".format(end_point, (xdim, ydim))) "with shape {}".format(end_point, (xdim, ydim)))
# From the original NCL code, but the error above will be thrown
# instead.
if ( x1 > xdim-1 ): if ( x1 > xdim-1 ):
x1 = xdim x1 = xdim - 1
if ( y1 > ydim-1): if ( y1 > ydim-1):
y1 = ydim y1 = ydim - 1
else: else:
raise ValueError("invalid start/end or pivot/angle arguments") raise ValueError("invalid start/end or pivot/angle arguments")
dx = x1 - x0 dx = x1 - x0
dy = y1 - y0 dy = y1 - y0
distance = (dx*dx + dy*dy)**0.5 distance = (dx*dx + dy*dy)**0.5
npts = int(distance) npts = int(distance) + 1
dxy = distance/npts
xy = np.zeros((npts,2), "float") xy = np.zeros((npts,2), "float")
dx = dx/npts dx = dx/(npts-1)
dy = dy/npts dy = dy/(npts-1)
for i in py3range(npts): for i in py3range(npts):
xy[i,0] = x0 + i*dx xy[i,0] = x0 + i*dx
@ -328,7 +329,8 @@ def get_xy(var, pivot_point=None, angle=None,
return xy return xy
def to_xy_coords(pairs, wrfin=None, timeidx=0, stagger=None, projection=None): def to_xy_coords(pairs, wrfin=None, timeidx=0, stagger=None, projection=None,
ll_point=None):
"""Return the coordinate pairs in grid space. """Return the coordinate pairs in grid space.
This function converts latitude,longitude coordinate pairs to This function converts latitude,longitude coordinate pairs to
@ -371,6 +373,12 @@ def to_xy_coords(pairs, wrfin=None, timeidx=0, stagger=None, projection=None):
coordinates, and must be specified if *wrfin* is None. Default coordinates, and must be specified if *wrfin* is None. Default
is None. 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
a sequence of :class:`wrf.CoordPair`. Default is None.
Returns: Returns:
:class:`wrf.CoordPair` or sequence: The coordinate pair(s) in :class:`wrf.CoordPair` or sequence: The coordinate pair(s) in
@ -378,15 +386,12 @@ def to_xy_coords(pairs, wrfin=None, timeidx=0, stagger=None, projection=None):
""" """
if wrfin is None and projection is None: if (wrfin is None and (projection is None or ll_point is None)):
raise ValueError ("'wrfin' or 'projection' parameter is required") raise ValueError ("'wrfin' parameter or "
"'projection' and 'll_point' parameters "
"are required")
if isinstance(pairs, Iterable): lat, lon = pairs_to_latlon(pairs)
lat = [pair.lat for pair in pairs]
lon = [pair.lon for pair in pairs]
else:
lat = pairs.lat
lon = pairs.lon
if wrfin is not None: if wrfin is not None:
xy_vals = _ll_to_xy(lat, lon, wrfin=wrfin, timeidx=timeidx, xy_vals = _ll_to_xy(lat, lon, wrfin=wrfin, timeidx=timeidx,
@ -408,14 +413,15 @@ def to_xy_coords(pairs, wrfin=None, timeidx=0, stagger=None, projection=None):
latinc = 0.0 latinc = 0.0
loninc = 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, as_int=True,
map_proj=projection.map_proj, map_proj=projection.map_proj,
truelat1=projection.truelat1, truelat1=projection.truelat1,
truelat2=projection.truelat2, truelat2=projection.truelat2,
stand_lon=projection.stand_lon, stand_lon=projection.stand_lon,
ref_lat=projection.ll_lat, ref_lat=ll_lat,
ref_lon=projection.ll_lon, ref_lon=ll_lon,
pole_lat=pole_lat, pole_lat=pole_lat,
pole_lon=pole_lon, pole_lon=pole_lon,
known_x=0, known_x=0,

6
src/wrf/latlonutils.py

@ -242,9 +242,9 @@ def _kwarg_proj_params(**projparams):
if var is None: if var is None:
raise ValueError("'{}' argument required".format(name)) raise ValueError("'{}' argument required".format(name))
# ref_lat and ref_lon are expectd to be lists # ref_lat and ref_lon are expected to be lists
ref_lat = np.asarray([ref_lat]) ref_lat = np.ravel(np.asarray([ref_lat]))
ref_lon = np.asarray([ref_lon]) ref_lon = np.ravel(np.asarray([ref_lon]))
# Fortran wants 1-based indexing # Fortran wants 1-based indexing
known_x = known_x + 1 known_x = known_x + 1

153
src/wrf/metadecorators.py

@ -1,5 +1,6 @@
from __future__ import (absolute_import, division, print_function, from __future__ import (absolute_import, division, print_function,
unicode_literals) unicode_literals)
import warnings
import wrapt import wrapt
from collections import OrderedDict from collections import OrderedDict
@ -322,6 +323,7 @@ def set_wind_metadata(copy_varname, name, description,
return func_wrapper return func_wrapper
def set_cape_metadata(is2d): def set_cape_metadata(is2d):
"""A decorator that sets the metadata for a wrapped CAPE function's output. """A decorator that sets the metadata for a wrapped CAPE function's output.
@ -468,7 +470,9 @@ def set_cloudfrac_metadata():
return wrapped(*args, **kwargs) return wrapped(*args, **kwargs)
argvars = from_args(wrapped, ("wrfin", "timeidx", "method", "squeeze", argvars = from_args(wrapped, ("wrfin", "timeidx", "method", "squeeze",
"cache", "_key"), "cache", "_key", "vert_type",
"low_thresh", "mid_thresh",
"high_thresh", "missing"),
*args, **kwargs) *args, **kwargs)
wrfin = argvars["wrfin"] wrfin = argvars["wrfin"]
timeidx = argvars["timeidx"] timeidx = argvars["timeidx"]
@ -476,6 +480,12 @@ def set_cloudfrac_metadata():
squeeze = argvars["squeeze"] squeeze = argvars["squeeze"]
cache = argvars["cache"] cache = argvars["cache"]
_key = argvars["_key"] _key = argvars["_key"]
vert_type = argvars["vert_type"]
low_thresh = argvars["low_thresh"]
mid_thresh = argvars["mid_thresh"]
high_thresh = argvars["high_thresh"]
missing = argvars["missing"]
if cache is None: if cache is None:
cache = {} cache = {}
@ -499,6 +509,20 @@ def set_cloudfrac_metadata():
outattrs.update(copy_var.attrs) outattrs.update(copy_var.attrs)
outdimnames = [None] * result.ndim outdimnames = [None] * result.ndim
# For printing units
unitstr = ("Pa" if vert_type.lower() == "pres"
or vert_type.lower() == "pressure" else "m")
# For setting the threholds in metdata
if vert_type.lower() == "pres" or vert_type.lower() == "pressure":
_low_thresh = 97000. if low_thresh is None else low_thresh
_mid_thresh = 80000. if mid_thresh is None else mid_thresh
_high_thresh = 45000. if high_thresh is None else high_thresh
elif vert_type.lower() == "height_msl" or "height_agl":
_low_thresh = 300. if low_thresh is None else low_thresh
_mid_thresh = 2000. if mid_thresh is None else mid_thresh
_high_thresh = 6000. if high_thresh is None else high_thresh
# Right dims # Right dims
outdimnames[-2:] = copy_var.dims[-2:] outdimnames[-2:] = copy_var.dims[-2:]
# Left dims # Left dims
@ -507,6 +531,11 @@ def set_cloudfrac_metadata():
outattrs["description"] = "low, mid, high clouds" outattrs["description"] = "low, mid, high clouds"
outattrs["MemoryOrder"] = "XY" outattrs["MemoryOrder"] = "XY"
outattrs["units"] = "%" outattrs["units"] = "%"
outattrs["low_thresh"] = "{} {}".format(_low_thresh, unitstr)
outattrs["mid_thresh"] = "{} {}".format(_mid_thresh, unitstr)
outattrs["high_thresh"] = "{} {}".format(_high_thresh, unitstr)
outattrs["_FillValue"] = missing
outattrs["missing_value"] = missing
outname = "cloudfrac" outname = "cloudfrac"
# xarray doesn't line up coordinate dimensions based on # xarray doesn't line up coordinate dimensions based on
@ -529,6 +558,7 @@ def set_cloudfrac_metadata():
return func_wrapper return func_wrapper
def set_latlon_metadata(xy=False): def set_latlon_metadata(xy=False):
"""A decorator that sets the metadata for a wrapped latlon function's """A decorator that sets the metadata for a wrapped latlon function's
output. output.
@ -614,7 +644,8 @@ def set_latlon_metadata(xy=False):
return func_wrapper return func_wrapper
def set_height_metadata(geopt=False):
def set_height_metadata(geopt=False, stag=False):
"""A decorator that sets the metadata for a wrapped height function's """A decorator that sets the metadata for a wrapped height function's
output. output.
@ -629,6 +660,9 @@ def set_height_metadata(geopt=False):
returns geopotential. Set to True if the wrapped function returns geopotential. Set to True if the wrapped function
returns geopotential height. Default is False. returns geopotential height. Default is False.
stag (:obj:`bool`, optional): Set to True to use the vertical
staggered grid, rather than the mass grid. Default is False.
Returns: Returns:
:class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped :class:`xarray.DataArray` or :class:`numpy.ndarray`: The wrapped
@ -664,9 +698,17 @@ def set_height_metadata(geopt=False):
if cache is None: if cache is None:
cache = {} cache = {}
is_met_em = False
# For height, either copy the met_em GHT variable or copy and modify # For height, either copy the met_em GHT variable or copy and modify
# pressure (which has the same dims as destaggered height) # pressure (which has the same dims as destaggered height)
if not stag:
ht_metadata_varname = either("P", "GHT")(wrfin) ht_metadata_varname = either("P", "GHT")(wrfin)
else:
ht_metadata_varname = either("PH", "GHT")(wrfin)
if ht_metadata_varname == "GHT":
is_met_em = True
ht_var = extract_vars(wrfin, timeidx, ht_metadata_varname, ht_var = extract_vars(wrfin, timeidx, ht_metadata_varname,
method, squeeze, cache, meta=True, method, squeeze, cache, meta=True,
_key=_key) _key=_key)
@ -692,18 +734,28 @@ def set_height_metadata(geopt=False):
if geopt: if geopt:
outname = "geopt" outname = "geopt"
outattrs["units"] = "m2 s-2" outattrs["units"] = "m2 s-2"
outattrs["description"] = "full model geopotential" if not stag or is_met_em:
outattrs["description"] = "geopotential (mass grid)"
else:
outattrs["description"] = ("geopotential (vertically "
"staggered grid)")
else: else:
outname = "height" if msl else "height_agl" outname = "height" if msl else "height_agl"
outattrs["units"] = units outattrs["units"] = units
height_type = "MSL" if msl else "AGL" height_type = "MSL" if msl else "AGL"
outattrs["description"] = "model height ({})".format(height_type) if not stag or is_met_em:
outattrs["description"] = ("model height - [{}] "
"(mass grid)".format(height_type))
else:
outattrs["description"] = ("model height - [{}] (vertically "
"staggered grid)".format(height_type))
return DataArray(result, name=outname, return DataArray(result, name=outname,
dims=outdimnames, coords=outcoords, attrs=outattrs) dims=outdimnames, coords=outcoords, attrs=outattrs)
return func_wrapper return func_wrapper
def _set_horiz_meta(wrapped, instance, args, kwargs): def _set_horiz_meta(wrapped, instance, args, kwargs):
"""A decorator implementation that sets the metadata for a wrapped """A decorator implementation that sets the metadata for a wrapped
horizontal interpolation function. horizontal interpolation function.
@ -753,7 +805,7 @@ def _set_horiz_meta(wrapped, instance, args, kwargs):
outname = None outname = None
outdimnames = None outdimnames = None
outcoords = None outcoords = None
outattrs = None outattrs = OrderedDict()
# Get the vertical level units # Get the vertical level units
vert_units = None vert_units = None
@ -771,7 +823,6 @@ def _set_horiz_meta(wrapped, instance, args, kwargs):
if isinstance(field3d, DataArray): if isinstance(field3d, DataArray):
outcoords = OrderedDict() outcoords = OrderedDict()
outattrs = OrderedDict()
outdimnames = list(field3d.dims) outdimnames = list(field3d.dims)
outcoords.update(field3d.coords) outcoords.update(field3d.coords)
outdimnames.remove(field3d.dims[-3]) outdimnames.remove(field3d.dims[-3])
@ -784,7 +835,6 @@ def _set_horiz_meta(wrapped, instance, args, kwargs):
else: else:
outname = "field3d_{0}".format(name_levelstr) outname = "field3d_{0}".format(name_levelstr)
outattrs = OrderedDict()
outattrs["level"] = levelstr outattrs["level"] = levelstr
outattrs["missing_value"] = missingval outattrs["missing_value"] = missingval
@ -799,6 +849,7 @@ def _set_horiz_meta(wrapped, instance, args, kwargs):
return DataArray(result, name=outname, dims=outdimnames, return DataArray(result, name=outname, dims=outdimnames,
coords=outcoords, attrs=outattrs) coords=outcoords, attrs=outattrs)
def _set_cross_meta(wrapped, instance, args, kwargs): def _set_cross_meta(wrapped, instance, args, kwargs):
"""A decorator implementation that sets the metadata for a wrapped cross \ """A decorator implementation that sets the metadata for a wrapped cross \
section interpolation function. section interpolation function.
@ -836,7 +887,7 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
argvars = from_args(wrapped, ("field3d", "vert", "levels", argvars = from_args(wrapped, ("field3d", "vert", "levels",
"latlon", "missing", "latlon", "missing",
"wrfin", "timeidx", "stagger", "projection", "wrfin", "timeidx", "stagger", "projection",
"pivot_point", "angle", "ll_point", "pivot_point", "angle",
"start_point", "end_point", "start_point", "end_point",
"cache"), "cache"),
*args, **kwargs) *args, **kwargs)
@ -850,6 +901,7 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
timeidx = argvars["timeidx"] timeidx = argvars["timeidx"]
stagger = argvars["stagger"] stagger = argvars["stagger"]
projection = argvars["projection"] projection = argvars["projection"]
ll_point = argvars["ll_point"]
pivot_point = argvars["pivot_point"] pivot_point = argvars["pivot_point"]
angle = argvars["angle"] angle = argvars["angle"]
start_point = argvars["start_point"] start_point = argvars["start_point"]
@ -863,7 +915,7 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
if pivot_point is not None: if pivot_point is not None:
if pivot_point.lat is not None and pivot_point.lon is not None: if pivot_point.lat is not None and pivot_point.lon is not None:
xy_coords = to_xy_coords(pivot_point, wrfin, timeidx, xy_coords = to_xy_coords(pivot_point, wrfin, timeidx,
stagger, projection) stagger, projection, ll_point)
pivot_point_xy = (xy_coords.x, xy_coords.y) pivot_point_xy = (xy_coords.x, xy_coords.y)
else: else:
pivot_point_xy = (pivot_point.x, pivot_point.y) pivot_point_xy = (pivot_point.x, pivot_point.y)
@ -871,14 +923,14 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
if start_point is not None and end_point is not None: if start_point is not None and end_point is not None:
if start_point.lat is not None and start_point.lon is not None: if start_point.lat is not None and start_point.lon is not None:
xy_coords = to_xy_coords(start_point, wrfin, timeidx, xy_coords = to_xy_coords(start_point, wrfin, timeidx,
stagger, projection) stagger, projection, ll_point)
start_point_xy = (xy_coords.x, xy_coords.y) start_point_xy = (xy_coords.x, xy_coords.y)
else: else:
start_point_xy = (start_point.x, start_point.y) start_point_xy = (start_point.x, start_point.y)
if end_point.lat is not None and end_point.lon is not None: if end_point.lat is not None and end_point.lon is not None:
xy_coords = to_xy_coords(end_point, wrfin, timeidx, xy_coords = to_xy_coords(end_point, wrfin, timeidx,
stagger, projection) stagger, projection, ll_point)
end_point_xy = (xy_coords.x, xy_coords.y) end_point_xy = (xy_coords.x, xy_coords.y)
else: else:
end_point_xy = (end_point.x, end_point.y) end_point_xy = (end_point.x, end_point.y)
@ -906,7 +958,7 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
outname = None outname = None
outdimnames = None outdimnames = None
outcoords = None outcoords = None
outattrs = None outattrs = OrderedDict()
# Use XY to set the cross-section metadata # Use XY to set the cross-section metadata
st_x = xy[0,0] st_x = xy[0,0]
@ -921,7 +973,6 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
if isinstance(field3d, DataArray): if isinstance(field3d, DataArray):
outcoords = OrderedDict() outcoords = OrderedDict()
outattrs = OrderedDict()
outdimnames = list(field3d.dims) outdimnames = list(field3d.dims)
outcoords.update(field3d.coords) outcoords.update(field3d.coords)
for i in py3range(-3,0,1): for i in py3range(-3,0,1):
@ -990,6 +1041,8 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
outcoords["xy_loc"] = (loc_dimnames, latlon_loc) outcoords["xy_loc"] = (loc_dimnames, latlon_loc)
else: else:
warnings.warn("'latlon' is set to True, but 'field3d' "
" contains no coordinate information")
outcoords["xy_loc"] = ("cross_line_idx", np.asarray(tuple( outcoords["xy_loc"] = ("cross_line_idx", np.asarray(tuple(
CoordPair(xy[i,0], xy[i,1]) CoordPair(xy[i,0], xy[i,1])
for i in py3range(xy.shape[-2])))) for i in py3range(xy.shape[-2]))))
@ -1002,8 +1055,11 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
outcoords["vertical"] = z_var2d[:] outcoords["vertical"] = z_var2d[:]
else: else:
if inc_latlon:
warnings.warn("'latlon' is set to True, but 'field3d' is "
"not of type xarray.DataArray and contains no "
"coordinate information")
outname = "field3d_cross" outname = "field3d_cross"
outattrs = OrderedDict()
outattrs["orientation"] = cross_str outattrs["orientation"] = cross_str
outattrs["missing_value"] = missingval outattrs["missing_value"] = missingval
@ -1013,7 +1069,6 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
coords=outcoords, attrs=outattrs) coords=outcoords, attrs=outattrs)
def _set_line_meta(wrapped, instance, args, kwargs): def _set_line_meta(wrapped, instance, args, kwargs):
"""A decorator implementation that sets the metadata for a wrapped line """A decorator implementation that sets the metadata for a wrapped line
interpolation function. interpolation function.
@ -1050,7 +1105,7 @@ def _set_line_meta(wrapped, instance, args, kwargs):
""" """
argvars = from_args(wrapped, ("field2d", argvars = from_args(wrapped, ("field2d",
"wrfin", "timeidx", "stagger", "projection", "wrfin", "timeidx", "stagger", "projection",
"pivot_point", "angle", "ll_point", "pivot_point", "angle",
"start_point", "end_point", "latlon", "start_point", "end_point", "latlon",
"cache"), "cache"),
*args, **kwargs) *args, **kwargs)
@ -1060,6 +1115,7 @@ def _set_line_meta(wrapped, instance, args, kwargs):
timeidx = argvars["timeidx"] timeidx = argvars["timeidx"]
stagger = argvars["stagger"] stagger = argvars["stagger"]
projection = argvars["projection"] projection = argvars["projection"]
ll_point = argvars["ll_point"]
pivot_point = argvars["pivot_point"] pivot_point = argvars["pivot_point"]
angle = argvars["angle"] angle = argvars["angle"]
start_point = argvars["start_point"] start_point = argvars["start_point"]
@ -1077,7 +1133,7 @@ def _set_line_meta(wrapped, instance, args, kwargs):
if pivot_point is not None: if pivot_point is not None:
if pivot_point.lat is not None and pivot_point.lon is not None: if pivot_point.lat is not None and pivot_point.lon is not None:
xy_coords = to_xy_coords(pivot_point, wrfin, timeidx, xy_coords = to_xy_coords(pivot_point, wrfin, timeidx,
stagger, projection) stagger, projection, ll_point)
pivot_point_xy = (xy_coords.x, xy_coords.y) pivot_point_xy = (xy_coords.x, xy_coords.y)
else: else:
pivot_point_xy = (pivot_point.x, pivot_point.y) pivot_point_xy = (pivot_point.x, pivot_point.y)
@ -1086,14 +1142,14 @@ def _set_line_meta(wrapped, instance, args, kwargs):
if start_point is not None and end_point is not None: if start_point is not None and end_point is not None:
if start_point.lat is not None and start_point.lon is not None: if start_point.lat is not None and start_point.lon is not None:
xy_coords = to_xy_coords(start_point, wrfin, timeidx, xy_coords = to_xy_coords(start_point, wrfin, timeidx,
stagger, projection) stagger, projection, ll_point)
start_point_xy = (xy_coords.x, xy_coords.y) start_point_xy = (xy_coords.x, xy_coords.y)
else: else:
start_point_xy = (start_point.x, start_point.y) start_point_xy = (start_point.x, start_point.y)
if end_point.lat is not None and end_point.lon is not None: if end_point.lat is not None and end_point.lon is not None:
xy_coords = to_xy_coords(end_point, wrfin, timeidx, xy_coords = to_xy_coords(end_point, wrfin, timeidx,
stagger, projection) stagger, projection, ll_point)
end_point_xy = (xy_coords.x, xy_coords.y) end_point_xy = (xy_coords.x, xy_coords.y)
else: else:
end_point_xy = (end_point.x, end_point.y) end_point_xy = (end_point.x, end_point.y)
@ -1115,7 +1171,7 @@ def _set_line_meta(wrapped, instance, args, kwargs):
outname = None outname = None
outdimnames = None outdimnames = None
outcoords = None outcoords = None
outattrs = None outattrs = OrderedDict()
# Use XY to set the cross-section metadata # Use XY to set the cross-section metadata
st_x = xy[0,0] st_x = xy[0,0]
@ -1130,7 +1186,6 @@ def _set_line_meta(wrapped, instance, args, kwargs):
if isinstance(field2d, DataArray): if isinstance(field2d, DataArray):
outcoords = OrderedDict() outcoords = OrderedDict()
outattrs = OrderedDict()
outdimnames = list(field2d.dims) outdimnames = list(field2d.dims)
outcoords.update(field2d.coords) outcoords.update(field2d.coords)
for i in py3range(-2,0,1): for i in py3range(-2,0,1):
@ -1198,6 +1253,8 @@ def _set_line_meta(wrapped, instance, args, kwargs):
outcoords["xy_loc"] = (loc_dimnames, latlon_loc) outcoords["xy_loc"] = (loc_dimnames, latlon_loc)
else: else:
warnings.warn("'latlon' is set to True, but 'field2d' "
"contains no coordinate information")
outcoords["xy_loc"] = ("line_idx", np.asarray(tuple( outcoords["xy_loc"] = ("line_idx", np.asarray(tuple(
CoordPair(xy[i,0], xy[i,1]) CoordPair(xy[i,0], xy[i,1])
for i in py3range(xy.shape[-2])))) for i in py3range(xy.shape[-2]))))
@ -1208,8 +1265,11 @@ def _set_line_meta(wrapped, instance, args, kwargs):
for i in py3range(xy.shape[-2])))) for i in py3range(xy.shape[-2]))))
else: else:
if inc_latlon:
warnings.warn("'latlon' is set to True, but 'field2d' is "
"not of type xarray.DataArray and contains no "
"coordinate information")
outname = "field2d_line" outname = "field2d_line"
outattrs = OrderedDict()
outattrs["orientation"] = cross_str outattrs["orientation"] = cross_str
@ -1270,12 +1330,11 @@ def _set_vinterp_meta(wrapped, instance, args, kwargs):
outname = None outname = None
outdimnames = None outdimnames = None
outcoords = None outcoords = None
outattrs = None outattrs = OrderedDict()
if isinstance(field, DataArray): if isinstance(field, DataArray):
outcoords = OrderedDict() outcoords = OrderedDict()
outattrs = OrderedDict()
outdimnames = list(field.dims) outdimnames = list(field.dims)
outcoords.update(field.coords) outcoords.update(field.coords)
@ -1288,13 +1347,14 @@ def _set_vinterp_meta(wrapped, instance, args, kwargs):
outdimnames.insert(-2, "interp_level") outdimnames.insert(-2, "interp_level")
outcoords["interp_level"] = interp_levels outcoords["interp_level"] = interp_levels
outattrs.update(field.attrs) outattrs.update(field.attrs)
outattrs["vert_interp_type"] = vert_coord
outname = field.name outname = field.name
else: else:
outname = field_type outname = field_type
outattrs["vert_interp_type"] = vert_coord
return DataArray(result, name=outname, dims=outdimnames, return DataArray(result, name=outname, dims=outdimnames,
coords=outcoords, attrs=outattrs) coords=outcoords, attrs=outattrs)
@ -1338,8 +1398,7 @@ def _set_2dxy_meta(wrapped, instance, args, kwargs):
argvars = from_args(wrapped, ("field3d", "xy"), *args, **kwargs) argvars = from_args(wrapped, ("field3d", "xy"), *args, **kwargs)
field3d = argvars["field3d"] field3d = argvars["field3d"]
xy = argvars["xy"] xy = to_np(argvars["xy"])
xy = to_np(xy)
result = wrapped(*args, **kwargs) result = wrapped(*args, **kwargs)
@ -1355,12 +1414,11 @@ def _set_2dxy_meta(wrapped, instance, args, kwargs):
outname = None outname = None
outdimnames = None outdimnames = None
outcoords = None outcoords = None
outattrs = None outattrs = OrderedDict()
# Dims are (...,xy,z) # Dims are (...,xy,z)
if isinstance(field3d, DataArray): if isinstance(field3d, DataArray):
outcoords = OrderedDict() outcoords = OrderedDict()
outattrs = OrderedDict()
outdimnames = list(field3d.dims) outdimnames = list(field3d.dims)
outcoords.update(field3d.coords) outcoords.update(field3d.coords)
@ -1456,12 +1514,11 @@ def _set_1d_meta(wrapped, instance, args, kwargs):
outname = None outname = None
outdimnames = None outdimnames = None
outcoords = None outcoords = None
outattrs = None outattrs = OrderedDict()
# Dims are (...,xy,z) # Dims are (...,xy,z)
if isinstance(field, DataArray): if isinstance(field, DataArray):
outcoords = OrderedDict() outcoords = OrderedDict()
outattrs = OrderedDict()
outdimnames = list(field.dims) outdimnames = list(field.dims)
outdimnames.pop(-1) outdimnames.pop(-1)
@ -1476,9 +1533,6 @@ def _set_1d_meta(wrapped, instance, args, kwargs):
outname = "{0}_z".format(field.name) outname = "{0}_z".format(field.name)
outcoords["z"] = z_out outcoords["z"] = z_out
outattrs["_FillValue"] = missingval
outattrs["missing_value"] = missingval
desc = field.attrs.get("description", None) desc = field.attrs.get("description", None)
if desc is not None: if desc is not None:
outattrs["description"] = desc outattrs["description"] = desc
@ -1490,6 +1544,8 @@ def _set_1d_meta(wrapped, instance, args, kwargs):
else: else:
outname = "field_z" outname = "field_z"
outattrs["_FillValue"] = missingval
outattrs["missing_value"] = missingval
return DataArray(result, name=outname, dims=outdimnames, return DataArray(result, name=outname, dims=outdimnames,
coords=outcoords, attrs=outattrs) coords=outcoords, attrs=outattrs)
@ -1770,6 +1826,7 @@ def set_alg_metadata(alg_ndims, refvarname,
return func_wrapper return func_wrapper
def set_smooth_metdata(): def set_smooth_metdata():
@wrapt.decorator @wrapt.decorator
def func_wrapper(wrapped, instance, args, kwargs): def func_wrapper(wrapped, instance, args, kwargs):
@ -1994,14 +2051,14 @@ def set_cape_alg_metadata(is2d, copyarg="pres_hpa"):
return func_wrapper return func_wrapper
def set_cloudfrac_alg_metadata(copyarg="pres"): def set_cloudfrac_alg_metadata(copyarg="vert"):
"""A decorator that sets the metadata for the wrapped raw cloud fraction """A decorator that sets the metadata for the wrapped raw cloud fraction
diagnostic function. diagnostic function.
Args: Args:
copyarg (:obj:`str`): The wrapped function argument to use for copyarg (:obj:`str`): The wrapped function argument to use for
copying dimension names. Default is 'pres'. copying dimension names. Default is 'vert'.
Returns: Returns:
@ -2025,6 +2082,16 @@ def set_cloudfrac_alg_metadata(copyarg="pres"):
result = wrapped(*args, **kwargs) result = wrapped(*args, **kwargs)
argvals = from_args(wrapped, (copyarg, "low_thresh",
"mid_thresh", "high_thresh",
"missing"),
*args, **kwargs)
cp = argvals[copyarg]
low_thresh = argvals["low_thresh"]
mid_thresh = argvals["mid_thresh"]
high_thresh = argvals["high_thresh"]
missing = argvals["missing"]
# Default dimension names # Default dimension names
outdims = ["dim_{}".format(i) for i in py3range(result.ndim)] outdims = ["dim_{}".format(i) for i in py3range(result.ndim)]
@ -2034,15 +2101,17 @@ def set_cloudfrac_alg_metadata(copyarg="pres"):
outattrs["description"] = "low, mid, high clouds" outattrs["description"] = "low, mid, high clouds"
outattrs["units"] = "%" outattrs["units"] = "%"
outattrs["MemoryOrder"] = "XY" outattrs["MemoryOrder"] = "XY"
outattrs["low_thresh"] = low_thresh
outattrs["mid_thresh"] = mid_thresh
outattrs["high_thresh"] = high_thresh
outattrs["_FillValue"] = missing
outattrs["missing_value"] = missing
if isinstance(cp, DataArray):
p = from_args(wrapped, copyarg, *args, **kwargs)[copyarg]
if isinstance(p, DataArray):
# Right dims # Right dims
outdims[-2:] = p.dims[-2:] outdims[-2:] = cp.dims[-2:]
# Left dims # Left dims
outdims[1:-2] = p.dims[0:-3] outdims[1:-2] = cp.dims[0:-3]
outcoords = {} outcoords = {}

8
src/wrf/projection.py

@ -575,11 +575,15 @@ class LambertConformal(WrfProj):
if not cartopy_enabled(): if not cartopy_enabled():
return None return None
# Set cutoff to -30 for NH, +30.0 for SH.
cutoff = -30.0 if self.moad_cen_lat >= 0 else 30.0
_cartopy = crs.LambertConformal( _cartopy = crs.LambertConformal(
central_longitude = self.stand_lon, central_longitude = self.stand_lon,
central_latitude = self.moad_cen_lat, central_latitude = self.moad_cen_lat,
standard_parallels = self._std_parallels, standard_parallels = self._std_parallels,
globe = self._globe()) globe = self._globe(),
cutoff = cutoff)
return _cartopy return _cartopy
@ -787,7 +791,7 @@ class PolarStereographic(WrfProj):
return _pyngl return _pyngl
def _basemap(self, **kwargs): def _basemap(self, geobounds, **kwargs):
if not basemap_enabled(): if not basemap_enabled():
return None return None

47
src/wrf/routines.py

@ -3,27 +3,27 @@ from __future__ import (absolute_import, division, print_function,
from .util import (get_iterable, is_standard_wrf_var, extract_vars, viewkeys, from .util import (get_iterable, is_standard_wrf_var, extract_vars, viewkeys,
get_id) get_id)
from .cape import get_2dcape, get_3dcape from .g_cape import get_2dcape, get_3dcape
from .ctt import get_ctt from .g_ctt import get_ctt
from .dbz import get_dbz, get_max_dbz from .g_dbz import get_dbz, get_max_dbz
from .dewpoint import get_dp, get_dp_2m from .g_dewpoint import get_dp, get_dp_2m
from .geoht import get_geopt, get_height from .g_geoht import get_geopt, get_height, get_stag_geopt, get_stag_height
from .helicity import get_srh, get_uh from .g_helicity import get_srh, get_uh
from .latlon import get_lat, get_lon from .g_latlon import get_lat, get_lon
from .omega import get_omega from .g_omega import get_omega
from .pressure import get_pressure, get_pressure_hpa from .g_pressure import get_pressure, get_pressure_hpa
from .pw import get_pw from .g_pw import get_pw
from .rh import get_rh, get_rh_2m from .g_rh import get_rh, get_rh_2m
from .slp import get_slp from .g_slp import get_slp
from .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 .terrain import get_terrain from .g_terrain import get_terrain
from .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_wdir)
from .vorticity import get_avo, get_pvo from .g_vorticity import get_avo, get_pvo
from .wind import (get_destag_wspd_wdir, get_destag_wspd_wdir10, from .g_wind import (get_destag_wspd_wdir, get_destag_wspd_wdir10,
get_u_destag, get_v_destag, get_w_destag) get_u_destag, get_v_destag, get_w_destag)
from .times import get_times from .g_times import get_times
from .cloudfrac import get_cloudfrac from .g_cloudfrac import get_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
@ -68,7 +68,9 @@ _FUNC_MAP = {"cape2d" : get_2dcape,
"uvmet_wspd_wdir" : get_uvmet_wspd_wdir, "uvmet_wspd_wdir" : get_uvmet_wspd_wdir,
"uvmet10_wspd_wdir" : get_uvmet10_wspd_wdir, "uvmet10_wspd_wdir" : get_uvmet10_wspd_wdir,
"ctt" : get_ctt, "ctt" : get_ctt,
"cloudfrac" : get_cloudfrac "cloudfrac" : get_cloudfrac,
"geopt_stag" : get_stag_geopt,
"zstag" : get_stag_height
} }
_VALID_KARGS = {"cape2d" : ["missing"], _VALID_KARGS = {"cape2d" : ["missing"],
@ -111,7 +113,10 @@ _VALID_KARGS = {"cape2d" : ["missing"],
"uvmet_wspd_wdir" : ["units"], "uvmet_wspd_wdir" : ["units"],
"uvmet10_wspd_wdir" : ["units"], "uvmet10_wspd_wdir" : ["units"],
"ctt" : [], "ctt" : [],
"cloudfrac" : [], "cloudfrac" : ["vert_type", "low_thresh",
"mid_thresh", "high_thresh"],
"geopt_stag" : [],
"zstag" : ["msl", "units"],
"default" : [] "default" : []
} }

54
src/wrf/specialdec.py

@ -7,7 +7,7 @@ import wrapt
from .util import iter_left_indexes, to_np from .util import iter_left_indexes, to_np
from .config import xarray_enabled from .config import xarray_enabled
from .constants import Constants from .constants import default_fill
if xarray_enabled(): if xarray_enabled():
from xarray import DataArray from xarray import DataArray
@ -74,12 +74,12 @@ def uvmet_left_iter(alg_dtype=np.float64):
v_arr = to_np(v) v_arr = to_np(v)
umissing = Constants.DEFAULT_FILL umissing = default_fill(np.float64)
if isinstance(u_arr, np.ma.MaskedArray): if isinstance(u_arr, np.ma.MaskedArray):
has_missing = True has_missing = True
umissing = u_arr.fill_value umissing = u_arr.fill_value
vmissing = Constants.DEFAULT_FILL vmissing = default_fill(np.float64)
if isinstance(v_arr, np.ma.MaskedArray): if isinstance(v_arr, np.ma.MaskedArray):
has_missing = True has_missing = True
vmissing = v_arr.fill_value vmissing = v_arr.fill_value
@ -383,6 +383,7 @@ def cape_left_iter(alg_dtype=np.float64):
return func_wrapper return func_wrapper
def cloudfrac_left_iter(alg_dtype=np.float64): 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. cloud fraction diagnostic.
@ -409,72 +410,71 @@ def cloudfrac_left_iter(alg_dtype=np.float64):
""" """
@wrapt.decorator @wrapt.decorator
def func_wrapper(wrapped, instance, args, kwargs): def func_wrapper(wrapped, instance, args, kwargs):
# The cape calculations use an ascending vertical pressure coordinate
new_args = list(args) new_args = list(args)
new_kwargs = dict(kwargs) new_kwargs = dict(kwargs)
p = args[0] vert = args[0]
rh = args[1] rh = args[1]
num_left_dims = p.ndim - 3 num_left_dims = vert.ndim - 3
orig_dtype = p.dtype orig_dtype = vert.dtype
# No special left side iteration, build the output from the cape,cin # No special left side iteration, build the output from the
# result # low, mid, high results.
if (num_left_dims == 0): if (num_left_dims == 0):
low, med, high = wrapped(*new_args, **new_kwargs) low, mid, high = wrapped(*new_args, **new_kwargs)
output_dims = (3,) output_dims = (3,)
output_dims += p.shape[-2:] output_dims += vert.shape[-2:]
output = np.empty(output_dims, orig_dtype) output = np.empty(output_dims, orig_dtype)
output[0,:] = low[:] output[0,:] = low[:]
output[1,:] = med[:] output[1,:] = mid[:]
output[2,:] = high[:] output[2,:] = high[:]
return output return output
# Initial output is ...,cape_cin,nz,ny,nx to create contiguous views # Initial output is ...,low_mid_high,nz,ny,nx to create contiguous views
outdims = p.shape[0:num_left_dims] outdims = vert.shape[0:num_left_dims]
extra_dims = tuple(outdims) # Copy the left-most dims for iteration extra_dims = tuple(outdims) # Copy the left-most dims for iteration
outdims += (3,) # low_mid_high outdims += (3,) # low_mid_high
outdims += p.shape[-2:] outdims += vert.shape[-2:]
outview_array = np.empty(outdims, alg_dtype) outview_array = np.empty(outdims, alg_dtype)
# Create the output array where the leftmost dim is the cloud type # Create the output array where the leftmost dim is the cloud type
output_dims = (3,) output_dims = (3,)
output_dims += extra_dims output_dims += extra_dims
output_dims += p.shape[-2:] output_dims += vert.shape[-2:]
output = np.empty(output_dims, orig_dtype) output = np.empty(output_dims, orig_dtype)
has_missing = False has_missing = False
missing = Constants.DEFAULT_FILL missing = default_fill(np.float64)
for left_idxs in iter_left_indexes(extra_dims): for left_idxs in iter_left_indexes(extra_dims):
left_and_slice_idxs = left_idxs + (slice(None),) left_and_slice_idxs = left_idxs + (slice(None),)
low_idxs = left_idxs + (0, slice(None)) low_idxs = left_idxs + (0, slice(None))
med_idxs = left_idxs + (1, slice(None)) mid_idxs = left_idxs + (1, slice(None))
high_idxs = left_idxs + (2, slice(None)) high_idxs = left_idxs + (2, slice(None))
low_output_idxs = (0,) + left_idxs + (slice(None),) low_output_idxs = (0,) + left_idxs + (slice(None),)
med_output_idxs = (1,) + left_idxs + (slice(None),) mid_output_idxs = (1,) + left_idxs + (slice(None),)
high_output_idxs = (2,) + left_idxs + (slice(None),) high_output_idxs = (2,) + left_idxs + (slice(None),)
new_args[0] = p[left_and_slice_idxs] new_args[0] = vert[left_and_slice_idxs]
new_args[1] = rh[left_and_slice_idxs] new_args[1] = rh[left_and_slice_idxs]
# Skip the possible empty/missing arrays for the join method # 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 cloudfrac.py or computation.py, so only
# supply the fill values here. # supply the fill values here.
skip_missing = False skip_missing = False
for arg in (new_args[0:2]): for arg in (new_args[0:2]):
if isinstance(arg, np.ma.MaskedArray): if isinstance(arg, np.ma.MaskedArray):
if arg.mask.all(): if arg.mask.all():
output[low_output_idxs] = missing output[low_output_idxs] = missing
output[med_output_idxs] = missing output[mid_output_idxs] = missing
output[high_output_idxs] = missing output[high_output_idxs] = missing
skip_missing = True skip_missing = True
@ -484,14 +484,14 @@ def cloudfrac_left_iter(alg_dtype=np.float64):
continue continue
lowview = outview_array[low_idxs] lowview = outview_array[low_idxs]
medview = outview_array[med_idxs] midview = outview_array[mid_idxs]
highview = outview_array[high_idxs] highview = outview_array[high_idxs]
new_kwargs["lowview"] = lowview new_kwargs["lowview"] = lowview
new_kwargs["medview"] = medview new_kwargs["midview"] = midview
new_kwargs["highview"] = highview new_kwargs["highview"] = highview
low, med, high = wrapped(*new_args, **new_kwargs) 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 # Can delete this once everything works
@ -501,8 +501,8 @@ def cloudfrac_left_iter(alg_dtype=np.float64):
output[low_output_idxs] = ( output[low_output_idxs] = (
outview_array[low_idxs].astype(orig_dtype)) outview_array[low_idxs].astype(orig_dtype))
output[med_output_idxs] = ( output[mid_output_idxs] = (
outview_array[med_idxs].astype(orig_dtype)) outview_array[mid_idxs].astype(orig_dtype))
output[high_output_idxs] = ( output[high_output_idxs] = (
outview_array[high_idxs].astype(orig_dtype)) outview_array[high_idxs].astype(orig_dtype))

286
src/wrf/util.py

@ -30,16 +30,16 @@ import numpy as np
import numpy.ma as ma import numpy.ma as ma
from .config import xarray_enabled from .config import xarray_enabled
from .constants import Constants, ALL_TIMES from .constants import default_fill, ALL_TIMES
from .py3compat import (viewitems, viewkeys, isstr, py3range, ucode) from .py3compat import (viewitems, viewkeys, isstr, py3range, ucode)
from .cache import cache_item, get_cached_item from .cache import cache_item, get_cached_item
from .geobnds import GeoBounds, NullGeoBounds from .geobnds import GeoBounds, NullGeoBounds
from .coordpair import CoordPair
from .projection import getproj from .projection import getproj
if xarray_enabled(): if xarray_enabled():
from xarray import DataArray from xarray import DataArray
from pandas import NaT
_COORD_PAIR_MAP = {"XLAT" : ("XLAT", "XLONG"), _COORD_PAIR_MAP = {"XLAT" : ("XLAT", "XLONG"),
@ -209,10 +209,29 @@ def _generator_copy(gen):
module = getmodule(gen.gi_frame) module = getmodule(gen.gi_frame)
if module is not None: if module is not None:
try:
try:
argd = {key:argvals.locals[key] for key in argvals.args}
res = module.get(funcname)(**argd)
except AttributeError:
res = getattr(module, funcname)(**argd)
except:
# This is the old way it used to work, but it looks like this was
# fixed by Python.
try:
res = module.get(funcname)(**argvals.locals) res = module.get(funcname)(**argvals.locals)
except AttributeError:
res = getattr(module, funcname)(**argvals.locals)
else: else:
# Created in jupyter or the python interpreter # Created in jupyter or the python interpreter
import __main__ import __main__
try:
argd = {key:argvals.locals[key] for key in argvals.args}
res = getattr(__main__, funcname)(**argd)
except:
# This was the old way it used to work, but appears to have
# been fixed by Python.
res = getattr(__main__, funcname)(**argvals.locals) res = getattr(__main__, funcname)(**argvals.locals)
return res return res
@ -727,8 +746,12 @@ def is_moving_domain(wrfin, varname=None, latvar=either("XLAT", "XLAT_M"),
# to be a shortcut in the netcdf files. # to be a shortcut in the netcdf files.
if varname is not None: if varname is not None:
try: try:
coord_names = getattr(first_wrfnc.variables[varname], coord_str = getattr(first_wrfnc.variables[varname], "coordinates")
"coordinates").split() # scipy.io.netcdf stores attributes as bytes rather than str
if isinstance(coord_str, str):
coord_names = coord_str.split()
else:
coord_names = coord_str.decode().split()
except AttributeError: except AttributeError:
# Variable doesn't have a coordinates attribute, use the # Variable doesn't have a coordinates attribute, use the
# arguments # arguments
@ -878,7 +901,17 @@ def extract_dim(wrfin, dim):
d = wrfin.dimensions[dim] d = wrfin.dimensions[dim]
if not isinstance(d, int): if not isinstance(d, int):
try:
return len(d) #netCDF4 return len(d) #netCDF4
except TypeError: #scipy.io.netcdf
# Scipy can't handled unlimited dimensions, so now we have to
# figure it out
try:
s = wrfin.variables["P"].shape
return s[-4]
except:
raise ValueError("unsupported NetCDF reader")
return d # PyNIO return d # PyNIO
@ -1078,6 +1111,7 @@ def _find_max_time_size(wrfseq):
return max_times return max_times
def _get_coord_names(wrfin, varname): def _get_coord_names(wrfin, varname):
# Need only the first real file # Need only the first real file
@ -1117,17 +1151,34 @@ def _get_coord_names(wrfin, varname):
time_coord = None time_coord = None
else: else:
try: try:
# met_em files # met_em files or old WRF files
stag_attr = getattr(var, "stagger") stag_attr = getattr(var, "stagger")
except AttributeError: except AttributeError:
lon_coord = None lon_coord = None
lat_coord = None lat_coord = None
# Let's just check for xlat and xlong in this case
if "XLAT" in wrfnc.variables:
lat_coord = "XLAT"
lon_coord = "XLONG"
else: else:
# For met_em files, use the stagger name to get the lat/lon var # For met_em files, use the stagger name to get the lat/lon var
lat_coord = "XLAT_{}".format(stag_attr) lat_coord = "XLAT_{}".format(stag_attr)
lon_coord = "XLONG_{}".format(stag_attr) lon_coord = "XLONG_{}".format(stag_attr)
# If this coord name is missing, it might be an old WRF file
if lat_coord not in wrfnc.variables:
lat_coord = None
lon_coord = None
if "XLAT" in wrfnc.variables:
lat_coord = "XLAT"
lon_coord = "XLONG"
else: else:
if isinstance(coord_attr, str):
coord_names = coord_attr.split() coord_names = coord_attr.split()
else:
coord_names = coord_attr.decode().split()
lon_coord = coord_names[0] lon_coord = coord_names[0]
lat_coord = coord_names[1] lat_coord = coord_names[1]
@ -1186,16 +1237,46 @@ def _build_data_array(wrfnc, varname, timeidx, is_moving_domain, is_multifile,
multitime = is_multi_time_req(timeidx) multitime = is_multi_time_req(timeidx)
time_idx_or_slice = timeidx if not multitime else slice(None) time_idx_or_slice = timeidx if not multitime else slice(None)
var = wrfnc.variables[varname] var = wrfnc.variables[varname]
if len(var.shape) > 1:
data = var[time_idx_or_slice, :] data = var[time_idx_or_slice, :]
else:
data = var[time_idx_or_slice]
# Want to preserve the time dimension # Want to preserve the time dimension
if not multitime: if not multitime:
if len(var.shape) > 1:
data = data[np.newaxis, :] data = data[np.newaxis, :]
else:
data = data[np.newaxis]
attrs = OrderedDict()
for dkey, val in viewitems(var.__dict__):
# scipy.io adds these but don't want them
if dkey in ("data", "_shape", "_size", "_typecode", "_attributes",
"maskandscale", "dimensions"):
continue
_dkey = dkey if isinstance(dkey, str) else dkey.decode()
if isstr(val):
_val = val
else:
if isinstance(val, bytes):
_val = val.decode() # scipy.io.netcdf
else:
_val = val
attrs[_dkey] = _val
attrs = OrderedDict(var.__dict__)
dimnames = var.dimensions[-data.ndim:] dimnames = var.dimensions[-data.ndim:]
lat_coord = lon_coord = time_coord = None
try:
if dimnames[-2] == "south_north" and dimnames[-1] == "west_east":
lat_coord, lon_coord, time_coord = _get_coord_names(wrfnc, varname) lat_coord, lon_coord, time_coord = _get_coord_names(wrfnc, varname)
except IndexError:
pass
coords = OrderedDict() coords = OrderedDict()
@ -1278,7 +1359,6 @@ def _build_data_array(wrfnc, varname, timeidx, is_moving_domain, is_multifile,
proj = getproj(**proj_params) proj = getproj(**proj_params)
attrs["projection"] = proj attrs["projection"] = proj
if dimnames[0] == "Time": if dimnames[0] == "Time":
t = extract_times(wrfnc, timeidx, meta=False, do_xtime=False) t = extract_times(wrfnc, timeidx, meta=False, do_xtime=False)
if not multitime: if not multitime:
@ -1341,8 +1421,13 @@ def _find_forward(wrfseq, varname, timeidx, is_moving, meta, _key):
return _build_data_array(wrfnc, varname, filetimeidx, return _build_data_array(wrfnc, varname, filetimeidx,
is_moving, True, _key) is_moving, True, _key)
else: else:
result = wrfnc.variables[varname][filetimeidx, :] var = wrfnc.variables[varname]
if len(var.shape) > 1:
result = var[filetimeidx, :]
return result[np.newaxis, :] # So that nosqueeze works return result[np.newaxis, :] # So that nosqueeze works
else:
result = var[filetimeidx]
return result[np.newaxis] # So that nosqueeze works
else: else:
comboidx += numtimes comboidx += numtimes
@ -1541,7 +1626,10 @@ def _cat_files(wrfseq, varname, timeidx, is_moving, squeeze, meta, _key):
startidx = 0 startidx = 0
endidx = numtimes endidx = numtimes
if first_var.ndim > 1:
outdata[startidx:endidx, :] = first_var[:] outdata[startidx:endidx, :] = first_var[:]
else:
outdata[startidx:endidx] = first_var[:]
if xarray_enabled() and meta: if xarray_enabled() and meta:
latname, lonname, timename = _find_coord_names(first_var.coords) latname, lonname, timename = _find_coord_names(first_var.coords)
@ -1600,7 +1688,10 @@ def _cat_files(wrfseq, varname, timeidx, is_moving, squeeze, meta, _key):
endidx = startidx + numtimes endidx = startidx + numtimes
if vardata.ndim > 1:
outdata[startidx:endidx, :] = vardata[:] outdata[startidx:endidx, :] = vardata[:]
else:
outdata[startidx:endidx] = vardata[:]
if xarray_enabled() and meta: if xarray_enabled() and meta:
if timename is not None and not timecached: if timename is not None and not timecached:
@ -1762,7 +1853,8 @@ def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key):
if xarray_enabled() and meta: if xarray_enabled() and meta:
first_var = _build_data_array(wrfnc, varname, ALL_TIMES, is_moving, first_var = _build_data_array(wrfnc, varname, ALL_TIMES, is_moving,
True, _key) True, _key)
time_coord = np.full((numfiles, maxtimes), int(NaT), "datetime64[ns]") time_coord = np.full((numfiles, maxtimes), np.datetime64("NaT"),
"datetime64[ns]")
time_coord[file_idx, 0:numtimes] = first_var.coords["Time"][:] time_coord[file_idx, 0:numtimes] = first_var.coords["Time"][:]
else: else:
first_var = wrfnc.variables[varname][:] first_var = wrfnc.variables[varname][:]
@ -1777,8 +1869,11 @@ def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key):
outdims += first_var.shape[1:] outdims += first_var.shape[1:]
# For join, always need to start with full masked values # For join, always need to start with full masked values
outdata = np.full(outdims, Constants.DEFAULT_FILL, first_var.dtype) outdata = np.full(outdims, default_fill(first_var.dtype), first_var.dtype)
if first_var.ndim > 1:
outdata[file_idx, 0:numtimes, :] = first_var[:] outdata[file_idx, 0:numtimes, :] = first_var[:]
else:
outdata[file_idx, 0:numtimes] = first_var[:]
# Create the secondary coordinate arrays # Create the secondary coordinate arrays
if xarray_enabled() and meta: if xarray_enabled() and meta:
@ -1800,7 +1895,8 @@ def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key):
if timename is not None: if timename is not None:
outxtimes = get_cached_item(_key, timekey) outxtimes = get_cached_item(_key, timekey)
if outxtimes is None: if outxtimes is None:
outxtimes = np.full(outdims[0:2], Constants.DEFAULT_FILL, outxtimes = np.full(outdims[0:2],
default_fill(first_var.dtype),
first_var.dtype) first_var.dtype)
outxtimes[file_idx, 0:numtimes] = first_var.coords[timename][:] outxtimes[file_idx, 0:numtimes] = first_var.coords[timename][:]
else: else:
@ -1810,7 +1906,8 @@ def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key):
if latname is not None: if latname is not None:
outlats = get_cached_item(_key, latkey) outlats = get_cached_item(_key, latkey)
if outlats is None: if outlats is None:
outlats = np.full(outcoorddims, Constants.DEFAULT_FILL, outlats = np.full(outcoorddims,
default_fill(first_var.dtype),
first_var.dtype) first_var.dtype)
outlats[file_idx, 0:numtimes, :] = ( outlats[file_idx, 0:numtimes, :] = (
first_var.coords[latname][:]) first_var.coords[latname][:])
@ -1820,7 +1917,8 @@ def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key):
if lonname is not None: if lonname is not None:
outlons = get_cached_item(_key, lonkey) outlons = get_cached_item(_key, lonkey)
if outlons is None: if outlons is None:
outlons = np.full(outcoorddims, Constants.DEFAULT_FILL, outlons = np.full(outcoorddims,
default_fill(first_var.dtype),
first_var.dtype) first_var.dtype)
outlons[file_idx, 0:numtimes, :] = ( outlons[file_idx, 0:numtimes, :] = (
first_var.coords[lonname][:]) first_var.coords[lonname][:])
@ -1842,7 +1940,10 @@ def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key):
if not multitime: if not multitime:
outvar = outvar[np.newaxis, :] outvar = outvar[np.newaxis, :]
if outvar.ndim > 1:
outdata[file_idx, 0:numtimes, :] = outvar[:] outdata[file_idx, 0:numtimes, :] = outvar[:]
else:
outdata[file_idx, 0:numtimes] = outvar[:]
if xarray_enabled() and meta: if xarray_enabled() and meta:
# For join, the times are a function of fileidx # For join, the times are a function of fileidx
@ -1871,7 +1972,7 @@ def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key):
# then a mask array is needed to flag all the missing arrays with # then a mask array is needed to flag all the missing arrays with
# missing values # missing values
if file_times_less_than_max: if file_times_less_than_max:
outdata = np.ma.masked_values(outdata, Constants.DEFAULT_FILL) outdata = np.ma.masked_values(outdata, default_fill(outdata.dtype))
if xarray_enabled() and meta: if xarray_enabled() and meta:
# Cache the coords if applicable # Cache the coords if applicable
@ -1898,8 +1999,8 @@ def _join_files(wrfseq, varname, timeidx, is_moving, meta, _key):
outcoords["datetime"] = outdimnames[0:2], time_coord outcoords["datetime"] = outdimnames[0:2], time_coord
if isinstance(outdata, np.ma.MaskedArray): if isinstance(outdata, np.ma.MaskedArray):
outattrs["_FillValue"] = Constants.DEFAULT_FILL outattrs["_FillValue"] = default_fill(outdata.dtype)
outattrs["missing_value"] = Constants.DEFAULT_FILL outattrs["missing_value"] = default_fill(outdata.dtype)
if timename is not None: if timename is not None:
outxtimes = outxtimes[:, time_idx_or_slice] outxtimes = outxtimes[:, time_idx_or_slice]
@ -2133,9 +2234,6 @@ def extract_vars(wrfin, timeidx, varnames, method="cat", squeeze=True,
:data:`wrf.ALL_TIMES` (an alias for None) to return :data:`wrf.ALL_TIMES` (an alias for None) to return
all times in the file or sequence. The default is 0. all times in the file or sequence. The default is 0.
is_moving (:obj:`bool`): A boolean type that indicates if the
sequence is a moving nest.
method (:obj:`str`, optional): The aggregation method to use for method (:obj:`str`, optional): The aggregation method to use for
sequences. Must be either 'cat' or 'join'. sequences. Must be either 'cat' or 'join'.
'cat' combines the data along the Time dimension. 'cat' combines the data along the Time dimension.
@ -2345,15 +2443,35 @@ def extract_times(wrfin, timeidx, method="cat", squeeze=True, cache=None,
else: else:
wrf_list = wrfin wrf_list = wrfin
dt = "datetime64[ns]" if not do_xtime else np.float64
fill_value = (np.datetime64('NaT') if not do_xtime else
default_fill(np.float64))
try: try:
if method.lower() == "cat": if method.lower() == "cat":
time_list = [file_time time_list = [file_time
for wrf_file in wrf_list for wrf_file in wrf_list
for file_time in _file_times(wrf_file, do_xtime)] for file_time in _file_times(wrf_file, do_xtime)]
time_arr = np.asarray(time_list, dtype=dt)
elif method.lower() == "join": elif method.lower() == "join":
time_list = [[file_time time_list = [[file_time
for file_time in _file_times(wrf_file, do_xtime)] for file_time in _file_times(wrf_file, do_xtime)]
for wrf_file in wrf_list] for wrf_file in wrf_list]
num_rows = len(time_list)
num_cols = len(time_list[0])
time_arr = np.full((num_rows, num_cols), fill_value, dtype=dt)
for i,row in enumerate(time_list):
if len(row) == num_cols:
time_arr[i,:] = row[:]
else:
for j,val in enumerate(row):
time_arr[i,j] = val
time_arr = ma.masked_values(time_arr, fill_value)
else: else:
raise ValueError("invalid method argument '{}'".format(method)) raise ValueError("invalid method argument '{}'".format(method))
except KeyError: except KeyError:
@ -2367,6 +2485,8 @@ def extract_times(wrfin, timeidx, method="cat", squeeze=True, cache=None,
outdimnames = ["Time"] outdimnames = ["Time"]
else: else:
outdimnames = ["fileidx", "Time"] outdimnames = ["fileidx", "Time"]
outattrs["missing_value"] = fill_value
outattrs["_FillValue"] = fill_value
if not do_xtime: if not do_xtime:
outname = "times" outname = "times"
@ -2379,11 +2499,12 @@ def extract_times(wrfin, timeidx, method="cat", squeeze=True, cache=None,
outname = "XTIME" outname = "XTIME"
outarr = DataArray(time_list, name=outname, coords=outcoords,
outarr = DataArray(time_arr, name=outname, coords=outcoords,
dims=outdimnames, attrs=outattrs) dims=outdimnames, attrs=outattrs)
else: else:
outarr = np.asarray(time_list, dtype="datetime64[ns]") outarr = time_arr
if not multitime: if not multitime:
return outarr[timeidx] return outarr[timeidx]
@ -2569,26 +2690,6 @@ def get_proj_params(wrfin):#, timeidx=0, varname=None):
"DX", "DY")) "DX", "DY"))
return proj_params return proj_params
# multitime = is_multi_time_req(timeidx)
# if not multitime:
# time_idx_or_slice = timeidx
# else:
# time_idx_or_slice = slice(None)
#
# if varname is not None:
# if not is_coordvar(varname):
# coord_names = getattr(wrfin.variables[varname],
# "coordinates").split()
# lon_coord = coord_names[0]
# lat_coord = coord_names[1]
# else:
# lat_coord, lon_coord = get_coord_pairs(varname)
# else:
# lat_coord, lon_coord = latlon_coordvars(wrfin.variables)
#
# return (wrfin.variables[lat_coord][time_idx_or_slice,:],
# wrfin.variables[lon_coord][time_idx_or_slice,:],
# proj_params)
def from_args(func, argnames, *args, **kwargs): def from_args(func, argnames, *args, **kwargs):
@ -2922,18 +3023,40 @@ def psafilepath():
return os.path.join(os.path.dirname(__file__), "data", "psadilookup.dat") return os.path.join(os.path.dirname(__file__), "data", "psadilookup.dat")
def get_id(obj): def get_filepath(obj):
"""Return the object id.
try:
path = obj.filepath()
except AttributeError:
try:
path = obj.file.path
except:
# Let's make up a filename from the first file time
found = False
times = extract_times(obj, None, meta=False, do_xtime=False)
for t in times:
path = "wrfout_{}".format(str(t))
found = True
break
if not found:
raise ValueError("file contains no path information")
return path
def get_id(obj, prefix=''):
"""Return the cache id.
The object id is used as a caching key for various routines. If the The cache id is used as a caching key for various routines. If the
object type is a mapping, then the result will also be a object type is a mapping, then the result will also be a
mapping of each key to the object id for the value. Otherwise, only the mapping of each key to the object id for the value.
object id is returned.
Args: Args:
obj (:obj:`object`): Any object type. obj (:obj:`object`): Any object type.
prefix (:obj:`str`): A string to help with recursive calls.
Returns: Returns:
:obj:`int` or :obj:`dict`: If the *obj* parameter is not a mapping, :obj:`int` or :obj:`dict`: If the *obj* parameter is not a mapping,
@ -2941,12 +3064,18 @@ def get_id(obj):
key to the object id for the value is returned. key to the object id for the value is returned.
""" """
if not is_multi_file(obj):
return hash(prefix + get_filepath(obj))
# For sequences, the hashing string will be the list ID and the
# path for the first file in the sequence
if not is_mapping(obj): if not is_mapping(obj):
return id(obj) _next = next(iter(obj))
return get_id(_next, prefix + str(id(obj)))
# For each key in the mapping, recursively call get_id until # For each key in the mapping, recursively call get_id until
# until a non-mapping is found # until a non-mapping is found
return {key : get_id(val) for key,val in viewitems(obj)} return {key : get_id(val, prefix) for key,val in viewitems(obj)}
def geo_bounds(var=None, wrfin=None, varname=None, timeidx=0, method="cat", def geo_bounds(var=None, wrfin=None, varname=None, timeidx=0, method="cat",
@ -3685,7 +3814,68 @@ def cartopy_ylim(var=None, geobounds=None, wrfin=None, varname=None, timeidx=0,
return wrf_proj.cartopy_ylim(native_geobnds) return wrf_proj.cartopy_ylim(native_geobnds)
def ll_points(lat, lon):
"""Return the lower left latitude and longitude point(s).
This functions extracts the lower left corner points and returns the result
as either a single :class:`CoordPair` object, or a list of
:class:`CoordPair` objects.
This is primarily used for testing or constructing the corner point objects
from the XLAT and XLONG variables.
Args:
lat (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The latitude
array. Must be at least two dimensions.
lon (:class:`xarray.DataArray` or :class:`numpy.ndarray`): The
longitude array. Must be at least two dimensions.
Returns:
:class:`wrf.CoordPair` or :obj:`list`: A single :class:`wrf.CoordPair`
object or a list of :class:`wrf.CoordPair` objects.
"""
latvals = np.ravel(to_np(lat)[...,0,0])
lonvals = np.ravel(to_np(lon)[...,0,0])
if latvals.shape[0] == 1:
return CoordPair(lat=float(latvals), lon=float(lonvals))
else:
return [CoordPair(lat=latvals[i], lon=lonvals[i])
for i in py3range(latvals.shape[0])]
def pairs_to_latlon(pairs):
"""Return latitude and longitude arrays from a sequence of \
:class:`wrf.CoordPair` objects.
This function converts a sequence of :class:`wrf.CoordPair` objects into
lists of latitude and longitude points. If the *pairs* argument is a
single :class:`wrf.CoordPair` object, then a single latitude and
longitude value is returned.
Args:
pairs (:class:`wrf.CoordPair` or sequence): A single
:class:`wrf.CoordPair` or sequence of :class:`wrf.CoordPair`.
Returns:
:obj:`tuple`: A tuple of (lat, lon), where lat and lon are single
values or lists of values.
"""
if isinstance(pairs, CoordPair):
return (pairs.lat, pairs.lon)
else:
lats = [pair.lat for pair in pairs]
lons = [pair.lon for pair in pairs]
return lats, lons

2
src/wrf/version.py

@ -1,2 +1,2 @@
__version__ = "1.0.5" __version__ = "1.1.0"

5
test/cachetest.py

@ -2,7 +2,10 @@ from __future__ import (absolute_import, division, print_function,
unicode_literals) unicode_literals)
from threading import Thread from threading import Thread
from Queue import Queue try:
from Queue import Queue
except ImportError:
from queue import Queue
from collections import OrderedDict from collections import OrderedDict
import unittest as ut import unittest as ut

BIN
test/ci_tests/ci_result_file.nc

Binary file not shown.

BIN
test/ci_tests/ci_test_file.nc

Binary file not shown.

17
test/ci_tests/make_test_file.py

@ -9,9 +9,9 @@ from netCDF4 import Dataset
from wrf import (getvar, interplevel, interpline, vertcross, vinterp, py2round, from wrf import (getvar, interplevel, interpline, vertcross, vinterp, py2round,
CoordPair, ll_to_xy, xy_to_ll, to_np) CoordPair, ll_to_xy, xy_to_ll, to_np)
VARS_TO_KEEP = ("XLAT", "XLONG", "XLAT_U", "XLAT_V", "XLONG_U", "XLONG_V", VARS_TO_KEEP = ("Times", "XLAT", "XLONG", "XLAT_U", "XLAT_V", "XLONG_U",
"U", "V", "W", "PH", "PHB", "T", "P", "PB", "Q2", "T2", "XLONG_V", "U", "V", "W", "PH", "PHB", "T", "P", "PB", "Q2",
"PSFC", "U10", "V10", "XTIME", "QVAPOR", "QCLOUD", "T2", "PSFC", "U10", "V10", "XTIME", "QVAPOR", "QCLOUD",
"QGRAUP", "QRAIN", "QSNOW", "MAPFAC_M", "MAPFAC_U", "QGRAUP", "QRAIN", "QSNOW", "MAPFAC_M", "MAPFAC_U",
"MAPFAC_V", "F", "HGT", "RAINC", "RAINSH", "RAINNC") "MAPFAC_V", "F", "HGT", "RAINC", "RAINSH", "RAINNC")
@ -22,7 +22,7 @@ WRF_DIAGS = ["avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz",
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure", "geopt", "helicity", "lat", "lon", "omg", "p", "pressure",
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc", "pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc",
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va", "theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va",
"wa", "uvmet10", "uvmet", "z", "cfrac"] "wa", "uvmet10", "uvmet", "z", "cfrac", "zstag"]
INTERP_METHS = ["interplevel", "vertcross", "interpline", "vinterp"] INTERP_METHS = ["interplevel", "vertcross", "interpline", "vinterp"]
@ -33,6 +33,7 @@ def copy_and_reduce(opts):
infilename = opts.filename infilename = opts.filename
outfilename = os.path.expanduser( outfilename = os.path.expanduser(
os.path.join(opts.outdir, "ci_test_file.nc")) os.path.join(opts.outdir, "ci_test_file.nc"))
with Dataset(infilename) as infile, Dataset(outfilename, "w") as outfile: with Dataset(infilename) as infile, Dataset(outfilename, "w") as outfile:
# Copy the global attributes # Copy the global attributes
@ -164,12 +165,14 @@ def main(opts):
if __name__ == "__main__": if __name__ == "__main__":
DEFAULT_FILE = ("/Users/ladwig/Documents/wrf_files/"
"wrf_vortex_multi/wrfout_d02_2005-08-28_12:00:00")
parser = argparse.ArgumentParser(description="Generate conda test files " parser = argparse.ArgumentParser(description="Generate conda test files "
"for unit testing.") "for unit testing.")
parser.add_argument("-f", "--filename", required=True, parser.add_argument("-f", "--filename", required=False,
default=DEFAULT_FILE,
help="the WRF test file") help="the WRF test file")
parser.add_argument("-o", "--outdir", required=True, parser.add_argument("-o", "--outdir", required=False, default="./",
help="the location for the output files") help="the location for the output files")
opts = parser.parse_args() opts = parser.parse_args()

28
test/ci_tests/utests.py

@ -8,7 +8,8 @@ import subprocess
from wrf import (getvar, interplevel, interpline, vertcross, vinterp, from wrf import (getvar, interplevel, interpline, vertcross, vinterp,
disable_xarray, xarray_enabled, to_np, disable_xarray, xarray_enabled, to_np,
xy_to_ll, ll_to_xy, xy_to_ll_proj, ll_to_xy_proj, 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 from wrf.util import is_multi_file
TEST_FILE = "ci_test_file.nc" TEST_FILE = "ci_test_file.nc"
@ -99,6 +100,10 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
ref_ht_850 = _get_refvals(referent, "interplevel", repeat, multi) ref_ht_850 = _get_refvals(referent, "interplevel", repeat, multi)
hts = getvar(in_wrfnc, "z", timeidx=timeidx) hts = getvar(in_wrfnc, "z", timeidx=timeidx)
p = getvar(in_wrfnc, "pressure", timeidx=timeidx) p = getvar(in_wrfnc, "pressure", timeidx=timeidx)
# Check that it works with numpy arrays
hts_850 = interplevel(to_np(hts), p, 850)
#print (hts_850)
hts_850 = interplevel(hts, p, 850) hts_850 = interplevel(hts, p, 850)
nt.assert_allclose(to_np(hts_850), ref_ht_850) nt.assert_allclose(to_np(hts_850), ref_ht_850)
@ -110,6 +115,10 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
p = getvar(in_wrfnc, "pressure", 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),
pivot_point=pivot_point, angle=90.)
#print (ht_cross)
ht_cross = vertcross(hts, p, pivot_point=pivot_point, angle=90.) ht_cross = vertcross(hts, p, pivot_point=pivot_point, angle=90.)
nt.assert_allclose(to_np(ht_cross), ref_ht_cross, rtol=.01) nt.assert_allclose(to_np(ht_cross), ref_ht_cross, rtol=.01)
@ -122,6 +131,10 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
t2 = getvar(in_wrfnc, "T2", timeidx=timeidx) t2 = getvar(in_wrfnc, "T2", timeidx=timeidx)
pivot_point = CoordPair(t2.shape[-1] // 2, t2.shape[-2] // 2) 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,
angle=90.0)
#print (t2_line1)
t2_line1 = interpline(t2, pivot_point=pivot_point, angle=90.0) t2_line1 = interpline(t2, pivot_point=pivot_point, angle=90.0)
nt.assert_allclose(to_np(t2_line1), ref_t2_line) nt.assert_allclose(to_np(t2_line1), ref_t2_line)
@ -135,6 +148,17 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
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_type="tk",
timeidx=timeidx,
log_p=True)
#print (field)
field = vinterp(in_wrfnc, field = vinterp(in_wrfnc,
field=tk, field=tk,
vert_coord="theta", vert_coord="theta",
@ -210,7 +234,7 @@ if __name__ == "__main__":
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure", "geopt", "helicity", "lat", "lon", "omg", "p", "pressure",
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc", "pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc",
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va", "theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va",
"wa", "uvmet10", "uvmet", "z", "cfrac"] "wa", "uvmet10", "uvmet", "z", "cfrac", "zstag"]
interp_methods = ["interplevel", "vertcross", "interpline", "vinterp"] interp_methods = ["interplevel", "vertcross", "interpline", "vinterp"]
latlon_tests = ["xy", "ll"] latlon_tests = ["xy", "ll"]

10
test/comp_utest.py

@ -498,6 +498,7 @@ def get_args(varname, wrfnc, timeidx, method, squeeze):
return (u, v, lat, lon, cen_lon, cone) return (u, v, lat, lon, cen_lon, cone)
if varname == "cloudfrac": if varname == "cloudfrac":
from wrf.g_geoht import get_height
vars = extract_vars(wrfnc, timeidx, ("P", "PB", "QVAPOR", "T"), vars = extract_vars(wrfnc, timeidx, ("P", "PB", "QVAPOR", "T"),
method, squeeze, cache=None, meta=True) method, squeeze, cache=None, meta=True)
@ -506,13 +507,16 @@ def get_args(varname, wrfnc, timeidx, method, squeeze):
qv = vars["QVAPOR"] qv = vars["QVAPOR"]
t = vars["T"] t = vars["T"]
geoht_agl = get_height(wrfnc, timeidx, method, squeeze,
cache=None, meta=True, msl=False)
full_p = p + pb full_p = p + pb
full_t = t + Constants.T_BASE full_t = t + Constants.T_BASE
tkel = tk(full_p, full_t) tkel = tk(full_p, full_t)
relh = rh(qv, full_p, tkel) relh = rh(qv, full_p, tkel)
return (full_p, relh) return (geoht_agl, relh, 1, 300., 2000., 6000.)
class WRFVarsTest(ut.TestCase): class WRFVarsTest(ut.TestCase):
@ -607,6 +611,10 @@ if __name__ == "__main__":
"omg", "pw", "rh", "slp", "td", "tk", "tv", "twb", "uvmet", "omg", "pw", "rh", "slp", "td", "tk", "tv", "twb", "uvmet",
"cloudfrac"] "cloudfrac"]
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 # Turn this one off when not needed, since it's slow
#varnames += ["cape_2d", "cape_3d"] #varnames += ["cape_2d", "cape_3d"]

17
test/generator_test.py

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

332
test/ipynb/Doc_Examples.ipynb

@ -2,10 +2,7 @@
"cells": [ "cells": [
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"# Cartopy Examples" "# Cartopy Examples"
] ]
@ -13,11 +10,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"%matplotlib inline" "%matplotlib inline"
@ -27,9 +20,6 @@
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {
"collapsed": false,
"deletable": true,
"editable": true,
"scrolled": false "scrolled": false
}, },
"outputs": [], "outputs": [],
@ -115,11 +105,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"%matplotlib inline\n", "%matplotlib inline\n",
@ -203,9 +189,6 @@
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {
"collapsed": false,
"deletable": true,
"editable": true,
"scrolled": false "scrolled": false
}, },
"outputs": [], "outputs": [],
@ -343,9 +326,6 @@
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {
"collapsed": false,
"deletable": true,
"editable": true,
"scrolled": false "scrolled": false
}, },
"outputs": [], "outputs": [],
@ -411,11 +391,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"%matplotlib inline\n", "%matplotlib inline\n",
@ -484,11 +460,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from __future__ import (absolute_import, division, print_function, unicode_literals)\n", "from __future__ import (absolute_import, division, print_function, unicode_literals)\n",
@ -568,11 +540,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from __future__ import print_function\n", "from __future__ import print_function\n",
@ -606,11 +574,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from __future__ import print_function\n", "from __future__ import print_function\n",
@ -631,10 +595,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"# Basemap Examples" "# Basemap Examples"
] ]
@ -642,11 +603,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"\n", "\n",
@ -704,11 +661,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"%matplotlib inline\n", "%matplotlib inline\n",
@ -781,11 +734,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"%matplotlib inline\n", "%matplotlib inline\n",
@ -921,11 +870,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from __future__ import print_function\n", "from __future__ import print_function\n",
@ -960,11 +905,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from __future__ import print_function\n", "from __future__ import print_function\n",
@ -986,11 +927,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"# SLP\n", "# SLP\n",
@ -1041,11 +978,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from __future__ import print_function\n", "from __future__ import print_function\n",
@ -1079,11 +1012,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from __future__ import print_function\n", "from __future__ import print_function\n",
@ -1101,6 +1030,233 @@
"\n", "\n",
"print (bounds)" "print (bounds)"
] ]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# OpenMP Routines"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from __future__ import print_function\n",
"\n",
"from wrf import omp_enabled\n",
"\n",
"print(omp_enabled())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from __future__ import print_function\n",
"\n",
"from wrf import omp_get_num_procs\n",
"\n",
"print(omp_get_num_procs())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from __future__ import print_function\n",
"\n",
"from wrf import omp_set_num_threads, omp_get_max_threads\n",
"\n",
"omp_set_num_threads(4)\n",
"\n",
"print(omp_get_max_threads())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from __future__ import print_function\n",
"\n",
"from wrf import omp_set_schedule, omp_get_schedule, OMP_SCHED_GUIDED\n",
"\n",
"omp_set_schedule(OMP_SCHED_GUIDED, 0)\n",
"\n",
"sched, modifier = omp_get_schedule()\n",
"\n",
"print(sched, modifier)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Loop and Fill Technique"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from __future__ import print_function, division\n",
"\n",
"import numpy as np\n",
"from netCDF4 import Dataset\n",
"from wrf import getvar, ALL_TIMES\n",
"\n",
"filename_list = [\"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/wrfout_d02_2005-08-28_00:00:00\",\n",
" \"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/wrfout_d02_2005-08-28_12:00:00\", \n",
" \"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/wrfout_d02_2005-08-29_00:00:00\"]\n",
"\n",
"# Result shape (hardcoded for this example, modify as necessary)\n",
"result_shape = (9, 29, 96, 96)\n",
"\n",
"# Only need 4-byte floats\n",
"z_final = np.empty(result_shape, np.float32)\n",
"\n",
"# Modify this number if using more than 1 time per file\n",
"times_per_file = 4\n",
"\n",
"for timeidx in xrange(result_shape[0]):\n",
" # Compute the file index and the time index inside the file\n",
" fileidx = timeidx // times_per_file\n",
" file_timeidx = timeidx % times_per_file\n",
"\n",
" f = Dataset(filename_list[fileidx]) \n",
" z = getvar(f, \"z\", file_timeidx)\n",
"\n",
" z_final[timeidx,:] = z[:]\n",
" f.close()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Using the cache argument"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from __future__ import print_function\n",
"\n",
"import time\n",
"from netCDF4 import Dataset\n",
"from wrf import getvar, ALL_TIMES, extract_vars\n",
"\n",
"wrf_filenames = [\"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/wrfout_d02_2005-08-28_00:00:00\",\n",
" \"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/wrfout_d02_2005-08-28_12:00:00\", \n",
" \"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/wrfout_d02_2005-08-29_00:00:00\"]\n",
"\n",
"wrfin = [Dataset(x) for x in wrf_filenames]\n",
"\n",
"start = time.time()\n",
"my_cache = extract_vars(wrfin, ALL_TIMES, (\"P\", \"PSFC\", \"PB\", \"PH\", \"PHB\", \"T\", \"QVAPOR\", \n",
" \"HGT\", \"U\", \"V\", \"W\"))\n",
"end = time.time()\n",
"print (\"Time taken to build cache: \", (end-start), \"s\")\n",
"\n",
"vars = (\"avo\", \"eth\", \"cape_2d\", \"cape_3d\", \"ctt\", \"dbz\", \"mdbz\", \n",
" \"geopt\", \"helicity\", \"lat\", \"lon\", \"omg\", \"p\", \"pressure\", \n",
" \"pvo\", \"pw\", \"rh2\", \"rh\", \"slp\", \"ter\", \"td2\", \"td\", \"tc\", \n",
" \"theta\", \"tk\", \"tv\", \"twb\", \"updraft_helicity\", \"ua\", \"va\", \n",
" \"wa\", \"uvmet10\", \"uvmet\", \"z\", \"cfrac\", \"zstag\", \"geopt_stag\")\n",
"\n",
"start = time.time()\n",
"for var in vars:\n",
" v = getvar(wrfin, var, ALL_TIMES)\n",
"end = time.time()\n",
"no_cache_time = (end-start)\n",
"\n",
"print (\"Time taken without variable cache: \", no_cache_time, \"s\")\n",
"\n",
"start = time.time()\n",
"for var in vars:\n",
" v = getvar(wrfin, var, ALL_TIMES, cache=my_cache)\n",
"end = time.time()\n",
"cache_time = (end-start)\n",
"\n",
"print (\"Time taken with variable cache: \", cache_time, \"s\")\n",
"\n",
"improvement = ((no_cache_time-cache_time)/no_cache_time) * 100 \n",
"print (\"The cache decreased computation time by: \", improvement, \"%\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Using the cache argument with OpenMP"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from __future__ import print_function\n",
"\n",
"import time\n",
"from netCDF4 import Dataset\n",
"from wrf import getvar, ALL_TIMES, extract_vars, omp_set_num_threads, omp_get_num_procs\n",
"\n",
"wrf_filenames = [\"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/wrfout_d02_2005-08-28_00:00:00\",\n",
" \"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/wrfout_d02_2005-08-28_12:00:00\", \n",
" \"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/wrfout_d02_2005-08-29_00:00:00\"]\n",
"\n",
"wrfin = [Dataset(x) for x in wrf_filenames]\n",
"\n",
"start = time.time()\n",
"my_cache = extract_vars(wrfin, ALL_TIMES, (\"P\", \"PSFC\", \"PB\", \"PH\", \"PHB\", \"T\", \"QVAPOR\", \n",
" \"HGT\", \"U\", \"V\", \"W\"))\n",
"end = time.time()\n",
"print (\"Time taken to build cache: \", (end-start), \"s\")\n",
"\n",
"omp_set_num_threads(omp_get_num_procs())\n",
"\n",
"vars = (\"avo\", \"eth\", \"cape_2d\", \"cape_3d\", \"ctt\", \"dbz\", \"mdbz\", \n",
" \"geopt\", \"helicity\", \"lat\", \"lon\", \"omg\", \"p\", \"pressure\", \n",
" \"pvo\", \"pw\", \"rh2\", \"rh\", \"slp\", \"ter\", \"td2\", \"td\", \"tc\", \n",
" \"theta\", \"tk\", \"tv\", \"twb\", \"updraft_helicity\", \"ua\", \"va\", \n",
" \"wa\", \"uvmet10\", \"uvmet\", \"z\", \"cfrac\", \"zstag\", \"geopt_stag\")\n",
"\n",
"start = time.time()\n",
"for var in vars:\n",
" v = getvar(wrfin, var, ALL_TIMES)\n",
"end = time.time()\n",
"no_cache_time = (end-start)\n",
"\n",
"print (\"Time taken without variable cache: \", no_cache_time, \"s\")\n",
"\n",
"start = time.time()\n",
"for var in vars:\n",
" v = getvar(wrfin, var, ALL_TIMES, cache=my_cache)\n",
"end = time.time()\n",
"cache_time = (end-start)\n",
"\n",
"print (\"Time taken with variable cache: \", cache_time, \"s\")\n",
"\n",
"improvement = ((no_cache_time-cache_time)/no_cache_time) * 100 \n",
"print (\"The cache decreased computation time by: \", improvement, \"%\")\n",
"\n",
"omp_set_num_threads(1)"
]
} }
], ],
"metadata": { "metadata": {
@ -1119,7 +1275,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython2", "pygments_lexer": "ipython2",
"version": "2.7.12" "version": "2.7.13"
} }
}, },
"nbformat": 4, "nbformat": 4,

376
test/ipynb/WRF_python_demo.ipynb

@ -2,10 +2,7 @@
"cells": [ "cells": [
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"# 1.0 Basic Variable Extraction" "# 1.0 Basic Variable Extraction"
] ]
@ -13,11 +10,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from __future__ import (absolute_import, division, print_function, unicode_literals)\n", "from __future__ import (absolute_import, division, print_function, unicode_literals)\n",
@ -32,9 +25,6 @@
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {
"collapsed": false,
"deletable": true,
"editable": true,
"scrolled": false "scrolled": false
}, },
"outputs": [], "outputs": [],
@ -45,10 +35,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"### 1.0.1 DataArray attributes: 'dims', 'coords', 'attrs'" "### 1.0.1 DataArray attributes: 'dims', 'coords', 'attrs'"
] ]
@ -56,11 +43,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"print(\"dims: \", p.dims)\n", "print(\"dims: \", p.dims)\n",
@ -71,10 +54,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"### 1.0.2 Removing implicit 'squeeze' behavior to preserve single sized dimensions" "### 1.0.2 Removing implicit 'squeeze' behavior to preserve single sized dimensions"
] ]
@ -82,11 +62,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"p_nosqueeze = getvar(ncfile, \"P\", timeidx=0, squeeze=False)\n", "p_nosqueeze = getvar(ncfile, \"P\", timeidx=0, squeeze=False)\n",
@ -95,10 +71,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"### 1.0.3 Single element metadata" "### 1.0.3 Single element metadata"
] ]
@ -106,11 +79,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"print (p_nosqueeze[0,0,100,200])\n", "print (p_nosqueeze[0,0,100,200])\n",
@ -119,10 +88,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"### 1.0.4 Disabling/Enabling xarray" "### 1.0.4 Disabling/Enabling xarray"
] ]
@ -130,11 +96,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from wrf import disable_xarray, enable_xarray\n", "from wrf import disable_xarray, enable_xarray\n",
@ -157,20 +119,14 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"# 2.0 Sequences of Input Files " "# 2.0 Sequences of Input Files "
] ]
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"## 2.0.1 Combining via the 'cat' method" "## 2.0.1 Combining via the 'cat' method"
] ]
@ -178,11 +134,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from wrf import ALL_TIMES\n", "from wrf import ALL_TIMES\n",
@ -196,10 +148,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"## 2.0.2 Combining via the 'join' method" "## 2.0.2 Combining via the 'join' method"
] ]
@ -207,11 +156,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"p_join = getvar(wrflist, \"P\", timeidx=ALL_TIMES, method=\"join\")\n", "p_join = getvar(wrflist, \"P\", timeidx=ALL_TIMES, method=\"join\")\n",
@ -220,10 +165,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"Note how the Time dimension was replaced with the file dimension, due to the 'squeezing' of the Time dimension.\n", "Note how the Time dimension was replaced with the file dimension, due to the 'squeezing' of the Time dimension.\n",
"\n", "\n",
@ -234,11 +176,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from wrf import ALL_TIMES\n", "from wrf import ALL_TIMES\n",
@ -249,10 +187,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"## 2.0.3 Dictionary Sequences" "## 2.0.3 Dictionary Sequences"
] ]
@ -260,11 +195,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"wrf_dict = {\"label1\" : [ncfile, ncfile],\n", "wrf_dict = {\"label1\" : [ncfile, ncfile],\n",
@ -276,10 +207,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"## 2.0.4 Generator Sequences" "## 2.0.4 Generator Sequences"
] ]
@ -287,11 +215,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"def gen_seq():\n", "def gen_seq():\n",
@ -306,10 +230,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"## 2.0.5 Custom Iterable Classes" "## 2.0.5 Custom Iterable Classes"
] ]
@ -317,11 +238,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"class FileGen(object):\n", "class FileGen(object):\n",
@ -334,7 +251,7 @@
" return self\n", " return self\n",
" \n", " \n",
" def next(self):\n", " def next(self):\n",
" if self._i >= self._total:\n", " if self._i > self._total:\n",
" raise StopIteration\n", " raise StopIteration\n",
" else:\n", " else:\n",
" val = self.ncfile[self._i]\n", " val = self.ncfile[self._i]\n",
@ -347,7 +264,7 @@
"\n", "\n",
"obj_gen = FileGen(ncfile, 3)\n", "obj_gen = FileGen(ncfile, 3)\n",
"\n", "\n",
"p_obj_gen = getvar(gen_seq(), \"P\", method=\"join\", squeeze=False)\n", "p_obj_gen = getvar(obj_gen, \"P\", method=\"join\", squeeze=False)\n",
"print(p_obj_gen)\n", "print(p_obj_gen)\n",
"\n", "\n",
"del p_obj_gen\n", "del p_obj_gen\n",
@ -356,10 +273,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"# 3.0 WRF Variable Computational Routines" "# 3.0 WRF Variable Computational Routines"
] ]
@ -367,11 +281,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"wrf_vars = [\"avo\", \"eth\", \"cape_2d\", \"cape_3d\", \"ctt\", \"dbz\", \"mdbz\", \n", "wrf_vars = [\"avo\", \"eth\", \"cape_2d\", \"cape_3d\", \"ctt\", \"dbz\", \"mdbz\", \n",
@ -390,10 +300,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"(Note all of the NaNs in the above routines which produce missing values (e.g. cape_2d). xarray always converts all masked_array missing values to NaN in order to work with pandas. To get back the original missing values in a numpy masked_array, you need to use the 'to_np' method from wrf.)" "(Note all of the NaNs in the above routines which produce missing values (e.g. cape_2d). xarray always converts all masked_array missing values to NaN in order to work with pandas. To get back the original missing values in a numpy masked_array, you need to use the 'to_np' method from wrf.)"
] ]
@ -401,11 +308,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from wrf import to_np\n", "from wrf import to_np\n",
@ -417,11 +320,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"keys = [x for x in vard.keys()]\n", "keys = [x for x in vard.keys()]\n",
@ -431,20 +330,14 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"## 3.1 Interpolation Routines" "## 3.1 Interpolation Routines"
] ]
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"### 3.1.1 Horizontal Level Interpolation" "### 3.1.1 Horizontal Level Interpolation"
] ]
@ -452,11 +345,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"# 500 MB Heights\n", "# 500 MB Heights\n",
@ -472,10 +361,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"### 3.1.2 Vertical Cross Section Interpolation" "### 3.1.2 Vertical Cross Section Interpolation"
] ]
@ -483,11 +369,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"# Pressure using pivot and angle\n", "# Pressure using pivot and angle\n",
@ -515,11 +397,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"# Pressure using pivot and angle\n", "# Pressure using pivot and angle\n",
@ -570,11 +448,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"# Pressure using pivot and angle\n", "# Pressure using pivot and angle\n",
@ -626,10 +500,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"### 3.1.3 Interpolate 2D Variable to a Line" "### 3.1.3 Interpolate 2D Variable to a Line"
] ]
@ -637,11 +508,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"# T2 using pivot and angle\n", "# T2 using pivot and angle\n",
@ -685,10 +552,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"### 3.1.4 Vertical Coordinate Interpolation" "### 3.1.4 Vertical Coordinate Interpolation"
] ]
@ -696,11 +560,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from wrf import vinterp, getvar\n", "from wrf import vinterp, getvar\n",
@ -782,10 +642,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"deletable": true,
"editable": true
},
"source": [ "source": [
"## 3.2 Lat/Lon to X/Y Routines" "## 3.2 Lat/Lon to X/Y Routines"
] ]
@ -793,11 +650,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from wrf.latlon import xy_to_ll, ll_to_xy \n", "from wrf.latlon import xy_to_ll, ll_to_xy \n",
@ -835,9 +688,7 @@
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {
"collapsed": true, "collapsed": true
"deletable": true,
"editable": true
}, },
"source": [ "source": [
"# 4.0 Plotting with Cartopy" "# 4.0 Plotting with Cartopy"
@ -846,11 +697,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": true,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"%matplotlib inline" "%matplotlib inline"
@ -859,11 +706,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"# SLP\n", "# SLP\n",
@ -905,11 +748,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"# SLP\n", "# SLP\n",
@ -986,11 +825,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"# 500 MB Heights and Winds\n", "# 500 MB Heights and Winds\n",
@ -1043,9 +878,6 @@
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {
"collapsed": false,
"deletable": true,
"editable": true,
"scrolled": false "scrolled": false
}, },
"outputs": [], "outputs": [],
@ -1075,11 +907,7 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"source": [ "source": [
"# Multi-time Moving Domain Files" "# Multi-time Moving Domain Files"
] ]
@ -1087,11 +915,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"import os\n", "import os\n",
@ -1111,11 +935,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"p = getvar(ncfiles, \"ctt\", timeidx=ALL_TIMES)" "p = getvar(ncfiles, \"ctt\", timeidx=ALL_TIMES)"
@ -1124,11 +944,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"print (p)\n", "print (p)\n",
@ -1138,11 +954,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"print (p.attrs[\"projection\"])\n" "print (p.attrs[\"projection\"])\n"
@ -1151,11 +963,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"ncfiles[2].variables[\"XTIME\"][:]\n" "ncfiles[2].variables[\"XTIME\"][:]\n"
@ -1164,11 +972,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"p = getvar(ncfiles, \"P\", timeidx=None, method=\"cat\", meta=True, squeeze=True)\n" "p = getvar(ncfiles, \"P\", timeidx=None, method=\"cat\", meta=True, squeeze=True)\n"
@ -1177,11 +981,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"print (p)" "print (p)"
@ -1190,11 +990,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"print (type(p.coords[\"Time\"]))" "print (type(p.coords[\"Time\"]))"
@ -1203,11 +999,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"import datetime\n", "import datetime\n",
@ -1220,11 +1012,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"wrf_vars = [\"avo\", \"eth\", \"cape_2d\", \"cape_3d\", \"ctt\", \"dbz\", \"mdbz\", \n", "wrf_vars = [\"avo\", \"eth\", \"cape_2d\", \"cape_3d\", \"ctt\", \"dbz\", \"mdbz\", \n",
@ -1249,11 +1037,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"import os\n", "import os\n",
@ -1290,11 +1074,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"import os\n", "import os\n",
@ -1335,11 +1115,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": true,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from wrf import getvar\n" "from wrf import getvar\n"
@ -1348,22 +1124,14 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": true,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [] "source": []
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from wrf.latlon import xy_to_ll, ll_to_xy \n", "from wrf.latlon import xy_to_ll, ll_to_xy \n",
@ -1390,11 +1158,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": false,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [ "source": [
"from glob import glob\n", "from glob import glob\n",
@ -1435,11 +1199,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": { "metadata": {},
"collapsed": true,
"deletable": true,
"editable": true
},
"outputs": [], "outputs": [],
"source": [] "source": []
} }
@ -1460,9 +1220,9 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython2", "pygments_lexer": "ipython2",
"version": "2.7.12" "version": "2.7.13"
} }
}, },
"nbformat": 4, "nbformat": 4,
"nbformat_minor": 0 "nbformat_minor": 1
} }

12
test/listBug.ncl

@ -1,6 +1,18 @@
; Bug1: This segfaults
l = NewList("fifo") l = NewList("fifo")
name = "foo" name = "foo"
ListAppend(l, (/name/)) ListAppend(l, (/name/))
print(l) print(l)
print(l[0]) print(l[0])
name = "bar" name = "bar"
; Bug2 Variables disappear
a = addfile("/Users/ladwig/Documents/wrf_files/wrfout_d02_2010-06-13_21:00:00.nc", "r")
b := wrf_user_getvar(a, "slp", -1)
c = NewList("fifo")
ListAppend(c, (/b/))
b := wrf_user_getvar(a, "rh", -1)
ListAppend(c, (/b/))
print(c[0])
print(c[1]) ; Variables start disappearing

44
test/mocktest.py

@ -0,0 +1,44 @@
import sys
import os
try:
from unittest.mock import MagicMock
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",
"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}
class MockWrfConstants(object):
def __init__(self):
self.__dict__ = consts
def mock_asscalar(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__)

77
test/test_filevars.py

@ -0,0 +1,77 @@
import unittest as ut
import numpy.testing as nt
import numpy as np
import numpy.ma as ma
import os, sys
import subprocess
from wrf import getvar, ALL_TIMES
TEST_DIR = "/Users/ladwig/Documents/wrf_files/wrf_vortex_multi"
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"]
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()
t1 = getvar(ncfiles, varname, 0)
#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()
t3 = getvar(ncfiles, varname, ALL_TIMES)
#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()
t5 = getvar(ncfiles, varname, ALL_TIMES, method="join")
#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))
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]
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()

122
test/test_omp.py

@ -0,0 +1,122 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import unittest as ut
import numpy.testing as nt
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_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_max_active_levels, omp_get_level,
omp_get_ancestor_thread_num, omp_get_team_size,
omp_get_active_level, omp_in_final,
omp_init_lock, omp_init_nest_lock,
omp_destroy_lock, omp_destroy_nest_lock,
omp_set_lock, omp_set_nest_lock,
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)
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)
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
thread_num = omp_get_thread_num()
self.assertEqual(thread_num, 0) # Always 0 outside of parallel region
num_procs = omp_get_num_procs()
in_parallel = omp_in_parallel()
self.assertFalse(in_parallel) # Always False outside of parallel region
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)
kind, modifier = omp_get_schedule()
self.assertEqual(kind, OMP_SCHED_GUIDED)
self.assertEqual(modifier, 100)
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.
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()

97
test/utests.py

@ -8,7 +8,7 @@ import subprocess
from wrf import (getvar, interplevel, interpline, vertcross, vinterp, from wrf import (getvar, interplevel, interpline, vertcross, vinterp,
disable_xarray, xarray_enabled, to_np, disable_xarray, xarray_enabled, to_np,
xy_to_ll, ll_to_xy, xy_to_ll_proj, ll_to_xy_proj, xy_to_ll, ll_to_xy, xy_to_ll_proj, ll_to_xy_proj,
extract_global_attrs, viewitems, CoordPair) extract_global_attrs, viewitems, CoordPair, ll_points)
from wrf.util import is_multi_file from wrf.util import is_multi_file
NCL_EXE = "/Users/ladwig/nclbuild/6.3.0/bin/ncl" NCL_EXE = "/Users/ladwig/nclbuild/6.3.0/bin/ncl"
@ -93,7 +93,10 @@ def make_test(varname, wrf_in, referent, multi=False, repeat=3, pynio=False):
multiproduct = varname in ("uvmet", "uvmet10", "cape_2d", "cape_3d", multiproduct = varname in ("uvmet", "uvmet10", "cape_2d", "cape_3d",
"cfrac") "cfrac")
# These varnames don't have NCL functions to test against
ignore_referent = ("zstag", "geopt_stag")
if varname not in ignore_referent:
if not multi: if not multi:
ref_vals = refnc.variables[varname][:] ref_vals = refnc.variables[varname][:]
else: else:
@ -138,12 +141,23 @@ def make_test(varname, wrf_in, referent, multi=False, repeat=3, pynio=False):
tol = 1/100. 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) nt.assert_allclose(to_np(my_vals), ref_vals, tol, atol)
elif (varname == "cfrac"):
# Change the vert_type to height_agl when NCL gets updated.
my_vals = getvar(in_wrfnc, "cfrac", timeidx=timeidx,
vert_type="pres")
tol = 1/100.
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"): elif (varname == "pw"):
my_vals = getvar(in_wrfnc, "pw", timeidx=timeidx) my_vals = getvar(in_wrfnc, "pw", timeidx=timeidx)
tol = .5/100.0 tol = .5/100.0
atol = 0 # NCL uses different constants and doesn't use same atol = 0 # NCL uses different constants and doesn't use same
# handrolled virtual temp in method # handrolled virtual temp in method
try:
nt.assert_allclose(to_np(my_vals), ref_vals, tol, atol) nt.assert_allclose(to_np(my_vals), ref_vals, tol, atol)
except AssertionError:
print (np.amax(np.abs(to_np(my_vals) - ref_vals)))
raise
elif (varname == "cape_2d"): elif (varname == "cape_2d"):
cape_2d = getvar(in_wrfnc, varname, timeidx=timeidx) cape_2d = getvar(in_wrfnc, varname, timeidx=timeidx)
tol = 0/100. tol = 0/100.
@ -165,12 +179,20 @@ def make_test(varname, wrf_in, referent, multi=False, repeat=3, pynio=False):
#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) nt.assert_allclose(to_np(cape_3d), ref_vals, tol, atol)
elif (varname == "zstag" or varname == "geopt_stag"):
v = getvar(in_wrfnc, varname, timeidx=timeidx)
# For now, only make sure it runs without crashing since no NCL
# to compare with yet.
else: else:
my_vals = getvar(in_wrfnc, varname, timeidx=timeidx) my_vals = getvar(in_wrfnc, varname, timeidx=timeidx)
tol = 2/100. tol = 2/100.
atol = 0.1 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)))
try:
nt.assert_allclose(to_np(my_vals), ref_vals, tol, atol) nt.assert_allclose(to_np(my_vals), ref_vals, tol, atol)
except:
print (np.amax(np.abs(to_np(my_vals) - ref_vals)))
raise
return test return test
@ -247,6 +269,9 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
ref_ht_500 = _get_refvals(referent, "z_500", repeat, multi) ref_ht_500 = _get_refvals(referent, "z_500", repeat, multi)
hts = getvar(in_wrfnc, "z", timeidx=timeidx) hts = getvar(in_wrfnc, "z", timeidx=timeidx)
p = getvar(in_wrfnc, "pressure", timeidx=timeidx) p = getvar(in_wrfnc, "pressure", timeidx=timeidx)
# Make sure the numpy versions work first
hts_500 = interplevel(to_np(hts), to_np(p), 500)
hts_500 = interplevel(hts, p, 500) hts_500 = interplevel(hts, p, 500)
nt.assert_allclose(to_np(hts_500), ref_ht_500) nt.assert_allclose(to_np(hts_500), ref_ht_500)
@ -259,20 +284,45 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
p = getvar(in_wrfnc, "pressure", 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)
#ht_cross = vertcross(to_np(hts), p, pivot_point=pivot_point,
# angle=90., latlon=True)
# Make sure the numpy versions work first
ht_cross = vertcross(to_np(hts), to_np(p),
pivot_point=pivot_point, angle=90.)
ht_cross = vertcross(hts, p, pivot_point=pivot_point, angle=90.) ht_cross = vertcross(hts, p, pivot_point=pivot_point, angle=90.)
nt.assert_allclose(to_np(ht_cross), ref_ht_cross, rtol=.01) # Note: Until the bug is fixed in NCL, the wrf-python cross
# sections will contain one extra point
nt.assert_allclose(to_np(ht_cross)[...,0:-1], ref_ht_cross,
rtol=.01)
# Test the manual projection method with lat/lon
lats = hts.coords["XLAT"]
lons = hts.coords["XLONG"]
ll_point = ll_points(lats, lons)
pivot = CoordPair(lat=lats[int(lats.shape[-2]/2),
int(lats.shape[-1]/2)],
lon=lons[int(lons.shape[-2]/2),
int(lons.shape[-1]/2)])
v1 = vertcross(hts,p,wrfin=in_wrfnc,pivot_point=pivot_point,
angle=90.0)
v2 = vertcross(hts,p,projection=hts.attrs["projection"],
ll_point=ll_point,
pivot_point=pivot_point, angle=90.)
nt.assert_allclose(to_np(v1), to_np(v2), rtol=.01)
# Test opposite # Test opposite
p_cross1 = vertcross(p,hts,pivot_point=pivot_point, angle=90.0) p_cross1 = vertcross(p,hts,pivot_point=pivot_point, angle=90.0)
nt.assert_allclose(to_np(p_cross1), nt.assert_allclose(to_np(p_cross1)[...,0:-1],
ref_p_cross, ref_p_cross,
rtol=.01) rtol=.01)
# Test point to point # Test point to point
start_point = CoordPair(0, hts.shape[-2]/2) start_point = CoordPair(0, hts.shape[-2]/2)
end_point = CoordPair(-1,hts.shape[-2]/2) end_point = CoordPair(-1,hts.shape[-2]/2)
p_cross2 = vertcross(p,hts,start_point=start_point, p_cross2 = vertcross(p,hts,start_point=start_point,
end_point=end_point) end_point=end_point)
@ -286,9 +336,30 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
t2 = getvar(in_wrfnc, "T2", timeidx=timeidx) t2 = getvar(in_wrfnc, "T2", timeidx=timeidx)
pivot_point = CoordPair(t2.shape[-1] / 2, t2.shape[-2] / 2) pivot_point = CoordPair(t2.shape[-1] / 2, t2.shape[-2] / 2)
#t2_line1 = interpline(to_np(t2), pivot_point=pivot_point,
# angle=90.0, latlon=True)
# Make sure the numpy version works
t2_line1 = interpline(to_np(t2), pivot_point=pivot_point,
angle=90.0)
t2_line1 = interpline(t2, pivot_point=pivot_point, angle=90.0) t2_line1 = interpline(t2, pivot_point=pivot_point, angle=90.0)
nt.assert_allclose(to_np(t2_line1), ref_t2_line) # Note: After NCL is fixed, remove the slice.
nt.assert_allclose(to_np(t2_line1)[...,0:-1], ref_t2_line)
# Test the manual projection method with lat/lon
lats = t2.coords["XLAT"]
lons = t2.coords["XLONG"]
ll_point = ll_points(lats, lons)
pivot = CoordPair(lat=lats[int(lats.shape[-2]/2),
int(lats.shape[-1]/2)],
lon=lons[int(lons.shape[-2]/2),
int(lons.shape[-1]/2)])
l1 = interpline(t2,wrfin=in_wrfnc,pivot_point=pivot_point,
angle=90.0)
l2 = interpline(t2,projection=t2.attrs["projection"],
ll_point=ll_point,
pivot_point=pivot_point, angle=90.)
nt.assert_allclose(to_np(l1), to_np(l2), rtol=.01)
# Test point to point # Test point to point
start_point = CoordPair(0, t2.shape[-2]/2) start_point = CoordPair(0, t2.shape[-2]/2)
@ -307,6 +378,16 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
interp_levels = [200,300,500,1000] interp_levels = [200,300,500,1000]
# Make sure the numpy version works
field = vinterp(in_wrfnc,
field=to_np(tk),
vert_coord="theta",
interp_levels=interp_levels,
extrapolate=True,
field_type="tk",
timeidx=timeidx,
log_p=True)
field = vinterp(in_wrfnc, field = vinterp(in_wrfnc,
field=tk, field=tk,
vert_coord="theta", vert_coord="theta",
@ -599,12 +680,18 @@ class WRFLatLonTest(ut.TestCase):
if __name__ == "__main__": if __name__ == "__main__":
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 ignore_vars = [] # Not testable yet
wrf_vars = ["avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz", wrf_vars = ["avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz",
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure", "geopt", "helicity", "lat", "lon", "omg", "p", "pressure",
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc", "pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc",
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va", "theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va",
"wa", "uvmet10", "uvmet", "z", "cfrac"] "wa", "uvmet10", "uvmet", "z", "cfrac", "zstag", "geopt_stag"]
interp_methods = ["interplevel", "vertcross", "interpline", "vinterp"] interp_methods = ["interplevel", "vertcross", "interpline", "vinterp"]
latlon_tests = ["xy", "ll"] latlon_tests = ["xy", "ll"]

36
test/varcache.py

@ -0,0 +1,36 @@
from __future__ import print_function
import time
from netCDF4 import Dataset
from wrf import getvar, ALL_TIMES, extract_vars
wrf_filenames = ["/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/wrfout_d02_2005-08-28_00:00:00",
"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/wrfout_d02_2005-08-28_12:00:00",
"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/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"))
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",
"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))
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",
"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))
Loading…
Cancel
Save