@@ -487,6 +487,11 @@ def create_netcdf(self, directory, savedir, title,
487
487
nc .j0 = np .int32 (self .j0 )
488
488
nc .j1 = np .int32 (self .j1 )
489
489
490
+ #nc.LONMIN = grd.LONMIN
491
+ #nc.LONMAX = grd.LONMAX
492
+ #nc.LATMIN = grd.LATMIN
493
+ #nc.LATMAX = grd.LATMAX
494
+
490
495
if 'ROMS' in self .DATATYPE :
491
496
nc .ROMS_grid = grd .grdfile
492
497
nc .model = model
@@ -512,55 +517,56 @@ def create_netcdf(self, directory, savedir, title,
512
517
# Create variables
513
518
nc .createVariable ('track' , np .int32 , ('Nobs' ), fill_value = self .fillval )
514
519
nc .createVariable ('n' , np .int32 , ('Nobs' ), fill_value = self .fillval )
520
+
515
521
# Use of jday should depend on clim vs interann
516
522
if self .INTERANNUAL : # AVISO or INTERANNUAL ROMS solution
517
523
nc .createVariable ('j1' , np .int32 , ('Nobs' ), fill_value = self .fillval )
524
+
518
525
else : # climatological ROMS solution
519
526
nc .createVariable ('ocean_time' , 'f8' , ('Nobs' ), fill_value = self .fillval )
527
+
520
528
nc .createVariable ('lon' , 'f4' , ('Nobs' ), fill_value = self .fillval )
521
529
nc .createVariable ('lat' , 'f4' , ('Nobs' ), fill_value = self .fillval )
522
530
nc .createVariable ('A' , 'f4' , ('Nobs' ), fill_value = self .fillval )
523
531
nc .createVariable ('L' , 'f4' , ('Nobs' ), fill_value = self .fillval )
524
532
nc .createVariable ('U' , 'f4' , ('Nobs' ), fill_value = self .fillval )
525
533
nc .createVariable ('Teke' , 'f4' , ('Nobs' ), fill_value = self .fillval )
526
534
nc .createVariable ('radius_e' , 'f4' , ('Nobs' ), fill_value = self .fillval )
535
+
527
536
if 'Q' in self .DIAGNOSTIC_TYPE :
528
537
nc .createVariable ('qparameter' , 'f4' , ('Nobs' ), fill_value = self .fillval )
538
+
529
539
if 'ROMS' in self .DATATYPE :
530
540
nc .createVariable ('temp' , 'f4' , ('Nobs' ), fill_value = self .fillval )
531
541
nc .createVariable ('salt' , 'f4' , ('Nobs' ), fill_value = self .fillval )
532
542
533
- #nc.createVariable('NLP', 'f8', ('Nobs'), fill_value=self.fillval)
534
- #nc.createVariable('bounds', np.int16, ('Nobs','four'), fill_value=self.fillval)
535
- nc .createVariable ('eddy_duration' , np .int16 , ('Nobs' ), fill_value = self .fillval )
543
+ #nc.createVariable('eddy_duration', np.int16, ('Nobs'), fill_value=self.fillval)
536
544
537
545
# Meta data for variables
538
546
nc .variables ['track' ].units = 'ordinal'
539
547
nc .variables ['track' ].min_val = np .int32 (0 )
548
+ nc .variables ['track' ].max_val = np .int32 (0 )
540
549
nc .variables ['track' ].long_name = 'track number'
541
550
nc .variables ['track' ].description = 'eddy identification number'
542
551
543
552
nc .variables ['n' ].units = 'ordinal'
544
- #nc.variables['n'].min_val = 4
545
- #nc.variables['n'].max_val = 293
546
553
nc .variables ['n' ].long_name = 'observation number'
547
554
# Add option here to set length of intervals.....
548
555
nc .variables ['n' ].description = 'observation sequence number (XX day intervals)'
549
556
550
557
## Use of jday should depend on clim vs interann
551
558
if self .INTERANNUAL : # AVISO or INTERANNUAL ROMS solution
552
559
nc .variables ['j1' ].units = 'days'
553
- #nc.variables['j1'].min_val = 2448910
554
- #nc.variables['j1'].max_val = 2455560
555
560
nc .variables ['j1' ].long_name = 'Julian date'
556
561
nc .variables ['j1' ].description = 'date of this observation'
557
562
nc .variables ['j1' ].reference = self .JDAY_REFERENCE
558
563
nc .variables ['j1' ].reference_description = "" .join (('Julian '
559
564
'date on Jan 1, 1992' ))
565
+
560
566
else : # climatological ROMS solution
561
567
nc .variables ['ocean_time' ].units = 'ROMS ocean_time (seconds)'
562
568
563
- nc .variables ['eddy_duration' ].units = 'days'
569
+ # nc.variables['eddy_duration'].units = 'days'
564
570
nc .variables ['lon' ].units = 'deg. longitude'
565
571
nc .variables ['lon' ].min_val = self .LONMIN
566
572
nc .variables ['lon' ].max_val = self .LONMAX
@@ -570,8 +576,10 @@ def create_netcdf(self, directory, savedir, title,
570
576
571
577
if 'Q' in self .DIAGNOSTIC_TYPE :
572
578
nc .variables ['A' ].units = 'None, normalised vorticity (abs(xi)/f)'
579
+
573
580
elif 'SLA' in self .DIAGNOSTIC_TYPE :
574
581
nc .variables ['A' ].units = 'cm'
582
+
575
583
nc .variables ['A' ].min_val = self .AMPMIN
576
584
nc .variables ['A' ].max_val = self .AMPMAX
577
585
nc .variables ['A' ].long_name = 'amplitude'
@@ -608,8 +616,6 @@ def create_netcdf(self, directory, savedir, title,
608
616
609
617
if 'Q' in self .DIAGNOSTIC_TYPE :
610
618
nc .variables ['qparameter' ].units = 's^{-2}'
611
- #nc.variables['NLP'].units = 'None, swirl vel. / propagation vel.'
612
- #nc.variables['NLP'].long_name = 'Non-linear parameter'
613
619
614
620
if 'ROMS' in self .DATATYPE :
615
621
nc .variables ['temp' ].units = 'deg. C'
@@ -681,7 +687,7 @@ def write2netcdf(self, rtime):
681
687
already written tracks.
682
688
Each inactive track is 'emptied' after saving
683
689
"""
684
- tracks2save = np .asarray ( self .get_inactive_tracks (rtime ))
690
+ tracks2save = np .array ([ self .get_inactive_tracks (rtime )] )
685
691
DBR = self .DAYS_BTWN_RECORDS
686
692
687
693
if np .any (tracks2save ): # Note, this could break if all eddies become inactive at same time
@@ -695,44 +701,65 @@ def write2netcdf(self, rtime):
695
701
(np .all (self .tracklist [i ].ocean_time )):
696
702
697
703
tsize = len (self .tracklist [i ].lon )
704
+
698
705
if (tsize >= self .TRACK_DURATION_MIN / DBR ) and tsize > 1. :
699
-
706
+ lon = np .array ([self .tracklist [i ].lon ])
707
+ lat = np .array ([self .tracklist [i ].lat ])
708
+ amp = np .array ([self .tracklist [i ].amplitude ])
709
+ uavg = np .array ([self .tracklist [i ].uavg ]) * 100. # to cm/s
710
+ teke = np .array ([self .tracklist [i ].teke ])
711
+ radius_s = np .array ([self .tracklist [i ].radius_s ]) * 1e-3 # to km
712
+ radius_e = np .array ([self .tracklist [i ].radius_e ]) * 1e-3 # to km
713
+ n = np .arange (tsize , dtype = np .int32 )
714
+ track = np .full (tsize , self .ch_index )
715
+ track_max_val = np .array ([nc .variables ['track' ].max_val ,
716
+ np .int32 (self .ch_index )]).max ()
717
+ #print self.tracklist[i].ocean_time
718
+ #exit()
719
+ #eddy_duration = np.array([self.tracklist[i].ocean_time]).ptp()
720
+
700
721
tend = self .ncind + tsize
701
- nc .variables ['lon' ][self .ncind :tend ] = np .asarray (self .tracklist [i ].lon )
702
- nc .variables ['lat' ][self .ncind :tend ] = np .asarray ([self .tracklist [i ].lat ])
703
- nc .variables ['A' ][self .ncind :tend ] = np .array ([self .tracklist [i ].amplitude ])
704
- self .tracklist [i ].uavg *= np .array (100. ) # to cm/s
705
- nc .variables ['U' ][self .ncind :tend ] = self .tracklist [i ].uavg
706
- nc .variables ['Teke' ][self .ncind :tend ] = np .array ([self .tracklist [i ].teke ])
707
- self .tracklist [i ].radius_s *= np .array (1e-3 ) # to km
708
- nc .variables ['L' ][self .ncind :tend ] = self .tracklist [i ].radius_s
709
- self .tracklist [i ].radius_e *= np .array (1e-3 ) # to km
710
- nc .variables ['radius_e' ][self .ncind :tend ] = self .tracklist [i ].radius_e
722
+ nc .variables ['lon' ][self .ncind :tend ] = lon
723
+ nc .variables ['lat' ][self .ncind :tend ] = lat
724
+ nc .variables ['A' ][self .ncind :tend ] = amp
725
+ nc .variables ['U' ][self .ncind :tend ] = uavg
726
+ nc .variables ['Teke' ][self .ncind :tend ] = teke
727
+ nc .variables ['L' ][self .ncind :tend ] = radius_s
728
+ nc .variables ['radius_e' ][self .ncind :tend ] = radius_e
729
+ nc .variables ['n' ][self .ncind :tend ] = n
730
+ nc .variables ['track' ][self .ncind :tend ] = track
731
+ nc .variables ['track' ].max_val = track_max_val
732
+ #nc.variables['eddy_duration'][self.ncind:tend] = eddy_duration
733
+
711
734
if 'ROMS' in self .DATATYPE :
712
- nc .variables ['temp' ][self .ncind :tend ] = np .array ([self .tracklist [i ].temp ])
713
- nc .variables ['salt' ][self .ncind :tend ] = np .array ([self .tracklist [i ].salt ])
714
- #nc.variables['bounds'][self.ncind:tend] = np.array([self.tracklist[i].bounds])
735
+ temp = np .array ([self .tracklist [i ].temp ])
736
+ salt = np .array ([self .tracklist [i ].salt ])
737
+
738
+ nc .variables ['temp' ][self .ncind :tend ] = temp
739
+ nc .variables ['salt' ][self .ncind :tend ] = salt
740
+
715
741
if self .INTERANNUAL :
716
742
# We add 1 because 'j1' is an integer in ncsavefile; julian day midnight has .5
717
743
# i.e., dt.julian2num(2448909.5) -> 727485.0
718
- nc .variables ['j1' ][self .ncind :tend ] = dt .num2julian (np .array ([self .tracklist [i ].ocean_time ])) + 1
744
+ j1 = dt .num2julian (np .array ([self .tracklist [i ].ocean_time ])) + 1
745
+ nc .variables ['j1' ][self .ncind :tend ] = j1
746
+
719
747
else :
720
- nc .variables ['ocean_time' ][self .ncind :tend ] = np .array ([self .tracklist [i ].ocean_time ])
721
- nc .variables ['n' ][self .ncind :tend ] = np .arange (tsize , dtype = np .int32 )
722
- nc .variables ['track' ][self .ncind :tend ] = np .full (tsize , self .ch_index )
723
- nc .variables ['track' ].max_val = np .int32 (self .ch_index )
724
- nc .variables ['eddy_duration' ][self .ncind :tend ] = np .array ([self .tracklist [i ].ocean_time ]).size \
725
- * self .DAYS_BTWN_RECORDS
748
+ ocean_time = np .array ([self .tracklist [i ].ocean_time ])
749
+ nc .variables ['ocean_time' ][self .ncind :tend ] = ocean_time
750
+
726
751
if self .TRACK_EXTRA_VARIABLES :
727
- nc .variables ['shape_error' ][self .ncind :tend ] = np .array ([self .tracklist [i ].shape_error ])
752
+ shape_error = np .array ([self .tracklist [i ].shape_error ])
753
+ nc .variables ['shape_error' ][self .ncind :tend ] = shape_error
754
+
728
755
for j in np .arange (tend - self .ncind ):
729
756
jj = j + self .ncind
730
- contour_e_arr = np .asarray (self .tracklist [i ].contour_e [j ]).ravel ()
757
+ contour_e_arr = np .array ([self .tracklist [i ].contour_e [j ]]).ravel ()
758
+ contour_s_arr = np .array ([self .tracklist [i ].contour_s [j ]]).ravel ()
759
+ uavg_profile_arr = np .array ([self .tracklist [i ].uavg_profile [j ]]).ravel ()
731
760
nc .variables ['contour_e' ][:contour_e_arr .size , jj ] = contour_e_arr
732
- contour_s_arr = np .asarray (self .tracklist [i ].contour_s [j ]).ravel ()
733
761
nc .variables ['contour_s' ][:contour_s_arr .size , jj ] = contour_s_arr
734
- uavg_profile_arr = np .asarray (self .tracklist [i ].uavg_profile [j ]).ravel ()
735
- nc .variables ['uavg_profile' ][:uavg_profile_arr .size , jj ] = uavg_profile_arr #np.asarray(self.tracklist[i].uavg_profile[j]).ravel()
762
+ nc .variables ['uavg_profile' ][:uavg_profile_arr .size , jj ] = uavg_profile_arr
736
763
737
764
# Flag indicating track[i] is now saved
738
765
self .tracklist [i ].saved2nc = True
@@ -743,6 +770,7 @@ def write2netcdf(self, rtime):
743
770
# Get index to first currently active track
744
771
try :
745
772
lasti = self .get_active_tracks (rtime )[0 ]
773
+
746
774
except Exception :
747
775
lasti = None
748
776
@@ -921,35 +949,7 @@ def insert_at_index(self, xarr, ind, x):
921
949
922
950
return self
923
951
924
-
925
-
926
-
927
- #def set_bounds(self, centlon, centlat, radius, i, j, grd):
928
- #"""
929
- #Get indices to a bounding box around the eddy
930
- #"""
931
- #def get_angle(deg, ang):
932
- #return deg - np.rad2deg(ang)
933
-
934
- #grdangle = grd.angle()[j,i]
935
- ##print type(centlon), type(centlat)
936
- #a_lon, a_lat = newPosition(centlon, centlat, get_angle(0, grdangle), radius)
937
- #b_lon, b_lat = newPosition(centlon, centlat, get_angle(90, grdangle), radius)
938
- #c_lon, c_lat = newPosition(centlon, centlat, get_angle(180, grdangle), radius)
939
- #d_lon, d_lat = newPosition(centlon, centlat, get_angle(270, grdangle), radius)
940
-
941
- ## Get i,j of bounding box around eddy
942
- ##print grd.lon().shape, grd.lat().shape, grd.shape
943
- #a_i, a_j = nearest(a_lon, a_lat, grd.lon(), grd.lat(), grd.shape)
944
- #b_i, b_j = nearest(b_lon, b_lat, grd.lon(), grd.lat(), grd.shape)
945
- #c_i, c_j = nearest(c_lon, c_lat, grd.lon(), grd.lat(), grd.shape)
946
- #d_i, d_j = nearest(d_lon, d_lat, grd.lon(), grd.lat(), grd.shape)
947
-
948
- #self.imin = np.maximum(np.min([a_i, b_i, c_i, d_i]) - 5, 0) # Must not go
949
- #self.jmin = np.maximum(np.min([a_j, b_j, c_j, d_j]) - 5, 0) # below zero
950
- #self.imax = np.max([a_i, b_i, c_i, d_i]) + 5
951
- #self.jmax = np.max([a_j, b_j, c_j, d_j]) + 5
952
- #return self
952
+
953
953
954
954
def set_bounds (self , contlon , contlat , grd ):
955
955
"""
@@ -1037,10 +1037,13 @@ def get_rwdistance(self, xpt, ypt, DAYS_BTWN_RECORDS):
1037
1037
self .distance *= 86400.
1038
1038
#if self.THE_DOMAIN in 'ROMS':
1039
1039
#self.distance *= 1.5
1040
+
1040
1041
elif 'BlackSea' in self .THE_DOMAIN :
1041
1042
self .distance [:] = 15000. # e.g., Blokhina & Afanasyev, 2003
1043
+
1042
1044
elif 'MedSea' in self .THE_DOMAIN :
1043
1045
self .distance [:] = 20000.
1046
+
1044
1047
else :
1045
1048
Exception # Unknown THE_DOMAIN
1046
1049
@@ -1060,7 +1063,7 @@ def get_rwdistance(self, xpt, ypt, DAYS_BTWN_RECORDS):
1060
1063
'eddy at %s, %s in the %s domain'
1061
1064
% (lon , lat , self .THE_DOMAIN )))
1062
1065
c = np .abs (self ._get_rlongwave_spd (xpt , ypt ))[0 ]
1063
- print "" .join (('--------- with extratropical long baroclinic' ,
1066
+ print "" .join (('--------- with extratropical long baroclinic ' ,
1064
1067
'Rossby wave phase speed of %s m/s' % c ))
1065
1068
self .start = False
1066
1069
@@ -1073,8 +1076,14 @@ def _make_subset(self):
1073
1076
"""
1074
1077
pad = 1.5 # degrees
1075
1078
LONMIN , LONMAX , LATMIN , LATMAX = self .limits
1076
- lloi = np .logical_and (self ._lon >= LONMIN - pad ,
1077
- self ._lon <= LONMAX + pad )
1079
+ if self .ZERO_CROSSING :
1080
+ ieast , iwest = (((self ._lon + 360. ) <= LONMAX + pad ),
1081
+ (self ._lon > LONMIN + pad ))
1082
+ self ._lon [ieast ] += 360.
1083
+ lloi = iwest + ieast
1084
+ else :
1085
+ lloi = np .logical_and (self ._lon >= LONMIN - pad ,
1086
+ self ._lon <= LONMAX + pad )
1078
1087
lloi *= np .logical_and (self ._lat >= LATMIN - pad ,
1079
1088
self ._lat <= LATMAX + pad )
1080
1089
self ._lon = self ._lon [lloi ]
@@ -1085,9 +1094,9 @@ def _make_subset(self):
1085
1094
1086
1095
1087
1096
def _make_kdtree (self ):
1088
- #points = np.vstack([self._lon, self._lat]).T
1089
1097
points = np .vstack ([self .x , self .y ]).T
1090
1098
self ._tree = spatial .cKDTree (points )
1099
+ return self
1091
1100
1092
1101
1093
1102
def _get_defrad (self , xpt , ypt ):
@@ -1104,7 +1113,7 @@ def _get_defrad(self, xpt, ypt):
1104
1113
1105
1114
def _get_rlongwave_spd (self , xpt , ypt ):
1106
1115
"""
1107
- Get the longwave phase speed, see Chelton etal (2008 ) pg 446:
1116
+ Get the longwave phase speed, see Chelton etal (1998 ) pg 446:
1108
1117
c = -beta * defrad**2 (this only for extratropical waves...)
1109
1118
"""
1110
1119
self .r_spd_long [:] = self ._get_defrad (xpt , ypt )
@@ -1157,7 +1166,7 @@ def __init__(self, THE_DOMAIN, grd, DAYS_BTWN_RECORDS, RW_PATH=None):
1157
1166
1158
1167
def _set_east_ellipse (self ):
1159
1168
"""
1160
- The east_ellipse is a full ellipse, but only its eastern
1169
+ The * east_ellipse* is a full ellipse, but only its eastern
1161
1170
part is used to build the search ellipse.
1162
1171
"""
1163
1172
self .east_ellipse = patch .Ellipse ((self .xpt , self .ypt ),
@@ -1167,7 +1176,7 @@ def _set_east_ellipse(self):
1167
1176
1168
1177
def _set_west_ellipse (self ):
1169
1178
"""
1170
- The east_ellipse is a full ellipse, but only its eastern
1179
+ The *west_ellipse* is a full ellipse, but only its western
1171
1180
part is used to build the search ellipse.
1172
1181
"""
1173
1182
self .west_ellipse = patch .Ellipse ((self .xpt , self .ypt ),
@@ -1177,7 +1186,8 @@ def _set_west_ellipse(self):
1177
1186
1178
1187
def _set_global_ellipse (self ):
1179
1188
"""
1180
-
1189
+ Set a Path object *ellipse_path* built from the eastern vertices of
1190
+ *east_ellipse* and the western vertices of *west_ellipse*.
1181
1191
"""
1182
1192
self ._set_east_ellipse ()._set_west_ellipse ()
1183
1193
e_verts = self .east_ellipse .get_verts ()
@@ -1194,6 +1204,7 @@ def _set_global_ellipse(self):
1194
1204
1195
1205
def _set_black_sea_ellipse (self ):
1196
1206
"""
1207
+ Set *ellipse_path* for the *black_sea_ellipse*.
1197
1208
"""
1198
1209
self .black_sea_ellipse = patch .Ellipse ((self .x , self .y ),
1199
1210
2. * self .rw_c_mod , 2. * self .rw_c_mod )
@@ -1205,6 +1216,14 @@ def _set_black_sea_ellipse(self):
1205
1216
1206
1217
def set_search_ellipse (self , xpt , ypt ):
1207
1218
"""
1219
+ Set the search ellipse around a point.
1220
+
1221
+ args:
1222
+
1223
+ *xpt*: lon coordinate (Basemap projection)
1224
+
1225
+ *ypt*: lat coordinate (Basemap projection)
1226
+
1208
1227
"""
1209
1228
self .xpt = xpt
1210
1229
self .ypt = ypt
@@ -1219,7 +1238,7 @@ def set_search_ellipse(self, xpt, ypt):
1219
1238
self .rw_c_mod *= 2.
1220
1239
self ._set_global_ellipse ()
1221
1240
1222
- elif 'BlackSea' in self .THE_DOMAIN :
1241
+ elif 'BlackSea' in self .THE_DOMAIN :
1223
1242
self .rw_c_mod [:] = 1.75
1224
1243
self .rw_c [:] = self .rwv .get_rwdistance (x , y ,
1225
1244
self .DAYS_BTWN_RECORDS )
0 commit comments