Skip to content

Commit 14c5645

Browse files
committed
Bugfixes to SearchEllipse
1 parent 2bd91eb commit 14c5645

File tree

4 files changed

+108
-106
lines changed

4 files changed

+108
-106
lines changed

eddy_tracker_configuration.yaml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,36 +14,36 @@ DOMAIN:
1414
#THE_DOMAIN = 'MedSea' # not yet implemented
1515
LONMIN: -40.
1616
LONMAX: -30.
17-
LATMIN: 30.
18-
LATMAX: 40.
19-
DATE_STR: 19980101
20-
DATE_END: 19980331
17+
LATMIN: 20.
18+
LATMAX: 30.
19+
DATE_STR: 20020101
20+
DATE_END: 20020630
2121

2222
# Specify the AVISO product
2323
AVISO:
2424
AVISO_DT14: Yes # Use new AVISO DT14 data (e.g., Capet et al, 2014)
25-
AVISO_FILES: 'dt_global_allsat_msla_h_????????_20140106.nc'
26-
AVISO_DT14_SUBSAMP: No # subsample the dqily AVISO DT14
25+
AVISO_FILES: 'dt_global_twosat_msla_h_????????_20140106.nc'
26+
AVISO_DT14_SUBSAMP: No # subsample the daily AVISO DT14
2727
DAYS_BTWN_RECORDS: 7 # sampling rate (days)
2828

2929
PATHS:
3030
# Path to AVISO data
31-
#DATA_DIR: '/data/PVA/Externe/global/delayed-time/grids/msla/two-sat-merged/h/2002/'
32-
DATA_DIR: '/Users/emason/data/AVISO/global/delayed-time/grids/msla/all-sat-merged/h/'
31+
DATA_DIR: '/data/PVA/Externe/global/delayed-time/grids/msla/two-sat-merged/h/2002/'
32+
# DATA_DIR: '/Users/emason/data/AVISO/global/delayed-time/grids/msla/all-sat-merged/h/'
3333
#DATA_DIR: '/marula/emason/data/altimetry/global/delayed-time/grids/msla/two-sat-merged/h/'
3434
# Path and filename of Chelton et al (1998) Rossby radius data
3535
# Obtain file from:
3636
# http://www-po.coas.oregonstate.edu/research/po/research/rossby_radius/
37-
#RW_PATH: '/homelocal/emason/rossrad.dat'
38-
RW_PATH: '/Users/emason/Downloads/rossrad.dat'
37+
RW_PATH: '/homelocal/emason/rossrad.dat'
38+
# RW_PATH: '/Users/emason/Downloads/rossrad.dat'
3939
#RW_PATH: '/home/emason/data_tmp/chelton_eddies/rossrad.dat'
4040

4141
# Path for saving of outputs
4242
# SAVE_DIR: '/homelocal/emason/outputs/before_swirl/'
4343
# SAVE_DIR: '/homelocal/emason/outputs/after_swirl/'
4444
# SAVE_DIR: '/homelocal/emason/outputs/after_swirl_slice/'
45-
#SAVE_DIR: '/homelocal/emason/outputs/'
46-
SAVE_DIR: '/Users/emason/toto/'
45+
SAVE_DIR: '/homelocal/emason/outputs/'
46+
# SAVE_DIR: '/Users/emason/toto/'
4747
#SAVE_DIR: '/marula/emason/aviso_eddy_tracking/fd0cdb4b2bd9/'
4848

4949
# Reference Julian day (Julian date at Jan 1, 1992)

make_eddy_track_AVISO.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ class PyEddyTracker (object):
6868
def __init__(self):
6969
"""
7070
Set some constants
71+
72+
*ZERO_CROSSING*:
73+
Boolean, *True* if THE_DOMAIN crosses 0 degree meridian
7174
"""
7275
self.GRAVITY = 9.81
7376
self.EARTH_RADIUS = 6371315.0
@@ -834,8 +837,7 @@ def set_interp_coeffs(self, sla, uspd):
834837

