source: flex_extract.git/source/python/mods/get_mars_data.py @ 45b99e6

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

added possibility to extract ensemble members with ELDA stream (and ENFO)

  • Property mode set to 100755
File size: 10.5 KB
RevLine 
[d69b677]1#!/usr/bin/env python
[efdb01a]2# -*- coding: utf-8 -*-
[991df6a]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):
[ff99eae]11#        - moved the getEIdata program into a function "get_mars_data"
[991df6a]12#        - moved the AgurmentParser into a seperate function
13#        - adatpted the function for the use in flex_extract
[ff99eae]14#        - renamed file to get_mars_data
[991df6a]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
[6f951ca]24#        - seperated get_mars_data function into several smaller pieces:
25#          write_reqheader, mk_server, mk_dates, remove_old, do_retrievment
[991df6a]26#
27# @License:
[6f951ca]28#    (C) Copyright 2014-2019.
29#    Anne Philipp, Leopold Haimberger
[991df6a]30#
[6f951ca]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.
[991df6a]35#*******************************************************************************
[6f951ca]36'''This script extracts MARS data from ECMWF servers.
[96e1533]37
[6f951ca]38At first, the necessary parameters from command line and CONTROL files are
39extracted. They define the data set to be extracted from MARS.
[96e1533]40
41This file can also be imported as a module and contains the following
42functions:
43
44    * main - the main function of the script
[6f951ca]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'''
[efdb01a]56# ------------------------------------------------------------------------------
57# MODULES
58# ------------------------------------------------------------------------------
[991df6a]59import os
60import sys
61import inspect
[ca867de]62from datetime import datetime, timedelta
[ff99eae]63
64# software specific classes and modules from flex_extract
[6f951ca]65# add path to local main python path for flex_extract to get full access
[70fee58]66sys.path.append(os.path.dirname(os.path.abspath(
67    inspect.getfile(inspect.currentframe()))) + '/../')
[2fb99de]68import _config
[9aefaad]69from tools import (my_error, normal_exit, get_cmdline_args,
[5bad6ec]70                   read_ecenv, make_dir)
[25b14be]71from classes.EcFlexpart import EcFlexpart
72from classes.UioFiles import UioFiles
[403cbf1]73from classes.MarsRetrieval import MarsRetrieval
[ca867de]74
75try:
76    ecapi = True
77    import ecmwfapi
78except ImportError:
79    ecapi = False
[efdb01a]80# ------------------------------------------------------------------------------
81# FUNCTION
82# ------------------------------------------------------------------------------
[991df6a]83def main():
[274f9ef]84    '''Controls the program to get data out of mars.
85
86    This is done if it is called directly from command line.
87    Then it also takes program call arguments and control file input.
[295ff45]88
[274f9ef]89    Parameters
90    ----------
[991df6a]91
[274f9ef]92    Return
93    ------
[991df6a]94
95    '''
[54a8a01]96
[9aefaad]97    args = get_cmdline_args()
[4971f63]98    c = ControlFile(args.controlfile)
[54a8a01]99
[2fb99de]100    env_parameter = read_ecenv(_config.PATH_ECMWF_ENV)
[295ff45]101    c.assign_args_to_control(args)
[54a8a01]102    c.assign_envs_to_control(env_parameter)
[2fb99de]103    c.check_conditions(args.queue)
[54a8a01]104
[ff99eae]105    get_mars_data(c)
[96e1533]106    normal_exit(c.mailops, c.queue, 'Done!')
[d69b677]107
[991df6a]108    return
109
[ff99eae]110def get_mars_data(c):
[274f9ef]111    '''Retrieves the EC data needed for a FLEXPART simulation.
112
113    Start and end dates for retrieval period is set. Retrievals
114    are divided into smaller periods if necessary and datechunk parameter
115    is set.
116
117    Parameters
118    ----------
[6f951ca]119    c : ControlFile
[274f9ef]120        Contains all the parameters of CONTROL file and
121        command line.
122
123    Return
124    ------
125
[991df6a]126    '''
[631ba13]127    c.ecapi = ecapi
[d69b677]128
129    if not os.path.exists(c.inputdir):
[5bad6ec]130        make_dir(c.inputdir)
[991df6a]131
[403cbf1]132    if c.request == 0:
[2fb99de]133        print("Retrieving EC data!")
[403cbf1]134    else:
135        if c.request == 1:
136            print("Printing mars requests!")
137        elif c.request == 2:
138            print("Retrieving EC data and printing mars request!")
[631ba13]139        write_reqheader(os.path.join(c.inputdir, _config.FILE_MARS_REQUESTS))
[2fb99de]140
141    print("start date %s " % (c.start_date))
142    print("end date %s " % (c.end_date))
[d69b677]143
[631ba13]144    server = mk_server(c)
145
146    # if data are to be retrieved, clean up any old grib files
147    if c.request == 0 or c.request == 2:
[1d15e27]148        remove_old('*grb', c.inputdir)
[631ba13]149
150    # --------------  flux data ------------------------------------------------
[45c6337]151    start, end, datechunk = mk_dates(c, fluxes=True)
[631ba13]152    do_retrievement(c, server, start, end, datechunk, fluxes=True)
153
154    # --------------  non flux data --------------------------------------------
[45c6337]155    start, end, datechunk = mk_dates(c, fluxes=False)
[631ba13]156    do_retrievement(c, server, start, end, datechunk, fluxes=False)
157
158    return
159
160def write_reqheader(marsfile):
161    '''Writes header with column names into mars request file.
162
163    Parameters
164    ----------
[6f951ca]165    marsfile : str
[631ba13]166        Path to the mars request file.
167
168    Return
169    ------
170
171    '''
172    MR = MarsRetrieval(None, None)
173    attrs = vars(MR).copy()
174    del attrs['server']
175    del attrs['public']
176    with open(marsfile, 'w') as f:
177        f.write('request_number' + ', ')
178        f.write(', '.join(str(key) for key in sorted(attrs.iterkeys())))
179        f.write('\n')
180
181    return
182
183def mk_server(c):
184    '''Creates server connection if ECMWF WebAPI is available.
185
186    Parameters
187    ----------
[6f951ca]188    c : ControlFile
[631ba13]189        Contains all the parameters of CONTROL file and
190        command line.
191
192    Return
193    ------
[6f951ca]194    server : ECMWFDataServer or ECMWFService
[631ba13]195        Connection to ECMWF server via python interface ECMWF WebAPI.
196
197    '''
198    if c.ecapi:
[5bad6ec]199        if c.public:
200            server = ecmwfapi.ECMWFDataServer()
201        else:
202            server = ecmwfapi.ECMWFService("mars")
[d69b677]203    else:
204        server = False
205
[2fb99de]206    print('Using ECMWF WebAPI: ' + str(c.ecapi))
[991df6a]207
[631ba13]208    return server
[54a8a01]209
210
[45b99e6]211def check_dates_for_nonflux_fc_times(types, times):
212    '''
213    '''
214    for ty, ti in zip(types,times):
215        if ty.upper() == 'FC' and int(ti) == 18:
216            return True
217    return False
218
219
[631ba13]220def mk_dates(c, fluxes):
221    '''Prepares start and end date depending on flux or non flux data.
[54a8a01]222
[631ba13]223    If forecast for maximum one day (upto 24h) are to be retrieved, then
224    collect accumulation data (flux data) with additional days in the
225    beginning and at the end (used for complete disaggregation of
226    original period)
[54a8a01]227
[631ba13]228    If forecast data longer than 24h are to be retrieved, then
229    collect accumulation data (flux data) with the exact start and end date
230    (disaggregation will be done for the exact time period with
231    boundary conditions)
232
233    Since for basetime the extraction contains the 12 hours upfront,
234    if basetime is 0, the starting date has to be the day before and
235
236    Parameters
237    ----------
[6f951ca]238    c : ControlFile
[631ba13]239        Contains all the parameters of CONTROL file and
240        command line.
241
[6f951ca]242    fluxes : boolean, optional
[631ba13]243        Decides if the flux parameter settings are stored or
244        the rest of the parameter list.
245        Default value is False.
246
247    Return
248    ------
[6f951ca]249    start : datetime
[631ba13]250        The start date of the retrieving data set.
251
[6f951ca]252    end : datetime
[631ba13]253        The end date of the retrieving data set.
254
[6f951ca]255    chunk : datetime
[631ba13]256        Time period in days for one single mars retrieval.
257
258    '''
[ca867de]259    start = datetime.strptime(c.start_date, '%Y%m%d')
260    end = datetime.strptime(c.end_date, '%Y%m%d')
[631ba13]261    chunk = timedelta(days=int(c.date_chunk))
262
[d4696e0]263    if c.basetime == 0:
264        start = start - timedelta(days=1)
[efdb01a]265
[d4696e0]266    if not c.purefc and fluxes and not c.basetime == 0:
[ca867de]267        start = start - timedelta(days=1)
[631ba13]268        end = end + timedelta(days=1)
[ca867de]269
[45b99e6]270    # if we have non-flux forecast data starting at 18 UTC
271    # we need to start retrieving data one day in advance
272    if not fluxes and check_dates_for_nonflux_fc_times(c.type, c.time):
273        start = start - timedelta(days=1)
274
[631ba13]275    return start, end, chunk
[54a8a01]276
[1d15e27]277def remove_old(pattern, inputdir):
[3f36e42]278    '''Deletes old retrieval files from current input directory
279    matching the pattern.
[54a8a01]280
[631ba13]281    Parameters
282    ----------
[6f951ca]283    pattern : str
[631ba13]284        The sub string pattern which identifies the files to be deleted.
[991df6a]285
[6f951ca]286    inputdir : str, optional
[1d15e27]287        Path to the directory where the retrieved data is stored.
288
[631ba13]289    Return
290    ------
[991df6a]291
[631ba13]292    '''
[1d15e27]293    print('... removing old content of ' + inputdir)
[631ba13]294
[1d15e27]295    tobecleaned = UioFiles(inputdir, pattern)
[631ba13]296    tobecleaned.delete_files()
[54a8a01]297
298    return
299
[631ba13]300
[54a8a01]301def do_retrievement(c, server, start, end, delta_t, fluxes=False):
[274f9ef]302    '''Divides the complete retrieval period in smaller chunks and
303    retrieves the data from MARS.
304
305    Parameters
306    ----------
[6f951ca]307    c : ControlFile
[274f9ef]308        Contains all the parameters of CONTROL file and
309        command line.
[54a8a01]310
[6f951ca]311    server : ECMWFService or ECMWFDataServer
[274f9ef]312            The server connection to ECMWF.
[54a8a01]313
[6f951ca]314    start : datetime
[274f9ef]315        The start date of the retrieval.
[54a8a01]316
[6f951ca]317    end : datetime
[274f9ef]318        The end date of the retrieval.
[54a8a01]319
[6f951ca]320    delta_t : datetime
[274f9ef]321        Delta_t + 1 is the maximal time period of a single
322        retrieval.
[54a8a01]323
[6f951ca]324    fluxes : boolean, optional
[274f9ef]325        Decides if the flux parameters are to be retrieved or
326        the rest of the parameter list.
327        Default value is False.
[54a8a01]328
[274f9ef]329    Return
330    ------
[54a8a01]331
332    '''
333
334    # since actual day also counts as one day,
335    # we only need to add datechunk - 1 days to retrieval
336    # for a period
[ca867de]337    delta_t_m1 = delta_t - timedelta(days=1)
[54a8a01]338
[efdb01a]339    day = start
340    while day <= end:
[54a8a01]341        flexpart = EcFlexpart(c, fluxes)
342        tmpday = day + delta_t_m1
[ff99eae]343        if tmpday < end:
344            dates = day.strftime("%Y%m%d") + "/to/" + \
345                    tmpday.strftime("%Y%m%d")
346        else:
347            dates = day.strftime("%Y%m%d") + "/to/" + \
348                    end.strftime("%Y%m%d")
[efdb01a]349
[2fb99de]350        print("... retrieve " + dates + " in dir " + c.inputdir)
[64cf353]351
[ff99eae]352        try:
[5bad6ec]353            flexpart.retrieve(server, dates, c.public, c.request, c.inputdir)
[ff99eae]354        except IOError:
[54a8a01]355            my_error(c.mailfail, 'MARS request failed')
[efdb01a]356
[54a8a01]357        day += delta_t
[64cf353]358
[efdb01a]359    return
[d69b677]360
361if __name__ == "__main__":
[991df6a]362    main()
Note: See TracBrowser for help on using the repository browser.
hosted by ZAMG