Changeset 54a8a01 in flex_extract.git for python/ControlFile.py


Ignore:
Timestamp:
Aug 31, 2018, 7:50:37 AM (6 years ago)
Author:
Anne Philipp <anne.philipp@…>
Branches:
master, ctbto, dev
Children:
597d4d1
Parents:
e1228f3
Message:

restructuring, documentations and bug fixes

File:
1 edited

Legend:

Unmodified
Added
Removed
  • python/ControlFile.py

    re1228f3 r54a8a01  
    11#!/usr/bin/env python
    22# -*- coding: utf-8 -*-
    3 #************************************************************************
    4 # ToDo AP
    5 # - write a test class
    6 #************************************************************************
    73#*******************************************************************************
    84# @Author: Leopold Haimberger (University of Vienna)
     
    1915#          self-explanation naming
    2016#        - 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
    2121#
    2222# @License:
     
    3636# @Class Content:
    3737#    - __init__
     38#    - __read_controlfile__
    3839#    - __str__
     40#    - assign_args_to_control
     41#    - assign_envs_to_control
     42#    - check_conditions
     43#    - check_install_conditions
    3944#    - to_list
    4045#
    4146# @Class Attributes:
    42 #    - start_date
    43 #    - end_date
    44 #    - accuracy
    45 #    - omega
    46 #    - cwc
    47 #    - omegadiff
    48 #    - etadiff
    49 #    - level
    50 #    - levelist
    51 #    - step
    52 #    - maxstep
    53 #    - prefix
    54 #    - makefile
    55 #    - basetime
    56 #    - date_chunk
    57 #    - grib2flexpart
    58 #    - exedir
    59 #    - flexpart_root_scripts
    60 #    - ecmwfdatadir
     47#
    6148#
    6249#*******************************************************************************
     
    6653# ------------------------------------------------------------------------------
    6754import os
     55import sys
    6856import inspect
    6957
     
    9280        '''
    9381        @Description:
    94             Initialises the instance of ControlFile class and defines and
    95             assign all CONTROL file variables. Set default values if
    96             parameter was not in CONTROL file.
     82            Initialises the instance of ControlFile class and defines
     83            all class attributes with default values. Afterwards calls
     84            function __read_controlfile__ to read parameter from
     85            Control file.
    9786
    9887        @Input:
     
    10695            <nothing>
    10796        '''
     97
     98        # list of all possible class attributes and their default values
     99        self.controlfile = filename
     100        self.start_date = None
     101        self.end_date = None
     102        self.date_chunk = 3
     103        self.dtime = None
     104        self.basetime = None
     105        self.maxstep = None
     106        self.type = None
     107        self.time = None
     108        self.step = None
     109        self.marsclass = None
     110        self.stream = None
     111        self.number = 'OFF'
     112        self.expver = None
     113        self.grid = None
     114        self.area = ''
     115        self.left = None
     116        self.lower = None
     117        self.upper = None
     118        self.right = None
     119        self.level = None
     120        self.levelist = None
     121        self.resol = None
     122        self.gauss = 0
     123        self.accuracy = 24
     124        self.omega = 0
     125        self.omegadiff = 0
     126        self.eta = 0
     127        self.etadiff = 0
     128        self.etapar = 77
     129        self.dpdeta = 1
     130        self.smooth = 0
     131        self.format = 'GRIB1'
     132        self.addpar = None
     133        self.prefix = 'EN'
     134        self.cwc = 0
     135        self.wrf = 0
     136        self.ecfsdir = 'ectmp:/${USER}/econdemand/'
     137        self.mailfail = ['${USER}']
     138        self.mailops = ['${USER}']
     139        self.grib2flexpart = 0
     140        self.ecstorage = 0
     141        self.ectrans = 0
     142        self.inputdir = '../work'
     143        self.outputdir = self.inputdir
     144        self.ecmwfdatadir = None
     145        self.exedir = None
     146        self.flexpart_root_scripts = None
     147        self.makefile = None
     148        self.destination = None
     149        self.gateway = None
     150        self.ecuid = None
     151        self.ecgid = None
     152        self.install_target = None
     153        self.debug = 0
     154
     155        self.__read_controlfile__()
     156
     157        return
     158
     159    def __read_controlfile__(self):
     160        '''
     161        @Description:
     162            Read CONTROL file and assign all CONTROL file variables.
     163
     164        @Input:
     165            self: instance of ControlFile class
     166                Description see class documentation.
     167
     168        @Return:
     169            <nothing>
     170        '''
    108171        from tools import my_error
    109172
    110173        # read whole CONTROL file
    111         with open(filename) as f:
     174        with open(self.controlfile) as f:
    112175            fdata = f.read().split('\n')
    113176
    114177        # go through every line and store parameter
    115         # as class variable
    116178        for ldata in fdata:
    117179            data = ldata.split()
     
    145207                                data[1] = data[1][:i] + var + data[1][k+1:]
    146208                            else:
    147                                 my_error(None, 'Could not find variable ' +
    148                                          data[1][j+1:k] + ' while reading ' +
    149                                          filename)
     209                                my_error(self.mailfail,
     210                                         'Could not find variable '
     211                                         + data[1][j+1:k] + ' while reading ' +
     212                                         self.controlfile)
    150213                        setattr(self, data[0].lower() + '_expanded', data[1])
    151214                    else:
     
    159222                pass
    160223
    161         # check a couple of necessary attributes if they contain values
    162         # otherwise set default values
    163         if not hasattr(self, 'start_date'):
    164             self.start_date = None
    165         if not hasattr(self, 'end_date'):
     224        # script directory
     225        self.ecmwfdatadir = os.path.dirname(os.path.abspath(inspect.getfile(
     226            inspect.currentframe()))) + '/../'
     227
     228        # Fortran source directory
     229        self.exedir = self.ecmwfdatadir + 'src/'
     230
     231        return
     232
     233    def __str__(self):
     234        '''
     235        @Description:
     236            Prepares a string which have all the ControlFile
     237            class attributes with its associated values.
     238            Each attribute is printed in one line and in
     239            alphabetical order.
     240
     241            Example:
     242            'age': 10
     243            'color': 'Spotted'
     244            'kids': 0
     245            'legs': 2
     246            'name': 'Dog'
     247            'smell': 'Alot'
     248
     249        @Input:
     250            self: instance of ControlFile class
     251                Description see class documentation.
     252
     253        @Return:
     254            string of ControlFile class attributes with their values
     255        '''
     256        import collections
     257
     258        attrs = vars(self)
     259        attrs = collections.OrderedDict(sorted(attrs.items()))
     260
     261        return '\n'.join("%s: %s" % item for item in attrs.items())
     262
     263    def assign_args_to_control(self, args):
     264        '''
     265        @Description:
     266            Overwrites the existing ControlFile instance attributes with
     267            the command line arguments.
     268
     269        @Input:
     270            self: instance of ControlFile class
     271                Description see class documentation.
     272
     273            args: instance of ArgumentParser
     274                Contains the commandline arguments from script/program call.
     275
     276        @Return:
     277            <nothing>
     278        '''
     279
     280        # get dictionary of command line parameters and eliminate all
     281        # parameters which are None (were not specified)
     282        args_dict = vars(args)
     283        arguments = {k : args_dict[k] for k in args_dict
     284                     if args_dict[k] != None}
     285
     286        # assign all passed command line arguments to ControlFile instance
     287        for k, v in arguments.iteritems():
     288            setattr(self, str(k), v)
     289
     290        return
     291
     292    def assign_envs_to_control(self, envs):
     293        '''
     294        @Description:
     295            Assigns the ECMWF environment parameter.
     296
     297        @Input:
     298            envs: dict of strings
     299                Contains the ECMWF environment parameternames "ECUID", "ECGID",
     300                "DESTINATION" and "GATEWAY" with its corresponding values.
     301                They were read from the file "ECMWF_ENV".
     302
     303        @Return:
     304            <nothing>
     305        '''
     306
     307        for k, v in envs.iteritems():
     308            setattr(self, str(k).lower(), str(v))
     309
     310        return
     311
     312    def check_conditions(self):
     313        '''
     314        @Description:
     315            Checks a couple of necessary attributes and conditions,
     316            such as if they exist and contain values.
     317            Otherwise set default values.
     318
     319        @Input:
     320            self: instance of ControlFile class
     321                Description see class documentation.
     322
     323        @Return:
     324            <nothing>
     325        '''
     326        from tools import my_error
     327        import numpy as np
     328
     329        # check for having at least a starting date
     330        # otherwise program is not allowed to run
     331        if self.start_date is None:
     332            print 'start_date specified neither in command line nor ' + \
     333                  'in CONTROL file ' +  self.controlfile
     334            print 'Try "' + sys.argv[0].split('/')[-1] + \
     335                  ' -h" to print usage information'
     336            sys.exit(1)
     337
     338        # retrieve just one day if end_date isn't set
     339        if self.end_date is None:
    166340            self.end_date = self.start_date
    167         if not hasattr(self, 'accuracy'):
    168             self.accuracy = 24
    169         if not hasattr(self, 'omega'):
    170             self.omega = '0'
    171         if not hasattr(self, 'cwc'):
    172             self.cwc = '0'
    173         if not hasattr(self, 'omegadiff'):
    174             self.omegadiff = '0'
    175         if not hasattr(self, 'etadiff'):
    176             self.etadiff = '0'
    177         if not hasattr(self, 'levelist'):
    178             if not hasattr(self, 'level'):
    179                 print 'Warning: neither levelist nor level \
    180                        specified in CONTROL file'
     341
     342        # assure consistency of levelist and level
     343        if self.levelist is None:
     344            if self.level is None:
     345                print 'Warning: neither levelist nor level ' + \
     346                      'specified in CONTROL file'
     347                sys.exit(1)
    181348            else:
    182349                self.levelist = '1/to/' + self.level
    183350        else:
    184             if 'to' in self.levelist:
     351            if 'to' in self.levelist.lower():
    185352                self.level = self.levelist.split('/')[2]
    186353            else:
    187354                self.level = self.levelist.split('/')[-1]
    188355
    189         if not hasattr(self, 'maxstep'):
    190             # find out maximum step
     356        # if area was provided at command line
     357        # decompse area into its 4 components
     358        if self.area:
     359            afloat = '.' in self.area
     360            l = self.area.split('/')
     361            if afloat:
     362                for i, item in enumerate(l):
     363                    item = str(int(float(item) * 1000))
     364            self.upper, self.left, self.lower, self.right = l
     365
     366        # prepare step for correct usage
     367        if '/' in self.step:
     368            l = self.step.split('/')
     369            if 'to' in self.step.lower():
     370                if 'by' in self.step.lower():
     371                    ilist = np.arange(int(l[0]), int(l[2]) + 1, int(l[4]))
     372                    self.step = ['{:0>3}'.format(i) for i in ilist]
     373                else:
     374                    my_error(self.mailfail, self.step + ':\n' +
     375                             'if "to" is used, please use "by" as well')
     376            else:
     377                self.step = l
     378
     379        # if maxstep wasn't provided
     380        # search for it in the "step" parameter
     381        if self.maxstep is None:
    191382            self.maxstep = 0
    192383            for s in self.step:
     
    196387            self.maxstep = int(self.maxstep)
    197388
    198         if not hasattr(self, 'prefix'):
    199             self.prefix = 'EN'
    200         if not hasattr(self, 'makefile'):
    201             self.makefile = None
    202         if not hasattr(self, 'basetime'):
    203             self.basetime = None
    204         if not hasattr(self, 'date_chunk'):
    205             self.date_chunk = '3'
    206         if not hasattr(self, 'grib2flexpart'):
    207             self.grib2flexpart = '0'
    208 
    209         # script directory
    210         self.ecmwfdatadir = os.path.dirname(os.path.abspath(inspect.getfile(
    211             inspect.currentframe()))) + '/../'
    212         # Fortran source directory
    213         self.exedir = self.ecmwfdatadir + 'src/'
    214 
    215         # FLEXPART directory
    216         if not hasattr(self, 'flexpart_root_scripts'):
     389        # set root scripts since it is needed later on
     390        if not self.flexpart_root_scripts:
    217391            self.flexpart_root_scripts = self.ecmwfdatadir
    218392
     393        if not isinstance(self.mailfail, list):
     394            if ',' in self.mailfail:
     395                self.mailfail = self.mailfail.split(',')
     396            elif ' ' in self.mailfail:
     397                self.mailfail = self.mailfail.split()
     398            else:
     399                self.mailfail = [self.mailfail]
     400
     401        if not isinstance(self.mailops, list):
     402            if ',' in self.mailops:
     403                self.mailops = self.mailops.split(',')
     404            elif ' ' in self.mailops:
     405                self.mailops = self.mailops.split()
     406            else:
     407                self.mailops = [self.mailops]
     408
     409        if not self.gateway or not self.destination or \
     410           not self.ecuid or not self.ecgid:
     411            print '\nEnvironment variables GATWAY, DESTINATION, ECUID and ' + \
     412                  'ECGID were not set properly!'
     413            print 'Please check for excistence of file "ECMWF_ENV" in the ' + \
     414                  'python directory!'
     415            sys.exit(1)
     416
    219417        return
    220418
    221     def __str__(self):
    222         '''
    223         @Description:
    224             Prepares a single string with all the comma seperated ControlFile
    225             class attributes including their values.
    226 
    227             Example:
    228             {'kids': 0, 'name': 'Dog', 'color': 'Spotted',
    229              'age': 10, 'legs': 2, 'smell': 'Alot'}
    230 
    231         @Input:
    232             self: instance of ControlFile class
    233                 Description see class documentation.
    234 
    235         @Return:
    236             string of ControlFile class attributes with their values
    237         '''
    238 
    239         attrs = vars(self)
    240 
    241         return ', '.join("%s: %s" % item for item in attrs.items())
     419    def check_install_conditions(self):
     420        '''
     421        @Description:
     422            Checks a couple of necessary attributes and conditions
     423            for the installation such as if they exist and contain values.
     424            Otherwise set default values.
     425
     426        @Input:
     427            self: instance of ControlFile class
     428                Description see class documentation.
     429
     430        @Return:
     431            <nothing>
     432        '''
     433
     434        if self.install_target and \
     435           self.install_target not in ['local', 'ecgate', 'cca']:
     436            print 'ERROR: unknown or missing installation target '
     437            print 'target: ', self.install_target
     438            print 'please specify correct installation target \
     439                   (local | ecgate | cca)'
     440            print 'use -h or --help for help'
     441            sys.exit(1)
     442
     443        if self.install_target and self.install_target != 'local':
     444            if not self.ecgid or not self.ecuid or \
     445               not self.gateway or not self.destination:
     446                print 'Please enter your ECMWF user id and group id as well as \
     447                       the \nname of the local gateway and the ectrans \
     448                       destination '
     449                print 'with command line options --ecuid --ecgid \
     450                       --gateway --destination'
     451                print 'Try "' + sys.argv[0].split('/')[-1] + \
     452                      ' -h" to print usage information'
     453                print 'Please consult ecaccess documentation or ECMWF user \
     454                       support for further details'
     455                sys.exit(1)
     456
     457            if not self.flexpart_root_scripts:
     458                self.flexpart_root_scripts = '${HOME}'
     459            else:
     460                self.flexpart_root_scripts = self.flexpart_root_scripts
     461        else:
     462            if not self.flexpart_root_scripts:
     463                self.flexpart_root_scripts = '../'
     464
     465        if not self.makefile:
     466            self.makefile = 'Makefile.gfortran'
     467
     468        return
    242469
    243470    def to_list(self):
     
    259486        '''
    260487
    261         attrs = vars(self)
     488        import collections
     489
     490        attrs = collections.OrderedDict(sorted(vars(self).items()))
     491
    262492        l = list()
    263493
     
    283513        return sorted(l)
    284514
    285     # def to_dict(self):
    286         # '''
    287 
    288         # '''
    289         # parameters_dict = vars(self)
    290 
    291         # # remove unneeded parameter
    292         # parameters_dict.pop('_expanded', None)
    293         # parameters_dict.pop('exedir', None)
    294         # parameters_dict.pop('flexpart_root_scripts', None)
    295         # parameters_dict.pop('ecmwfdatadir', None)
    296 
    297         # parameters_dict_str = {}
    298         # for key, value in parameters_dict.iteritems():
    299             # if isinstance(value, list):
    300                 # parameters_dict_str[str(key)] = get_list_as_string(value, ' ')
    301             # else:
    302                 # parameters_dict_str[str(key)] = str(value)
    303 
    304         # return parameters_dict_str
Note: See TracChangeset for help on using the changeset viewer.
hosted by ZAMG