@@ -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