Skip to content

Commit 6f1c5a4

Browse files
authored
Merge pull request #234 from jswhit/speedup_redtoreg
more redtoreg optimizations
2 parents d8437c6 + 334a288 commit 6f1c5a4

File tree

2 files changed

+41
-42
lines changed

2 files changed

+41
-42
lines changed

src/pygrib/_pygrib.pyx

+40-41
Original file line numberDiff line numberDiff line change
@@ -15,62 +15,61 @@ from numpy import ma
1515
import pyproj
1616
npc.import_array()
1717

18-
ctypedef fused my_type:
18+
ctypedef fused float_type:
1919
float
2020
double
2121

22-
def _redtoreg(cython.Py_ssize_t nlons, my_type[:] redgrid_data, long[:] lonsperlat, my_type missval):
22+
def redtoreg(float_type[:] redgrid_data, long[:] lonsperlat, missval=None):
23+
"""
24+
redtoreg(redgrid_data, lonsperlat, missval=None)
25+
26+
Takes 1-d array on ECMWF reduced gaussian grid (redgrid_data), linearly interpolates
27+
to corresponding regular gaussian grid.
28+
29+
Reduced gaussian grid defined by lonsperlat array, regular gaussian
30+
grid has the same number of latitudes and max(lonsperlat) longitudes.
31+
32+
Includes handling of missing values using nearest neighbor interpolation.
33+
"""
34+
35+
cdef cython.Py_ssize_t nlons = np.max(lonsperlat)
2336
cdef cython.Py_ssize_t nlats = lonsperlat.shape[0]
24-
cdef cython.Py_ssize_t i,j,n,indx,ilons,im,ip
25-
cdef my_type zxi, zdx, flons
26-
if my_type is float:
27-
dtype = np.float32
28-
elif my_type is double:
29-
dtype = np.double
30-
reggrid_data = np.full((nlats,nlons), missval, dtype)
31-
cdef my_type[:, ::1] reggrid_data_view = reggrid_data
37+
cdef cython.Py_ssize_t i,j,indx,ilons,im,ip,nlona
38+
cdef float_type zxi, zdx, flons, missvalc
39+
if float_type is float:
40+
float_dtype = np.float32
41+
elif float_type is double:
42+
float_dtype = np.double
43+
if missval is None:
44+
missval = np.nan
45+
missvalc = missval
46+
reggrid_data = np.full((nlats, nlons), missval, float_dtype)
47+
cdef float_type[:, ::1] reggrid_data_view = reggrid_data
3248
indx = 0
3349
for j in range(nlats):
34-
ilons = lonsperlat[j]
35-
flons = <my_type>ilons
36-
for i in range(nlons):
37-
# zxi is the grid index (relative to the reduced grid)
38-
# of the i'th point on the full grid.
39-
zxi = i * flons / nlons # goes from 0 to ilons
40-
im = <long>zxi
41-
zdx = zxi - <my_type>im
42-
if ilons != 0:
50+
ilons = lonsperlat[j]; flons = ilons
51+
if ilons != 0:
52+
for i in range(nlons):
53+
# zxi is the grid index (relative to the reduced grid)
54+
# of the i'th point on the full grid.
55+
zxi = i * flons / nlons # goes from 0 to ilons
56+
im = <cython.Py_ssize_t>zxi; zdx = zxi - im
4357
im = (im + ilons)%ilons
4458
ip = (im + 1 + ilons)%ilons
4559
# if one of the nearest values is missing, use nearest
4660
# neighbor interpolation.
47-
if redgrid_data[indx+im] == missval or\
48-
redgrid_data[indx+ip] == missval:
61+
if redgrid_data[indx+im] == missvalc or\
62+
redgrid_data[indx+ip] == missvalc:
4963
if zdx < 0.5:
5064
reggrid_data_view[j,i] = redgrid_data[indx+im]
5165
else:
5266
reggrid_data_view[j,i] = redgrid_data[indx+ip]
5367
else: # linear interpolation.
5468
reggrid_data_view[j,i] = redgrid_data[indx+im]*(1.-zdx) +\
5569
redgrid_data[indx+ip]*zdx
56-
indx = indx + ilons
70+
indx = indx + ilons
5771
return reggrid_data
5872

59-
def redtoreg(redgrid_data, lonsperlat, missval=None):
60-
"""
61-
redtoreg(redgrid_data, lonsperlat, missval=None)
62-
63-
Takes 1-d array on ECMWF reduced gaussian grid (``redgrid_data``), linearly interpolates to corresponding
64-
regular gaussian grid (given by ``lonsperlat`` array, with max(lonsperlat) longitudes).
65-
If any values equal to specified missing value (``missval``, default NaN), a masked array is returned."""
66-
67-
if missval is None:
68-
missval = np.nan
69-
datarr = _redtoreg(lonsperlat.max(),redgrid_data,lonsperlat,missval)
70-
if np.count_nonzero(datarr==missval):
71-
datarr = ma.masked_values(datarr, missval)
72-
return datarr
73-
7473
cdef extern from "stdlib.h":
7574
ctypedef long size_t
7675
void *malloc(size_t size)
@@ -1314,8 +1313,8 @@ cdef class gribmessage(object):
13141313
else:
13151314
missval = 1.e30
13161315
if self.expand_reduced:
1317-
nx = 2*ny
1318-
datarr = _redtoreg(2*ny, datarr, self['pl'], missval)
1316+
nx = self['pl'].max()
1317+
datarr = redtoreg(datarr, self['pl'], missval=missval)
13191318
else:
13201319
nx = None
13211320
elif self.has_key('Nx') and self.has_key('Ny'):
@@ -1550,7 +1549,7 @@ cdef class gribmessage(object):
15501549
lats = self['distinctLatitudes']
15511550
if lat2 < lat1 and lats[-1] > lats[0]: lats = lats[::-1]
15521551
ny = self['Nj']
1553-
nx = 2*ny
1552+
nx = self['pl'].max()
15541553
lon1 = self['longitudeOfFirstGridPointInDegrees']
15551554
lon2 = self['longitudeOfLastGridPointInDegrees']
15561555
lons = np.linspace(lon1,lon2,nx)
@@ -1561,7 +1560,7 @@ cdef class gribmessage(object):
15611560
elif self['gridType'] == 'reduced_ll': # reduced lat/lon grid
15621561
if self.expand_reduced:
15631562
ny = self['Nj']
1564-
nx = 2*ny
1563+
nx = self['pl'].max()
15651564
lat1 = self['latitudeOfFirstGridPointInDegrees']
15661565
lat2 = self['latitudeOfLastGridPointInDegrees']
15671566
lon1 = self['longitudeOfFirstGridPointInDegrees']

test/test_latlons.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def test_latlons_corners(samplegribfile, expected):
9494
("flux.grb", [47, 64], [120.0, -0.952367]),
9595
("ecmwf_tigge.grb", [200, 266], [119.7, -0.224718]),
9696
("dspr.temp.bin", [112, 113], [-66.676034, 18.2714926]),
97-
("reduced_latlon_surface.grib2", [250, 334], [119.99976, 0.0])
97+
("reduced_latlon_surface.grib2", [250, 334], [120.24, 0.0])
9898
])
9999
def test_latlons_randpoint(samplegribfile, pt_ji, expected):
100100
"""Test the resulting grid data."""

0 commit comments

Comments
 (0)