source: flex_extract.git/Source/Python/Classes/GribUtil.py @ c77630a

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

BUGFIX: for python3-eccodes the file openings need to be in binary mode! added binary marker in filemode

  • Property mode set to 100644
File size: 10.5 KB
Line 
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#*******************************************************************************
4# @Author: Anne Fouilloux (University of Oslo)
5#
6# @Date: July 2014
7#
8# @Change History:
9#   February 2018 - Anne Philipp (University of Vienna):
10#        - applied PEP8 style guide
11#        - added documentation
12#        - changed some naming
13#
14# @License:
15#    (C) Copyright 2014-2019.
16#    Anne Philipp, Leopold Haimberger
17#
18#    SPDX-License-Identifier: CC-BY-4.0
19#
20#    This work is licensed under the Creative Commons Attribution 4.0
21#    International License. To view a copy of this license, visit
22#    http://creativecommons.org/licenses/by/4.0/ or send a letter to
23#    Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
24#*******************************************************************************
25
26# ------------------------------------------------------------------------------
27# MODULES
28# ------------------------------------------------------------------------------
29from __future__ import print_function
30
31import os
32
33# ------------------------------------------------------------------------------
34# CLASS
35# ------------------------------------------------------------------------------
36class GribUtil(object):
37    '''
38    Class for GRIB utilities (new methods) based on GRIB API
39
40    The GRIB API provides all necessary tools to work directly with the
41    grib files. Nevertheless, the GRIB API tools are very basic and are in
42    direct connection with the grib files. This class provides some higher
43    functions which apply a set of GRIB API tools together in the respective
44    context. So, the class initially contains a list of grib files (their
45    names) and the using program then applies the methods directly on the
46    class objects without having to think about how the actual GRIB API
47    tools have to be arranged.
48    '''
49    # --------------------------------------------------------------------------
50    # CLASS FUNCTIONS
51    # --------------------------------------------------------------------------
52    def __init__(self, filenames):
53        '''Initialise an object of GribUtil and assign a list of filenames.
54
55        Parameters
56        ----------
57        filenames : :obj:`list` of :obj:`strings`
58             A list of filenames.
59
60        Return
61        ------
62
63        '''
64
65        self.filenames = filenames
66
67        return
68
69
70    def get_keys(self, keynames, wherekeynames=[], wherekeyvalues=[]):
71        '''Get keyvalues for a given list of keynames a where statement
72        can be given (list of key and list of values)
73
74        Parameters
75        ----------
76        keynames : :obj:`list` of :obj:`string`
77            List of keynames.
78
79        wherekeynames : :obj:`list` of :obj:`string`, optional
80            Default value is an empty list.
81
82        wherekeyvalues : :obj:`list` of :obj:`string`, optional
83            Default value is an empty list.
84
85        Return
86        ------
87        return_list : :obj:`list` of :obj:`string`
88            List of keyvalues for given keynames.
89        '''
90        from eccodes import (codes_new_from_file, codes_is_defined, codes_get,
91                             codes_release)
92
93        return_list = []
94
95        with open(self.filenames, 'rb') as fileid:
96
97            gid = codes_new_from_file(fileid)
98
99            if len(wherekeynames) != len(wherekeyvalues):
100                raise Exception("Number of key values and key names must be \
101                                 the same. Give a value for each keyname!")
102
103            select = True
104            i = 0
105            for wherekey in wherekeynames:
106                if not codes_is_defined(gid, wherekey):
107                    raise Exception("where key was not defined")
108
109                select = (select and (str(wherekeyvalues[i]) ==
110                                      str(codes_get(gid, wherekey))))
111                i += 1
112
113            if select:
114                llist = []
115                for key in keynames:
116                    llist.extend([str(codes_get(gid, key))])
117                return_list.append(llist)
118
119            codes_release(gid)
120
121        return return_list
122
123
124    def set_keys(self, fromfile, keynames, keyvalues, wherekeynames=[],
125                 wherekeyvalues=[], strict=False, filemode='wb'):
126        '''Opens the file to read the grib messages and then write
127        the selected messages (with wherekeys) to a new output file.
128        Also, the keyvalues of the passed list of keynames are set.
129
130        Parameters
131        ----------
132        fromfile : :obj:`string`
133            Filename of the input file to read the grib messages from.
134
135        keynames : :obj:`list` of :obj:`string`
136            List of keynames to set in the selected messages.
137            Default is an empty list.
138
139        keyvalues : :obj:`list` of :obj:`string`
140            List of keyvalues to set in the selected messages.
141            Default is an empty list.
142
143        wherekeynames : :obj:`list` of :obj:`string`, optional
144            List of keynames to select correct message.
145            Default value is an empty list.
146
147        wherekeyvalues : :obj:`list` of :obj:`string`, optional
148            List of keyvalues for keynames to select correct message.
149            Default value is an empty list.
150
151        strict : :obj:`boolean`, optional
152            Decides if everything from keynames and keyvalues
153            is written out the grib file (False) or only those
154            meeting the where statement (True). Default is False.
155
156        filemode : :obj:`string`, optional
157            Sets the mode for the output file. Default is "wb".
158
159        Return
160        ------
161
162        '''
163        from eccodes import (codes_grib_new_from_file, codes_is_defined,
164                             codes_get, codes_set, codes_write,
165                             codes_set_values, codes_release)
166
167        if len(wherekeynames) != len(wherekeyvalues):
168            raise Exception("Give a value for each keyname!")
169
170        fout = open(self.filenames, filemode)
171
172        with open(fromfile, 'rb') as fin:
173            gid = codes_grib_new_from_file(fin)
174
175            select = True
176            i = 0
177            for wherekey in wherekeynames:
178                if not codes_is_defined(gid, wherekey):
179                    raise Exception("wherekey was not defined")
180
181                select = (select and (str(wherekeyvalues[i]) ==
182                                      str(codes_get(gid, wherekey))))
183                i += 1
184
185            if select:
186                i = 0
187                for key in keynames:
188                    if key == 'values':
189                        codes_set_values(gid, keyvalues[i])
190                    else:
191                        codes_set(gid, key, keyvalues[i])
192                    i += 1
193
194                codes_write(gid, fout)
195
196            codes_release(gid)
197
198        fout.close()
199
200        return
201
202    def copy_dummy_msg(self, filename_in, selectWhere=True,
203                 keynames=[], keyvalues=[], filemode='wb'):
204        '''Add the content of another input grib file to the objects file but
205        only messages corresponding to keys/values passed to the function.
206        The selectWhere switch decides if to copy the keys equal to (True) or
207        different to (False) the keynames/keyvalues list passed to the function.
208
209        Parameters
210        ----------
211        filename_in : :obj:`string`
212            Filename of the input file to read the grib messages from.
213
214        selectWhere : :obj:`boolean`, optional
215            Decides if to copy the keynames and values equal to (True) or
216            different to (False) the keynames/keyvalues list passed to the
217            function. Default is True.
218
219        keynames : :obj:`list` of :obj:`string`, optional
220            List of keynames. Default is an empty list.
221
222        keyvalues : :obj:`list` of :obj:`string`, optional
223            List of keyvalues. Default is an empty list.
224
225        filemode : :obj:`string`, optional
226            Sets the mode for the output file. Default is "wb".
227
228        Return
229        ------
230
231        '''
232        from eccodes import (codes_grib_new_from_file, codes_is_defined,
233                             codes_get, codes_release, codes_write)
234
235        if len(keynames) != len(keyvalues):
236            raise Exception("Give a value for each keyname!")
237
238
239        fout = open(self.filenames, filemode)
240
241        fields = 0
242
243        with open(filename_in, 'rb') as fin:
244            if fields >= 1:
245                fout.close()
246                return
247
248            gid = codes_grib_new_from_file(fin)
249
250            select = True
251            i = 0
252            for key in keynames:
253                if not codes_is_defined(gid, key):
254                    raise Exception("Key was not defined")
255
256                if selectWhere:
257                    select = (select and (str(keyvalues[i]) ==
258                                          str(codes_get(gid, key))))
259                else:
260                    select = (select and (str(keyvalues[i]) !=
261                                          str(codes_get(gid, key))))
262                i += 1
263
264            if select:
265                fields = fields + 1
266                codes_write(gid, fout)
267
268            codes_release(gid)
269
270        fout.close()
271
272        return
273
274    def index(self, index_keys=["mars"], index_file="my.idx"):
275        '''Create index file from a list of files if it does not exist or
276        read an index file.
277
278        Parameters
279        ----------
280        index_keys: :obj:`list` of :obj:`string`, optional
281            Contains the list of key parameter names from
282            which the index is to be created.
283            Default is a list with a single entry string "mars".
284
285        index_file: :obj:`string`, optional
286            Filename where the indices are stored.
287            Default is "my.idx".
288
289        Return
290        ------
291        iid: :obj:`integer`
292            Grib index id.
293        '''
294        from eccodes import (codes_index_read, codes_index_new_from_file,
295                             codes_index_add_file, codes_index_write)
296
297        print("... index will be done")
298        iid = None
299
300        if os.path.exists(index_file):
301            iid = codes_index_read(index_file)
302            print("Use existing index file: %s " % (index_file))
303        else:
304            for filename in self.filenames:
305                print("Inputfile: %s " % (filename))
306                if iid is None:
307                    iid = codes_index_new_from_file(filename, index_keys)
308                else:
309                    codes_index_add_file(iid, filename)
310
311            if iid is not None:
312                codes_index_write(iid, index_file)
313
314        print('... index done')
315
316        return iid
Note: See TracBrowser for help on using the repository browser.
hosted by ZAMG