Skip to content

Commit bafeb50

Browse files
committed
increase performance to get pixel in contour
1 parent 8913b5f commit bafeb50

File tree

3 files changed

+50
-28
lines changed

3 files changed

+50
-28
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
*.eclipse.*
88
*.idea*
99
*.project*
10-
10+
*__pycache__*

src/py_eddy_tracker/dataset/grid.py

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from ..eddy_feature import Amplitude, Contours
2323
from .. import VAR_DESCR
2424
from ..generic import distance, interp2d_geo, fit_circle, uniform_resample
25-
from ..poly import poly_contain_poly, winding_number_grid_in_poly
25+
from ..poly import poly_contain_poly, winding_number_grid_in_poly, winding_number_poly
2626

2727
logger = logging.getLogger("pet")
2828

@@ -117,6 +117,33 @@ def _fit_circle_path(vertice):
117117
return centlon_e, centlat_e, eddy_radius_e, aerr
118118

119119

120+
@njit(cache=True, fastmath=True)
121+
def _get_pixel_in_regular(vertices, x_c, y_c, x_start, x_stop, y_start, y_stop):
122+
if x_stop < x_start:
123+
x_ref = vertices[0, 0]
124+
x_array = (concatenate((x_c[x_start:], x_c[:x_stop])) - x_ref + 180) % 360 + x_ref - 180
125+
return winding_number_grid_in_poly(x_array, y_c[y_start:y_stop], x_start, x_stop, x_c.shape[0], y_start,
126+
vertices)
127+
else:
128+
return winding_number_grid_in_poly(x_c[x_start:x_stop], y_c[y_start:y_stop], x_start, x_stop, x_c.shape[0],
129+
y_start, vertices)
130+
131+
132+
@njit(cache=True, fastmath=True)
133+
def _get_pixel_in_unregular(vertices, x_c, y_c, x_start, x_stop, y_start, y_stop):
134+
nb_x, nb_y = x_stop - x_start, y_stop -y_start
135+
wn = empty((nb_x, nb_y), dtype=numba_types.bool_)
136+
for i in range(nb_x):
137+
for j in range(nb_y):
138+
x_pt = x_c[i + x_start, j + y_start]
139+
y_pt = y_c[i + x_start, j + y_start]
140+
wn[i, j] = winding_number_poly(x_pt, y_pt, vertices)
141+
i_x, i_y = where(wn)
142+
i_x += x_start
143+
i_y += y_start
144+
return i_x, i_y
145+
146+
120147
@njit(cache=True, fastmath=True)
121148
def coordinates_to_local(lon, lat, lon0, lat0):
122149
D2R = pi / 180.
@@ -216,6 +243,7 @@ class GridDataset(object):
216243
GRAVITY = 9.807
217244
EARTH_RADIUS = 6370997.
218245
# EARTH_RADIUS = 6378136.3
246+
# indice margin (if put to 0, raise warning that i don't understand)
219247
N = 1
220248