835838
# Instantiate search ellipse object
836839
search_ellipse = eddy_tracker.SearchEllipse(THE_DOMAIN, sla_grd,
837-
DAYS_BTWN_RECORDS, sla_grd.ZERO_CROSSING, RW_PATH,
838-
[LONMIN, LONMAX, LATMIN, LATMAX])
840+
DAYS_BTWN_RECORDS, RW_PATH)
839841

840842

841843
if 'Gaussian' in SMOOTHING_TYPE:

make_eddy_tracker_list_obj.py

Lines changed: 92 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,66 +1001,71 @@ def reshape_mask_eff(self, grd):
10011001

10021002
class RossbyWaveSpeed (object):
10031003

1004-
def __init__(self, domain, grd, ZERO_CROSSING, limits, rw_path=None):
1004+
def __init__(self, THE_DOMAIN, grd, RW_PATH=None):
10051005
"""
10061006
Initialise the RossbyWaveSpeedsobject
10071007
"""
1008-
self.domain = domain
1008+
self.THE_DOMAIN = THE_DOMAIN
10091009
self.M = grd.M
1010-
self.ZERO_CROSSING = ZERO_CROSSING
1011-
self.rw_path = rw_path
1012-
if self.domain in ('Global', 'ROMS'):
1013-
assert self.rw_path is not None, \
1010+
self.EARTH_RADIUS = grd.EARTH_RADIUS
1011+
self.ZERO_CROSSING = grd.ZERO_CROSSING
1012+
self.RW_PATH = RW_PATH
1013+
if self.THE_DOMAIN in ('Global', 'ROMS'):
1014+
assert self.RW_PATH is not None, \
10141015
'Must supply a path for the Rossby deformation radius data'
1015-
data = np.loadtxt(rw_path)
1016+
data = np.loadtxt(RW_PATH)
10161017
self._lon = data[:, 1] - 360.
10171018
self._lat = data[:, 0]
10181019
self._defrad = data[:, 3]
1019-
self.limits = limits
1020+
self.limits = [grd.LONMIN, grd.LONMAX, grd.LATMIN, grd.LATMAX]
10201021
self._make_subset()._make_kdtree()
10211022
self.vartype = 'variable'
10221023
else:
10231024
self.vartype = 'constant'
10241025
self.distance = np.empty(1)
1026+
self.beta = np.empty(1)
1027+
self.r_spd_long = np.empty(1)
10251028
self.start = True
10261029

10271030

10281031
def get_rwdistance(self, xpt, ypt, DAYS_BTWN_RECORDS):
10291032
"""
10301033
"""
1031-
if self.domain in ('Global', 'ROMS'):
1034+
if self.THE_DOMAIN in ('Global', 'ROMS'):
10321035
#print 'xpt, ypt', xpt, ypt
1033-
self.distance[:] = self._get_c(xpt, ypt)
1036+
self.distance[:] = self._get_rlongwave_spd(xpt, ypt)
10341037
self.distance *= 86400.
1035-
#if self.domain in 'ROMS':
1038+
#if self.THE_DOMAIN in 'ROMS':
10361039
#self.distance *= 1.5
1037-
elif 'BlackSea' in self.domain:
1040+
elif 'BlackSea' in self.THE_DOMAIN:
10381041
self.distance[:] = 15000. # e.g., Blokhina & Afanasyev, 2003
1039-
elif 'MedSea' in self.domain:
1042+
elif 'MedSea' in self.THE_DOMAIN:
10401043
self.distance[:] = 20000.
10411044
else:
1042-
Exception # Unknown domain
1045+
Exception # Unknown THE_DOMAIN
10431046

10441047
if self.start:
1045-
#print x, y
1046-
if x < 0.:
1047-
lon = "".join((str(x), 'W'))
1048-
elif x >= 0:
1049-
lon = "".join((str(x), 'E'))
1050-
if y < 0:
1051-
lat = "".join((str(y), 'S'))
1052-
elif y >= 0:
1053-
lat = "".join((str(y), 'N'))
1048+
lon, lat = self.M.projtran(xpt, ypt, inverse=True)
1049+
lon, lat = np.round(lon, 2), np.round(lat, 2)
1050+
if lon < 0.:
1051+
lon = "".join((str(lon), 'W'))
1052+
elif lon >= 0:
1053+
lon = "".join((str(lon), 'E'))
1054+
if lat < 0:
1055+
lat = "".join((str(lat), 'S'))
1056+
elif lat >= 0:
1057+
lat = "".join((str(lat), 'N'))
10541058

