@@ -1001,66 +1001,71 @@ def reshape_mask_eff(self, grd):
1001
1001
1002
1002
class RossbyWaveSpeed (object ):
1003
1003
1004
- def __init__ (self , domain , grd , ZERO_CROSSING , limits , rw_path = None ):
1004
+ def __init__ (self , THE_DOMAIN , grd , RW_PATH = None ):
1005
1005
"""
1006
1006
Initialise the RossbyWaveSpeedsobject
1007
1007
"""
1008
- self .domain = domain
1008
+ self .THE_DOMAIN = THE_DOMAIN
1009
1009
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 , \
1014
1015
'Must supply a path for the Rossby deformation radius data'
1015
- data = np .loadtxt (rw_path )
1016
+ data = np .loadtxt (RW_PATH )
1016
1017
self ._lon = data [:, 1 ] - 360.
1017
1018
self ._lat = data [:, 0 ]
1018
1019
self ._defrad = data [:, 3 ]
1019
- self .limits = limits
1020
+ self .limits = [ grd . LONMIN , grd . LONMAX , grd . LATMIN , grd . LATMAX ]
1020
1021
self ._make_subset ()._make_kdtree ()
1021
1022
self .vartype = 'variable'
1022
1023
else :
1023
1024
self .vartype = 'constant'
1024
1025
self .distance = np .empty (1 )
1026
+ self .beta = np .empty (1 )
1027
+ self .r_spd_long = np .empty (1 )
1025
1028
self .start = True
1026
1029
1027
1030
1028
1031
def get_rwdistance (self , xpt , ypt , DAYS_BTWN_RECORDS ):
1029
1032
"""
1030
1033
"""
1031
- if self .domain in ('Global' , 'ROMS' ):
1034
+ if self .THE_DOMAIN in ('Global' , 'ROMS' ):
1032
1035
#print 'xpt, ypt', xpt, ypt
1033
- self .distance [:] = self ._get_c (xpt , ypt )
1036
+ self .distance [:] = self ._get_rlongwave_spd (xpt , ypt )
1034
1037
self .distance *= 86400.
1035
- #if self.domain in 'ROMS':
1038
+ #if self.THE_DOMAIN in 'ROMS':
1036
1039
#self.distance *= 1.5
1037
- elif 'BlackSea' in self .domain :
1040
+ elif 'BlackSea' in self .THE_DOMAIN :
1038
1041
self .distance [:] = 15000. # e.g., Blokhina & Afanasyev, 2003
1039
- elif 'MedSea' in self .domain :
1042
+ elif 'MedSea' in self .THE_DOMAIN :
1040
1043
self .distance [:] = 20000.
1041
1044
else :
1042
- Exception # Unknown domain
1045
+ Exception # Unknown THE_DOMAIN
1043
1046
1044
1047
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' ))
1054
1058
1055
1059
print "" .join (('--------- setting ellipse for first tracked ' ,
1056
1060
'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 ))
1060
1065
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
1064
1069
1065
1070
1066
1071
def _make_subset (self ):
@@ -1074,7 +1079,7 @@ def _make_subset(self):
1074
1079
self ._lat <= LATMAX + pad )
1075
1080
self ._lon = self ._lon [lloi ]
1076
1081
self ._lat = self ._lat [lloi ]
1077
- self ._c = self ._c [lloi ]
1082
+ self ._defrad = self ._defrad [lloi ]
1078
1083
self .x , self .y = self .M (self ._lon , self ._lat )
1079
1084
return self
1080
1085
@@ -1085,72 +1090,75 @@ def _make_kdtree(self):
1085
1090
self ._tree = spatial .cKDTree (points )
1086
1091
1087
1092
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 ):
1100
1094
"""
1101
1095
Get a point average of the deformation radius
1102
- at x, y
1096
+ at xpt, ypt
1103
1097
"""
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 )
1105
1099
weights /= weights .sum ()
1106
1100
self ._weights = weights
1107
1101
self .i = i
1108
1102
return np .average (self ._defrad [i ], weights = weights )
1109
1103
1110
1104
1111
- def _get_rlongwave_spd (self , x , y ):
1105
+ def _get_rlongwave_spd (self , xpt , ypt ):
1112
1106
"""
1113
1107
Get the longwave phase speed, see Chelton etal (2008) pg 446:
1114
1108
c = -beta * defrad**2 (this only for extratropical waves...)
1115
1109
"""
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
1125
1120
1126
1121
1127
1122
1128
1123
1129
1124
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 ):
1133
1130
"""
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
1135
1133
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.
1136
1146
"""
1137
- self .domain = domain
1147
+ self .THE_DOMAIN = THE_DOMAIN
1138
1148
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
1143
1149
self .e_w_major = self .DAYS_BTWN_RECORDS * 3e5 / 7.
1144
1150
self .n_s_minor = self .DAYS_BTWN_RECORDS * 2 * 15e4 / 7.
1145
1151
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
1150
1156
1151
1157
1152
1158
def _set_east_ellipse (self ):
1153
1159
"""
1160
+ The east_ellipse is a full ellipse, but only its eastern
1161
+ part is used to build the search ellipse.
1154
1162
"""
1155
1163
self .east_ellipse = patch .Ellipse ((self .xpt , self .ypt ),
1156
1164
self .e_w_major , self .n_s_minor )
@@ -1159,14 +1167,17 @@ def _set_east_ellipse(self):
1159
1167
1160
1168
def _set_west_ellipse (self ):
1161
1169
"""
1170
+ The east_ellipse is a full ellipse, but only its eastern
1171
+ part is used to build the search ellipse.
1162
1172
"""
1163
1173
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 )
1165
1175
return self
1166
1176
1167
1177
1168
1178
def _set_global_ellipse (self ):
1169
1179
"""
1180
+
1170
1181
"""
1171
1182
self ._set_east_ellipse ()._set_west_ellipse ()
1172
1183
e_verts = self .east_ellipse .get_verts ()
@@ -1185,7 +1196,7 @@ def _set_black_sea_ellipse(self):
1185
1196
"""
1186
1197
"""
1187
1198
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 )
1189
1200
verts = self .black_sea_ellipse .get_verts ()
1190
1201
self .ellipse_path = path .Path (np .array ([verts [:, 0 ],
1191
1202
verts [:, 1 ]]).T )
@@ -1198,26 +1209,21 @@ def set_search_ellipse(self, xpt, ypt):
1198
1209
self .xpt = xpt
1199
1210
self .ypt = ypt
1200
1211
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 ,
1203
1214
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 ,
1209
1218
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.
1214
1220
self ._set_global_ellipse ()
1215
1221
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
1221
1227
self ._set_black_sea_ellipse ()
1222
1228
1223
1229
else :
@@ -1232,7 +1238,7 @@ def view_search_ellipse(self, Eddy):
1232
1238
"""
1233
1239
plt .figure ()
1234
1240
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])
1236
1242
Eddy .M .scatter (self .xpt , self .ypt , c = 'b' )
1237
1243
Eddy .M .plot (self .ellipse_path .vertices [:, 0 ],
1238
1244
self .ellipse_path .vertices [:, 1 ], 'r' )
@@ -1242,7 +1248,6 @@ def view_search_ellipse(self, Eddy):
1242
1248
labels = [1 , 0 , 0 , 0 ], ax = ax )
1243
1249
Eddy .M .drawmeridians (np .arange (- 360 , 360. + stride , stride ),
1244
1250
labels = [0 , 0 , 0 , 1 ], ax = ax )
1245
- #plt.axis('image')
1246
1251
plt .show ()
1247
1252
1248
1253
0 commit comments