@@ -1001,66 +1001,71 @@ def reshape_mask_eff(self, grd):
10011001
10021002class 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
11291124class 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
0 commit comments