Skip to content

Commit 9e60118

Browse files
committed
move main code in function, to try to manage memory leak
1 parent 6f095ba commit 9e60118

File tree

2 files changed

+124
-129
lines changed

2 files changed

+124
-129
lines changed

src/py_eddy_tracker/property_functions.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -362,16 +362,14 @@ def _fit_circle_path(self):
362362
BasePath._fit_circle_path = _fit_circle_path
363363

364364

365-
def collection_loop(contours, grd, rtime, eddy,
366-
x_i=None, c_s_xi=None):
365+
def collection_loop(contours, grd, eddy, x_i=None, c_s_xi=None):
367366
"""
368367
Loop over each collection of contours
369368
"""
370369
if eddy.diagnostic_type not in ['Q', 'SLA']:
371370
raise Exception('Unknown Diagnostic : %s' % eddy.diagnostic_type)
372371

373-
sign_type = eddy.sign_type
374-
anticyclonic_search = 'Anticyclonic' in sign_type
372+
anticyclonic_search = 'Anticyclonic' in eddy.sign_type
375373
iterator = 1 if anticyclonic_search else -1
376374

377375
# Set contour coordinates and indices for calculation of
@@ -524,7 +522,6 @@ def collection_loop(contours, grd, rtime, eddy,
524522
properties.obs['radius_s'] = eddy_radius_s
525523
properties.obs['speed_radius'] = uavg
526524
properties.obs['radius_e'] = eddy_radius_e
527-
properties.obs['time'] = rtime
528525
properties.obs['eke'] = teke
529526
if 'shape_error' in eddy.track_extra_variables:
530527
properties.obs['shape_error'] = aerr
@@ -555,8 +552,6 @@ def collection_loop(contours, grd, rtime, eddy,
555552
eddy.sla[eddy.slice_j, eddy.slice_i][
556553
eddy.mask_eff] = eddy.fillval
557554

558-
# Leave collection_loop
559-
return eddy
560555

561556

562557
def func_hann2d_fast(var, numpasses):

src/scripts/EddyIdentification

Lines changed: 122 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,9 @@ from scipy.ndimage import gaussian_filter
3030
from matplotlib.dates import date2num, num2julian
3131
from matplotlib.figure import Figure
3232
from re import compile as re_compile
33-
from os.path import exists
33+
from os.path import exists, join
3434
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
3736

3837
from py_eddy_tracker import EddyParser
3938
from py_eddy_tracker.property_functions import \
@@ -43,126 +42,134 @@ from py_eddy_tracker.grid.aviso import AvisoGrid
4342
from 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

Comments
 (0)