Browse Source

Added the jinja patch for 1.21 conda-build so it works with numpy distutils. Added code for the threadlocal caching. Added a cached test. Modified cloudfrac to match what has been committed to NCL. Modified the NCL test script to add cloud fraction.

main
Bill Ladwig 9 years ago
parent
commit
1f731e8b25
  1. 9
      conda_recipe/meta.yaml
  2. 0
      fortran/wrf_cloud_fracf.f90
  3. 22
      fortran/wrffortran.pyf
  4. 148
      ncl_reference/WRFUserARW.ncl
  5. 183
      ncl_reference/jinja_context.py
  6. 4
      setup.py
  7. 52
      src/wrf/cache.py
  8. 76
      src/wrf/config.py
  9. 14
      src/wrf/metadecorators.py
  10. 3
      src/wrf/routines.py
  11. 47
      src/wrf/util.py
  12. 65
      test/cachetest.py
  13. 2
      test/ncl_get_var.ncl
  14. 41
      test/utests.py

9
conda_recipe/meta.yaml

@ -1,13 +1,16 @@ @@ -1,13 +1,16 @@
# For the version to work, the patch in ncl_reference needs to be applied
# to the installed conda-build. Otherwise, it needs to be set manually until
# continuum can release a fix.
package:
name: wrf-python
version: "0.0.1"
version: {{ load_setup_py_data().version }}
source:
git_url: git@github.com:NCAR/wrf-python.git
git_rev: prebeta.0.1
build:
number: 5
number: 1
detect_binary_files_with_prefix: true
requirements:

0
fortran/cloud_fracf.f90 → fortran/wrf_cloud_fracf.f90

22
fortran/wrffortran.pyf

@ -22,17 +22,6 @@ python module _wrffortran ! in @@ -22,17 +22,6 @@ python module _wrffortran ! in
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
subroutine deqthecalc(qvp,tmk,prs,eth,miy,mjx,mkzh) ! in :_wrffortran:eqthecalc.f90
threadsafe
use wrf_constants, only: tlclc2,tlclc3,tlclc1,tlclc4,eps,thtecon3,gammamd,thtecon1,gamma,thtecon2
@ -104,6 +93,17 @@ python module _wrffortran ! in @@ -104,6 +93,17 @@ python module _wrffortran ! in
integer intent(inout) :: errstat
character*(*) intent(inout) :: errmsg
end subroutine dcapecalc3d
subroutine dcloudfrac(pres,rh,lowc,midc,highc,nz,ns,ew) ! in :_wrffortran:wrf_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 wrf_constants ! in :_wrffortran:wrf_constants.f90
real(kind=8), parameter,optional :: wrf_earth_radius=6370000.d0
real(kind=8), parameter,optional :: rhowat=1000.d0

148
ncl_reference/WRFUserARW.ncl

