@@ -30,10 +30,9 @@ from scipy.ndimage import gaussian_filter
3030from matplotlib .dates import date2num , num2julian
3131from matplotlib .figure import Figure
3232from re import compile as re_compile
33- from os .path import exists
33+ from os .path import exists , join
3434from 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
3736
3837from py_eddy_tracker import EddyParser
3938from py_eddy_tracker .property_functions import \
@@ -43,126 +42,134 @@ from py_eddy_tracker.grid.aviso import AvisoGrid
4342from py_eddy_tracker .tracking_objects import IdentificationList
4443
4544
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. "
4948 "To run use EddyIdentification "
5049 "eddy_tracker_configuration.yaml'" )
51- PARSER .add_argument ('yaml_file' ,
50+ parser .add_argument ('yaml_file' ,
5251 help = 'Yaml file to configure py-eddy-tracker' )
53- YAML_FILE = PARSER .parse_args (). yaml_file
52+ opts = parser .parse_args ()
5453
5554 # 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+
7072
71- CONFIG ['THE_DOMAIN' ] = CONFIG ['DOMAIN' ]['THE_DOMAIN' ]
73+ config ['THE_DOMAIN' ] = config ['DOMAIN' ]['THE_DOMAIN' ]
7274
7375 # It is not recommended to change values given below
7476 # 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' ] :
9092 raise Exception ('DATE_END must be larger than DATE_STR' )
9193
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'
9497 ]['CONTOUR_PARAMETER_SLA' ]['MAX_SLA' ]
95- INTERVAL = CONFIG ['CONTOUR_PARAMETER'
98+ interval = config ['CONTOUR_PARAMETER'
9699 ]['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 ()
111127
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 )
118132
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 )
125136
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 ]
137140
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
142143
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 ]
148144
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+ )
152156
153- DATASET_LIST = DATASET_LIST [MASK_DATE ]
157+ # End user configuration setup options
158+ # ----------------------------------------------------------
154159
155160 # Set up a grid object using first AVISO file in the list
156161 SLA_GRD = AvisoGrid (DATASET_LIST [0 ]['filename' ], CONFIG ['THE_DOMAIN' ],
157162 CONFIG ['lonmin' ], CONFIG ['lonmax' ],
158163 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' ] )
162167
163- if 'Gaussian' in SMOOTHING_TYPE :
168+ if 'Gaussian' in CONFIG [ 'SMOOTHING_SLA' ][ 'TYPE' ] :
164169 # 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' ])
166173
167174 # See Chelton section B2 (0.4 degree radius)
168175 # These should give 8 and 1000 for 0.25 deg resolution
@@ -181,7 +188,7 @@ if __name__ == '__main__':
181188 logging .info ('Start tracking' )
182189
183190 # Loop over grid
184- for date , filename in DATASET_LIST :
191+ for filename , date in DATASET_LIST :
185192 date = date .astype (dt .date )
186193 # Extract grid date
187194 grd_int_date = num2julian (date2num (date ))
@@ -199,13 +206,13 @@ if __name__ == '__main__':
199206 sla = SLA_GRD .get_aviso_data (filename )
200207 SLA_GRD .set_mask (sla ).uvmask ()
201208
202- if SMOOTHING :
203- if 'Gaussian' in SMOOTHING_TYPE :
209+ if CONFIG [ ' SMOOTHING' ] :
210+ if 'Gaussian' in CONFIG [ 'SMOOTHING_SLA' ][ 'TYPE' ] :
204211 logging .info ('applying Gaussian high-pass filter' )
205212 # Set landpoints to zero
206- place ( sla , SLA_GRD .mask , 0. )
213+ sla [ SLA_GRD .mask ] = 0.
207214 if hasattr (sla , 'data' ):
208- place ( sla , sla .data == SLA_GRD .fillval , 0. )
215+ sla [ sla .data == SLA_GRD .fillval ] = 0.
209216 # High pass filter, see
210217 # http://stackoverflow.com/questions/6094957/high-pass-filter-
211218 # for-image-processing-in-python-by-using-scipy-numpy
@@ -234,7 +241,7 @@ if __name__ == '__main__':
234241 # Calculate EKE
235242 SLA_GRD .get_eke ()
236243
237- if 'SLA' in DIAGNOSTIC_TYPE :
244+ if 'SLA' in CONFIG [ ' DIAGNOSTIC_TYPE' ] :
238245 A_EDDY .sla = sla .copy ()
239246 C_EDDY .sla = sla .copy ()
240247
@@ -249,14 +256,15 @@ if __name__ == '__main__':
249256 C_EDDY .sla_coeffs = SLA_GRD .sla_coeffs
250257 C_EDDY .uspd_coeffs = SLA_GRD .uspd_coeffs
251258
252- if 'SLA' in DIAGNOSTIC_TYPE :
259+ if 'SLA' in CONFIG [ ' DIAGNOSTIC_TYPE' ] :
253260 logging .info ('Processing SLA contours for eddies' )
254261 MIN_SLA , MAX_SLA = A_EDDY .sla .min (), A_EDDY .sla .max ()
255262 if (MIN_SLA < A_EDDY .contour_parameter [0 ]) or (
256263 MAX_SLA > A_EDDY .contour_parameter [- 1 ]):
257264 logging .warning ('SLA values [%f,%f] is larger than levels %s' ,
258265 MIN_SLA , MAX_SLA , A_EDDY .contour_parameter )
259266
267+ # we reduce levels if don't needed
260268 i_min , i_max = interp (
261269 (MIN_SLA , MAX_SLA ),
262270 A_EDDY .contour_parameter ,
@@ -266,18 +274,8 @@ if __name__ == '__main__':
266274 A_EDDY .contour_parameter = A_EDDY .contour_parameter [i_min :i_max ]
267275 C_EDDY .contour_parameter = C_EDDY .contour_parameter [i_min :i_max ]
268276
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 )
281279 # Note that C_CS is in reverse order
282280 logging .info ('Processing SLA contours for eddies -- Ok' )
283281
@@ -287,21 +285,23 @@ if __name__ == '__main__':
287285 C_EDDY .swirl = A_EDDY .swirl
288286
289287 # Now we loop over the CS collection
290- if 'SLA' in DIAGNOSTIC_TYPE :
288+ if 'SLA' in CONFIG [ ' DIAGNOSTIC_TYPE' ] :
291289 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 )
294291 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 )
296293
294+ A_EDDY .observations .obs ['time' ] = grd_int_date
295+ C_EDDY .observations .obs ['time' ] = grd_int_date
297296 # clear the current axis
298297 CONT_AX .cla ()
299298 # 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
302302
303303 # Total running time
304304 logging .info ('Mean duration by loop : %s' ,
305305 (datetime .now () - START_TIME ) / len (DATASET_LIST ))
306306 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