10551059
print "".join(('--------- setting ellipse for first tracked ',
10561060
'eddy at %s, %s in the %s domain'
1057-
% (lon, lat, self.domain)))
1058-
print '--------- using %s Rossby deformation radius of %s m' \
1059-
% (self.vartype, np.abs(self.distance[0]))
1061+
% (lon, lat, self.THE_DOMAIN)))
1062+
c = np.abs(self._get_rlongwave_spd(xpt, ypt))[0]
1063+
print "".join(('--------- with extratropical long baroclinic',
1064+
'Rossby wave phase speed of %s m/s' % c))
10601065
self.start = False
1061-
self.distance *= DAYS_BTWN_RECORDS
1062-
#print 'aaaa', self.distance
1063-
return self.distance
1066+
1067+
self.distance = np.abs(self.distance)
1068+
return self.distance * DAYS_BTWN_RECORDS
10641069

10651070

10661071
def _make_subset(self):
@@ -1074,7 +1079,7 @@ def _make_subset(self):
10741079
self._lat <= LATMAX + pad)
10751080
self._lon = self._lon[lloi]
10761081
self._lat = self._lat[lloi]
1077-
self._c = self._c[lloi]
1082+
self._defrad = self._defrad[lloi]
10781083
self.x, self.y = self.M(self._lon, self._lat)
10791084
return self
10801085

@@ -1085,72 +1090,75 @@ def _make_kdtree(self):
10851090
self._tree = spatial.cKDTree(points)
10861091

10871092

1088-
#def _get_defrad(self, x, y):
1089-
#"""
1090-
#Get a point average of the deformation radius
1091-
#at x, y
1092-
#"""
1093-
#weights, i = self._tree.query(np.array([x, y]), k=4, p=2)
1094-
#weights /= weights.sum()
1095-
#self._weights = weights
1096-
#self.i = i
1097-
#return np.average(self._defrad[i], weights=weights)
1098-
1099-
def _get_c(self, xpt, ypt):
1093+
def _get_defrad(self, xpt, ypt):
11001094
"""
11011095
Get a point average of the deformation radius
1102-
at x, y
1096+
at xpt, ypt
11031097
"""
1104-
weights, i = self._tree.query(np.array([x, y]), k=4, p=2)
1098+
weights, i = self._tree.query(np.array([xpt, ypt]), k=4, p=2)
11051099
weights /= weights.sum()
11061100
self._weights = weights
11071101
self.i = i
11081102
return np.average(self._defrad[i], weights=weights)
11091103

11101104

1111-
def _get_rlongwave_spd(self, x, y):
1105+
def _get_rlongwave_spd(self, xpt, ypt):
11121106
"""
11131107
Get the longwave phase speed, see Chelton etal (2008) pg 446:
11141108
c = -beta * defrad**2 (this only for extratropical waves...)
11151109
"""
1116-
r_spd_long = self._get_defrad(x, y)
1117-
r_spd_long *= 1000. # km to m
1118-
r_spd_long **= 2
1119-
lat = np.average(self._lat[self.i], weights=self._weights)
1120-
beta = np.cos(np.deg2rad(lat))
1121-
beta *= 1458e-7 # 1458e-7 ~ (2 * 7.29*10**-5)
1122-
beta /= 6371315.0
1123-
r_spd_long *= -beta
1124-
return r_spd_long
1110+
self.r_spd_long[:] = self._get_defrad(xpt, ypt)
1111+
self.r_spd_long *= 1000. # km to m
1112+
self.r_spd_long **= 2
1113+
self.beta[:] = np.average(self._lat[self.i],
1114+
weights=self._weights) # lat
1115+
self.beta[:] = np.cos(np.deg2rad(self.beta))
1116+
self.beta *= 1458e-7 # 1458e-7 ~ (2 * 7.29*10**-5)
1117+
self.beta /= self.EARTH_RADIUS
1118+
self.r_spd_long *= -self.beta
1119+
return self.r_spd_long
11251120

