@@ -30,10 +30,9 @@ from scipy.ndimage import gaussian_filter
30
30
from matplotlib .dates import date2num , num2julian
31
31
from matplotlib .figure import Figure
32
32
from re import compile as re_compile
33
- from os .path import exists
33
+ from os .path import exists , join
34
34
from os import mkdir
35
- from multiprocessing import Pool
36
- from numpy import array , arange , atleast_1d , unique , round , int , place , interp , pi
35
+ from numpy import array , arange , atleast_1d , unique , round , int , interp , pi
37
36
38
37
from py_eddy_tracker import EddyParser
39
38
from py_eddy_tracker .property_functions import \
@@ -43,126 +42,134 @@ from py_eddy_tracker.grid.aviso import AvisoGrid
43
42
from py_eddy_tracker .tracking_objects import IdentificationList
44
43
45
44
46
- if __name__ == '__main__' :
47
- # Run using:
48
- PARSER = EddyParser ("Tool to detect eddies. "
45
+ def load_config () :
46
+ # Command Parser
47
+ parser = EddyParser ("Tool to detect eddies. "
49
48
"To run use EddyIdentification "
50
49
"eddy_tracker_configuration.yaml'" )
51
- PARSER .add_argument ('yaml_file' ,
50
+ parser .add_argument ('yaml_file' ,
52
51
help = 'Yaml file to configure py-eddy-tracker' )
53
- YAML_FILE = PARSER .parse_args (). yaml_file
52
+ opts = parser .parse_args ()
54
53
55
54
# Read yaml configuration file
56
- with open (YAML_FILE , 'r' ) as stream :
57
- CONFIG = yaml_load (stream )
58
-
59
- logging .info ('Launching with yaml file: %s' , YAML_FILE )
60
-
61
- # Setup configuration
62
- SAVE_DIR = CONFIG ['PATHS' ]['SAVE_DIR' ]
63
- logging .info ('Outputs saved to %(SAVE_DIR)s' , CONFIG ['PATHS' ])
64
- if not exists (SAVE_DIR ):
65
- mkdir (SAVE_DIR )
66
-
67
- DIAGNOSTIC_TYPE = CONFIG ['DIAGNOSTIC_TYPE' ]
68
- if DIAGNOSTIC_TYPE not in ['SLA' ]:
69
- raise Exception ('Unknown diagnostic %s' , DIAGNOSTIC_TYPE )
55
+ config = None
56
+ with open (opts .yaml_file , 'r' ) as stream :
57
+ config = yaml_load (stream )
58
+ if config is None :
59
+ raise Exception ('Yaml file empty' )
60
+ logging .info ('Launching with yaml file: %s' , opts .yaml_file )
61
+
62
+ # Create ouput directory if needed
63
+ save_dir = config ['PATHS' ]['SAVE_DIR' ]
64
+ logging .info ('Outputs saved to %(SAVE_DIR)s' , config ['PATHS' ])
65
+ if not exists (save_dir ):
66
+ mkdir (save_dir )
67
+
68
+ diagnostic_type = config ['DIAGNOSTIC_TYPE' ]
69
+ if diagnostic_type not in ['SLA' ]:
70
+ raise Exception ('Unknown diagnostic %s' , diagnostic_type )
71
+
70
72
71
- CONFIG ['THE_DOMAIN' ] = CONFIG ['DOMAIN' ]['THE_DOMAIN' ]
73
+ config ['THE_DOMAIN' ] = config ['DOMAIN' ]['THE_DOMAIN' ]
72
74
73
75
# It is not recommended to change values given below
74
76
# for 'Global', 'BlackSea' or 'MedSea'...
75
- if 'Global' in CONFIG ['THE_DOMAIN' ]:
76
- CONFIG ['lonmin' ] = - 100.
77
- CONFIG ['lonmax' ] = 290.
78
- CONFIG ['latmin' ] = - 80.
79
- CONFIG ['latmax' ] = 80.
80
-
81
- elif CONFIG ['THE_DOMAIN' ] in ('Regional' ):
82
- CONFIG ['lonmin' ] = CONFIG ['DOMAIN' ]['LONMIN' ]
83
- CONFIG ['lonmax' ] = CONFIG ['DOMAIN' ]['LONMAX' ]
84
- CONFIG ['latmin' ] = CONFIG ['DOMAIN' ]['LATMIN' ]
85
- CONFIG ['latmax' ] = CONFIG ['DOMAIN' ]['LATMAX' ]
86
-
87
- START_DATE = CONFIG ['DATE_STR' ] = CONFIG ['DOMAIN' ]['DATE_STR' ]
88
- END_DATE = CONFIG ['DATE_END' ] = CONFIG ['DOMAIN' ]['DATE_END' ]
89
- if START_DATE > END_DATE :
77
+ if 'Global' in config ['THE_DOMAIN' ]:
78
+ config ['lonmin' ] = - 100.
79
+ config ['lonmax' ] = 290.
80
+ config ['latmin' ] = - 80.
81
+ config ['latmax' ] = 80.
82
+
83
+ elif config ['THE_DOMAIN' ] in ('Regional' ):
84
+ config ['lonmin' ] = config ['DOMAIN' ]['LONMIN' ]
85
+ config ['lonmax' ] = config ['DOMAIN' ]['LONMAX' ]
86
+ config ['latmin' ] = config ['DOMAIN' ]['LATMIN' ]
87
+ config ['latmax' ] = config ['DOMAIN' ]['LATMAX' ]
88
+
89
+ config ['DATE_STR' ] = config ['DOMAIN' ]['DATE_STR' ]
90
+ config ['DATE_END' ] = config ['DOMAIN' ]['DATE_END' ]
91
+ if config [ 'DATE_STR' ] > config [ 'DATE_END' ] :
90
92
raise Exception ('DATE_END must be larger than DATE_STR' )
91
93
92
- if 'SLA' in DIAGNOSTIC_TYPE :
93
- MAX_SLA = CONFIG ['CONTOUR_PARAMETER'
94
+
95
+ if 'SLA' in diagnostic_type :
96
+ max_sla = config ['CONTOUR_PARAMETER'
94
97
]['CONTOUR_PARAMETER_SLA' ]['MAX_SLA' ]
95
- INTERVAL = CONFIG ['CONTOUR_PARAMETER'
98
+ interval = config ['CONTOUR_PARAMETER'
96
99
]['CONTOUR_PARAMETER_SLA' ]['INTERVAL' ]
97
- CONFIG ['CONTOUR_PARAMETER' ] = arange (- MAX_SLA , MAX_SLA + INTERVAL ,
98
- INTERVAL )
99
- # AMPMIN = CONFIG['AMPMIN']
100
- # AMPMAX = CONFIG['AMPMAX']
101
-
102
- SMOOTHING = CONFIG ['SMOOTHING' ]
103
- if SMOOTHING :
104
- if 'SLA' in DIAGNOSTIC_TYPE :
105
- ZWL = atleast_1d (CONFIG ['SMOOTHING_SLA' ]['ZWL' ])
106
- MWL = atleast_1d (CONFIG ['SMOOTHING_SLA' ]['MWL' ])
107
- SMOOTHING_TYPE = CONFIG ['SMOOTHING_SLA' ]['TYPE' ]
108
-
109
- # End user configuration setup options
110
- # ----------------------------------------------------------
100
+ config ['CONTOUR_PARAMETER' ] = arange (- max_sla , max_sla + interval ,
101
+ interval )
102
+
103
+ smoothing = config ['SMOOTHING' ]
104
+ if smoothing :
105
+ if 'SLA' in diagnostic_type :
106
+ config ['SMOOTHING_SLA' ]['ZWL' ] = atleast_1d (config ['SMOOTHING_SLA' ]['ZWL' ])
107
+ config ['SMOOTHING_SLA' ]['MWL' ] = atleast_1d (config ['SMOOTHING_SLA' ]['MWL' ])
108
+ return config
109
+
110
+ def browse_dataset_in (data_dir , files_model , date_regexp , date_model ,
111
+ start_date , end_date , sub_sampling_step = 1 ):
112
+ pattern_regexp = re_compile ('.*/' + date_regexp )
113
+ full_path = join (data_dir , files_model )
114
+ logging .info ('Search files : %s' , full_path )
115
+
116
+ dataset_list = array (glob (full_path ),
117
+ dtype = [('filename' , 'S256' ),
118
+ ('date' , 'datetime64[D]' ),
119
+ ])
120
+
121
+ logging .info ('%s grids available' , dataset_list .shape [0 ])
122
+ for item in dataset_list :
123
+ result = pattern_regexp .match (item ['filename' ])
124
+ if result :
125
+ str_date = result .groups ()[0 ]
126
+ item ['date' ] = datetime .strptime (str_date , date_model ).date ()
111
127
112
- # Get complete AVISO file list
113
- DATA_DIR = CONFIG ['DATASET' ]['DATA_DIR' ]
114
- FILES_MODEL = CONFIG ['DATASET' ]['FILES_MODEL' ]
115
- SUBSAMPLING_STEP = CONFIG ['DATASET' ]['SUBSAMPLING' ]
116
- DATE_REGEXP = re_compile ('.*/' + CONFIG ['DATASET' ]['DATE_REGEXP' ])
117
- PATTERN_DATE = CONFIG ['DATASET' ]['DATE_MODEL' ]
128
+ dataset_list .sort (order = ['date' , 'filename' ])
129
+ logging .info ('Filtering grid by time %s, %s' , start_date , end_date )
130
+ mask = (dataset_list ['date' ] >= start_date ) * (
131
+ dataset_list ['date' ] <= end_date )
118
132
119
- GRID_NAME = CONFIG ['DATASET' ]['VAR_NAME' ]
120
- LAT_NAME = CONFIG ['DATASET' ]['LAT_NAME' ]
121
- LON_NAME = CONFIG ['DATASET' ]['LON_NAME' ]
122
-
123
- logging .info ('Search files : %s' , DATA_DIR + FILES_MODEL )
124
- DATASET_FILES = glob (DATA_DIR + FILES_MODEL )
133
+ steps = unique (dataset_list ['date' ][1 :] - dataset_list ['date' ][:- 1 ])
134
+ if len (steps ) != 1 :
135
+ raise Exception ('Several days steps in grid dataset %s' % steps )
125
136
126
- DATASET_LIST = array (DATASET_FILES ,
127
- dtype = [('date' , 'datetime64[D]' ),
128
- ('filename' , 'S256' )])
129
- DATASET_LIST ['filename' ] = array (DATASET_FILES )
130
-
131
- logging .info ('%s grids available' , DATASET_LIST .shape [0 ])
132
- for item in DATASET_LIST :
133
- result = DATE_REGEXP .match (item ['filename' ])
134
- if result :
135
- str_date = result .groups ()[0 ]
136
- item ['date' ] = datetime .strptime (str_date , PATTERN_DATE ).date ()
137
+ if sub_sampling_step != 1 :
138
+ logging .info ('Grid subsampling %d' , sub_sampling_step )
139
+ dataset_list = dataset_list [::sub_sampling_step ]
137
140
138
- DATASET_LIST .sort (order = ['date' , 'filename' ])
139
- logging .info ('Filtering grid by time %s, %s' , START_DATE , END_DATE )
140
- MASK_DATE = (DATASET_LIST ['date' ] >= START_DATE ) * (
141
- DATASET_LIST ['date' ] <= END_DATE )
141
+ dataset_list = dataset_list [mask ]
142
+ return dataset_list
142
143
143
- STEPS = unique (DATASET_LIST ['date' ][1 :] - DATASET_LIST ['date' ][:- 1 ])
144
- if len (STEPS ) != 1 :
145
- raise Exception ('Several days steps in grid dataset %s' % STEPS )
146
- else :
147
- DAYS_BTWN_RECORDS = STEPS [0 ]
148
144
149
- if SUBSAMPLING_STEP != 1 :
150
- logging .info ('Grid subsampling %d' , SUBSAMPLING_STEP )
151
- DATASET_LIST = DATASET_LIST [::SUBSAMPLING_STEP ]
145
+ if __name__ == '__main__' :
146
+ CONFIG = load_config ()
147
+ DATASET_LIST = browse_dataset_in (
148
+ data_dir = CONFIG ['DATASET' ]['DATA_DIR' ],
149
+ files_model = CONFIG ['DATASET' ]['FILES_MODEL' ],
150
+ date_regexp = CONFIG ['DATASET' ]['DATE_REGEXP' ],
151
+ date_model = CONFIG ['DATASET' ]['DATE_MODEL' ],
152
+ start_date = CONFIG ['DATE_STR' ],
153
+ end_date = CONFIG ['DATE_END' ],
154
+ sub_sampling_step = CONFIG ['DATASET' ]['SUBSAMPLING' ],
155
+ )
152
156
153
- DATASET_LIST = DATASET_LIST [MASK_DATE ]
157
+ # End user configuration setup options
158
+ # ----------------------------------------------------------
154
159
155
160
# Set up a grid object using first AVISO file in the list
156
161
SLA_GRD = AvisoGrid (DATASET_LIST [0 ]['filename' ], CONFIG ['THE_DOMAIN' ],
157
162
CONFIG ['lonmin' ], CONFIG ['lonmax' ],
158
163
CONFIG ['latmin' ], CONFIG ['latmax' ],
159
- grid_name = GRID_NAME ,
160
- lon_name = LON_NAME ,
161
- lat_name = LAT_NAME )
164
+ grid_name = CONFIG [ 'DATASET' ][ 'VAR_NAME' ] ,
165
+ lon_name = CONFIG [ 'DATASET' ][ ' LON_NAME' ] ,
166
+ lat_name = CONFIG [ 'DATASET' ][ ' LAT_NAME' ] )
162
167
163
- if 'Gaussian' in SMOOTHING_TYPE :
168
+ if 'Gaussian' in CONFIG [ 'SMOOTHING_SLA' ][ 'TYPE' ] :
164
169
# Get parameters for gaussian_filter
165
- ZRES , MRES = SLA_GRD .gaussian_resolution (ZWL , MWL )
170
+ ZRES , MRES = SLA_GRD .gaussian_resolution (
171
+ CONFIG ['SMOOTHING_SLA' ]['ZWL' ],
172
+ CONFIG ['SMOOTHING_SLA' ]['MWL' ])
166
173
167
174
# See Chelton section B2 (0.4 degree radius)
168
175
# These should give 8 and 1000 for 0.25 deg resolution
@@ -181,7 +188,7 @@ if __name__ == '__main__':
181
188
logging .info ('Start tracking' )
182
189
183
190
# Loop over grid
184
- for date , filename in DATASET_LIST :
191
+ for filename , date in DATASET_LIST :
185
192
date = date .astype (dt .date )
186
193
# Extract grid date
187
194
grd_int_date = num2julian (date2num (date ))
@@ -199,13 +206,13 @@ if __name__ == '__main__':
199
206
sla = SLA_GRD .get_aviso_data (filename )
200
207
SLA_GRD .set_mask (sla ).uvmask ()
201
208
202
- if SMOOTHING :
203
- if 'Gaussian' in SMOOTHING_TYPE :
209
+ if CONFIG [ ' SMOOTHING' ] :
210
+ if 'Gaussian' in CONFIG [ 'SMOOTHING_SLA' ][ 'TYPE' ] :
204
211
logging .info ('applying Gaussian high-pass filter' )
205
212
# Set landpoints to zero
206
- place ( sla , SLA_GRD .mask , 0. )
213
+ sla [ SLA_GRD .mask ] = 0.
207
214
if hasattr (sla , 'data' ):
208
- place ( sla , sla .data == SLA_GRD .fillval , 0. )
215
+ sla [ sla .data == SLA_GRD .fillval ] = 0.
209
216
# High pass filter, see
210
217
# http://stackoverflow.com/questions/6094957/high-pass-filter-
211
218
# for-image-processing-in-python-by-using-scipy-numpy
@@ -234,7 +241,7 @@ if __name__ == '__main__':
234
241
# Calculate EKE
235
242
SLA_GRD .get_eke ()
236
243
237
- if 'SLA' in DIAGNOSTIC_TYPE :
244
+ if 'SLA' in CONFIG [ ' DIAGNOSTIC_TYPE' ] :
238
245
A_EDDY .sla = sla .copy ()
239
246
C_EDDY .sla = sla .copy ()
240
247
@@ -249,14 +256,15 @@ if __name__ == '__main__':
249
256
C_EDDY .sla_coeffs = SLA_GRD .sla_coeffs
250
257
C_EDDY .uspd_coeffs = SLA_GRD .uspd_coeffs
251
258
252
- if 'SLA' in DIAGNOSTIC_TYPE :
259
+ if 'SLA' in CONFIG [ ' DIAGNOSTIC_TYPE' ] :
253
260
logging .info ('Processing SLA contours for eddies' )
254
261
MIN_SLA , MAX_SLA = A_EDDY .sla .min (), A_EDDY .sla .max ()
255
262
if (MIN_SLA < A_EDDY .contour_parameter [0 ]) or (
256
263
MAX_SLA > A_EDDY .contour_parameter [- 1 ]):
257
264
logging .warning ('SLA values [%f,%f] is larger than levels %s' ,
258
265
MIN_SLA , MAX_SLA , A_EDDY .contour_parameter )
259
266
267
+ # we reduce levels if don't needed
260
268
i_min , i_max = interp (
261
269
(MIN_SLA , MAX_SLA ),
262
270
A_EDDY .contour_parameter ,
@@ -266,18 +274,8 @@ if __name__ == '__main__':
266
274
A_EDDY .contour_parameter = A_EDDY .contour_parameter [i_min :i_max ]
267
275
C_EDDY .contour_parameter = C_EDDY .contour_parameter [i_min :i_max ]
268
276
269
- CONTOURS = CONT_AX .contour (
270
- SLA_GRD .lon ,
271
- SLA_GRD .lat ,
272
- A_EDDY .sla ,
273
- levels = A_EDDY .contour_parameter )
274
-
275
- # MultiThreading on path to fit circle could accelerate processing
276
- # may be in python 3
277
- #~ paths = []
278
- #~ for i in CONTOURS.collections:
279
- #~ paths += i.get_paths()
280
- #~ circle_process(paths)
277
+ CONTOURS = CONT_AX .contour (SLA_GRD .lon , SLA_GRD .lat , A_EDDY .sla ,
278
+ levels = A_EDDY .contour_parameter )
281
279
# Note that C_CS is in reverse order
282
280
logging .info ('Processing SLA contours for eddies -- Ok' )
283
281
@@ -287,21 +285,23 @@ if __name__ == '__main__':
287
285
C_EDDY .swirl = A_EDDY .swirl
288
286
289
287
# Now we loop over the CS collection
290
- if 'SLA' in DIAGNOSTIC_TYPE :
288
+ if 'SLA' in CONFIG [ ' DIAGNOSTIC_TYPE' ] :
291
289
logging .info ("Anticyclonic research" )
292
- A_EDDY = collection_loop (CONTOURS , SLA_GRD , grd_int_date , A_EDDY )
293
- # Note that C_CS is reverse order
290
+ collection_loop (CONTOURS , SLA_GRD , A_EDDY )
294
291
logging .info ("Cyclonic research" )
295
- C_EDDY = collection_loop (CONTOURS , SLA_GRD , grd_int_date , C_EDDY )
292
+ collection_loop (CONTOURS , SLA_GRD , C_EDDY )
296
293
294
+ A_EDDY .observations .obs ['time' ] = grd_int_date
295
+ C_EDDY .observations .obs ['time' ] = grd_int_date
297
296
# clear the current axis
298
297
CONT_AX .cla ()
299
298
# Save file
300
- A_EDDY .write_netcdf (path = SAVE_DIR )
301
- C_EDDY .write_netcdf (path = SAVE_DIR )
299
+ A_EDDY .write_netcdf (path = CONFIG ['PATHS' ]['SAVE_DIR' ])
300
+ C_EDDY .write_netcdf (path = CONFIG ['PATHS' ]['SAVE_DIR' ])
301
+ del CONTOURS , A_EDDY , C_EDDY
302
302
303
303
# Total running time
304
304
logging .info ('Mean duration by loop : %s' ,
305
305
(datetime .now () - START_TIME ) / len (DATASET_LIST ))
306
306
logging .info ('Duration : %s' , datetime .now () - START_TIME )
307
- logging .info ('Outputs saved to %s' , SAVE_DIR )
307
+ logging .info ('Outputs saved to %s' , CONFIG [ 'PATHS' ][ ' SAVE_DIR' ] )
0 commit comments