source: flex_extract.git/source/python/classes/MarsRetrieval.py @ 2625ca8

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

removed unneeded function

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