11261121

11271122

11281123

11291124
class SearchEllipse (object):
1130-
1131-
def __init__(self, domain, grd, DAYS_BTWN_RECORDS, ZERO_CROSSING,
1132-
rw_path, limits):
1125+
"""
1126+
Class to construct a search ellipse/circle around a specified point.
1127+
See CSS11 Appendix B.4. "Automated eddy tracking" for details.
1128+
"""
1129+
def __init__(self, THE_DOMAIN, grd, DAYS_BTWN_RECORDS, RW_PATH=None):
11331130
"""
1134-
Class to construct a search ellipse/circle around a specified point.
1131+
Set the constant dimensions of the search ellipse.
1132+
Instantiate a RossbyWaveSpeed object
11351133
1134+
Arguments:
1135+
1136+
*THE_DOMAIN*: string
1137+
Refers to THE_DOMAIN specified in yaml configuration file
1138+
1139+
*grd*: An AvisoGrid or RomsGrid object.
1140+
1141+
*DAYS_BTWN_RECORDS*: integer
1142+
Constant defined in yaml configuration file.
1143+
1144+
*RW_PATH*: string
1145+
Path to rossrad.dat file, specified in yaml configuration file.
11361146
"""
1137-
self.domain = domain
1147+
self.THE_DOMAIN = THE_DOMAIN
11381148
self.DAYS_BTWN_RECORDS = DAYS_BTWN_RECORDS
1139-
self.ZERO_CROSSING = ZERO_CROSSING
1140-
self.rw_path = rw_path
1141-
self.limits = limits
1142-
self.rw_d_fac = 1.75
11431149
self.e_w_major = self.DAYS_BTWN_RECORDS * 3e5 / 7.
11441150
self.n_s_minor = self.DAYS_BTWN_RECORDS * 2 * 15e4 / 7.
11451151
self.semi_n_s_minor = 0.5 * self.n_s_minor
1146-
self.rwv = RossbyWaveSpeed(domain, grd, ZERO_CROSSING,
1147-
limits, rw_path=rw_path)
1148-
self.rw_d = np.empty(1)
1149-
self.rw_d_mod = np.empty(1)
1152+
self.rwv = RossbyWaveSpeed(THE_DOMAIN, grd, RW_PATH=RW_PATH)
1153+
self.rw_c = np.empty(1)
1154+
self.rw_c_mod = np.empty(1)
1155+
self.rw_c_fac = 1.75
11501156

11511157

11521158
def _set_east_ellipse(self):
11531159
"""
1160+
The east_ellipse is a full ellipse, but only its eastern
1161+
part is used to build the search ellipse.
11541162
"""
11551163
self.east_ellipse = patch.Ellipse((self.xpt, self.ypt),
11561164
self.e_w_major, self.n_s_minor)
@@ -1159,14 +1167,17 @@ def _set_east_ellipse(self):
11591167

11601168
def _set_west_ellipse(self):
11611169
"""
1170+
The east_ellipse is a full ellipse, but only its eastern
1171+
part is used to build the search ellipse.
11621172
"""
11631173
self.west_ellipse = patch.Ellipse((self.xpt, self.ypt),
1164-
self.rw_d_mod, self.n_s_minor)
1174+
self.rw_c_mod, self.n_s_minor)
11651175
return self
11661176

11671177

11681178
def _set_global_ellipse(self):
11691179
"""
1180+
11701181
"""
11711182
self._set_east_ellipse()._set_west_ellipse()
11721183
e_verts = self.east_ellipse.get_verts()
@@ -1185,7 +1196,7 @@ def _set_black_sea_ellipse(self):
11851196
"""
11861197
"""
11871198
self.black_sea_ellipse = patch.Ellipse((self.x, self.y),
1188-
2. * self.rw_d_mod, 2. * self.rw_d_mod)
1199+
2. * self.rw_c_mod, 2. * self.rw_c_mod)
11891200
verts = self.black_sea_ellipse.get_verts()
11901201
self.ellipse_path = path.Path(np.array([verts[:, 0],
11911202
verts[:, 1]]).T)
@@ -1198,26 +1209,21 @@ def set_search_ellipse(self, xpt, ypt):
11981209
self.xpt = xpt
11991210
self.ypt = ypt
12001211

