source: flex_extract.git/source/python/mods/get_mars_data.py @ 7e25255

ctbtodev
Last change on this file since 7e25255 was 7e25255, checked in by Anne Philipp <anne.philipp@…>, 5 years ago

python2 downgrade/ extra check for pure forecast vs one day forecast

  • Property mode set to 100755
File size: 11.0 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#*******************************************************************************
4# @Author: Anne Fouilloux (University of Oslo)
5#
6# @Date: October 2014
7#
8# @Change History:
9#
10#    November 2015 - Leopold Haimberger (University of Vienna):
11#        - moved the getEIdata program into a function "get_mars_data"
12#        - moved the AgurmentParser into a seperate function
13#        - adatpted the function for the use in flex_extract
14#        - renamed file to get_mars_data
15#
16#    February 2018 - Anne Philipp (University of Vienna):
17#        - applied PEP8 style guide
18#        - added structured documentation
19#        - minor changes in programming style for consistence
20#        - added function main and moved function calls vom __main__ there
21#          (necessary for better documentation with docstrings for later
22#          online documentation)
23#        - use of UIFiles class for file selection and deletion
24#        - seperated get_mars_data function into several smaller pieces:
25#          write_reqheader, mk_server, mk_dates, remove_old, do_retrievment
26#
27# @License:
28#    (C) Copyright 2014-2019.
29#    Anne Philipp, Leopold Haimberger
30#
31#    This work is licensed under the Creative Commons Attribution 4.0
32#    International License. To view a copy of this license, visit
33#    http://creativecommons.org/licenses/by/4.0/ or send a letter to
34#    Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
35#*******************************************************************************
36'''This script extracts MARS data from ECMWF servers.
37
38At first, the necessary parameters from command line and CONTROL files are
39extracted. They define the data set to be extracted from MARS.
40
41This file can also be imported as a module and contains the following
42functions:
43
44    * main - the main function of the script
45    * get_mars_data - overall control of ECMWF data retrievment
46    * write_reqheader - writes the header into the mars_request file
47    * mk_server - creates the server connection to ECMWF servers
48    * mk_dates - defines the start and end date
49    * remove_old - deletes old retrieved grib files
50    * do_retrievement - creates individual retrievals
51
52Type: get_mars_data.py --help
53to get information about command line parameters.
54Read the documentation for usage instructions.
55'''
56# ------------------------------------------------------------------------------
57# MODULES
58# ------------------------------------------------------------------------------
59from __future__ import print_function
60
61import os
62import sys
63import inspect
64from datetime import datetime, timedelta
65
66# software specific classes and modules from flex_extract
67# add path to local main python path for flex_extract to get full access
68sys.path.append(os.path.dirname(os.path.abspath(
69    inspect.getfile(inspect.currentframe()))) + '/../')
70import _config
71from mods.tools import (setup_controldata, my_error, normal_exit, get_cmdline_args,
72                   read_ecenv, make_dir)
73from classes.EcFlexpart import EcFlexpart
74from classes.UioFiles import UioFiles
75from classes.MarsRetrieval import MarsRetrieval
76
77try:
78    ec_api = True
79    import ecmwfapi
80except ImportError:
81    ec_api = False
82
83try:
84    cds_api = True
85    import cdsapi
86except ImportError:
87    cds_api = False
88# ------------------------------------------------------------------------------
89# FUNCTION
90# ------------------------------------------------------------------------------
91def main():
92    '''Controls the program to get data out of mars.
93
94    This is done if it is called directly from command line.
95    Then it also takes program call arguments and control file input.
96
97    Parameters
98    ----------
99
100    Return
101    ------
102
103    '''
104
105    c, _, _, _ = setup_controldata()
106    get_mars_data(c)
107    normal_exit('Retrieving MARS data: Done!')
108
109    return
110
111def get_mars_data(c):
112    '''Retrieves the EC data needed for a FLEXPART simulation.
113
114    Start and end dates for retrieval period is set. Retrievals
115    are divided into smaller periods if necessary and datechunk parameter
116    is set.
117
118    Parameters
119    ----------
120    c : ControlFile
121        Contains all the parameters of CONTROL file and
122        command line.
123
124    Return
125    ------
126
127    '''
128    c.ec_api = ec_api
129    c.cds_api = cds_api
130
131    if not os.path.exists(c.inputdir):
132        make_dir(c.inputdir)
133
134    if c.request == 0:
135        print("Retrieving EC data!")
136    else:
137        if c.request == 1:
138            print("Printing mars requests!")
139        elif c.request == 2:
140            print("Retrieving EC data and printing mars request!")
141        write_reqheader(os.path.join(c.inputdir, _config.FILE_MARS_REQUESTS))
142
143    print("start date %s " % (c.start_date))
144    print("end date %s " % (c.end_date))
145
146    server = mk_server(c)
147
148    # if data are to be retrieved, clean up any old grib files
149    if c.request == 0 or c.request == 2:
150        remove_old('*grb', c.inputdir)
151
152    # --------------  flux data ------------------------------------------------
153    start, end, datechunk = mk_dates(c, fluxes=True)
154    do_retrievement(c, server, start, end, datechunk, fluxes=True)
155
156    # --------------  non flux data --------------------------------------------
157    start, end, datechunk = mk_dates(c, fluxes=False)
158    do_retrievement(c, server, start, end, datechunk, fluxes=False)
159
160    return
161
162def write_reqheader(marsfile):
163    '''Writes header with column names into mars request file.
164
165    Parameters
166    ----------
167    marsfile : str
168        Path to the mars request file.
169
170    Return
171    ------
172
173    '''
174    MR = MarsRetrieval(None, None)
175    attrs = vars(MR).copy()
176    del attrs['server']
177    del attrs['public']
178    with open(marsfile, 'w') as f:
179        f.write('request_number' + ', ')
180        f.write(', '.join(str(key) for key in sorted(attrs.keys())))
181        f.write('\n')
182
183    return
184
185def mk_server(c):
186    '''Creates a server connection with available python API.
187
188    Which API is used depends on availability and the dataset to be retrieved.
189    The CDS API is used for ERA5 dataset no matter if the user is a member or
190    a public user. ECMWF WebAPI is used for all other available datasets.
191
192    Parameters
193    ----------
194    c : ControlFile
195        Contains all the parameters of CONTROL file and
196        command line.
197
198    Return
199    ------
200    server : ECMWFDataServer, ECMWFService or Client
201        Connection to ECMWF server via python interface ECMWF WebAPI or CDS API.
202
203    '''
204    if cds_api and (c.marsclass.upper() == 'EA'):
205        server = cdsapi.Client()
206        c.ec_api = False
207    elif c.ec_api:
208        if c.public:
209            server = ecmwfapi.ECMWFDataServer()
210        else:
211            server = ecmwfapi.ECMWFService("mars")
212        c.cds_api = False
213    else:
214        server = False
215
216    print('Using ECMWF WebAPI: ' + str(c.ec_api))
217    print('Using CDS API: ' + str(c.cds_api))
218
219    return server
220
221
222def check_dates_for_nonflux_fc_times(types, times):
223    '''
224    '''
225    for ty, ti in zip(types,times):
226        if ty.upper() == 'FC' and int(ti) == 18:
227            return True
228    return False
229
230
231def mk_dates(c, fluxes):
232    '''Prepares start and end date depending on flux or non flux data.
233
234    If forecast for maximum one day (upto 24h) are to be retrieved, then
235    collect accumulation data (flux data) with additional days in the
236    beginning and at the end (used for complete disaggregation of
237    original period)
238
239    If forecast data longer than 24h are to be retrieved, then
240    collect accumulation data (flux data) with the exact start and end date
241    (disaggregation will be done for the exact time period with
242    boundary conditions)
243
244    Since for basetime the extraction contains the 12 hours upfront,
245    if basetime is 0, the starting date has to be the day before and
246
247    Parameters
248    ----------
249    c : ControlFile
250        Contains all the parameters of CONTROL file and
251        command line.
252
253    fluxes : boolean, optional
254        Decides if the flux parameter settings are stored or
255        the rest of the parameter list.
256        Default value is False.
257
258    Return
259    ------
260    start : datetime
261        The start date of the retrieving data set.
262
263    end : datetime
264        The end date of the retrieving data set.
265
266    chunk : datetime
267        Time period in days for one single mars retrieval.
268
269    '''
270    start = datetime.strptime(c.start_date, '%Y%m%d')
271    end = datetime.strptime(c.end_date, '%Y%m%d')
272    chunk = timedelta(days=int(c.date_chunk))
273
274    if c.basetime == 0:
275        start = start - timedelta(days=1)
276
277    if c.purefc and fluxes and c.maxstep < 24:
278        start = start - timedelta(days=1)
279        end = end + timedelta(days=1)
280
281    if not c.purefc and fluxes and not c.basetime == 0:
282        start = start - timedelta(days=1)
283        end = end + timedelta(days=1)
284
285    # if we have non-flux forecast data starting at 18 UTC
286    # we need to start retrieving data one day in advance
287    if not fluxes and check_dates_for_nonflux_fc_times(c.type, c.time):
288        start = start - timedelta(days=1)
289
290    return start, end, chunk
291
292def remove_old(pattern, inputdir):
293    '''Deletes old retrieval files from current input directory
294    matching the pattern.
295
296    Parameters
297    ----------
298    pattern : str
299        The sub string pattern which identifies the files to be deleted.
300
301    inputdir : str, optional
302        Path to the directory where the retrieved data is stored.
303
304    Return
305    ------
306
307    '''
308    print('... removing old content of ' + inputdir)
309
310    tobecleaned = UioFiles(inputdir, pattern)
311    tobecleaned.delete_files()
312
313    return
314
315
316def do_retrievement(c, server, start, end, delta_t, fluxes=False):
317    '''Divides the complete retrieval period in smaller chunks and
318    retrieves the data from MARS.
319
320    Parameters
321    ----------
322    c : ControlFile
323        Contains all the parameters of CONTROL file and
324        command line.
325
326    server : ECMWFService or ECMWFDataServer
327            The server connection to ECMWF.
328
329    start : datetime
330        The start date of the retrieval.
331
332    end : datetime
333        The end date of the retrieval.
334
335    delta_t : datetime
336        Delta_t + 1 is the maximal time period of a single
337        retrieval.
338
339    fluxes : boolean, optional
340        Decides if the flux parameters are to be retrieved or
341        the rest of the parameter list.
342        Default value is False.
343
344    Return
345    ------
346
347    '''
348
349    # since actual day also counts as one day,
350    # we only need to add datechunk - 1 days to retrieval
351    # for a period
352    delta_t_m1 = delta_t - timedelta(days=1)
353
354    day = start
355    while day <= end:
356        flexpart = EcFlexpart(c, fluxes)
357        tmpday = day + delta_t_m1
358        if tmpday < end:
359            dates = day.strftime("%Y%m%d") + "/to/" + \
360                    tmpday.strftime("%Y%m%d")
361        else:
362            dates = day.strftime("%Y%m%d") + "/to/" + \
363                    end.strftime("%Y%m%d")
364
365        print("... retrieve " + dates + " in dir " + c.inputdir)
366
367        try:
368            flexpart.retrieve(server, dates, c.public, c.request, c.inputdir)
369        except IOError:
370            my_error('MARS request failed')
371
372        day += delta_t
373
374    return
375
376if __name__ == "__main__":
377    main()
Note: See TracBrowser for help on using the repository browser.
hosted by ZAMG