Browse Source

Merge tag '1.1.0' into develop

Version 1.1.0

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

5
fortran/wrf_user.f90

@ -386,8 +386,9 @@ SUBROUTINE DCOMPUTESEAPRS(nx, ny, nz, z, t, p, q, sea_level_pressure, &
! Get temperature PCONST Pa above surface. Use this to extrapolate ! Get temperature PCONST Pa above surface. Use this to extrapolate
! the temperature at the surface and down to sea level. ! the temperature at the surface and down to sea level.
!$OMP PARALLEL DO COLLAPSE(2) PRIVATE(i,j,klo,khi) REDUCTION(+:errcnt) & !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(i,j,klo,khi,plo, &
!$OMP SCHEDULE(runtime) !$OMP phi,tlo,thi,zlo,zhi,p_at_pconst,t_at_pconst,z_at_pconst) &
!$OMP REDUCTION(+:errcnt) SCHEDULE(runtime)
DO j = 1,ny DO j = 1,ny
DO i = 1,nx DO i = 1,nx

4
src/wrf/extension.py

@ -28,7 +28,7 @@ from wrf._wrffortran import (dcomputetk, dinterp3dz, dinterp2dxy, dinterp1d,
fomp_set_lock, fomp_set_nest_lock, fomp_set_lock, fomp_set_nest_lock,
fomp_unset_lock, fomp_unset_nest_lock, fomp_unset_lock, fomp_unset_nest_lock,
fomp_test_lock, fomp_test_nest_lock, fomp_test_lock, fomp_test_nest_lock,
fomp_get_wtime, fomp_get_wtick) fomp_get_wtime, fomp_get_wtick, fomp_enabled)
from .decorators import (left_iteration, cast_type, from .decorators import (left_iteration, cast_type,
extract_and_transpose, check_args) extract_and_transpose, check_args)
@ -946,7 +946,7 @@ def omp_set_num_threads(num_threads):
None. None.
""" """
if num_threads < 0: if num_threads < 0 and fomp_enabled():
raise ValueError("'num_threads' must be a positive integer.") raise ValueError("'num_threads' must be a positive integer.")
fomp_set_num_threads(num_threads) fomp_set_num_threads(num_threads)

10
test/comp_utest.py

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

21
test/test_omp.py

@ -19,8 +19,9 @@ from wrf import (omp_set_num_threads, omp_get_num_threads,
omp_set_lock, omp_set_nest_lock, omp_set_lock, omp_set_nest_lock,
omp_unset_lock, omp_unset_nest_lock, omp_unset_lock, omp_unset_nest_lock,
omp_test_lock, omp_test_nest_lock, omp_test_lock, omp_test_nest_lock,
omp_get_wtime, omp_get_wtick) omp_get_wtime, omp_get_wtick,
from wrf import Constants OMP_SCHED_STATIC, OMP_SCHED_DYNAMIC,
OMP_SCHED_GUIDED, OMP_SCHED_AUTO)
class OmpTest(ut.TestCase): class OmpTest(ut.TestCase):
@ -77,24 +78,24 @@ class OmpTest(ut.TestCase):
def test_schedule(self): def test_schedule(self):
omp_set_schedule(Constants.OMP_SCHED_STATIC, 100000) omp_set_schedule(OMP_SCHED_STATIC, 100000)
kind, modifier = omp_get_schedule() kind, modifier = omp_get_schedule()
self.assertEqual(kind, Constants.OMP_SCHED_STATIC) self.assertEqual(kind, OMP_SCHED_STATIC)
self.assertEqual(modifier, 100000) self.assertEqual(modifier, 100000)
omp_set_schedule(Constants.OMP_SCHED_DYNAMIC, 10000) omp_set_schedule(OMP_SCHED_DYNAMIC, 10000)
kind, modifier = omp_get_schedule() kind, modifier = omp_get_schedule()
self.assertEqual(kind, Constants.OMP_SCHED_DYNAMIC) self.assertEqual(kind, OMP_SCHED_DYNAMIC)
self.assertEqual(modifier, 10000) self.assertEqual(modifier, 10000)
omp_set_schedule(Constants.OMP_SCHED_GUIDED, 100) omp_set_schedule(OMP_SCHED_GUIDED, 100)
kind, modifier = omp_get_schedule() kind, modifier = omp_get_schedule()
self.assertEqual(kind, Constants.OMP_SCHED_GUIDED) self.assertEqual(kind, OMP_SCHED_GUIDED)
self.assertEqual(modifier, 100) self.assertEqual(modifier, 100)
omp_set_schedule(Constants.OMP_SCHED_AUTO, 10) omp_set_schedule(OMP_SCHED_AUTO, 10)
kind, modifier = omp_get_schedule() kind, modifier = omp_get_schedule()
self.assertEqual(kind, Constants.OMP_SCHED_AUTO) self.assertEqual(kind, OMP_SCHED_AUTO)
self.assertNotEqual(modifier, 10) # The modifier argument is ignored, self.assertNotEqual(modifier, 10) # The modifier argument is ignored,
# so it will be set to the previous # so it will be set to the previous
# value of 100. # value of 100.

12
test/utests.py

@ -300,8 +300,10 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
lats = hts.coords["XLAT"] lats = hts.coords["XLAT"]
lons = hts.coords["XLONG"] lons = hts.coords["XLONG"]
ll_point = ll_points(lats, lons) ll_point = ll_points(lats, lons)
pivot = CoordPair(lat=lats[lats.shape[-2]/2, lats.shape[-1]/2], pivot = CoordPair(lat=lats[int(lats.shape[-2]/2),
lon=lons[lons.shape[-2]/2, lons.shape[-1]/2]) int(lats.shape[-1]/2)],
lon=lons[int(lons.shape[-2]/2),
int(lons.shape[-1]/2)])
v1 = vertcross(hts,p,wrfin=in_wrfnc,pivot_point=pivot_point, v1 = vertcross(hts,p,wrfin=in_wrfnc,pivot_point=pivot_point,
angle=90.0) angle=90.0)
v2 = vertcross(hts,p,projection=hts.attrs["projection"], v2 = vertcross(hts,p,projection=hts.attrs["projection"],
@ -348,8 +350,10 @@ def make_interp_test(varname, wrf_in, referent, multi=False,
lats = t2.coords["XLAT"] lats = t2.coords["XLAT"]
lons = t2.coords["XLONG"] lons = t2.coords["XLONG"]
ll_point = ll_points(lats, lons) ll_point = ll_points(lats, lons)
pivot = CoordPair(lat=lats[lats.shape[-2]/2, lats.shape[-1]/2], pivot = CoordPair(lat=lats[int(lats.shape[-2]/2),
lon=lons[lons.shape[-2]/2, lons.shape[-1]/2]) int(lats.shape[-1]/2)],
lon=lons[int(lons.shape[-2]/2),
int(lons.shape[-1]/2)])
l1 = interpline(t2,wrfin=in_wrfnc,pivot_point=pivot_point, l1 = interpline(t2,wrfin=in_wrfnc,pivot_point=pivot_point,
angle=90.0) angle=90.0)
l2 = interpline(t2,projection=t2.attrs["projection"], l2 = interpline(t2,projection=t2.attrs["projection"],

Loading…
Cancel
Save