1201-
if self.domain in ('Global', 'ROMS'):
1202-
self.rw_d[:] = self.rwv.get_rwdistance(xpt, ypt,
1212+
if self.THE_DOMAIN in ('Global', 'ROMS'):
1213+
self.rw_c[:] = self.rwv.get_rwdistance(xpt, ypt,
12031214
self.DAYS_BTWN_RECORDS)
1204-
#print self.rw_d
1205-
#exit()
1206-
self.rw_d_mod[:] = 1.75
1207-
self.rw_d_mod *= self.rw_d
1208-
self.rw_d_mod[:] = np.array([self.rw_d_mod,
1215+
self.rw_c_mod[:] = 1.75
1216+
self.rw_c_mod *= self.rw_c
1217+
self.rw_c_mod[:] = np.array([self.rw_c_mod,
12091218
self.semi_n_s_minor]).max()
1210-
1211-
#print self.rw_d_mod, self.semi_n_s_minor
1212-
1213-
self.rw_d_mod *= 2.
1219+
self.rw_c_mod *= 2.
12141220
self._set_global_ellipse()
12151221

1216-
elif 'BlackSea' in self.domain:
1217-
self.rw_d_mod[:] = 1.75
1218-
self.rw_d[:] = self.rwv.get_rwdistance(x, y,
1219-
self.DAYS_BTWN_RECORDS)
1220-
self.rw_d_mod *= self.rw_d
1222+
elif 'BlackSea' in self.THE_DOMAIN:
1223+
self.rw_c_mod[:] = 1.75
1224+
self.rw_c[:] = self.rwv.get_rwdistance(x, y,
1225+
self.DAYS_BTWN_RECORDS)
1226+
self.rw_c_mod *= self.rw_c
12211227
self._set_black_sea_ellipse()
12221228

12231229
else:
@@ -1232,7 +1238,7 @@ def view_search_ellipse(self, Eddy):
12321238
"""
12331239
plt.figure()
12341240
ax = plt.subplot()
1235-
#ax.set_title('Rossby def. rad %s m' %self.rw_d[0])
1241+
#ax.set_title('Rossby def. rad %s m' %self.rw_c[0])
12361242
Eddy.M.scatter(self.xpt, self.ypt, c='b')
12371243
Eddy.M.plot(self.ellipse_path.vertices[:, 0],
12381244
self.ellipse_path.vertices[:, 1], 'r')
@@ -1242,7 +1248,6 @@ def view_search_ellipse(self, Eddy):
12421248
labels=[1, 0, 0, 0], ax=ax)
12431249
Eddy.M.drawmeridians(np.arange(-360, 360. + stride, stride),
12441250
labels=[0, 0, 0, 1], ax=ax)
1245-
#plt.axis('image')
12461251
plt.show()
12471252

12481253

py_eddy_tracker_classes.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -911,8 +911,6 @@ def track_eddies(Eddy, first_record):
911911
# Make an ellipse at current old_eddy location
912912
# (See CSS11 sec. B4, pg. 208)
913913
if 'ellipse' in Eddy.SEPARATION_METHOD:
914-
#Eddy.search_ellipse.set_search_ellipse(Eddy.old_lon[old_ind],
915-
#Eddy.old_lat[old_ind])
916914
Eddy.search_ellipse.set_search_ellipse(old_x[old_ind],
917915
old_y[old_ind])
918916

@@ -923,9 +921,6 @@ def track_eddies(Eddy, first_record):
923921
if 'ellipse' in Eddy.SEPARATION_METHOD:
924922
if Eddy.search_ellipse.ellipse_path.contains_point(
925923
(new_x[new_ind], new_y[new_ind])):
926-
#if Eddy.search_ellipse.ellipse_path.contains_point(
927-
#(Eddy.new_lon_tmp[new_ind], Eddy.new_lat_tmp[new_ind])):
928-
#Eddy.search_ellipse.view_search_ellipse(Eddy)
929924
sep_proceed = True
930925
else:
931926
sep_proceed = False

0 commit comments

Comments
 (0)