source: flex_extract.git/source/python/classes/MarsRetrieval.py @ b957ef7

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

python2 downgrade/ manually select EMOSLIB instead of MIR

  • Property mode set to 100644
File size: 20.3 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#        - optimized display_info
12#        - optimized data_retrieve and seperate between python and shell
13#          script call
14#
15#   February 2018 - Anne Philipp (University of Vienna):
16#        - applied PEP8 style guide
17#        - added documentation
18#        - applied some minor modifications in programming style/structure
19#        - added writing of mars request attributes to a csv file
20#
21# @License:
22#    (C) Copyright 2014-2019.
23#    Anne Philipp, Leopold Haimberger
24#
25#    This work is licensed under the Creative Commons Attribution 4.0
26#    International License. To view a copy of this license, visit
27#    http://creativecommons.org/licenses/by/4.0/ or send a letter to
28#    Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
29#*******************************************************************************
30
31# ------------------------------------------------------------------------------
32# MODULES
33# ------------------------------------------------------------------------------
34from __future__ import print_function
35
36import os
37import sys
38import subprocess
39import traceback
40
41# software specific classes and modules from flex_extract
42sys.path.append('../')
43import _config
44try:
45    ec_api = True
46    import ecmwfapi
47except ImportError:
48    ec_api = False
49
50try:
51    cds_api = True
52    import cdsapi
53except ImportError:
54    cds_api = False
55# ------------------------------------------------------------------------------
56# CLASS
57# ------------------------------------------------------------------------------
58class MarsRetrieval(object):
59    '''Specific syntax and content for submission of MARS retrievals.
60
61    A MARS revtrieval has a specific syntax with a selection of keywords and
62    their corresponding values. This class provides the necessary functions
63    by displaying the selected parameters and their values and the actual
64    retrievement of the data through a mars request or a Python web api
65    interface. The initialization already expects all the keyword values.
66
67    A description of MARS keywords/arguments and examples of their
68    values can be found here:
69    https://software.ecmwf.int/wiki/display/UDOC/\
70                   Identification+keywords#Identificationkeywords-class
71
72    Attributes
73    ----------
74    server : ECMWFService or ECMWFDataServer
75        This is the connection to the ECMWF data servers.
76
77    public : int
78        Decides which Web API Server version is used.
79
80    marsclass : str, optional
81        Characterisation of dataset.
82
83    dataset : str, optional
84        For public datasets there is the specific naming and parameter
85        dataset which has to be used to characterize the type of
86        data.
87
88    type : str, optional
89        Determines the type of fields to be retrieved.
90
91    levtype : str, optional
92        Denotes type of level.
93
94    levelist : str, optional
95        Specifies the required levels.
96
97    repres : str, optional
98        Selects the representation of the archived data.
99
100    date : str, optional
101        Specifies the Analysis date, the Forecast base date or
102        Observations date.
103
104    resol : str, optional
105        Specifies the desired triangular truncation of retrieved data,
106        before carrying out any other selected post-processing.
107
108    stream : str, optional
109        Identifies the forecasting system used to generate the data.
110
111    area : str, optional
112        Specifies the desired sub-area of data to be extracted.
113
114    time : str, optional
115        Specifies the time of the data in hours and minutes.
116
117    step : str, optional
118        Specifies the forecast time step from forecast base time.
119
120    expver : str, optional
121        The version of the dataset.
122
123    number : str, optional
124        Selects the member in ensemble forecast run.
125
126    accuracy : str, optional
127        Specifies the number of bits per value to be used in the
128        generated GRIB coded fields.
129
130    grid : str, optional
131        Specifies the output grid which can be either a Gaussian grid
132        or a Latitude/Longitude grid.
133
134    gaussian : str, optional
135        This parameter is deprecated and should no longer be used.
136        Specifies the desired type of Gaussian grid for the output.
137
138    target : str, optional
139        Specifies a file into which data is to be written after
140        retrieval or manipulation.
141
142    param : str, optional
143        Specifies the meteorological parameter.
144    '''
145
146    def __init__(self, server, public, marsclass="EA", dataset="", type="",
147                 levtype="", levelist="", repres="", date="", resol="",
148                 stream="", area="", time="", step="", expver="1",
149                 number="", accuracy="", grid="", gaussian="", target="",
150                 param=""):
151        '''Initialises the instance of the MarsRetrieval class and
152        defines and assigns a set of the necessary retrieval parameters
153        for the FLEXPART input data.
154        A description of MARS keywords/arguments, their dependencies
155        on each other and examples of their values can be found here:
156
157        https://software.ecmwf.int/wiki/display/UDOC/MARS+keywords
158
159        Parameters
160        ----------
161        server : ECMWFService or ECMWFDataServer
162            This is the connection to the ECMWF data servers.
163            It is needed for the pythonic access of ECMWF data.
164
165        public : int
166            Decides which Web API version is used:
167            0: member-state users and full archive access
168            1: public access and limited access to the public server and
169               datasets. Needs the parameter dataset.
170            Default is "0" and for member-state users.
171
172        marsclass : str, optional
173            Characterisation of dataset. E.g. EI (ERA-Interim),
174            E4 (ERA40), OD (Operational archive), EA (ERA5).
175            Default is the ERA5 dataset "EA".
176
177        dataset : str, optional
178            For public datasets there is the specific naming and parameter
179            dataset which has to be used to characterize the type of
180            data. Usually there is less data available, either in times,
181            domain or parameter.
182            Default is an empty string.
183
184        type : str, optional
185            Determines the type of fields to be retrieved.
186            Selects between observations, images or fields.
187            Examples for fields: Analysis (an), Forecast (fc),
188            Perturbed Forecast (pf), Control Forecast (cf) and so on.
189            Default is an empty string.
190
191        levtype : str, optional
192            Denotes type of level. Has a direct implication on valid
193            levelist values!
194            E.g. model level (ml), pressure level (pl), surface (sfc),
195            potential vorticity (pv), potential temperature (pt)
196            and depth (dp).
197            Default is an empty string.
198
199        levelist : str, optional
200            Specifies the required levels. It has to have a valid
201            correspondence to the selected levtype.
202            Examples: model level: 1/to/137, pressure levels: 500/to/1000
203            Default is an empty string.
204
205        repres : str, optional
206            Selects the representation of the archived data.
207            E.g. sh - spherical harmonics, gg - Gaussian grid,
208            ll - latitude/longitude, ...
209            Default is an empty string.
210
211        date : str, optional
212            Specifies the Analysis date, the Forecast base date or
213            Observations date. Valid formats are:
214            Absolute as YYYY-MM-DD or YYYYMMDD.
215            Default is an empty string.
216
217        resol : str, optional
218            Specifies the desired triangular truncation of retrieved data,
219            before carrying out any other selected post-processing.
220            The default is automatic truncation (auto), by which the lowest
221            resolution compatible with the value specified in grid is
222            automatically selected for the retrieval.
223            Users wanting to perform post-processing from full spectral
224            resolution should specify Archived Value (av).
225            The following are examples of existing resolutions found in
226            the archive: 63, 106, 159, 213, 255, 319, 399, 511, 799 or 1279.
227            This keyword has no meaning/effect if the archived data is
228            not in spherical harmonics representation.
229            The best selection can be found here:
230            https://software.ecmwf.int/wiki/display/UDOC/\
231                  Retrieve#Retrieve-Truncationbeforeinterpolation
232            Default is an empty string.
233
234        stream : str, optional
235            Identifies the forecasting system used to generate the data.
236            E.g. oper (Atmospheric model), enfo (Ensemble forecats), ...
237            Default is an empty string.
238
239        area : str, optional
240            Specifies the desired sub-area of data to be extracted.
241            Areas can be defined to wrap around the globe.
242
243            Latitude values must be given as signed numbers, with:
244                north latitudes (i.e. north of the equator)
245                    being positive (e.g: 40.5)
246                south latitutes (i.e. south of the equator)
247                    being negative (e.g: -50.5)
248            Longtitude values must be given as signed numbers, with:
249                east longitudes (i.e. east of the 0 degree meridian)
250                    being positive (e.g: 35.0)
251                west longitudes (i.e. west of the 0 degree meridian)
252                    being negative (e.g: -20.5)
253
254            E.g.: North/West/South/East
255            Default is an empty string.
256
257        time : str, optional
258            Specifies the time of the data in hours and minutes.
259            Valid values depend on the type of data: Analysis time,
260            Forecast base time or First guess verification time
261            (all usually at synoptic hours: 00, 06, 12 and 18 ).
262            Observation time (any combination in hours and minutes is valid,
263            subject to data availability in the archive).
264            The syntax is HHMM or HH:MM. If MM is omitted it defaults to 00.
265            Default is an empty string.
266
267        step : str, optional
268            Specifies the forecast time step from forecast base time.
269            Valid values are hours (HH) from forecast base time. It also
270            specifies the length of the forecast which verifies at
271            First Guess time.
272            E.g. 1/3/6-hourly
273            Default is an empty string.
274
275        expver : str, optional
276            The version of the dataset. Each experiment is assigned a
277            unique code (version). Production data is assigned 1 or 2,
278            and experimental data in Operations 11, 12 ,...
279            Research or Member State's experiments have a four letter
280            experiment identifier.
281            Default is "1".
282
283        number : str, optional
284            Selects the member in ensemble forecast run. (Only then it
285            is necessary.) It has a different meaning depending on
286            the type of data.
287            E.g. Perturbed Forecasts: specifies the Ensemble forecast member
288            Default is an empty string.
289
290        accuracy : str, optional
291            Specifies the number of bits per value to be used in the
292            generated GRIB coded fields.
293            A positive integer may be given to specify the preferred number
294            of bits per packed value. This must not be greater than the
295            number of bits normally used for a Fortran integer on the
296            processor handling the request (typically 32 or 64 bit).
297            Within a compute request the accuracy of the original fields
298            can be passed to the result field by specifying accuracy=av.
299            Default is an empty string.
300
301        grid : str, optional
302            Specifies the output grid which can be either a Gaussian grid
303            or a Latitude/Longitude grid. MARS requests specifying
304            grid=av will return the archived model grid.
305
306            Lat/Lon grid: The grid spacing needs to be an integer
307            fraction of 90 degrees e.g. grid = 0.5/0.5
308
309            Gaussian grid: specified by a letter denoting the type of
310            Gaussian grid followed by an integer (the grid number)
311            representing the number of lines between the Pole and Equator,
312            e.g.
313            grid = F160 - full (or regular) Gaussian grid with
314                   160 latitude lines between the pole and equator
315            grid = N320 - ECMWF original reduced Gaussian grid with
316                   320 latitude lines between the pole and equator,
317                   see Reduced Gaussian Grids for grid numbers used at ECMWF
318            grid = O640 - ECMWF octahedral (reduced) Gaussian grid with
319                   640 latitude lines between the pole and equator
320            Default is an empty string.
321
322        gaussian : str, optional
323            This parameter is deprecated and should no longer be used.
324            Specifies the desired type of Gaussian grid for the output.
325            Valid Gaussian grids are quasi-regular (reduced) or regular.
326            Keyword gaussian can only be specified together with
327            keyword grid. Gaussian without grid has no effect.
328            Default is an empty string.
329
330        target : str, optional
331            Specifies a file into which data is to be written after
332            retrieval or manipulation. Path names should always be
333            enclosed in double quotes. The MARS client supports automatic
334            generation of multiple target files using MARS keywords
335            enclosed in square brackets [ ].  If the environment variable
336            MARS_MULTITARGET_STRICT_FORMAT is set to 1 before calling mars,
337            the keyword values will be used in the filename as shown by
338            the ecCodes GRIB tool grib_ls -m, e.g. with
339            MARS_MULTITARGET_STRICT_FORMAT set to 1 the keywords time,
340            expver and param will be formatted as 0600, 0001 and 129.128
341            rather than 600, 1 and 129.
342            Default is an empty string.
343
344        param : str, optional
345            Specifies the meteorological parameter.
346            The list of meteorological parameters in MARS is extensive.
347            Their availability is directly related to their meteorological
348            meaning and, therefore, the rest of directives specified
349            in the MARS request.
350            Meteorological parameters can be specified by their
351            GRIB code (param=130), their mnemonic (param=t) or
352            full name (param=temperature).
353            The list of parameter should be seperated by a "/"-sign.
354            E.g. 130/131/133
355            Default is an empty string.
356
357        Return
358        ------
359
360        '''
361
362        self.server = server
363        self.public = public
364        self.marsclass = marsclass
365        self.dataset = dataset
366        self.type = type
367        self.levtype = levtype
368        self.levelist = levelist
369        self.repres = repres
370        self.date = date
371        self.resol = resol
372        self.stream = stream
373        self.area = area
374        self.time = time
375        self.step = step
376        self.expver = expver
377        self.number = number
378        self.accuracy = accuracy
379        self.grid = grid
380        self.gaussian = gaussian
381        self.target = target
382        self.param = param
383
384        return
385
386
387    def display_info(self):
388        '''Prints all class attributes and their values to the
389        standard output.
390
391        Parameters
392        ----------
393
394        Return
395        ------
396
397        '''
398        # Get all class attributes and their values as a dictionary
399        attrs = vars(self).copy()
400
401        # iterate through all attributes and print them
402        # with their corresponding values
403        for item in attrs.items():
404            if item[0] in ['server', 'public']:
405                pass
406            else:
407                print(item[0] + ': ' + str(item[1]))
408
409        return
410
411
412    def print_infodata_csv(self, inputdir, request_number):
413        '''Write all request parameter in alpabetical order into a "csv" file.
414
415        Parameters
416        ----------
417        inputdir : str
418            The path where all data from the retrievals are stored.
419
420        request_number : int
421            Number of mars requests for flux and non-flux data.
422
423        Return
424        ------
425
426        '''
427
428        # Get all class attributes and their values as a dictionary
429        attrs = vars(self).copy()
430        del attrs['server']
431        del attrs['public']
432
433        # open a file to store all requests to
434        with open(os.path.join(inputdir,
435                               _config.FILE_MARS_REQUESTS), 'a') as f:
436            f.write(str(request_number) + ', ')
437            f.write(', '.join(str(attrs[key])
438                              for key in sorted(attrs.keys())))
439            f.write('\n')
440
441        return
442
443    def data_retrieve(self):
444        '''Submits a MARS retrieval. Depending on the existence of
445        ECMWF Web-API or CDS API it is submitted via Python or a
446        subprocess in the Shell. The parameter for the mars retrieval
447        are taken from the defined class attributes.
448
449        Parameters
450        ----------
451
452        Return
453        ------
454
455        '''
456        # Get all class attributes and their values as a dictionary
457        attrs = vars(self).copy()
458
459        # eliminate unnecessary attributes from the dictionary attrs
460        del attrs['server']
461        del attrs['public']
462
463        # exchange parameter name for marsclass
464        mclass = attrs.get('marsclass')
465        del attrs['marsclass']
466        attrs['class'] = mclass
467
468        # prepare target variable as needed for the Web API or CDS API mode
469        # within the dictionary for full access
470        # as a single variable for public access
471        target = attrs.get('target')
472        if not int(self.public):
473            del attrs['target']
474        print('target: ' + target)
475
476        # find all keys without a value and convert all other values to strings
477        empty_keys = []
478        for key, value in attrs.items():
479            if value == '':
480                empty_keys.append(str(key))
481            else:
482                attrs[key] = str(value)
483
484        # delete all empty parameter from the dictionary
485        for key in empty_keys:
486            del attrs[key]
487
488        attrs['ppengine'] = 'emos'
489
490        # MARS request via Python script
491        if self.server:
492            try:
493                if cds_api and isinstance(self.server, cdsapi.Client):
494                    print('RETRIEVE ERA5 WITH CDS API!')
495                    self.server.retrieve(_config.CDS_DATASET,
496                                         attrs, target)
497                elif ec_api and isinstance(self.server, ecmwfapi.ECMWFDataServer):
498                    print('RETRIEVE PUBLIC DATA (NOT ERA5)!')
499                    self.server.retrieve(attrs)
500                elif ec_api and isinstance(self.server, ecmwfapi.ECMWFService):
501                    print('EXECUTE NON-PUBLIC RETRIEVAL (NOT ERA5)!')
502                    self.server.execute(attrs, target)
503                else:
504                    print('ERROR:')
505                    print('No match for Web API instance!')
506                    raise IOError
507            except Exception as e:
508                print('\n\nMARS Request failed!')
509                print(e)
510                tb = sys.exc_info()[2]
511                print(traceback.format_exc())
512                sys.exit()
513
514        # MARS request via call in shell
515        else:
516            request_str = 'ret'
517            for key, value in attrs.items():
518                request_str = request_str + ',' + key + '=' + str(value)
519            request_str += ',target="' + target + '"'
520            p = subprocess.Popen(['mars', '-e'],
521                                 stdin=subprocess.PIPE,
522                                 stdout=subprocess.PIPE,
523                                 stderr=subprocess.PIPE,
524                                 bufsize=1)
525            pout = p.communicate(input=request_str.encode())[0]
526            print(pout.decode())
527
528            if 'Some errors reported' in pout.decode():
529                print('MARS Request failed - please check request')
530                raise IOError
531            elif os.stat(target).st_size == 0:
532                print('MARS Request returned no data - please check request')
533                raise IOError
534
535        return
Note: See TracBrowser for help on using the repository browser.
hosted by ZAMG