source: flex_extract.git/source/python/classes/ControlFile.py @ 87ae9a3

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

added possibility to write comments with '#' in to CONTROL files, either single lines with starting '#' or in the same line after parameter values

  • Property mode set to 100644
File size: 13.8 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#*******************************************************************************
4# @Author: Leopold Haimberger (University of Vienna)
5#
6# @Date: November 2015
7#
8# @Change History:
9#
10#   February 2018 - Anne Philipp (University of Vienna):
11#        - applied PEP8 style guide
12#        - added documentation
13#        - applied some minor modifications in programming style/structure
14#        - changed name of class Control to ControlFile for more
15#          self-explanation naming
16#        - outsource of class ControlFile
17#        - initialisation of class attributes ( to avoid high number of
18#          conditional statements and set default values )
19#        - divided assignment of attributes and the check of conditions
20#        - outsourced the commandline argument assignments to control attributes
21#
22# @License:
23#    (C) Copyright 2015-2018.
24#
25#    This software is licensed under the terms of the Apache Licence Version 2.0
26#    which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
27#
28# @Class Description:
29#    The CONTROL file is the steering part of the FLEXPART extraction
30#    software. All necessary parameters needed to retrieve the data fields
31#    from the MARS archive for driving FLEXPART are set in a CONTROL file.
32#    Some specific parameters like the start and end dates can be overwritten
33#    by the command line parameters, but in generel all parameters needed
34#    for a complete set of fields for FLEXPART can be set in the CONTROL file.
35#
36# @Class Content:
37#    - __init__
38#    - __read_controlfile__
39#    - __str__
40#    - assign_args_to_control
41#    - assign_envs_to_control
42#    - check_conditions
43#    - check_install_conditions
44#    - to_list
45#
46# @Class Attributes:
47#
48#
49#*******************************************************************************
50
51# ------------------------------------------------------------------------------
52# MODULES
53# ------------------------------------------------------------------------------
54import os
55import re
56import sys
57import inspect
58import numpy as np
59
60# software specific classes and modules from flex_extract
61sys.path.append('../')
62import _config
63from mods.tools import my_error, silent_remove
64from mods.checks import (check_grid, check_area, check_levels, check_purefc,
65                         check_step, check_mail, check_queue, check_pathes,
66                         check_dates, check_maxstep, check_type, check_request,
67                         check_basetime, check_public, check_acctype,
68                         check_acctime, check_accmaxstep, check_time,
69                         check_logicals_type, check_len_type_time_step,
70                         check_addpar)
71
72# ------------------------------------------------------------------------------
73# CLASS
74# ------------------------------------------------------------------------------
75class ControlFile(object):
76    '''
77    Contains the information which are stored in the CONTROL files.
78    '''
79
80    def __init__(self, filename):
81        '''Initialises the instance of ControlFile class and defines
82        all class attributes with default values. Afterwards calls
83        function __read_controlfile__ to read parameter from Control file.
84
85        Parameters
86        ----------
87        filename : :obj:`string`
88            Name of CONTROL file.
89
90        Return
91        ------
92
93        '''
94
95        # list of all possible class attributes and their default values
96        self.controlfile = filename
97        self.start_date = None
98        self.end_date = None
99        self.date_chunk = 3
100        self.dtime = None
101        self.basetime = None
102        self.maxstep = None
103        self.type = None
104        self.time = None
105        self.step = None
106        self.acctype = None
107        self.acctime = None
108        self.accmaxstep = None
109        self.marsclass = None
110        self.dataset = None
111        self.stream = None
112        self.number = 'OFF'
113        self.expver = '1'
114        self.gaussian = ''
115        self.grid = None
116        self.area = ''
117        self.left = None
118        self.lower = None
119        self.upper = None
120        self.right = None
121        self.level = None
122        self.levelist = None
123        self.resol = None
124        self.gauss = 0
125        self.accuracy = 24
126        self.omega = 0
127        self.omegadiff = 0
128        self.eta = 0
129        self.etadiff = 0
130        self.etapar = 77
131        self.dpdeta = 1
132        self.smooth = 0
133        self.format = 'GRIB1'
134        self.addpar = None
135        self.prefix = 'EN'
136        self.cwc = 0
137        self.wrf = 0
138        self.ecfsdir = 'ectmp:/${USER}/econdemand/'
139        self.mailfail = ['${USER}']
140        self.mailops = ['${USER}']
141        self.grib2flexpart = 0
142        self.ecstorage = 0
143        self.ectrans = 0
144        self.inputdir = _config.PATH_INPUT_DIR
145        self.outputdir = None
146        self.flexextractdir = _config.PATH_FLEXEXTRACT_DIR
147        self.exedir = _config.PATH_FORTRAN_SRC
148        self.flexpartdir = None
149        self.makefile = 'Makefile.gfortran'
150        self.destination = None
151        self.gateway = None
152        self.ecuid = None
153        self.ecgid = None
154        self.install_target = None
155        self.debug = 0
156        self.request = 0
157        self.public = 0
158        self.ecapi = None
159        self.purefc = 0
160        self.rrint = 0
161
162        self.logicals = ['gauss', 'omega', 'omegadiff', 'eta', 'etadiff',
163                         'dpdeta', 'cwc', 'wrf', 'grib2flexpart', 'ecstorage',
164                         'ectrans', 'debug', 'request', 'public', 'purefc',
165                         'rrint']
166
167        self._read_controlfile()
168
169        return
170
171    def _read_controlfile(self):
172        '''Read CONTROL file and assign all CONTROL file variables.
173
174        Parameters
175        ----------
176
177        Return
178        ------
179
180        '''
181
182        try:
183            cfile = os.path.join(_config.PATH_CONTROLFILES, self.controlfile)
184            with open(cfile) as f:
185                fdata = f.read().split('\n')
186        except IOError:
187            print('Could not read CONTROL file "' + cfile + '"')
188            print('Either it does not exist or its syntax is wrong.')
189            print('Try "' + sys.argv[0].split('/')[-1] + \
190                      ' -h" to print usage information')
191            sys.exit(1)
192
193        # go through every line and store parameter
194        for ldata in fdata:
195            if ldata and ldata[0] == '#':
196                # ignore comment line in control file
197                continue
198            if '#' in ldata:
199                # cut off comment
200                ldata = ldata.split('#')[0]
201            data = ldata.split()
202            if len(data) > 1:
203                if 'm_' in data[0].lower():
204                    data[0] = data[0][2:]
205                if data[0].lower() == 'class':
206                    data[0] = 'marsclass'
207                if data[0].lower() == 'day1':
208                    data[0] = 'start_date'
209                if data[0].lower() == 'day2':
210                    data[0] = 'end_date'
211                if len(data) == 2:
212                    if '$' in data[1]:
213                        setattr(self, data[0].lower(), data[1])
214                        while '$' in data[1]:
215                            i = data[1].index('$')
216                            j = data[1].find('{')
217                            k = data[1].find('}')
218                            var = os.getenv(data[1][j+1:k])
219                            if var is not None:
220                                data[1] = data[1][:i] + var + data[1][k+1:]
221                            else:
222                                my_error(self.mailfail,
223                                         'Could not find variable '
224                                         + data[1][j+1:k] + ' while reading ' +
225                                         self.controlfile)
226                        setattr(self, data[0].lower() + '_expanded', data[1])
227                    else:
228                        if data[1].lower() != 'none':
229                            setattr(self, data[0].lower(), data[1])
230                        else:
231                            setattr(self, data[0].lower(), None)
232                elif len(data) > 2:
233                    setattr(self, data[0].lower(), (data[1:]))
234            else:
235                pass
236
237        return
238
239    def __str__(self):
240        '''Prepares a string which have all the ControlFile class attributes
241        with its associated values. Each attribute is printed in one line and
242        in alphabetical order.
243
244        Example
245        -------
246        'age': 10
247        'color': 'Spotted'
248        'kids': 0
249        'legs': 2
250        'name': 'Dog'
251        'smell': 'Alot'
252
253        Parameters
254        ----------
255
256        Return
257        ------
258        string
259            Single string of concatenated ControlFile class attributes
260            with their values
261        '''
262        import collections
263
264        attrs = vars(self).copy()
265        attrs = collections.OrderedDict(sorted(attrs.items()))
266
267        return '\n'.join("%s: %s" % item for item in attrs.items())
268
269    def assign_args_to_control(self, args):
270        '''Overwrites the existing ControlFile instance attributes with
271        the command line arguments.
272
273        Parameters
274        ----------
275        args : :obj:`Namespace`
276            Contains the commandline arguments from script/program call.
277
278        Return
279        ------
280
281        '''
282
283        # get dictionary of command line parameters and eliminate all
284        # parameters which are None (were not specified)
285        args_dict = vars(args)
286        arguments = {k : args_dict[k] for k in args_dict
287                     if args_dict[k] != None}
288
289        # assign all passed command line arguments to ControlFile instance
290        for k, v in arguments.iteritems():
291            setattr(self, str(k), v)
292
293        return
294
295    def assign_envs_to_control(self, envs):
296        '''Assigns the ECMWF environment parameter.
297
298        Parameters
299        ----------
300        envs : :obj:`dictionary` of :obj:`strings`
301            Contains the ECMWF environment parameternames "ECUID", "ECGID",
302            "DESTINATION" and "GATEWAY" with its corresponding values.
303            They were read from the file "ECMWF_ENV".
304
305        Return
306        ------
307
308        '''
309
310        for k, v in envs.iteritems():
311            setattr(self, str(k).lower(), str(v))
312
313        return
314
315    def check_conditions(self, queue):
316        '''Checks a couple of necessary attributes and conditions,
317        such as if they exist and contain values.
318        Otherwise set default values.
319
320        Parameters
321        ----------
322        queue : :obj:`string`
323            Name of the queue if submitted to the ECMWF servers.
324            Used to check if ecuid, ecgid, gateway and destination
325            are set correctly and are not empty.
326
327        Return
328        ------
329
330        '''
331        check_logicals_type(self, self.logicals)
332
333        self.mailfail = check_mail(self.mailfail)
334
335        self.mailops = check_mail(self.mailops)
336
337        check_queue(queue, self.gateway, self.destination,
338                    self.ecuid, self.ecgid)
339
340        self.outputdir, self.flexpartdir = check_pathes(self.inputdir,
341             self.outputdir, self.flexpartdir, self.flexextractdir)
342
343        self.start_date, self.end_date = check_dates(self.start_date,
344                                                     self.end_date)
345
346        check_basetime(self.basetime)
347
348        self.levelist, self.level = check_levels(self.levelist, self.level)
349
350        self.step = check_step(self.step, self.mailfail)
351
352        self.maxstep = check_maxstep(self.maxstep, self.step)
353
354        check_request(self.request,
355                      os.path.join(self.inputdir, _config.FILE_MARS_REQUESTS))
356
357        check_public(self.public, self.dataset)
358
359        self.type = check_type(self.type, self.step)
360
361        self.time = check_time(self.time)
362
363        self.type, self.time, self.step = check_len_type_time_step(self.type,
364                                                                   self.time,
365                                                                   self.step,
366                                                                   self.maxstep,
367                                                                   self.purefc)
368
369        self.acctype = check_acctype(self.acctype, self.type)
370
371        self.acctime = check_acctime(self.acctime, self.acctype, self.purefc)
372
373        self.accmaxstep = check_accmaxstep(self.accmaxstep, self.acctype,
374                                           self.purefc, self.maxstep)
375
376        self.purefc = check_purefc(self.type)
377
378        self.grid = check_grid(self.grid)
379
380        self.area = check_area(self.grid, self.area, self.upper, self.lower,
381                               self.left, self.right)
382
383        self.addpar = check_addpar(self.addpar)
384
385
386        return
387
388    def to_list(self):
389        '''Just generates a list of strings containing the attributes and
390        assigned values except the attributes "_expanded", "exedir",
391        "flexextractdir" and "flexpartdir".
392
393        Parameters
394        ----------
395
396        Return
397        ------
398        l : :obj:`list`
399            A sorted list of the all ControlFile class attributes with
400            their values except the attributes "_expanded", "exedir",
401            "flexextractdir" and "flexpartdir".
402        '''
403
404        import collections
405
406        attrs = collections.OrderedDict(sorted(vars(self).copy().items()))
407
408        l = list()
409
410        for item in attrs.items():
411            if '_expanded' in item[0]:
412                pass
413            elif 'exedir' in item[0]:
414                pass
415            elif 'flexpartdir' in item[0]:
416                pass
417            elif 'flexextractdir' in item[0]:
418                pass
419            else:
420                if isinstance(item[1], list):
421                    stot = ''
422                    for s in item[1]:
423                        stot += s + ' '
424
425                    l.append("%s %s\n" % (item[0], stot))
426                else:
427                    l.append("%s %s\n" % item)
428
429        return sorted(l)
430
Note: See TracBrowser for help on using the repository browser.
hosted by ZAMG