Skip to content

Commit 5b8f9c7

Browse files
committed
Changed common area tracking to new dependency (Polygon3);
old dependency (Shapely) removed. Reason was strange edge case where closed contour had a vertical tail.
1 parent ba49f2e commit 5b8f9c7

File tree

2 files changed

+51
-39
lines changed

2 files changed

+51
-39
lines changed

src/py_eddy_tracker/dataset/grid.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,8 @@ def eddy_identification(self, grid_height, uname, vname, date, step=0.005, shape
424424
raise Exception('Date argument be a datetime object')
425425
# The inf limit must be in pixel and sup limit in surface
426426
if pixel_limit is None:
427-
pixel_limit = (4, 1000)
427+
#pixel_limit = (4, 1000)
428+
pixel_limit = (10, 1018)
428429

429430
# Compute an interpolator for eke
430431
self.init_speed_coef(uname, vname)

src/py_eddy_tracker/observations.py

Lines changed: 49 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,23 @@
3232
interp, floor
3333
from netCDF4 import Dataset
3434
from .generic import distance_grid, distance
35-
from shapely.geometry import Polygon
36-
from shapely.geos import TopologicalError
3735
from . import VAR_DESCR, VAR_DESCR_inv
3836
import logging
3937
from datetime import datetime
4038
from numba import njit, types as numba_types
39+
from Polygon import Polygon as Polygon
40+
41+
42+
@njit(cache=True, fastmath=True)
43+
def custom_concat(x, y):
44+
'''
45+
'''
46+
nb = x.shape[0]
47+
a = empty((nb,2))
48+
for i in range(nb):
49+
a[i,0] = x[i]
50+
a[i,1] = y[i]
51+
return a
4152

4253

4354
class EddiesObservations(object):
@@ -342,59 +353,59 @@ def propagate(previous_obs, current_obs, obs_to_extend, dead_track, nb_next, mod
342353
next_obs['segment_size'][:] += 1
343354
return next_obs
344355

356+
357+
358+
359+
345360
@staticmethod
346-
def cost_function_common_area(records_in, records_out, distance, intern=False):
347-
"""
348-
How it's work on x bound ?
361+
def cost_function_common_area(xy_in, xy_out, distance, intern=False):
362+
""" How does it work on x bound ?
349363
Args:
350-
records_in:
351-
records_out:
364+
xy_in:
365+
xy_out:
352366
distance:
353367
intern:
354-
355368
Returns:
356369
357370
"""
358-
x_name, y_name = ('contour_lon_s', 'contour_lat_s') if intern else ('contour_lon_e', 'contour_lat_e')
371+
x_name, y_name = (('contour_lon_s', 'contour_lat_s') if intern
372+
else ('contour_lon_e', 'contour_lat_e'))
359373
r_name = 'radius_s' if intern else 'radius_e'
360-
nb_records = records_in.shape[0]
361-
costs = ma.empty(nb_records,dtype='f4')
362-
tolerance = 0.025
363-
x_in, y_in = records_in[x_name], records_in[y_name]
364-
x_out, y_out = records_out[x_name], records_out[y_name]
374+
nb_records = xy_in.shape[0]
375+
x_in, y_in = xy_in[x_name], xy_in[y_name]
376+
x_out, y_out = xy_out[x_name], xy_out[y_name]
365377
x_in_min, y_in_min = x_in.min(axis=1), y_in.min(axis=1)
366378
x_in_max, y_in_max = x_in.max(axis=1), y_in.max(axis=1)
367379
x_out_min, y_out_min = x_out.min(axis=1), y_out.min(axis=1)
368380
x_out_max, y_out_max = x_out.max(axis=1), y_out.max(axis=1)
369-
for i_record in range(nb_records):
370-
if x_in_max[i_record] < x_out_min[i_record] or x_in_min[i_record] > x_out_max[i_record]:
371-
costs[i_record] = 1
381+
costs = ma.empty(nb_records, dtype='f4')
382+
383+
for i in range(nb_records):
384+
if (x_in_max[i] < x_out_min[i] or
385+
x_in_min[i] > x_out_max[i]):
386+
costs[i] = 1
372387
continue
373-
if y_in_max[i_record] < y_out_min[i_record] or y_in_min[i_record] > y_out_max[i_record]:
374-
costs[i_record] = 1
388+
if (y_in_max[i] < y_out_min[i] or
389+
y_in_min[i] > y_out_max[i]):
390+
costs[i] = 1
375391
continue
376-
poly_in = Polygon(concatenate(((x_in[i_record],), (y_in[i_record],))).T)
377-
poly_out = Polygon(concatenate(((x_out[i_record],),(y_out[i_record],))).T)
378-
if not poly_in.is_valid:
379-
poly_in = poly_in.simplify(tolerance=tolerance)
380-
if not poly_in.is_valid:
381-
logging.warning('Need to simplify polygon in for a second time')
382-
poly_in = poly_in.buffer(0)
383-
if not poly_out.is_valid:
384-
poly_out = poly_out.simplify(tolerance=tolerance)
385-
if not poly_out.is_valid:
386-
logging.warning('Need to simplify polygon out for a second time')
387-
poly_out = poly_out.buffer(0)
388-
try:
389-
costs[i_record] = 1 - poly_in.intersection(poly_out).area / poly_in.area
390-
except TopologicalError:
391-
costs[i_record] = 1
392+
393+
x_in_, x_out_ = x_in[i], x_out[i]
394+
p_in = Polygon(custom_concat(x_in_, y_in[i]))
395+
if abs(x_in_[0] - x_out_[0]) > 180:
396+
x_out_ = (x_out[i] - (x_in_[0] - 180)) % 360 + x_in_[0] - 180
397+
p_out = Polygon(custom_concat(x_out_, y_out[i]))
398+
costs[i] = 1 - (p_in & p_out).area() / min(p_in.area(), p_out.area())
392399
costs.mask = costs == 1
393400
return costs
394401

402+
403+
404+
395405
def mask_function(self, other, distance):
396406
return distance < 125
397407

408+
398409
@staticmethod
399410
def cost_function(records_in, records_out, distance):
400411
cost = ((records_in['amplitude'] - records_out['amplitude']
@@ -577,13 +588,13 @@ def solve_first(cost, multiple_link=False):
577588
if hasattr(cost_reduce[i,j], 'mask'):
578589
continue
579590
links_resolve += 1
580-
# Set to False all link
591+
# Set all links to False
581592
mask[i_self_keep[i]] = False
582593
cost_reduce.mask[i] = True
583594
if not multiple_link:
584595
mask[:, i_other_keep[j]] = False
585596
cost_reduce.mask[:, j] = True
586-
# we active only this link
597+
# We activate this link only
587598
mask[i_self_keep[i], i_other_keep[j]] = True
588599

589600
logging.debug('%d links resolve', links_resolve)
@@ -747,7 +758,7 @@ def shifted_ellipsoid_degrees_mask(lon0, lat0, lon1, lat1, minor=1.5, major=1.5)
747758
# Focal
748759
f_right = lon0
749760
f_left = f_right - (c - minor)
750-
# Ellips center
761+
# Ellipse center
751762
x_c = (f_left + f_right) * .5
752763

753764
nb_0, nb_1 = lat0.shape[0], lat1.shape[0]

0 commit comments

Comments
 (0)