Skip to content

Commit 9b5aa7e

Browse files
committed
First working (no output, but effective identification)version for unregular grid
1 parent 6ac157d commit 9b5aa7e

File tree

3 files changed

+226
-154
lines changed

3 files changed

+226
-154
lines changed

src/py_eddy_tracker/dataset/grid.py

Lines changed: 45 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,17 @@
55
from scipy.interpolate import interp1d
66
from numpy import concatenate, int32, empty, maximum, where, array, \
77
sin, deg2rad, pi, ones, cos, ma, int8, histogram2d, arange, float_, \
8-
linspace, meshgrid, sinc, errstate, round_, int_, column_stack, interp
8+
linspace, errstate, round_, int_, column_stack, interp
99
from netCDF4 import Dataset
1010
from scipy.ndimage import gaussian_filter, convolve
11-
from scipy.ndimage.filters import convolve1d
1211
from scipy.interpolate import RectBivariateSpline
1312
from scipy.spatial import cKDTree
14-
from matplotlib.figure import Figure
1513
from matplotlib.path import Path as BasePath
1614
from matplotlib.contour import QuadContourSet as BaseQuadContourSet
1715
from pyproj import Proj
1816
from ..tools import fit_circle_c, distance_vector
1917
from ..observations import EddiesObservations
20-
from ..eddy_feature import Amplitude, get_uavg
18+
from ..eddy_feature import Amplitude, get_uavg, Contours
2119

2220

2321
def contour_iter(self, anticyclonic_search):
@@ -35,6 +33,7 @@ def isvalid(self):
3533
BasePath.isvalid = isvalid
3634

3735

36+
@property
3837
def mean_coordinates(self):
3938
return self.vertices.mean(axis=0)
4039

@@ -83,19 +82,22 @@ def uniform_resample(x_val, y_val, num_fac=2, fixed_size=None):
8382
def regular_coordinates(self):
8483
"""Give a standard/regular/double sample of contour
8584
"""
86-
if hasattr(self, '_regular_coordinates'):
87-
self._regular_coordinates = uniform_resample(self.lon, self.lat)
85+
if not hasattr(self, '_regular_coordinates'):
86+
self._regular_coordinates = column_stack(uniform_resample(self.lon, self.lat))
8887
return self._regular_coordinates
8988

9089

90+
BasePath.regular_coordinates = regular_coordinates
91+
92+
9193
def fit_circle_path(self):
9294
if not hasattr(self, '_circle_params'):
9395
self._fit_circle_path()
9496
return self._circle_params
9597

9698