@ -894,7 +894,7 @@ begin @@ -894,7 +894,7 @@ begin
uvmet(1,:,:) = (/v(:,:)/)
end if
copy_VarAtts_except(u,uvmet,(/"description","units"/))
uvmet@description = " u,v met velocity"
uvmet@description = "u,v met velocity"
uvmet!0 = "u_v"
do n=0,dimsizes(dims)-1 ; Copy dimension names
if(isdimnamed(u,n))
@ -950,7 +950,7 @@ begin @@ -950,7 +950,7 @@ begin
end if
if( (variable .eq. "uvmet10") ) then
uvmet@description = " u10,v10 met velocity"
uvmet@description = "u10,v10 met velocity"
end if
return(uvmet)
@ -1377,7 +1377,68 @@ begin @@ -1377,7 +1377,68 @@ begin
return(cape)
end if
if( any( variable .eq. "cfrac" )) then
print("calculating wrf cloud fraction")
if(typeof(file_handle).eq."file") then
ISFILE = True
nc_file = file_handle
else if(typeof(file_handle).eq."list") then
ISFILE = False
nc_file = file_handle[0]
else
print("wrf_user_getvar: error: the first argument must be a file or a list of files opened with addfile or addfiles")
return
end if
end if
time_in = time
if ( time .eq. -1 ) then
if(ISFILE) then
P = nc_file->P
PB = nc_file->PB
rh = wrf_user_getvar(nc_file,"rh",-1)
else
P = file_handle[:]->P
PB = file_handle[:]->PB
rh = wrf_user_getvar(file_handle,"rh",-1)
end if
else
if(ISFILE) then
P = nc_file->P(time_in,:,:,:)
PB = nc_file->PB(time_in,:,:,:)
rh = wrf_user_getvar(file_handle,"rh",time_in)
else
P = file_handle[:]->P(time_in,:,:,:)
PB = file_handle[:]->PB(time_in,:,:,:)
rh = wrf_user_getvar(file_handle,"rh",time_in)
end if
end if
pres = (P + PB)
thedims = dimsizes(pres)
if(time .eq. -1) then
nt = thedims(0)
nz = thedims(1)
ns = thedims(2)
ew = thedims(3)
else
nt = 1
nz = thedims(0)
ns = thedims(1)
ew = thedims(2)
end if
out_array = wrf_cloud_fraction(pres,rh)
out_array@units = "%"
out_array@description = "Low, Mid, High Clouds"
return(out_array)
end if ;variable is cfrac
if( any( variable .eq. (/"pw"/) ) ) then
;Precipitable Water
@ -2172,6 +2233,7 @@ begin @@ -2172,6 +2233,7 @@ begin
field_type = str_lower(get_res_value_keep(opts,"field_type","none"))
log_of_Pressure = get_res_value_keep(opts,"logP",False)
debug = get_res_value_keep(opts,"debug",False)
timeidx = get_res_value_keep(opts,"time",-1)
valid_field_types = (/"none","pressure","pres","p","z","t","ght"/)
if(.not.any(field_type.eq.valid_field_types)) then
@ -2237,29 +2299,23 @@ begin @@ -2237,29 +2299,23 @@ begin
;We will need some basic fields for the interpolation
;regardless of the field requested. Get all time periods
;of the fields.
P = _get_wrf_var(file_handle,"P",-1) + _get_wrf_var(file_handle,"PB",-1)
qvp = _get_wrf_var(file_handle,"QVAPOR",-1)
terht = _get_wrf_var(file_handle,"HGT",-1)
sfp = _get_wrf_var(file_handle,"PSFC",-1) * 0.01
P = _get_wrf_var(file_handle,"P",timeidx) + _get_wrf_var(file_handle,"PB",timeidx)
qvp = _get_wrf_var(file_handle,"QVAPOR",timeidx)
terht = _get_wrf_var(file_handle,"HGT",timeidx)
sfp = _get_wrf_var(file_handle,"PSFC",timeidx) * 0.01
Pdims = dimsizes(P)
if(ISFILE) then
ght = wrf_user_getvar(nc_file,"height",-1)
tk = wrf_user_getvar(nc_file,"tk",-1)
else
tmpz = file_handle[:]->PH
PHB = file_handle[:]->PHB
tmpz = (tmpz + PHB)/9.81
ght = wrf_user_unstagger(tmpz,"Z")
T = file_handle[:]->T
T = T + 300.
tk = wrf_tk( P , T )
end if
smsfp = sfp
wrf_smooth_2d(smsfp,3)
ght = wrf_user_getvar(file_handle,"height",timeidx)
tk = wrf_user_getvar(file_handle,"tk",timeidx)
smsfp = sfp
wrf_smooth_2d(smsfp,3)
;Initialize an array for the vertical coordinate
ntimes = Pdims(0)
if (timeidx .lt. 0) then
ntimes = Pdims(0)
else
ntimes = 1
end if
;Get the vertical coordinate type
vcor = 0
@ -2276,14 +2332,26 @@ begin @@ -2276,14 +2332,26 @@ begin
if(vert_coordinate .eq. "ght_agl") then
vcor = 3
rtemp = new( (/nz,ns,ew/),float)
vcord_array = new((/ntimes,nz,ns,ew/),float)
do it = 0, ntimes - 1
do ilev = 0,nz-1
rtemp(ilev,:,:) = ght(it,ilev,:,:) - terht(0,:,:)
end do
vcord_array(it,:,:,:) = exp(-rtemp/sclht)
end do
if (timeidx .lt. 0) then
rtemp = new( (/nz,ns,ew/),float)
vcord_array = new((/ntimes,nz,ns,ew/),float)
do it = 0, ntimes - 1
do ilev = 0,nz-1
rtemp(ilev,:,:) = ght(it,ilev,:,:) - terht(it,:,:)
end do
vcord_array(it,:,:,:) = exp(-rtemp/sclht)
end do
else
rtemp = new((/nz,ns,ew/),float)
vcord_array = new((/nz,ns,ew/), float)
do ilev = 0,nz-1
rtemp(ilev,:,:) = ght(ilev,:,:) - terht(:,:)
end do
vcord_array(:,:,:) = exp(-rtemp/sclht)
end if
delete(rtemp)
end if
@ -2292,13 +2360,8 @@ begin @@ -2292,13 +2360,8 @@ begin
idir = 1
icorsw = 0
delta = 0.01
if(ISFILE) then
coriolis = nc_file->F(0,:,:)
theta = wrf_user_getvar(nc_file,"theta",-1)
else
coriolis = file_handle[0]->F(0,:,:)
theta = T
end if
coriolis = _get_wrf_var(file_handle, "F", timeidx)
theta = wrf_user_getvar(file_handle,"theta",timeidx)
preshPa = P * 0.01
vcord_array = wrf_monotonic(theta,preshPa,coriolis,idir,delta,icorsw)
;
@ -2313,13 +2376,8 @@ begin @@ -2313,13 +2376,8 @@ begin
icorsw = 0
idir = 1
delta = 0.01
if(ISFILE) then
coriolis = nc_file->F(0,:,:)
eqpot = wrf_user_getvar(nc_file,"eth",-1)
else
coriolis = file_handle[0]->F(0,:,:)
eqpot = wrf_eth ( qvp, tk, P )
end if
coriolis = _get_wrf_var(file_handle, "F", timeidx)
eqpot = wrf_user_getvar(file_handle,"eth",timeidx)
preshPa = P * 0.01
vcord_array = wrf_monotonic(eqpot,preshPa,coriolis,idir,delta,icorsw)
@ -2332,7 +2390,7 @@ begin @@ -2332,7 +2390,7 @@ begin
print("icase = " + icase + " extrap = " + extrap + " vcor = " + vcor + " logP = " + logP)
end if
field_out = wrf_vintrp(field,P,tk,qvp,ght,terht(0,:,:),sfp,smsfp,\
field_out = wrf_vintrp(field,P,tk,qvp,ght,terht,sfp,smsfp,\
vcord_array,interp_levels,icase,extrap,vcor,logP)
; Add metadata to return array
@ -2341,7 +2399,7 @@ begin @@ -2341,7 +2399,7 @@ begin
; Add new levels as a coordinate array
lev_field = num_field_dims-3
field_out!lev_field = "interp_levels"
field_out&$field_out!lev_field$ = interp_levels(::-1)
field_out&$field_out!lev_field$ = interp_levels(:)
field_out@vert_interp_type = vert_coordinate
return(field_out)

183
ncl_reference/jinja_context.py

@ -0,0 +1,183 @@ @@ -0,0 +1,183 @@
'''
Created on Jan 16, 2014
@author: sean
'''
from __future__ import absolute_import, division, print_function
from functools import partial
import json
import logging
import os
import sys
import jinja2
from .conda_interface import PY3
from .environ import get_dict as get_environ
from .metadata import select_lines, ns_cfg
from .source import WORK_DIR
log = logging.getLogger(__file__)
class UndefinedNeverFail(jinja2.Undefined):
"""
A class for Undefined jinja variables.
This is even less strict than the default jinja2.Undefined class,
because it permits things like {{ MY_UNDEFINED_VAR[:2] }} and
{{ MY_UNDEFINED_VAR|int }}. This can mask lots of errors in jinja templates, so it
should only be used for a first-pass parse, when you plan on running a 'strict'
second pass later.
"""
all_undefined_names = []
def __init__(self, hint=None, obj=jinja2.runtime.missing, name=None,
exc=jinja2.exceptions.UndefinedError):
UndefinedNeverFail.all_undefined_names.append(name)
jinja2.Undefined.__init__(self, hint, obj, name, exc)
__add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
__truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \
__mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
__getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
__complex__ = __pow__ = __rpow__ = \
lambda self, *args, **kwargs: UndefinedNeverFail(hint=self._undefined_hint,
obj=self._undefined_obj,
name=self._undefined_name,
exc=self._undefined_exception)
__str__ = __repr__ = \
lambda *args, **kwargs: u''
__int__ = lambda _: 0
__float__ = lambda _: 0.0
def __getattr__(self, k):
try:
return object.__getattr__(self, k)
except AttributeError:
return UndefinedNeverFail(hint=self._undefined_hint,
obj=self._undefined_obj,
name=self._undefined_name + '.' + k,
exc=self._undefined_exception)
class FilteredLoader(jinja2.BaseLoader):
"""
A pass-through for the given loader, except that the loaded source is
filtered according to any metadata selectors in the source text.
"""
def __init__(self, unfiltered_loader):
self._unfiltered_loader = unfiltered_loader
self.list_templates = unfiltered_loader.list_templates
def get_source(self, environment, template):
contents, filename, uptodate = self._unfiltered_loader.get_source(environment,
template)
return select_lines(contents, ns_cfg()), filename, uptodate
def load_setup_py_data(setup_file='setup.py', from_recipe_dir=False, recipe_dir=None,
unload_modules=None, fail_on_error=False):
_setuptools_data = {}
def setup(**kw):
_setuptools_data.update(kw)
import setuptools
import distutils.core
try:
import numpy.distutils.core
except ImportError:
do_numpy = False
else:
do_numpy = True
cd_to_work = False
if from_recipe_dir and recipe_dir:
setup_file = os.path.abspath(os.path.join(recipe_dir, setup_file))
elif os.path.exists(WORK_DIR):
cd_to_work = True
cwd = os.getcwd()
os.chdir(WORK_DIR)
if not os.path.isabs(setup_file):
setup_file = os.path.join(WORK_DIR, setup_file)
# this is very important - or else if versioneer or otherwise is in the start folder,
# things will pick up the wrong versioneer/whatever!
sys.path.insert(0, WORK_DIR)
else:
log.debug("Did not find setup.py file in manually specified location, and source "
"not downloaded yet.")
return {}
# Patch setuptools, distutils
setuptools_setup = setuptools.setup
distutils_setup = distutils.core.setup
setuptools.setup = distutils.core.setup = setup
if do_numpy:
numpy_setup = numpy.distutils.core.setup
numpy.distutils.core.setup = setup
ns = {
'__name__': '__main__',
'__doc__': None,
'__file__': setup_file,
}
try:
code = compile(open(setup_file).read(), setup_file, 'exec', dont_inherit=1)
exec(code, ns, ns)
distutils.core.setup = distutils_setup
setuptools.setup = setuptools_setup
if do_numpy:
numpy.distutils.core.setup = numpy_setup
# this happens if setup.py is used in load_setup_py_data, but source is not yet downloaded
except:
raise
finally:
if cd_to_work:
os.chdir(cwd)
del sys.path[0]
return _setuptools_data
def load_setuptools(setup_file='setup.py', from_recipe_dir=False, recipe_dir=None,
unload_modules=None, fail_on_error=False):
log.warn("Deprecation notice: the load_setuptools function has been renamed to "
"load_setup_py_data. load_setuptools will be removed in a future release.")
return load_setup_py_data(setup_file=setup_file, from_recipe_dir=from_recipe_dir,
recipe_dir=recipe_dir, unload_modules=unload_modules,
fail_on_error=fail_on_error)
def load_npm():
# json module expects bytes in Python 2 and str in Python 3.
mode_dict = {'mode': 'r', 'encoding': 'utf-8'} if PY3 else {'mode': 'rb'}
with open('package.json', **mode_dict) as pkg:
return json.load(pkg)
def context_processor(initial_metadata, recipe_dir):
"""
Return a dictionary to use as context for jinja templates.
initial_metadata: Augment the context with values from this MetaData object.
Used to bootstrap metadata contents via multiple parsing passes.
"""
ctx = get_environ(m=initial_metadata)
environ = dict(os.environ)
environ.update(get_environ(m=initial_metadata))
ctx.update(
load_setup_py_data=partial(load_setup_py_data, recipe_dir=recipe_dir),
# maintain old alias for backwards compatibility:
load_setuptools=partial(load_setuptools, recipe_dir=recipe_dir),
load_npm=load_npm,
environ=environ)
return ctx

4
setup.py

@ -8,7 +8,7 @@ ext1 = numpy.distutils.core.Extension( @@ -8,7 +8,7 @@ ext1 = numpy.distutils.core.Extension(
"fortran/wrf_testfunc.f90",
"fortran/wrf_user.f90",
"fortran/rip_cape.f90",
"fortran/cloud_fracf.f90",
"fortran/wrf_cloud_fracf.f90",
"fortran/wrf_fctt.f90",
"fortran/wrf_user_dbz.f90",
"fortran/wrf_relhl.f90",
@ -22,7 +22,7 @@ ext1 = numpy.distutils.core.Extension( @@ -22,7 +22,7 @@ ext1 = numpy.distutils.core.Extension(
"fortran/wrffortran.pyf"]
)
with open('src/wrf/version.py') as f:
with open("src/wrf/version.py") as f:
exec(f.read())
requirements = [

52
src/wrf/cache.py

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)
from threading import local
from collections import OrderedDict
from .config import get_cache_size
_local_storage = local()
def cache_item(key, product, value):
global _local_storage
try:
cache = _local_storage.cache
except AttributeError:
_local_storage.cache = OrderedDict()
cache = _local_storage.cache
try:
prod_dict = cache[key]
except KeyError:
if len(cache) >= get_cache_size():
cache.popitem(last=False) # Remove the oldest dataset
cache[key] = OrderedDict()
prod_dict = cache[key]
cache[key][product] = value
def get_cached_item(key, product):
cache = getattr(_local_storage, "cache", None)
if cache is None:
return None
prod_dict = cache.get(key, None)
if prod_dict is None:
return None
return prod_dict.get(product, None)
def _get_cache():
return getattr(_local_storage, "cache", None)

76
src/wrf/config.py

@ -4,75 +4,87 @@ from __future__ import (absolute_import, division, print_function, @@ -4,75 +4,87 @@ from __future__ import (absolute_import, division, print_function,
try:
from xarray import DataArray
except ImportError:
_XARRAY_ENABLED = False
_xarray_enabled = False
else:
_XARRAY_ENABLED = True
_xarray_enabled = True
try:
from cartopy import crs
except ImportError:
_CARTOPY_ENABLED = False
_cartopy_enabled = False
else:
_CARTOPY_ENABLED = True
_cartopy_enabled = True
try:
from mpl_toolkits.basemap import Basemap
except ImportError:
_BASEMAP_ENABLED = False
_basemap_enabled = False
else:
_BASEMAP_ENABLED = True
_basemap_enabled = True
try:
from Ngl import Resources
except ImportError:
_PYNGL_ENABLED = False
_pyngl_enabled = False
else:
_PYNGL_ENABLED = True
_pyngl_enabled = True
_cache_size = 5
def xarray_enabled():
global _XARRAY_ENABLED
return _XARRAY_ENABLED
global _xarray_enabled
return _xarray_enabled
def disable_xarray():
global _XARRAY_ENABLED
_XARRAY_ENABLED = False
global _xarray_enabled
_xarray_enabled = False
def enable_xarray():
global _XARRAY_ENABLED
_XARRAY_ENABLED = True
global _xarray_enabled
_xarray_enabled = True
def cartopy_enabled():
global _CARTOPY_ENABLED
return _CARTOPY_ENABLED
global _cartopy_enabled
return _cartopy_enabled
def enable_cartopy():
global _CARTOPY_ENABLED
_CARTOPY_ENABLED = True
global _cartopy_enabled
_cartopy_enabled = True
def disable_cartopy():
global _CARTOPY_ENABLED
_CARTOPY_ENABLED = True
global _cartopy_enabled
_cartopy_enabled = True
def basemap_enabled():
global _BASEMAP_ENABLED
return _BASEMAP_ENABLED
global _basemap_enabled
return _basemap_enabled
def enable_basemap():
global _BASEMAP_ENABLED
_BASEMAP_ENABLED = True
global _basemap_enabled
_basemap_enabled = True
def disable_basemap():
global _BASEMAP_ENABLED
_BASEMAP_ENABLED = True
global _basemap_enabled
_basemap_enabled = True
def pyngl_enabled():
global _PYNGL_ENABLED
return _PYNGL_ENABLED
global _pyngl_enabled
return _pyngl_enabled
def enable_pyngl():
global _PYNGL_ENABLED
_PYNGL_ENABLED = True
global _pyngl_enabled
_pyngl_enabled = True
def disable_pyngl():
global _PYNGL_ENABLED
_PYNGL_ENABLED = True
global _pyngl_enabled
_pyngl_enabled = True
def set_cache_size(size):
global _cache_size
_cache_size = size
def get_cache_size():
return int(_cache_size)

14
src/wrf/metadecorators.py

@ -369,8 +369,8 @@ def set_cloudfrac_metadata(): @@ -369,8 +369,8 @@ def set_cloudfrac_metadata():
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"
outdimnames[0] = "low_mid_high"
outattrs["description"] = "low, mid, high clouds"
outattrs["MemoryOrder"] = "XY"
outattrs["units"] = "%"
outname = "cloudfrac"
@ -388,7 +388,7 @@ def set_cloudfrac_metadata(): @@ -388,7 +388,7 @@ def set_cloudfrac_metadata():
elif key == "Time":
outcoords[key] = npvalues(dataarray)
outcoords["low_med_high"] = ["low", "med", "high"]
outcoords["low_mid_high"] = ["low", "mid", "high"]
return DataArray(result, name=outname, coords=outcoords,
dims=outdimnames, attrs=outattrs)
@ -1342,7 +1342,7 @@ def set_cloudfrac_alg_metadata(copyarg="pres"): @@ -1342,7 +1342,7 @@ def set_cloudfrac_alg_metadata(copyarg="pres"):
outattrs = OrderedDict()
outname = "cloudfrac"
outattrs["description"] = "low, med, high clouds"
outattrs["description"] = "low, mid, high clouds"
outattrs["units"] = "%"
outattrs["MemoryOrder"] = "XY"
@ -1357,9 +1357,9 @@ def set_cloudfrac_alg_metadata(copyarg="pres"): @@ -1357,9 +1357,9 @@ def set_cloudfrac_alg_metadata(copyarg="pres"):
outcoords = {}
# Left-most is always cape_cin or cape_cin_lcl_lfc
outdims[0] = "low_med_high"
outcoords["low_med_high"] = ["low", "med", "high"]
# Left-most is always low_mid_high
outdims[0] = "low_mid_high"
outcoords["low_mid_high"] = ["low", "mid", "high"]
out = DataArray(result, name=outname, dims=outdims, coords=outcoords,
attrs=outattrs)

3
src/wrf/routines.py

@ -129,7 +129,8 @@ _ALIASES = {"cape_2d" : "cape2d", @@ -129,7 +129,8 @@ _ALIASES = {"cape_2d" : "cape2d",
"ter" : "terrain",
"updraft_helicity" : "uhel",
"td" : "dp",
"td2" : "dp2m"
"td2" : "dp2m",
"cfrac" : "cloudfrac"
}
class ArgumentError(Exception):

47
src/wrf/util.py

@ -325,18 +325,20 @@ def is_moving_domain(wrfseq, varname=None, latvar=either("XLAT", "XLAT_M"), @@ -325,18 +325,20 @@ def is_moving_domain(wrfseq, varname=None, latvar=either("XLAT", "XLAT_M"),
# Quick check on pressure coordinates, bypassing the need to search the
# domain corner points
try:
coord_names = getattr(first_wrfnc.variables["P"],
"coordinates").split()
except KeyError:
pass
else:
if "XTIME" in coord_names:
return True
else:
return False
# try:
# coord_names = getattr(first_wrfnc.variables["P"],
# "coordinates").split()
# except KeyError:
# pass
# else:
# if "XTIME" in coord_names:
# return True
# else:
# return False
# The long way of checking all lat/lon corner points
# There doesn't appear to be a shortcut, so this should probably
# be stored in a cache somewhere
if varname is not None:
try:
coord_names = getattr(first_wrfnc.variables[varname],
@ -349,18 +351,18 @@ def is_moving_domain(wrfseq, varname=None, latvar=either("XLAT", "XLAT_M"), @@ -349,18 +351,18 @@ def is_moving_domain(wrfseq, varname=None, latvar=either("XLAT", "XLAT_M"),
else:
# If the XTIME variable is found to be a coordinate variable,
# then it's a moving domain file
try:
xtime_coord = coord_names[2]
except IndexError:
# XTIME is not a coordinate variable, if the variable is in the
# file, then this is not a moving domain file
if "XTIME" in first_wrfnc.variables:
return False
else:
# XTIME is a coordinate, so this is a moving domain file
if xtime_coord == "XTIME":
return True
# try:
# xtime_coord = coord_names[2]
# except IndexError:
# # XTIME is not a coordinate variable, if the variable is in the
# # file, then this is not a moving domain file
# if "XTIME" in first_wrfnc.variables:
# return False
#
# else:
# # XTIME is a coordinate, so this is a moving domain file
# if xtime_coord == "XTIME":
# return True
lon_coord = coord_names[0]
lat_coord = coord_names[1]
@ -395,6 +397,7 @@ def is_moving_domain(wrfseq, varname=None, latvar=either("XLAT", "XLAT_M"), @@ -395,6 +397,7 @@ def is_moving_domain(wrfseq, varname=None, latvar=either("XLAT", "XLAT_M"),
else:
if _corners_moved(wrfnc, ll_corner, ur_corner,
lat_coord, lon_coord):
return True
return False

65
test/cachetest.py

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

2
test/ncl_get_var.ncl

@ -22,7 +22,7 @@ @@ -22,7 +22,7 @@
"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"/]
"wa", "uvmet10", "uvmet", "z", "cfrac"/]
unique_dimname_list = NewList("fifo")
unique_dimsize_list = NewList("fifo")

41
test/utests.py

@ -83,15 +83,14 @@ def make_test(varname, wrf_in, referent, multi=False, repeat=3, pynio=False): @@ -83,15 +83,14 @@ 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)
# These have a left index that defines the product type
multiproduct = varname in ("uvmet", "uvmet10", "cape_2d", "cape_3d",
"cfrac")
if not multi:
ref_vals = refnc.variables[varname][:]
else:
@ -104,6 +103,8 @@ def make_test(varname, wrf_in, referent, multi=False, repeat=3, pynio=False): @@ -104,6 +103,8 @@ def make_test(varname, wrf_in, referent, multi=False, repeat=3, pynio=False):
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:]]
elif (varname == "cfrac"):
new_dims = [3] + [repeat] + [x for x in data.shape[1:]]
masked=False
@ -116,32 +117,18 @@ def make_test(varname, wrf_in, referent, multi=False, repeat=3, pynio=False): @@ -116,32 +117,18 @@ def make_test(varname, wrf_in, referent, multi=False, repeat=3, pynio=False):
ref_vals = ma.asarray(np.zeros(new_dims, data.dtype))
for i in xrange(repeat):
if (varname != "uvmet" and varname != "uvmet10"
and varname != "cape_2d" and varname != "cape_3d"):
if not multiproduct:
ref_vals[i,:] = data[:]
if masked:
ref_vals.mask[i,:] = data.mask[:]
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[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,:]
else:
for prod in xrange(ref_vals.shape[0]):
ref_vals[prod,i,:] = data[prod,:]
if masked:
ref_vals.mask[prod,i,:] = data.mask[prod,:]
if (varname == "tc"):
my_vals = getvar(in_wrfnc, "temp", timeidx=timeidx, units="c")
@ -483,7 +470,7 @@ if __name__ == "__main__": @@ -483,7 +470,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", "cloudfrac"]
"wa", "uvmet10", "uvmet", "z", "cfrac"]
interp_methods = ["interplevel", "vertcross", "interpline", "vinterp"]
try:

Loading…
Cancel
Save