2929
3030"""
3131from numpy import zeros , empty , nan , arange , interp , where , unique , \
32- ma
32+ ma , concatenate
3333from netCDF4 import Dataset
3434from py_eddy_tracker .tools import distance_matrix
35+ from shapely .geometry import Polygon
36+ from shapely .geos import TopologicalError
3537from . import VAR_DESCR , VAR_DESCR_inv
3638import logging
3739
@@ -66,6 +68,16 @@ class EddiesObservations(object):
6668 rtime:
6769 Time
6870 """
71+
72+ ELEMENTS = [
73+ 'lon' , # 'centlon'
74+ 'lat' , # 'centlat'
75+ 'radius_s' , # 'eddy_radius_s'
76+ 'radius_e' , # 'eddy_radius_e'
77+ 'amplitude' , # 'amplitude'
78+ 'speed_radius' , # 'uavg'
79+ 'eke' , # 'teke'
80+ 'time' ] # 'rtime'
6981
7082 def __init__ (self , size = 0 , track_extra_variables = None ,
7183 track_array_variables = 0 , array_variables = None ):
@@ -108,15 +120,7 @@ def dtype(self):
108120 def elements (self ):
109121 """Return all variable name
110122 """
111- elements = [
112- 'lon' , # 'centlon'
113- 'lat' , # 'centlat'
114- 'radius_s' , # 'eddy_radius_s'
115- 'radius_e' , # 'eddy_radius_e'
116- 'amplitude' , # 'amplitude'
117- 'speed_radius' , # 'uavg'
118- 'eke' , # 'teke'
119- 'time' ] # 'rtime'
123+ elements = [i for i in self .ELEMENTS ]
120124 if self .track_array_variables > 0 :
121125 elements += self .array_variables
122126
@@ -226,6 +230,13 @@ def load_from_netcdf(filename):
226230 for variable in h_nc .variables :
227231 if array_dim in h_nc .variables [variable ].dimensions :
228232 kwargs ['array_variables' ].append (str (variable ))
233+ kwargs ['track_extra_variables' ] = []
234+ for variable in h_nc .variables :
235+ if variable == 'cyc' :
236+ continue
237+ var_inv = VAR_DESCR_inv [variable ]
238+ if var_inv not in EddiesObservations .ELEMENTS and var_inv not in kwargs ['array_variables' ]:
239+ kwargs ['track_extra_variables' ].append (var_inv )
229240
230241 eddies = EddiesObservations (size = nb_obs , ** kwargs )
231242 for variable in h_nc .variables :
@@ -236,35 +247,62 @@ def load_from_netcdf(filename):
236247 eddies .sign_type = h_nc .variables ['cyc' ][0 ]
237248 return eddies
238249
239- def cost_function (self , records_in , records_out ):
250+ def cost_function2 (self , records_in , records_out , distance ):
251+ nb_records = records_in .shape [0 ]
252+ costs = ma .empty (nb_records ,dtype = 'f4' )
253+ for i_record in xrange (nb_records ):
254+ poly_in = Polygon (
255+ concatenate ((
256+ (records_in [i_record ]['contour_lon' ],),
257+ (records_in [i_record ]['contour_lat' ],))
258+ ).T
259+ )
260+ poly_out = Polygon (
261+ concatenate ((
262+ (records_out [i_record ]['contour_lon' ],),
263+ (records_out [i_record ]['contour_lat' ],))
264+ ).T
265+ )
266+ try :
267+ costs [i_record ] = 1 - poly_in .intersection (poly_out ).area / poly_in .area
268+ except TopologicalError :
269+ costs [i_record ] = 1
270+ costs .mask = costs == 1
271+ return costs
272+
273+ def cost_function (self , records_in , records_out , distance ):
240274 cost = ((records_in ['amplitude' ] - records_out ['amplitude' ]
241275 ) / records_in ['amplitude' ]
242276 ) ** 2
243277 cost += ((records_in ['radius_s' ] - records_out ['radius_s' ]
244278 ) / records_in ['radius_s' ]
245279 ) ** 2
246- return cost ** 0.5
280+ cost += (distance / 125 ) ** 2
281+ cost **= 0.5
282+ # Mask value superior at 60 % of variation
283+ return ma .array (cost , mask = cost > 0.6 )
247284
248285 def tracking (self , other ):
249286 """Track obs between self and other
250287 """
251288 dist = self .distance (other )
252289 # Links available which are close (circle area selection)
253- mask_accept_dist = dist < 100
290+ mask_accept_dist = dist < 125
254291 indexs_closest = where (mask_accept_dist )
255- cost_values = self .cost_function (
292+ cost_values = self .cost_function2 (
256293 self .obs [indexs_closest [0 ]],
257- other .obs [indexs_closest [1 ]])
294+ other .obs [indexs_closest [1 ]],
295+ dist [mask_accept_dist ])
258296
259297 cost_mat = ma .empty (dist .shape , dtype = 'f4' )
260298 cost_mat .mask = - mask_accept_dist
261299 cost_mat [mask_accept_dist ] = cost_values
262300 # Links available which respect a maximal cost
263- cost = dist
264- mask_accept_cost = cost < 100
265- cost = ma .array (cost , mask = - mask_accept_cost , dtype = 'i2' )
301+ # cost = dist
302+ # mask_accept_cost = cost < 100
303+ # cost = ma.array(cost, mask=-mask_accept_cost, dtype='i2')
266304
267- mask_accept_cost = mask_accept_dist
305+ mask_accept_cost = - cost_mat . mask
268306 cost = cost_mat
269307 # Count number of link by self obs and other obs
270308 self_links = mask_accept_cost .sum (axis = 1 )
@@ -297,7 +335,13 @@ def tracking(self, other):
297335 matrix_size )
298336
299337 links_resolve = 0
338+ # Arbitrary value
339+ max_iteration = max (cost_reduce .shape )
340+ security_increment = 0
300341 while False in cost_reduce .mask :
342+ if security_increment > max_iteration :
343+ raise Exception ('To many iteration: %d' % security_increment )
344+ security_increment += 1
301345 i_min_value = cost_reduce .argmin ()
302346 i , j = i_min_value / shape [1 ], i_min_value % shape [1 ]
303347 # Set to False all link
@@ -361,6 +405,7 @@ def extract_longer_eddies(self, nb_min, nb_obs, compress_id=True):
361405 logging .info ('Selection of %d observations' , nb_obs_select )
362406 eddies = TrackEddiesObservations (
363407 size = nb_obs_select ,
408+ track_extra_variables = self .track_extra_variables ,
364409 track_array_variables = self .track_array_variables ,
365410 array_variables = self .array_variables
366411 )
0 commit comments