9799
def _fit_circle_path(self):
98-
lon_mean, lat_mean = self.mean_coordinates()
100+
lon_mean, lat_mean = self.mean_coordinates
99101
# Prepare for shape test and get eddy_radius_e
100102
# http://www.geo.hunter.cuny.edu/~jochen/gtech201/lectures/
101103
# lec6concepts/map%20coordinate%20systems/
@@ -344,12 +346,7 @@ def bounds(self):
344346
"""
345347
return self.x_bounds.min(), self.x_bounds.max(), self.y_bounds.min(), self.y_bounds.max()
346348

347-
def eddy_identification(self, grid_height, step=0.005, shape_error=55, extra_variables=None,
348-
extra_array_variables=None, array_sampling=50, pixel_limit=None):
349-
if extra_variables is None:
350-
extra_variables = list()
351-
if extra_array_variables is None:
352-
extra_array_variables = list()
349+
def eddy_identification(self, grid_height, step=0.005, shape_error=55, array_sampling=50, pixel_limit=None):
353350
if pixel_limit is None:
354351
pixel_limit = (8, 1000)
355352

@@ -361,22 +358,15 @@ def eddy_identification(self, grid_height, step=0.005, shape_error=55, extra_var
361358
levels = arange(z_min - z_min % step, z_max - z_max % step + 2 * step, step)
362359

363360
x, y = self.vars[self.coordinates[0]], self.vars[self.coordinates[1]]
364-
## To re write
365-
if len(x.shape) == 1:
366-
data = data.T
367-
##
368-
logging.debug('Start computing iso lines')
369-
fig = Figure()
370-
ax = fig.add_subplot(111)
371-
contours = ax.contour(x, y, data, levels)
372-
logging.debug('Finish computing iso lines')
361+
362+
eddies = list()
363+
contours = Contours(x, y, data, levels)
373364

374365
anticyclonic_search = True
375366
iterator = 1 if anticyclonic_search else -1
376367

377368
# Loop over each collection
378-
for coll_ind, coll in enumerate(contours.collections[::iterator]):
379-
369+
for coll_ind, coll in enumerate(contours.iter(step=iterator)):
380370
corrected_coll_index = coll_ind
381371
if iterator == -1:
382372
corrected_coll_index = - coll_ind - 1
@@ -390,11 +380,13 @@ def eddy_identification(self, grid_height, step=0.005, shape_error=55, extra_var
390380
corrected_coll_index, cvalues, nb_paths)
391381

392382
# Loop over individual c_s contours (i.e., every eddy in field)
393-
for cont in contour_paths:
383+
for current_contour in contour_paths:
384+
if current_contour.used:
385+
continue
394386
# Filter for closed contours
395-
if not cont.isvalid:
387+
if not current_contour.isvalid:
396388
continue
397-
centlon_e, centlat_e, eddy_radius_e, aerr = cont.fit_circle()
389+
centlon_e, centlat_e, eddy_radius_e, aerr = current_contour.fit_circle()
398390
# Filter for shape
399391
if aerr < 0 or aerr > shape_error:
400392
continue
@@ -410,10 +402,10 @@ def eddy_identification(self, grid_height, step=0.005, shape_error=55, extra_var
410402
if anticyclonic_search != acyc_not_cyc:
411403
continue
412404

413-
i_x_in, i_y_in = cont.pixels_in(self)
405+
i_x_in, i_y_in = current_contour.pixels_in(self)
414406

415407
# Maybe limit max must be replace with a maximum of surface
416-
if cont.nb_pixel < pixel_limit[0] or cont.nb_pixel > pixel_limit[1]:
408+
if current_contour.nb_pixel < pixel_limit[0] or current_contour.nb_pixel > pixel_limit[1]:
417409
continue
418410

419411
reset_centroid, amp = self.get_amplitude(i_x_in, i_y_in, cvalues, data,
@@ -426,82 +418,50 @@ def eddy_identification(self, grid_height, step=0.005, shape_error=55, extra_var
426418
if reset_centroid:
427419
centi = reset_centroid[0]
428420
centj = reset_centroid[1]
429-
centlon_e = x[centj, centi]
430-
centlat_e = y[centj, centi]
421+
centlon_e = x[centi, centj]
422+
centlat_e = y[centi, centj]
431423

432-
# Get sum of eke within Ceff
433-
#~ teke = grd.eke[eddy.slice_j, eddy.slice_i][eddy.mask_eff].sum()
434-
435-
#~ (uavg, contlon_s, contlat_s, inner_contlon, inner_contlat, any_inner_contours
436-
#~ ) = get_uavg(eddy, contours, centlon_e, centlat_e, cont, grd, anticyclonic_search)
437-
(uavg, contlon_s, contlat_s, inner_contlon, inner_contlat, any_inner_contours
438-
) = get_uavg(self, contours, centlon_e, centlat_e, cont, anticyclonic_search)
424+
average_speed, speed_contour, inner_contour, speed_array = \
425+
get_uavg(self, contours, centlon_e, centlat_e, current_contour, anticyclonic_search, corrected_coll_index)
439426

440427
# Use azimuth equal projection for radius
441-
proj = Proj('+proj=aeqd +ellps=WGS84 +lat_0=%s +lon_0=%s'
442-
% (inner_contlat.mean(), inner_contlon.mean()))
443-
428+
proj = Proj('+proj=aeqd +ellps=WGS84 +lat_0={1} +lon_0={0}'.format(*inner_contour.mean_coordinates))
444429
# First, get position based on innermost
445430
# contour
446-
c_x, c_y = proj(inner_contlon, inner_contlat)
431+
c_x, c_y = proj(inner_contour.lon, inner_contour.lat)
447432
centx_s, centy_s, _, _ = fit_circle_c(c_x, c_y)
448-
centlon_s, centlat_s = proj(centx_s, centy_s,
449-
inverse=True)
433+
centlon_s, centlat_s = proj(centx_s, centy_s, inverse=True)
450434
# Second, get speed-based radius based on
451435
# contour of max uavg
452-
# (perhaps we should make a new proj here
453-
# based on contlon_s, contlat_s but I'm not
454-
# sure it's that important ... Antoine?)
455-
# A. : I dont think, the difference is tiny
456-
c_x, c_y = proj(contlon_s, contlat_s)
436+
c_x, c_y = proj(speed_contour.lon, speed_contour.lat)
457437
_, _, eddy_radius_s, aerr_s = fit_circle_c(c_x, c_y)
458438

459439
# Instantiate new EddyObservation object
460440
properties = EddiesObservations(
461441
size=1,
462-
track_extra_variables=extra_variables,
442+
track_extra_variables=['shape_error_e', 'shape_error_s'],
463443
track_array_variables=array_sampling,
464-
array_variables=extra_array_variables
444+
array_variables=['contour_lon_e', 'contour_lat_e', 'contour_lon_s', 'contour_lat_s']
465445
)
466446
properties.obs['amplitude'] = amp.amplitude
467447
properties.obs['radius_s'] = eddy_radius_s / 1000
468-
properties.obs['speed_radius'] = uavg
448+
properties.obs['speed_radius'] = average_speed
469449
properties.obs['radius_e'] = eddy_radius_e / 1000
470-
#~ properties.obs['eke'] = teke
471-
if 'shape_error_e' in eddy.track_extra_variables:
472-
properties.obs['shape_error_e'] = aerr
473-
if 'shape_error_s' in eddy.track_extra_variables:
474-
properties.obs['shape_error_s'] = aerr_s
475-
476-
if aerr > 99.9 or aerr_s > 99.9:
477-
logging.warning(
478-
'Strange shape at this step! shape_error : %f, %f',
479-
aerr,
480-
aerr_s)
481-
continue
482-
483-
# Update SLA eddy properties
484-
485-
# See CSS11 section B4
450+
properties.obs['shape_error_e'] = aerr
451+
properties.obs['shape_error_s'] = aerr_s
486452
properties.obs['lon'] = centlon_s
487453
properties.obs['lat'] = centlat_s
488-
if 'contour_lon_e' in extra_array_variables:
489-
(properties.obs['contour_lon_e'],
490-
properties.obs['contour_lat_e']) = uniform_resample(
491-
cont.lon, cont.lat,
492-
fixed_size=array_sampling)
493-
if 'contour_lon_s' in extra_array_variables:
494-
(properties.obs['contour_lon_s'],
495-
properties.obs['contour_lat_s']) = uniform_resample(
496-
contlon_s, contlat_s,
497-
fixed_size=array_sampling)
498-
499-
# for AVISO
500-
eddy.update_eddy_properties(properties)
501-
502-
# Mask out already found eddies
503-
eddy.sla[eddy.slice_j, eddy.slice_i][
504-
eddy.mask_eff] = eddy.fillval
454+
properties.obs['contour_lon_e'], properties.obs['contour_lat_e'] = uniform_resample(
455+
current_contour.lon, current_contour.lat, fixed_size=array_sampling)
456+
properties.obs['contour_lon_s'], properties.obs['contour_lat_s'] = uniform_resample(
457+
speed_contour.lon, speed_contour.lat, fixed_size=array_sampling)
458+
if aerr > 99.9 or aerr_s > 99.9:
459+
logging.warning('Strange shape at this step! shape_error : %f, %f', aerr, aerr_s)
460+
461+
eddies.append(properties)
462+
# To reserve definitively the area
463+
data.mask[i_x_in, i_y_in] = True
464+
return eddies
505465

506466
@staticmethod
507467
def _gaussian_filter(data, sigma, mode='reflect'):
@@ -562,15 +522,6 @@ def get_pixels_in(self, contour):
562522
i_x, i_y = where(mask)
563523
i_x += slice_x.start
564524
i_y += slice_y.start
565-
566-
# import matplotlib
567-
# matplotlib.use('AGG')
568-
# import matplotlib.pyplot as plt
569-
# plt.figure()
570-
# plt.plot(self.x_c[i_x, i_y], self.y_c[i_x, i_y], 'g.', zorder=-10, markersize=20)
571-
# plt.plot(self.x_c[slice_x, slice_y], self.y_c[slice_x, slice_y], 'r.', zorder=+10)
572-
# plt.plot(contour.lon, contour.lat, 'b', zorder=20)
573-
# plt.savefig('/tmp/toto.png')
574525
return i_x, i_y
575526

576527
def nearest_grd_indice(self, x, y):

0 commit comments

Comments
 (0)