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
RevLine 
[7e25255]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# ------------------------------------------------------------------------------
[7e25255]59from __future__ import print_function
60
[991df6a]61import os
62import sys
63import inspect
[ca867de]64from datetime import datetime, timedelta
[ff99eae]65
66# software specific classes and modules from flex_extract
[6f951ca]67# add path to local main python path for flex_extract to get full access
[70fee58]68sys.path.append(os.path.dirname(os.path.abspath(
69    inspect.getfile(inspect.currentframe()))) + '/../')
[2fb99de]70import _config
[d727af2]71from mods.tools import (setup_controldata, my_error, normal_exit, get_cmdline_args,
[5bad6ec]72                   read_ecenv, make_dir)
[25b14be]73from classes.EcFlexpart import EcFlexpart
74from classes.UioFiles import UioFiles
[403cbf1]75from classes.MarsRetrieval import MarsRetrieval
[ca867de]76
77try:
[f20af73]78    ec_api = True
[ca867de]79    import ecmwfapi
80except ImportError:
[f20af73]81    ec_api = False
82
83try:
84    cds_api = True
85    import cdsapi
86except ImportError:
87    cds_api = False
[efdb01a]88# ------------------------------------------------------------------------------
89# FUNCTION
90# ------------------------------------------------------------------------------
[991df6a]91def main():
[274f9ef]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.
[295ff45]96
[274f9ef]97    Parameters
98    ----------
[991df6a]99
[274f9ef]100    Return
101    ------
[991df6a]102
103    '''
[54a8a01]104
[f20af73]105    c, _, _, _ = setup_controldata()
[ff99eae]106    get_mars_data(c)
[f20af73]107    normal_exit('Retrieving MARS data: Done!')
[d69b677]108
[991df6a]109    return
110
[ff99eae]111def get_mars_data(c):
[274f9ef]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    ----------
[6f951ca]120    c : ControlFile
[274f9ef]121        Contains all the parameters of CONTROL file and
122        command line.
123
124    Return
125    ------
126
[991df6a]127    '''
[f20af73]128    c.ec_api = ec_api
129    c.cds_api = cds_api
[d69b677]130
131    if not os.path.exists(c.inputdir):
[5bad6ec]132        make_dir(c.inputdir)
[991df6a]133
[403cbf1]134    if c.request == 0:
[2fb99de]135        print("Retrieving EC data!")
[403cbf1]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!")
[631ba13]141        write_reqheader(os.path.join(c.inputdir, _config.FILE_MARS_REQUESTS))
[2fb99de]142
143    print("start date %s " % (c.start_date))
144    print("end date %s " % (c.end_date))
[d69b677]145
[631ba13]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:
[1d15e27]150        remove_old('*grb', c.inputdir)
[631ba13]151
152    # --------------  flux data ------------------------------------------------
[45c6337]153    start, end, datechunk = mk_dates(c, fluxes=True)
[631ba13]154    do_retrievement(c, server, start, end, datechunk, fluxes=True)
155
156    # --------------  non flux data --------------------------------------------
[45c6337]157    start, end, datechunk = mk_dates(c, fluxes=False)
[631ba13]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    ----------
[6f951ca]167    marsfile : str
[631ba13]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' + ', ')
[79729d5]180        f.write(', '.join(str(key) for key in sorted(attrs.keys())))
[631ba13]181        f.write('\n')
182
183    return
184
185def mk_server(c):
[f20af73]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.
[631ba13]191
192    Parameters
193    ----------
[6f951ca]194    c : ControlFile
[631ba13]195        Contains all the parameters of CONTROL file and
196        command line.
197
198    Return
199    ------
[f20af73]200    server : ECMWFDataServer, ECMWFService or Client
201        Connection to ECMWF server via python interface ECMWF WebAPI or CDS API.
[631ba13]202
203    '''
[f20af73]204    if cds_api and (c.marsclass.upper() == 'EA'):
205        server = cdsapi.Client()
206        c.ec_api = False
207    elif c.ec_api:
[5bad6ec]208        if c.public:
209            server = ecmwfapi.ECMWFDataServer()
210        else:
211            server = ecmwfapi.ECMWFService("mars")
[f20af73]212        c.cds_api = False
[d69b677]213    else:
214        server = False
215
[f20af73]216    print('Using ECMWF WebAPI: ' + str(c.ec_api))
217    print('Using CDS API: ' + str(c.cds_api))
[991df6a]218
[631ba13]219    return server
[54a8a01]220
221
[45b99e6]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
[631ba13]231def mk_dates(c, fluxes):
232    '''Prepares start and end date depending on flux or non flux data.
[54a8a01]233
[631ba13]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)
[54a8a01]238
[631ba13]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    ----------
[6f951ca]249    c : ControlFile
[631ba13]250        Contains all the parameters of CONTROL file and
251        command line.
252
[6f951ca]253    fluxes : boolean, optional
[631ba13]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    ------
[6f951ca]260    start : datetime
[631ba13]261        The start date of the retrieving data set.
262
[6f951ca]263    end : datetime
[631ba13]264        The end date of the retrieving data set.
265
[6f951ca]266    chunk : datetime
[631ba13]267        Time period in days for one single mars retrieval.
268
269    '''
[ca867de]270    start = datetime.strptime(c.start_date, '%Y%m%d')
271    end = datetime.strptime(c.end_date, '%Y%m%d')
[631ba13]272    chunk = timedelta(days=int(c.date_chunk))
273
[d4696e0]274    if c.basetime == 0:
275        start = start - timedelta(days=1)
[efdb01a]276
[7e25255]277    if c.purefc and fluxes and c.maxstep < 24:
278        start = start - timedelta(days=1)
279        end = end + timedelta(days=1)
280
[d4696e0]281    if not c.purefc and fluxes and not c.basetime == 0:
[ca867de]282        start = start - timedelta(days=1)
[631ba13]283        end = end + timedelta(days=1)
[ca867de]284
[45b99e6]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
[631ba13]290    return start, end, chunk
[54a8a01]291
[1d15e27]292def remove_old(pattern, inputdir):
[3f36e42]293    '''Deletes old retrieval files from current input directory
294    matching the pattern.
[54a8a01]295
[631ba13]296    Parameters
297    ----------
[6f951ca]298    pattern : str
[631ba13]299        The sub string pattern which identifies the files to be deleted.
[991df6a]300
[6f951ca]301    inputdir : str, optional
[1d15e27]302        Path to the directory where the retrieved data is stored.
303
[631ba13]304    Return
305    ------
[991df6a]306
[631ba13]307    '''
[1d15e27]308    print('... removing old content of ' + inputdir)
[631ba13]309
[1d15e27]310    tobecleaned = UioFiles(inputdir, pattern)
[631ba13]311    tobecleaned.delete_files()
[54a8a01]312
313    return
314
[631ba13]315
[54a8a01]316def do_retrievement(c, server, start, end, delta_t, fluxes=False):
[274f9ef]317    '''Divides the complete retrieval period in smaller chunks and
318    retrieves the data from MARS.
319
320    Parameters
321    ----------
[6f951ca]322    c : ControlFile
[274f9ef]323        Contains all the parameters of CONTROL file and
324        command line.
[54a8a01]325
[6f951ca]326    server : ECMWFService or ECMWFDataServer
[274f9ef]327            The server connection to ECMWF.
[54a8a01]328
[6f951ca]329    start : datetime
[274f9ef]330        The start date of the retrieval.
[54a8a01]331
[6f951ca]332    end : datetime
[274f9ef]333        The end date of the retrieval.
[54a8a01]334
[6f951ca]335    delta_t : datetime
[274f9ef]336        Delta_t + 1 is the maximal time period of a single
337        retrieval.
[54a8a01]338
[6f951ca]339    fluxes : boolean, optional
[274f9ef]340        Decides if the flux parameters are to be retrieved or
341        the rest of the parameter list.
342        Default value is False.
[54a8a01]343
[274f9ef]344    Return
345    ------
[54a8a01]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
[ca867de]352    delta_t_m1 = delta_t - timedelta(days=1)
[54a8a01]353
[efdb01a]354    day = start
355    while day <= end:
[54a8a01]356        flexpart = EcFlexpart(c, fluxes)
357        tmpday = day + delta_t_m1
[ff99eae]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")
[efdb01a]364
[2fb99de]365        print("... retrieve " + dates + " in dir " + c.inputdir)
[64cf353]366
[ff99eae]367        try:
[5bad6ec]368            flexpart.retrieve(server, dates, c.public, c.request, c.inputdir)
[ff99eae]369        except IOError:
[f20af73]370            my_error('MARS request failed')
[efdb01a]371
[54a8a01]372        day += delta_t
[64cf353]373
[efdb01a]374    return
[d69b677]375
376if __name__ == "__main__":
[991df6a]377    main()
Note: See TracBrowser for help on using the repository browser.
hosted by ZAMG