221249
def __init__(self, filename, x_name, y_name, centered=None, indexs=None):
@@ -235,7 +263,7 @@ def __init__(self, filename, x_name, y_name, centered=None, indexs=None):
235263
self.filename = filename
236264
self.coordinates = x_name, y_name
237265
self.vars = dict()
238-
self.indexs = None if indexs is None else indexs
266+
self.indexs = dict() if indexs is None else indexs
239267
self.interpolators = dict()
240268
if centered is None:
241269
logger.warning('We assume the position of grid is the center'
@@ -793,18 +821,12 @@ def bbox_indice(self, vertices):
793821
dist, idx = self.index_interp.query(vertices, k=1)
794822
i_y = idx % self.x_c.shape[1]
795823
i_x = int_((idx - i_y) / self.x_c.shape[1])
796-
return (i_x.min() - self.N, i_x.max() + self.N + 1), (i_y.min() - self.N, i_y.max() + self.N + 1)
824+
return (max(i_x.min() - self.N, 0), i_x.max() + self.N + 1), \
825+
(max(i_y.min() - self.N, 0), i_y.max() + self.N + 1)
797826

798827
def get_pixels_in(self, contour):
799828
(x_start, x_stop), (y_start, y_stop) = contour.bbox_slice
800-
pts = array((self.x_c[x_start:x_stop, y_start:y_stop].reshape(-1),
801-
self.y_c[x_start:x_stop, y_start:y_stop].reshape(-1))).T
802-
x_stop = min(x_stop, self.x_c.shape[0])
803-
mask = contour.contains_points(pts).reshape((x_stop - x_start, -1))
804-
i_x, i_y = where(mask)
805-
i_x += x_start
806-
i_y += y_start
807-
return i_x, i_y
829+
return _get_pixel_in_unregular(contour.vertices, self.x_c, self.y_c, x_start, x_stop, y_start, y_stop)
808830

809831
def normalize_x_indice(self, indices):
810832
"""Not do"""
@@ -903,25 +925,18 @@ def init_pos_interpolator(self):
903925
self.yinterp = arange(self.y_bounds.shape[0])
904926

905927
def bbox_indice(self, vertices):
906-
return bbox_indice_regular(vertices, self.x_bounds[0], self.y_bounds[0], self.xstep, self.ystep,
928+
return bbox_indice_regular(vertices, self.x_bounds, self.y_bounds, self.xstep, self.ystep,
907929
self.N, self.is_circular(), self.x_size)
908930

909931
def get_pixels_in(self, contour):
910932
(x_start, x_stop), (y_start, y_stop) = contour.bbox_slice
911-
if x_stop < x_start:
912-
x_ref = contour.vertices[0, 0]
913-
x_array = (concatenate((self.x_c[x_start:], self.x_c[:x_stop])) - x_ref + 180) % 360 + x_ref - 180
914-
else:
915-
x_array = self.x_c[x_start:x_stop]
916-
return winding_number_grid_in_poly(x_array, self.y_c[y_start:y_stop], x_start, x_stop, self.x_size, y_start,
917-
contour.vertices)
933+
return _get_pixel_in_regular(contour.vertices, self.x_c, self.y_c, x_start, x_stop, y_start, y_stop)
918934

919935
def normalize_x_indice(self, indices):
920936
return indices % self.x_size
921937

922938
def nearest_grd_indice(self, x, y):
923-
return int32(round_(((x - self.x_bounds[0]) % 360) / self.xstep)), \
924-
int32(round_((y - self.y_bounds[0]) / self.ystep))
939+
return _nearest_grd_indice(x,y, self.x_bounds, self.y_bounds, self.xstep, self.ystep)
925940

926941
@property
927942
def xstep(self):
@@ -1066,7 +1081,7 @@ def convolve_filter_with_dynamic_kernel(self, grid, kernel_func, lat_max=85, ext
10661081
t0 = datetime.now()
10671082
if debug_active and len(dt) > 0:
10681083
dt_mean = np_mean(dt) * (nb_lines - i)
1069-
print('Remain ', dt_mean, 'ETA ', t0 + dt_mean, 'current kernel size :', k_shape, 'Step : %d/%d' % (i, nb_lines), end="\r")
1084+
print('Remain ', dt_mean, 'ETA ', t0 + dt_mean, 'current kernel size :', k_shape, 'Step : %d/%d ' % (i, nb_lines), end="\r")
10701085

10711086

10721087
# Half size, k_shape must be always impair
@@ -1452,11 +1467,16 @@ def bbox_indice_regular(vertices, x0, y0, xstep, ystep, N, circular, x_size):
14521467
lon, lat = vertices[:, 0], vertices[:, 1]
14531468
lon_min, lon_max = lon.min(), lon.max()
14541469
lat_min, lat_max = lat.min(), lat.max()
1455-
i_x0, i_y0 = int32(((lon_min - x0) % 360) // xstep), int32((lat_min - y0) // ystep)
1456-
i_x1, i_y1 = int32(((lon_max - x0) % 360) // xstep), int32((lat_max - y0) // ystep)
1470+
i_x0, i_y0 = _nearest_grd_indice(lon_min, lat_min, x0, y0, xstep, ystep)
1471+
i_x1, i_y1 = _nearest_grd_indice(lon_max, lat_max, x0, y0, xstep, ystep)
14571472
if circular:
14581473
slice_x = (i_x0 - N) % x_size, (i_x1 + N + 1) % x_size
14591474
else:
1460-
slice_x = min(i_x0 - N, 0), i_x1 + N + 1
1475+
slice_x = max(i_x0 - N, 0), i_x1 + N + 1
14611476
slice_y = i_y0 - N, i_y1 + N + 1
14621477
return slice_x, slice_y
1478+
1479+
1480+
@njit(cache=True, fastmath=True)
1481+
def _nearest_grd_indice(x, y, x0, y0, xstep, ystep):
1482+
return numba_types.int32(round(((x - x0[0]) % 360.) / xstep)), numba_types.int32(round((y - y0[0]) / ystep))

src/py_eddy_tracker/eddy_feature.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class Amplitude(object):
4545
'h_0',
4646
'grid_extract',
4747
'pixel_mask',
48+
'nb_pixel',
4849
'sla',
4950
'contour',
5051
'interval_min',
@@ -77,6 +78,7 @@ def __init__(self, contour, contour_height, data, interval):
7778
i_x %= data.shape[0]
7879

7980
self.pixel_mask[i_x, contour.pixels_index[1] - y_start] = True
81+
self.nb_pixel = i_x.shape[0]
8082

8183
# Only pixel in contour
8284
self.sla = data[contour.pixels_index]
@@ -106,7 +108,7 @@ def all_pixels_below_h0(self, level):
106108
# After we use grid.data because index are in contour and we check before than no pixel are hide
107109
nb = len(lmi_i)
108110
if nb == 0:
109-
logger.warning('No extrema found in contour in level %f', level)
111+
logger.warning('No extrema found in contour of %d pixels in level %f', self.nb_pixel,level)
110112
return False
111113
elif nb == 1:
112114
i, j = lmi_i[0], lmi_j[0]
@@ -137,7 +139,7 @@ def all_pixels_above_h0(self, level):
137139
self.mle, -1)
138140
nb = len(lmi_i)
139141
if nb == 0:
140-
logger.warning('No extrema found in contour in level %f', level)
142+
logger.warning('No extrema found in contour of %d pixels in level %f', self.nb_pixel,level)
141143
return False
142144
elif nb == 1:
143145
i, j = lmi_i[0], lmi_j[0]

0 commit comments

Comments
 (0)