Browse Source

Fix issues found during testing of static and moving nests.

lon0
Bill Ladwig 7 years ago
parent
commit
06280e5cae
  1. 31
      src/wrf/interp.py
  2. 2
      src/wrf/latlonutils.py
  3. 32
      src/wrf/metadecorators.py
  4. 3
      src/wrf/util.py
  5. 106
      test/utests.py

31
src/wrf/interp.py

@ -272,15 +272,20 @@ def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64),
end_point_xy = None end_point_xy = None
pivot_point_xy = None pivot_point_xy = None
if timeidx is None:
if (latlon is True or is_latlon_pair(start_point) or if (latlon is True or is_latlon_pair(start_point) or
is_latlon_pair(pivot_point)): is_latlon_pair(pivot_point)):
if wrfin is not None:
is_moving = is_moving_domain(wrfin)
else:
is_moving = False
if timeidx is None:
if wrfin is not None: if wrfin is not None:
# Moving nests aren't supported with ALL_TIMES because the # Moving nests aren't supported with ALL_TIMES because the
# domain could move outside of the cross section, which causes # domain could move outside of the line, which causes
# crashes or different line lengths. # crashes or different line lengths.
if is_moving_domain(wrfin): if is_moving:
raise ValueError("Requesting all times with a moving nest " raise ValueError("Requesting all times with a moving nest "
"is not supported when using lat/lon " "is not supported when using lat/lon "
"cross sections because the domain could " "cross sections because the domain could "
@ -288,6 +293,7 @@ def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64),
"You must request each time " "You must request each time "
"individually.") "individually.")
else: else:
# Domain not moving, just use 0
_timeidx = 0 _timeidx = 0
# If using grid coordinates, then don't care about lat/lon # If using grid coordinates, then don't care about lat/lon
@ -295,7 +301,12 @@ def vertcross(field3d, vert, levels=None, missing=default_fill(np.float64),
else: else:
_timeidx = 0 _timeidx = 0
else: else:
if is_moving:
_timeidx = timeidx _timeidx = timeidx
else:
# When using non-moving nests, set the time to 0
# to avoid problems downstream
_timeidx = 0
if pivot_point is not None: if pivot_point is not None:
if pivot_point.lat is not None and pivot_point.lon is not None: if pivot_point.lat is not None and pivot_point.lon is not None:
@ -472,15 +483,20 @@ def interpline(field2d, pivot_point=None,
end_point_xy = None end_point_xy = None
pivot_point_xy = None pivot_point_xy = None
if timeidx is None:
if (latlon is True or is_latlon_pair(start_point) or if (latlon is True or is_latlon_pair(start_point) or
is_latlon_pair(pivot_point)): is_latlon_pair(pivot_point)):
if wrfin is not None:
is_moving = is_moving_domain(wrfin)
else:
is_moving = False
if timeidx is None:
if wrfin is not None: if wrfin is not None:
# Moving nests aren't supported with ALL_TIMES because the # Moving nests aren't supported with ALL_TIMES because the
# domain could move outside of the line, which causes # domain could move outside of the line, which causes
# crashes or different line lengths. # crashes or different line lengths.
if is_moving_domain(wrfin): if is_moving:
raise ValueError("Requesting all times with a moving nest " raise ValueError("Requesting all times with a moving nest "
"is not supported when using a lat/lon " "is not supported when using a lat/lon "
"line because the domain could " "line because the domain could "
@ -496,7 +512,12 @@ def interpline(field2d, pivot_point=None,
else: else:
_timeidx = 0 _timeidx = 0
else: else:
if is_moving:
_timeidx = timeidx _timeidx = timeidx
else:
# When using non-moving nests, set the time to 0
# to avoid problems downstream
_timeidx = 0
if pivot_point is not None: if pivot_point is not None:
if pivot_point.lat is not None and pivot_point.lon is not None: if pivot_point.lat is not None and pivot_point.lon is not None:

2
src/wrf/latlonutils.py

@ -167,7 +167,7 @@ def _get_proj_params(wrfin, timeidx, stagger, method, squeeze, cache, _key):
# Only need one file and one time if the domain is not moving # Only need one file and one time if the domain is not moving
if not is_moving: if not is_moving:
if is_multi_time_req(timeidx): # Always use the 0th time for non-moving domains to avoid problems
lat_timeidx = 0 lat_timeidx = 0
if is_multi_file(wrfin): if is_multi_file(wrfin):

32
src/wrf/metadecorators.py

@ -933,15 +933,20 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
end_point_xy = None end_point_xy = None
pivot_point_xy = None pivot_point_xy = None
if timeidx is None:
if (inc_latlon is True or is_latlon_pair(start_point) or if (inc_latlon is True or is_latlon_pair(start_point) or
is_latlon_pair(pivot_point)): is_latlon_pair(pivot_point)):
if wrfin is not None:
is_moving = is_moving_domain(wrfin)
else:
is_moving = False
if timeidx is None:
if wrfin is not None: if wrfin is not None:
# Moving nests aren't supported with ALL_TIMES because the # Moving nests aren't supported with ALL_TIMES because the
# domain could move outside of the cross section, which causes # domain could move outside of the line, which causes
# crashes or different line lengths. # crashes or different line lengths.
if is_moving_domain(wrfin): if is_moving:
raise ValueError("Requesting all times with a moving nest " raise ValueError("Requesting all times with a moving nest "
"is not supported when using lat/lon " "is not supported when using lat/lon "
"cross sections because the domain could " "cross sections because the domain could "
@ -949,6 +954,7 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
"You must request each time " "You must request each time "
"individually.") "individually.")
else: else:
# Domain not moving, just use 0
_timeidx = 0 _timeidx = 0
# If using grid coordinates, then don't care about lat/lon # If using grid coordinates, then don't care about lat/lon
@ -956,7 +962,12 @@ def _set_cross_meta(wrapped, instance, args, kwargs):
else: else:
_timeidx = 0 _timeidx = 0
else: else:
if is_moving:
_timeidx = timeidx _timeidx = timeidx
else:
# When using non-moving nests, set the time to 0
# to avoid problems downstream
_timeidx = 0
if pivot_point is not None: if pivot_point is not None:
if pivot_point.lat is not None and pivot_point.lon is not None: if pivot_point.lat is not None and pivot_point.lon is not None:
@ -1176,15 +1187,20 @@ def _set_line_meta(wrapped, instance, args, kwargs):
end_point_xy = None end_point_xy = None
pivot_point_xy = None pivot_point_xy = None
if timeidx is None:
if (inc_latlon is True or is_latlon_pair(start_point) or if (inc_latlon is True or is_latlon_pair(start_point) or
is_latlon_pair(pivot_point)): is_latlon_pair(pivot_point)):
if wrfin is not None:
is_moving = is_moving_domain(wrfin)
else:
is_moving = False
if timeidx is None:
if wrfin is not None: if wrfin is not None:
# Moving nests aren't supported with ALL_TIMES because the # Moving nests aren't supported with ALL_TIMES because the
# domain could move outside of the line, which causes # domain could move outside of the line, which causes
# crashes or different line lengths. # crashes or different line lengths.
if is_moving_domain(wrfin): if is_moving:
raise ValueError("Requesting all times with a moving nest " raise ValueError("Requesting all times with a moving nest "
"is not supported when using a lat/lon " "is not supported when using a lat/lon "
"line because the domain could " "line because the domain could "
@ -1200,7 +1216,13 @@ def _set_line_meta(wrapped, instance, args, kwargs):
else: else:
_timeidx = 0 _timeidx = 0
else: else:
if is_moving:
_timeidx = timeidx _timeidx = timeidx
else:
# When using non-moving nests, set the time to 0
# to avoid problems downstream
_timeidx = 0
if pivot_point is not None: if pivot_point is not None:
if pivot_point.lat is not None and pivot_point.lon is not None: if pivot_point.lat is not None and pivot_point.lon is not None:

3
src/wrf/util.py

@ -3893,7 +3893,10 @@ def is_latlon_pair(pair):
:obj:`bool`: True if the pair is a lat/lon pair. :obj:`bool`: True if the pair is a lat/lon pair.
""" """
if pair is not None:
return (pair.lat is not None and pair.lon is not None) return (pair.lat is not None and pair.lon is not None)
else:
return False

106
test/utests.py

@ -15,9 +15,11 @@ from wrf.util import is_multi_file
NCL_EXE = "/Users/ladwig/miniconda2/envs/ncl_build/bin/ncl" NCL_EXE = "/Users/ladwig/miniconda2/envs/ncl_build/bin/ncl"
NCARG_ROOT = "/Users/ladwig/miniconda2/envs/ncl_build" NCARG_ROOT = "/Users/ladwig/miniconda2/envs/ncl_build"
#TEST_FILE = "/Users/ladwig/Documents/wrf_files/wrfout_d01_2010-06-13_21:00:00" #TEST_FILE = "/Users/ladwig/Documents/wrf_files/wrfout_d01_2010-06-13_21:00:00"
DIR = "/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/moving_nest" DIRS = ["/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/moving_nest",
"/Users/ladwig/Documents/wrf_files/wrf_vortex_multi/static_nest"]
PATTERN = "wrfout_d02_*" PATTERN = "wrfout_d02_*"
REF_NC_FILE = "/tmp/wrftest.nc" REF_NC_FILES = ["/tmp/wrftest_moving.nc", "/tmp/wrftest_static.nc"]
NEST = ["moving", "static"]
# Python 3 # Python 3
if sys.version_info > (3,): if sys.version_info > (3,):
@ -36,15 +38,17 @@ def setUpModule():
ncl_script = os.path.join(os.path.dirname(this_path), ncl_script = os.path.join(os.path.dirname(this_path),
"ncl_get_var.ncl") "ncl_get_var.ncl")
cmd = "%s %s 'dir=\"%s\"' 'pattern=\"%s\"' 'out_file=\"%s\"'" % (NCL_EXE, for dir,outfile in zip(DIRS, REF_NC_FILES):
cmd = "%s %s 'dir=\"%s\"' 'pattern=\"%s\"' 'out_file=\"%s\"'" % (
NCL_EXE,
ncl_script, ncl_script,
DIR, dir,
PATTERN, PATTERN,
REF_NC_FILE) outfile)
print cmd print cmd
if not os.path.exists(REF_NC_FILE): if not os.path.exists(outfile):
status = subprocess.call(cmd, shell=True) status = subprocess.call(cmd, shell=True)
if (status != 0): if (status != 0):
raise RuntimeError("NCL script failed. Could not set up test.") raise RuntimeError("NCL script failed. Could not set up test.")
@ -377,6 +381,9 @@ def make_interp_test(varname, dir, pattern, referent, multi=False,
# Only do this for the non-multi case, since the domain # Only do this for the non-multi case, since the domain
# might be moving # might be moving
if not multi: if not multi:
if lats.ndim > 2: # moving nest
lats = lats[0,:]
lons = lons[0,:]
ll_point = ll_points(lats, lons) ll_point = ll_points(lats, lons)
@ -430,7 +437,7 @@ def make_interp_test(varname, dir, pattern, referent, multi=False,
nt.assert_allclose(to_np(ht_cross), nt.assert_allclose(to_np(ht_cross),
to_np(ref_ht_vertcross2), atol=.01) to_np(ref_ht_vertcross2), atol=.01)
idxs = (0, slice(None)) if multi else (slice(None),) idxs = (0, slice(None)) if lats.ndim > 2 else (slice(None),)
start_lat = np.amin(lats[idxs]) + .25*(np.amax(lats[idxs]) - np.amin(lats[idxs])) start_lat = np.amin(lats[idxs]) + .25*(np.amax(lats[idxs]) - np.amin(lats[idxs]))
end_lat = np.amin(lats[idxs]) + .65*(np.amax(lats[idxs]) - np.amin(lats[idxs])) end_lat = np.amin(lats[idxs]) + .65*(np.amax(lats[idxs]) - np.amin(lats[idxs]))
@ -501,6 +508,7 @@ def make_interp_test(varname, dir, pattern, referent, multi=False,
lats = t2.coords["XLAT"] lats = t2.coords["XLAT"]
lons = t2.coords["XLONG"] lons = t2.coords["XLONG"]
if multi: if multi:
if lats.ndim > 2: # moving nest
lats = lats[0,:] lats = lats[0,:]
lons = lons[0,:] lons = lons[0,:]
@ -852,6 +860,14 @@ def make_latlon_test(testid, dir, pattern, referent, single,
nt.assert_allclose(to_np(xy), ref) nt.assert_allclose(to_np(xy), ref)
if xy.ndim > 2:
# Moving nest
is_moving = True
numtimes = xy.shape[-2]
else:
is_moving = False
numtimes = 1
for tidx in range(9): for tidx in range(9):
# Next make sure the 'proj' version works # Next make sure the 'proj' version works
@ -859,7 +875,12 @@ def make_latlon_test(testid, dir, pattern, referent, single,
xy_proj = ll_to_xy_proj(lats, lons, as_int=False, xy_proj = ll_to_xy_proj(lats, lons, as_int=False,
**projparams) **projparams)
nt.assert_allclose(to_np(xy_proj), to_np(xy[:,tidx,:])) if is_moving:
idxs = (slice(None), tidx, slice(None))
else:
idxs = (slice(None),)
nt.assert_allclose(to_np(xy_proj), to_np(xy[idxs]))
else: else:
# i_s, j_s taken from NCL script, just hard-coding for now # i_s, j_s taken from NCL script, just hard-coding for now
@ -887,13 +908,25 @@ def make_latlon_test(testid, dir, pattern, referent, single,
nt.assert_allclose(to_np(ll), ref) nt.assert_allclose(to_np(ll), ref)
if ll.ndim > 2:
# Moving nest
is_moving = True
numtimes = ll.shape[-2]
else:
is_moving = False
numtimes = 1
for tidx in range(9): for tidx in range(numtimes):
# Next make sure the 'proj' version works # Next make sure the 'proj' version works
projparams = extract_proj_params(wrfin, timeidx=tidx) projparams = extract_proj_params(wrfin, timeidx=tidx)
ll_proj = xy_to_ll_proj(x_s, y_s, **projparams) ll_proj = xy_to_ll_proj(x_s, y_s, **projparams)
nt.assert_allclose(to_np(ll_proj), to_np(ll[:,tidx,:])) if is_moving:
idxs = (slice(None), tidx, slice(None))
else:
idxs = (slice(None),)
nt.assert_allclose(to_np(ll_proj), to_np(ll[idxs]))
return test return test
@ -924,6 +957,7 @@ if __name__ == "__main__":
interp_methods = ["interplevel", "vertcross", "interpline", "vinterp"] interp_methods = ["interplevel", "vertcross", "interpline", "vinterp"]
latlon_tests = ["xy", "ll"] latlon_tests = ["xy", "ll"]
for dir, ref_nc_file, nest in zip(DIRS, REF_NC_FILES, NEST):
try: try:
import netCDF4 import netCDF4
except ImportError: except ImportError:
@ -933,32 +967,32 @@ if __name__ == "__main__":
if var in ignore_vars: if var in ignore_vars:
continue continue
test_func1 = make_test(var, DIR, PATTERN, REF_NC_FILE) test_func1 = make_test(var, dir, PATTERN, ref_nc_file)
test_func2 = make_test(var, DIR, PATTERN, REF_NC_FILE, multi=True) test_func2 = make_test(var, dir, PATTERN, ref_nc_file, multi=True)
setattr(WRFVarsTest, 'test_{0}'.format(var), test_func1) setattr(WRFVarsTest, 'test_{0}_{1}'.format(nest,var), test_func1)
setattr(WRFVarsTest, 'test_multi_{0}'.format(var), test_func2) setattr(WRFVarsTest, 'test_{0}_multi_{1}'.format(nest,var), test_func2)
for method in interp_methods: for method in interp_methods:
test_interp_func1 = make_interp_test(method, DIR, PATTERN, test_interp_func1 = make_interp_test(method, dir, PATTERN,
REF_NC_FILE) ref_nc_file)
test_interp_func2 = make_interp_test(method, DIR, PATTERN, test_interp_func2 = make_interp_test(method, dir, PATTERN,
REF_NC_FILE, multi=True) ref_nc_file, multi=True)
setattr(WRFInterpTest, 'test_{0}'.format(method), setattr(WRFInterpTest, 'test_{0}_{1}'.format(nest,method),
test_interp_func1) test_interp_func1)
setattr(WRFInterpTest, 'test_multi_{0}'.format(method), setattr(WRFInterpTest, 'test_{0}_multi_{1}'.format(nest,method),
test_interp_func2) test_interp_func2)
for testid in latlon_tests: for testid in latlon_tests:
for single in (True, False): for single in (True, False):
for multi in (True, False): for multi in (True, False):
test_ll_func = make_latlon_test(testid, DIR, PATTERN, test_ll_func = make_latlon_test(testid, dir, PATTERN,
REF_NC_FILE, ref_nc_file,
single=single, single=single,
multi=multi, multi=multi,
pynio=False) pynio=False)
multistr = "" if not multi else "_multi" multistr = "" if not multi else "_multi"
singlestr = "_nosingle" if not single else "_single" singlestr = "_nosingle" if not single else "_single"
test_name = "test_{}{}{}".format(testid, singlestr, test_name = "test_{}_{}{}{}".format(nest, testid, singlestr,
multistr) multistr)
setattr(WRFLatLonTest, test_name, test_ll_func) setattr(WRFLatLonTest, test_name, test_ll_func)
@ -971,34 +1005,34 @@ if __name__ == "__main__":
if var in ignore_vars: if var in ignore_vars:
continue continue
test_func1 = make_test(var, DIR, PATTERN, REF_NC_FILE, pynio=True) test_func1 = make_test(var, dir, PATTERN, ref_nc_file, pynio=True)
test_func2 = make_test(var, DIR, PATTERN, REF_NC_FILE, multi=True, test_func2 = make_test(var, dir, PATTERN, ref_nc_file, multi=True,
pynio=True) pynio=True)
setattr(WRFVarsTest, 'test_pynio_{0}'.format(var), test_func1) setattr(WRFVarsTest, 'test_pynio_{0}_{1}'.format(nest,var), test_func1)
setattr(WRFVarsTest, 'test_pynio_multi_{0}'.format(var), setattr(WRFVarsTest, 'test_pynio_{0}_multi_{1}'.format(nest,var),
test_func2) test_func2)
for method in interp_methods: for method in interp_methods:
test_interp_func1 = make_interp_test(method, DIR, PATTERN, test_interp_func1 = make_interp_test(method, dir, PATTERN,
REF_NC_FILE) ref_nc_file)
test_interp_func2 = make_interp_test(method, DIR, PATTERN, test_interp_func2 = make_interp_test(method, dir, PATTERN,
REF_NC_FILE, multi=True) ref_nc_file, multi=True)
setattr(WRFInterpTest, 'test_pynio_{0}'.format(method), setattr(WRFInterpTest, 'test_pynio_{0}_{1}'.format(nest,method),
test_interp_func1) test_interp_func1)
setattr(WRFInterpTest, 'test_pynio_multi_{0}'.format(method), setattr(WRFInterpTest, 'test_pynio_{0}_multi_{1}'.format(nest,method),
test_interp_func2) test_interp_func2)
for testid in latlon_tests: for testid in latlon_tests:
for single in (True, False): for single in (True, False):
for multi in (True, False): for multi in (True, False):
test_ll_func = make_latlon_test(testid, DIR, PATTERN, test_ll_func = make_latlon_test(testid, dir, PATTERN,
REF_NC_FILE, ref_nc_file,
single=single, single=single,
multi=multi, multi=multi,
pynio=False) pynio=False)
multistr = "" if not multi else "_multi" multistr = "" if not multi else "_multi"
singlestr = "_nosingle" if not single else "_single" singlestr = "_nosingle" if not single else "_single"
test_name = "test_pynio_{}{}{}".format(testid, test_name = "test_pynio_{}_{}{}{}".format(nest, testid,
singlestr, singlestr,
multistr) multistr)
setattr(WRFLatLonTest, test_name, test_ll_func) setattr(WRFLatLonTest, test_name, test_ll_func)

Loading…
Cancel
Save