29
29
30
30
"""
31
31
from numpy import zeros , empty , nan , arange , interp , where , unique , \
32
- ma
32
+ ma , concatenate
33
33
from netCDF4 import Dataset
34
34
from py_eddy_tracker .tools import distance_matrix
35
+ from shapely .geometry import Polygon
36
+ from shapely .geos import TopologicalError
35
37
from . import VAR_DESCR , VAR_DESCR_inv
36
38
import logging
37
39
@@ -66,6 +68,16 @@ class EddiesObservations(object):
66
68
rtime:
67
69
Time
68
70
"""
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'
69
81
70
82
def __init__ (self , size = 0 , track_extra_variables = None ,
71
83
track_array_variables = 0 , array_variables = None ):
@@ -108,15 +120,7 @@ def dtype(self):
108
120
def elements (self ):
109
121
"""Return all variable name
110
122
"""
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 ]
120
124
if self .track_array_variables > 0 :
121
125
elements += self .array_variables
122
126
@@ -226,6 +230,13 @@ def load_from_netcdf(filename):
226
230
for variable in h_nc .variables :
227
231
if array_dim in h_nc .variables [variable ].dimensions :
228
232
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 )
229
240
230
241
eddies = EddiesObservations (size = nb_obs , ** kwargs )
231
242
for variable in h_nc .variables :
@@ -236,35 +247,62 @@ def load_from_netcdf(filename):
236
247
eddies .sign_type = h_nc .variables ['cyc' ][0 ]
237
248
return eddies
238
249
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 ):
240
274
cost = ((records_in ['amplitude' ] - records_out ['amplitude' ]
241
275
) / records_in ['amplitude' ]
242
276
) ** 2
243
277
cost += ((records_in ['radius_s' ] - records_out ['radius_s' ]
244
278
) / records_in ['radius_s' ]
245
279
) ** 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 )
247
284
248
285
def tracking (self , other ):
249
286
"""Track obs between self and other
250
287
"""
251
288
dist = self .distance (other )
252
289
# Links available which are close (circle area selection)
253
- mask_accept_dist = dist < 100
290
+ mask_accept_dist = dist < 125
254
291
indexs_closest = where (mask_accept_dist )
255
- cost_values = self .cost_function (
292
+ cost_values = self .cost_function2 (
256
293
self .obs [indexs_closest [0 ]],
257
- other .obs [indexs_closest [1 ]])
294
+ other .obs [indexs_closest [1 ]],
295
+ dist [mask_accept_dist ])
258
296
259
297
cost_mat = ma .empty (dist .shape , dtype = 'f4' )
260
298
cost_mat .mask = - mask_accept_dist
261
299
cost_mat [mask_accept_dist ] = cost_values
262
300
# 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')
266
304
267
- mask_accept_cost = mask_accept_dist
305
+ mask_accept_cost = - cost_mat . mask
268
306
cost = cost_mat
269
307
# Count number of link by self obs and other obs
270
308
self_links = mask_accept_cost .sum (axis = 1 )
@@ -297,7 +335,13 @@ def tracking(self, other):
297
335
matrix_size )
298
336
299
337
links_resolve = 0
338
+ # Arbitrary value
339
+ max_iteration = max (cost_reduce .shape )
340
+ security_increment = 0
300
341
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
301
345
i_min_value = cost_reduce .argmin ()
302
346
i , j = i_min_value / shape [1 ], i_min_value % shape [1 ]
303
347
# Set to False all link
@@ -361,6 +405,7 @@ def extract_longer_eddies(self, nb_min, nb_obs, compress_id=True):
361
405
logging .info ('Selection of %d observations' , nb_obs_select )
362
406
eddies = TrackEddiesObservations (
363
407
size = nb_obs_select ,
408
+ track_extra_variables = self .track_extra_variables ,
364
409
track_array_variables = self .track_array_variables ,
365
410
array_variables = self .array_variables
366
411
)
0 commit comments