Skip to content

Commit d28a12e

Browse files
committed
amplitude will not use pixel outside of contour
1 parent ee3b2df commit d28a12e

File tree

3 files changed

+50
-24
lines changed

3 files changed

+50
-24
lines changed

src/py_eddy_tracker/dataset/grid.py

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ class GridDataset(object):
194194
'vars',
195195
'interpolators',
196196
'speed_coef',
197+
'contours',
197198
)
198199

199200
GRAVITY = 9.807
@@ -211,6 +212,7 @@ def __init__(self, filename, x_name, y_name, centered=None):
211212
self.x_dim = None
212213
self.y_dim = None
213214
self.centered = centered
215+
self.contours = None
214216
self.xinterp = None
215217
self.yinterp = None
216218
self.filename = filename
@@ -413,16 +415,18 @@ def eddy_identification(self, grid_height, uname, vname, date, step=0.005, shape
413415
x, y = self.x_c, self.y_c
414416

415417
# Compute ssh contour
416-
contours = Contours(x, y, data, levels, bbox_surface_min_degree=bbox_surface_min_degree, wrap_x=self.is_circular())
418+
self.contours = Contours(x, y, data, levels, bbox_surface_min_degree=bbox_surface_min_degree, wrap_x=self.is_circular())
417419

420+
track_extra_variables = ['height_max_speed_contour', 'height_external_contour', 'height_inner_contour']
421+
array_variables = ['contour_lon_e', 'contour_lat_e', 'contour_lon_s', 'contour_lat_s', 'uavg_profile']
418422
# Compute cyclonic and anticylonic research:
419423
a_and_c = list()
420424
for anticyclonic_search in [True, False]:
421425
eddies = list()
422426
iterator = 1 if anticyclonic_search else -1
423427

424428
# Loop over each collection
425-
for coll_ind, coll in enumerate(contours.iter(step=iterator)):
429+
for coll_ind, coll in enumerate(self.contours.iter(step=iterator)):
426430
corrected_coll_index = coll_ind
427431
if iterator == -1:
428432
corrected_coll_index = - coll_ind - 1
@@ -431,7 +435,7 @@ def eddy_identification(self, grid_height, uname, vname, date, step=0.005, shape
431435
nb_paths = len(contour_paths)
432436
if nb_paths == 0:
433437
continue
434-
cvalues = contours.cvalues[corrected_coll_index]
438+
cvalues = self.contours.cvalues[corrected_coll_index]
435439
logging.debug('doing collection %s, contour value %.4f, %d paths',
436440
corrected_coll_index, cvalues, nb_paths)
437441

@@ -440,6 +444,7 @@ def eddy_identification(self, grid_height, uname, vname, date, step=0.005, shape
440444
if current_contour.used:
441445
continue
442446
centlon_e, centlat_e, eddy_radius_e, aerr = current_contour.fit_circle()
447+
443448
# Filter for shape
444449
if aerr < 0 or aerr > shape_error:
445450
continue
@@ -465,13 +470,14 @@ def eddy_identification(self, grid_height, uname, vname, date, step=0.005, shape
465470
# Compute amplitude
466471
reset_centroid, amp = self.get_amplitude(current_contour, cvalues, data,
467472
anticyclonic_search=anticyclonic_search,
468-
level=contours.levels[corrected_coll_index], step=step)
469-
473+
level=self.contours.levels[corrected_coll_index], step=step)
474+
print(reset_centroid, amp.amplitude)
470475
# If we have a valid amplitude
471476
if (not amp.within_amplitude_limits()) or (amp.amplitude == 0):
472477
continue
473478

474479
if reset_centroid:
480+
475481
if self.is_circular():
476482
centi = self.normalize_x_indice(reset_centroid[0])
477483
else:
@@ -487,7 +493,8 @@ def eddy_identification(self, grid_height, uname, vname, date, step=0.005, shape
487493

488494
# centlat_e and centlon_e must be index of maximum, we will loose some inner contour, if it's not
489495
max_average_speed, speed_contour, inner_contour, speed_array, i_max_speed, i_inner = \
490-
self.get_uavg(contours, centlon_e, centlat_e, current_contour, anticyclonic_search, corrected_coll_index)
496+
self.get_uavg(self.contours, centlon_e, centlat_e, current_contour, anticyclonic_search,
497+
corrected_coll_index)
491498

492499
# Use azimuth equal projection for radius
493500
proj = Proj('+proj=aeqd +ellps=WGS84 +lat_0={1} +lon_0={0}'.format(*inner_contour.mean_coordinates))
@@ -502,16 +509,13 @@ def eddy_identification(self, grid_height, uname, vname, date, step=0.005, shape
502509
_, _, eddy_radius_s, aerr_s = fit_circle_c(c_x, c_y)
503510

504511
# Instantiate new EddyObservation object
505-
properties = EddiesObservations(
506-
size=1,
507-
track_extra_variables=[ 'height_max_speed_contour', 'height_external_contour', 'height_inner_contour'],
508-
track_array_variables=array_sampling,
509-
array_variables=['contour_lon_e', 'contour_lat_e', 'contour_lon_s', 'contour_lat_s', 'uavg_profile']
510-
)
511-
512-
properties.obs['height_max_speed_contour'] = contours.cvalues[i_max_speed]
512+
properties = EddiesObservations(size=1, track_extra_variables=track_extra_variables,
513+
track_array_variables=array_sampling,
514+
array_variables=array_variables)
515+
516+
properties.obs['height_max_speed_contour'] = self.contours.cvalues[i_max_speed]
513517
properties.obs['height_external_contour'] = cvalues
514-
properties.obs['height_inner_contour'] = contours.cvalues[i_inner]
518+
properties.obs['height_inner_contour'] = self.contours.cvalues[i_inner]
515519
array_size = speed_array.shape[0]
516520
properties.obs['nb_contour_selected'] = array_size
517521
if speed_array.shape[0] == 1:
@@ -537,7 +541,9 @@ def eddy_identification(self, grid_height, uname, vname, date, step=0.005, shape
537541
# To reserve definitively the area
538542
data.mask[i_x_in, i_y_in] = True
539543
if len(eddies) == 0:
540-
eddies_collection = EddiesObservations()
544+
eddies_collection = EddiesObservations(track_extra_variables=track_extra_variables,
545+
track_array_variables=array_sampling,
546+
array_variables=array_variables)
541547
else:
542548
eddies_collection = EddiesObservations.concatenate(eddies)
543549
eddies_collection.sign_type = 1 if anticyclonic_search else -1
@@ -1168,6 +1174,11 @@ def init_speed_coef(self, uname='u', vname='v'):
11681174
speed[speed.mask] = 0
11691175
self._speed_ev = RectBivariateSpline(self.x_c, self.y_c, speed, kx=1, ky=1).ev
11701176

1177+
def display(self, ax, name, **kwargs):
1178+
if 'cmap' not in kwargs:
1179+
kwargs['cmap'] = 'coolwarm'
1180+
return ax.pcolormesh(self.x_bounds, self.y_bounds, self.grid(name).T, **kwargs)
1181+
11711182
def interp(self, grid_name, lons, lats):
11721183
"""
11731184
Compute z over lons, lats

src/py_eddy_tracker/eddy_feature.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"""
2828

2929
import logging
30-
from numpy import ones, where, empty, array, concatenate, ma
30+
from numpy import ones, where, empty, array, concatenate, ma, zeros
3131
from scipy.ndimage import minimum_filter
3232
from scipy.ndimage import binary_erosion
3333
from matplotlib.figure import Figure
@@ -43,6 +43,7 @@ class Amplitude(object):
4343
__slots__ = (
4444
'h_0',
4545
'grid_extract',
46+
'mask',
4647
'sla',
4748
'contour',
4849
'interval',
@@ -65,6 +66,8 @@ def __init__(self, contour, contour_height, data, interval):
6566
else:
6667
self.grid_extract = data[slice_x, slice_y]
6768
# => maybe replace pixel out of contour by nan?
69+
self.mask = zeros(self.grid_extract.shape, dtype='bool')
70+
self.mask[contour.pixels_index[0] - slice_x.start, contour.pixels_index[1] - slice_y.start] = True
6871

6972
# Only pixel in contour
7073
self.sla = data[contour.pixels_index]
@@ -83,12 +86,12 @@ def within_amplitude_limits(self):
8386
def _set_cyc_amplitude(self):
8487
"""Get amplitude for cyclone
8588
"""
86-
self.amplitude = self.h_0 - self.grid_extract.min()
89+
self.amplitude = self.h_0 - self.sla.min()
8790

8891
def _set_acyc_amplitude(self):
8992
"""Get amplitude for anticyclone
9093
"""
91-
self.amplitude = self.grid_extract.max() - self.h_0
94+
self.amplitude = self.sla.max() - self.h_0
9295

9396
def all_pixels_below_h0(self, level):
9497
"""
@@ -100,6 +103,8 @@ def all_pixels_below_h0(self, level):
100103
else:
101104
self._set_local_extrema(1)
102105
lmi_i, lmi_j = where(self.local_extrema_inds)
106+
m = self.mask[lmi_i, lmi_j]
107+
lmi_i, lmi_j = lmi_i[m], lmi_j[m]
103108
nb_real_extrema = ((level - self.grid_extract[lmi_i, lmi_j]) >= 2 * self.interval).sum()
104109
if nb_real_extrema > self.mle:
105110
return False
@@ -122,6 +127,8 @@ def all_pixels_above_h0(self, level):
122127
else:
123128
self._set_local_extrema(-1)
124129
lmi_i, lmi_j = where(self.local_extrema_inds)
130+
m = self.mask[lmi_i, lmi_j]
131+
lmi_i, lmi_j = lmi_i[m], lmi_j[m]
125132
nb_real_extrema = ((self.grid_extract[lmi_i, lmi_j] - level) >= 2 * self.interval).sum()
126133
if nb_real_extrema > self.mle:
127134
return False
@@ -277,7 +284,7 @@ def __init__(self, x, y, z, levels, bbox_surface_min_degree, wrap_x=False, keep_
277284
logging.debug('Y shape : %s', y.shape)
278285
logging.debug('Z shape : %s', z.shape)
279286
logging.info('Start computing iso lines with %d levels from %f to %f ...', len(levels), levels[0], levels[-1])
280-
self.contours = ax.contour(x, y, z.T, levels)
287+
self.contours = ax.contour(x, y, z.T, levels, cmap='Spectral_r')
281288
if wrap_x:
282289
self.find_wrapcut_path_and_join(x[0], x[-1])
283290
logging.info('Finish computing iso lines')
@@ -410,8 +417,12 @@ def get_index_nearest_path_bbox_contain_pt(self, level, xpt, ypt):
410417
return self.contours.collections[level]._paths[index]
411418

412419
def display(self, ax, **kwargs):
420+
from matplotlib.collections import LineCollection
413421
for collection in self.contours.collections:
414-
for path in collection.get_paths():
415-
x, y= path.vertices[:, 0], path.vertices[:, 1]
416-
ax.plot(x, y, **kwargs)
417-
422+
ax.add_collection(LineCollection(
423+
(i.vertices for i in collection.get_paths()),
424+
color=collection.get_color(),
425+
**kwargs
426+
))
427+
ax.update_datalim([self.contours._mins, self.contours._maxs])
428+
ax.autoscale_view()

src/py_eddy_tracker/observations.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,10 @@ def write_netcdf(self, path='./', filename='%(path)s/%(sign_type)s.nc'):
843843
def set_global_attr_netcdf(self, h_nc):
844844
pass
845845

846+
def display(self, ax, ref=0, **kwargs):
847+
ax.plot((self.obs['contour_lon_s'].T - ref) % 360 + ref, self.obs['contour_lat_s'].T, ** kwargs)
848+
ax.plot((self.obs['contour_lon_e'].T - ref) % 360 + ref, self.obs['contour_lat_e'].T, linestyle='-.', ** kwargs)
849+
846850

847851
class VirtualEddiesObservations(EddiesObservations):
848852
"""Class to work with virtual obs

0 commit comments

Comments
 (0)