Browse Source

Completed the backporting of fortran 90 code to NCL. All routines should now pass numpy views directly to fortran to be filled rather than copying. Multi-product output now moves the product type to the left index. Raw computational routines have a public API (not tested yet however). Lots of clean-up done, and lots remaining.

main
Bill Ladwig 9 years ago
parent
commit
68b9f1a6eb
  1. 1
      conda_recipe/meta.yaml
  2. BIN
      doc/.DS_Store
  3. 230
      doc/Makefile
  4. 281
      doc/make.bat
  5. 288
      doc/source/conf.py
  6. 36
      doc/source/index.rst
  7. 126
      fortran/calc_uh.f90
  8. 56
      fortran/cloud_fracf.f90
  9. 64
      fortran/constants.f90
  10. 51
      fortran/eqthecalc.f90
  11. 0
      fortran/reference/wrfcape.f90
  12. 0
      fortran/reference/wrfcape.pyf
  13. 0
      fortran/reference/wrfext.f90
  14. 0
      fortran/reference/wrfext.pyf
  15. 0
      fortran/reference/wrfext2.f90.BAK
  16. 1018
      fortran/ripW.c
  17. 617
      fortran/rip_cape.f90
  18. 13330
      fortran/wrfW.c
  19. 125
      fortran/wrf_fctt.f90
  20. 122
      fortran/wrf_pvo.f90
  21. 31
      fortran/wrf_pw.f90
  22. 84
      fortran/wrf_relhl.f90
  23. 269
      fortran/wrf_rip_phys_routines.f90
  24. 102
      fortran/wrf_user.f90
  25. 147
      fortran/wrf_user_dbz.f90
  26. 524
      fortran/wrf_user_latlon_routines.f90
  27. 445
      fortran/wrf_vinterp.f90
  28. 406
      fortran/wrffortran.pyf
  29. 5541
      ncl_reference/WRFUsersherrie.ncl
  30. 60
      ncl_reference/cloud_fracf.f
  31. 170
      ncl_reference/module_model_constants.f
  32. 380
      ncl_reference/wrf_map_fix.ncl
  33. 40
      setup.py
  34. 16
      src/wrf/api.py
  35. 96
      src/wrf/cape.py
  36. 27
      src/wrf/cloudfrac.py
  37. 162
      src/wrf/computation.py
  38. 5
      src/wrf/config.py
  39. 18
      src/wrf/constants.py
  40. 4
      src/wrf/ctt.py
  41. 4575
      src/wrf/data/psadilookup.dat
  42. 29
      src/wrf/dbz.py
  43. 83
      src/wrf/decorators.py
  44. 699
      src/wrf/extension.py
  45. 6
      src/wrf/helicity.py
  46. 42
      src/wrf/interp.py
  47. 2
      src/wrf/interputils.py
  48. 29
      src/wrf/latlon.py
  49. 197
      src/wrf/latlonutils.py
  50. 369
      src/wrf/metadecorators.py
  51. 4
      src/wrf/omega.py
  52. 6
      src/wrf/pw.py
  53. 55
      src/wrf/py3compat.py
  54. 15
      src/wrf/routines.py
  55. 489
      src/wrf/specialdec.py
  56. 8
      src/wrf/temp.py
  57. 2
      src/wrf/units.py
  58. 162
      src/wrf/util.py
  59. 229
      src/wrf/uvdecorator.py
  60. 6
      src/wrf/vorticity.py
  61. 9
      src/wrf/wind.py
  62. 145
      test/ipynb/WRF_Workshop_Demo.ipynb
  63. 61
      test/ipynb/nocopy_test.ipynb
  64. 81
      test/utests.py
  65. 17
      test/viewtest.py

1
conda_recipe/meta.yaml

@ -22,6 +22,7 @@ requirements: @@ -22,6 +22,7 @@ requirements:
- python
- wrapt
- libgcc 4.8.5
- xarray
test:
requires:

BIN
doc/.DS_Store vendored

Binary file not shown.

230
doc/Makefile

@ -0,0 +1,230 @@ @@ -0,0 +1,230 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
.PHONY: help
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " epub3 to make an epub3"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
@echo " dummy to check syntax errors of document sources"
.PHONY: clean
clean:
rm -rf $(BUILDDIR)/*
.PHONY: html
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
.PHONY: dirhtml
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
.PHONY: singlehtml
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
.PHONY: pickle
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
.PHONY: json
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
.PHONY: htmlhelp
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
.PHONY: qthelp
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/wrf-python.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/wrf-python.qhc"
.PHONY: applehelp
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
.PHONY: devhelp
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/wrf-python"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/wrf-python"
@echo "# devhelp"
.PHONY: epub
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
.PHONY: epub3
epub3:
$(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3
@echo
@echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3."
.PHONY: latex
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
.PHONY: latexpdf
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: latexpdfja
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: text
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
.PHONY: man
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
.PHONY: texinfo
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
.PHONY: info
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
.PHONY: gettext
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
.PHONY: changes
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
.PHONY: linkcheck
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
.PHONY: doctest
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
.PHONY: coverage
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
.PHONY: xml
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
.PHONY: pseudoxml
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
.PHONY: dummy
dummy:
$(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy
@echo
@echo "Build finished. Dummy builder generates no files."

281
doc/make.bat

@ -0,0 +1,281 @@ @@ -0,0 +1,281 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
set I18NSPHINXOPTS=%SPHINXOPTS% source
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. epub3 to make an epub3
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
echo. coverage to run coverage check of the documentation if enabled
echo. dummy to check syntax errors of document sources
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
REM Check if sphinx-build is available and fallback to Python version if any
%SPHINXBUILD% 1>NUL 2>NUL
if errorlevel 9009 goto sphinx_python
goto sphinx_ok
:sphinx_python
set SPHINXBUILD=python -m sphinx.__init__
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
:sphinx_ok
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\wrf-python.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\wrf-python.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "epub3" (
%SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub3 file is in %BUILDDIR%/epub3.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "coverage" (
%SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
if errorlevel 1 exit /b 1
echo.
echo.Testing of coverage in the sources finished, look at the ^
results in %BUILDDIR%/coverage/python.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
if "%1" == "dummy" (
%SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy
if errorlevel 1 exit /b 1
echo.
echo.Build finished. Dummy builder generates no files.
goto end
)
:end

288
doc/source/conf.py

@ -0,0 +1,288 @@ @@ -0,0 +1,288 @@
# -*- coding: utf-8 -*-
#
# wrf-python documentation build configuration file, created by
# sphinx-quickstart on Wed Jun 29 14:57:16 2016.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc', 'sphinx.ext.napoleon'
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'wrf-python'
copyright = u'2016, Bill Ladwig'
author = u'Bill Ladwig'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'0.0.1'
# The full version, including alpha/beta/rc tags.
release = u'0.0.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents.
# "<project> v<release> documentation" by default.
#html_title = u'wrf-python v0.0.1'
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (relative to this directory) to use as a favicon of
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not None, a 'Last updated on:' timestamp is inserted at every page
# bottom, using the given strftime format.
# The empty string is equivalent to '%b %d, %Y'.
#html_last_updated_fmt = None
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh'
#html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# 'ja' uses this config value.
# 'zh' user can custom change `jieba` dictionary path.
#html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'wrf-pythondoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'wrf-python.tex', u'wrf-python Documentation',
u'Bill Ladwig', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'wrf-python', u'wrf-python Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'wrf-python', u'wrf-python Documentation',
author, 'wrf-python', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

36
doc/source/index.rst

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
.. wrf-python documentation master file, created by
sphinx-quickstart on Wed Jun 29 14:57:16 2016.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to wrf-python's documentation!
======================================
Contents:
.. toctree::
:maxdepth: 2
Extraction Routine
------------------
.. autofunction:: wrf.getvar
Interpolation Routines
----------------------
.. autofunction:: wrf.interplevel
.. autofunction:: wrf.vertcross
.. autofunction:: wrf.interpline
.. autofunction:: wrf.vinterp
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

126
fortran/calc_uh.f90

@ -0,0 +1,126 @@ @@ -0,0 +1,126 @@
!NCLFORTSTART
SUBROUTINE DCALCUH(nx, ny, nz, nzp1, zp, mapfct, dx, dy, uhmnhgt, uhmxhgt, us, &
vs, w, uh, tem1, tem2)
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: uh
INTEGER, INTENT(IN) :: nx, ny, nz, nzp1
REAL(KIND=8), DIMENSION(nx,ny,nzp1), INTENT(IN) :: zp
REAL(KIND=8), DIMENSION(nx,ny), INTENT(IN) :: mapfct
REAL(KIND=8), INTENT(IN) :: dx, dy
REAL(KIND=8), INTENT(IN) :: uhmnhgt, uhmxhgt
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(IN) :: us
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(IN) :: vs
REAL(KIND=8), DIMENSION(nx,ny,nzp1), INTENT(IN) :: w
REAL(KIND=8), DIMENSION(nx,ny), INTENT(OUT) :: uh
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(INOUT) :: tem1
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(INOUT) :: tem2
!NCLEND
! Misc local variables
INTEGER :: i, j, k, kbot, ktop
REAL(KIND=8) :: twodx, twody, wgtlw, sum, wmean, wsum, wavg
REAL(KIND=8) :: helbot, heltop, wbot, wtop
REAL(KIND=8) :: zbot, ztop
! Initialize arrays
uh = 0.0
tem1 = 0.0
! Calculate vertical component of helicity at scalar points
! us: u at scalar points
! vs: v at scalar points
twodx = 2.0*dx
twody = 2.0*dy
DO k=2,nz-2
DO j=2,ny-1
DO i=2,nx-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)) - &
(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))
END DO
END DO
END DO
! Integrate over depth uhminhgt to uhmxhgt AGL
!
! WRITE(6,'(a,f12.1,a,f12.1,a)') &
! 'Calculating UH from ',uhmnhgt,' to ',uhmxhgt,' m AGL'
DO j=2,ny-2
DO i=2,nx-2
zbot = zp(i,j,2) + uhmnhgt
ztop = zp(i,j,2) + uhmxhgt
!
! Find wbar, weighted-mean vertical velocity in column
! Find w at uhmnhgt AGL (bottom)
!
DO k=2,nz-3
IF(zp(i,j,k) > zbot) EXIT
END DO
kbot = k
wgtlw = (zp(i,j,kbot) - zbot)/(zp(i,j,kbot) - zp(i,j,kbot-1))
wbot = (wgtlw*w(i,j,kbot-1)) + ((1.-wgtlw)*w(i,j,kbot))
! Find w at uhmxhgt AGL (top)
DO k=2,nz-3
IF(zp(i,j,k) > ztop) EXIT
END DO
ktop = k
wgtlw = (zp(i,j,ktop) - ztop)/(zp(i,j,ktop) - zp(i,j,ktop-1))
wtop = (wgtlw*w(i,j,ktop-1)) + ((1.-wgtlw)*w(i,j,ktop))
! First part, uhmnhgt to kbot
wsum = 0.5*(w(i,j,kbot) + wbot) * (zp(i,j,kbot) - zbot)
! Integrate up through column
DO k=(kbot+1),(ktop-1)
wsum = wsum + 0.5*(w(i,j,k) + w(i,j,k-1)) * (zp(i,j,k) - zp(i,j,k-1))
END DO
! Last part, ktop-1 to uhmxhgt
wsum = wsum + 0.5*(wtop + w(i,j,ktop-1)) * (ztop - zp(i,j,ktop-1))
wmean = wsum/(uhmxhgt - uhmnhgt)
IF (wmean > 0.) THEN ! column updraft, not downdraft
! Find helicity at uhmnhgt AGL (bottom)
DO k=2,nz-3
IF (tem2(i,j,k) > zbot) EXIT
END DO
kbot = k
wgtlw = (tem2(i,j,kbot) - zbot)/(tem2(i,j,kbot) - tem2(i,j,kbot-1))
helbot = (wgtlw*tem1(i,j,kbot-1)) + ((1.-wgtlw)*tem1(i,j,kbot))
! Find helicity at uhmxhgt AGL (top)
DO k=2,nz-3
IF (tem2(i,j,k) > ztop) EXIT
END DO
ktop = k
wgtlw = (tem2(i,j,ktop) - ztop)/(tem2(i,j,ktop) - tem2(i,j,ktop-1))
heltop = (wgtlw*tem1(i,j,ktop-1)) + ((1.-wgtlw)*tem1(i,j,ktop))
! First part, uhmnhgt to kbot
sum = 0.5*(tem1(i,j,kbot) + helbot) * (tem2(i,j,kbot) - zbot)
! Integrate up through column
DO k=(kbot+1),(ktop-1)
sum = sum + 0.5*(tem1(i,j,k) + tem1(i,j,k-1)) * (tem2(i,j,k) - tem2(i,j,k-1))
END DO
! Last part, ktop-1 to uhmxhgt
uh(i,j) = sum + 0.5*(heltop + tem1(i,j,ktop-1)) * (ztop - tem2(i,j,ktop-1))
END IF
END DO
END DO
uh = uh * 1000. ! Scale according to Kain et al. (2008)
RETURN
END SUBROUTINE DCALCUH

56
fortran/cloud_fracf.f90

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
! NCLFORTSTART
SUBROUTINE DCLOUDFRAC(pres, rh, 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) :: pres, rh
REAL(KIND=8), DIMENSION(ew, ns), INTENT(OUT) :: lowc, midc, highc
! NCLEND
INTEGER i, j, k
INTEGER kchi, kcmi, kclo
! Remove compiler warnings
kchi = 0
kcmi = 0
kclo = 0
DO j = 1,ns
DO i = 1,ew
DO k = 1,nz-1
IF ( pres(i,j,k) .GT. 97000. ) kclo=k
IF ( pres(i,j,k) .GT. 80000. ) kcmi=k
IF ( pres(i,j,k) .GT. 45000. ) kchi=k
END DO
DO k = 1,nz-1
IF (k .GE. kclo .AND. k .LT. kcmi) THEN
lowc(i,j) = AMAX1(rh(i,j,k), lowc(i,j))
ELSE IF (k .GE. kcmi .AND. k .LT. kchi) THEN ! mid cloud
midc(i,j) = AMAX1(rh(i,j,k), midc(i,j))
ELSE if (k .GE. kchi) THEN ! high cloud
highc(i,j) = AMAX1(rh(i,j,k), highc(i,j))
END IF
END DO
lowc(i,j) = 4.0 * lowc(i,j)/100. - 3.0
midc(i,j) = 4.0 * midc(i,j)/100. - 3.0
highc(i,j) = 2.5 * highc(i,j)/100. - 1.5
lowc(i,j) = amin1(lowc(i,j), 1.0)
lowc(i,j) = amax1(lowc(i,j), 0.0)
midc(i,j) = amin1(midc(i,j), 1.0)
midc(i,j) = amax1(midc(i,j), 0.0)
highc(i,j) = amin1(highc(i,j), 1.0)
highc(i,j) = amax1(highc(i,j), 0.0)
END DO
END DO
RETURN
END SUBROUTINE DCLOUDFRAC

64
fortran/constants.f90

@ -1,10 +1,66 @@ @@ -1,10 +1,66 @@
! These are chosen to match the wrf module_model_constants.F where
! applicable
MODULE constants
INTEGER :: ERRLEN=512
INTEGER :: ALGERR=64
REAL(KIND=8), PARAMETER :: WRF_EARTH_RADIUS = 6370000.D0
REAL(KIND=8), PARAMETER :: T_BASE = 300.0
REAL(KIND=8), PARAMETER :: PI = 3.1415926535897932384626433D0
REAL(KIND=8), PARAMETER :: RAD_PER_DEG = PI/180.D0
REAL(KIND=8), PARAMETER :: DEG_PER_RAD = 180.D0/PI
REAL(KIND=8), PARAMETER :: DEFAULT_FILL = 9.9692099683868690D36
REAL(KIND=8), PARAMETER :: P1000MB = 100000.D0
REAL(KIND=8), PARAMETER :: R_D=287.D0
REAL(KIND=8), PARAMETER :: CP=7.D0*R_D/2.D0
REAL(KIND=8), PARAMETER :: R=287.04D0
! j/k/kg
REAL(KIND=8), PARAMETER :: RD = 287.D0
REAL(KIND=8), PARAMETER :: RV = 461.6D0
!REAL(KIND=8), PARAMETER :: RV = 461.5D0
! j/k/kg note: not using bolton's value of 1005.7
REAL(KIND=8), PARAMETER :: CP = 1004.5D0
!REAL(KIND=8), PARAMETER :: CP = 1004D0
REAL(KIND=8), PARAMETER :: G = 9.81D0
REAL(KIND=8), PARAMETER :: GAMMA=0.0065D0
REAL(KIND=8), PARAMETER :: USSALR = 0.0065D0 ! deg C per m
REAL(KIND=8), PARAMETER :: CELKEL = 273.15D0
REAL(KIND=8), PARAMETER :: CELKEL_TRIPLE = 273.16D0
!REAL(KIND=8), PARAMETER :: GRAV = 9.81D0
! hpa
REAL(KIND=8), PARAMETER :: EZERO = 6.112D0
REAL(KIND=8), PARAMETER :: ESLCON1 = 17.67D0
REAL(KIND=8), PARAMETER :: ESLCON2 = 29.65D0
REAL(KIND=8), PARAMETER :: EPS = 0.622D0
REAL(KIND=8), PARAMETER :: GAMMA = RD/CP
! cp_moist=cp*(1.+cpmd*qvp)
REAL(KIND=8), PARAMETER :: CPMD = .887D0
! rgas_moist=rgas*(1.+rgasmd*qvp)
REAL(KIND=8), PARAMETER :: RGASMD = .608D0
! gamma_moist=gamma*(1.+gammamd*qvp)
REAL(KIND=8), PARAMETER :: GAMMAMD = RGASMD - CPMD
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
! k
REAL(KIND=8), PARAMETER :: THTECON1 = 3376.D0
REAL(KIND=8), PARAMETER :: THTECON2 = 2.54D0
REAL(KIND=8), PARAMETER :: THTECON3 = .81D0
REAL(KIND=8), PARAMETER :: ABSCOEFI = .272D0 ! cloud ice absorption coefficient in m^2/g
REAL(KIND=8), PARAMETER :: ABSCOEF = .145D0 ! cloud water absorption coefficient in m^2/g
REAL(KIND=8), PARAMETER :: GAMMA_SEVEN = 720.D0
REAL(KIND=8), PARAMETER :: RHOWAT = 1000.D0
REAL(KIND=8), PARAMETER :: RHO_R = RHOWAT
REAL(KIND=8), PARAMETER :: RHO_S = 100.D0
REAL(KIND=8), PARAMETER :: RHO_G = 400.D0
REAL(KIND=8), PARAMETER :: ALPHA = 0.224D0
REAL(KIND=8), PARAMETER :: SCLHT = RD*256.D0/G
REAL(KIND=8), PARAMETER :: EXPON = RD*USSALR/G
REAL(KIND=8), PARAMETER :: EXPONI = 1./EXPON
END MODULE constants

51
fortran/eqthecalc.f90

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
! Theta-e
!NCLFORTSTART
SUBROUTINE DEQTHECALC(qvp, tmk, prs, eth, miy, mjx, mkzh)
USE constants, ONLY : EPS, GAMMA, GAMMAMD, TLCLC1, TLCLC2, TLCLC3, TLCLC4, &
THTECON1, THTECON2, THTECON3
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: eth
! Input variables
! Sizes
INTEGER,INTENT(IN) :: miy, mjx, mkzh
! Qvapor [g/kg]
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(IN) :: qvp
! Temperature [K]
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(IN) :: tmk
! full pressure (=P+PB) [hPa]
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(IN) :: prs
! Output variable
! equivalent potential temperature [K]
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(OUT) :: eth
!NCLEND
! local variables
REAL(KIND=8) :: q
REAL(KIND=8) :: t
REAL(KIND=8) :: p
REAL(KIND=8) :: e
REAL(KIND=8) :: tlcl
INTEGER :: i, j, k
DO k = 1,mkzh
DO j = 1,mjx
DO i = 1,miy
q = MAX(qvp(i,j,k), 1.D-15)
t = tmk(i,j,k)
p = prs(i,j,k)/100.
e = q*p/(EPS + q)
tlcl = TLCLC1/(LOG(t**TLCLC2/e) - TLCLC3) + TLCLC4
eth(i,j,k) = t*(1000.D0/p)**(GAMMA*(1.D0 + GAMMAMD*q))* &
EXP((THTECON1/tlcl - THTECON2)*q*(1.D0 + THTECON3*q))
END DO
END DO
END DO
RETURN
END SUBROUTINE DEQTHECALC

0
src/wrf/wrfcape.f90 → fortran/reference/wrfcape.f90

0
src/wrf/wrfcape.pyf → fortran/reference/wrfcape.pyf

0
src/wrf/wrfext.f90 → fortran/reference/wrfext.f90

0
src/wrf/wrfext.pyf → fortran/reference/wrfext.pyf

0
src/wrf/wrfext2.f90.BAK → fortran/reference/wrfext2.f90.BAK

1018
fortran/ripW.c

File diff suppressed because it is too large Load Diff

617
fortran/rip_cape.f90

@ -0,0 +1,617 @@ @@ -0,0 +1,617 @@
!======================================================================
!
! !IROUTINE: VIRTUAL -- Calculate virtual temperature (K)
!
! !DESCRIPTION:
!
! This function returns a single value of virtual temperature in
! K, given temperature in K and mixing ratio in kg/kg. For an
! array of virtual temperatures, use subroutine VIRTUAL_TEMP.
!
! !INPUT:
! RATMIX - water vapor mixing ratio (kg/kg)
! TEMP - temperature (K)
!
! !OUTPUT:
! TV - Virtual temperature (K)
!
! NCLFORTSTART
REAL(KIND=8) FUNCTION TVIRTUAL(temp, ratmix)
USE constants, ONLY : EPS
!f2py threadsafe
IMPLICIT NONE
REAL(KIND=8), INTENT(IN) :: temp, ratmix
! NCLEND
TVIRTUAL = temp*(EPS + ratmix)/(EPS*(1.D0 + ratmix))
RETURN
END FUNCTION TVIRTUAL
! NCLFORTSTART
REAL(KIND=8) FUNCTION TONPSADIABAT(thte,prs,psadithte,psadiprs,psaditmk,gamma,&
errstat, errmsg)
USE constants, ONLY : ALGERR
!f2py threadsafe
!f2py intent(in,out) :: cape, cin
IMPLICIT NONE
REAL(KIND=8), INTENT(IN) :: thte
REAL(KIND=8), INTENT(IN) :: prs
REAL(KIND=8), DIMENSION(150), INTENT(IN) :: psadithte
REAL(KIND=8), DIMENSION(150), INTENT(IN) :: psadiprs
REAL(KIND=8), DIMENSION(150,150), INTENT(IN) :: psaditmk
REAL(KIND=8), INTENT(IN) :: gamma
INTEGER, INTENT(INOUT) :: errstat
CHARACTER(LEN=*), INTENT(INOUT) :: errmsg
! NCLEND
REAL(KIND=8) :: fracjt
REAL(KIND=8) :: fracjt2
REAL(KIND=8) :: fracip
REAL(KIND=8) :: fracip2
INTEGER :: ip, ipch, jt, jtch
! This function gives the temperature (in K) on a moist adiabat
! (specified by thte in K) given pressure in hPa. It uses a
! lookup table, with data that was generated by the Bolton (1980)
! formula for theta_e.
! First check if pressure is less than min pressure in lookup table.
! If it is, assume parcel is so dry that the given theta-e value can
! be interpretted as theta, and get temperature from the simple dry
! theta formula.
IF (prs .LE. psadiprs(150)) THEN
TONPSADIABAT = thte * (prs/1000.D0)**gamma
RETURN
END IF
! Otherwise, look for the given thte/prs point in the lookup table.
jt = -1
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
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
! Set the error and return
TONPSADIABAT = -1
errstat = ALGERR
WRITE(errmsg, *) "capecalc3d: Outside of lookup table bounds. prs,thte=", prs, thte
RETURN
END IF
fracjt = (thte-psadithte(jt)) / (psadithte(jt+1)-psadithte(jt))
fracjt2 = 1.D0 - fracjt
fracip = (psadiprs(ip)-prs) / (psadiprs(ip)-psadiprs(ip+1))
fracip2 = 1.D0 - fracip
IF (psaditmk(ip,jt) .GT. 1D9 .OR. psaditmk(ip+1,jt) .GT. 1D9 .OR. &
psaditmk(ip,jt+1) .GT. 1D9 .OR. psaditmk(ip+1,jt+1) .GT. 1D9) THEN
! Set the error and return
TONPSADIABAT = -1
errstat = ALGERR
WRITE(errmsg, *) "capecalc3d: Tried to access missing temperature in lookup table. ", &
"Prs and Thte probably unreasonable. prs,thte=", prs, thte
RETURN
END IF
TONPSADIABAT = fracip2*fracjt2*psaditmk(ip,jt) + fracip*fracjt2*psaditmk(ip+1,jt) + &
fracip2*fracjt*psaditmk(ip,jt+1) + fracip*fracjt*psaditmk(ip+1,jt+1)
RETURN
END FUNCTION TONPSADIABAT
!NCLFORTSTART
SUBROUTINE DLOOKUP_TABLE(psadithte, psadiprs, psaditmk, fname, errstat, errmsg)
USE constants, ONLY : ALGERR
!f2py threadsafe
REAL(KIND=8), DIMENSION(150), INTENT(INOUT) :: psadithte, psadiprs
REAL(KIND=8), DIMENSION(150,150), INTENT(INOUT) :: psaditmk
CHARACTER(LEN=*), INTENT(IN) :: fname
INTEGER, INTENT(INOUT) :: errstat
CHARACTER(LEN=*), INTENT(INOUT) :: errmsg
!NCLEND
! Locals
INTEGER :: iustnlist, i, nthte, nprs, ip, jt
! FNAME = 'psadilookup.dat'
iustnlist = 33
OPEN (UNIT=iustnlist, FILE=fname, FORM='formatted', STATUS='old')
DO i = 1,14
READ (iustnlist, FMT=*)
END DO
READ (iustnlist, FMT=*) nthte, nprs
IF (nthte .NE. 150 .OR. nprs .NE. 150) THEN
errstat = ALGERR
errmsg = "Number of pressure or theta_e levels in lookup table file not 150"
RETURN
END IF
READ (iustnlist, FMT="(5D15.7)") (psadithte(jt),jt=1,nthte)
READ (iustnlist, FMT="(5D15.7)") (psadiprs(ip),ip=1,nprs)
READ (iustnlist, FMT="(5D15.7)") ((psaditmk(ip,jt),ip=1,nprs),jt=1,nthte)
CLOSE (iustnlist)
RETURN
END SUBROUTINE DLOOKUP_TABLE
! Historically, this routine calculated the pressure at full sigma
! levels when RIP was specifically designed for MM4/MM5 output.
! With the new generalized RIP (Feb '02), this routine is still
! intended to calculate a set of pressure levels that bound the
! layers represented by the vertical grid points, although no such
! layer boundaries are assumed to be defined. The routine simply
! uses the midpoint between the pressures of the vertical grid
! points as the bounding levels. The array only contains mkzh
! levels, so the pressure of the top of the uppermost layer is
! actually excluded. The kth value of pf is the lower bounding
! pressure for the layer represented by kth data level. At the
! lower bounding level of the lowest model layer, it uses the
! surface pressure, unless the data set is pressure-level data, in
! which case it assumes the lower bounding pressure level is as far
! below the lowest vertical level as the upper bounding pressure
! level is above.
SUBROUTINE DPFCALC(prs, sfp, pf, miy, mjx, mkzh, ter_follow)
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(IN) :: prs
REAL(KIND=8), DIMENSION(miy,mjx), INTENT(IN) :: sfp
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(OUT) :: pf
INTEGER, INTENT(IN) :: ter_follow,miy,mjx,mkzh
INTEGER :: i,j,k
! do j=1,mjx-1 Artifact of MM5
DO j = 1,mjx
! do i=1,miy-1 staggered grid
DO i = 1,miy
DO k = 1,mkzh
IF (k .EQ. mkzh) THEN
! terrain-following data
IF (ter_follow .EQ. 1) THEN
pf(i,j,k) = sfp(i,j)
! pressure-level data
ELSE
pf(i,j,k) = .5D0 * (3.D0*prs(i,j,k) - prs(i,j,k-1))
END IF
ELSE
pf(i,j,k) = .5D0 * (prs(i,j,k+1) + prs(i,j,k))
END IF
END DO
END DO
END DO
RETURN
END SUBROUTINE DPFCALC
!======================================================================
!
! !IROUTINE: capecalc3d -- Calculate CAPE and CIN
!
! !DESCRIPTION:
!
! If i3dflag=1, this routine calculates CAPE and CIN (in m**2/s**2,
! or J/kg) for every grid point in the entire 3D domain (treating
! each grid point as a parcel). If i3dflag=0, then it
! 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",
! we mean a 500-m deep parcel, with actual temperature and moisture
! 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
! the cape and cin arrays. Also, if i3dflag=0, LCL and LFC heights
! 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
! 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,miy,mjx,mkzh,i3dflag,ter_follow,&
psafile, errstat, errmsg)
USE constants, ONLY : ALGERR, CELKEL, G, EZERO, ESLCON1, ESLCON2, &
EPS, RD, CP, GAMMA, CPMD, RGASMD, GAMMAMD, TLCLC1, &
TLCLC2, TLCLC3, TLCLC4, THTECON1, THTECON2, THTECON3
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: cape, cin
INTEGER, INTENT(IN) :: miy,mjx,mkzh,i3dflag,ter_follow
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(IN) :: prs
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(IN) :: tmk
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(IN) :: qvp
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(IN) :: ght
REAL(KIND=8), DIMENSION(miy,mjx), INTENT(IN) :: ter
REAL(KIND=8), DIMENSION(miy,mjx), INTENT(IN) ::sfp
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(OUT) :: cape
REAL(KIND=8), DIMENSION(miy,mjx,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, kpar1, kpar2
REAL(KIND=8) :: davg, ethmax, q, t, p, e, eth, tlcl, zlcl
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) :: facden, fac1, fac2, qvplift, tmklift, tvenv, tvlift, ghtlift
REAL(KIND=8) :: eslift, tmkenv, qvpenv, tonpsadiabat
REAL(KIND=8) :: benamin, dz, pup, pdn
REAL(KIND=8), DIMENSION(150) :: buoy, zrel, benaccum
REAL(KIND=8), DIMENSION(miy,mjx,mkzh) :: prsf
REAL(KIND=8), DIMENSION(150) :: psadithte, psadiprs
REAL(KIND=8), DIMENSION(150,150) :: psaditmk
LOGICAL :: elfound
! To remove compiler warnings
tmkpari = 0
qvppari = 0
klev = 0
klcl = 0
kel = 0
! 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)
CALL DPFCALC(prs, sfp, prsf, miy, mjx, 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
! do j=1,mjx-1
DO j = 1,mjx
! do i=1,miy-1
DO i = 1,miy
cape(i,j,1) = 0.d0
cin(i,j,1) = 0.d0
IF (i3dflag .EQ. 1) THEN
kpar1 = 2
kpar2 = mkzh
ELSE
! find parcel with max theta-e in lowest 3 km agl.
ethmax = -1.d0
DO k = mkzh,1,-1
IF (ght(i,j,k)-ter(i,j) .LT. 3000.d0) THEN
q = MAX(qvp(i,j,k), 1.d-15)
t = tmk(i,j,k)
p = prs(i,j,k)
e = q*p/(EPS + q)
tlcl = TLCLC1 / (LOG(t**TLCLC2/e)-TLCLC3) + TLCLC4
eth = t * (1000.d0/p)**(GAMMA*(1.d0 + GAMMAMD*q))*&
EXP((THTECON1/tlcl - THTECON2)*q*(1.d0 + THTECON3*q))
IF (eth .GT. ethmax) THEN
klev = k
ethmax = eth
END IF
END IF
END DO
kpar1 = klev
kpar2 = klev
! Establish average properties of that parcel
! (over depth of approximately davg meters)
! davg=.1
davg = 500.d0
pavg = davg*prs(i,j,kpar1)*&
G/(RD*tvirtual(tmk(i,j,kpar1), qvp(i,j,kpar1)))
p2 = MIN(prs(i,j,kpar1)+.5d0*pavg, prsf(i,j,mkzh))
p1 = p2 - pavg
totthe = 0.d0
totqvp = 0.d0
totprs = 0.d0
DO k = mkzh,2,-1
IF (prsf(i,j,k) .LE. p1) EXIT !GOTO 35
IF (prsf(i,j,k-1) .GE. p2) CYCLE !GOTO 34
p = prs(i,j,k)
pup = prsf(i,j,k)
pdn = prsf(i,j,k-1)
q = MAX(qvp(i,j,k),1.d-15)
th = tmk(i,j,k)*(1000.d0/p)**(GAMMA*(1.d0 + GAMMAMD*q))
pp1 = MAX(p1,pdn)
pp2 = MIN(p2,pup)
IF (pp2 .GT. pp1) THEN
deltap = pp2 - pp1
totqvp = totqvp + q*deltap
totthe = totthe + th*deltap
totprs = totprs + deltap
END IF
! 34 CONTINUE
END DO
! 35 CONTINUE
qvppari = totqvp/totprs
tmkpari = (totthe/totprs)*&
(prs(i,j,kpar1)/1000.d0)**(GAMMA*(1.d0+GAMMAMD*qvp(i,j,kpar1)))
END IF
DO kpar = kpar1, kpar2
! Calculate temperature and moisture properties of parcel
! (note, qvppari and tmkpari already calculated above for 2d case.)
IF (i3dflag .EQ. 1) THEN
qvppari = qvp(i,j,kpar)
tmkpari = tmk(i,j,kpar)
END IF
prspari = prs(i,j,kpar)
ghtpari = ght(i,j,kpar)
gammam = GAMMA * (1.d0 + GAMMAMD*qvppari)
cpm = CP * (1.d0 + CPMD*qvppari)
e = MAX(1.d-20,qvppari*prspari/(EPS + qvppari))
tlcl = TLCLC1/(LOG(tmkpari**TLCLC2/e) - TLCLC3) + TLCLC4
ethpari = tmkpari*(1000.d0/prspari)**(GAMMA*(1.d0 + GAMMAMD*qvppari))*&
EXP((THTECON1/tlcl - THTECON2)*qvppari*(1.d0 + THTECON3*qvppari))
zlcl = ghtpari + (tmkpari - tlcl)/(G/cpm)
! 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 (ghtpari .GE. zlcl) THEN
! Initial parcel already saturated or supersaturated.
ilcl = 2
klcl = 1
END IF
k = kpar
DO WHILE (k .GE. 1)!k = kpar, 1, -1
!DO k = kpar, 1, -1
! For arrays that go bottom to top
! 33 kk = kk + 1
kk = kk + 1
! Model level is below lcl
IF (ght(i,j,k) .LT. zlcl) THEN
qvplift = qvppari
tmklift = tmkpari - G/cpm*(ght(i,j,k) - ghtpari)
tvenv = tvirtual(tmk(i,j,k), qvp(i,j,k))
tvlift = tvirtual(tmklift, qvplift)
ghtlift = ght(i,j,k)
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.
tmklift = tlcl
qvplift = qvppari
facden = ght(i,j,k) - ght(i,j,k+1)
fac1 = (zlcl-ght(i,j,k+1))/facden
fac2 = (ght(i,j,k)-zlcl)/facden
tmkenv = tmk(i,j,k+1)*fac2 + tmk(i,j,k)*fac1
qvpenv = qvp(i,j,k+1)*fac2 + qvp(i,j,k)*fac1
tvenv = tvirtual(tmkenv, qvpenv)
tvlift = tvirtual(tmklift, qvplift)
ghtlift = zlcl
ilcl = 1
ELSE
tmklift = TONPSADIABAT(ethpari, prs(i,j,k), psadithte, psadiprs,&
psaditmk, GAMMA, errstat, errmsg)
eslift = EZERO*EXP(ESLCON1*(tmklift - CELKEL)/(tmklift - ESLCON2))
qvplift = EPS*eslift/(prs(i,j,k) - eslift)
tvenv = tvirtual(tmk(i,j,k), qvp(i,j,k))
tvlift = tvirtual(tmklift, qvplift)
ghtlift = ght(i,j,k)
END IF
! Buoyancy
buoy(kk) = G*(tvlift - tvenv)/tvenv
zrel(kk) = ghtlift - ghtpari
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
!GOTO 33
CYCLE
END IF
k = k - 1
END DO
kmax = kk
IF (kmax .GT. 150) THEN
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
!GOTO 50
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.
! cape(i,j,kpar) = -0.1d0
! cin(i,j,kpar) = -0.1d0
IF (.NOT. elfound) THEN
cape(i,j,kpar) = cmsg
cin(i,j,kpar) = cmsg
klfc = kmax
CYCLE
END IF
! GOTO 102
! 50 CONTINUE
! 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) = -0.1d0
IF (cape(i,j,kpar) .LT. 100.d0) cin(i,j,kpar) = cmsg
! 102 CONTINUE
END DO
IF (i3dflag .EQ. 0) THEN
cape(i,j,mkzh) = cape(i,j,kpar1)
cin(i,j,mkzh) = cin(i,j,kpar1)
! meters agl
cin(i,j,mkzh-1) = zrel(klcl) + ghtpari - ter(i,j)
! meters agl
cin(i,j,mkzh-2) = zrel(klfc) + ghtpari - ter(i,j)
ENDIF
END DO
END DO
RETURN
END SUBROUTINE DCAPECALC3D

13330
fortran/wrfW.c

File diff suppressed because it is too large Load Diff

125
fortran/wrf_fctt.f90

@ -0,0 +1,125 @@ @@ -0,0 +1,125 @@
!NCLFORTSTART
SUBROUTINE wrfcttcalc(prs, tk, qci, qcw, qvp, ght, ter, ctt, haveqci, ew, ns, nz)
USE constants, ONLY : EPS, USSALR, RD, G, ABSCOEFI, ABSCOEF, CELKEL
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: ctt
INTEGER, INTENT(IN) :: nz, ns, ew, haveqci
REAL(KIND=8), DIMENSION(ew,ns,nz), INTENT(IN) :: ght, prs, tk, qci, qcw, qvp
REAL(KIND=8), DIMENSION(ew,ns), INTENT(IN) :: ter
REAL(KIND=8), DIMENSION(ew,ns), INTENT(OUT) :: ctt
!NCLEND
! REAL(KIND=8) :: znfac(nz)
! LOCAL VARIABLES
INTEGER i,j,k,ripk
!INTEGER :: mjx,miy,mkzh
REAL(KIND=8) :: vt,opdepthu,opdepthd,dp
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) :: p1, p2
!mjx = ew
!miy = ns
!mkzh = nz
prsctt = 0 ! removes the warning
! Calculate the surface pressure
DO j=1,ns
DO i=1,ew
ratmix = .001d0*qvp(i,j,1)
arg1 = EPS + ratmix
arg2 = EPS * (1. + ratmix)
vt = tk(i,j,1) * arg1/arg2 !Virtual temperature
agl_hgt = ght(i,j,nz) - ter(i,j)
arg1 = -G / (RD * USSALR)
pf(i,j,nz) = prs(i,j,1) * (vt / (vt + USSALR*(agl_hgt)))**(arg1)
END DO
END DO
DO k=1,nz-1
DO j=1,ns
DO i=1,ew
ripk = nz-k+1
pf(i,j,k) = .5d0 * (prs(i,j,ripk) + prs(i,j,ripk-1))
END DO
END DO
END DO
DO j=1,ns
DO i=1,ew
opdepthd = 0.d0
k = 0
! Integrate downward from model top, calculating path at full
! model vertical levels.
!20 opdepthu=opdepthd
DO k=1, nz
opdepthu = opdepthd
!k=k+1
ripk = nz - k + 1
IF (k .EQ. 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
END IF
IF (haveqci .EQ. 0) then
IF (tk(i,j,k) .LT. CELKEL) then
! Note: abscoefi is m**2/g, qcw is g/kg, so no convrsion needed
opdepthd = opdepthu + ABSCOEFI*qcw(i,j,k) * dp/G
ELSE
opdepthd = opdepthu + ABSCOEF*qcw(i,j,k) * dp/G
END IF
ELSE
opdepthd = opdepthd + (ABSCOEF*qcw(i,j,ripk) + ABSCOEFI*qci(i,j,ripk)) * dp/G
END IF
IF (opdepthd .LT. 1. .AND. k .LT. nz) THEN
!GOTO 20
CYCLE
ELSE IF (opdepthd .LT. 1. .AND. k .EQ. nz) THEN
prsctt = prs(i,j,1)
EXIT
ELSE
fac = (1. - opdepthu) / (opdepthd - opdepthu)
prsctt = pf(i,j,k-1) + fac*(pf(i,j,k) - pf(i,j,k-1))
prsctt = MIN(prs(i,j,1), MAX(prs(i,j,nz), prsctt))
EXIT
END IF
END DO
DO k=2,nz
ripk = nz-k+1
p1 = prs(i,j,ripk+1)
p2 = prs(i,j,ripk)
IF (prsctt .GE. p1 .AND. prsctt .LE. p2) THEN
fac = (prsctt - p1) / (p2 - p1)
arg1 = fac * (tk(i,j,ripk) - tk(i,j,ripk+1)) - CELKEL
ctt(i,j) = tk(i,j,ripk+1) + arg1
!GOTO 40
EXIT
END IF
END DO
END DO
END DO
! 30 CONTINUE
! 40 CONTINUE
! 190 CONTINUE
RETURN
END SUBROUTINE wrfcttcalc

122
fortran/wrf_pvo.f90

@ -0,0 +1,122 @@ @@ -0,0 +1,122 @@
!NCLFORTSTART
SUBROUTINE DCOMPUTEABSVORT(av, u, v, msfu, msfv, msft, cor, dx, dy, nx, ny, nz,&
nxp1, nyp1)
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: av
INTEGER, INTENT(IN) :: nx, ny, nz, nxp1, nyp1
REAL(KIND=8), DIMENSION(nxp1,ny,nz), INTENT(IN) :: u
REAL(KIND=8), DIMENSION(nx,nyp1,nz), INTENT(IN) :: v
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(OUT) :: av
REAL(KIND=8), DIMENSION(nxp1,ny), INTENT(IN):: msfu
REAL(KIND=8), DIMENSION(nx,nyp1), INTENT(IN) :: msfv
REAL(KIND=8), DIMENSION(nx,ny), INTENT(IN) :: msft
REAL(KIND=8), DIMENSION(nx,ny), INTENT(IN) :: cor
REAL(KIND=8) :: dx, dy
!NCLEND
INTEGER :: jp1, jm1, ip1, im1, i, j, k
REAL(KIND=8) :: dsy, dsx, dudy, dvdx, avort
REAL(KIND=8) :: mm
! PRINT*,'nx,ny,nz,nxp1,nyp1'
! PRINT*,nx,ny,nz,nxp1,nyp1
DO k = 1,nz
DO j = 1,ny
jp1 = MIN(j+1, ny)
jm1 = MAX(j-1, 1)
DO i = 1,nx
ip1 = MIN(i+1, nx)
im1 = MAX(i-1, 1)
! PRINT *,jp1,jm1,ip1,im1
dsx = (ip1 - im1) * dx
dsy = (jp1 - jm1) * dy
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) - &
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) - &
v(im1,j,k)/msfv(im1,j) - v(im1,j+1,k)/msfv(im1,j+1))/dsx*mm
avort = dvdx - dudy + cor(i,j)
av(i,j,k) = avort*1.D5
END DO
END DO
END DO
RETURN
END SUBROUTINE DCOMPUTEABSVORT
!NCLFORTSTART
SUBROUTINE DCOMPUTEPV(pv, u, v, theta, prs, msfu, msfv, msft, cor, dx, dy, nx, &
ny, nz, nxp1, nyp1)
USE constants, ONLY : G
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: pv
INTEGER,INTENT(IN) :: nx, ny, nz, nxp1, nyp1
REAL(KIND=8), DIMENSION(nxp1,ny,nz), INTENT(IN) :: u
REAL(KIND=8), DIMENSION(nx,nyp1,nz), INTENT(IN) :: v
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(IN) :: prs
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(IN) :: theta
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(OUT) :: pv
REAL(KIND=8), DIMENSION(nxp1,ny), INTENT(IN) :: msfu
REAL(KIND=8), DIMENSION(nx,nyp1), INTENT(IN) :: msfv
REAL(KIND=8), DIMENSION(nx,ny), INTENT(IN) :: msft
REAL(KIND=8), DIMENSION(nx,ny), INTENT(IN) :: cor
REAL(KIND=8) :: dx,dy
!NCLEND
INTEGER :: kp1, km1, jp1, jm1, ip1, im1, i, j, k
REAL(KIND=8) :: dsy, dsx, dp, dudy, dvdx, dudp, dvdp, dthdp, avort
REAL(KIND=8) :: dthdx, dthdy, mm
! PRINT*,'nx,ny,nz,nxp1,nyp1'
! PRINT*,nx,ny,nz,nxp1,nyp1
DO k = 1,nz
kp1 = MIN(k+1, nz)
km1 = MAX(k-1, 1)
DO J = 1,ny
jp1 = MIN(j+1, ny)
jm1 = MAX(j-1, 1)
DO i = 1,nx
ip1 = MIN(i+1, nx)
im1 = MAX(i-1, 1)
! PRINT *,jp1,jm1,ip1,im1
dsx = (ip1 - im1) * dx
dsy = (jp1 - jm1) * dy
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) - &
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) - &
v(im1,j,k)/msfv(im1,j) - v(im1,j+1,k)/msfv(im1,j+1))/dsx*mm
avort = dvdx - dudy + cor(i,j)
dp = prs(i,j,kp1) - prs(i,j,km1)
dudp = 0.5D0 * (u(i,j,kp1) + u(i+1,j,kp1) - u(i,j,km1) - u(i+1,j,km1))/dp
dvdp = 0.5D0 * (v(i,j,kp1) + v(i,j+1,kp1) - v(i,j,km1) - v(i,J+1,km1))/dp
dthdp = (theta(i,j,kp1) - theta(i,j,km1))/dp
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)
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
END DO
END DO
END DO
RETURN
END SUBROUTINE DCOMPUTEPV

31
fortran/wrf_pw.f90

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
!NCLFORTSTART
SUBROUTINE DCOMPUTEPW(p, tv, qv, ht, pw, nx, ny, nz, nzh)
USE constants, ONLY : RD
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: pw
INTEGER, INTENT(IN) :: nx, ny, nz, nzh
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(IN) :: p, tv, qv
REAL(KIND=8), DIMENSION(nx,ny,nzh), INTENT(IN) :: ht
REAL(KIND=8), DIMENSION(nx,ny), INTENT(OUT) :: pw
!NCLEND
INTEGER :: i, j, k
!REAL(KIND=8),PARAMETER :: R=287.06
pw = 0
DO k=1,nz
DO j=1,ny
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)))
END DO
END DO
END DO
RETURN
END SUBROUTINE DCOMPUTEPW

84
fortran/wrf_relhl.f90

@ -0,0 +1,84 @@ @@ -0,0 +1,84 @@
! NCLFORTSTART
SUBROUTINE DCALRELHL(u, v, ght, ter, top, sreh, miy, mjx, mkzh)
USE constants, ONLY : PI, RAD_PER_DEG, DEG_PER_RAD
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: sreh
INTEGER, INTENT(IN) :: miy, mjx, mkzh
REAL(KIND=8), DIMENSION(miy,mjx,mkzh), INTENT(IN) :: u, v, ght
REAL(KIND=8), INTENT(IN) :: top
REAL(KIND=8), DIMENSION(miy,mjx), INTENT(IN) :: ter
REAL(KIND=8), DIMENSION(miy,mjx), INTENT(OUT) :: sreh
! NCLEND
! This helicity code was provided by Dr. Craig Mattocks, and
! verified by Cindy Bruyere to produce results equivalent to
! those generated by RIP4. (The code came from RIP4?)
REAL(KIND=8) :: dh, sdh, su, sv, ua, va, asp, adr, bsp, bdr
REAL(KIND=8) :: cu, cv, x, sum
INTEGER :: i, j, k, k10, k3, ktop
!REAL(KIND=8), PARAMETER :: DTR=PI/180.d0, DPR=180.d0/PI
DO j = 1, mjx-1
DO i = 1, miy-1
sdh = 0.d0
su = 0.d0
sv = 0.d0
k3 = 0
k10 = 0
ktop = 0
DO k = mkzh, 2, -1
IF (((ght(i,j,k) - ter(i,j)) .GT. 10000.D0) .AND. (k10 .EQ. 0)) THEN
k10 = k
EXIT
ENDIF
IF (((ght(i,j,k) - ter(i,j)) .GT. top) .AND. (ktop .EQ. 0)) THEN
ktop = k
ENDIF
IF (((ght(i,j,k) - ter(i,j)) .GT. 3000.D0) .AND. (k3 .EQ. 0)) THEN
k3 = k
ENDIF
END DO
IF (k10 .EQ. 0) THEN
k10 = 2
ENDIF
DO k = k3, k10, -1
dh = ght(i,j,k-1) - ght(i,j,k)
sdh = sdh + dh
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))
END DO
ua = su / sdh
va = sv / sdh
asp = SQRT(ua*ua + va*va)
IF (ua .EQ. 0.D0 .AND. va .EQ. 0.D0) THEN
adr = 0.D0
ELSE
adr = DEG_PER_RAD * (PI + ATAN2(ua,va))
ENDIF
bsp = 0.75D0 * asp
bdr = adr + 30.D0
IF (bdr .GT. 360.D0) THEN
bdr = bdr - 360.D0
ENDIF
cu = -bsp * SIN(bdr * RAD_PER_DEG)
cv = -bsp * COS(bdr * RAD_PER_DEG)
sum = 0.D0
DO k = mkzh-1, ktop, -1
x = ((u(i,j,k) - cu) * (v(i,j,k) - v(i,j,k+1))) - &
((v(i,j,k) - cv) * (u(i,j,k) - u(i,j,k+1)))
sum = sum + x
END DO
sreh(i,j) = -sum
END DO
END DO
RETURN
END SUBROUTINE DCALRELHL

269
fortran/wrf_rip_phys_routines.f90

@ -0,0 +1,269 @@ @@ -0,0 +1,269 @@
!======================================================================
!
! !IROUTINE: WETBULBCALC -- Calculate wet bulb temperature (C)
!
! !DESCRIPTION:
!
! Calculates wet bulb temperature in C, given pressure in
! temperature in K and mixing ratio in kg/kg.
!
! !INPUT:
! nx - index for x dimension
! ny - index for y dimension
! nz - index for z dimension
! prs - pressure (mb)
! tmk - temperature (K)
! qvp - water vapor mixing ratio (kg/kg)
!
! !OUTPUT:
! twb - Wet bulb temperature (C)
!
! !ASSUMPTIONS:
!
! !REVISION HISTORY:
! 2009-March - Mark T. Stoelinga - from RIP4.5
! 2010-August - J. Schramm
! 2014-March - A. Jaye - modified to run with NCL and ARW wrf output
!
! !INTERFACE:
! ------------------------------------------------------------------
! NCLFORTSTART
SUBROUTINE WETBULBCALC(prs, tmk, qvp, twb, nx, ny, nz, psafile, errstat, errmsg)
USE constants, ONLY : ALGERR, GAMMA, GAMMAMD, TLCLC1, TLCLC2, TLCLC3, &
EPS, TLCLC4, THTECON1, THTECON2, THTECON3
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: twb
INTEGER, INTENT(IN) :: nx, ny, nz
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(IN) :: prs
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(IN) :: tmk
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(IN) :: qvp
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(OUT) :: twb
CHARACTER(LEN=*), INTENT(IN) :: psafile
INTEGER, INTENT(INOUT) :: errstat
CHARACTER(LEN=*), INTENT(INOUT) :: errmsg
!NCLEND
INTEGER :: i, j, k
INTEGER :: jtch, jt, ipch, ip
REAL(KIND=8) :: q, t, p, e, tlcl, eth
REAL(KIND=8) :: fracip, fracip2, fracjt, fracjt2
REAL(KIND=8), DIMENSION(150) :: PSADITHTE, PSADIPRS
REAL(KIND=8), DIMENSION(150,150) :: PSADITMK
REAL(KIND=8) :: tonpsadiabat
! 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
DO k=1,nz
DO j=1,ny
DO i=1,nx
q = DMAX1(qvp(i,j,k), 1.D-15)
t = tmk(i,j,k)
p = prs(i,j,k)/100.
e = q*p/(EPS + q)
tlcl = TLCLC1/(DLOG(t**TLCLC2/e) - TLCLC3) + TLCLC4
eth = t*(1000./p)**(GAMMA*(1. + GAMMAMD*q))*&
EXP((THTECON1/tlcl - THTECON2)*q*(1. + THTECON3*q))
! Now we need to find the temperature (in K) on a moist adiabat
! (specified by eth in K) given pressure in hPa. It uses a
! lookup table, with data that was generated by the Bolton (1980)
! formula for theta_e.
! First check if pressure is less than min pressure in lookup table.
! If it is, assume parcel is so dry that the given theta-e value can
! be interpretted as theta, and get temperature from the simple dry
! theta formula.
IF (p .LE. PSADIPRS(150)) THEN
tonpsadiabat = eth*(p/1000.)**GAMMA
ELSE
! Otherwise, look for the given thte/prs point in the lookup table.
jt=-1
DO jtch=1,150-1
IF (eth .GE. PSADITHTE(jtch) .AND. eth .LT. PSADITHTE(jtch+1)) THEN
jt = jtch
EXIT
ENDIF
END DO
ip=-1
DO ipch=1,150-1
IF (p .LE. PSADIPRS(ipch) .AND. p .GT. PSADIPRS(ipch+1)) THEN
ip = ipch
EXIT
ENDIF
END DO
IF (jt .EQ. -1 .OR. ip .EQ. -1) THEN
errstat = ALGERR
WRITE(errmsg, *) "Outside of lookup table bounds. prs,thte=", p, eth
RETURN
ENDIF
fracjt = (eth - PSADITHTE(jt))/(PSADITHTE(jt+1) - PSADITHTE(jt))
fracjt2 = 1. - fracjt
fracip = (PSADIPRS(ip) - p)/(PSADIPRS(ip) - PSADIPRS(ip+1))
fracip2 = 1. - fracip
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
!PRINT*,'Tried to access missing tmperature in lookup table.'
errstat = ALGERR
WRITE(errmsg, *) "Prs and Thte probably unreasonable. prs, thte=", p, eth
RETURN
ENDIF
tonpsadiabat = fracip2*fracjt2*PSADITMK(ip,jt) + &
fracip*fracjt2*PSADITMK(ip+1,jt) + &
fracip2*fracjt*PSADITMK(ip,jt+1) + &
fracip*fracjt*PSADITMK(ip+1,jt+1)
ENDIF
twb(i,j,k) = tonpsadiabat
END DO
END DO
END DO
RETURN
END SUBROUTINE WETBULBCALC
! !IROUTINE: omgcalc -- Calculate omega (dp/dt)
!
! !DESCRIPTION:
!
! Calculate approximate omega, based on vertical velocity w (dz/dt).
! It is approximate because it cannot take into account the vertical
! motion of pressure surfaces.
!
! !INPUT:
! mx - index for x dimension
! my - index for y dimension
! mx - index for vertical dimension
! qvp - water vapor mixing ratio (kg/kg)
! tmk - temperature (K)
! www - vertical velocity (m/s)
! prs - pressure (Pa)
!
! !OUTPUT:
! omg - omega (Pa/sec)
!
! !ASSUMPTIONS:
!
! !REVISION HISTORY:
! 2009-March - Mark T. Stoelinga - from RIP4.5
! 2010-August - J. Schramm
! 2014-March - A. Jaye - modified to run with NCL and ARW wrf output
!
! ------------------------------------------------------------------
!NCLFORTSTART
SUBROUTINE OMGCALC(qvp, tmk, www, prs, omg, mx, my, mz)
USE constants, ONLY : G, RD, EPS
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: omg
INTEGER,INTENT(IN) :: mx, my, mz
REAL(KIND=8), INTENT(IN), DIMENSION(mx,my,mz) :: qvp
REAL(KIND=8), INTENT(IN), DIMENSION(mx,my,mz) :: tmk
REAL(KIND=8), INTENT(IN), DIMENSION(mx,my,mz) :: www
REAL(KIND=8), INTENT(IN), DIMENSION(mx,my,mz) :: prs
REAL(KIND=8), INTENT(OUT), DIMENSION(mx,my,mz) :: omg
!NCLEND
! Local variables
INTEGER :: i, j, k
!REAL(KIND=8), PARAMETER :: GRAV=9.81, RGAS=287.04, EPS=0.622
DO k=1,mz
DO j=1,my
DO i=1,mx
omg(i,j,k) = -G*prs(i,j,k)/&
(RD*((tmk(i,j,k)*(EPS + qvp(i,j,k)))/&
(EPS*(1. + qvp(i,j,k)))))*www(i,j,k)
END DO
END DO
END DO
RETURN
END SUBROUTINE OMGCALC
!======================================================================
!
! !IROUTINE: VIRTUAL_TEMP -- Calculate virtual temperature (K)
!
! !DESCRIPTION:
!
! Calculates virtual temperature in K, given temperature
! in K and mixing ratio in kg/kg.
!
! !INPUT:
! NX - index for x dimension
! NY - index for y dimension
! NZ - index for z dimension
! RATMIX - water vapor mixing ratio (kg/kg)
! TEMP - temperature (K)
!
! !OUTPUT:
! TV - Virtual temperature (K)
!
! !ASSUMPTIONS:
!
! !REVISION HISTORY:
! 2009-March - Mark T. Stoelinga - from RIP4.5
! 2010-August - J. Schramm
! 2014-March - A. Jaye - modified to run with NCL and ARW wrf output
!
! ------------------------------------------------------------------
!NCLFORTSTART
SUBROUTINE VIRTUAL_TEMP(temp, ratmix, tv, nx, ny, nz)
USE constants, ONLY : EPS
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: tv
INTEGER, INTENT(IN) :: nx, ny, nz
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(IN) :: temp
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(IN) :: ratmix
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(OUT) :: tv
!NCLEND
INTEGER :: i,j,k
!REAL(KIND=8),PARAMETER :: EPS = 0.622D0
DO k=1,nz
DO j=1,ny
DO i=1,nx
tv(i,j,k) = temp(i,j,k)*(EPS + ratmix(i,j,k))/(EPS*(1.D0 + ratmix(i,j,k)))
END DO
END DO
END DO
RETURN
END SUBROUTINE VIRTUAL_TEMP

102
fortran/wrf_user.f90

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
! NCLFORTSTART
SUBROUTINE DCOMPUTEPI(pi, pressure, nx, ny, nz)
USE constants, ONLY : P1000MB, R_D, CP
USE constants, ONLY : P1000MB, RD, CP
IMPLICIT NONE
@ -19,7 +19,7 @@ SUBROUTINE DCOMPUTEPI(pi, pressure, nx, ny, nz) @@ -19,7 +19,7 @@ SUBROUTINE DCOMPUTEPI(pi, pressure, nx, ny, nz)
DO k = 1,nz
DO j = 1,ny
DO i = 1,nx
pi(i,j,k) = (pressure(i,j,k)/P1000MB)**(R_D/CP)
pi(i,j,k) = (pressure(i,j,k)/P1000MB)**(RD/CP)
END DO
END DO
END DO
@ -29,7 +29,7 @@ END SUBROUTINE DCOMPUTEPI @@ -29,7 +29,7 @@ END SUBROUTINE DCOMPUTEPI
! Temperature from potential temperature in kelvin.
!NCLFORTSTART
SUBROUTINE DCOMPUTETK(tk, pressure, theta, nx)
USE constants, ONLY : P1000MB, R_D, CP
USE constants, ONLY : P1000MB, RD, CP
IMPLICIT NONE
@ -46,10 +46,10 @@ SUBROUTINE DCOMPUTETK(tk, pressure, theta, nx) @@ -46,10 +46,10 @@ SUBROUTINE DCOMPUTETK(tk, pressure, theta, nx)
INTEGER :: i
!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, RD=287.D0, CP=7.D0*RD/2.D0
DO i = 1,nx
pi = (pressure(i)/P1000MB)**(R_D/CP)
pi = (pressure(i)/P1000MB)**(RD/CP)
tk(i) = pi*theta(i)
END DO
@ -282,7 +282,7 @@ END SUBROUTINE DINTERP1D @@ -282,7 +282,7 @@ END SUBROUTINE DINTERP1D
! NCLFORTSTART
SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, &
t_sea_level, t_surf, level, errstat, errmsg)
USE constants, ONLY : ERRLEN, R, G, GAMMA
USE constants, ONLY : ALGERR, RD, G, USSALR
IMPLICIT NONE
@ -297,11 +297,10 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, & @@ -297,11 +297,10 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, &
REAL(KIND=8), DIMENSION(nx,ny), INTENT(OUT) :: sea_level_pressure
INTEGER, DIMENSION(nx,ny), INTENT(INOUT) :: level
REAL(KIND=8), DIMENSION(nx,ny), INTENT(INOUT) :: t_surf, t_sea_level
! NCLFORTEND
INTEGER, INTENT(INOUT) :: errstat
CHARACTER(LEN=*), INTENT(INOUT) :: errmsg
INTEGER, OPTIONAL, INTENT(INOUT) :: errstat
CHARACTER(LEN=ERRLEN), OPTIONAL, INTENT(INOUT) :: errmsg
! NCLFORTEND
! Some required physical constants:
@ -329,9 +328,7 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, & @@ -329,9 +328,7 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, &
! temperature, which is supposed to reduce the effect of the diurnal
! heating cycle in the pressure field.
IF (PRESENT(errstat)) THEN
errstat = 0
END IF
DO j = 1,ny
DO i = 1,nx
@ -348,16 +345,14 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, & @@ -348,16 +345,14 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, &
END DO
IF (level(i,j) == -1) THEN
IF (PRESENT(errstat)) THEN
errstat = 1
errmsg = 'Error in finding 100 hPa up'
errstat = ALGERR
errmsg = "Error in finding 100 hPa up"
RETURN
ELSE
PRINT '(A,I4,A)','Troubles finding level ', NINT(PCONST)/100,' above ground.'
PRINT '(A,I4,A,I4,A)','Problems first occur at (',I,',',J,')'
PRINT '(A,F6.1,A)','Surface pressure = ',p(i,j,1)/100,' hPa.'
STOP 'Error in finding 100 hPa up'
END IF
!PRINT '(A,I4,A)','Troubles finding level ', NINT(PCONST)/100,' above ground.'
!PRINT '(A,I4,A,I4,A)','Problems first occur at (',I,',',J,')'
!PRINT '(A,F6.1,A)','Surface pressure = ',p(i,j,1)/100,' hPa.'
!STOP 'Error in finding 100 hPa up'
END IF
END DO
@ -366,22 +361,20 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, & @@ -366,22 +361,20 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, &
! Get temperature PCONST Pa above surface. Use this to extrapolate
! the temperature at the surface and down to sea level.
DO J = 1,ny
DO I = 1,nx
DO j = 1,ny
DO i = 1,nx
klo = MAX(level(i,j)-1,1)
khi = MIN(klo+1,nz-1)
IF (klo == khi) THEN
IF (PRESENT(errstat)) THEN
errstat = 1
errmsg = 'Error trapping levels'
errstat = ALGERR
errmsg = "Error trapping levels"
RETURN
ELSE
PRINT '(A)','Trapping levels are weird.'
PRINT '(A,I3,A,I3,A)','klo = ',klo,', khi = ',khi,': and they should not be equal.'
STOP 'Error trapping levels'
END IF
!PRINT '(A)','Trapping levels are weird.'
!PRINT '(A,I3,A,I3,A)','klo = ',klo,', khi = ',khi,': and they should not be equal.'
!STOP 'Error trapping levels'
END IF
plo = p(i,j,klo)
@ -397,8 +390,8 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, & @@ -397,8 +390,8 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, &
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)
t_surf(i,j) = t_at_pconst * (p(i,j,1)/p_at_pconst)**(GAMMA*R/G)
t_sea_level(i,j) = t_at_pconst + GAMMA*z_at_pconst
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
END DO
END DO
@ -408,8 +401,8 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, & @@ -408,8 +401,8 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, &
! temperatures are *too* hot.
IF (ridiculous_mm5_test) THEN
DO J = 1,ny
DO I = 1,nx
DO j = 1,ny
DO i = 1,nx
l1 = t_sea_level(i,j) < TC
l2 = t_surf(i,j) <= TC
l3 = .NOT. l1
@ -423,8 +416,8 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, & @@ -423,8 +416,8 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, &
END IF
! The grand finale: ta da!
DO J = 1,ny
DO I = 1,nx
DO j = 1,ny
DO i = 1,nx
! z_half_lowest=zetahalf(1)/ztop*(ztop-terrain(i,j))+terrain(i,j)
z_half_lowest = z(i,j,1)
@ -432,7 +425,7 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, & @@ -432,7 +425,7 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, &
! Fortran routine didn't do this, but the NCL script that called it
! did, so we moved it here.
sea_level_pressure(i,j) = 0.01 * (p(i,j,1)*EXP((2.D0*G*z_half_lowest)/&
(R*(t_sea_level(i,j)+t_surf(i,j)))))
(RD*(t_sea_level(i,j)+t_surf(i,j)))))
END DO
END DO
@ -592,6 +585,7 @@ END SUBROUTINE FILTER2D @@ -592,6 +585,7 @@ END SUBROUTINE FILTER2D
! NCLFORTSTART
SUBROUTINE DCOMPUTERH(qv, p, t, rh, nx)
USE constants, ONLY : EZERO, ESLCON1, ESLCON2, CELKEL, RD, RV, EPS
IMPLICIT NONE
@ -604,20 +598,16 @@ SUBROUTINE DCOMPUTERH(qv, p, t, rh, nx) @@ -604,20 +598,16 @@ SUBROUTINE DCOMPUTERH(qv, p, t, rh, nx)
! NCLEND
REAL(KIND=8), PARAMETER :: SVP1=0.6112D0,SVP2=17.67D0,SVP3=29.65D0,SVPT0=273.15D0
INTEGER :: i
REAL(KIND=8) :: qvs,es,pressure,temperature
REAL(KIND=8), PARAMETER :: R_D=287.D0,R_V=461.6D0,EP_2=R_D/R_V
REAL(KIND=8), PARAMETER :: EP_3=0.622D0
DO i = 1,nx
pressure = p(i)
temperature = t(i)
! es = 1000.*svp1*
es = 10.D0*SVP1*EXP(SVP2* (temperature-SVPT0)/(temperature-SVP3))
es = EZERO * EXP(ESLCON1 * (temperature-CELKEL) / (temperature-ESLCON2))
! qvs = ep_2*es/(pressure-es)
qvs = EP_3*es/ (0.01D0*pressure- (1.D0-EP_3)*es)
qvs = EPS * es / (0.01D0 * pressure - (1.D0 - EPS) * es)
! rh = 100*amax1(1., qv(i)/qvs)
! rh(i) = 100.*qv(i)/qvs
rh(i) = 100.D0 * DMAX1(DMIN1(qv(i) / qvs, 1.0D0), 0.0D0)
@ -744,7 +734,7 @@ SUBROUTINE DCOMPUTEUVMET(u, v, uvmet, longca,longcb,flong,flat, & @@ -744,7 +734,7 @@ SUBROUTINE DCOMPUTEUVMET(u, v, uvmet, longca,longcb,flong,flat, &
END DO
END DO
! WRITE (6,FMT=*) ' computing velocities '
! WRITE (6,FMT=*) " computing velocities "
DO j = 1,ny
DO i = 1,nx
IF (istag.EQ.1) THEN
@ -859,27 +849,24 @@ SUBROUTINE DCOMPUTEICLW(iclw, pressure, qc_in, nx, ny, nz) @@ -859,27 +849,24 @@ SUBROUTINE DCOMPUTEICLW(iclw, pressure, qc_in, nx, ny, nz)
END SUBROUTINE DCOMPUTEICLW
SUBROUTINE testfunc(a, b, nx, ny, nz, errstat, errstr)
SUBROUTINE testfunc(a, b, c, nx, ny, nz, errstat, errmsg)
USE constants, ONLY : ALGERR
IMPLICIT NONE
!f2py threadsafe
!threadsafe
!f2py intent(in,out) :: b
INTEGER, INTENT(IN) :: nx, ny, nz
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(IN) :: a
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(OUT) :: b
INTEGER, INTENT(INOUT), OPTIONAL :: errstat
CHARACTER(LEN=512), INTENT(INOUT), OPTIONAL :: errstr
CHARACTER(LEN=*), INTENT(IN) :: c
INTEGER, INTENT(INOUT) :: errstat
REAL(KIND=8), PARAMETER :: blah=123.45
CHARACTER(LEN=*), INTENT(INOUT) :: errmsg
INTEGER :: i,j,k
IF (PRESENT(errstat)) THEN
errstat = 0
errstr = 'test string worked'
END IF
DO k=1,nz
DO j=1,ny
DO i=1,nx
@ -888,9 +875,8 @@ SUBROUTINE testfunc(a, b, nx, ny, nz, errstat, errstr) @@ -888,9 +875,8 @@ SUBROUTINE testfunc(a, b, nx, ny, nz, errstat, errstr)
END DO
END DO
IF (PRESENT(errstat)) THEN
errstat = 1
END IF
errstat = ALGERR
WRITE(errmsg, *) c(1:20), blah
RETURN

147
fortran/wrf_user_dbz.f90

@ -0,0 +1,147 @@ @@ -0,0 +1,147 @@
!NCLFORTSTART
SUBROUTINE CALCDBZ(prs, tmk, qvp, qra, qsn, qgr, sn0, ivarint, iliqskin, dbz, nx, ny, nz)
USE constants, ONLY : GAMMA_SEVEN, RHOWAT, RHO_R, RHO_S, RHO_G, ALPHA, &
CELKEL, PI, RD
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: dbz
! Arguments
INTEGER, INTENT(IN) :: nx, ny, nz
INTEGER, INTENT(IN) :: sn0, ivarint, iliqskin
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(OUT) :: dbz
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(IN) :: prs
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(IN) :: tmk
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(INOUT) :: qvp
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(INOUT) :: qra
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(INOUT) :: qsn
REAL(KIND=8), DIMENSION(nx,ny,nz), INTENT(INOUT) :: qgr
!NCLEND
! Local Variables
INTEGER :: i, j, k
REAL(KIND=8) :: temp_c, virtual_t
REAL(KIND=8) :: gonv, ronv, sonv
REAL(KIND=8) :: factor_g, factor_r, factor_s
REAL(KIND=8) :: factorb_g, factorb_s
REAL(KIND=8) :: rhoair, z_e
! Constants used to calculate variable intercepts
REAL(KIND=8), PARAMETER :: R1 = 1.D-15
REAL(KIND=8), PARAMETER :: RON = 8.D6
REAL(KIND=8), PARAMETER :: RON2 = 1.D10
REAL(KIND=8), PARAMETER :: SON = 2.D7
REAL(KIND=8), PARAMETER :: GON = 5.D7
REAL(KIND=8), PARAMETER :: RON_MIN = 8.D6
REAL(KIND=8), PARAMETER :: RON_QR0 = 0.00010D0
REAL(KIND=8), PARAMETER :: RON_DELQR0 = 0.25D0*RON_QR0
REAL(KIND=8), PARAMETER :: RON_CONST1R = (RON2-RON_MIN)*0.5D0
REAL(KIND=8), PARAMETER :: RON_CONST2R = (RON2+RON_MIN)*0.5D0
! Constant intercepts
REAL(KIND=8), PARAMETER :: RN0_R = 8.D6
REAL(KIND=8), PARAMETER :: RN0_S = 2.D7
REAL(KIND=8), PARAMETER :: RN0_G = 4.D6
! Force all Q arrays to be 0.0 or greater.
DO k = 1,nz
DO j = 1,ny
DO i = 1,nx
IF (qvp(i,j,k).LT.0.0) THEN
qvp(i,j,k) = 0.0
END IF
IF (qra(i,j,k).LT.0.0) THEN
qra(i,j,k) = 0.0
END IF
IF (qsn(i,j,k).LT.0.0) THEN
qsn(i,j,k) = 0.0
END IF
IF (qgr(i,j,k).LT.0.0) THEN
qgr(i,j,k) = 0.0
END IF
END DO
END DO
END DO
! Input pressure is Pa, but we need hPa in calculations
IF (sn0 .EQ. 0) THEN
DO k = 1,nz
DO j = 1,ny
DO i = 1,nx
IF (tmk(i,j,k) .LT. CELKEL) THEN
qsn(i,j,k) = qra(i,j,k)
qra(i,j,k) = 0.D0
END IF
END DO
END DO
END DO
END IF
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_g = GAMMA_SEVEN*1.D18*(1.D0/(PI*RHO_G))**1.75D0*(RHO_G/RHOWAT)**2*ALPHA
DO k = 1,nz
DO j = 1,ny
DO i = 1,nx
virtual_t = tmk(i,j,k)*(0.622D0 + qvp(i,j,k))/(0.622D0*(1.D0 + qvp(i,j,k)))
rhoair = prs(i,j,k) / (RD*virtual_t)
! Adjust factor for brightband, where snow or graupel particle
! scatters like liquid water (alpha=1.0) because it is assumed to
! have a liquid skin.
IF (iliqskin .EQ. 1 .AND. tmk(i,j,k) .GT. CELKEL) THEN
factorb_s = factor_s/ALPHA
factorb_g = factor_g/ALPHA
ELSE
factorb_s = factor_s
factorb_g = factor_g
END IF
! Calculate variable intercept parameters
IF (ivarint .EQ. 1) THEN
temp_c = DMIN1(-0.001D0, tmk(i,j,k)-CELKEL)
sonv = DMIN1(2.0D8, 2.0D6*EXP(-0.12D0*temp_c))
gonv = gon
IF (qgr(i,j,k) .GT. R1) THEN
gonv = 2.38D0 * (PI*RHO_G/(rhoair*qgr(i,j,k)))**0.92D0
gonv = MAX(1.D4, MIN(gonv,GON))
END IF
ronv = RON2
IF (qra(i,j,k) .GT. R1) THEN
ronv = RON_CONST1R*TANH((RON_QR0-qra(i,j,k))/RON_DELQR0) + RON_CONST2R
END IF
ELSE
ronv = RN0_R
sonv = RN0_S
gonv = RN0_G
END IF
! Total equivalent reflectivity factor (z_e, in mm^6 m^-3) is
! the sum of z_e for each hydrometeor species:
z_e = factor_r*(rhoair*qra(i,j,k))**1.75D0/ronv**.75D0 + &
factorb_s*(rhoair*qsn(i,j,k))**1.75D0/sonv**.75D0 + &
factorb_g* (rhoair*qgr(i,j,k))**1.75D0/gonv**.75D0
! Adjust small values of Z_e so that dBZ is no lower than -30
z_e = MAX(z_e, .001D0)
! Convert to dBZ
dbz(i,j,k) = 10.D0*LOG10(z_e)
END DO
END DO
END DO
RETURN
END SUBROUTINE CALCDBZ

524
fortran/wrf_user_latlon_routines.f90

@ -0,0 +1,524 @@ @@ -0,0 +1,524 @@
!NCLFORTSTART
SUBROUTINE ROTATECOORDS(ilat, ilon, olat, olon, lat_np, lon_np, lon_0, direction)
USE constants, ONLY : PI, RAD_PER_DEG, DEG_PER_RAD
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: olat, olon
REAL(KIND=8), INTENT(IN) :: ilat, ilon
REAL(KIND=8), INTENT(OUT) :: olat, olon
REAL(KIND=8), INTENT(IN) :: lat_np, lon_np, lon_0
INTEGER, INTENT(IN) :: direction
! NCLFORTEND
! >=0, default : computational -> geographical
! < 0 : geographical -> computational
REAL(KIND=8) :: rlat, rlon
REAL(KIND=8) :: phi_np, lam_np, lam_0, dlam
REAL(KIND=8) :: sinphi, cosphi, coslam, sinlam
!REAL(KIND=8), PARAMETER :: PI=3.141592653589793D0
!REAL(KIND=8), PARAMETER :: RAD_PER_DEG=PI/180.D0
!REAL(KIND=8), PARAMETER :: DEG_PER_RAD=180.D0/PI
!convert all angles to radians
phi_np = lat_np*RAD_PER_DEG
lam_np = lon_np*RAD_PER_DEG
lam_0 = lon_0*RAD_PER_DEG
rlat = ilat*RAD_PER_DEG
rlon = ilon*RAD_PER_DEG
IF (direction .LT. 0) THEN
! the equations are exactly the same except for one
! small difference with respect to longitude ...
dlam = pi - lam_0
ELSE
dlam = lam_np
END IF
sinphi = COS(phi_np)*COS(rlat)*COS(rlon - dlam) + SIN(phi_np)*SIN(rlat)
cosphi = SQRT(1.D0 - sinphi*sinphi)
coslam = SIN(phi_np)*COS(rlat)*COS(rlon - dlam) - COS(phi_np)*SIN(rlat)
sinlam = COS(rlat)*SIN(rlon - dlam)
IF (cosphi.NE.0.D0) THEN
coslam = coslam/cosphi
sinlam = sinlam/cosphi
END IF
olat = DEG_PER_RAD*ASIN(sinphi)
olon = DEG_PER_RAD*(ATAN2(sinlam,coslam) - dlam - lam_0 + lam_np)
RETURN
END SUBROUTINE ROTATECOORDS
!NCLFORTSTART
SUBROUTINE DLLTOIJ(map_proj, truelat1, truelat2, stdlon, lat1, lon1,&
pole_lat, pole_lon, knowni, knownj, dx, dy, latinc,&
loninc, lat, lon, loc, errstat, errmsg)
USE constants, ONLY : ALGERR, PI, RAD_PER_DEG, DEG_PER_RAD, WRF_EARTH_RADIUS
! Converts input lat/lon values to the cartesian (i,j) value
! for the given projection.
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: loc
INTEGER, INTENT(IN) :: map_proj
REAL(KIND=8), INTENT(IN) :: stdlon
REAL(KIND=8), INTENT(IN) ::lat1, lon1, pole_lat, pole_lon, knowni, knownj
REAL(KIND=8), INTENT(IN) ::dx, dy, latinc, loninc
REAL(KIND=8), INTENT(INOUT) :: lat, lon, truelat1, truelat2 ! these might get modified
REAL(KIND=8), DIMENSION(2), INTENT(OUT) :: loc
INTEGER, INTENT(INOUT) :: errstat
CHARACTER(LEN=*), INTENT(INOUT) :: errmsg
!NCLEND
REAL(KIND=8) :: deltalon1
REAL(KIND=8) :: tl1r
REAL(KIND=8) :: clain, dlon, rsw, deltalon, deltalat
REAL(KIND=8) :: reflon, scale_top, ala1, alo1, ala, alo, rm, polei, polej
! earth radius divided by dx
REAL(KIND=8) :: rebydx
REAL(KIND=8) :: ctl1r, arg, cone, hemi
REAL(KIND=8) :: i, j
REAL(KIND=8) :: lat1n, lon1n, olat, olon
! Contants
!REAL(KIND=8),PARAMETER :: PI=3.141592653589793D0
!REAL(KIND=8),PARAMETER :: RAD_PER_DEG=PI/180.D0
!REAL(KIND=8),PARAMETER :: DEG_PER_RAD=180.D0/PI
!REAL(KIND=8),PARAMETER :: RE_M=6370000.D0 ! radius of earth in meters
! lat1 ! sw latitude (1,1) in degrees (-90->90n)
! lon1 ! sw longitude (1,1) in degrees (-180->180e)
! dx ! grid spacing in meters at truelats
! dlat ! lat increment for lat/lon grids
! dlon ! lon increment for lat/lon grids
! stdlon ! longitude parallel to y-axis (-180->180e)
! truelat1 ! first true latitude (all projections)
! truelat2 ! second true lat (lc only)
! hemi ! 1 for nh, -1 for sh
! cone ! cone factor for lc projections
! polei ! computed i-location of pole point
! polej ! computed j-location of pole point
! rsw ! computed radius to sw corner
! knowni ! x-location of known lat/lon
! knownj ! y-location of known lat/lon
! re_m ! radius of spherical earth, meters
! rebydx ! earth radius divided by dx
errstat = INT(dy) ! remove compiler warning since dy not used
errstat = 0
rebydx = WRF_EARTH_RADIUS/dx
! Get rid of compiler warnings
i=0
j=0
hemi = 1.0D0
IF (truelat1 .LT. 0.0D0) THEN
hemi = -1.0D0
END IF
! mercator
IF (map_proj.EQ.3) THEN
! preliminary variables
clain = COS(RAD_PER_DEG*truelat1)
dlon = dx/(WRF_EARTH_RADIUS*clain)
! compute distance from equator to origin, and store in
! the rsw tag.
rsw = 0.D0
IF (lat1 .NE. 0.D0) THEN
rsw = (DLOG(TAN(0.5D0*((lat1 + 90.D0)*RAD_PER_DEG))))/dlon
END IF
deltalon = lon - lon1
IF (deltalon .LT. -180.D0) deltalon = deltalon + 360.D0
IF (deltalon .GT. 180.D0) deltalon = deltalon - 360.D0
i = knowni + (deltalon/(dlon*DEG_PER_RAD))
j = knownj + (DLOG(TAN(0.5D0*((lat + 90.D0)*RAD_PER_DEG))))/dlon - rsw
! ps
ELSE IF (map_proj .EQ. 2) THEN
reflon = stdlon + 90.D0
! compute numerator term of map scale factor
scale_top = 1.D0 + hemi*SIN(truelat1*RAD_PER_DEG)
! compute radius to lower-left (sw) corner
ala1 = lat1*RAD_PER_DEG
rsw = rebydx*COS(ala1)*scale_top/(1.D0 + hemi*SIN(ala1))
! find the pole point
alo1 = (lon1 - reflon)*RAD_PER_DEG
polei = knowni - rsw*COS(alo1)
polej = knownj - hemi*rsw*SIN(alo1)
! find radius to desired point
ala = lat*RAD_PER_DEG
rm = rebydx*COS(ala)*scale_top/(1.D0 + hemi*SIN(ala))
alo = (lon - reflon)*RAD_PER_DEG
i = polei + rm*COS(alo)
j = polej + hemi*rm*SIN(alo)
! lambert
ELSE IF (map_proj .EQ. 1) THEN
IF (ABS(truelat2) .GT. 90.D0) THEN
truelat2 = truelat1
END IF
IF (ABS(truelat1 - truelat2) .GT. 0.1D0) THEN
cone = (DLOG(COS(truelat1*RAD_PER_DEG))-DLOG(COS(truelat2*RAD_PER_DEG)))/&
(DLOG(TAN((90.D0 - ABS(truelat1))*RAD_PER_DEG*0.5D0))-&
DLOG(TAN((90.D0 - ABS(truelat2))*RAD_PER_DEG*0.5D0)))
ELSE
cone = SIN(ABS(truelat1)*RAD_PER_DEG)
END IF
! compute longitude differences and ensure we stay
! out of the forbidden "cut zone"
deltalon1 = lon1 - stdlon
IF (deltalon1 .GT. +180.D0) deltalon1 = deltalon1 - 360.D0
IF (deltalon1 .LT. -180.D0) deltalon1 = deltalon1 + 360.D0
! convert truelat1 to radian and compute cos for later use
tl1r = truelat1*RAD_PER_DEG
ctl1r = COS(tl1r)
! compute the radius to our known lower-left (sw) corner
rsw = rebydx*ctl1r/cone*(TAN((90.D0*hemi - lat1)*RAD_PER_DEG/2.D0)/&
TAN((90.D0*hemi - truelat1)*RAD_PER_DEG/2.D0))**cone
! find pole point
arg = cone*(deltalon1*RAD_PER_DEG)
polei = hemi*knowni - hemi*rsw*SIN(arg)
polej = hemi*knownj + rsw*COS(arg)
! compute deltalon between known longitude and standard
! lon and ensure it is not in the cut zone
deltalon = lon - stdlon
IF (deltalon .GT. +180.D0) deltalon = deltalon - 360.D0
IF (deltalon .LT. -180.D0) deltalon = deltalon + 360.D0
! radius to desired point
rm = rebydx*ctl1r/cone*(TAN((90.D0*hemi - lat)*RAD_PER_DEG/2.D0)/&
TAN((90.D0*hemi - truelat1)*RAD_PER_DEG/2.D0))**cone
arg = cone*(deltalon*RAD_PER_DEG)
i = polei + hemi*rm*SIN(arg)
j = polej - rm*COS(arg)
! finally, if we are in the southern hemisphere, flip the
! i/j values to a coordinate system where (1,1) is the sw
! corner (what we assume) which is different than the
! original ncep algorithms which used the ne corner as
! the origin in the southern hemisphere (left-hand vs.
! right-hand coordinate?)
i = hemi*i
j = hemi*j
! lat-lon
ELSE IF (map_proj .EQ. 6) THEN
IF (pole_lat .NE. 90.D0) THEN
CALL ROTATECOORDS(lat, lon, olat, olon, pole_lat, pole_lon, stdlon, -1)
lat = olat
lon = olon + stdlon
END IF
! make sure center lat/lon is good
IF (pole_lat .NE. 90.D0) THEN
CALL ROTATECOORDS(lat1, lon1, olat, olon, pole_lat, pole_lon, stdlon, -1)
lat1n = olat
lon1n = olon + stdlon
deltalat = lat - lat1n
deltalon = lon - lon1n
ELSE
deltalat = lat - lat1
deltalon = lon - lon1
END IF
! compute i/j
i = deltalon/loninc
j = deltalat/latinc
i = i + knowni
j = j + knownj
ELSE
errstat = ALGERR
WRITE(errmsg, *) "Do not know map projection ", map_proj
RETURN
END IF
loc(1) = j
loc(2) = i
RETURN
END SUBROUTINE DLLTOIJ
!NCLFORTSTART
SUBROUTINE DIJTOLL(map_proj, truelat1, truelat2, stdlon, lat1, lon1,&
pole_lat, pole_lon, knowni, knownj, dx, dy, latinc,&
loninc, ai, aj, loc, errstat, errmsg)
USE constants, ONLY : ALGERR, PI, RAD_PER_DEG, DEG_PER_RAD, WRF_EARTH_RADIUS
! converts input lat/lon values to the cartesian (i,j) value
! for the given projection.
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: loc
INTEGER, INTENT(IN) :: map_proj
REAL(KIND=8), INTENT(IN) :: stdlon
REAL(KIND=8), INTENT(IN) :: lat1, lon1, pole_lat, pole_lon, knowni, knownj
REAL(KIND=8), INTENT(IN) :: dx, dy, latinc, loninc, ai, aj
REAL(KIND=8), INTENT(INOUT) :: truelat1, truelat2
REAL(KIND=8), DIMENSION(2), INTENT(OUT) :: loc
INTEGER, INTENT(INOUT) :: errstat
CHARACTER(LEN=*), INTENT(INOUT) :: errmsg
!NCLEND
REAL(KIND=8) :: gi2
REAL(KIND=8) :: arccos
REAL(KIND=8) :: deltalon1
REAL(KIND=8) :: tl1r
REAL(KIND=8) :: clain, dlon, rsw, deltalon, deltalat
REAL(KIND=8) :: reflon, scale_top, ala1, alo1, polei, polej
! earth radius divided by dx
REAL(KIND=8) :: rebydx
REAL(KIND=8) :: ctl1r, cone, hemi
!REAL(KIND=8),PARAMETER :: PI = 3.141592653589793D0
!REAL(KIND=8),PARAMETER :: RAD_PER_DEG = PI/180.D0
!REAL(KIND=8),PARAMETER :: DEG_PER_RAD = 180.D0/PI
!REAL(KIND=8),PARAMETER :: RE_M = 6370000.D0 ! radius of sperical earth
REAL(KIND=8) :: inew, jnew, r, r2
REAL(KIND=8) :: chi, chi1, chi2
REAL(KIND=8) :: xx, yy, lat, lon
REAL(KIND=8) :: olat, olon, lat1n, lon1n
! lat1 ! sw latitude (1,1) in degrees (-90->90n)
! lon1 ! sw longitude (1,1) in degrees (-180->180e)
! dx ! grid spacing in meters at truelats
! dlat ! lat increment for lat/lon grids
! dlon ! lon increment for lat/lon grids
! stdlon ! longitude parallel to y-axis (-180->180e)
! truelat1 ! first true latitude (all projections)
! truelat2 ! second true lat (lc only)
! hemi ! 1 for nh, -1 for sh
! cone ! cone factor for lc projections
! polei ! computed i-location of pole point
! polej ! computed j-location of pole point
! rsw ! computed radius to sw corner
! knowni ! x-location of known lat/lon
! knownj ! y-location of known lat/lon
! re_m ! radius of spherical earth, meters
! rebydx ! earth radius divided by dx
errstat = INT(dy) ! Remove compiler warning since dy not used
errstat = 0
rebydx = WRF_EARTH_RADIUS/dx
hemi = 1.0D0
IF (truelat1 .LT. 0.0D0) THEN
hemi = -1.0D0
END IF
! mercator
IF (map_proj .EQ. 3) THEN
! preliminary variables
clain = COS(RAD_PER_DEG*truelat1)
dlon = dx/(WRF_EARTH_RADIUS*clain)
! compute distance from equator to origin, and store in
! the rsw tag.
rsw = 0.D0
IF (lat1 .NE. 0.D0) THEN
rsw = (DLOG(TAN(0.5D0*((lat1 + 90.D0)*RAD_PER_DEG))))/dlon
END IF
lat = 2.0D0*ATAN(EXP(dlon*(rsw + aj - knownj)))*DEG_PER_RAD - 90.D0
lon = (ai - knowni)*dlon*DEG_PER_RAD + lon1
IF (lon .GT. 180.D0) lon = lon - 360.D0
IF (lon .LT. -180.D0) lon = lon + 360.D0
! ps
ELSE IF (map_proj .EQ. 2) THEN
! compute the reference longitude by rotating 90 degrees to
! the east to find the longitude line parallel to the
! positive x-axis.
reflon = stdlon + 90.D0
! compute numerator term of map scale factor
scale_top = 1.D0 + hemi*SIN(truelat1*RAD_PER_DEG)
! compute radius to known point
ala1 = lat1*RAD_PER_DEG
rsw = rebydx*COS(ala1)*scale_top/(1.D0 + hemi*SIN(ala1))
! find the pole point
alo1 = (lon1 - reflon)*RAD_PER_DEG
polei = knowni - rsw*COS(alo1)
polej = knownj - hemi*rsw*SIN(alo1)
! compute radius to point of interest
xx = ai - polei
yy = (aj - polej)*hemi
r2 = xx**2 + yy**2
! now the magic code
IF (r2 .EQ. 0.D0) THEN
lat = hemi*90.D0
lon = reflon
ELSE
gi2 = (rebydx*scale_top)**2.D0
lat = DEG_PER_RAD*hemi*ASIN((gi2 - r2)/(gi2 + r2))
arccos = ACOS(xx/SQRT(r2))
IF (yy .GT. 0) THEN
lon = reflon + DEG_PER_RAD*arccos
ELSE
lon = reflon - DEG_PER_RAD*arccos
END IF
END IF
! convert to a -180 -> 180 east convention
IF (lon .GT. 180.D0) lon = lon - 360.D0
IF (lon .LT. -180.D0) lon = lon + 360.D0
! !lambert
ELSE IF (map_proj .EQ. 1) THEN
IF (ABS(truelat2) .GT. 90.D0) THEN
truelat2 = truelat1
END IF
IF (ABS(truelat1 - truelat2) .GT. 0.1D0) THEN
cone = (DLOG(COS(truelat1*RAD_PER_DEG)) - DLOG(COS(truelat2*RAD_PER_DEG)))/&
(DLOG(TAN((90.D0 - ABS(truelat1))*RAD_PER_DEG*0.5D0)) - &
DLOG(TAN((90.D0 - ABS(truelat2))*RAD_PER_DEG*0.5D0)))
ELSE
cone = SIN(ABS(truelat1)*RAD_PER_DEG)
END IF
! compute longitude differences and ensure we stay out of the
! forbidden "cut zone"
deltalon1 = lon1 - stdlon
IF (deltalon1 .GT. +180.D0) deltalon1 = deltalon1 - 360.D0
IF (deltalon1 .LT. -180.D0) deltalon1 = deltalon1 + 360.D0
! convert truelat1 to radian and compute cos for later use
tl1r = truelat1*RAD_PER_DEG
ctl1r = COS(tl1r)
! compute the radius to our known point
rsw = rebydx*ctl1r/cone*(TAN((90.D0*hemi - lat1)*RAD_PER_DEG/2.D0)/&
TAN((90.D0*hemi - truelat1)*RAD_PER_DEG/2.D0))**cone
! find pole point
alo1 = cone*(deltalon1*RAD_PER_DEG)
polei = hemi*knowni - hemi*rsw*SIN(alo1)
polej = hemi*knownj + rsw*COS(alo1)
chi1 = (90.D0 - hemi*truelat1)*RAD_PER_DEG
chi2 = (90.D0 - hemi*truelat2)*RAD_PER_DEG
! see if we are in the southern hemispere and flip the
! indices if we are.
inew = hemi*ai
jnew = hemi*aj
! compute radius**2 to i/j location
reflon = stdlon + 90.D0
xx = inew - polei
yy = polej - jnew
r2 = (xx*xx + yy*yy)
r = sqrt(r2)/rebydx
! convert to lat/lon
IF (r2 .EQ. 0.D0) THEN
lat = hemi*90.D0
lon = stdlon
ELSE
lon = stdlon + DEG_PER_RAD*ATAN2(hemi*xx,yy)/cone
lon = dmod(lon + 360.D0, 360.D0)
IF (chi1 .EQ. chi2) THEN
chi = 2.0D0*ATAN((r/TAN(chi1))**(1.D0/cone)*TAN(chi1*0.5D0))
ELSE
chi = 2.0D0*ATAN((r*cone/SIN(chi1))**(1.D0/cone)*TAN(chi1*0.5D0))
END IF
lat = (90.0D0 - chi*DEG_PER_RAD)*hemi
END IF
IF (lon .GT. +180.D0) lon = lon - 360.D0
IF (lon .LT. -180.D0) lon = lon + 360.D0
! !lat-lon
ELSE IF (map_proj .EQ. 6) THEN
inew = ai - knowni
jnew = aj - knownj
IF (inew .LT. 0.D0) inew = inew + 360.D0/loninc
IF (inew .GE. 360.D0/dx) inew = inew - 360.D0/loninc
! compute deltalat and deltalon
deltalat = jnew*latinc
deltalon = inew*loninc
IF (pole_lat .NE. 90.D0) THEN
CALL ROTATECOORDS(lat1, lon1, olat, olon, pole_lat, pole_lon, stdlon, -1)
lat1n = olat
lon1n = olon + stdlon
lat = deltalat + lat1n
lon = deltalon + lon1n
ELSE
lat = deltalat + lat1
lon = deltalon + lon1
END IF
IF (pole_lat .NE. 90.D0) THEN
lon = lon - stdlon
CALL ROTATECOORDS(lat, lon, olat, olon, pole_lat, pole_lon, stdlon, 1)
lat = olat
lon = olon
END IF
IF (lon .LT. -180.D0) lon = lon + 360.D0
IF (lon .GT. 180.D0) lon = lon - 360.D0
ELSE
errstat = ALGERR
WRITE(errmsg, *) "Do not know map projection ", map_proj
RETURN
END IF
loc(1) = lat
loc(2) = lon
RETURN
END SUBROUTINE DIJTOLL

445
fortran/wrf_vinterp.f90

@ -0,0 +1,445 @@ @@ -0,0 +1,445 @@
!NCLFORTSTART
SUBROUTINE wrf_monotonic(out, in, lvprs, cor, idir, delta, ew, ns, nz, icorsw)
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: out
INTEGER, INTENT(IN) :: idir, ew, ns, nz, icorsw
REAL(KIND=8), INTENT(IN) :: delta
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) :: lvprs
REAL(KIND=8), DIMENSION(ew,ns) :: cor
!NCLEND
INTEGER :: i, j, k, ripk, k300
k300 = 0 ! removes the warning
DO j=1,ns
DO i=1,ew
IF (icorsw .EQ. 1 .AND. cor(i,j) .LT. 0.) THEN
DO k=1,nz
in(i,j,k) = -in(i,j,k)
END DO
END IF
! First find k index that is at or below (height-wise)
! the 300 hPa level.
DO k = 1,nz
ripk = nz-k+1
IF (lvprs(i,j,k) .LE. 300.D0) THEN
k300 = k
EXIT
END IF
END DO
DO k = k300,1,-1
IF (idir .EQ. 1) THEN
out(i,j,k) = MIN(in(i,j,k), in(i,j,k+1) + delta)
ELSE IF (idir .EQ. -1) THEN
out(i,j,k) = MAX(in(i,j,k), in(i,j,k+1) - delta)
END IF
END DO
DO k = k300+1, nz
IF (idir .EQ. 1) THEN
out(i,j,k) = MAX(in(i,j,k), in(i,j,k-1) - delta)
ELSE IF (idir .EQ. -1) THEN
out(i,j,k) = MIN(in(i,j,k), in(i,j,k-1) + delta)
END IF
END DO
END DO
END DO
RETURN
END SUBROUTINE wrf_monotonic
!NCLFORTSTART
FUNCTION wrf_intrp_value(wvalp0, wvalp1, vlev, vcp0, vcp1, icase, errstat, errmsg)
USE constants, ONLY : ALGERR, SCLHT
IMPLICIT NONE
!f2py threadsafe
INTEGER, INTENT(IN) :: icase
REAL(KIND=8), INTENT(IN) :: wvalp0, wvalp1, vlev, vcp0, vcp1
INTEGER, INTENT(INOUT) :: errstat
CHARACTER(LEN=*), INTENT(INOUT) :: errmsg
REAL(KIND=8) :: wrf_intrp_value
!NCLEND
REAL(KIND=8) :: valp0, valp1, rvalue
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
valp0 = wvalp0
valp1 = wvalp1
IF ( icase .EQ. 2) THEN !GHT
valp0=EXP(-wvalp0/SCLHT)
valp1=EXP(-wvalp1/SCLHT)
END IF
chkdiff = vcp1 - vcp0
IF(chkdiff .EQ. 0) THEN
errstat = ALGERR
errmsg = "bad difference in vcp's"
wrf_intrp_value = 0
RETURN
!PRINT *,"bad difference in vcp's"
!STOP
END IF
rvalue = (vlev - vcp0)*(valp1 - valp0)/(vcp1 - vcp0) + valp0
IF (icase .EQ. 2) THEN !GHT
wrf_intrp_value = -SCLHT*LOG(rvalue)
ELSE
wrf_intrp_value = rvalue
END IF
RETURN
END FUNCTION wrf_intrp_value
! NOTES:
! vcarray is the array holding the values for the vertical coordinate.
! It will always come in with the dimensions of the staggered U and V grid.
!NCLFORTSTART
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)
USE constants, ONLY : ALGERR, SCLHT, EXPON, EXPONI, GAMMA, GAMMAMD, TLCLC1, &
TLCLC2, TLCLC3, TLCLC4, THTECON1, THTECON2, THTECON3, &
CELKEL, EPS, USSALR
IMPLICIT NONE
!f2py threadsafe
!f2py intent(in,out) :: dataout
INTEGER, INTENT(IN) :: ew, ns, nz, icase, extrap
INTEGER, INTENT(IN) :: vcor, numlevels, logp
REAL(KIND=8), DIMENSION(ew,ns,nz), INTENT(IN) :: datain, pres, tk, qvp
REAL(KIND=8), DIMENSION(ew,ns,nz), INTENT(IN) :: ght
REAL(KIND=8), DIMENSION(ew,ns), INTENT(IN) :: terrain, sfp, smsfp
REAL(KIND=8), DIMENSION(ew,ns,numlevels), INTENT(OUT) :: dataout
REAL(KIND=8), DIMENSION(ew,ns,nz), INTENT(IN) :: vcarray
REAL(KIND=8), DIMENSION(numlevels), INTENT(IN) :: interp_levels
REAL(KIND=8), INTENT(IN) :: rmsg
INTEGER, INTENT(INOUT) :: errstat
CHARACTER(LEN=*), INTENT(INOUT) :: errmsg
!NCLEND
INTEGER :: nreqlvs, ripk !njx,niy
INTEGER :: i, j, k, kupper !itriv
INTEGER :: ifound, isign !miy,mjx
REAL(KIND=8), DIMENSION(ew,ns) :: tempout
REAL(KIND=8) :: rlevel, vlev, diff
REAL(KIND=8) :: tmpvlev
REAL(KIND=8) :: vcp1, vcp0, valp0, valp1
! REAL(KIND=8) :: cvc
REAL(KIND=8) :: vclhsl, vctophsl !qvlhsl,ttlhsl
REAL(KIND=8) :: wrf_intrp_value
REAL(KIND=8) :: plhsl, zlhsl, ezlhsl, tlhsl, psurf, pratio, tlev
REAL(KIND=8) :: ezsurf, psurfsm, zsurf, qvapor, vt
REAL(KIND=8) :: ezlev, plev, zlev, ptarget, dpmin, dp
REAL(KIND=8) :: pbot, zbot, tbotextrap, e
REAL(KIND=8) :: tlcl, gammam
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
cvcord = ''
plev = 0
zlev = 0
vlev = 0
errstat = 0
IF (vcor .EQ. 1) THEN
cvcord = 'p'
ELSE IF ((vcor .EQ. 2) .OR. (vcor .EQ. 3)) THEN
cvcord = 'z'
ELSE IF ((vcor .EQ. 4) .OR. (vcor .EQ. 5)) THEN
cvcord = 't'
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
IF (cvcord .EQ. 'z') THEN
! Convert rlevel to meters from km
rlevel = interp_levels(nreqlvs) * 1000.D0
vlev = EXP(-rlevel/SCLHT)
ELSE IF (cvcord .EQ. 'p') THEN
vlev = interp_levels(nreqlvs)
ELSE IF (cvcord .EQ. 't') THEN
vlev = interp_levels(nreqlvs)
END IF
DO j=1,ns
DO i=1,ew
! Get the interpolated value that is within the model domain
ifound = 0
DO k = 1,nz-1
ripk = nz-k+1
vcp1 = vcarray(i,j,ripk-1)
vcp0 = vcarray(i,j,ripk)
valp0 = datain(i,j,ripk)
valp1 = datain(i,j,ripk-1)
IF ((vlev .GE. vcp0 .AND. vlev .LE. vcp1) .OR. &
(vlev .LE. vcp0 .AND. vlev .GE. vcp1)) THEN
! print *,i,j,valp0,valp1
IF ((valp0 .EQ. rmsg) .OR. (valp1 .EQ. rmsg)) THEN
tempout(i,j) = rmsg
ifound = 1
ELSE
IF (logp .EQ. 1) THEN
vcp1 = LOG(vcp1)
vcp0 = LOG(vcp0)
IF (vlev .EQ. 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)
ELSE
tmpvlev = vlev
END IF
tempout(i,j) = wrf_intrp_value(valp0, valp1, tmpvlev, vcp0, &
vcp1, icase, errstat, errmsg)
IF (errstat .NE. 0) THEN
RETURN
END IF
! print *,"one ",i,j,tempout(i,j)
ifound = 1
END IF
!GOTO 115 ! EXIT
EXIT
END IF
END DO !end for the k loop
!115 CONTINUE
IF (ifound .EQ. 1) THEN !Grid point is in the model domain
!GOTO 333 ! CYCLE
CYCLE
END IF
!If the user has requested no extrapolatin then just assign
!all values above or below the model level to rmsg.
IF (extrap .EQ. 0) THEN
tempout(i,j) = rmsg
!GOTO 333 ! CYCLE
CYCLE
END IF
! The grid point is either above or below the model domain
! First we will check to see if the grid point is above the
! model domain.
vclhsl = vcarray(i,j,1) !lowest model level
vctophsl = vcarray(i,j,nz) !highest model level
diff = vctophsl - vclhsl
isign = NINT(diff/ABS(diff))
IF (isign*vlev .GE. isign*vctophsl) THEN
! Assign the highest model level to the out array
tempout(i,j) = datain(i,j,nz)
! print *,"at warn",i,j,tempout(i,j)
!GOTO 333 ! CYCLE
CYCLE
END IF
! Only remaining possibility is that the specified level is below
! lowest model level. If lowest model level value is missing,
! set interpolated value to missing.
IF (datain(i,j,1) .EQ. rmsg) THEN
tempout(i,j) = rmsg
!GOTO 333 ! CYCLE
CYCLE
END IF
! If the field comming in is not a pressure,temperature or height
! field we can set the output array to the value at the lowest
! model level.
tempout(i,j) = datain(i,j,1)
! For the special cases of pressure on height levels or height on
! pressure levels, or temperature-related variables on pressure or
! height levels, perform a special extrapolation based on
! US Standard Atmosphere. Here we calcualate the surface pressure
! with the altimeter equation. This is how RIP calculates the
! surface pressure.
IF (icase .GT. 0) THEN
plhsl = pres(i,j,1) * 0.01D0 !pressure at lowest model level
zlhsl = ght(i,j,1) !grid point height a lowest model level
ezlhsl = EXP(-zlhsl/SCLHT)
tlhsl = tk(i,j,1) !temperature in K at lowest model level
zsurf = terrain(i,j)
qvapor = MAX((qvp(i,j,1)*.001D0),1.e-15)
! virtual temperature
! vt = tlhsl * (eps + qvapor)/(eps*(1.0 + qvapor))
! psurf = plhsl * (vt/(vt+USSALR * (zlhsl-zsurf)))**rconst
psurf = sfp(i,j)
psurfsm = smsfp(i,j)
ezsurf = EXP(-zsurf/SCLHT)
! The if for checking above ground
IF ((cvcord .EQ. 'z' .AND. vlev .LT. ezsurf) .OR. &
(cvcord .EQ. 'p' .AND. vlev .LT. psurf)) THEN
! We are below the lowest data level but above the ground.
! Use linear interpolation (linear in prs and exp-height).
IF (cvcord .EQ. 'p') THEN
plev = vlev
ezlev = ((plev - plhsl)*&
ezsurf + (psurf - plev)*ezlhsl)/(psurf - plhsl)
zlev = -SCLHT*LOG(ezlev)
IF (icase .EQ. 2) THEN
tempout(i,j) = zlev
!GOTO 333 ! CYCLE
CYCLE
END IF
ELSE IF (cvcord .EQ. 'z') THEN
ezlev = vlev
zlev = -SCLHT*LOG(ezlev)
plev = ((ezlev - ezlhsl)*&
psurf + (ezsurf - ezlev)*plhsl)/(ezsurf - ezlhsl)
IF (icase .EQ. 1) THEN
tempout(i,j) = plev
!GOTO 333 ! CYCLE
CYCLE
END IF
END IF
ELSE !else for checking above ground
ptarget = psurfsm - 150.D0
dpmin = 1.e4
DO k=1,nz
ripk = nz-k+1
dp = ABS((pres(i,j,ripk) * 0.01D0) - ptarget)
IF (dp .GT. dpmin) THEN
!GOTO 334 ! EXIT
EXIT
END IF
dpmin = MIN(dpmin, dp)
END DO
!334
kupper = k-1
ripk = nz - kupper + 1
pbot = MAX(plhsl,psurf)
zbot = MIN(zlhsl,zsurf)
pratio = pbot/(pres(i,j,ripk) * 0.01D0)
tbotextrap = tk(i,j,ripk)*(pratio)**EXPON
! virtual temperature
vt = tbotextrap * (EPS + qvapor)/(EPS*(1.0D0 + qvapor))
IF (cvcord .EQ. 'p') THEN
plev = vlev
zlev = zbot + vt/USSALR*(1. - (vlev/pbot)**EXPON)
IF (icase .EQ. 2) THEN
tempout(i,j) = zlev
!GOTO 333 ! CYCLE
CYCLE
END IF
ELSE IF (cvcord .EQ. 'z') THEN
zlev = -sclht*LOG(vlev)
plev = pbot*(1. + USSALR/vt*(zbot - zlev))**EXPONI
IF (icase .EQ. 1) THEN
tempout(i,j) = plev
!GOTO 333 ! CYCLE
CYCLE
END IF
END IF
END IF !end if for checking above ground
END IF !for icase gt 0
IF (icase .GT. 2) THEN !extrapolation for temperature
tlev = tlhsl + (zlhsl - zlev)*USSALR
qvapor = MAX(qvp(i,j,1), 1.e-15)
gammam = GAMMA*(1. + GAMMAMD*qvapor)
IF (icase .EQ. 3) THEN
tempout(i,j) = tlev - CELKEL
ELSE IF (icase .EQ. 4) THEN
tempout(i,j) = tlev
! Potential temperature - theta
ELSE IF (icase .EQ. 5) THEN
tempout(i,j) = tlev*(1000.D0/plev)**gammam
! extraolation for equivalent potential temperature
ELSE IF (icase .EQ. 6) THEN
e = qvapor*plev/(EPS + qvapor)
tlcl = TLCLC1/(LOG(tlev**TLCLC2/e) - TLCLC3) + TLCLC4
tempout(i,j)=tlev*(1000.D0/plev)**(gammam)*&
EXP((THTECON1/tlcl - THTECON2)*&
qvapor*(1. + THTECON3*qvapor))
END IF
END IF
!333 CONTINUE
END DO
END DO
! print *,"----done----",interp_levels(nreqlvs)
DO j = 1,ns
DO i = 1,ew
dataout(i,j,nreqlvs) = tempout(i,j)
END DO
END DO
END DO !end for the nreqlvs
RETURN
END SUBROUTINE wrf_vintrp

406
fortran/wrffortran.pyf

@ -3,18 +3,269 @@ @@ -3,18 +3,269 @@
python module _wrffortran ! in
interface ! in :_wrffortran
subroutine dcalcuh(nx,ny,nz,nzp1,zp,mapfct,dx,dy,uhmnhgt,uhmxhgt,us,vs,w,uh,tem1,tem2) ! in :_wrffortran:calc_uh.f90
threadsafe
integer, optional,intent(in),check(shape(zp,0)==nx),depend(zp) :: nx=shape(zp,0)
integer, optional,intent(in),check(shape(zp,1)==ny),depend(zp) :: ny=shape(zp,1)
integer, optional,intent(in),check(shape(us,2)==nz),depend(us) :: nz=shape(us,2)
integer, optional,intent(in),check(shape(zp,2)==nzp1),depend(zp) :: nzp1=shape(zp,2)
real(kind=8) dimension(nx,ny,nzp1),intent(in) :: zp
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: mapfct
real(kind=8) intent(in) :: dx
real(kind=8) intent(in) :: dy
real(kind=8) intent(in) :: uhmnhgt
real(kind=8) intent(in) :: uhmxhgt
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny) :: us
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: vs
real(kind=8) dimension(nx,ny,nzp1),intent(in),depend(nx,ny,nzp1) :: w
real(kind=8) dimension(nx,ny),intent(out,in),depend(nx,ny) :: uh
real(kind=8) dimension(nx,ny,nz),intent(inout),depend(nx,ny,nz) :: tem1
real(kind=8) dimension(nx,ny,nz),intent(inout),depend(nx,ny,nz) :: tem2
end subroutine dcalcuh
subroutine dcloudfrac(pres,rh,lowc,midc,highc,nz,ns,ew) ! in :_wrffortran:cloud_fracf.f90
threadsafe
real(kind=8) dimension(ew,ns,nz),intent(in) :: pres
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: rh
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(pres,2)==nz),depend(pres) :: nz=shape(pres,2)
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)
end subroutine dcloudfrac
module constants ! in :_wrffortran:constants.f90
real(kind=8), parameter,optional :: wrf_earth_radius=6370000.d0
real(kind=8), parameter,optional :: rhowat=1000.d0
real(kind=8), parameter,optional :: t_base=300.0
real(kind=8), parameter,optional :: cp=1004.d0
real(kind=8), parameter,optional :: thtecon1=3376.d0
real(kind=8), parameter,optional :: thtecon3=.81d0
real(kind=8), parameter,optional :: thtecon2=2.54d0
real(kind=8), parameter,optional :: p1000mb=100000.d0
real(kind=8), parameter,optional :: r=287.04d0
real(kind=8), parameter,optional :: rv=461.5d0
real(kind=8), parameter,optional,depend(pi) :: rad_per_deg=pi/180.d0
real(kind=8), parameter,optional :: rd=287.04d0
real(kind=8), parameter,optional :: abscoef=.145d0
real(kind=8), parameter,optional :: celkel=273.15d0
real(kind=8), parameter,optional :: abscoefi=.272d0
real(kind=8), parameter,optional :: eslcon2=29.65d0
real(kind=8), parameter,optional :: eslcon1=17.67d0
real(kind=8), parameter,optional :: pi=3.141592653589793d0
real(kind=8), parameter,optional :: tlclc2=3.5d0
real(kind=8), parameter,optional :: tlclc3=4.805d0
real(kind=8), parameter,optional :: rho_g=400.d0
real(kind=8), parameter,optional :: tlclc1=2840.d0
real(kind=8), parameter,optional :: tlclc4=55.d0
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,depend(rd,g) :: sclht=rd*256.d0/g
real(kind=8), parameter,optional :: ussalr=0.0065d0
real(kind=8), parameter,optional :: default_fill=9.9692099683868690d36
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 :: alpha=0.224d0
real(kind=8), parameter,optional :: celkel_triple=273.16d0
real(kind=8), parameter,optional :: ezero=6.112d0
real(kind=8), parameter,optional,depend(rd,ussalr,g) :: expon=0.190189602446
real(kind=8), parameter,optional :: rgasmd=.608d0
real(kind=8), parameter,optional :: g=9.81d0
real(kind=8), parameter,optional :: r_d=287.d0
real(kind=8), parameter,optional,depend(r_d) :: cp=7.d0*r_d/2.d0
integer, optional :: errlen=512
real(kind=8), parameter,optional :: gamma=0.0065d0
real(kind=8), parameter,optional :: eps=0.622d0
real(kind=8), parameter,optional :: gamma_seven=720.d0
real(kind=8), parameter,optional,depend(cpmd,rgasmd) :: gammamd=-0.279
integer, optional :: algerr=64
real(kind=8), parameter,optional,depend(cp,rd) :: gamma=0.285896414343
real(kind=8), parameter,optional,depend(expon,rd,ussalr,g) :: exponi=5.25791098534
end module constants
subroutine deqthecalc(qvp,tmk,prs,eth,miy,mjx,mkzh) ! in :_wrffortran:eqthecalc.f90
threadsafe
use constants, only: tlclc2,tlclc3,tlclc1,tlclc4,eps,thtecon3,gammamd,thtecon1,gamma,thtecon2
real(kind=8) dimension(miy,mjx,mkzh),intent(in) :: qvp
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: tmk
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: prs
real(kind=8) dimension(miy,mjx,mkzh),intent(out,in),depend(miy,mjx,mkzh) :: eth
integer, optional,intent(in),check(shape(qvp,0)==miy),depend(qvp) :: miy=shape(qvp,0)
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)
end subroutine deqthecalc
function tvirtual(temp,ratmix) ! in :_wrffortran:rip_cape.f90
threadsafe
use constants, only: eps
real(kind=8) intent(in) :: temp
real(kind=8) intent(in) :: ratmix
real(kind=8) :: tvirtual
end function tvirtual
function tonpsadiabat(thte,prs,psadithte,psadiprs,psaditmk,gamma,errstat,errmsg) ! in :_wrffortran:rip_cape.f90
threadsafe
use constants, only: algerr
real(kind=8) intent(in) :: thte
real(kind=8) intent(in) :: prs
real(kind=8) dimension(150),intent(in) :: psadithte
real(kind=8) dimension(150),intent(in) :: psadiprs
real(kind=8) dimension(150,150),intent(in) :: psaditmk
real(kind=8) intent(in) :: gamma
integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg
real(kind=8) :: tonpsadiabat
end function tonpsadiabat
subroutine dlookup_table(psadithte,psadiprs,psaditmk,fname,errstat,errmsg) ! in :_wrffortran:rip_cape.f90
threadsafe
use constants, only: algerr
real(kind=8) dimension(150),intent(inout) :: psadithte
real(kind=8) dimension(150),intent(inout) :: psadiprs
real(kind=8) dimension(150,150),intent(inout) :: psaditmk
character*(*) intent(in) :: fname
integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg
end subroutine dlookup_table
subroutine dpfcalc(prs,sfp,pf,miy,mjx,mkzh,ter_follow) ! in :_wrffortran:rip_cape.f90
real(kind=8) dimension(miy,mjx,mkzh),intent(in) :: prs
real(kind=8) dimension(miy,mjx),intent(in),depend(miy,mjx) :: sfp
real(kind=8) dimension(miy,mjx,mkzh),intent(out),depend(miy,mjx,mkzh) :: pf
integer, optional,intent(in),check(shape(prs,0)==miy),depend(prs) :: miy=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,2)==mkzh),depend(prs) :: mkzh=shape(prs,2)
integer intent(in) :: ter_follow
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
threadsafe
use constants, only: tlclc2,gamma,tlclc1,rgasmd,tlclc4,g,tlclc3,thtecon3,eps,rd,cpmd,celkel,gammamd,eslcon2,eslcon1,cp,thtecon1,algerr,ezero,thtecon2
real(kind=8) dimension(miy,mjx,mkzh),intent(in) :: prs
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: tmk
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: qvp
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: ght
real(kind=8) dimension(miy,mjx),intent(in),depend(miy,mjx) :: ter
real(kind=8) dimension(miy,mjx),intent(in),depend(miy,mjx) :: sfp
real(kind=8) dimension(miy,mjx,mkzh),intent(out,in),depend(miy,mjx,mkzh) :: cape
real(kind=8) dimension(miy,mjx,mkzh),intent(out,in),depend(miy,mjx,mkzh) :: cin
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,1)==mjx),depend(prs) :: mjx=shape(prs,1)
integer, optional,intent(in),check(shape(prs,2)==mkzh),depend(prs) :: mkzh=shape(prs,2)
integer intent(in) :: i3dflag
integer intent(in) :: ter_follow
character*(*) intent(in) :: psafile
integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg
end subroutine dcapecalc3d
subroutine wrfcttcalc(prs,tk,qci,qcw,qvp,ght,ter,ctt,haveqci,ew,ns,nz) ! in :_wrffortran:wrf_fctt.f90
threadsafe
use constants, only: g,eps,rd,ussalr,abscoefi,abscoef,celkel
real(kind=8) dimension(ew,ns,nz),intent(in) :: prs
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: tk
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: qci
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: qcw
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: qvp
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: ght
real(kind=8) dimension(ew,ns),intent(in),depend(ew,ns) :: ter
real(kind=8) dimension(ew,ns),intent(out,in),depend(ew,ns) :: ctt
integer intent(in) :: haveqci
integer, optional,intent(in),check(shape(prs,0)==ew),depend(prs) :: ew=shape(prs,0)
integer, optional,intent(in),check(shape(prs,1)==ns),depend(prs) :: ns=shape(prs,1)
integer, optional,intent(in),check(shape(prs,2)==nz),depend(prs) :: nz=shape(prs,2)
end subroutine wrfcttcalc
subroutine dcomputeabsvort(av,u,v,msfu,msfv,msft,cor,dx,dy,nx,ny,nz,nxp1,nyp1) ! in :_wrffortran:wrf_pvo.f90
threadsafe
real(kind=8) dimension(nx,ny,nz),intent(out,in) :: av
real(kind=8) dimension(nxp1,ny,nz),intent(in),depend(ny,nz) :: u
real(kind=8) dimension(nx,nyp1,nz),intent(in),depend(nx,nz) :: v
real(kind=8) dimension(nxp1,ny),intent(in),depend(nxp1,ny) :: msfu
real(kind=8) dimension(nx,nyp1),intent(in),depend(nx,nyp1) :: msfv
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: msft
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: cor
real(kind=8) :: dx
real(kind=8) :: dy
integer, optional,intent(in),check(shape(av,0)==nx),depend(av) :: nx=shape(av,0)
integer, optional,intent(in),check(shape(av,1)==ny),depend(av) :: ny=shape(av,1)
integer, optional,intent(in),check(shape(av,2)==nz),depend(av) :: nz=shape(av,2)
integer, optional,intent(in),check(shape(u,0)==nxp1),depend(u) :: nxp1=shape(u,0)
integer, optional,intent(in),check(shape(v,1)==nyp1),depend(v) :: nyp1=shape(v,1)
end subroutine dcomputeabsvort
subroutine dcomputepv(pv,u,v,theta,prs,msfu,msfv,msft,cor,dx,dy,nx,ny,nz,nxp1,nyp1) ! in :_wrffortran:wrf_pvo.f90
threadsafe
use constants, only: g
real(kind=8) dimension(nx,ny,nz),intent(out,in) :: pv
real(kind=8) dimension(nxp1,ny,nz),intent(in),depend(ny,nz) :: u
real(kind=8) dimension(nx,nyp1,nz),intent(in),depend(nx,nz) :: v
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: theta
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: prs
real(kind=8) dimension(nxp1,ny),intent(in),depend(nxp1,ny) :: msfu
real(kind=8) dimension(nx,nyp1),intent(in),depend(nx,nyp1) :: msfv
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: msft
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: cor
real(kind=8) :: dx
real(kind=8) :: dy
integer, optional,intent(in),check(shape(pv,0)==nx),depend(pv) :: nx=shape(pv,0)
integer, optional,intent(in),check(shape(pv,1)==ny),depend(pv) :: ny=shape(pv,1)
integer, optional,intent(in),check(shape(pv,2)==nz),depend(pv) :: nz=shape(pv,2)
integer, optional,intent(in),check(shape(u,0)==nxp1),depend(u) :: nxp1=shape(u,0)
integer, optional,intent(in),check(shape(v,1)==nyp1),depend(v) :: nyp1=shape(v,1)
end subroutine dcomputepv
subroutine dcomputepw(p,tv,qv,ht,pw,nx,ny,nz,nzh) ! in :_wrffortran:wrf_pw.f90
threadsafe
use constants, only: rd
real(kind=8) dimension(nx,ny,nz),intent(in) :: p
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: tv
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: qv
real(kind=8) dimension(nx,ny,nzh),intent(in),depend(nx,ny) :: ht
real(kind=8) dimension(nx,ny),intent(out,in),depend(nx,ny) :: pw
integer, optional,intent(in),check(shape(p,0)==nx),depend(p) :: nx=shape(p,0)
integer, optional,intent(in),check(shape(p,1)==ny),depend(p) :: ny=shape(p,1)
integer, optional,intent(in),check(shape(p,2)==nz),depend(p) :: nz=shape(p,2)
integer, optional,intent(in),check(shape(ht,2)==nzh),depend(ht) :: nzh=shape(ht,2)
end subroutine dcomputepw
subroutine dcalrelhl(u,v,ght,ter,top,sreh,miy,mjx,mkzh) ! in :_wrffortran:wrf_relhl.f90
threadsafe
use constants, only: rad_per_deg,deg_per_rad,pi
real(kind=8) dimension(miy,mjx,mkzh),intent(in) :: u
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: v
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: ght
real(kind=8) dimension(miy,mjx),intent(in),depend(miy,mjx) :: ter
real(kind=8) intent(in) :: top
real(kind=8) dimension(miy,mjx),intent(out,in),depend(miy,mjx) :: sreh
integer, optional,intent(in),check(shape(u,0)==miy),depend(u) :: miy=shape(u,0)
integer, optional,intent(in),check(shape(u,1)==mjx),depend(u) :: mjx=shape(u,1)
integer, optional,intent(in),check(shape(u,2)==mkzh),depend(u) :: mkzh=shape(u,2)
end subroutine dcalrelhl
subroutine wetbulbcalc(prs,tmk,qvp,twb,nx,ny,nz,psafile,errstat,errmsg) ! in :_wrffortran:wrf_rip_phys_routines.f90
threadsafe
use constants, only: tlclc2,tlclc3,tlclc1,tlclc4,eps,thtecon3,gammamd,thtecon1,algerr,gamma,thtecon2
real(kind=8) dimension(nx,ny,nz),intent(in) :: prs
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: tmk
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: qvp
real(kind=8) dimension(nx,ny,nz),intent(out,in),depend(nx,ny,nz) :: twb
integer, optional,intent(in),check(shape(prs,0)==nx),depend(prs) :: nx=shape(prs,0)
integer, optional,intent(in),check(shape(prs,1)==ny),depend(prs) :: ny=shape(prs,1)
integer, optional,intent(in),check(shape(prs,2)==nz),depend(prs) :: nz=shape(prs,2)
character*(*) intent(in) :: psafile
integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg
end subroutine wetbulbcalc
subroutine omgcalc(qvp,tmk,www,prs,omg,mx,my,mz) ! in :_wrffortran:wrf_rip_phys_routines.f90
threadsafe
use constants, only: rd,eps,g
real(kind=8) dimension(mx,my,mz),intent(in) :: qvp
real(kind=8) dimension(mx,my,mz),intent(in),depend(mx,my,mz) :: tmk
real(kind=8) dimension(mx,my,mz),intent(in),depend(mx,my,mz) :: www
real(kind=8) dimension(mx,my,mz),intent(in),depend(mx,my,mz) :: prs
real(kind=8) dimension(mx,my,mz),intent(out,in),depend(mx,my,mz) :: omg
integer, optional,intent(in),check(shape(qvp,0)==mx),depend(qvp) :: mx=shape(qvp,0)
integer, optional,intent(in),check(shape(qvp,1)==my),depend(qvp) :: my=shape(qvp,1)
integer, optional,intent(in),check(shape(qvp,2)==mz),depend(qvp) :: mz=shape(qvp,2)
end subroutine omgcalc
subroutine virtual_temp(temp,ratmix,tv,nx,ny,nz) ! in :_wrffortran:wrf_rip_phys_routines.f90
threadsafe
use constants, only: eps
real(kind=8) dimension(nx,ny,nz),intent(in) :: temp
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: ratmix
real(kind=8) dimension(nx,ny,nz),intent(out,in),depend(nx,ny,nz) :: tv
integer, optional,intent(in),check(shape(temp,0)==nx),depend(temp) :: nx=shape(temp,0)
integer, optional,intent(in),check(shape(temp,1)==ny),depend(temp) :: ny=shape(temp,1)
integer, optional,intent(in),check(shape(temp,2)==nz),depend(temp) :: nz=shape(temp,2)
end subroutine virtual_temp
subroutine dcomputepi(pi,pressure,nx,ny,nz) ! in :_wrffortran:wrf_user.f90
threadsafe
use constants, only: p1000mb,cp,r_d
use constants, only: rd,p1000mb,cp
real(kind=8) dimension(nx,ny,nz),intent(out,in) :: pi
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: pressure
integer, optional,intent(in),check(shape(pi,0)==nx),depend(pi) :: nx=shape(pi,0)
@ -23,7 +274,7 @@ python module _wrffortran ! in @@ -23,7 +274,7 @@ python module _wrffortran ! in
end subroutine dcomputepi
subroutine dcomputetk(tk,pressure,theta,nx) ! in :_wrffortran:wrf_user.f90
threadsafe
use constants, only: p1000mb,cp,r_d
use constants, only: rd,p1000mb,cp
real(kind=8) dimension(nx),intent(out,in) :: tk
real(kind=8) dimension(nx),intent(in),depend(nx) :: pressure
real(kind=8) dimension(nx),intent(in),depend(nx) :: theta
@ -74,7 +325,7 @@ python module _wrffortran ! in @@ -74,7 +325,7 @@ python module _wrffortran ! in
end subroutine dinterp1d
subroutine dcomputeseaprs(nx,ny,nz,z,t,p,q,sea_level_pressure,t_sea_level,t_surf,level,errstat,errmsg) ! in :_wrffortran:wrf_user.f90
threadsafe
use constants, only: r,errlen,gamma,g
use constants, only: rd,ussalr,algerr,g
integer, optional,intent(in),check(shape(z,0)==nx),depend(z) :: nx=shape(z,0)
integer, optional,intent(in),check(shape(z,1)==ny),depend(z) :: ny=shape(z,1)
integer, optional,intent(in),check(shape(z,2)==nz),depend(z) :: nz=shape(z,2)
@ -86,8 +337,8 @@ python module _wrffortran ! in @@ -86,8 +337,8 @@ python module _wrffortran ! in
real(kind=8) dimension(nx,ny),intent(inout),depend(nx,ny) :: t_sea_level
real(kind=8) dimension(nx,ny),intent(inout),depend(nx,ny) :: t_surf
integer dimension(nx,ny),intent(inout),depend(nx,ny) :: level
integer, optional,intent(inout) :: errstat
character*errlen, optional,intent(inout) :: errmsg
integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg
end subroutine dcomputeseaprs
subroutine dfilter2d(a,b,nx,ny,it,missing) ! in :_wrffortran:wrf_user.f90
threadsafe
@ -109,6 +360,7 @@ python module _wrffortran ! in @@ -109,6 +360,7 @@ python module _wrffortran ! in
end subroutine filter2d
subroutine dcomputerh(qv,p,t,rh,nx) ! in :_wrffortran:wrf_user.f90
threadsafe
use constants, only: rv,eps,rd,ezero,eslcon2,eslcon1,celkel
real(kind=8) dimension(nx),intent(in) :: qv
real(kind=8) dimension(nx),intent(in),depend(nx) :: p
real(kind=8) dimension(nx),intent(in),depend(nx) :: t
@ -165,16 +417,144 @@ python module _wrffortran ! in @@ -165,16 +417,144 @@ python module _wrffortran ! in
integer, optional,intent(in),check(shape(iclw,1)==ny),depend(iclw) :: ny=shape(iclw,1)
integer, optional,intent(in),check(shape(pressure,2)==nz),depend(pressure) :: nz=shape(pressure,2)
end subroutine dcomputeiclw
subroutine testfunc(a,b,nx,ny,nz,errstat,errstr) ! in :_wrffortran:wrf_user.f90
threadsafe
subroutine testfunc(a,b,c,nx,ny,nz,errstat,errmsg) ! in :_wrffortran:wrf_user.f90
use constants, only: algerr
real(kind=8) dimension(nx,ny,nz),intent(in) :: a
real(kind=8) dimension(nx,ny,nz),intent(out,in),depend(nx,ny,nz) :: b
character*(*) intent(in) :: c
integer, optional,intent(in),check(shape(a,0)==nx),depend(a) :: nx=shape(a,0)
integer, optional,intent(in),check(shape(a,1)==ny),depend(a) :: ny=shape(a,1)
integer, optional,intent(in),check(shape(a,2)==nz),depend(a) :: nz=shape(a,2)
integer, optional,intent(inout) :: errstat
character*512, optional,intent(inout) :: errstr
integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg
end subroutine testfunc
subroutine calcdbz(prs,tmk,qvp,qra,qsn,qgr,sn0,ivarint,iliqskin,dbz,nx,ny,nz) ! in :_wrffortran:wrf_user_dbz.f90
threadsafe
use constants, only: rho_g,gamma_seven,rho_r,rd,rho_s,alpha,rhowat,pi,celkel
real(kind=8) dimension(nx,ny,nz),intent(in) :: prs
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: tmk
real(kind=8) dimension(nx,ny,nz),intent(inout),depend(nx,ny,nz) :: qvp
real(kind=8) dimension(nx,ny,nz),intent(inout),depend(nx,ny,nz) :: qra
real(kind=8) dimension(nx,ny,nz),intent(inout),depend(nx,ny,nz) :: qsn
real(kind=8) dimension(nx,ny,nz),intent(inout),depend(nx,ny,nz) :: qgr
integer intent(in) :: sn0
integer intent(in) :: ivarint
integer intent(in) :: iliqskin
real(kind=8) dimension(nx,ny,nz),intent(out,in),depend(nx,ny,nz) :: dbz
integer, optional,intent(in),check(shape(prs,0)==nx),depend(prs) :: nx=shape(prs,0)
integer, optional,intent(in),check(shape(prs,1)==ny),depend(prs) :: ny=shape(prs,1)
integer, optional,intent(in),check(shape(prs,2)==nz),depend(prs) :: nz=shape(prs,2)
end subroutine calcdbz
subroutine rotatecoords(ilat,ilon,olat,olon,lat_np,lon_np,lon_0,direction) ! in :_wrffortran:wrf_user_latlon_routines.f90
threadsafe
use constants, only: rad_per_deg,deg_per_rad,pi
real(kind=8) intent(in) :: ilat
real(kind=8) intent(in) :: ilon
real(kind=8) intent(out,in) :: olat
real(kind=8) intent(out,in) :: olon
real(kind=8) intent(in) :: lat_np
real(kind=8) intent(in) :: lon_np
real(kind=8) intent(in) :: lon_0
integer intent(in) :: direction
end subroutine rotatecoords
subroutine dlltoij(map_proj,truelat1,truelat2,stdlon,lat1,lon1,pole_lat,pole_lon,knowni,knownj,dx,dy,latinc,loninc,lat,lon,loc,errstat,errmsg) ! in :_wrffortran:wrf_user_latlon_routines.f90
threadsafe
use constants, only: rad_per_deg,deg_per_rad,pi,algerr,wrf_earth_radius
integer intent(in) :: map_proj
real(kind=8) intent(inout) :: truelat1
real(kind=8) intent(inout) :: truelat2
real(kind=8) intent(in) :: stdlon
real(kind=8) intent(in) :: lat1
real(kind=8) intent(in) :: lon1
real(kind=8) intent(in) :: pole_lat
real(kind=8) intent(in) :: pole_lon
real(kind=8) intent(in) :: knowni
real(kind=8) intent(in) :: knownj
real(kind=8) intent(in) :: dx
real(kind=8) intent(in) :: dy
real(kind=8) intent(in) :: latinc
real(kind=8) intent(in) :: loninc
real(kind=8) intent(inout) :: lat
real(kind=8) intent(inout) :: lon
real(kind=8) dimension(2),intent(out,in) :: loc
integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg
end subroutine dlltoij
subroutine dijtoll(map_proj,truelat1,truelat2,stdlon,lat1,lon1,pole_lat,pole_lon,knowni,knownj,dx,dy,latinc,loninc,ai,aj,loc,errstat,errmsg) ! in :_wrffortran:wrf_user_latlon_routines.f90
threadsafe
use constants, only: rad_per_deg,deg_per_rad,pi,algerr,wrf_earth_radius
integer intent(in) :: map_proj
real(kind=8) intent(inout) :: truelat1
real(kind=8) intent(inout) :: truelat2
real(kind=8) intent(in) :: stdlon
real(kind=8) intent(in) :: lat1
real(kind=8) intent(in) :: lon1
real(kind=8) intent(in) :: pole_lat
real(kind=8) intent(in) :: pole_lon
real(kind=8) intent(in) :: knowni
real(kind=8) intent(in) :: knownj
real(kind=8) intent(in) :: dx
real(kind=8) intent(in) :: dy
real(kind=8) intent(in) :: latinc
real(kind=8) intent(in) :: loninc
real(kind=8) intent(in) :: ai
real(kind=8) intent(in) :: aj
real(kind=8) dimension(2),intent(out,in) :: loc
integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg
end subroutine dijtoll
subroutine wrf_monotonic(out,in,lvprs,cor,idir,delta,ew,ns,nz,icorsw) ! in :_wrffortran:wrf_vinterp.f90
threadsafe
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),depend(ew,ns,nz) :: lvprs
real(kind=8) dimension(ew,ns),depend(ew,ns) :: cor
integer intent(in) :: idir
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,1)==ns),depend(out) :: ns=shape(out,1)
integer, optional,intent(in),check(shape(out,2)==nz),depend(out) :: nz=shape(out,2)
integer intent(in) :: icorsw
end subroutine wrf_monotonic
function wrf_intrp_value(wvalp0,wvalp1,vlev,vcp0,vcp1,icase,errstat,errmsg) ! in :_wrffortran:wrf_vinterp.f90
threadsafe
use constants, only: sclht,algerr
real(kind=8) intent(in) :: wvalp0
real(kind=8) intent(in) :: wvalp1
real(kind=8) intent(in) :: vlev
real(kind=8) intent(in) :: vcp0
real(kind=8) intent(in) :: vcp1
integer intent(in) :: icase
integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg
real(kind=8) :: 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
threadsafe
use constants, only: tlclc2,tlclc3,sclht,tlclc4,thtecon3,eps,tlclc1,celkel,exponi,gammamd,ussalr,expon,thtecon1,algerr,gamma,thtecon2
real(kind=8) dimension(ew,ns,nz),intent(in) :: datain
real(kind=8) dimension(ew,ns,numlevels),intent(out,in),depend(ew,ns) :: dataout
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: pres
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: tk
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: qvp
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: ght
real(kind=8) dimension(ew,ns),intent(in),depend(ew,ns) :: terrain
real(kind=8) dimension(ew,ns),intent(in),depend(ew,ns) :: sfp
real(kind=8) dimension(ew,ns),intent(in),depend(ew,ns) :: smsfp
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: vcarray
real(kind=8) dimension(numlevels),intent(in),depend(numlevels) :: interp_levels
integer, optional,intent(in),check(shape(dataout,2)==numlevels),depend(dataout) :: numlevels=shape(dataout,2)
integer intent(in) :: icase
integer, optional,intent(in),check(shape(datain,0)==ew),depend(datain) :: ew=shape(datain,0)
integer, optional,intent(in),check(shape(datain,1)==ns),depend(datain) :: ns=shape(datain,1)
integer, optional,intent(in),check(shape(datain,2)==nz),depend(datain) :: nz=shape(datain,2)
integer intent(in) :: extrap
integer intent(in) :: vcor
integer intent(in) :: logp
real(kind=8) intent(in) :: rmsg
integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg
end subroutine wrf_vintrp
end interface
end python module _wrffortran

5541
ncl_reference/WRFUsersherrie.ncl

File diff suppressed because it is too large Load Diff

60
ncl_reference/cloud_fracf.f

@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
C NCLFORTSTART
subroutine cloud_frac(pres,rh,lowc,midc,highc,nz,ns,ew)
implicit none
integer nz,ns,ew
real pres(ew,ns,nz),rh(ew,ns,nz)
real lowc(ew,ns),midc(ew,ns),highc(ew,ns)
C NCLEND
integer i,j,k
integer kchi,kcmi,kclo
DO j = 1,ns
DO i = 1,ew
DO k = 1,nz-1
c if((pres(i,j,k) .ge. 45000. ) .and.
c & (pres(i,j,k) .lt. 80000.)) then
c kchi = k
c else if((pres(i,j,k) .ge. 80000.) .and.
c & (pres(i,j,k) .lt. 97000.)) then
c kcmi = k
c else if (pres(i,j,k) .ge. 97000.) then
c kclo = k
c end if
IF ( pres(i,j,k) .gt. 97000. ) kclo=k
IF ( pres(i,j,k) .gt. 80000. ) kcmi=k
IF ( pres(i,j,k) .gt. 45000. ) kchi=k
end do
DO k = 1,nz-1
IF ( k .ge. kclo .AND. k .lt. kcmi ) then
lowc(i,j) = AMAX1(rh(i,j,k),lowc(i,j))
else IF ( k .ge. kcmi .AND. k .lt. kchi ) then !! mid cloud
midc(i,j) = AMAX1(rh(i,j,k),midc(i,j))
else if ( k .ge. kchi ) then !! high cloud
highc(i,j) = AMAX1(rh(i,j,k),highc(i,j))
end if
END DO
lowc(i,j) = 4.0 * lowc(i,j)/100.-3.0
midc(i,j) = 4.0 * midc(i,j)/100.-3.0
highc(i,j) = 2.5 * highc(i,j)/100.-1.5
lowc(i,j) = amin1(lowc(i,j),1.0)
lowc(i,j) = amax1(lowc(i,j),0.0)
midc(i,j) = amin1(midc(i,j),1.0)
midc(i,j) = amax1(midc(i,j),0.0)
highc(i,j) = amin1(highc(i,j),1.0)
highc(i,j) = amax1(highc(i,j),0.0)
END DO
END DO
return
end

170
ncl_reference/module_model_constants.f

@ -0,0 +1,170 @@ @@ -0,0 +1,170 @@
!WRF:MODEL_LAYER:CONSTANTS
!
MODULE module_model_constants
! 2. Following are constants for use in defining real number bounds.
! A really small number.
REAL , PARAMETER :: epsilon = 1.E-15
! 4. Following is information related to the physical constants.
! These are the physical constants used within the model.
! JM NOTE -- can we name this grav instead?
REAL , PARAMETER :: g = 9.81 ! acceleration due to gravity (m {s}^-2)
#if ( NMM_CORE == 1 )
REAL , PARAMETER :: r_d = 287.04
REAL , PARAMETER :: cp = 1004.6
#else
REAL , PARAMETER :: r_d = 287.
REAL , PARAMETER :: cp = 7.*r_d/2.
#endif
REAL , PARAMETER :: r_v = 461.6
REAL , PARAMETER :: cv = cp-r_d
REAL , PARAMETER :: cpv = 4.*r_v
REAL , PARAMETER :: cvv = cpv-r_v
REAL , PARAMETER :: cvpm = -cv/cp
REAL , PARAMETER :: cliq = 4190.
REAL , PARAMETER :: cice = 2106.
REAL , PARAMETER :: psat = 610.78
REAL , PARAMETER :: rcv = r_d/cv
REAL , PARAMETER :: rcp = r_d/cp
REAL , PARAMETER :: rovg = r_d/g
REAL , PARAMETER :: c2 = cp * rcv
real , parameter :: mwdry = 28.966 ! molecular weight of dry air (g/mole)
REAL , PARAMETER :: p1000mb = 100000.
REAL , PARAMETER :: t0 = 300.
REAL , PARAMETER :: p0 = p1000mb
REAL , PARAMETER :: cpovcv = cp/(cp-r_d)
REAL , PARAMETER :: cvovcp = 1./cpovcv
REAL , PARAMETER :: rvovrd = r_v/r_d
REAL , PARAMETER :: reradius = 1./6370.0e03
REAL , PARAMETER :: asselin = .025
! REAL , PARAMETER :: asselin = .0
REAL , PARAMETER :: cb = 25.
REAL , PARAMETER :: XLV0 = 3.15E6
REAL , PARAMETER :: XLV1 = 2370.
REAL , PARAMETER :: XLS0 = 2.905E6
REAL , PARAMETER :: XLS1 = 259.532
REAL , PARAMETER :: XLS = 2.85E6
REAL , PARAMETER :: XLV = 2.5E6
REAL , PARAMETER :: XLF = 3.50E5
REAL , PARAMETER :: rhowater = 1000.
REAL , PARAMETER :: rhosnow = 100.
REAL , PARAMETER :: rhoair0 = 1.28
!
! Now namelist-specified parameter: ccn_conc - RAS
! REAL , PARAMETER :: n_ccn0 = 1.0E8
!
REAL , PARAMETER :: piconst = 3.1415926535897932384626433
REAL , PARAMETER :: DEGRAD = piconst/180.
REAL , PARAMETER :: DPD = 360./365.
REAL , PARAMETER :: SVP1=0.6112
REAL , PARAMETER :: SVP2=17.67
REAL , PARAMETER :: SVP3=29.65
REAL , PARAMETER :: SVPT0=273.15
REAL , PARAMETER :: EP_1=R_v/R_d-1.
REAL , PARAMETER :: EP_2=R_d/R_v
REAL , PARAMETER :: KARMAN=0.4
REAL , PARAMETER :: EOMEG=7.2921E-5
REAL , PARAMETER :: STBOLT=5.67051E-8
REAL , PARAMETER :: prandtl = 1./3.0
! constants for w-damping option
REAL , PARAMETER :: w_alpha = 0.3 ! strength m/s/s
REAL , PARAMETER :: w_beta = 1.0 ! activation cfl number
REAL , PARAMETER :: pq0=379.90516
REAL , PARAMETER :: epsq2=0.2
REAL , PARAMETER :: a2=17.2693882
REAL , PARAMETER :: a3=273.16
REAL , PARAMETER :: a4=35.86
REAL , PARAMETER :: epsq=1.e-12
REAL , PARAMETER :: p608=rvovrd-1.
!#if ( NMM_CORE == 1 )
REAL , PARAMETER :: climit=1.e-20
REAL , PARAMETER :: cm1=2937.4
REAL , PARAMETER :: cm2=4.9283
REAL , PARAMETER :: cm3=23.5518
! REAL , PARAMETER :: defc=8.0
! REAL , PARAMETER :: defm=32.0
REAL , PARAMETER :: defc=0.0
REAL , PARAMETER :: defm=99999.0
REAL , PARAMETER :: epsfc=1./1.05
REAL , PARAMETER :: epswet=0.0
REAL , PARAMETER :: fcdif=1./3.
#if ( HWRF == 1 )
REAL , PARAMETER :: fcm=0.0
#else
REAL , PARAMETER :: fcm=0.00003
#endif
REAL , PARAMETER :: gma=-r_d*(1.-rcp)*0.5
REAL , PARAMETER :: p400=40000.0
REAL , PARAMETER :: phitp=15000.0
REAL , PARAMETER :: pi2=2.*3.1415926, pi1=3.1415926
REAL , PARAMETER :: plbtm=105000.0
REAL , PARAMETER :: plomd=64200.0
REAL , PARAMETER :: pmdhi=35000.0
REAL , PARAMETER :: q2ini=0.50
REAL , PARAMETER :: rfcp=0.25/cp
REAL , PARAMETER :: rhcrit_land=0.75
REAL , PARAMETER :: rhcrit_sea=0.80
REAL , PARAMETER :: rlag=14.8125
REAL , PARAMETER :: rlx=0.90
REAL , PARAMETER :: scq2=50.0
REAL , PARAMETER :: slopht=0.001
REAL , PARAMETER :: tlc=2.*0.703972477
REAL , PARAMETER :: wa=0.15
REAL , PARAMETER :: wght=0.35
REAL , PARAMETER :: wpc=0.075
REAL , PARAMETER :: z0land=0.10
#if ( HWRF == 1 )
REAL , PARAMETER :: z0max=0.01
#else
REAL , PARAMETER :: z0max=0.008
#endif
REAL , PARAMETER :: z0sea=0.001
!#endif
! Earth
! The value for P2SI *must* be set to 1.0 for Earth
! Although, now we may not need this declaration here (see above)
!REAL , PARAMETER :: P2SI = 1.0
! Orbital constants:
INTEGER , PARAMETER :: PLANET_YEAR = 365
REAL , PARAMETER :: OBLIQUITY = 23.5
REAL , PARAMETER :: ECCENTRICITY = 0.014
REAL , PARAMETER :: SEMIMAJORAXIS = 1.0 ! In AU
! Don't know the following values, so we'll fake them for now
REAL , PARAMETER :: zero_date = 0.0 ! Time of perihelion passage
! Fraction into the year (from perhelion) of the
! occurrence of the Northern Spring Equinox
REAL , PARAMETER :: EQUINOX_FRACTION= 0.0
! 2012103
#if (EM_CORE == 1)
! for calls to set_tiles
INTEGER, PARAMETER :: ZONE_SOLVE_EM = 1
INTEGER, PARAMETER :: ZONE_SFS = 2
#endif
CONTAINS
SUBROUTINE init_module_model_constants
END SUBROUTINE init_module_model_constants
END MODULE module_model_constants

380
ncl_reference/wrf_map_fix.ncl

@ -0,0 +1,380 @@ @@ -0,0 +1,380 @@
undef("set_mp_wrf_map_resources")
function set_mp_wrf_map_resources(in_file[1]:file,opt_args[1]:logical)
begin
;
opts = opt_args ; Make a copy of the resource list
; Set some resources depending on what kind of map projection is
; chosen.
;
; MAP_PROJ = 0 : "CylindricalEquidistant"
; MAP_PROJ = 1 : "LambertConformal"
; MAP_PROJ = 2 : "Stereographic"
; MAP_PROJ = 3 : "Mercator"
; MAP_PROJ = 6 : "Lat/Lon"
if(isatt(in_file,"MAP_PROJ"))
; CylindricalEquidistant
if(in_file@MAP_PROJ .eq. 0)
projection = "CylindricalEquidistant"
opts@mpProjection = projection
opts@mpGridSpacingF = 45
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", 0.0)
if(isatt(in_file,"STAND_LON"))
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",in_file@STAND_LON)
else
if(isatt(in_file,"CEN_LON"))
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",in_file@CEN_LON)
else
print("ERROR: Found neither STAND_LON or CEN_LON in file")
end if
end if
end if
; LambertConformal projection
if(in_file@MAP_PROJ .eq. 1)
projection = "LambertConformal"
opts@mpProjection = projection
opts@mpLambertParallel1F = get_res_value_keep(opts, "mpLambertParallel1F",in_file@TRUELAT1)
opts@mpLambertParallel2F = get_res_value_keep(opts, "mpLambertParallel2F",in_file@TRUELAT2)
if(isatt(in_file,"STAND_LON"))
opts@mpLambertMeridianF = get_res_value_keep(opts, "mpLambertMeridianF",in_file@STAND_LON)
else
if(isatt(in_file,"CEN_LON"))
opts@mpLambertMeridianF = get_res_value_keep(opts, "mpLambertMeridianF",in_file@CEN_LON)
else
print("ERROR: Found neither STAND_LON or CEN_LON in file")
end if
end if
end if
; Stereographic projection
if(in_file@MAP_PROJ .eq. 2)
projection = "Stereographic"
opts@mpProjection = projection
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", in_file@CEN_LAT)
if(isatt(in_file,"STAND_LON"))
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",in_file@STAND_LON)
else
if(isatt(in_file,"CEN_LON"))
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",in_file@CEN_LON)
else
print("ERROR: Found neither STAND_LON or CEN_LON in file")
end if
end if
end if
; Mercator projection
if(in_file@MAP_PROJ .eq. 3)
projection = "Mercator"
opts@mpProjection = projection
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", 0.0)
if(isatt(in_file,"STAND_LON"))
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",in_file@STAND_LON)
else
if(isatt(in_file,"CEN_LON"))
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",in_file@CEN_LON)
else
print("ERROR: Found neither STAND_LON or CEN_LON in file")
end if
end if
end if
; global WRF CylindricalEquidistant
if(in_file@MAP_PROJ .eq. 6)
projection = "CylindricalEquidistant"
opts@mpProjection = projection
opts@mpGridSpacingF = 45
if (isatt(in_file,"POLE_LON") .and. isatt(in_file,"POLE_LAT") .and. isatt(in_file,"STAND_LON")) then
if (in_file@POLE_LON .eq. 0 .and. in_file@POLE_LAT .eq. 90) then
; not rotated
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", 0.0)
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",180 - in_file@STAND_LON)
else
; rotated
southern = False ; default to northern hemisphere
if (in_file@POLE_LON .eq. 0.0) then
southern = True
else if (in_file@POLE_LON .ne. 180) then
if (isatt(in_file,"CEN_LAT") .and. in_file@CEN_LAT .lt. 0.0) then
southern = True ; probably but not necessarily true -- no way to tell for sure
end if
end if
end if
if (.not. southern) then
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", 90.0 - in_file@POLE_LAT)
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF", -in_file@STAND_LON)
else
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", in_file@POLE_LAT - 90)
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF", 180 - in_file@STAND_LON)
end if
end if
else if (isatt(in_file,"ref_lon") .and. isatt(in_file,"ref_lat")) then
;; this is definitely true for NMM grids but unlikely for ARW grids especially if ref_x and ref_y are set
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", in_file@REF_LAT)
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF", in_file@REF_LON)
else if (isatt(in_file,"cen_lat") .and. isatt(in_file,"cen_lon")) then
;; these usually specifiy the center of the coarse domain --- not necessarily the center of the projection
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF",in_file@CEN_LAT)
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",in_file@CEN_LON)
else
;; default values for global grid
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", 0.0)
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF", 180.0)
end if
end if
end if
end if
end if
return(opts) ; Return.
end
undef("wrf_map_resources")
function wrf_map_resources(in_file[1]:file,map_args[1]:logical)
local lat, lon, x1, x2, y1, y2, dims, ii, jj, southern
begin
;
; This function sets resources for a WRF map plot, basing the projection on
; the MAP_PROJ attribute in the given file. It's intended to be callable
; by users who need to set mpXXXX resources for other plotting scripts.
;
; Set some resources depending on what kind of map projection is
; chosen.
;
; MAP_PROJ = 0 : "CylindricalEquidistant"
; MAP_PROJ = 1 : "LambertConformal"
; MAP_PROJ = 2 : "Stereographic"
; MAP_PROJ = 3 : "Mercator"
; MAP_PROJ = 6 : "Lat/Lon"
if(isatt(in_file,"MAP_PROJ"))
; CylindricalEquidistant
if(in_file@MAP_PROJ .eq. 0)
map_args@mpProjection = "CylindricalEquidistant"
map_args@mpGridSpacingF = 45
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", 0.0)
if(isatt(in_file,"STAND_LON"))
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",in_file@STAND_LON)
else
if(isatt(in_file,"CEN_LON"))
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",in_file@CEN_LON)
else
print("ERROR: Found neither STAND_LON or CEN_LON in file")
end if
end if
end if
; LambertConformal projection
if(in_file@MAP_PROJ .eq. 1)
map_args@mpProjection = "LambertConformal"
map_args@mpLambertParallel1F = get_res_value_keep(map_args, "mpLambertParallel1F",in_file@TRUELAT1)
map_args@mpLambertParallel2F = get_res_value_keep(map_args, "mpLambertParallel2F",in_file@TRUELAT2)
if(isatt(in_file,"STAND_LON"))
map_args@mpLambertMeridianF = get_res_value_keep(map_args, "mpLambertMeridianF",in_file@STAND_LON)
else
if(isatt(in_file,"CEN_LON"))
map_args@mpLambertMeridianF = get_res_value_keep(map_args, "mpLambertMeridianF",in_file@CEN_LON)
else
print("ERROR: Found neither STAND_LON or CEN_LON in file")
end if
end if
end if
; Stereographic projection
if(in_file@MAP_PROJ .eq. 2)
map_args@mpProjection = "Stereographic"
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", in_file@CEN_LAT)
if(isatt(in_file,"STAND_LON"))
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",in_file@STAND_LON)
else
if(isatt(in_file,"CEN_LON"))
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",in_file@CEN_LON)
else
print("ERROR: Found neither STAND_LON or CEN_LON in file")
end if
end if
end if
; Mercator projection
if(in_file@MAP_PROJ .eq. 3)
map_args@mpProjection = "Mercator"
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", 0.0)
if(isatt(in_file,"STAND_LON"))
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",in_file@STAND_LON)
else
if(isatt(in_file,"CEN_LON"))
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",in_file@CEN_LON)
else
print("ERROR: Found neither STAND_LON or CEN_LON in file")
end if
end if
end if
; global WRF CylindricalEquidistant
if(in_file@MAP_PROJ .eq. 6)
print ("YES, THIS WORKED")
projection = "CylindricalEquidistant"
map_args@mpProjection = projection
map_args@mpGridSpacingF = 45
;; according to the docs if POLE_LON is 0 then the projection center is in the southern hemisphere
;; if POLE_LON is 180 the projection center is in the northern hemisphere
;; otherwise you can't tell for sure -- CEN_LAT does not have to be the projection center but hopefully
;; it is in the same hemisphere. The same is true for REF_LAT except that if REF_Y is specified REF_LAT might
;; be in a corner or somewhere else and therefore it is even less reliable
;;
if (isatt(in_file,"POLE_LON") .and. isatt(in_file,"POLE_LAT") .and. isatt(in_file,"STAND_LON")) then
if (in_file@POLE_LON .eq. 0 .and. in_file@POLE_LAT .eq. 90) then
; not rotated
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", 0.0)
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",180 - in_file@STAND_LON)
else
; rotated
southern = False ; default to northern hemisphere
if (in_file@POLE_LON .eq. 0.0) then
southern = True
else if (in_file@POLE_LON .ne. 180) then
if (isatt(in_file,"CEN_LAT") .and. in_file@CEN_LAT .lt. 0.0) then
southern = True ; probably but not necessarily true -- no way to tell for sure
end if
end if
end if
if (.not. southern) then
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", 90.0 - in_file@POLE_LAT)
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF", -in_file@STAND_LON)
else
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", in_file@POLE_LAT - 90)
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF", 180 - in_file@STAND_LON)
end if
end if
else if (isatt(in_file,"ref_lon") .and. isatt(in_file,"ref_lat")) then
;; this is definitely true for NMM grids but unlikely for ARW grids especially if ref_x and ref_y are set
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", in_file@REF_LAT)
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF", in_file@REF_LON)
else if (isatt(in_file,"cen_lat") .and. isatt(in_file,"cen_lon")) then
;; these usually specifiy the center of the coarse domain --- not necessarily the center of the projection
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF",in_file@CEN_LAT)
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",in_file@CEN_LON)
else
;; default values for global grid
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", 0.0)
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF", 180.0)
end if
end if
end if
end if
else
return(map_args)
end if
map_args@mpNestTime = get_res_value_keep(map_args, "mpNestTime",0)
if(isfilevar(in_file,"XLAT"))
lat = in_file->XLAT(map_args@mpNestTime,:,:)
lon = in_file->XLONG(map_args@mpNestTime,:,:)
else
lat = in_file->XLAT_M(map_args@mpNestTime,:,:)
lon = in_file->XLONG_M(map_args@mpNestTime,:,:)
end if
dims = dimsizes(lat)
do ii = 0, dims(0)-1
do jj = 0, dims(1)-1
if ( lon(ii,jj) .lt. 0.0) then
lon(ii,jj) = lon(ii,jj) + 360.
end if
end do
end do
map_args@start_lat = lat(0,0)
map_args@start_lon = lon(0,0)
map_args@end_lat = lat(dims(0)-1,dims(1)-1)
map_args@end_lon = lon(dims(0)-1,dims(1)-1)
; end_lon must be greater than start_lon, or errors are thrown
if (map_args@end_lon .le. map_args@start_lon) then
map_args@end_lon = map_args@end_lon + 360.0
end if
; Set some resources common to all map projections.
map_args = set_mp_resources(map_args)
if ( isatt(map_args,"ZoomIn") .and. map_args@ZoomIn ) then
y1 = 0
x1 = 0
y2 = dims(0)-1
x2 = dims(1)-1
if ( isatt(map_args,"Ystart") ) then
y1 = map_args@Ystart
delete(map_args@Ystart)
end if
if ( isatt(map_args,"Xstart") ) then
x1 = map_args@Xstart
delete(map_args@Xstart)
end if
if ( isatt(map_args,"Yend") ) then
if ( map_args@Yend .le. y2 ) then
y2 = map_args@Yend
end if
delete(map_args@Yend)
end if
if ( isatt(map_args,"Xend") ) then
if ( map_args@Xend .le. x2 ) then
x2 = map_args@Xend
end if
delete(map_args@Xend)
end if
map_args@mpLeftCornerLatF = lat(y1,x1)
map_args@mpLeftCornerLonF = lon(y1,x1)
map_args@mpRightCornerLatF = lat(y2,x2)
map_args@mpRightCornerLonF = lon(y2,x2)
if ( map_args@mpRightCornerLonF .lt. 0.0 ) then
map_args@mpRightCornerLonF = map_args@mpRightCornerLonF + 360.0
end if
if ( map_args@mpRightCornerLonF .le. map_args@mpRightCornerLonF ) then
map_args@mpRightCornerLonF = map_args@mpRightCornerLonF + 360.0
end if
delete(map_args@ZoomIn)
end if
return(map_args)
end

40
setup.py

@ -1,22 +1,34 @@ @@ -1,22 +1,34 @@
import setuptools
import numpy.distutils.core
ext1 = numpy.distutils.core.Extension(
name = "wrf._wrfext",
sources = ["src/wrf/wrfext.f90",
"src/wrf/wrfext.pyf"]
)
#ext1 = numpy.distutils.core.Extension(
# name = "wrf._wrfext",
# sources = ["src/wrf/wrfext.f90",
# "src/wrf/wrfext.pyf"]
# )
ext2 = numpy.distutils.core.Extension(
name = "wrf._wrfcape",
sources = ["src/wrf/wrfcape.f90",
"src/wrf/wrfcape.pyf"]
)
#ext2 = numpy.distutils.core.Extension(
# name = "wrf._wrfcape",
# sources = ["src/wrf/wrfcape.f90",
# "src/wrf/wrfcape.pyf"]
# )
ext3 = numpy.distutils.core.Extension(
ext1 = numpy.distutils.core.Extension(
name = "wrf._wrffortran",
sources = ["fortran/constants.f90",
"fortran/wrf_user.f90",
"fortran/rip_cape.f90",
"fortran/cloud_fracf.f90",
"fortran/wrf_fctt.f90",
"fortran/wrf_user_dbz.f90",
"fortran/wrf_relhl.f90",
"fortran/calc_uh.f90",
"fortran/wrf_user_latlon_routines.f90",
"fortran/wrf_pvo.f90",
"fortran/eqthecalc.f90",
"fortran/wrf_rip_phys_routines.f90",
"fortran/wrf_pw.f90",
"fortran/wrf_vinterp.f90",
"fortran/wrffortran.pyf"]
)
@ -24,8 +36,10 @@ numpy.distutils.core.setup( @@ -24,8 +36,10 @@ numpy.distutils.core.setup(
name = "wrf",
version = "0.0.1",
packages = setuptools.find_packages("src"),
ext_modules = [ext1,ext2,ext3],
ext_modules = [ext1],
package_dir={"" : "src"},
#namespace_packages=["wrf"],
scripts=[],
# Note: If this doesn't work, you need to add the file to MANIFEST
package_data={"wrf" : ["data/psadilookup.dat"]},
scripts=[]
)

16
src/wrf/api.py

@ -6,10 +6,12 @@ from .constants import ALL_TIMES, Constants, ConversionFactors @@ -6,10 +6,12 @@ from .constants import ALL_TIMES, Constants, ConversionFactors
from .destag import destagger
from .routines import getvar
from .computation import (xy, interp1d, interp2dxy, interpz3d, slp, tk, td, rh,
uvmet, smooth2d)
uvmet, smooth2d, cape_2d, cape_3d, cloudfrac)
from .interp import (interplevel, vertcross, interpline, vinterp)
from .util import (viewitems, viewkeys, viewvalues, isstr, py2round,
py3range, ucode, npvalues, extract_global_attrs,
from .latlon import (xy_to_ll, ll_to_xy)
from .py3compat import (viewitems, viewkeys, viewvalues, isstr, py2round,
py3range, ucode)
from .util import (npvalues, extract_global_attrs,
extract_dim, extract_vars, extract_times, combine_files,
is_staggered, get_left_indexes, iter_left_indexes,
get_right_slices, get_proj_params)
@ -22,11 +24,13 @@ __all__ += ["xarray_enabled", "disable_xarray", "enable_xarray", @@ -22,11 +24,13 @@ __all__ += ["xarray_enabled", "disable_xarray", "enable_xarray",
__all__ += ["ALL_TIMES", "Constants", "ConversionFactors"]
__all__ += ["destagger"]
__all__ += ["getvar"]
__all__ += ["xy", "interp1d", "interp2dxy", "interpz3d", "slp", "tk", "td", "rh",
"uvmet", "smooth2d"]
__all__ += ["xy", "interp1d", "interp2dxy", "interpz3d", "slp", "tk", "td",
"rh", "uvmet", "smooth2d", "cape_2d", "cape_3d", "cloudfrac"]
__all__ += ["interplevel", "vertcross", "interpline", "vinterp"]
__all__ += ["xy_to_ll", "ll_to_xy"]
__all__ += ["viewitems", "viewkeys", "viewvalues", "isstr", "py2round",
"py3range", "ucode", "npvalues", "extract_global_attrs",
"py3range", "ucode"]
__all__ += ["npvalues", "extract_global_attrs",
"extract_dim", "extract_vars", "extract_times", "combine_files",
"is_staggered", "get_left_indexes", "iter_left_indexes",
"get_right_slices", "get_proj_params"]

96
src/wrf/cape.py

@ -1,26 +1,28 @@ @@ -1,26 +1,28 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import numpy as n
import numpy as np
import numpy.ma as ma
#from .extension import computetk,computecape
from .extension import _tk,computecape
from .extension import _tk, _cape
from .destag import destagger
from .constants import Constants, ConversionFactors
from .util import extract_vars, combine_with
from .metadecorators import copy_and_set_metadata
@copy_and_set_metadata(copy_varname="T",
name="cape_2d",
dimnames=combine_with("T", remove_dims=("bottom_top",),
insert_before="south_north",
new_dimnames=["mcape_mcin_lcl_lfc"]),
description="mcape ; mcin ; lcl ; lfc",
units="J/kg ; J/kg ; m ; m",
MemoryOrder="XY")
from .metadecorators import set_cape_metadata
#@copy_and_set_metadata(copy_varname="T",
# name="cape_2d",
# dimnames=combine_with("T", remove_dims=("bottom_top",),
# insert_before="south_north",
# new_dimnames=["mcape_mcin_lcl_lfc"]),
# description="mcape ; mcin ; lcl ; lfc",
# units="J/kg ; J/kg ; m ; m",
# MemoryOrder="XY")
@set_cape_metadata(is2d=True)
def get_2dcape(wrfnc, timeidx=0, method="cat",
squeeze=True, cache=None, meta=True,
missing=Constants.DEFAULT_FILL):
"""Return the 2d fields of cape, cin, lcl, and lfc"""
@ -53,37 +55,35 @@ def get_2dcape(wrfnc, timeidx=0, method="cat", @@ -53,37 +55,35 @@ def get_2dcape(wrfnc, timeidx=0, method="cat",
i3dflag = 0
ter_follow = 1
cape_res,cin_res = computecape(p_hpa,tk,qv,z,ter,psfc_hpa,
missing,i3dflag,ter_follow)
cape_cin = _cape(p_hpa, tk, qv, z, ter, psfc_hpa, missing, i3dflag,
ter_follow)
cape = cape_res[...,0,:,:]
cin = cin_res[...,0,:,:]
lcl = cin_res[...,1,:,:]
lfc = cin_res[...,2,:,:]
left_dims = cape_cin.shape[1:-3]
right_dims = cape_cin.shape[-2:]
left_dims = [x for x in cape_res.shape[0:-3]]
right_dims = [x for x in cape_res.shape[-2:]]
resdim = left_dims + [4] + right_dims
resdim = (4,) + left_dims + right_dims
# Make a new output array for the result
res = n.zeros(resdim, cape.dtype)
res[...,0,:,:] = cape[:]
res[...,1,:,:] = cin[:]
res[...,2,:,:] = lcl[:]
res[...,3,:,:] = lfc[:]
return ma.masked_values(res, missing)
@copy_and_set_metadata(copy_varname="T", name="cape_3d",
dimnames=combine_with("T",
insert_before="bottom_top",
new_dimnames=["cape_cin"]),
description="cape ; cin",
units="J kg-1 ; J kg-1",
MemoryOrder="XY")
result = np.zeros(resdim, cape_cin.dtype)
# Cape 2D output is not flipped in the vertical, so index from the
# end
result[0,...,:,:] = cape_cin[0,...,-1,:,:]
result[1,...,:,:] = cape_cin[1,...,-1,:,:]
result[2,...,:,:] = cape_cin[1,...,-2,:,:]
result[3,...,:,:] = cape_cin[1,...,-3,:,:]
return ma.masked_values(result, missing)
#@copy_and_set_metadata(copy_varname="T", name="cape_3d",
# dimnames=combine_with("T",
# insert_before="bottom_top",
# new_dimnames=["cape_cin"]),
# description="cape ; cin",
# units="J kg-1 ; J kg-1",
# MemoryOrder="XY")
@set_cape_metadata(is2d=False)
def get_3dcape(wrfnc, timeidx=0, method="cat",
squeeze=True, cache=None, meta=True,
missing=Constants.DEFAULT_FILL):
@ -115,21 +115,11 @@ def get_3dcape(wrfnc, timeidx=0, method="cat", @@ -115,21 +115,11 @@ def get_3dcape(wrfnc, timeidx=0, method="cat",
i3dflag = 1
ter_follow = 1
cape,cin = computecape(p_hpa,tk,qv,z,ter,psfc_hpa,
missing,i3dflag,ter_follow)
# Make a new output array for the result
left_dims = [x for x in cape.shape[0:-3]]
right_dims = [x for x in cape.shape[-3:]]
resdim = left_dims + [2] + right_dims
res = n.zeros(resdim, cape.dtype)
cape_cin = _cape(p_hpa, tk, qv, z, ter, psfc_hpa, missing, i3dflag,
ter_follow)
res[...,0,:,:,:] = cape[:]
res[...,1,:,:,:] = cin[:]
return ma.masked_values(res, missing)
return ma.masked_values(cape_cin, missing)

27
src/wrf/cloudfrac.py

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
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(wrfnc, timeidx=0, method="cat", squeeze=True,
cache=None, meta=True):
vars = extract_vars(wrfnc, timeidx, ("P", "PB", "QVAPOR", "T"),
method, squeeze, cache, meta=False)
p = vars["P"]
pb = vars["PB"]
qv = vars["QVAPOR"]
t = vars["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)

162
src/wrf/computation.py

@ -1,10 +1,17 @@ @@ -1,10 +1,17 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import numpy as np
import numpy.ma as ma
from .constants import Constants
from .extension import (_interpz3d, _interp2dxy, _interp1d, _slp, _tk, _td,
_rh, _uvmet, _smooth2d)
_rh, _uvmet, _smooth2d, _cape, _cloudfrac, _ctt, _dbz,
_srhel, _udhel, _eth, _wetbulb, _tv, _omega)
from .util import from_var
from .metadecorators import (set_alg_metadata, set_uvmet_alg_metadata,
set_interp_metadata)
set_interp_metadata, set_cape_alg_metadata,
set_cloudfrac_alg_metadata)
from .interputils import get_xy
@set_interp_metadata("xy")
@ -30,25 +37,25 @@ def interpz3d(field3d, z, desiredloc, missingval=Constants.DEFAULT_FILL, @@ -30,25 +37,25 @@ def interpz3d(field3d, z, desiredloc, missingval=Constants.DEFAULT_FILL,
return _interpz3d(field3d, z, desiredloc, missingval)
@set_alg_metadata(2, refvarname="z", refvarndims=3, units="hpa",
@set_alg_metadata(2, "z", refvarndims=3, units="hpa",
description="sea level pressure")
def slp(z, t, p, q, meta=True):
return _slp(z, t, p, q)
@set_alg_metadata(3, refvarname="pressure", units="K",
@set_alg_metadata(3, "pressure", units="K",
description="temperature")
def tk(pressure, theta, meta=True):
return _tk(pressure, theta)
@set_alg_metadata(3, refvarname="pressure", units="degC",
@set_alg_metadata(3, "pressure", units="degC",
description="dew point temperature")
def td(pressure, qv_in, meta=True):
return _td(pressure, qv_in)
@set_alg_metadata(3, refvarname="pressure",
@set_alg_metadata(3, "pressure",
description="relative humidity", units=None)
def rh(qv, q, t, meta=True):
return _rh(qv, q, t, meta)
@ -59,9 +66,148 @@ def uvmet(u, v, lat, lon, cen_long, cone, meta=True): @@ -59,9 +66,148 @@ def uvmet(u, v, lat, lon, cen_long, cone, meta=True):
return _uvmet(u, v, lat, lon, cen_long, cone)
@set_alg_metadata(2,
refvarname="field",
@set_alg_metadata(2, "field",
description=from_var("field", "description"),
units=from_var("field", "units"))
def smooth2d(field, passes, meta=True):
return _smooth2d(field, passes)
@set_cape_alg_metadata(is2d=True)
def cape_2d(p_hpa, tk, qvapor, height, terrain, psfc_hpa, ter_follow,
missing=Constants.DEFAULT_FILL, meta=True):
if isinstance(ter_follow, bool):
ter_follow = 1 if ter_follow else 0
i3dflag = 0
cape_cin = _cape(p_hpa, tk, qvapor, height, terrain, psfc_hpa,
missing, i3dflag, ter_follow)
left_dims = cape_cin.shape[1:-3]
right_dims = cape_cin.shape[-2:]
resdim = (4,) + left_dims + right_dims
# Make a new output array for the result
result = np.zeros(resdim, cape_cin.dtype)
# Cape 2D output is not flipped in the vertical, so index from the
# end
result[0,...,:,:] = cape_cin[0,...,-1,:,:]
result[1,...,:,:] = cape_cin[1,...,-1,:,:]
result[2,...,:,:] = cape_cin[1,...,-2,:,:]
result[3,...,:,:] = cape_cin[1,...,-3,:,:]
return ma.masked_values(result, missing)
@set_cape_alg_metadata(is2d=False)
def cape_3d(p_hpa, tk, qvapor, height, terrain, psfc_hpa, ter_follow,
missing=Constants.DEFAULT_FILL, meta=True):
if isinstance(ter_follow, bool):
ter_follow = 1 if ter_follow else 0
i3dflag = 1
cape_cin = _cape(p_hpa, tk, qvapor, height, terrain, psfc_hpa,
missing, i3dflag, ter_follow)
return ma.masked_values(cape_cin, missing)
@set_cloudfrac_alg_metadata()
def cloudfrac(p, rh, meta=True):
return _cloudfrac(p, rh)
@set_alg_metadata(2, "p_hpa", refvarndims=3, units="degC",
description="cloud top temperature")
def ctt(p_hpa, tk, qv, qcld, ght, ter, qice=None, meta=True):
# Qice and QCLD need to be in g/kg
if qice is None:
qice = n.zeros(qv.shape, qv.dtype)
haveqci = 0
else:
haveqci = 1 if qice.any() else 0
ctt = _ctt(p_hpa, tk, qice, qcld, qv, ght, ter, haveqci)
return _ctt(p, rh)
@set_alg_metadata(3, "p", units="dBZ",
description="radar reflectivity")
def dbz(p, tk, qv, qr, ivarint, iliqskin, qs=None, qg=None, meta=True):
if qs is None:
qs = np.zeros(qv.shape, qv.dtype)
if qg is None:
qg = np.zeros(qv.shape, qv.dtype)
sn0 = 1 if qs.any() else 0
ivarint = 1 if do_varint else 0
iliqskin = 1 if do_liqskin else 0
return _dbz(p, tk, qv, qr, qs, qg, sn0, ivarint, iliqskin)
@set_alg_metadata(2, "ter", units="m-2/s-2",
description="storm relative helicity")
def srhel(u, v, z, ter, top):
return _srhel(u, v, z, ter, top=3000.0)
@set_alg_metadata(2, "u", refvarndims=3, units="m-2/s-2",
description="updraft helicity")
def udhel(zstag, mapfct, u, v, wstag, dx, dy, bottom=2000.0, top=5000.0):
return _udhel(zstag, mapfct, u, v, wstag, dx, dy, bottom, top)
# Requires both u an v for dimnames
@set_alg_metadata(3, "u", units="10-5 s-1",
stagdim=-1, stagsubvar="vstag",
description="absolute vorticity")
def avo(ustag, vstag, msfu, msfv, msfm, cor, dx, dy):
return _avo(ustag, vstag, msfu, msfv, msfm, cor, dx, dy)
@set_alg_metadata(3, "t", units="PVU",
description="potential vorticity")
def pvo(ustag, vstag, t, p, msfu, msfv, msfm, cor, dx, dy):
return _pvo(ustag, vstag, t, p, msfu, msfv, msfm, cor, dx, dy)
@set_alg_metadata(3, "qv", units="K",
description="equivalent potential temperature")
def eth(qv, tk, p):
return _eth(qv, tk, p)
@set_alg_metadata(3, "p", units="K",
description="wetbulb temperature")
def wetbulb(p, tk, qv):
return _wetbulb(p, tk, qv)
@set_alg_metadata(3, "tk", units="K",
description="virtual temperature")
def tvirtual(tk, qv):
return _tv(tk, qv)
@set_alg_metadata(3, "qv", units="Pa/s",
description="omega")
def omega(qv, tk, w, p):
return _omega(qv, tk, w, p)
@set_alg_metadata(2, "p", refvarndims=3, units="kg m-2",
description="precipitable water")
def pw(p, tk, qv, ht):
tv = _tv(tk, qv)
return _pw(full_p, tv, qv, ht)

5
src/wrf/config.py

@ -29,11 +29,6 @@ except ImportError: @@ -29,11 +29,6 @@ except ImportError:
else:
_PYNGL_ENABLED = True
__all__ = ["xarray_enabled", "disable_xarray", "enable_xarray",
"cartopy_enabled", "enable_cartopy", "enable_cartopy",
"basemap_enabled", "disable_basemap", "enable_basemap",
"pyngl_enabled", "enable_pyngl", "disable_pyngl"]
def xarray_enabled():
global _XARRAY_ENABLED
return _XARRAY_ENABLED

18
src/wrf/constants.py

@ -1,18 +1,18 @@ @@ -1,18 +1,18 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import numpy as np
from .py3compat import viewitems
from wrf._wrffortran import constants
ALL_TIMES = None
class Constants(object):
R = 287.06
CP = 1005.0
G = 9.81
TCK0 = 273.15
T_BASE = 300.0 # In WRF the base temperature is always 300 (not var T00)
PI = 3.141592653589793
DEFAULT_FILL = 9.9692099683868690e+36 # Value is from netcdf.h
WRF_EARTH_RADIUS = 6370000.
ERRLEN = 512
pass
for key,val in viewitems(constants.__dict__):
setattr(Constants, key.upper(), np.asscalar(val))
class ConversionFactors(object):
PA_TO_HPA = .01

4
src/wrf/ctt.py

@ -4,7 +4,7 @@ from __future__ import (absolute_import, division, print_function, @@ -4,7 +4,7 @@ from __future__ import (absolute_import, division, print_function,
import numpy as n
#from .extension import computectt, computetk
from .extension import computectt, _tk
from .extension import _ctt, _tk
from .constants import Constants, ConversionFactors
from .destag import destagger
from .decorators import convert_units
@ -61,6 +61,6 @@ def get_ctt(wrfnc, timeidx=0, method="cat", @@ -61,6 +61,6 @@ def get_ctt(wrfnc, timeidx=0, method="cat",
geopt_unstag = destagger(geopt, -3)
ght = geopt_unstag / Constants.G
ctt = computectt(p_hpa, tk, qice, qcld, qv, ght, ter, haveqci)
ctt = _ctt(p_hpa, tk, qice, qcld, qv, ght, ter, haveqci)
return ctt

4575
src/wrf/data/psadilookup.dat

File diff suppressed because it is too large Load Diff

29
src/wrf/dbz.py

@ -1,10 +1,10 @@ @@ -1,10 +1,10 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import numpy as n
import numpy as np
#from .extension import computedbz,computetk
from .extension import computedbz, _tk
from .extension import _dbz, _tk
from .constants import Constants
from .util import extract_vars
from .metadecorators import copy_and_set_metadata
@ -39,7 +39,7 @@ def get_dbz(wrfnc, timeidx=0, method="cat", @@ -39,7 +39,7 @@ def get_dbz(wrfnc, timeidx=0, method="cat",
snowvars = extract_vars(wrfnc, timeidx, "QSNOW",
method, squeeze, cache, meta=False)
except KeyError:
qs = n.zeros(qv.shape, "float")
qs = np.zeros(qv.shape, qv.dtype)
else:
qs = snowvars["QSNOW"]
@ -47,28 +47,20 @@ def get_dbz(wrfnc, timeidx=0, method="cat", @@ -47,28 +47,20 @@ def get_dbz(wrfnc, timeidx=0, method="cat",
graupvars = extract_vars(wrfnc, timeidx, "QGRAUP",
method, squeeze, cache, meta=False)
except KeyError:
qg = n.zeros(qv.shape, "float")
qg = np.zeros(qv.shape, qv.dtype)
else:
qg = graupvars["QGRAUP"]
# If qsnow is all 0, set sn0 to 1
sn0 = 0
if (n.any(qs != 0)):
sn0 = 1
full_t = t + Constants.T_BASE
full_p = p + pb
tk = _tk(full_p, full_t)
ivarint = 0
if do_varint:
ivarint = 1
iliqskin = 0
if do_liqskin:
iliqskin = 1
# If qsnow is not all 0, set sn0 to 1
sn0 = 1 if qs.any() else 0
ivarint = 1 if do_varint else 0
iliqskin = 1 if do_liqskin else 0
return computedbz(full_p,tk,qv,qr,qs,qg,sn0,ivarint,iliqskin)
return _dbz(full_p, tk, qv, qr, qs, qg, sn0, ivarint, iliqskin)
@copy_and_set_metadata(copy_varname="T", name="max_dbz",
@ -79,8 +71,7 @@ def get_dbz(wrfnc, timeidx=0, method="cat", @@ -79,8 +71,7 @@ def get_dbz(wrfnc, timeidx=0, method="cat",
def get_max_dbz(wrfnc, timeidx=0, method="cat",
squeeze=True, cache=None, meta=True,
do_varint=False, do_liqskin=False):
return n.amax(get_dbz(wrfnc, timeidx, method,
squeeze, cache, meta,
return np.amax(get_dbz(wrfnc, timeidx, method, squeeze, cache, meta,
do_varint, do_liqskin),
axis=-3)

83
src/wrf/decorators.py

@ -8,8 +8,8 @@ import numpy as np @@ -8,8 +8,8 @@ import numpy as np
import numpy.ma as ma
from .units import do_conversion, check_units
from .util import (iter_left_indexes, viewitems, viewvalues, from_args,
npvalues, py3range, combine_dims, isstr)
from .util import iter_left_indexes, from_args, npvalues, combine_dims
from .py3compat import viewitems, viewvalues, py3range, isstr
from .config import xarray_enabled
from .constants import Constants
@ -351,38 +351,6 @@ def left_iter_nocopy(ref_var_expected_dims, @@ -351,38 +351,6 @@ def left_iter_nocopy(ref_var_expected_dims,
return func_wrapper
# Only flip the input arguments, but flip the result
def flip_vertical(argidxs=None, argkeys=None, flip_result=True):
@wrapt.decorator
def func_wrapper(wrapped, instance, args, kwargs):
_argidxs = argidxs if argidxs is not None else ()
_argkeys = argkeys if argkeys is not None else ()
# Slice the args if applicable
new_args = [np.ascontiguousarray(arg[...,::-1,:,:])
if i in _argidxs else arg
for i,arg in enumerate(args)]
# Slice the kwargs if applicable
new_kargs = {key:np.ascontiguousarray(kwarg[...,::-1,:,:])
if key in _argkeys else kwarg
for key,kwarg in viewitems(kwargs)}
result = wrapped(*args, **kwargs)
if flip_result:
if isinstance(result, np.ndarray):
return np.ascontiguousarray(result[...,::-1,:,:])
else:
# Sequence
return [np.ascontiguousarray(arr[...,::-1,:,:])
for arr in result]
return result
return func_wrapper
def handle_casting(ref_idx=0, arg_idxs=None, karg_names=None,
alg_dtype=np.float64,
@ -397,7 +365,7 @@ def handle_casting(ref_idx=0, arg_idxs=None, karg_names=None, @@ -397,7 +365,7 @@ def handle_casting(ref_idx=0, arg_idxs=None, karg_names=None,
_karg_names = karg_names if karg_names is not None else ()
# Handle output views if applicable
_outkeys = [outviews] if isstr(outviews) else _outviews
_outkeys = [outviews] if isstr(outviews) else outviews
_outviews = from_args(wrapped, _outkeys, *args, **kwargs)
has_outview = False
@ -425,7 +393,7 @@ def handle_casting(ref_idx=0, arg_idxs=None, karg_names=None, @@ -425,7 +393,7 @@ def handle_casting(ref_idx=0, arg_idxs=None, karg_names=None,
if result.dtype == orig_type:
return result
return result.astype(orig_type)
else: # got back a sequence of arrays
elif isinstance(result, Iterable): # got back a sequence of arrays
return tuple(arr.astype(orig_type)
if arr.dtype != orig_type else arr
for arr in result)
@ -458,7 +426,7 @@ def handle_extract_transpose(do_transpose=True, outviews="outview"): @@ -458,7 +426,7 @@ def handle_extract_transpose(do_transpose=True, outviews="outview"):
def func_wrapper(wrapped, instance, args, kwargs):
# Handle output views if applicable
_outkeys = [outviews] if isstr(outviews) else _outviews
_outkeys = [outviews] if isstr(outviews) else outviews
_outviews = from_args(wrapped, _outkeys, *args, **kwargs)
has_outview = False
@ -490,13 +458,37 @@ def handle_extract_transpose(do_transpose=True, outviews="outview"): @@ -490,13 +458,37 @@ def handle_extract_transpose(do_transpose=True, outviews="outview"):
return func_wrapper
def check_args(refvaridx, refvarndim, rightdims):
def check_args(refvaridx, refvarndim, rightdims, stagger=None,
refstagdim=None):
"""
refvaridx - reference variable to check for presence of left dimensions
refvarndim - the number of dimensions for the references variable
expected by the fortran routine
rightdims - the expected number of right dimensions for each argument
stagger - the dimension which is staggered for each argument. Use
None to indicate no staggering.
refstagdim - If the reference variable is staggered, indicate the dim that
is staggered
"""
@wrapt.decorator
def func_wrapper(wrapped, instance, args, kwargs):
refvar = args[refvaridx]
extra_dims = refvar.ndim - refvarndim
ref_right_sizes = refvar.shape[extra_dims:]
# Always use unstaggered as the basis of comparison
if refstagdim is not None:
_refshape = list(refvar.shape)
_refshape[refstagdim] -= 1
_refshape = tuple(_refshape)
else:
_refshape = refvar.shape
if stagger is None:
_stagger = [None]*len(rightdims)
else:
_stagger = stagger
for i,ndim in enumerate(rightdims):
if ndim is None:
@ -513,9 +505,20 @@ def check_args(refvaridx, refvarndim, rightdims): @@ -513,9 +505,20 @@ def check_args(refvaridx, refvarndim, rightdims):
var.ndim,
right_var_ndims + extra_dims))
# Add 1 to the reference staggered dim index before doing the check
if _stagger[i] is not None:
ref_shape = list(_refshape)
ref_shape[_stagger[i]] += 1
ref_shape = tuple(ref_shape)
else:
ref_shape = _refshape
ref_right_sizes = ref_shape[extra_dims:]
# Check that right dimensions are lined up
if (var.shape[-right_var_ndims:] !=
ref_right_sizes[-right_var_ndims:]):
raise ValueError("invalid shape for argument "
"{} (got {}, expected {})".format(i,
var.shape[-right_var_ndims:],
@ -531,3 +534,5 @@ def check_args(refvaridx, refvarndim, rightdims): @@ -531,3 +534,5 @@ def check_args(refvaridx, refvarndim, rightdims):

699
src/wrf/extension.py

@ -4,30 +4,36 @@ from __future__ import (absolute_import, division, print_function, @@ -4,30 +4,36 @@ from __future__ import (absolute_import, division, print_function,
import numpy as np
from .constants import Constants
from .psadlookup import get_lookup_tables
#from .psadlookup import get_lookup_tables
# Old way
from ._wrfext import (f_interpz3d, f_interp2dxy,f_interp1d,
f_computeslp, f_computetk, f_computetd, f_computerh,
f_computeabsvort,f_computepvo, f_computeeth,
f_computeuvmet,
f_computeomega, f_computetv, f_computewetbulb,
f_computesrh, f_computeuh, f_computepw, f_computedbz,
f_lltoij, f_ijtoll, f_converteta, f_computectt,
f_monotonic, f_filter2d, f_vintrp)
from ._wrfcape import f_computecape
#from ._wrfext import (f_interpz3d, f_interp2dxy,f_interp1d,
# f_computeslp, f_computetk, f_computetd, f_computerh,
# f_computeabsvort,f_computepvo, f_computeeth,
# f_computeuvmet,
# f_computeomega, f_computetv, f_computewetbulb,
# f_computesrh, f_computeuh, f_computepw, f_computedbz,
# f_lltoij, f_ijtoll, f_converteta, f_computectt,
# f_monotonic, f_filter2d, f_vintrp)
#from ._wrfcape import f_computecape
# New way
from ._wrffortran import (dcomputetk, dinterp3dz, dinterp2dxy, dinterp1d,
dcomputeseaprs, dfilter2d, dcomputerh, dcomputeuvmet,
dcomputetd)
dcomputetd, dcapecalc3d, dcloudfrac, wrfcttcalc,
calcdbz, dcalrelhl, dcalcuh, dcomputepv,
dcomputeabsvort, dlltoij, dijtoll, deqthecalc,
omgcalc, virtual_temp, wetbulbcalc, dcomputepw,
wrf_monotonic, wrf_vintrp)
from .decorators import (handle_left_iter, handle_casting,
handle_extract_transpose)
from .decorators import (left_iter_nocopy, check_args)
from .util import py3range, combine_dims, _npbytes_to_str
from .uvdecorator import uvmet_left_iter_nocopy
from .util import combine_dims, npbytes_to_str, psafilepath
from .py3compat import py3range
from .specialdec import (uvmet_left_iter_nocopy, cape_left_iter,
cloudfrac_left_iter)
__all__ = []
#__all__ = []
# __all__ += ["FortranException", "computeslp", "computetk", "computetd",
# "computerh", "computeavo", "computepvo", "computeeth",
# "computeuvmet","computeomega", "computetv", "computesrh",
@ -37,7 +43,13 @@ __all__ = [] @@ -37,7 +43,13 @@ __all__ = []
# "computevertcross"]
# __all__ += ["", ""]
class FortranException(Exception):
class FortranError(Exception):
def __init__(self, message=None):
self._msg = message
def __str__(self):
return self._msg
def __call__(self, message):
raise self.__class__(message)
@ -233,7 +245,7 @@ def _slp(z, t, p, q, outview=None): @@ -233,7 +245,7 @@ def _slp(z, t, p, q, outview=None):
errmsg=errmsg)
if int(errstat) != 0:
raise RuntimeError("".join(_npbytes_to_str(errmsg)).strip())
raise FortranError("".join(npbytes_to_str(errmsg)).strip())
return result
@ -321,11 +333,37 @@ def _rh(qv, q, t, outview=None): @@ -321,11 +333,37 @@ def _rh(qv, q, t, outview=None):
return result
@handle_left_iter(3,0, ignore_args=(6,7))
#@handle_left_iter(3,0, ignore_args=(6,7))
#@handle_casting(arg_idxs=(0,1,2,3,4,5))
#@handle_extract_transpose()
#def computeavo(u, v, msfu, msfv, msfm, cor, dx, dy):
# result = f_computeabsvort(u,
# v,
# msfu,
# msfv,
# msfm,
# cor,
# dx,
# dy)
#
# return result
# Note: combining the -3 and -2 dimensions from u, then the -1 dimension
# from v
@check_args(0, 3, (3,3,2,2,2,2), stagger=(-1,-2,-1,-2,None,None),
refstagdim=-1)
@left_iter_nocopy(3, combine_dims([(0, (-3,-2)),
(1, (-1,))]),
ref_var_idx=0, ignore_args=(6,7))
@handle_casting(arg_idxs=(0,1,2,3,4,5))
@handle_extract_transpose()
def computeavo(u, v, msfu, msfv, msfm, cor, dx, dy):
result = f_computeabsvort(u,
def _avo(u, v, msfu, msfv, msfm, cor, dx, dy, outview=None):
if outview is None:
outshape = (v.shape[0],) + u.shape[1:]
outview = np.empty(outshape, np.float64, order="F")
result = dcomputeabsvort(outview,
u,
v,
msfu,
msfv,
@ -336,12 +374,36 @@ def computeavo(u, v, msfu, msfv, msfm, cor, dx, dy): @@ -336,12 +374,36 @@ def computeavo(u, v, msfu, msfv, msfm, cor, dx, dy):
return result
@handle_left_iter(3,2, ignore_args=(8,9))
#@handle_left_iter(3,2, ignore_args=(8,9))
#@handle_casting(arg_idxs=(0,1,2,3,4,5,6,7))
#@handle_extract_transpose()
#def computepvo(u, v, theta, prs, msfu, msfv, msfm, cor, dx, dy):
#
# result = f_computepvo(u,
# v,
# theta,
# prs,
# msfu,
# msfv,
# msfm,
# cor,
# dx,
# dy)
#
# return result
@check_args(0, 3, (3,3,3,3,2,2,2,2), stagger=(-1,-2,None,None,-1,-2,None,
None),
refstagdim=-1)
@left_iter_nocopy(3, 3, ref_var_idx=2, ignore_args=(8,9))
@handle_casting(arg_idxs=(0,1,2,3,4,5,6,7))
@handle_extract_transpose()
def computepvo(u, v, theta, prs, msfu, msfv, msfm, cor, dx, dy):
def _pvo(u, v, theta, prs, msfu, msfv, msfm, cor, dx, dy, outview=None):
if outview is None:
outview = np.empty_like(prs)
result = f_computepvo(u,
result = dcomputepv(outview,
u,
v,
theta,
prs,
@ -354,14 +416,30 @@ def computepvo(u, v, theta, prs, msfu, msfv, msfm, cor, dx, dy): @@ -354,14 +416,30 @@ def computepvo(u, v, theta, prs, msfu, msfv, msfm, cor, dx, dy):
return result
@handle_left_iter(3,0)
#@handle_left_iter(3,0)
#@handle_casting(arg_idxs=(0,1,2))
#@handle_extract_transpose()
#def computeeth(qv, tk, p):
#
# result = f_computeeth(qv,
# tk,
# p)
#
# return result
@check_args(0, 3, (3,3,3))
@left_iter_nocopy(3, 3, ref_var_idx=0)
@handle_casting(arg_idxs=(0,1,2))
@handle_extract_transpose()
def computeeth(qv, tk, p):
def _eth(qv, tk, p, outview=None):
if outview is None:
outview = np.empty_like(qv)
result = f_computeeth(qv,
result = deqthecalc(qv,
tk,
p)
p,
outview)
return result
@ -399,7 +477,6 @@ def computeeth(qv, tk, p): @@ -399,7 +477,6 @@ def computeeth(qv, tk, p):
#
# return np.squeeze(result)
# uvmet_left_iter needs to determine if the variable has missing values
@uvmet_left_iter_nocopy()
@handle_casting(arg_idxs=(0,1,2,3))
@handle_extract_transpose()
@ -432,68 +509,168 @@ def _uvmet(u, v, lat, lon, cen_long, cone, isstag=0, has_missing=False, @@ -432,68 +509,168 @@ def _uvmet(u, v, lat, lon, cen_long, cone, isstag=0, has_missing=False,
return result
@handle_left_iter(3,0)
#@handle_left_iter(3,0)
#@handle_casting(arg_idxs=(0,1,2,3))
#@handle_extract_transpose()
#def computeomega(qv, tk, w, p):
#
# result = f_computeomega(qv,
# tk,
# w,
# p)
#
# return result
@check_args(0, 3, (3,3,3,3))
@left_iter_nocopy(3, 3, ref_var_idx=0)
@handle_casting(arg_idxs=(0,1,2,3))
@handle_extract_transpose()
def computeomega(qv, tk, w, p):
def _omega(qv, tk, w, p, outview=None):
if outview is None:
outview = np.empty_like(qv)
result = f_computeomega(qv,
result = omgcalc(qv,
tk,
w,
p)
p,
outview)
return result
@handle_left_iter(3,0)
#@handle_left_iter(3,0)
#@handle_casting(arg_idxs=(0,1))
#@handle_extract_transpose()
#def computetv(tk, qv):
# result = f_computetv(tk,
# qv)
#
# return result
@check_args(0, 3, (3,3))
@left_iter_nocopy(3, 3, ref_var_idx=0)
@handle_casting(arg_idxs=(0,1))
@handle_extract_transpose()
def computetv(tk, qv):
result = f_computetv(tk,
qv)
def _tv(tk, qv, outview=None):
if outview is None:
outview = np.empty_like(tk)
result = virtual_temp(tk,
qv,
outview)
return result
@handle_left_iter(3,0)
#@handle_left_iter(3,0)
#@handle_casting(arg_idxs=(0,1,2))
#@handle_extract_transpose()
#def computewetbulb(p, tk, qv):
# PSADITHTE, PSADIPRS, PSADITMK = get_lookup_tables()
# PSADITMK = PSADITMK.T
#
# result = f_computewetbulb(p,
# tk,
# qv,
# PSADITHTE,
# PSADIPRS,
# PSADITMK,
# FortranError())
#
# return result
@check_args(0, 3, (3,3,3))
@left_iter_nocopy(3, 3, ref_var_idx=0, ignore_args=(3,))
@handle_casting(arg_idxs=(0,1,2))
@handle_extract_transpose()
def computewetbulb(p, tk, qv):
PSADITHTE, PSADIPRS, PSADITMK = get_lookup_tables()
PSADITMK = PSADITMK.T
def _wetbulb(p, tk, qv, psafile=psafilepath(), outview=None):
if outview is None:
outview = np.empty_like(p)
result = f_computewetbulb(p,
errstat = np.array(0)
errmsg = np.zeros(Constants.ERRLEN, "c")
result = wetbulbcalc(p,
tk,
qv,
PSADITHTE,
PSADIPRS,
PSADITMK,
FortranException())
outview,
psafile,
errstat,
errmsg)
if int(errstat) != 0:
raise FortranError("".join(npbytes_to_str(errmsg)).strip())
return result
@handle_left_iter(3,0, ignore_args=(4,))
#@handle_left_iter(3,0, ignore_args=(4,))
#@handle_casting(arg_idxs=(0,1,2,3))
#@handle_extract_transpose()
#def computesrh(u, v, z, ter, top):
#
# result = f_computesrh(u,
# v,
# z,
# ter,
# top)
#
# return result
@check_args(0, 3, (3,3,3,2))
@left_iter_nocopy(3, 2, ref_var_idx=0, ignore_args=(4,))
@handle_casting(arg_idxs=(0,1,2,3))
@handle_extract_transpose()
def computesrh(u, v, z, ter, top):
def _srhel(u, v, z, ter, top, outview=None):
if outview is None:
outview = np.empty_like(ter)
result = f_computesrh(u,
result = dcalrelhl(u,
v,
z,
ter,
top)
top,
outview)
return result
@handle_left_iter(3,2, ignore_args=(5,6,7,8))
#@handle_left_iter(3,2, ignore_args=(5,6,7,8))
#@handle_casting(arg_idxs=(0,1,2,3,4))
#@handle_extract_transpose()
#def computeuh(zp, mapfct, u, v, wstag, dx, dy, bottom, top):
#
# tem1 = np.zeros((u.shape[0], u.shape[1], u.shape[2]), np.float64,
# order="F")
# tem2 = np.zeros((u.shape[0], u.shape[1], u.shape[2]), np.float64,
# order="F")
#
# result = f_computeuh(zp,
# mapfct,
# dx,
# dy,
# bottom,
# top,
# u,
# v,
# wstag,
# tem1,
# tem2)
#
# return result
@check_args(2, 3, (3,2,3,3,3), stagger=(-3,None,None,None,-3))
@left_iter_nocopy(3, 2, ref_var_idx=2, ignore_args=(5,6,7,8))
@handle_casting(arg_idxs=(0,1,2,3,4))
@handle_extract_transpose()
def computeuh(zp, mapfct, u, v, wstag, dx, dy, bottom, top):
def _udhel(zstag, mapfct, u, v, wstag, dx, dy, bottom, top, outview=None):
if outview is None:
outview = np.empty_like(mapfct)
tem1 = np.zeros((u.shape[0], u.shape[1], u.shape[2]), np.float64,
order="F")
tem2 = np.zeros((u.shape[0], u.shape[1], u.shape[2]), np.float64,
order="F")
result = f_computeuh(zp,
result = dcalcuh(zstag,
mapfct,
dx,
dy,
@ -502,31 +679,70 @@ def computeuh(zp, mapfct, u, v, wstag, dx, dy, bottom, top): @@ -502,31 +679,70 @@ def computeuh(zp, mapfct, u, v, wstag, dx, dy, bottom, top):
u,
v,
wstag,
outview,
tem1,
tem2)
return result
@handle_left_iter(3,0)
#@handle_left_iter(3,0)
#@handle_casting(arg_idxs=(0,1,2,3))
#@handle_extract_transpose()
#def computepw(p, tv, qv, ht):
#
# zdiff = np.zeros((p.shape[0], p.shape[1]), np.float64, order="F")
# result = f_computepw(p,
# tv,
# qv,
# ht,
# zdiff)
#
# return result
@check_args(0, 3, (3,3,3,3), stagger=(None, None, None, -3))
@left_iter_nocopy(3, 2, ref_var_idx=0)
@handle_casting(arg_idxs=(0,1,2,3))
@handle_extract_transpose()
def computepw(p, tv, qv, ht):
def _pw(p, tv, qv, ht, outview=None):
zdiff = np.zeros((p.shape[0], p.shape[1]), np.float64, order="F")
result = f_computepw(p,
if outview is None:
outview = np.empty(p.shape[0:2], p.dtype, order="F")
result = dcomputepw(p,
tv,
qv,
ht,
zdiff)
outview)
return result
@handle_left_iter(3,0, ignore_args=(6,7,8))
#@handle_left_iter(3,0, ignore_args=(6,7,8))
#@handle_casting(arg_idxs=(0,1,2,3,4,5))
#@handle_extract_transpose()
#def computedbz(p, tk, qv, qr, qs, qg, sn0, ivarint, iliqskin):
#
# result = f_computedbz(p,
# tk,
# qv,
# qr,
# qs,
# qg,
# sn0,
# ivarint,
# iliqskin)
#
# return result
@check_args(0, 3, (3,3,3,3,3,3))
@left_iter_nocopy(3, 3, ref_var_idx=0, ignore_args=(6,7,8))
@handle_casting(arg_idxs=(0,1,2,3,4,5))
@handle_extract_transpose()
def computedbz(p, tk, qv, qr, qs, qg, sn0, ivarint, iliqskin):
def _dbz(p, tk, qv, qr, qs, qg, sn0, ivarint, iliqskin, outview=None):
if outview is None:
outview = np.empty_like(p)
result = f_computedbz(p,
result = calcdbz(p,
tk,
qv,
qr,
@ -534,7 +750,8 @@ def computedbz(p, tk, qv, qr, qs, qg, sn0, ivarint, iliqskin): @@ -534,7 +750,8 @@ def computedbz(p, tk, qv, qr, qs, qg, sn0, ivarint, iliqskin):
qg,
sn0,
ivarint,
iliqskin)
iliqskin,
outview)
return result
@ -544,52 +761,162 @@ def computedbz(p, tk, qv, qr, qs, qg, sn0, ivarint, iliqskin): @@ -544,52 +761,162 @@ def computedbz(p, tk, qv, qr, qs, qg, sn0, ivarint, iliqskin):
# Then flip the final result. The copy is unavoidable, but at least it is
# only happening once, not every time.
@handle_left_iter(3,0,ignore_args=(6,7,8))
@handle_casting(arg_idxs=(0,1,2,3,4,5))
@handle_extract_transpose()
def computecape(p_hpa, tk, qv, ht, ter, sfp, missing, i3dflag, ter_follow):
flip_cape = np.zeros(p_hpa.shape[0:3], np.float64, order="F")
flip_cin = np.zeros(p_hpa.shape[0:3], np.float64, order="F")
PSADITHTE, PSADIPRS, PSADITMK = get_lookup_tables()
PSADITMK = PSADITMK.T
# The fortran routine needs pressure to be ascending in z-direction,
# along with tk,qv,and ht.
# The extra mumbo-jumbo is so that the view created by numpy is fortran
# contiguous. 'ascontiguousarray' only works in C ordering, hence the
# extra transposes. Note, this is probably making a copy
flip_p = np.ascontiguousarray(p_hpa[:,:,::-1].T).T
flip_tk = np.ascontiguousarray(tk[:,:,::-1].T).T
flip_qv = np.ascontiguousarray(qv[:,:,::-1].T).T
flip_ht = np.ascontiguousarray(ht[:,:,::-1].T).T
f_computecape(flip_p,
flip_tk,
flip_qv,
flip_ht,
# @handle_left_iter(3,0,ignore_args=(6,7,8))
# @handle_casting(arg_idxs=(0,1,2,3,4,5))
# @handle_extract_transpose()
# def computecape(p_hpa, tk, qv, ht, ter, sfp, missing, i3dflag, ter_follow):
# flip_cape = np.zeros(p_hpa.shape[0:3], np.float64, order="F")
# flip_cin = np.zeros(p_hpa.shape[0:3], np.float64, order="F")
# PSADITHTE, PSADIPRS, PSADITMK = get_lookup_tables()
# PSADITMK = PSADITMK.T
#
# # The fortran routine needs pressure to be ascending in z-direction,
# # along with tk,qv,and ht.
# # The extra mumbo-jumbo is so that the view created by numpy is fortran
# # contiguous. 'ascontiguousarray' only works in C ordering, hence the
# # extra transposes. Note, this is probably making a copy
# flip_p = np.ascontiguousarray(p_hpa[:,:,::-1].T).T
# flip_tk = np.ascontiguousarray(tk[:,:,::-1].T).T
# flip_qv = np.ascontiguousarray(qv[:,:,::-1].T).T
# flip_ht = np.ascontiguousarray(ht[:,:,::-1].T).T
#
# f_computecape(flip_p,
# flip_tk,
# flip_qv,
# flip_ht,
# ter,
# sfp,
# flip_cape,
# flip_cin,
# PSADITHTE,
# PSADIPRS,
# PSADITMK,
# missing,
# i3dflag,
# ter_follow,
# FortranException())
#
# # Need to flip the vertical back to decending pressure with height.
# cape = np.ascontiguousarray(flip_cape[:,:,::-1].T).T
# cin = np.ascontiguousarray(flip_cin[:,:,::-1].T).T
#
# return (cape, cin)
@check_args(0, 3, (3,3,3,3,2,2))
@cape_left_iter()
@handle_casting(arg_idxs=(0,1,2,3,4,5), outviews=("capeview", "cinview"))
@handle_extract_transpose(outviews=("capeview", "cinview"))
def _cape(p_hpa, tk, qv, ht, ter, sfp, missing, i3dflag, ter_follow,
psafile=psafilepath(), capeview=None, cinview=None):
if capeview is None:
capeview = np.zeros(p_hpa.shape[0:3], p_hpa.dtype, order="F")
if cinview is None:
cinview = np.zeros(p_hpa.shape[0:3], p_hpa.dtype, order="F")
errstat = np.array(0)
errmsg = np.zeros(Constants.ERRLEN, "c")
# note that p_hpa, tk, qv, and ht have the vertical flipped
result = dcapecalc3d(p_hpa,
tk,
qv,
ht,
ter,
sfp,
flip_cape,
flip_cin,
PSADITHTE,
PSADIPRS,
PSADITMK,
capeview,
cinview,
missing,
i3dflag,
ter_follow,
FortranException())
psafile,
errstat,
errmsg)
if int(errstat) != 0:
raise FortranError("".join(npbytes_to_str(errmsg)).strip())
return result
@check_args(0, 3, (3,3))
@cloudfrac_left_iter()
@handle_casting(arg_idxs=(0, 1), outviews=("lowview", "medview", "highview"))
@handle_extract_transpose(outviews=("lowview", "medview", "hightview"))
def _cloudfrac(p, rh, lowview=None, medview=None, highview=None):
if lowview is None:
lowview = np.zeros(p.shape[0:2], p.dtype, order="F")
if medview is None:
medview = np.zeros(p.shape[0:2], p.dtype, order="F")
# Need to flip the vertical back to decending pressure with height.
cape = np.ascontiguousarray(flip_cape[:,:,::-1].T).T
cin = np.ascontiguousarray(flip_cin[:,:,::-1].T).T
if highview is None:
highview = np.zeros(p.shape[0:2], p.dtype, order="F")
return (cape, cin)
result = dcloudfrac(p,
rh,
lowview,
medview,
highview)
def computeij(map_proj, truelat1, truelat2, stdlon,
return result
#def computeij(map_proj, truelat1, truelat2, stdlon,
# lat1, lon1, pole_lat, pole_lon,
# knowni, knownj, dx, latinc, loninc, lat, lon):
#
# result = f_lltoij(map_proj,
# truelat1,
# truelat2,
# stdlon,
# lat1,
# lon1,
# pole_lat,
# pole_lon,
# knowni,
# knownj,
# dx,
# latinc,
# loninc,
# lat,
# lon,
# FortranError())
#
# return result
#def computell(map_proj, truelat1, truelat2, stdlon, lat1, lon1,
# pole_lat, pole_lon, knowni, knownj, dx, latinc,
# loninc, i, j):
#
# result = f_ijtoll(map_proj,
# truelat1,
# truelat2,
# stdlon,
# lat1,
# lon1,
# pole_lat,
# pole_lon,
# knowni,
# knownj,
# dx,
# latinc,
# loninc,
# i,
# j,
# FortranError())
#
# return result
def _lltoxy(map_proj, truelat1, truelat2, stdlon,
lat1, lon1, pole_lat, pole_lon,
knowni, knownj, dx, latinc, loninc, lat, lon):
known_x, known_y, dx, dy, latinc, loninc, lat, lon):
errstat = np.array(0)
errmsg = np.zeros(Constants.ERRLEN, "c")
result = f_lltoij(map_proj,
result = dlltoij(map_proj,
truelat1,
truelat2,
stdlon,
@ -597,22 +924,31 @@ def computeij(map_proj, truelat1, truelat2, stdlon, @@ -597,22 +924,31 @@ def computeij(map_proj, truelat1, truelat2, stdlon,
lon1,
pole_lat,
pole_lon,
knowni,
knownj,
known_x,
known_y,
dx,
dy,
latinc,
loninc,
lat,
lon,
FortranException())
errstat,
errmsg)
if int(errstat) != 0:
raise FortranError("".join(npbytes_to_str(errmsg)).strip())
return result
def computell(map_proj, truelat1, truelat2, stdlon, lat1, lon1,
pole_lat, pole_lon, knowni, knownj, dx, latinc,
loninc, i, j):
result = f_ijtoll(map_proj,
def _xytoll(map_proj, truelat1, truelat2, stdlon, lat1, lon1,
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc,
loninc, x, y):
errstat = np.array(0)
errmsg = np.zeros(Constants.ERRLEN, "c")
result = dijtoll(map_proj,
truelat1,
truelat2,
stdlon,
@ -620,50 +956,77 @@ def computell(map_proj, truelat1, truelat2, stdlon, lat1, lon1, @@ -620,50 +956,77 @@ def computell(map_proj, truelat1, truelat2, stdlon, lat1, lon1,
lon1,
pole_lat,
pole_lon,
knowni,
knownj,
known_x,
known_y,
dx,
dy,
latinc,
loninc,
i,
j,
FortranException())
x,
y,
errstat,
errmsg)
if int(errstat) != 0:
raise FortranError("".join(npbytes_to_str(errmsg)).strip())
return result
@handle_left_iter(3,0, ignore_args=(3,))
@handle_casting(arg_idxs=(0,1,2))
@handle_extract_transpose()
def computeeta(full_t, znu, psfc, ptop):
pcalc = np.zeros(full_t.shape, np.float64, order="F")
mean_t = np.zeros(full_t.shape, np.float64, order="F")
temp_t = np.zeros(full_t.shape, np.float64, order="F")
result = f_converteta(full_t,
znu,
psfc,
ptop,
pcalc,
mean_t,
temp_t)
return result
#@handle_left_iter(3,0, ignore_args=(3,))
#@handle_casting(arg_idxs=(0,1,2))
#@handle_extract_transpose()
#def computeeta(full_t, znu, psfc, ptop):
# pcalc = np.zeros(full_t.shape, np.float64, order="F")
# mean_t = np.zeros(full_t.shape, np.float64, order="F")
# temp_t = np.zeros(full_t.shape, np.float64, order="F")
#
# result = f_converteta(full_t,
# znu,
# psfc,
# ptop,
# pcalc,
# mean_t,
# temp_t)
#
# return result
#@handle_left_iter(3,0,ignore_args=(7,))
#@handle_casting(arg_idxs=(0,1,2,3,4,5,6))
#@handle_extract_transpose()
#def computectt(p_hpa, tk, qice, qcld, qv, ght, ter, haveqci):
# result = f_computectt(p_hpa,
# tk,
# qice,
# qcld,
# qv,
# ght,
# ter,
# haveqci)
#
# return result
@handle_left_iter(3,0,ignore_args=(7,))
@check_args(0, 3, (3,3,3,3,3,3,2))
@left_iter_nocopy(3, 2, ref_var_idx=0, ignore_args=(7,))
@handle_casting(arg_idxs=(0,1,2,3,4,5,6))
@handle_extract_transpose()
def computectt(p_hpa, tk, qice, qcld, qv, ght, ter, haveqci):
result = f_computectt(p_hpa,
def _ctt(p_hpa, tk, qice, qcld, qv, ght, ter, haveqci, outview=None):
if outview is None:
outview = np.empty_like(ter)
result = wrfcttcalc(p_hpa,
tk,
qice,
qcld,
qv,
ght,
ter,
outview,
haveqci)
return result
# @handle_left_iter(2,0,ignore_args=(1,))
# @handle_casting(arg_idxs=(0,))
# @handle_extract_transpose()
@ -717,11 +1080,34 @@ def _smooth2d(field, passes, outview=None): @@ -717,11 +1080,34 @@ def _smooth2d(field, passes, outview=None):
# array. It's only modifying the existing array.
return outview
@handle_left_iter(3,0,ignore_args=(3,4,5))
#@handle_left_iter(3,0,ignore_args=(3,4,5))
#@handle_casting(arg_idxs=(0,1,2))
#@handle_extract_transpose()
#def monotonic(var, lvprs, coriolis, idir, delta, icorsw):
# result = f_monotonic(var,
# lvprs,
# coriolis,
# idir,
# delta,
# icorsw)
#
# return result
@check_args(0, 3, (3,3,2))
@left_iter_nocopy(3, 3, ref_var_idx=0, ignore_args=(3,4,5))
@handle_casting(arg_idxs=(0,1,2))
@handle_extract_transpose()
def monotonic(var, lvprs, coriolis, idir, delta, icorsw):
result = f_monotonic(var,
def _monotonic(var, lvprs, coriolis, idir, delta, icorsw, outview=None):
# If icorsw is not 0, then the input variable might get modified by the
# fortran routine. We don't want this, so make a copy and pass that on.
var = var.copy(order="A") if icorsw != 0 else var
if outview is None:
outview = np.empty_like(var)
result = wrf_monotonic(outview,
var,
lvprs,
coriolis,
idir,
@ -730,14 +1116,52 @@ def monotonic(var, lvprs, coriolis, idir, delta, icorsw): @@ -730,14 +1116,52 @@ def monotonic(var, lvprs, coriolis, idir, delta, icorsw):
return result
@handle_left_iter(3,0,ignore_args=(9,10,11,12,13,14))
#@handle_left_iter(3,0,ignore_args=(9,10,11,12,13,14))
#@handle_casting(arg_idxs=(0,1,2,3,4,5,6,7,8,9))
#@handle_extract_transpose()
#def vintrp(field, pres, tk, qvp, ght, terrain, sfp, smsfp,
# vcarray, interp_levels, icase, extrap, vcor, logp,
# missing):
#
# result = f_vintrp(field,
# pres,
# tk,
# qvp,
# ght,
# terrain,
# sfp,
# smsfp,
# vcarray,
# interp_levels,
# icase,
# extrap,
# vcor,
# logp,
# missing)
#
# return result
# Output shape is interp_levels.shape + field.shape[-2:]
@check_args(0, 3, (3,3,3,3,3,2,2,2,3))
@left_iter_nocopy(3, combine_dims([(9, (-1,)),
(0, (-2,-1))]),
ref_var_idx=0, ignore_args=(9,10,11,12,13,14))
@handle_casting(arg_idxs=(0,1,2,3,4,5,6,7,8,9))
@handle_extract_transpose()
def vintrp(field, pres, tk, qvp, ght, terrain, sfp, smsfp,
def _vintrp(field, pres, tk, qvp, ght, terrain, sfp, smsfp,
vcarray, interp_levels, icase, extrap, vcor, logp,
missing):
missing, outview=None):
if outview is None:
outdims = field.shape[0:2] + interp_levels.shape
outview = np.empty(outdims, field.dtype, order="F")
errstat = np.array(0)
errmsg = np.zeros(Constants.ERRLEN, "c")
result = f_vintrp(field,
result = wrf_vintrp(field,
outview,
pres,
tk,
qvp,
@ -751,7 +1175,12 @@ def vintrp(field, pres, tk, qvp, ght, terrain, sfp, smsfp, @@ -751,7 +1175,12 @@ def vintrp(field, pres, tk, qvp, ght, terrain, sfp, smsfp,
extrap,
vcor,
logp,
missing)
missing,
errstat,
errmsg)
if int(errstat) != 0:
raise FortranError("".join(npbytes_to_str(errmsg)).strip())
return result

6
src/wrf/helicity.py

@ -3,7 +3,7 @@ from __future__ import (absolute_import, division, print_function, @@ -3,7 +3,7 @@ from __future__ import (absolute_import, division, print_function,
from .constants import Constants
from .extension import computesrh, computeuh
from .extension import _srhel, _udhel
from .destag import destagger
from .util import extract_vars, extract_global_attrs, either
from .metadecorators import copy_and_set_metadata
@ -44,7 +44,7 @@ def get_srh(wrfnc, timeidx=0, method="cat", squeeze=True, @@ -44,7 +44,7 @@ def get_srh(wrfnc, timeidx=0, method="cat", squeeze=True,
v1 = v[...,::-1,:,:]
z1 = z[...,::-1,:,:]
srh = computesrh(u1, v1, z1, ter, top)
srh = _srhel(u1, v1, z1, ter, top)
return srh
@ -80,7 +80,7 @@ def get_uh(wrfnc, timeidx=0, method="cat", squeeze=True, @@ -80,7 +80,7 @@ def get_uh(wrfnc, timeidx=0, method="cat", squeeze=True,
zp = ph + phb
uh = computeuh(zp, mapfct, u, v, wstag, dx, dy, bottom, top)
uh = _udhel(zp, mapfct, u, v, wstag, dx, dy, bottom, top)
return uh

42
src/wrf/interp.py

@ -9,7 +9,7 @@ import numpy.ma as ma @@ -9,7 +9,7 @@ import numpy.ma as ma
# computeinterpline)
from .extension import (_interpz3d, _interp2dxy, _interp1d, _vertcross,
_interpline, _smooth2d, monotonic, vintrp)
_interpline, _smooth2d, _monotonic, _vintrp)
from .metadecorators import set_interp_metadata
from .util import extract_vars, is_staggered
@ -51,7 +51,7 @@ def interplevel(field3d, z, desiredlev, missing=Constants.DEFAULT_FILL, @@ -51,7 +51,7 @@ def interplevel(field3d, z, desiredlev, missing=Constants.DEFAULT_FILL,
Returns
-------
out : 'xarray.DataArray` or `numpy.ndarray`
`xarray.DataArray` or `numpy.ndarray`
Returns the interpolated variable. If xarray is enabled and
the meta parameter is True, then the result will be an
`xarray.DataArray` object. Otherwise, the result will be a
@ -70,7 +70,7 @@ def vertcross(field3d, z, missing=Constants.DEFAULT_FILL, @@ -70,7 +70,7 @@ def vertcross(field3d, z, missing=Constants.DEFAULT_FILL,
include_latlon=False,
cache=None, meta=True):
"""Return the vertical cross section for a 3D field, interpolated
to a verical plane defined by a horizontal line.
to a vertical plane defined by a horizontal line.
The horizontal line is defined by either including the
`pivot_point` and `angle` parameters, or the `start_point` and
@ -123,7 +123,7 @@ def vertcross(field3d, z, missing=Constants.DEFAULT_FILL, @@ -123,7 +123,7 @@ def vertcross(field3d, z, missing=Constants.DEFAULT_FILL,
Returns
-------
out : 'xarray.DataArray` or `numpy.ndarray`
`xarray.DataArray` or `numpy.ndarray`
Returns the interpolated variable. If xarray is enabled and
the meta parameter is True, then the result will be an
`xarray.DataArray` object. Otherwise, the result will be a
@ -195,7 +195,7 @@ def interpline(field2d, pivot_point=None, @@ -195,7 +195,7 @@ def interpline(field2d, pivot_point=None,
Returns
-------
out : 'xarray.DataArray` or `numpy.ndarray`
`xarray.DataArray` or `numpy.ndarray`
Returns the interpolated variable. If xarray is enabled and
the meta parameter is True, then the result will be an
`xarray.DataArray` object. Otherwise, the result will be a
@ -227,16 +227,15 @@ def vinterp(wrfnc, field, vert_coord, interp_levels, extrapolate=False, @@ -227,16 +227,15 @@ def vinterp(wrfnc, field, vert_coord, interp_levels, extrapolate=False,
field2d : `xarray.DataArray` or `numpy.ndarray`
A two-dimensional field.
vert_coord : {"pressure", "pres", "p", "ght_msl",
"ght_agl", "theta", "th", "theta-e",
"thetae", "eth"}
vert_coord : {'pressure', 'pres', 'p', 'ght_msl', 'ght_agl', 'theta', 'th', 'theta-e', 'thetae', 'eth'}
A string indicating the vertical coordinate type to interpolate to.
Valid strings are:
* "pressure", "pres", "p": pressure [hPa]
* "ght_msl": grid point height msl [km]
* "ght_agl": grid point height agl [km]
* "theta", "th": potential temperature [K]
* "theta-e", "thetae", "eth": equivalent potential temperature [K]
* 'pressure', 'pres', 'p': pressure [hPa]
* 'ght_msl': grid point height msl [km]
* 'ght_agl': grid point height agl [km]
* 'theta', 'th': potential temperature [K]
* 'theta-e', 'thetae', 'eth': equivalent potential temperature [K]
interp_levels : sequence
A 1D sequence of vertical levels to interpolate to.
@ -244,8 +243,7 @@ def vinterp(wrfnc, field, vert_coord, interp_levels, extrapolate=False, @@ -244,8 +243,7 @@ def vinterp(wrfnc, field, vert_coord, interp_levels, extrapolate=False,
extrapolate : {True, False}, optional
Set to True to extrapolate values below ground. Default is False.
field_type : {"none", "pressure", "pres", "p", "z", "tc", "tk", "theta",
"th", "theta-e", "thetae", "eth", "ght"}, optional
field_type : {'none', 'pressure', 'pres', 'p', 'z', 'tc', 'tk', 'theta', 'th', 'theta-e', 'thetae', 'eth', 'ght'}, optional
The type of field. Default is None.
log_p : {True, False}
@ -280,7 +278,7 @@ def vinterp(wrfnc, field, vert_coord, interp_levels, extrapolate=False, @@ -280,7 +278,7 @@ def vinterp(wrfnc, field, vert_coord, interp_levels, extrapolate=False,
Returns
-------
out : 'xarray.DataArray` or `numpy.ndarray`
`xarray.DataArray` or `numpy.ndarray`
Returns the interpolated variable. If xarray is enabled and
the meta parameter is True, then the result will be an
`xarray.DataArray` object. Otherwise, the result will be a
@ -314,9 +312,9 @@ def vinterp(wrfnc, field, vert_coord, interp_levels, extrapolate=False, @@ -314,9 +312,9 @@ def vinterp(wrfnc, field, vert_coord, interp_levels, extrapolate=False,
"eth" : 6}
# These constants match what's in the fortran code.
rgas = 287.04 #J/K/kg
ussalr = .0065 # deg C per m, avg lapse rate
sclht = rgas*256./9.81
rgas = Constants.RD#287.04 #J/K/kg
ussalr = Constants.USSALR#.0065 # deg C per m, avg lapse rate
sclht = Constants.SCLHT #rgas*256./9.81
# interp_levels might be a list or tuple, make a numpy array
if not isinstance(interp_levels, np.ndarray):
@ -390,7 +388,7 @@ def vinterp(wrfnc, field, vert_coord, interp_levels, extrapolate=False, @@ -390,7 +388,7 @@ def vinterp(wrfnc, field, vert_coord, interp_levels, extrapolate=False,
p_hpa = p * ConversionFactors.PA_TO_HPA
vcord_array = monotonic(t, p_hpa, coriolis, idir, delta, icorsw)
vcord_array = _monotonic(t, p_hpa, coriolis, idir, delta, icorsw)
# We only extrapolate temperature fields below ground
# if we are interpolating to pressure or height vertical surfaces.
@ -407,7 +405,7 @@ def vinterp(wrfnc, field, vert_coord, interp_levels, extrapolate=False, @@ -407,7 +405,7 @@ def vinterp(wrfnc, field, vert_coord, interp_levels, extrapolate=False,
p_hpa = p * ConversionFactors.PA_TO_HPA
vcord_array = monotonic(eth, p_hpa, coriolis, idir, delta, icorsw)
vcord_array = _monotonic(eth, p_hpa, coriolis, idir, delta, icorsw)
# We only extrapolate temperature fields below ground if we are
# interpolating to pressure or height vertical surfaces
icase = 0
@ -424,7 +422,7 @@ def vinterp(wrfnc, field, vert_coord, interp_levels, extrapolate=False, @@ -424,7 +422,7 @@ def vinterp(wrfnc, field, vert_coord, interp_levels, extrapolate=False,
"same value used when extracting the 'field' "
"variable.")
res = vintrp(field, p, tk, qv, ght, terht, sfp, smsfp,
res = _vintrp(field, p, tk, qv, ght, terht, sfp, smsfp,
vcord_array, interp_levels,
icase, extrap, vcor, log_p_int, missing)

2
src/wrf/interputils.py

@ -6,7 +6,7 @@ from math import floor, ceil @@ -6,7 +6,7 @@ from math import floor, ceil
import numpy as np
from .extension import _interp2dxy
from .util import py3range
from .py3compat import py3range
def to_positive_idxs(shape, coord):

29
src/wrf/latlon.py

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
from .util import (extract_vars)
from .latlonutils import (_lat_varname, _lon_varname, ll_to_ij, ij_to_ll)
from .util import extract_vars
from .latlonutils import (_lat_varname, _lon_varname, _ll_to_xy, _xy_to_ll)
from .metadecorators import set_latlon_metadata
@ -28,19 +28,22 @@ def get_lon(wrfnc, timeidx=0, method="cat", squeeze=True, @@ -28,19 +28,22 @@ def get_lon(wrfnc, timeidx=0, method="cat", squeeze=True,
return lon_var[varname]
# TODO: Rename these!
@set_latlon_metadata(ij=True)
def get_ij(wrfnc, latitude, longitude, timeidx=0,
stagger=None, method="cat", squeeze=True, cache=None, meta=True):
return ll_to_ij(wrfnc, latitude, longitude, timeidx, stagger,
method, squeeze, cache)
# Can either use wrfnc as a single file or sequence, or provide
# projection parameters (which don't allow for moving domains)
@set_latlon_metadata(xy=True)
def ll_to_xy(latitude, longitude, wrfnc=None, timeidx=0,
stagger=None, method="cat", squeeze=True, cache=None, meta=True,
**projparms):
return _ll_to_xy(latitude, longitude, wrfnc, timeidx, stagger,
method, squeeze, cache, **projparams)
@set_latlon_metadata(ij=False)
def get_ll(wrfnc, i, j, timeidx=0,
stagger=None, method="cat", squeeze=True, cache=None, meta=True):
return ij_to_ll(wrfnc, i, j, timeidx, stagger,
method, squeeze, cache)
@set_latlon_metadata(xy=False)
def xy_to_ll(x, y, wrfnc=None, timeidx=0,
stagger=None, method="cat", squeeze=True, cache=None, meta=True,
**projparms):
return _xy_to_ll(x, y, wrfnc, timeidx, stagger,
method, squeeze, cache, **projparams)

197
src/wrf/latlonutils.py

@ -6,11 +6,11 @@ from collections import Iterable @@ -6,11 +6,11 @@ from collections import Iterable
import numpy as np
from .constants import Constants
from .extension import computeij, computell
from .extension import _lltoxy, _xytoll
from .util import (extract_vars, extract_global_attrs,
either, _is_moving_domain, _is_multi_time_req,
iter_left_indexes, _is_mapping, _is_multi_file,
viewkeys)
either, is_moving_domain, is_multi_time_req,
iter_left_indexes, is_mapping, is_multi_file)
from .py3compat import viewkeys, viewitems
def _lat_varname(wrfnc, stagger):
if stagger is None or stagger.lower() == "m":
@ -64,15 +64,15 @@ def _get_proj_params(wrfnc, timeidx, stagger, method, squeeze, cache): @@ -64,15 +64,15 @@ def _get_proj_params(wrfnc, timeidx, stagger, method, squeeze, cache):
lat_timeidx = timeidx
is_moving = _is_moving_domain(wrfnc, latvar=latvar, lonvar=lonvar)
is_moving = is_moving_domain(wrfnc, latvar=latvar, lonvar=lonvar)
# Only need one file and one time if the domain is not moving
if not is_moving:
if _is_multi_time_req(timeidx):
if is_multi_time_req(timeidx):
lat_timeidx = 0
if _is_multi_file(wrfnc):
if not _is_mapping(wrfnc):
if is_multi_file(wrfnc):
if not is_mapping(wrfnc):
wrfnc = next(iter(wrfnc)) # only need one file
else:
wrfnc = wrfnc[next(iter(viewkeys(wrfnc)))]
@ -88,19 +88,91 @@ def _get_proj_params(wrfnc, timeidx, stagger, method, squeeze, cache): @@ -88,19 +88,91 @@ def _get_proj_params(wrfnc, timeidx, stagger, method, squeeze, cache):
ref_lon = np.ravel(xlon[..., 0, 0])
# Note: fortran index
known_i = 1.0
known_j = 1.0
known_x = 1.0
known_y = 1.0
return (map_proj, truelat1, truelat2, stdlon, ref_lat, ref_lon,
pole_lat, pole_lon, known_i, known_j, dx, latinc, loninc)
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc, loninc)
def _dict_keys_to_upper(d):
return {key.upper(): val for key, val in viewitems(d)}
# known_x and known_y are 0-based
def _kwarg_proj_params(projparams):
projparams = _dict_keys_to_upper(projparams)
map_proj = projparams.get("MAP_PROJ"),
truelat1 = projparams.get("TRUELAT1"),
truelat2 = projparams.get("TRUELAT2"),
stdlon = projparams.get("STDLON"),
ref_lat = projparams.get("REF_LAT"),
ref_lon = projparams.get("REF_LON"),
pole_lat = projparams.get("POLE_LAT", 90.0),
pole_lon = projparams.get("POLE_LON", 0.0),
known_x = projparams.get("KNOWN_X"), # Use 0-based
known_y = projparams.get("KNOWN_Y"), # Use 0-based
dx = projparams.get("DX"),
dy = projparams.get("DY"),
latinc = projparams.get("LATINC"),
loninc = projparams.get("LONINC")
# Sanity checks
# Required args for all projections
for name, var in viewitems({"MAP_PROJ" : map_proj,
"STDLON" : stdlon,
"REF_LAT" : ref_lat,
"REF_LON" : ref_lon,
"KNOWN_X" : known_x,
"KNOWN_Y" : known_y,
"DX" : dx}):
if var is None:
raise ValueError("'{}' argument required".format(name))
# Fortran wants 1-based indexing
known_x = known_x + 1
known_y = known_y + 1
if map_proj in (1, 2, 3):
if truelat1 is None:
raise ValueError("'TRUELAT1' argument required")
else:
if truelat1 is None:
truelat1 = 0.0
# Map projection 6 (lat lon) required latinc, loninc, and dy
if map_proj == 6:
if latinc is None:
raise ValueError("'LATINC' argument required")
if loninc is None:
raise ValueError("'LONINC' argument required")
if dy is None:
raise ValueError("'DY' argument required")
else:
latinc = 0.0
loninc = 0.0
dy = 0.0
return (map_proj, truelat1, truelat2, stdlon, ref_lat, ref_lon, pole_lat,
pole_lon, known_x, known_y, dx, dy, latinc, loninc)
def ll_to_ij(wrfnc, latitude, longitude, timeidx=0,
stagger=None, method="cat", squeeze=True, cache=None):
# Will return 0-based indexes
def _ll_to_xy(latitude, longitude, wrfnc=None, timeidx=0,
stagger=None, method="cat", squeeze=True, cache=None,
**projparms):
if wrfnc is not None:
(map_proj, truelat1, truelat2, stdlon, ref_lat, ref_lon,
pole_lat,pole_lon,known_i,known_j,dx,latinc,
loninc) = _get_proj_params(wrfnc, timeidx, stagger, method, squeeze, cache)
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc,
loninc) = _get_proj_params(wrfnc, timeidx, stagger, method, squeeze,
cache)
else:
(map_proj, truelat1, truelat2, stdlon, ref_lat, ref_lon,
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc,
loninc) = _kwarg_proj_params(**projparams)
if isinstance(latitude, Iterable):
lats = np.asarray(latitude)
@ -116,7 +188,6 @@ def ll_to_ij(wrfnc, latitude, longitude, timeidx=0, @@ -116,7 +188,6 @@ def ll_to_ij(wrfnc, latitude, longitude, timeidx=0,
raise ValueError("'latitude' and 'longitude' "
"must be the same length")
if ref_lat.size == 1:
outdim = [lats.size, 2]
extra_dims = [outdim[0]]
@ -125,7 +196,7 @@ def ll_to_ij(wrfnc, latitude, longitude, timeidx=0, @@ -125,7 +196,7 @@ def ll_to_ij(wrfnc, latitude, longitude, timeidx=0,
outdim = [lats.size, ref_lat.size, 2]
extra_dims = outdim[0:2]
res = np.empty(outdim, np.float64)
result = np.empty(outdim, np.float64)
for left_idxs in iter_left_indexes(extra_dims):
left_and_slice_idxs = left_idxs + (slice(None), )
@ -140,55 +211,70 @@ def ll_to_ij(wrfnc, latitude, longitude, timeidx=0, @@ -140,55 +211,70 @@ def ll_to_ij(wrfnc, latitude, longitude, timeidx=0,
lat = lats[left_idxs[0]]
lon = lons[left_idxs[0]]
ij = computeij(map_proj, truelat1, truelat2, stdlon,
xy = _lltoxy(map_proj, truelat1, truelat2, stdlon,
ref_lat_val, ref_lon_val, pole_lat, pole_lon,
known_i, known_j, dx, latinc, loninc,
known_x, known_y, dx, dy, latinc, loninc,
lat, lon)
res[left_and_slice_idxs] = ij[:]
result[left_and_slice_idxs] = xy[:]
else:
res = computeij(map_proj, truelat1, truelat2, stdlon,
result = _lltoxy(map_proj, truelat1, truelat2, stdlon,
ref_lat, ref_lon, pole_lat, pole_lon,
known_i, known_j, dx, latinc, loninc,
known_x, known_y, dx, dy, latinc, loninc,
latitude, longitude)
# Make indexes 0-based
result = result - 1
if squeeze:
res = res.squeeze()
result = result.squeeze()
return res
return result
def ij_to_ll(wrfnc, i, j, timeidx=0,
stagger=None, method="cat", squeeze=True, cache=None):
# X and Y should be 0-based
def _xy_to_ll(x, y, wrfnc=None, timeidx=0, stagger=None,
method="cat", squeeze=True, cache=None, **projparams):
if wrfnc is not None:
(map_proj, truelat1, truelat2, stdlon, ref_lat, ref_lon,
pole_lat,pole_lon,known_i,known_j,dx,latinc,
loninc) = _get_proj_params(wrfnc, timeidx, stagger, method, squeeze, cache)
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc,
loninc) = _get_proj_params(wrfnc, timeidx, stagger, method, squeeze,
cache)
else:
(map_proj, truelat1, truelat2, stdlon, ref_lat, ref_lon,
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc,
loninc) = _kwarg_proj_params(**projparams)
if isinstance(x, Iterable):
x_arr = np.asarray(x)
y_arr = np.asarray(y)
if isinstance(i, Iterable):
i_arr = np.asarray(i)
j_arr = np.asarray(j)
# Convert 0-based x, y to 1-based
x_arr = x_arr + 1
y_arr = y_arr + 1
if i_arr.ndim > 1:
i_arr = i_arr.ravel()
if x_arr.ndim > 1:
x_arr = x_arr.ravel()
if j_arr.ndim > 1:
j_arr = j_arr.ravel()
if y_arr.ndim > 1:
y_arr = y_arr.ravel()
if (i_arr.size != j_arr.size):
raise ValueError("'i' and 'j' "
if (x_arr.size != y_arr.size):
raise ValueError("'x' and 'y' "
"must be the same length")
if ref_lat.size == 1:
outdim = [i_arr.size, 2]
outdim = [x_arr.size, 2]
extra_dims = [outdim[0]]
else:
# Moving domain will have moving ref_lats/ref_lons
outdim = [i_arr.size, ref_lat.size, 2]
outdim = [x_arr.size, ref_lat.size, 2]
extra_dims = outdim[0:2]
res = np.empty(outdim, np.float64)
result = np.empty(outdim, np.float64)
for left_idxs in iter_left_indexes(extra_dims):
left_and_slice_idxs = left_idxs + (slice(None), )
@ -200,28 +286,25 @@ def ij_to_ll(wrfnc, i, j, timeidx=0, @@ -200,28 +286,25 @@ def ij_to_ll(wrfnc, i, j, timeidx=0,
ref_lat_val = ref_lat[left_idxs[-1]]
ref_lon_val = ref_lon[left_idxs[-1]]
i_val = i_arr[left_idxs[0]]
j_val = j_arr[left_idxs[0]]
x_val = x_arr[left_idxs[0]]
y_val = y_arr[left_idxs[0]]
ll = computell(map_proj, truelat1, truelat2,
stdlon, ref_lat_val, ref_lon_val,
pole_lat, pole_lon, known_i, known_j,
dx, latinc, loninc,
i_val, j_val)
ll = _xytoll(map_proj, truelat1, truelat2, stdlon, ref_lat_val,
ref_lon_val, pole_lat, pole_lon, known_x, known_y,
dx, dy, latinc, loninc, x_val, y_val)
res[left_and_slice_idxs] = ll[:]
result[left_and_slice_idxs] = ll[:]
else:
i_val = i
j_val = j
# Convert 0-based to 1-based for Fortran
x_val = x + 1
y_val = y + 1
res = computell(map_proj, truelat1, truelat2,
stdlon, ref_lat, ref_lon,
pole_lat, pole_lon, known_i, known_j,
dx, latinc, loninc,
i_val, j_val)
result = _xytoll(map_proj, truelat1, truelat2, stdlon, ref_lat, ref_lon,
pole_lat, pole_lon, known_x, known_y, dx, dy, latinc,
loninc, x_val, y_val)
if squeeze:
res = res.squeeze()
result = result.squeeze()
return res
return result

369
src/wrf/metadecorators.py

@ -7,12 +7,11 @@ import numpy as np @@ -7,12 +7,11 @@ import numpy as np
import numpy.ma as ma
from .extension import _interpline
from .util import (viewkeys, viewitems, extract_vars,
combine_with, either, from_args, arg_location,
from .util import (extract_vars, combine_with, either, from_args, arg_location,
is_coordvar, latlon_coordvars, CoordPair, npvalues,
py3range, ucode, from_var, iter_left_indexes)
from_var, iter_left_indexes)
from .py3compat import viewkeys, viewitems, py3range, ucode
from .interputils import get_xy_z_params, get_xy
from .latlonutils import ij_to_ll, ll_to_ij
from .config import xarray_enabled
if xarray_enabled():
@ -231,7 +230,172 @@ def set_wind_metadata(copy_varname, name, description, @@ -231,7 +230,172 @@ def set_wind_metadata(copy_varname, name, description,
return func_wrapper
def set_latlon_metadata(ij=False):
def set_cape_metadata(is2d):
@wrapt.decorator
def func_wrapper(wrapped, instance, args, kwargs):
do_meta = from_args(wrapped, ("meta",), *args, **kwargs)["meta"]
if do_meta is None:
do_meta = True
if not xarray_enabled() or not do_meta:
return wrapped(*args, **kwargs)
argvars = from_args(wrapped, ("wrfnc", "timeidx", "method", "squeeze",
"cache", "missing"),
*args, **kwargs)
wrfnc = argvars["wrfnc"]
timeidx = argvars["timeidx"]
method = argvars["method"]
squeeze = argvars["squeeze"]
cache = argvars["cache"]
missing = argvars["missing"]
if cache is None:
cache = {}
_copy_varname = "P"
copy_var = extract_vars(wrfnc, timeidx, _copy_varname, method, squeeze,
cache, meta=True)[_copy_varname]
# Make a copy so we don't modify a user supplied cache
new_cache = dict(cache)
new_cache[_copy_varname] = copy_var
# Don't modify the original args/kargs. The args need to be a list
# so it can be modified.
new_args, cache_argloc = arg_location(wrapped, "cache", args, kwargs)
new_args[cache_argloc] = new_cache
result = wrapped(*new_args)
outcoords = OrderedDict()
outattrs = OrderedDict()
outattrs.update(copy_var.attrs)
outdimnames = [None] * result.ndim
if is2d:
# Right dims
outdimnames[-2:] = copy_var.dims[-2:]
# Left dims
outdimnames[1:-2] = copy_var.dims[0:-3]
outdimnames[0] = "mcape_mcin_lcl_lfc"
outattrs["description"] = "mcape ; mcin ; lcl ; lfc"
outattrs["MemoryOrder"] = "XY"
outattrs["units"] = "J/kg ; J/kg ; m ; m"
outname = "cape_2d"
else:
# Right dims
outdimnames[-3:] = copy_var.dims[-3:]
# Left dims
outdimnames[1:-3] = copy_var.dims[0:-3]
outdimnames[0] = "cape_cin"
outattrs["description"] = "cape; cin"
outattrs["units"] = "J kg-1 ; J kg-1"
outattrs["MemoryOrder"] = "XYZ"
outname = "cape_3d"
outattrs["_FillValue"] = missing
outattrs["missing_value"] = missing
# xarray doesn't line up coordinate dimensions based on
# names, it just remembers the index it originally mapped to.
# So, need to rebuild the XLAT, XLONG, coordinates again since the
# leftmost index changed.
for key,dataarray in viewitems(copy_var.coords):
if is_coordvar(key):
outcoords[key] = dataarray.dims, npvalues(dataarray)
elif key == "XTIME":
outcoords[key] = dataarray.dims, npvalues(dataarray)
elif key == "Time":
outcoords[key] = npvalues(dataarray)
if is2d:
outcoords["mcape_mcin_lcl_lfc"] = ["mcape", "mcin", "lcl", "lfc"]
else:
outcoords["cape_cin"] = ["cape", "cin"]
return DataArray(result, name=outname, coords=outcoords,
dims=outdimnames, attrs=outattrs)
return func_wrapper
def set_cloudfrac_metadata():
@wrapt.decorator
def func_wrapper(wrapped, instance, args, kwargs):
do_meta = from_args(wrapped, ("meta",), *args, **kwargs)["meta"]
if do_meta is None:
do_meta = True
if not xarray_enabled() or not do_meta:
return wrapped(*args, **kwargs)
argvars = from_args(wrapped, ("wrfnc", "timeidx", "method", "squeeze",
"cache"),
*args, **kwargs)
wrfnc = argvars["wrfnc"]
timeidx = argvars["timeidx"]
method = argvars["method"]
squeeze = argvars["squeeze"]
cache = argvars["cache"]
if cache is None:
cache = {}
_copy_varname = "P"
copy_var = extract_vars(wrfnc, timeidx, _copy_varname, method, squeeze,
cache, meta=True)[_copy_varname]
# Make a copy so we don't modify a user supplied cache
new_cache = dict(cache)
new_cache[_copy_varname] = copy_var
# Don't modify the original args/kargs. The args need to be a list
# so it can be modified.
new_args, cache_argloc = arg_location(wrapped, "cache", args, kwargs)
new_args[cache_argloc] = new_cache
result = wrapped(*new_args)
outcoords = OrderedDict()
outattrs = OrderedDict()
outattrs.update(copy_var.attrs)
outdimnames = [None] * result.ndim
# Right dims
outdimnames[-2:] = copy_var.dims[-2:]
# Left dims
outdimnames[1:-2] = copy_var.dims[0:-3]
outdimnames[0] = "low_med_high"
outattrs["description"] = "low, med, high clouds"
outattrs["MemoryOrder"] = "XY"
outattrs["units"] = "%"
outname = "cloudfrac"
# xarray doesn't line up coordinate dimensions based on
# names, it just remembers the index it originally mapped to.
# So, need to rebuild the XLAT, XLONG, coordinates again since the
# leftmost index changed.
for key,dataarray in viewitems(copy_var.coords):
if is_coordvar(key):
outcoords[key] = dataarray.dims, npvalues(dataarray)
elif key == "XTIME":
outcoords[key] = dataarray.dims, npvalues(dataarray)
elif key == "Time":
outcoords[key] = npvalues(dataarray)
outcoords["low_med_high"] = ["low", "med", "high"]
return DataArray(result, name=outname, coords=outcoords,
dims=outdimnames, attrs=outattrs)
return func_wrapper
def set_latlon_metadata(xy=False):
@wrapt.decorator
def func_wrapper(wrapped, instance, args, kwargs):
@ -243,22 +407,27 @@ def set_latlon_metadata(ij=False): @@ -243,22 +407,27 @@ def set_latlon_metadata(ij=False):
if not xarray_enabled() or not do_meta:
return wrapped(*args, **kwargs)
res = wrapped(*args, **kwargs)
# Set squeeze to False. Squeeze will be handled in here
new_args, squeeze_argloc = arg_location(wrapped, "squeeze", args,
kwargs)
new_args[squeeze_argloc] = False
result = wrapped(*new_args)
# Want to preserve the input coordinate pair in metadata
if res.ndim == 1:
res = res[np.newaxis, :]
if result.ndim == 1:
result = result[np.newaxis, :]
argnames = ["i", "j"] if not ij else ["latitude", "longitude"]
argnames = ["x", "y"] if not xy else ["latitude", "longitude"]
argnames.append("squeeze")
outname = "latlon" if not ij else "ij"
outname = "latlon" if not xy else "xy"
if res.ndim == 2:
dimnames = (["ij", "lat_lon"] if not ij
else ["latlon", "i_j"])
if result.ndim == 2:
dimnames = (["xy", "lat_lon"] if not xy
else ["latlon", "x_y"])
else:
dimnames = (["ij", "domain", "lat_lon"] if not ij
else ["latlon", "domain", "i_j"])
dimnames = (["xy", "domain", "lat_lon"] if not xy
else ["latlon", "domain", "x_y"])
argvars = from_args(wrapped, argnames, *args, **kwargs)
@ -271,15 +440,15 @@ def set_latlon_metadata(ij=False): @@ -271,15 +440,15 @@ def set_latlon_metadata(ij=False):
coords = {}
if not ij:
coords["coord_pair"] = (dimnames[0], [CoordPair(i=x[0], j=x[1])
coords["coord_pair"] = (dimnames[0], [CoordPair(x=x[0], y=x[1])
for x in zip(arr1, arr2)])
coords[dimnames[-1]] = ["lat", "lon"]
else:
coords["coord_pair"] = (dimnames[0], [CoordPair(lat=x[0], lon=x[1])
for x in zip(arr1, arr2)])
coords[dimnames[-1]] = ["i", "j"]
coords[dimnames[-1]] = ["x", "y"]
da = DataArray(res, name=outname, dims=dimnames, coords=coords)
da = DataArray(result, name=outname, dims=dimnames, coords=coords)
if squeeze:
da = da.squeeze()
@ -642,12 +811,11 @@ def _set_line_meta(wrapped, instance, args, kwargs): @@ -642,12 +811,11 @@ def _set_line_meta(wrapped, instance, args, kwargs):
lats = _interpline(latcoord, xy)
lons = _interpline(loncoord, xy)
outcoords["xy_loc"] = ("xy",
np.asarray(tuple(
outcoords["xy_loc"] = np.asarray(tuple(
CoordPair(x=xy[i,0], y=xy[i,1],
lat=lats[i], lon=lons[i])
for i in py3range(xy.shape[-2])))
)
else:
extra_dims = latcoord.shape[0:-2]
@ -919,11 +1087,21 @@ def set_interp_metadata(interp_type): @@ -919,11 +1087,21 @@ def set_interp_metadata(interp_type):
return func_wrapper
def set_alg_metadata(alg_ndims, right_dimnames=None,
refvarndims=None,
refvarname=None, missingarg=None,
insert_dimnames=None,
def set_alg_metadata(alg_ndims, refvarname,
refvarndims=None, missingarg=None,
stagdim=None, stagsubvar=None,
units=None, description=None, squeeze=False):
"""
alg_ndims: number of dimensions returned by the algorithm
refvarndims: number of right dimensions for the refernce var, used
when the result has less dimensions than reference
refvarname: argument name for the reference variable
missingarg: argument name for the missing value
stagdim: staggered dimension in reference
stagsubvar: the variable to use to supply the staggered dimension name
"""
@wrapt.decorator
def func_wrapper(wrapped, instance, args, kwargs):
@ -980,15 +1158,20 @@ def set_alg_metadata(alg_ndims, right_dimnames=None, @@ -980,15 +1158,20 @@ def set_alg_metadata(alg_ndims, right_dimnames=None,
else:
refvar = None
if stagsubvar is not None:
stagvar = from_args(wrapped, (stagsubvar,),
*args, **kwargs)[stagsubvar]
else:
stagvar = None
if isinstance(refvar, DataArray):
# If right dims are provided, use them first
if right_dimnames is not None:
outdims[-alg_ndims:] = right_dimnames[-alg_ndims:]
else:
# Copy the right dims
outdims[-alg_ndims:] = refvar.dims[-alg_ndims:]
# Use the stagsubvar if applicable
outdims[stagdim] = stagvar.dims[stagdim]
# Left dims
if refvarndims is None:
# Used when result and reference are aligned on right
@ -1001,7 +1184,8 @@ def set_alg_metadata(alg_ndims, right_dimnames=None, @@ -1001,7 +1184,8 @@ def set_alg_metadata(alg_ndims, right_dimnames=None,
outdims[idx] = refvar.dims[idx]
else:
continue
# When reference and result aren't exactly aligned (slp,uvmet)
# When reference and result aren't exactly aligned (slp)
# (reference is 3D, result is 2D)
else:
ref_extra = refvar.ndim - refvarndims
ref_left_dimnames = refvar.dims[0:ref_extra]
@ -1013,12 +1197,7 @@ def set_alg_metadata(alg_ndims, right_dimnames=None, @@ -1013,12 +1197,7 @@ def set_alg_metadata(alg_ndims, right_dimnames=None,
else:
continute
if insert_dimnames is not None:
for pair in insert_dimnames:
outdims.insert(pair[0], pair[1])
out = DataArray(result, name=outname, dims=outdims,
attrs=outattrs)
out = DataArray(result, name=outname, dims=outdims, attrs=outattrs)
if squeeze:
return out.squeeze()
@ -1065,8 +1244,124 @@ def set_uvmet_alg_metadata(units="mps", description="earth rotated u,v"): @@ -1065,8 +1244,124 @@ def set_uvmet_alg_metadata(units="mps", description="earth rotated u,v"):
# Left-most is always u_v
outdims[0] = "u_v"
outcoords = {}
outcoords["u_v"] = ["u", "v"]
out = DataArray(result, name=outname, dims=outdims, coords=outcoords,
attrs=outattrs)
return out
return func_wrapper
def set_cape_alg_metadata(is2d):
@wrapt.decorator
def func_wrapper(wrapped, instance, args, kwargs):
do_meta = from_args(wrapped, ("meta",), *args, **kwargs)["meta"]
if do_meta is None:
do_meta = True
if not xarray_enabled() or not do_meta:
return wrapped(*args, **kwargs)
result = wrapped(*args, **kwargs)
# Default dimension names
outdims = ["dim_{}".format(i) for i in py3range(result.ndim)]
outattrs = OrderedDict()
if is2d:
outname = "cape_2d"
outattrs["description"] = "mcape ; mcin ; lcl ; lfc"
outattrs["units"] = "J/kg ; J/kg ; m ; m"
outattrs["MemoryOrder"] = "XY"
else:
outname = "cape_3d"
outattrs["description"] = "cape; cin"
outattrs["units"] = "J kg-1 ; J kg-1"
outattrs["MemoryOrder"] = "XYZ"
argvals = from_args(wrapped, ("p_hpa","missing"), *args, **kwargs)
p = argvals["p_hpa"]
missing = argvals["missing"]
if isinstance(p, DataArray):
if is2d:
# Right dims
outdims[-2:] = p.dims[-2:]
# Left dims
outdims[1:-2] = p.dims[0:-3]
else:
# Right dims
outdims[-3:] = p.dims[-3:]
# Left dims
outdims[1:-3] = p.dims[0:-3]
outcoords = {}
# Left-most is always cape_cin or cape_cin_lcl_lfc
if is2d:
outdims[0] = "cape_cin_lcl_lfc"
outcoords["cape_cin_lcl_lfc"] = ["cape", "cin", "lcl", "lfc"]
else:
outdims[0] = "cape_cin"
outcoords["cape_cin"] = ["cape", "cin"]
outattrs["_FillValue"] = missing
outattrs["missing_value"] = missing
out = DataArray(result, name=outname, dims=outdims, coords=outcoords,
attrs=outattrs)
return out
return func_wrapper
def set_cloudfrac_alg_metadata():
@wrapt.decorator
def func_wrapper(wrapped, instance, args, kwargs):
do_meta = from_args(wrapped, ("meta",), *args, **kwargs)["meta"]
if do_meta is None:
do_meta = True
if not xarray_enabled() or not do_meta:
return wrapped(*args, **kwargs)
result = wrapped(*args, **kwargs)
# Default dimension names
outdims = ["dim_{}".format(i) for i in py3range(result.ndim)]
outattrs = OrderedDict()
outname = "cloudfrac"
outattrs["description"] = "low, med, high clouds"
outattrs["units"] = "%"
outattrs["MemoryOrder"] = "XY"
argvals = from_args(wrapped, "p", *args, **kwargs)["p"]
if isinstance(p, DataArray):
# Right dims
outdims[-2:] = p.dims[-2:]
# Left dims
outdims[1:-2] = p.dims[0:-3]
outcoords = {}
# Left-most is always cape_cin or cape_cin_lcl_lfc
outdims[0] = "low_med_high"
outcoords["low_med_high"] = ["low", "med", "high"]
out = DataArray(result, name=outname, dims=outdims,
out = DataArray(result, name=outname, dims=outdims, coords=outcoords,
attrs=outattrs)
return out

4
src/wrf/omega.py

@ -4,7 +4,7 @@ from __future__ import (absolute_import, division, print_function, @@ -4,7 +4,7 @@ from __future__ import (absolute_import, division, print_function,
from .constants import Constants
from .destag import destagger
#from .extension import computeomega,computetk
from .extension import computeomega, _tk
from .extension import _omega, _tk
from .util import extract_vars
from .metadecorators import copy_and_set_metadata
@ -28,7 +28,7 @@ def get_omega(wrfnc, timeidx=0, method="cat", squeeze=True, cache=None, @@ -28,7 +28,7 @@ def get_omega(wrfnc, timeidx=0, method="cat", squeeze=True, cache=None,
full_p = p + pb
tk = _tk(full_p, full_t)
omega = computeomega(qv,tk,wa,full_p)
omega = _omega(qv, tk, wa, full_p)
return omega

6
src/wrf/pw.py

@ -2,7 +2,7 @@ from __future__ import (absolute_import, division, print_function, @@ -2,7 +2,7 @@ from __future__ import (absolute_import, division, print_function,
unicode_literals)
#from .extension import computepw,computetv,computetk
from .extension import computepw,computetv, _tk
from .extension import _pw, _tv, _tk
from .constants import Constants
from .util import extract_vars
from .metadecorators import copy_and_set_metadata
@ -32,9 +32,9 @@ def get_pw(wrfnc, timeidx=0, method="cat", squeeze=True, cache=None, @@ -32,9 +32,9 @@ def get_pw(wrfnc, timeidx=0, method="cat", squeeze=True, cache=None,
full_t = t + Constants.T_BASE
tk = _tk(full_p, full_t)
tv = computetv(tk, qv)
tv = _tv(tk, qv)
return computepw(full_p, tv, qv, ht)
return _pw(full_p, tv, qv, ht)

55
src/wrf/py3compat.py

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
from sys import version_info
# Dictionary python 2-3 compatibility stuff
def viewitems(d):
func = getattr(d, "viewitems", None)
if func is None:
func = d.items
return func()
def viewkeys(d):
func = getattr(d, "viewkeys", None)
if func is None:
func = d.keys
return func()
def viewvalues(d):
func = getattr(d, "viewvalues", None)
if func is None:
func = d.values
return func()
def isstr(s):
try:
return isinstance(s, basestring)
except NameError:
return isinstance(s, str)
# Python 2 rounding behavior
def _round2(x, d=0):
p = 10 ** d
return float(floor((x * p) + copysign(0.5, x)))/p
def py2round(x, d=0):
if version_info >= (3,):
return _round2(x, d)
return round(x, d)
def py3range(*args):
if version_info >= (3,):
return range(*args)
return xrange(*args)
def ucode(*args, **kwargs):
if version_info >= (3, ):
return str(*args, **kwargs)
return unicode(*args, **kwargs)

15
src/wrf/routines.py

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
from .util import _get_iterable, is_standard_wrf_var, extract_vars, viewkeys
from .util import get_iterable, is_standard_wrf_var, extract_vars, viewkeys
from .cape import get_2dcape, get_3dcape
from .ctt import get_ctt
from .dbz import get_dbz, get_max_dbz
@ -22,6 +22,7 @@ from .vorticity import get_avo, get_pvo @@ -22,6 +22,7 @@ from .vorticity import get_avo, get_pvo
from .wind import (get_destag_wspd_wdir, get_destag_wspd_wdir10,
get_u_destag, get_v_destag, get_w_destag)
from .times import get_times
from .cloudfrac import get_cloudfrac
# func is the function to call. kargs are required arguments that should
@ -65,7 +66,8 @@ _FUNC_MAP = {"cape2d" : get_2dcape, @@ -65,7 +66,8 @@ _FUNC_MAP = {"cape2d" : get_2dcape,
"wspd_wdir10" : get_destag_wspd_wdir10,
"wspd_wdir_uvmet" : get_uvmet_wspd_wdir,
"wspd_wdir_uvmet10" : get_uvmet10_wspd_wdir,
"ctt" : get_ctt
"ctt" : get_ctt,
"cloudfrac" : get_cloudfrac
}
_VALID_KARGS = {"cape2d" : ["missing"],
@ -108,6 +110,7 @@ _VALID_KARGS = {"cape2d" : ["missing"], @@ -108,6 +110,7 @@ _VALID_KARGS = {"cape2d" : ["missing"],
"wspd_wdir_uvmet" : ["units"],
"wspd_wdir_uvmet10" : ["units"],
"ctt" : [],
"cloudfrac" : [],
"default" : []
}
@ -171,6 +174,8 @@ def getvar(wrfnc, varname, timeidx=0, @@ -171,6 +174,8 @@ def getvar(wrfnc, varname, timeidx=0,
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+
| ctt | Cloud Top Temperature | C | |
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+
| cloudfrac | Cloud Fraction | % | |
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+
| dbz | Reflectivity | dBz | do_variant: Set to True to enable variant calculation. Default is False. |
| | | | do_liqskin : Set to True to enable liquid skin calculation. Default is False. |
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+
@ -270,15 +275,15 @@ def getvar(wrfnc, varname, timeidx=0, @@ -270,15 +275,15 @@ def getvar(wrfnc, varname, timeidx=0,
Returns
-------
out : 'xarray.DataArray` or `numpy.ndarray`
Returns the specififed diagnostics output. If xarray is enabled and
`xarray.DataArray` or `numpy.ndarray`
Returns the specified diagnostics output. If xarray is enabled and
the meta parameter is True, then the result will be an
`xarray.DataArray` object. Otherwise, the result will be a
`numpy.ndarray` object with no metadata.
"""
wrfnc = _get_iterable(wrfnc)
wrfnc = get_iterable(wrfnc)
if is_standard_wrf_var(wrfnc, varname):
return extract_vars(wrfnc, timeidx, varname,

489
src/wrf/specialdec.py

@ -0,0 +1,489 @@ @@ -0,0 +1,489 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import numpy as np
import wrapt
#from .destag import destagger
from .util import iter_left_indexes, npvalues
from .py3compat import py3range
from .config import xarray_enabled
from .constants import Constants
if xarray_enabled():
from xarray import DataArray
# def uvmet_left_iter():
# """Decorator to handle iterating over leftmost dimensions when using
# multiple files and/or multiple times with the uvmet product.
#
# """
# @wrapt.decorator
# def func_wrapper(wrapped, instance, args, kwargs):
# u = args[0]
# v = args[1]
# lat = args[2]
# lon = args[3]
# cen_long = args[4]
# cone = args[5]
#
# if u.ndim == lat.ndim:
# num_right_dims = 2
# is_3d = False
# else:
# num_right_dims = 3
# is_3d = True
#
# is_stag = False
# if ((u.shape[-1] != lat.shape[-1]) or
# (u.shape[-2] != lat.shape[-2])):
# is_stag = True
#
# if is_3d:
# extra_dim_num = u.ndim - 3
# else:
# extra_dim_num = u.ndim - 2
#
# if is_stag:
# u = destagger(u,-1)
# v = destagger(v,-2)
#
# # No special left side iteration, return the function result
# if (extra_dim_num == 0):
# return wrapped(u, v, lat, lon, cen_long, cone)
#
# # Start by getting the left-most 'extra' dims
# outdims = u.shape[0:extra_dim_num]
# extra_dims = list(outdims) # Copy the left-most dims for iteration
#
# # Append the right-most dimensions
# outdims += [2] # For u/v components
#
# #outdims += [u.shape[x] for x in py3range(-num_right_dims,0,1)]
# outdims += list(u.shape[-num_right_dims:])
#
# output = np.empty(outdims, u.dtype)
#
# for left_idxs in iter_left_indexes(extra_dims):
# # Make the left indexes plus a single slice object
# # The single slice will handle all the dimensions to
# # the right (e.g. [1,1,:])
# left_and_slice_idxs = tuple([x for x in left_idxs] + [slice(None)])
#
# new_u = u[left_and_slice_idxs]
# new_v = v[left_and_slice_idxs]
# new_lat = lat[left_and_slice_idxs]
# new_lon = lon[left_and_slice_idxs]
#
# # Call the numerical routine
# result = wrapped(new_u, new_v, new_lat, new_lon, cen_long, cone)
#
# # Note: The 2D version will return a 3D array with a 1 length
# # dimension. Numpy is unable to broadcast this without
# # sqeezing first.
# result = np.squeeze(result)
#
# output[left_and_slice_idxs] = result[:]
#
# return output
#
# return func_wrapper
def _move_dim_to_left(arr, dimidx):
if isinstance(arr, np.ma.MaskedArray):
has_missing = True
missing = result.fill_value
shape = list(arr.shape)
move_dim_size = shape.pop(dimidx)
output_dims = [move_dim_size] + shape
output = np.empty(output_dims, arr.dtype)
if dimidx < 0:
right_ndim = -dimidx
else:
right_ndim = arr.ndim - dimidx
rightdims = [slice(None)] * right_ndim
for i in py3range(move_dim_size):
rightdims[0] = i
outidxs = (Ellipsis,) + tuple(rightdims)
output[i,:] = outview_array[outidxs]
if has_missing:
output = np.ma.masked_values(output, missing)
return output
def uvmet_left_iter_nocopy(alg_dtype=np.float64):
"""Decorator to handle iterating over leftmost dimensions when using
multiple files and/or multiple times with the uvmet product.
"""
@wrapt.decorator
def func_wrapper(wrapped, instance, args, kwargs):
u = args[0]
v = args[1]
lat = args[2]
lon = args[3]
cen_long = args[4]
cone = args[5]
orig_dtype = u.dtype
lat_lon_fixed = False
if lat.ndim == 2:
lat_lon_fixed = True
if lon.ndim == 2 and not lat_lon_fixed:
raise ValueError("'lat' and 'lon' shape mismatch")
num_left_dims_u = u.ndim - 2
num_left_dims_lat = lat.ndim - 2
if (num_left_dims_lat > num_left_dims_u):
raise ValueError("number of 'lat' dimensions is greater than 'u'")
if lat_lon_fixed:
mode = 0 # fixed lat/lon
else:
if num_left_dims_u == num_left_dims_lat:
mode = 1 # lat/lon same as u
else:
mode = 2 # probably 3D with 2D lat/lon plus Time
has_missing = False
u_arr = u
if isinstance(u, DataArray):
u_arr = npvalues(u)
v_arr = v
if isinstance(v, DataArray):
v_arr = npvalues(v)
umissing = Constants.DEFAULT_FILL
if isinstance(u_arr, np.ma.MaskedArray):
has_missing = True
umissing = u_arr.fill_value
vmissing = Constants.DEFAULT_FILL
if isinstance(v_arr, np.ma.MaskedArray):
has_missing = True
vmissing = v_arr.fill_value
uvmetmissing = umissing
is_stag = 0
if (u.shape[-1] != lat.shape[-1] or u.shape[-2] != lat.shape[-2]):
is_stag = 1
# Sanity check
if (v.shape[-1] == lat.shape[-1] or v.shape[-2] == lat.shape[-2]):
raise ValueError("u is staggered but v is not")
if (v.shape[-1] != lat.shape[-1] or v.shape[-2] != lat.shape[-2]):
is_stag = 1
# Sanity check
if (u.shape[-1] == lat.shape[-1] or u.shape[-2] == lat.shape[-2]):
raise ValueError("v is staggered but u is not")
# No special left side iteration, return the function result
if (num_left_dims_u == 0):
return wrapped(u, v, lat, lon, cen_long, cone, isstag=is_stag,
has_missing=has_missing, umissing=umissing,
vmissing=vmissing, uvmetmissing=uvmetmissing)
# Initial output is time,nz,2,ny,nx to create contiguous views
outdims = u.shape[0:num_left_dims_u]
extra_dims = tuple(outdims) # Copy the left-most dims for iteration
outdims += (2,)
outdims += lat.shape[-2:]
outview_array = np.empty(outdims, alg_dtype)
# Final Output moves the u_v dimension to left side
output_dims = (2,)
output_dims += extra_dims
output_dims += lat.shape[-2:]
output = np.empty(output_dims, orig_dtype)
for left_idxs in iter_left_indexes(extra_dims):
left_and_slice_idxs = left_idxs + (slice(None),)
if mode == 0:
lat_left_and_slice = (slice(None),)
elif mode == 1:
lat_left_and_slice = left_and_slice_idxs
elif mode == 2:
# Only need the left-most
lat_left_and_slice = tuple(left_idx
for left_idx in left_idxs[0:num_left_dims_lat])
u_output_idxs = (0,) + left_idxs + (slice(None),)
v_output_idxs = (1,) + left_idxs + (slice(None),)
u_view_idxs = left_idxs + (0, slice(None))
v_view_idxs = left_idxs + (1, slice(None))
new_u = u[left_and_slice_idxs]
new_v = v[left_and_slice_idxs]
new_lat = lat[lat_left_and_slice]
new_lon = lon[lat_left_and_slice]
outview = outview_array[left_and_slice_idxs]
# Call the numerical routine
result = wrapped(new_u, new_v, new_lat, new_lon, cen_long, cone,
isstag=is_stag, has_missing=has_missing,
umissing=umissing, vmissing=vmissing,
uvmetmissing=uvmetmissing, outview=outview)
# Make sure the result is the same data as what got passed in
# Can delete this once everything works
if (result.__array_interface__["data"][0] !=
outview.__array_interface__["data"][0]):
raise RuntimeError("output array was copied")
output[u_output_idxs] = (
outview_array[u_view_idxs].astype(orig_dtype))
output[v_output_idxs] = (
outview_array[v_view_idxs].astype(orig_dtype))
if has_missing:
output = np.ma.masked_values(output, uvmetmissing)
return output
return func_wrapper
def cape_left_iter(alg_dtype=np.float64):
"""Decorator to handle iterating over leftmost dimensions when using
multiple files and/or multiple times with the cape product.
"""
@wrapt.decorator
def func_wrapper(wrapped, instance, args, kwargs):
# The cape calculations use an ascending vertical pressure coordinate
new_args = list(args)
new_kwargs = dict(kwargs)
p_hpa = args[0]
tk = args[1]
qv = args[2]
ht = args[3]
ter = args[4]
sfp = args[5]
missing = args[6]
i3dflag = args[7]
ter_follow = args[8]
is2d = False if i3dflag != 0 else True
# Need to order in ascending pressure order
flip = False
bot_idxs = (0,) * p_hpa.ndim
top_idxs = list(bot_idxs)
top_idxs[-3] = -1
top_idxs = tuple(top_idxs)
if p_hpa[bot_idxs] > p_hpa[top_idxs]:
flip = True
p_hpa = np.ascontiguousarray(p_hpa[...,::-1,:,:])
tk = np.ascontiguousarray(tk[...,::-1,:,:])
qv = np.ascontiguousarray(qv[...,::-1,:,:])
ht = np.ascontiguousarray(ht[...,::-1,:,:])
new_args[0] = p_hpa
new_args[1] = tk
new_args[2] = qv
new_args[3] = ht
num_left_dims = p_hpa.ndim - 3
orig_dtype = p_hpa.dtype
# No special left side iteration, build the output from the cape,cin
# result
if (num_left_dims == 0):
cape, cin = wrapped(*new_args, **new_kwargs)
output_dims = (2,)
output_dims += p_hpa.shape[-3:]
output = np.empty(output_dims, orig_dtype)
if flip and not is2d:
output[0,:] = cape[::-1,:,:]
output[1,:] = cin[::-1,:,:]
else:
output[0,:] = cape[:]
output[1,:] = cin[:]
return output
# Initial output is ...,cape_cin,nz,ny,nx to create contiguous views
outdims = p_hpa.shape[0:num_left_dims]
extra_dims = tuple(outdims) # Copy the left-most dims for iteration
outdims += (2,) # cape_cin
outdims += p_hpa.shape[-3:]
outview_array = np.empty(outdims, alg_dtype)
# Create the output array where the leftmost dim is the product type
output_dims = (2,)
output_dims += extra_dims
output_dims += p_hpa.shape[-3:]
output = np.empty(output_dims, orig_dtype)
for left_idxs in iter_left_indexes(extra_dims):
left_and_slice_idxs = left_idxs + (slice(None),)
cape_idxs = left_idxs + (0, slice(None))
cin_idxs = left_idxs + (1, slice(None))
cape_output_idxs = (0,) + left_idxs + (slice(None),)
cin_output_idxs = (1,) + left_idxs + (slice(None),)
view_cape_reverse_idxs = left_idxs + (0, slice(None,None,-1),
slice(None))
view_cin_reverse_idxs = left_idxs + (1, slice(None,None,-1),
slice(None))
new_args[0] = p_hpa[left_and_slice_idxs]
new_args[1] = tk[left_and_slice_idxs]
new_args[2] = qv[left_and_slice_idxs]
new_args[3] = ht[left_and_slice_idxs]
new_args[4] = ter[left_and_slice_idxs]
new_args[5] = sfp[left_and_slice_idxs]
capeview = outview_array[cape_idxs]
cinview = outview_array[cin_idxs]
# Call the numerical routine
new_kwargs["capeview"] = capeview
new_kwargs["cinview"] = cinview
cape, cin = wrapped(*new_args, **new_kwargs)
# Make sure the result is the same data as what got passed in
# Can delete this once everything works
if (cape.__array_interface__["data"][0] !=
capeview.__array_interface__["data"][0]):
raise RuntimeError("output array was copied")
if flip and not is2d:
output[cape_output_idxs] = (
outview_array[view_cape_reverse_idxs].astype(orig_dtype))
output[cin_output_idxs] = (
outview_array[view_cin_reverse_idxs].astype(orig_dtype))
else:
output[cape_output_idxs] = (
outview_array[cape_idxs].astype(orig_dtype))
output[cin_output_idxs] = (
outview_array[cin_idxs].astype(orig_dtype))
return output
return func_wrapper
def cloudfrac_left_iter(alg_dtype=np.float64):
"""Decorator to handle iterating over leftmost dimensions when using
multiple files and/or multiple times with the cloudfrac product.
"""
@wrapt.decorator
def func_wrapper(wrapped, instance, args, kwargs):
# The cape calculations use an ascending vertical pressure coordinate
new_args = list(args)
new_kwargs = dict(kwargs)
p = args[0]
rh = args[1]
num_left_dims = p.ndim - 3
orig_dtype = p.dtype
# No special left side iteration, build the output from the cape,cin
# result
if (num_left_dims == 0):
low, med, high = wrapped(*new_args, **new_kwargs)
output_dims = (3,)
output_dims += p.shape[-2:]
output = np.empty(output_dims, orig_dtype)
output[0,:] = low[:]
output[1,:] = med[:]
output[2,:] = high[:]
return output
# Initial output is ...,cape_cin,nz,ny,nx to create contiguous views
outdims = p.shape[0:num_left_dims]
extra_dims = tuple(outdims) # Copy the left-most dims for iteration
outdims += (3,) # low_mid_high
outdims += p.shape[-2:]
outview_array = np.empty(outdims, alg_dtype)
# Create the output array where the leftmost dim is the cloud type
output_dims = (3,)
output_dims += extra_dims
output_dims += p.shape[-2:]
output = np.empty(output_dims, orig_dtype)
for left_idxs in iter_left_indexes(extra_dims):
left_and_slice_idxs = left_idxs + (slice(None),)
low_idxs = left_idxs + (0, slice(None))
med_idxs = left_idxs + (1, slice(None))
high_idxs = left_idxs + (2, slice(None))
low_output_idxs = (0,) + left_idxs + (slice(None),)
med_output_idxs = (1,) + left_idxs + (slice(None),)
high_output_idxs = (2,) + left_idxs + (slice(None),)
new_args[0] = p[left_and_slice_idxs]
new_args[1] = rh[left_and_slice_idxs]
lowview = outview_array[low_idxs]
medview = outview_array[med_idxs]
highview = outview_array[high_idxs]
new_kwargs["lowview"] = lowview
new_kwargs["medview"] = medview
new_kwargs["highview"] = highview
low, med, high = wrapped(*new_args, **new_kwargs)
# Make sure the result is the same data as what got passed in
# Can delete this once everything works
if (low.__array_interface__["data"][0] !=
lowview.__array_interface__["data"][0]):
raise RuntimeError("output array was copied")
output[low_output_idxs] = (
outview_array[low_idxs].astype(orig_dtype))
output[med_output_idxs] = (
outview_array[med_idxs].astype(orig_dtype))
output[high_output_idxs] = (
outview_array[high_idxs].astype(orig_dtype))
return output
return func_wrapper

8
src/wrf/temp.py

@ -3,7 +3,7 @@ from __future__ import (absolute_import, division, print_function, @@ -3,7 +3,7 @@ from __future__ import (absolute_import, division, print_function,
from .constants import Constants
#from .extension import computetk, computeeth, computetv, computewetbulb
from .extension import _tk, computeeth, computetv, computewetbulb
from .extension import _tk, _eth, _tv, _wetbulb
from .decorators import convert_units
from .metadecorators import copy_and_set_metadata
from .util import extract_vars
@ -65,7 +65,7 @@ def get_eth(wrfnc, timeidx=0, method="cat", squeeze=True, @@ -65,7 +65,7 @@ def get_eth(wrfnc, timeidx=0, method="cat", squeeze=True,
full_p = p + pb
tk = _tk(full_p, full_t)
eth = computeeth(qv, tk, full_p)
eth = _eth(qv, tk, full_p)
return eth
@ -90,7 +90,7 @@ def get_tv(wrfnc, timeidx=0, method="cat", squeeze=True, @@ -90,7 +90,7 @@ def get_tv(wrfnc, timeidx=0, method="cat", squeeze=True,
full_p = p + pb
tk = _tk(full_p, full_t)
tv = computetv(tk,qv)
tv = _tv(tk, qv)
return tv
@ -114,7 +114,7 @@ def get_tw(wrfnc, timeidx=0, method="cat", squeeze=True, @@ -114,7 +114,7 @@ def get_tw(wrfnc, timeidx=0, method="cat", squeeze=True,
full_p = p + pb
tk = _tk(full_p, full_t)
tw = computewetbulb(full_p,tk,qv)
tw = _wetbulb(full_p, tk, qv)
return tw

2
src/wrf/units.py

@ -22,7 +22,7 @@ def _apply_conv_fact(var, vartype, var_unit, dest_unit): @@ -22,7 +22,7 @@ def _apply_conv_fact(var, vartype, var_unit, dest_unit):
def _to_celsius(var, var_unit):
if var_unit == "k":
return var - Constants.TCK0
return var - Constants.CELKEL
elif var_unit == "f":
return (var - 32.0) * (5.0/9.0)

162
src/wrf/util.py

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import os
from sys import version_info
from copy import copy
from collections import Iterable, Mapping, OrderedDict
@ -26,20 +27,13 @@ import numpy.ma as ma @@ -26,20 +27,13 @@ import numpy.ma as ma
from .config import xarray_enabled
from .projection import getproj, NullProjection
from .constants import Constants, ALL_TIMES
from .py3compat import (viewitems, viewkeys, viewvalues, isstr, py2round,
py3range, ucode)
if xarray_enabled():
from xarray import DataArray
from pandas import NaT
__all__ = ["extract_vars", "extract_global_attrs", "extract_dim",
"combine_files", "is_standard_wrf_var", "extract_times",
"iter_left_indexes", "get_left_indexes", "get_right_slices",
"is_staggered", "get_proj_params", "viewitems", "viewkeys",
"viewvalues", "py2round", "py3range", "combine_with", "either",
"from_args", "arg_location", "args_to_list", "npvalues",
"CoordPair"]
_COORD_PAIR_MAP = {"XLAT" : ("XLAT", "XLONG"),
"XLONG" : ("XLAT", "XLONG"),
@ -63,25 +57,25 @@ _LON_COORDS = ("XLONG", "XLONG_M", "XLONG_U","XLONG_V", "CLONG") @@ -63,25 +57,25 @@ _LON_COORDS = ("XLONG", "XLONG_M", "XLONG_U","XLONG_V", "CLONG")
_TIME_COORD_VARS = ("XTIME",)
def _is_time_coord_var(varname):
def is_time_coord_var(varname):
return varname in _TIME_COORD_VARS
def _get_coord_pairs(varname):
def get_coord_pairs(varname):
return _COORD_PAIR_MAP[varname]
def _is_multi_time_req(timeidx):
def is_multi_time_req(timeidx):
return timeidx is None
def _is_multi_file(wrfnc):
def is_multi_file(wrfnc):
return (isinstance(wrfnc, Iterable) and not isstr(wrfnc))
def _has_time_coord(wrfnc):
def has_time_coord(wrfnc):
return "XTIME" in wrfnc.variables
def _is_mapping(wrfnc):
def is_mapping(wrfnc):
return isinstance(wrfnc, Mapping)
def _generator_copy(gen):
@ -159,12 +153,12 @@ class IterWrapper(Iterable): @@ -159,12 +153,12 @@ class IterWrapper(Iterable):
return obj_copy.__iter__()
def _get_iterable(wrfseq):
def get_iterable(wrfseq):
"""Returns a resetable iterable object."""
if not _is_multi_file(wrfseq):
if not is_multi_file(wrfseq):
return wrfseq
else:
if not _is_mapping(wrfseq):
if not is_mapping(wrfseq):
if isinstance(wrfseq, (list, tuple, IterWrapper)):
return wrfseq
@ -177,72 +171,17 @@ def _get_iterable(wrfseq): @@ -177,72 +171,17 @@ def _get_iterable(wrfseq):
else:
return dict(wrfseq) # generator/custom iterable class
# Dictionary python 2-3 compatibility stuff
def viewitems(d):
func = getattr(d, "viewitems", None)
if func is None:
func = d.items
return func()
def viewkeys(d):
func = getattr(d, "viewkeys", None)
if func is None:
func = d.keys
return func()
def viewvalues(d):
func = getattr(d, "viewvalues", None)
if func is None:
func = d.values
return func()
def isstr(s):
try:
return isinstance(s, basestring)
except NameError:
return isinstance(s, str)
# Python 2 rounding behavior
def _round2(x, d=0):
p = 10 ** d
return float(floor((x * p) + copysign(0.5, x)))/p
def py2round(x, d=0):
if version_info >= (3,):
return _round2(x, d)
return round(x, d)
def py3range(*args):
if version_info >= (3,):
return range(*args)
return xrange(*args)
def ucode(*args, **kwargs):
if version_info >= (3, ):
return str(*args, **kwargs)
return unicode(*args, **kwargs)
# Helper to extract masked arrays from DataArrays that convert to NaN
def npvalues(da):
if not isinstance(da, DataArray):
result = da
def npvalues(array_type):
if not isinstance(array_type, DataArray):
result = array_type
else:
try:
fill_value = da.attrs["_FillValue"]
fill_value = array_type.attrs["_FillValue"]
except KeyError:
result = da.values
result = array_type.values
else:
result = ma.masked_invalid(da.values, copy=False)
result = ma.masked_invalid(array_type.values, copy=False)
result.set_fill_value(fill_value)
return result
@ -253,8 +192,8 @@ class either(object): @@ -253,8 +192,8 @@ class either(object):
self.varnames = varnames
def __call__(self, wrfnc):
if _is_multi_file(wrfnc):
if not _is_mapping(wrfnc):
if is_multi_file(wrfnc):
if not is_mapping(wrfnc):
wrfnc = next(iter(wrfnc))
else:
entry = wrfnc[next(iter(viewkeys(wrfnc)))]
@ -362,7 +301,7 @@ def _corners_moved(wrfnc, first_ll_corner, first_ur_corner, latvar, lonvar): @@ -362,7 +301,7 @@ def _corners_moved(wrfnc, first_ll_corner, first_ur_corner, latvar, lonvar):
return False
def _is_moving_domain(wrfseq, varname=None, latvar=either("XLAT", "XLAT_M"),
def is_moving_domain(wrfseq, varname=None, latvar=either("XLAT", "XLAT_M"),
lonvar=either("XLONG", "XLONG_M")):
if isinstance(latvar, either):
@ -372,17 +311,17 @@ def _is_moving_domain(wrfseq, varname=None, latvar=either("XLAT", "XLAT_M"), @@ -372,17 +311,17 @@ def _is_moving_domain(wrfseq, varname=None, latvar=either("XLAT", "XLAT_M"),
lonvar = lonvar(wrfseq)
# In case it's just a single file
if not _is_multi_file(wrfseq):
if not is_multi_file(wrfseq):
wrfseq = [wrfseq]
# Slow, but safe. Compare the corner points to the first item and see
# any move. User iterator protocol in case wrfseq is not a list/tuple.
if not _is_mapping(wrfseq):
if not is_mapping(wrfseq):
wrf_iter = iter(wrfseq)
first_wrfnc = next(wrf_iter)
else:
entry = wrfseq[next(iter(viewkeys(wrfseq)))]
return _is_moving_domain(entry, varname, latvar, lonvar)
return is_moving_domain(entry, varname, latvar, lonvar)
# Quick check on pressure coordinates, bypassing the need to search the
# domain corner points
@ -475,10 +414,10 @@ def extract_global_attrs(wrfnc, attrs): @@ -475,10 +414,10 @@ def extract_global_attrs(wrfnc, attrs):
else:
attrlist = attrs
multifile = _is_multi_file(wrfnc)
multifile = is_multi_file(wrfnc)
if multifile:
if not _is_mapping(wrfnc):
if not is_mapping(wrfnc):
wrfnc = next(iter(wrfnc))
else:
entry = wrfnc[next(iter(viewkeys(wrfnc)))]
@ -487,8 +426,8 @@ def extract_global_attrs(wrfnc, attrs): @@ -487,8 +426,8 @@ def extract_global_attrs(wrfnc, attrs):
return {attr:_get_global_attr(wrfnc, attr) for attr in attrlist}
def extract_dim(wrfnc, dim):
if _is_multi_file(wrfnc):
if not _is_mapping(wrfnc):
if is_multi_file(wrfnc):
if not is_mapping(wrfnc):
wrfnc = next(iter(wrfnc))
else:
entry = wrfnc[next(iter(viewkeys(wrfnc)))]
@ -509,7 +448,7 @@ def _combine_dict(wrfdict, varname, timeidx, method, meta): @@ -509,7 +448,7 @@ def _combine_dict(wrfdict, varname, timeidx, method, meta):
first_key = next(key_iter)
keynames.append(first_key)
is_moving = _is_moving_domain(wrfdict, varname)
is_moving = is_moving_domain(wrfdict, varname)
first_array = _extract_var(wrfdict[first_key], varname,
timeidx, is_moving=is_moving, method=method,
@ -591,7 +530,7 @@ def _find_max_time_size(wrfseq): @@ -591,7 +530,7 @@ def _find_max_time_size(wrfseq):
def _build_data_array(wrfnc, varname, timeidx, is_moving_domain):
multitime = _is_multi_time_req(timeidx)
multitime = is_multi_time_req(timeidx)
time_idx_or_slice = timeidx if not multitime else slice(None)
var = wrfnc.variables[varname]
data = var[time_idx_or_slice, :]
@ -611,10 +550,10 @@ def _build_data_array(wrfnc, varname, timeidx, is_moving_domain): @@ -611,10 +550,10 @@ def _build_data_array(wrfnc, varname, timeidx, is_moving_domain):
except AttributeError:
if is_coordvar(varname):
# Coordinate variable (most likely XLAT or XLONG)
lat_coord, lon_coord = _get_coord_pairs(varname)
lat_coord, lon_coord = get_coord_pairs(varname)
time_coord = None
if is_moving_domain and _has_time_coord(wrfnc):
if is_moving_domain and has_time_coord(wrfnc):
time_coord = "XTIME"
else:
@ -769,11 +708,11 @@ def _find_arr_for_time(wrfseq, varname, timeidx, is_moving, meta): @@ -769,11 +708,11 @@ def _find_arr_for_time(wrfseq, varname, timeidx, is_moving, meta):
# TODO: implement in C
def _cat_files(wrfseq, varname, timeidx, is_moving, squeeze, meta):
if is_moving is None:
is_moving = _is_moving_domain(wrfseq, varname)
is_moving = is_moving_domain(wrfseq, varname)
file_times = extract_times(wrfseq, ALL_TIMES)
multitime = _is_multi_time_req(timeidx)
multitime = is_multi_time_req(timeidx)
# For single times, just need to find the ncfile and appropriate
# time index, and return that array
@ -920,8 +859,8 @@ def _get_numfiles(wrfseq): @@ -920,8 +859,8 @@ def _get_numfiles(wrfseq):
# TODO: implement in C
def _join_files(wrfseq, varname, timeidx, is_moving, meta):
if is_moving is None:
is_moving = _is_moving_domain(wrfseq, varname)
multitime = _is_multi_time_req(timeidx)
is_moving = is_moving_domain(wrfseq, varname)
multitime = is_multi_time_req(timeidx)
numfiles = _get_numfiles(wrfseq)
maxtimes = _find_max_time_size(wrfseq)
@ -1101,10 +1040,10 @@ def combine_files(wrfseq, varname, timeidx, is_moving=None, @@ -1101,10 +1040,10 @@ def combine_files(wrfseq, varname, timeidx, is_moving=None,
method="cat", squeeze=True, meta=True):
# Handles generators, single files, lists, tuples, custom classes
wrfseq = _get_iterable(wrfseq)
wrfseq = get_iterable(wrfseq)
# Dictionary is unique
if _is_mapping(wrfseq):
if is_mapping(wrfseq):
outarr = _combine_dict(wrfseq, varname, timeidx, method, meta)
elif method.lower() == "cat":
outarr = _cat_files(wrfseq, varname, timeidx, is_moving,
@ -1133,13 +1072,13 @@ def _extract_var(wrfnc, varname, timeidx, is_moving, @@ -1133,13 +1072,13 @@ def _extract_var(wrfnc, varname, timeidx, is_moving,
return cache_var
multitime = _is_multi_time_req(timeidx)
multifile = _is_multi_file(wrfnc)
multitime = is_multi_time_req(timeidx)
multifile = is_multi_file(wrfnc)
if not multifile:
if xarray_enabled() and meta:
if is_moving is None:
is_moving = _is_moving_domain(wrfnc, varname)
is_moving = is_moving_domain(wrfnc, varname)
result = _build_data_array(wrfnc, varname, timeidx, is_moving)
else:
if not multitime:
@ -1167,16 +1106,16 @@ def extract_vars(wrfnc, timeidx, varnames, method="cat", squeeze=True, @@ -1167,16 +1106,16 @@ def extract_vars(wrfnc, timeidx, varnames, method="cat", squeeze=True,
for var in varlist}
# Python 3 compatability
def _npbytes_to_str(var):
def npbytes_to_str(var):
return (bytes(c).decode("utf-8") for c in var[:])
def _make_time(timearr):
return dt.datetime.strptime("".join(_npbytes_to_str(timearr)),
return dt.datetime.strptime("".join(npbytes_to_str(timearr)),
"%Y-%m-%d_%H:%M:%S")
def _file_times(wrfnc, timeidx):
multitime = _is_multi_time_req(timeidx)
multitime = is_multi_time_req(timeidx)
if multitime:
times = wrfnc.variables["Times"][:,:]
for i in py3range(times.shape[0]):
@ -1187,7 +1126,7 @@ def _file_times(wrfnc, timeidx): @@ -1187,7 +1126,7 @@ def _file_times(wrfnc, timeidx):
def extract_times(wrfnc, timeidx):
multi_file = _is_multi_file(wrfnc)
multi_file = is_multi_file(wrfnc)
if not multi_file:
wrf_list = [wrfnc]
else:
@ -1199,9 +1138,9 @@ def extract_times(wrfnc, timeidx): @@ -1199,9 +1138,9 @@ def extract_times(wrfnc, timeidx):
def is_standard_wrf_var(wrfnc, var):
multifile = _is_multi_file(wrfnc)
multifile = is_multi_file(wrfnc)
if multifile:
if not _is_mapping(wrfnc):
if not is_mapping(wrfnc):
wrfnc = next(iter(wrfnc))
else:
entry = wrfnc[next(iter(viewkeys(wrfnc)))]
@ -1268,7 +1207,7 @@ def get_proj_params(wrfnc, timeidx=0, varname=None): @@ -1268,7 +1207,7 @@ def get_proj_params(wrfnc, timeidx=0, varname=None):
"TRUELAT1", "TRUELAT2",
"MOAD_CEN_LAT", "STAND_LON",
"POLE_LAT", "POLE_LON"))
multitime = _is_multi_time_req(timeidx)
multitime = is_multi_time_req(timeidx)
if not multitime:
time_idx_or_slice = timeidx
else:
@ -1281,7 +1220,7 @@ def get_proj_params(wrfnc, timeidx=0, varname=None): @@ -1281,7 +1220,7 @@ def get_proj_params(wrfnc, timeidx=0, varname=None):
lon_coord = coord_names[0]
lat_coord = coord_names[1]
else:
lat_coord, lon_coord = _get_coord_pairs(varname)
lat_coord, lon_coord = get_coord_pairs(varname)
else:
lat_coord, lon_coord = latlon_coordvars(wrfnc.variables)
@ -1440,6 +1379,9 @@ def arg_location(func, argname, args, kwargs): @@ -1440,6 +1379,9 @@ def arg_location(func, argname, args, kwargs):
return _arg_location(func, argname, args, kwargs)
def psafilepath():
return os.path.join(os.path.dirname(__file__), "data", "psadilookup.dat")

229
src/wrf/uvdecorator.py

@ -1,229 +0,0 @@ @@ -1,229 +0,0 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import numpy as np
import wrapt
#from .destag import destagger
from .util import iter_left_indexes, py3range, npvalues
from .config import xarray_enabled
from .constants import Constants
if xarray_enabled():
from xarray import DataArray
# def uvmet_left_iter():
# """Decorator to handle iterating over leftmost dimensions when using
# multiple files and/or multiple times with the uvmet product.
#
# """
# @wrapt.decorator
# def func_wrapper(wrapped, instance, args, kwargs):
# u = args[0]
# v = args[1]
# lat = args[2]
# lon = args[3]
# cen_long = args[4]
# cone = args[5]
#
# if u.ndim == lat.ndim:
# num_right_dims = 2
# is_3d = False
# else:
# num_right_dims = 3
# is_3d = True
#
# is_stag = False
# if ((u.shape[-1] != lat.shape[-1]) or
# (u.shape[-2] != lat.shape[-2])):
# is_stag = True
#
# if is_3d:
# extra_dim_num = u.ndim - 3
# else:
# extra_dim_num = u.ndim - 2
#
# if is_stag:
# u = destagger(u,-1)
# v = destagger(v,-2)
#
# # No special left side iteration, return the function result
# if (extra_dim_num == 0):
# return wrapped(u, v, lat, lon, cen_long, cone)
#
# # Start by getting the left-most 'extra' dims
# outdims = u.shape[0:extra_dim_num]
# extra_dims = list(outdims) # Copy the left-most dims for iteration
#
# # Append the right-most dimensions
# outdims += [2] # For u/v components
#
# #outdims += [u.shape[x] for x in py3range(-num_right_dims,0,1)]
# outdims += list(u.shape[-num_right_dims:])
#
# output = np.empty(outdims, u.dtype)
#
# for left_idxs in iter_left_indexes(extra_dims):
# # Make the left indexes plus a single slice object
# # The single slice will handle all the dimensions to
# # the right (e.g. [1,1,:])
# left_and_slice_idxs = tuple([x for x in left_idxs] + [slice(None)])
#
# new_u = u[left_and_slice_idxs]
# new_v = v[left_and_slice_idxs]
# new_lat = lat[left_and_slice_idxs]
# new_lon = lon[left_and_slice_idxs]
#
# # Call the numerical routine
# result = wrapped(new_u, new_v, new_lat, new_lon, cen_long, cone)
#
# # Note: The 2D version will return a 3D array with a 1 length
# # dimension. Numpy is unable to broadcast this without
# # sqeezing first.
# result = np.squeeze(result)
#
# output[left_and_slice_idxs] = result[:]
#
# return output
#
# return func_wrapper
def uvmet_left_iter_nocopy(alg_dtype=np.float64):
"""Decorator to handle iterating over leftmost dimensions when using
multiple files and/or multiple times with the uvmet product.
"""
@wrapt.decorator
def func_wrapper(wrapped, instance, args, kwargs):
u = args[0]
v = args[1]
lat = args[2]
lon = args[3]
cen_long = args[4]
cone = args[5]
orig_dtype = u.dtype
lat_lon_fixed = False
if lat.ndim == 2:
lat_lon_fixed = True
if lon.ndim == 2 and not lat_lon_fixed:
raise ValueError("'lat' and 'lon' shape mismatch")
num_left_dims_u = u.ndim - 2
num_left_dims_lat = lat.ndim - 2
if (num_left_dims_lat > num_left_dims_u):
raise ValueError("number of 'lat' dimensions is greater than 'u'")
if lat_lon_fixed:
mode = 0 # fixed lat/lon
else:
if num_left_dims_u == num_left_dims_lat:
mode = 1 # lat/lon same as u
else:
mode = 2 # probably 3D with 2D lat/lon plus Time
has_missing = False
u_arr = u
if isinstance(u, DataArray):
u_arr = npvalues(u)
v_arr = v
if isinstance(v, DataArray):
v_arr = npvalues(v)
umissing = Constants.DEFAULT_FILL
if isinstance(u_arr, np.ma.MaskedArray):
has_missing = True
umissing = u_arr.fill_value
vmissing = Constants.DEFAULT_FILL
if isinstance(v_arr, np.ma.MaskedArray):
has_missing = True
vmissing = v_arr.fill_value
uvmetmissing = umissing
is_stag = 0
if (u.shape[-1] != lat.shape[-1] or u.shape[-2] != lat.shape[-2]):
is_stag = 1
# Sanity check
if (v.shape[-1] == lat.shape[-1] or v.shape[-2] == lat.shape[-2]):
raise ValueError("u is staggered but v is not")
if (v.shape[-1] != lat.shape[-1] or v.shape[-2] != lat.shape[-2]):
is_stag = 1
# Sanity check
if (u.shape[-1] == lat.shape[-1] or u.shape[-2] == lat.shape[-2]):
raise ValueError("v is staggered but u is not")
# No special left side iteration, return the function result
if (num_left_dims_u == 0):
return wrapped(u, v, lat, lon, cen_long, cone, isstag=is_stag,
has_missing=has_missing, umissing=umissing,
vmissing=vmissing, uvmetmissing=uvmetmissing)
# Initial output is time,nz,2,ny,nx to create contiguous views
outdims = u.shape[0:num_left_dims_u]
extra_dims = tuple(outdims) # Copy the left-most dims for iteration
outdims += (2,)
outdims += lat.shape[-2:]
outview_array = np.empty(outdims, alg_dtype)
for left_idxs in iter_left_indexes(extra_dims):
left_and_slice_idxs = left_idxs + (slice(None),)
if mode == 0:
lat_left_and_slice = (slice(None),)
elif mode == 1:
lat_left_and_slice = left_and_slice_idxs
elif mode == 2:
# Only need the left-most
lat_left_and_slice = tuple(left_idx
for left_idx in left_idxs[0:num_left_dims_lat])
new_u = u[left_and_slice_idxs]
new_v = v[left_and_slice_idxs]
new_lat = lat[lat_left_and_slice]
new_lon = lon[lat_left_and_slice]
outview = outview_array[left_and_slice_idxs]
# Call the numerical routine
result = wrapped(new_u, new_v, new_lat, new_lon, cen_long, cone,
isstag=is_stag, has_missing=has_missing,
umissing=umissing, vmissing=vmissing,
uvmetmissing=uvmetmissing, outview=outview)
# Make sure the result is the same data as what got passed in
# Can delete this once everything works
if (result.__array_interface__["data"][0] !=
outview.__array_interface__["data"][0]):
raise RuntimeError("output array was copied")
# Need to reshape this so that u_v is left dim, then time (or others),
# then nz, ny, nz
output_dims = (2,)
output_dims += extra_dims
output_dims += lat.shape[-2:]
output = np.empty(output_dims, orig_dtype)
output[0,:] = outview_array[...,0,:,:].astype(orig_dtype)
output[1,:] = outview_array[...,1,:,:].astype(orig_dtype)
if has_missing:
output = np.ma.masked_values(output, uvmetmissing)
return output
return func_wrapper

6
src/wrf/vorticity.py

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
from .extension import computeavo, computepvo
from .extension import _avo, _pvo
from .util import extract_vars, extract_global_attrs
from .metadecorators import copy_and_set_metadata
@ -27,7 +27,7 @@ def get_avo(wrfnc, timeidx=0, method="cat", squeeze=True, cache=None, @@ -27,7 +27,7 @@ def get_avo(wrfnc, timeidx=0, method="cat", squeeze=True, cache=None,
dx = attrs["DX"]
dy = attrs["DY"]
return computeavo(u, v, msfu, msfv, msfm, cor, dx, dy)
return _avo(u, v, msfu, msfv, msfm, cor, dx, dy)
@copy_and_set_metadata(copy_varname="T", name="pvo",
@ -58,5 +58,5 @@ def get_pvo(wrfnc, timeidx=0, method="cat", squeeze=True, cache=None, @@ -58,5 +58,5 @@ def get_pvo(wrfnc, timeidx=0, method="cat", squeeze=True, cache=None,
full_t = t + 300
full_p = p + pb
return computepvo(u, v, full_t, full_p, msfu, msfv, msfm, cor, dx, dy)
return _pvo(u, v, full_t, full_p, msfu, msfv, msfm, cor, dx, dy)

9
src/wrf/wind.py

@ -28,7 +28,7 @@ def _calc_wspd_wdir(u, v, two_d, units): @@ -28,7 +28,7 @@ def _calc_wspd_wdir(u, v, two_d, units):
outdims = list(wspd.shape[0:idx_end]) + [2] + list(wspd.shape[idx_end:])
res = np.zeros(outdims, wspd.dtype)
result = np.zeros(outdims, wspd.dtype)
idxs0 = ((0,Ellipsis, slice(None), slice(None), slice(None))
if not two_d else
@ -38,10 +38,10 @@ def _calc_wspd_wdir(u, v, two_d, units): @@ -38,10 +38,10 @@ def _calc_wspd_wdir(u, v, two_d, units):
if not two_d else
(0, Ellipsis, slice(None), slice(None)))
res[idxs0] = wspd[:]
res[idxs1] = wdir[:]
result[idxs0] = wspd[:]
result[idxs1] = wdir[:]
return res
return result
@set_wind_metadata(copy_varname=either("P", "PRES"),
@ -76,6 +76,7 @@ def get_v_destag(wrfnc, timeidx=0, method="cat", squeeze=True, @@ -76,6 +76,7 @@ def get_v_destag(wrfnc, timeidx=0, method="cat", squeeze=True,
v_vars = extract_vars(wrfnc, timeidx, varname, method, squeeze, cache,
meta=False)
v = destagger(v_vars[varname], -2)
return v

145
test/ipynb/WRF_Workshop_Demo.ipynb

@ -1,5 +1,72 @@ @@ -1,5 +1,72 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Demo for `wrf-python`\n",
"\n",
"# 1.0 Introduction\n",
"\n",
"1) **Created to provide Python with the same functionality found in WRF-NCL**\n",
" * WRF variable computation and extraction\n",
" * 2D and 3D interpolation routines\n",
" * WRF-ARW only\n",
" * Metadata\n",
"2) **Key differences with WRF-NCL**:\n",
" * Plotting is handled through matplotlib (with cartopy or basemap), or PyNGL.\n",
" * Metadata is optional and can be disabled\n",
" \n",
"**`wrf-python` is a work in progress and should be considered \"pre-alpha\". Changes to the API are likely to occur between now and the first official release.** \n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"# 2.0 Data Structures : `numpy.ndarray` and `xarray.DataArray`\n",
"\n",
"\n",
"`numpy.ndarray`:\n",
"----------------\n",
"* Standard array object in Python for array-based computations.\n",
"* Supports all standard compiled types and also Python types.\n",
"* Has methods to reshape, perform mathematical calculations, elementwise operations, etc.\n",
"* Supports missing/fill values using the `numpy.ma.MaskedArray` subclass\n",
"* Does not support metadata.\n",
"\n",
"`xarray.DataArray` (if enabled):\n",
"--------------------------------\n",
"* Adds metadata capabilities to the numpy array by wrapping around it.\n",
"* **HAS A** numpy array, is not a numpy array subclass.\n",
"* Supports many of the numpy methods, but generally requires the numpy array to be extracted out for computations.\n",
"* __Always uses NaN to represent missing/fill values__, rather than the MaskedArray type familiar to numpy users.\n",
"\n",
"\n",
"`npvalues` method:\n",
"------------------\n",
"1. If no missing/fill values, simply extracts the numpy array using the `DataArray.values` property.\n",
"2. If missing/fill values are found, converts the NaN values to the fill values and returns a MaskedArray."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 3.0 Examples"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Example 1: Basic Variable Extraction with `getvar` and Print the DataArray and Numpy Array Result"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -22,16 +89,20 @@ @@ -22,16 +89,20 @@
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from matplotlib.cm import get_cmap\n",
"from Nio import open_file\n",
"from wrf import getvar, npvalues\n",
"\n",
"#filename = \"/Users/ladwig/Documents/wrf_files/wrfout_d01_2016-02-25_18_00_00\"\n",
"#filename = \"/Users/ladwig/Documents/wrf_files/wrfout_d01_2010-06-13_21:00:00\"\n",
"filename = \"wrfout_d01_2010-06-13_21:00:00\"\n",
"# Open the output NetCDF file with PyNIO\n",
"filename = \"wrfout_d01_2010-06-13_21-00-00\"\n",
"pynio_filename = filename + \".nc\"\n",
"ncfile = open_file(pynio_filename)\n",
"\n",
"# Alternative using netCDF4-python (for reference)\n",
"# Do 'conda install netcdf4' if the netcdf4 package is not installed\n",
"#from netCDF4 import Dataset as nc\n",
"#filename = \"wrfout_d01_2010-06-13_21-00-00\"\n",
"#ncfile = nc(filename)\n",
"\n",
"# Extract the terrain height, which will be returned as an xarray.DataArray object (if available). DataArray\n",
"# objects include meta data, similar to NCL's variables.\n",
"# Note: can also use the 'ter' variable\n",
@ -45,6 +116,13 @@ @@ -45,6 +116,13 @@
"print (terrain_numpy)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Example 2: Use `getvar` to Extract the 'HGT' Variable and Make a Plot Using Matplotlib with Basemap"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -59,10 +137,8 @@ @@ -59,10 +137,8 @@
"from Nio import open_file\n",
"from wrf import getvar, npvalues\n",
"\n",
"\n",
"#filename = \"/Users/ladwig/Documents/wrf_files/wrfout_d01_2016-02-25_18_00_00\"\n",
"#filename = \"/Users/ladwig/Documents/wrf_files/wrfout_d01_2010-06-13_21:00:00\"\n",
"filename = \"wrfout_d01_2010-06-13_21:00:00\"\n",
"# Open the output NetCDF file with PyNIO\n",
"filename = \"wrfout_d01_2010-06-13_21-00-00\"\n",
"pynio_filename = filename + \".nc\"\n",
"ncfile = open_file(pynio_filename)\n",
"\n",
@ -107,6 +183,13 @@ @@ -107,6 +183,13 @@
"plt.show()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Example 3: Use `getvar` to Compute Dewpoint and Make a Plot Using Matplotlib with Basemap"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -122,10 +205,8 @@ @@ -122,10 +205,8 @@
"from Nio import open_file\n",
"from wrf import getvar, npvalues\n",
"\n",
"\n",
"#filename = \"/Users/ladwig/Documents/wrf_files/wrfout_d01_2016-02-25_18_00_00\"\n",
"#filename = \"/Users/ladwig/Documents/wrf_files/wrfout_d01_2010-06-13_21:00:00\"\n",
"filename = \"wrfout_d01_2010-06-13_21:00:00\"\n",
"# Open the output NetCDF file with PyNIO\n",
"filename = \"wrfout_d01_2010-06-13_21-00-00\"\n",
"pynio_filename = filename + \".nc\"\n",
"ncfile = open_file(pynio_filename)\n",
"\n",
@ -174,6 +255,13 @@ @@ -174,6 +255,13 @@
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Example 4: Create a Vertical Cross-Section Using `vertcross` and Make a Plot Using Matplotlib with Basemap"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -189,16 +277,14 @@ @@ -189,16 +277,14 @@
"from Nio import open_file\n",
"from wrf import getvar, vertcross, npvalues\n",
"\n",
"# Open the output netcdf file\n",
"#filename = \"/Users/ladwig/Documents/wrf_files/wrfout_d01_2016-02-25_18_00_00\"\n",
"#filename = \"/Users/ladwig/Documents/wrf_files/wrfout_d01_2010-06-13_21:00:00\"\n",
"filename = \"wrfout_d01_2010-06-13_21:00:00\"\n",
"# Open the output NetCDF file with PyNIO\n",
"filename = \"wrfout_d01_2010-06-13_21-00-00\"\n",
"pynio_filename = filename + \".nc\"\n",
"ncfile = open_file(pynio_filename)\n",
"\n",
"# Extract pressure and model height\n",
"p = getvar(ncfile, \"pressure\")\n",
"z = getvar(ncfile, \"z\")\n",
"p = getvar(ncfile, \"pressure\", timeidx=0)\n",
"z = getvar(ncfile, \"z\", timeidx=0)\n",
"\n",
"# Define a horizontal cross section going left to right using a pivot point in the center of the grid\n",
"# with an angle of 90.0 degrees (0 degrees is vertical).\n",
@ -246,6 +332,13 @@ @@ -246,6 +332,13 @@
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Example 5: Interpolate Wind and Height to the 500 hPa Level Using `interplevel` and Make a Plot of the 500 hPa Wind Barbs, Wind Speed, and Height Contours Using Matplotlib with Basemap"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -260,19 +353,17 @@ @@ -260,19 +353,17 @@
"from Nio import open_file\n",
"from wrf import getvar, interplevel, npvalues\n",
"\n",
"# Open the output netcdf file\n",
"#filename = \"/Users/ladwig/Documents/wrf_files/wrfout_d01_2016-02-25_18_00_00\"\n",
"#filename = \"/Users/ladwig/Documents/wrf_files/wrfout_d01_2010-06-13_21:00:00\"\n",
"filename = \"wrfout_d01_2010-06-13_21:00:00\"\n",
"# Open the output NetCDF file with PyNIO\n",
"filename = \"wrfout_d01_2010-06-13_21-00-00\"\n",
"pynio_filename = filename + \".nc\"\n",
"ncfile = open_file(pynio_filename)\n",
"\n",
"# Extract pressure, model height, u and v winds on mass points\n",
"p = getvar(ncfile, \"pressure\")\n",
"z = getvar(ncfile, \"z\", units=\"dm\")\n",
"ua = getvar(ncfile, \"ua\", units=\"kts\")\n",
"va = getvar(ncfile, \"va\", units=\"kts\")\n",
"wspd = getvar(ncfile, \"wspd_wdir\", units=\"kts\")[0,...]\n",
"p = getvar(ncfile, \"pressure\", timeidx=0)\n",
"z = getvar(ncfile, \"z\", timeidx=0, units=\"dm\")\n",
"ua = getvar(ncfile, \"ua\", timeidx=0, units=\"kts\")\n",
"va = getvar(ncfile, \"va\", timeidx=0, units=\"kts\")\n",
"wspd = getvar(ncfile, \"wspd_wdir\", timeidx=0, units=\"kts\")[0,...]\n",
"\n",
"# Interpolate height, u, and v to to 500 hPa\n",
"ht_500 = interplevel(z, p, 500)\n",

61
test/ipynb/nocopy_test.ipynb

@ -483,6 +483,67 @@ @@ -483,6 +483,67 @@
"print (\"\\n\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"\n",
"import numpy as np\n",
"\n",
"from wrf import (ALL_TIMES, getvar, cape_2d, cape_3d, extract_vars, tk, destagger, ConversionFactors, Constants)\n",
"from netCDF4 import Dataset as nc\n",
"\n",
"timeidx = ALL_TIMES\n",
"method = \"cat\"\n",
"squeeze=True\n",
"cache=None\n",
"timeidx = None\n",
"\n",
"wrfnc = nc(\"/Users/ladwig/Documents/wrf_files/wrfout_d01_2010-06-13_21:00:00\")\n",
"\n",
"wrfnc = [wrfnc, wrfnc]\n",
"\n",
"varnames = (\"T\", \"P\", \"PB\", \"QVAPOR\", \"PH\", \"PHB\", \"HGT\", \"PSFC\")\n",
"ncvars = extract_vars(wrfnc, timeidx, varnames, method, squeeze, cache,\n",
" meta=True)\n",
"t = ncvars[\"T\"]\n",
"p = ncvars[\"P\"]\n",
"pb = ncvars[\"PB\"]\n",
"qvapor = ncvars[\"QVAPOR\"]\n",
"ph = ncvars[\"PH\"]\n",
"phb = ncvars[\"PHB\"]\n",
"ter = ncvars[\"HGT\"]\n",
"psfc = ncvars[\"PSFC\"]\n",
" \n",
"full_t = t + Constants.T_BASE\n",
"full_p = p + pb\n",
"tkel = tk(full_p, full_t)\n",
" \n",
"geopt = ph + phb\n",
"geopt_unstag = destagger(geopt, -3)\n",
"height = geopt_unstag/Constants.G\n",
" \n",
"# Convert pressure to hPa\n",
"p_hpa = ConversionFactors.PA_TO_HPA * full_p\n",
"psfc_hpa = ConversionFactors.PA_TO_HPA * psfc \n",
"\n",
"ter_follow = 1\n",
"\n",
"cape2d = cape_2d(p_hpa, tkel, qvapor, height, ter, psfc_hpa, ter_follow, \n",
" missing=Constants.DEFAULT_FILL, meta=True)\n",
"\n",
"cape3d = cape_3d(p_hpa, tkel, qvapor, height, ter, psfc_hpa, ter_follow, \n",
" missing=Constants.DEFAULT_FILL, meta=True)\n",
"\n",
"print (cape2d)\n",
"print (cape3d)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,

81
test/utests.py

@ -83,16 +83,29 @@ def make_test(varname, wrf_in, referent, multi=False, repeat=3, pynio=False): @@ -83,16 +83,29 @@ def make_test(varname, wrf_in, referent, multi=False, repeat=3, pynio=False):
nc = Nio.open_file(wrf_file)
in_wrfnc = [nc for i in xrange(repeat)]
# Note: remove this after cloudfrac is included in NCL
# For now just make sure it runs
if varname == "cloudfrac":
my_vals = getvar(in_wrfnc, "cloudfrac", timeidx=timeidx)
return
refnc = NetCDF(referent)
if not multi:
ref_vals = refnc.variables[varname][:]
else:
data = refnc.variables[varname][:]
if varname != "uvmet" and varname != "uvmet10":
if (varname != "uvmet" and varname != "uvmet10"
and varname != "cape_2d" and varname != "cape_3d"):
new_dims = [repeat] + [x for x in data.shape]
else:
elif (varname == "uvmet" or varname == "uvmet10"
or varname == "cape_3d"):
new_dims = [2] + [repeat] + [x for x in data.shape[1:]]
elif (varname == "cape_2d"):
new_dims = [4] + [repeat] + [x for x in data.shape[1:]]
masked=False
if (isinstance(data, ma.core.MaskedArray)):
masked=True
@ -103,24 +116,36 @@ def make_test(varname, wrf_in, referent, multi=False, repeat=3, pynio=False): @@ -103,24 +116,36 @@ def make_test(varname, wrf_in, referent, multi=False, repeat=3, pynio=False):
ref_vals = ma.asarray(n.zeros(new_dims, data.dtype))
for i in xrange(repeat):
if varname != "uvmet" and varname != "uvmet10":
if (varname != "uvmet" and varname != "uvmet10"
and varname != "cape_2d" and varname != "cape_3d"):
ref_vals[i,:] = data[:]
if masked:
ref_vals.mask[i,:] = data.mask[:]
else:
elif (varname == "uvmet" or varname == "uvmet10"
or varname=="cape_3d"):
ref_vals[0, i, :] = data[0,:]
ref_vals[1, i, :] = data[1,:]
if masked:
ref_vals.mask[0,i,:] = data.mask[:]
ref_vals.mask[1,i,:] = data.mask[:]
ref_vals.mask[0,i,:] = data.mask[0,:]
ref_vals.mask[1,i,:] = data.mask[1,:]
elif varname == "cape_2d":
ref_vals[0, i, :] = data[0,:]
ref_vals[1, i, :] = data[1,:]
ref_vals[2, i, :] = data[2,:]
ref_vals[3, i, :] = data[3,:]
if masked:
ref_vals.mask[0,i,:] = data.mask[0,:]
ref_vals.mask[1,i,:] = data.mask[1,:]
ref_vals.mask[2,i,:] = data.mask[2,:]
ref_vals.mask[3,i,:] = data.mask[3,:]
if (varname == "tc"):
my_vals = getvar(in_wrfnc, "temp", timeidx=timeidx, units="c")
tol = 0
tol = 1/100.
atol = .1 # Note: NCL uses 273.16 as conversion for some reason
nt.assert_allclose(npvalues(my_vals), ref_vals, tol, atol)
elif (varname == "pw"):
@ -131,18 +156,30 @@ def make_test(varname, wrf_in, referent, multi=False, repeat=3, pynio=False): @@ -131,18 +156,30 @@ def make_test(varname, wrf_in, referent, multi=False, repeat=3, pynio=False):
nt.assert_allclose(npvalues(my_vals), ref_vals, tol, atol)
elif (varname == "cape_2d"):
cape_2d = getvar(in_wrfnc, varname, timeidx=timeidx)
tol = 0/100. # Not sure why different, F77 vs F90?
atol = .2
nt.assert_allclose(npvalues(cape_2d), ref_vals, tol, atol)
tol = 0/100.
atol = 200.0
# Let's only compare CAPE values until the F90 changes are
# merged back in to NCL. The modifications to the R and CP
# changes TK enough that non-lifting parcels could lift, thus
# causing wildly different values in LCL
nt.assert_allclose(npvalues(cape_2d[0,:]), ref_vals[0,:], tol, atol)
elif (varname == "cape_3d"):
cape_3d = getvar(in_wrfnc, varname, timeidx=timeidx)
tol = 0/100. # Not sure why different, F77 vs F90?
atol = .01
# Changing the R and CP constants, while keeping TK within
# 2%, can lead to some big changes in CAPE. Tolerances
# have been set wide when comparing the with the original
# NCL. Change back when the F90 code is merged back with
# NCL
tol = 0/100.
atol = 200.0
#print n.amax(n.abs(npvalues(cape_3d[0,:]) - ref_vals[0,:]))
nt.assert_allclose(npvalues(cape_3d), ref_vals, tol, atol)
else:
my_vals = getvar(in_wrfnc, varname, timeidx=timeidx)
tol = 0/100.
atol = 0.0001
tol = 2/100.
atol = 0.1
#print (n.amax(n.abs(npvalues(my_vals) - ref_vals)))
nt.assert_allclose(npvalues(my_vals), ref_vals, tol, atol)
@ -289,10 +326,11 @@ def make_interp_test(varname, wrf_in, referent, multi=False, @@ -289,10 +326,11 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
timeidx=timeidx,
log_p=True)
tol = 0/100.
tol = 5/100.
atol = 0.0001
field = n.squeeze(field)
#print (n.amax(n.abs(npvalues(field) - fld_tk_theta)))
nt.assert_allclose(npvalues(field), fld_tk_theta, tol, atol)
# Tk to theta-e
@ -310,10 +348,11 @@ def make_interp_test(varname, wrf_in, referent, multi=False, @@ -310,10 +348,11 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
timeidx=timeidx,
log_p=True)
tol = 0/100.
atol = 0.0001
tol = 3/100.
atol = 50.0001
field = n.squeeze(field)
#print (n.amax(n.abs(npvalues(field) - fld_tk_theta_e)/fld_tk_theta_e)*100)
nt.assert_allclose(npvalues(field), fld_tk_theta_e, tol, atol)
# Tk to pressure
@ -333,6 +372,7 @@ def make_interp_test(varname, wrf_in, referent, multi=False, @@ -333,6 +372,7 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
field = n.squeeze(field)
#print (n.amax(n.abs(npvalues(field) - fld_tk_pres)))
nt.assert_allclose(npvalues(field), fld_tk_pres, tol, atol)
# Tk to geoht_msl
@ -350,6 +390,7 @@ def make_interp_test(varname, wrf_in, referent, multi=False, @@ -350,6 +390,7 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
log_p=True)
field = n.squeeze(field)
#print (n.amax(n.abs(npvalues(field) - fld_tk_ght_msl)))
nt.assert_allclose(npvalues(field), fld_tk_ght_msl, tol, atol)
# Tk to geoht_agl
@ -367,6 +408,7 @@ def make_interp_test(varname, wrf_in, referent, multi=False, @@ -367,6 +408,7 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
log_p=True)
field = n.squeeze(field)
#print (n.amax(n.abs(npvalues(field) - fld_tk_ght_agl)))
nt.assert_allclose(npvalues(field), fld_tk_ght_agl, tol, atol)
# Hgt to pressure
@ -385,6 +427,7 @@ def make_interp_test(varname, wrf_in, referent, multi=False, @@ -385,6 +427,7 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
log_p=True)
field = n.squeeze(field)
#print (n.amax(n.abs(npvalues(field) - fld_ht_pres)))
nt.assert_allclose(npvalues(field), fld_ht_pres, tol, atol)
# Pressure to theta
@ -403,6 +446,7 @@ def make_interp_test(varname, wrf_in, referent, multi=False, @@ -403,6 +446,7 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
log_p=True)
field = n.squeeze(field)
#print (n.amax(n.abs(npvalues(field) - fld_pres_theta)))
nt.assert_allclose(npvalues(field), fld_pres_theta, tol, atol)
# Theta-e to pres
@ -421,6 +465,7 @@ def make_interp_test(varname, wrf_in, referent, multi=False, @@ -421,6 +465,7 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
log_p=True)
field = n.squeeze(field)
#print (n.amax(n.abs(npvalues(field) - fld_thetae_pres)))
nt.assert_allclose(npvalues(field), fld_thetae_pres, tol, atol)
return test
@ -438,7 +483,7 @@ if __name__ == "__main__": @@ -438,7 +483,7 @@ if __name__ == "__main__":
"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", "ctt"]
"wa", "uvmet10", "uvmet", "z", "ctt", "cloudfrac"]
interp_methods = ["interplevel", "vertcross", "interpline", "vinterp"]
try:

17
test/viewtest.py

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