#!/usr/bin/env python # -*- coding: utf-8 -*- #************************************************************************ # ToDo AP # - write a test class #************************************************************************ #******************************************************************************* # @Author: Leopold Haimberger (University of Vienna) # # @Date: November 2015 # # @Change History: # # February 2018 - Anne Philipp (University of Vienna): # - applied PEP8 style guide # - added documentation # - applied some minor modifications in programming style/structure # - changed name of class Control to ControlFile for more # self-explanation naming # - outsource of class ControlFile # # @License: # (C) Copyright 2015-2018. # # This software is licensed under the terms of the Apache Licence Version 2.0 # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. # # @Class Description: # The CONTROL file is the steering part of the FLEXPART extraction # software. All necessary parameters needed to retrieve the data fields # from the MARS archive for driving FLEXPART are set in a CONTROL file. # Some specific parameters like the start and end dates can be overwritten # by the command line parameters, but in generel all parameters needed # for a complete set of fields for FLEXPART can be set in the CONTROL file. # # @Class Content: # - __init__ # - __str__ # - to_list # # @Class Attributes: # - start_date # - end_date # - accuracy # - omega # - cwc # - omegadiff # - etadiff # - level # - levelist # - step # - maxstep # - prefix # - makefile # - basetime # - date_chunk # - grib2flexpart # - exedir # - flexpart_root_scripts # - ecmwfdatadir # #******************************************************************************* # ------------------------------------------------------------------------------ # MODULES # ------------------------------------------------------------------------------ import os import inspect # software specific module from flex_extract from tools import get_list_as_string, my_error # ------------------------------------------------------------------------------ # CLASS # ------------------------------------------------------------------------------ class ControlFile(object): ''' Class containing the information of the flex_extract CONTROL file. Contains all the parameters of CONTROL file, which are e.g.: DAY1(start_date), DAY2(end_date), DTIME, MAXSTEP, TYPE, TIME, STEP, CLASS(marsclass), STREAM, NUMBER, EXPVER, GRID, LEFT, LOWER, UPPER, RIGHT, LEVEL, LEVELIST, RESOL, GAUSS, ACCURACY, OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA, SMOOTH, FORMAT, ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS, ECFSDIR, MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR, BASETIME, DATE_CHUNK, DEBUG, INPUTDIR, OUTPUTDIR, FLEXPART_ROOT_SCRIPTS For more information about format and content of the parameter see documentation. ''' def __init__(self, filename): ''' @Description: Initialises the instance of ControlFile class and defines and assign all CONTROL file variables. Set default values if parameter was not in CONTROL file. @Input: self: instance of ControlFile class Description see class documentation. filename: string Name of CONTROL file. @Return: ''' # read whole CONTROL file with open(filename) as f: fdata = f.read().split('\n') # go through every line and store parameter # as class variable for ldata in fdata: data = ldata.split() if len(data) > 1: if 'm_' in data[0].lower(): data[0] = data[0][2:] if data[0].lower() == 'class': data[0] = 'marsclass' if data[0].lower() == 'day1': data[0] = 'start_date' if data[0].lower() == 'day2': data[0] = 'end_date' if data[0].lower() == 'addpar': if '/' in data[1]: # remove leading '/' sign from addpar content if data[1][0] == '/': data[1] = data[1][1:] dd = data[1].split('/') data = [data[0]] for d in dd: data.append(d) if len(data) == 2: if '$' in data[1]: setattr(self, data[0].lower(), data[1]) while '$' in data[1]: i = data[1].index('$') j = data[1].find('{') k = data[1].find('}') var = os.getenv(data[1][j+1:k]) if var is not None: data[1] = data[1][:i] + var + data[1][k+1:] else: my_error(None, 'Could not find variable ' + data[1][j+1:k] + ' while reading ' + filename) setattr(self, data[0].lower() + '_expanded', data[1]) else: if data[1].lower() != 'none': setattr(self, data[0].lower(), data[1]) else: setattr(self, data[0].lower(), None) elif len(data) > 2: setattr(self, data[0].lower(), (data[1:])) else: pass # check a couple of necessary attributes if they contain values # otherwise set default values if not hasattr(self, 'start_date'): self.start_date = None if not hasattr(self, 'end_date'): self.end_date = self.start_date if not hasattr(self, 'accuracy'): self.accuracy = 24 if not hasattr(self, 'omega'): self.omega = '0' if not hasattr(self, 'cwc'): self.cwc = '0' if not hasattr(self, 'omegadiff'): self.omegadiff = '0' if not hasattr(self, 'etadiff'): self.etadiff = '0' if not hasattr(self, 'levelist'): if not hasattr(self, 'level'): print 'Warning: neither levelist nor level \ specified in CONTROL file' else: self.levelist = '1/to/' + self.level else: if 'to' in self.levelist: self.level = self.levelist.split('/')[2] else: self.level = self.levelist.split('/')[-1] if not hasattr(self, 'maxstep'): # find out maximum step self.maxstep = 0 for s in self.step: if int(s) > self.maxstep: self.maxstep = int(s) else: self.maxstep = int(self.maxstep) if not hasattr(self, 'prefix'): self.prefix = 'EN' if not hasattr(self, 'makefile'): self.makefile = None if not hasattr(self, 'basetime'): self.basetime = None if not hasattr(self, 'date_chunk'): self.date_chunk = '3' if not hasattr(self, 'grib2flexpart'): self.grib2flexpart = '0' # script directory self.ecmwfdatadir = os.path.dirname(os.path.abspath(inspect.getfile( inspect.currentframe()))) + '/../' # Fortran source directory self.exedir = self.ecmwfdatadir + 'src/' # FLEXPART directory if not hasattr(self, 'flexpart_root_scripts'): self.flexpart_root_scripts = self.ecmwfdatadir return def __str__(self): ''' @Description: Prepares a single string with all the comma seperated ControlFile class attributes including their values. Example: {'kids': 0, 'name': 'Dog', 'color': 'Spotted', 'age': 10, 'legs': 2, 'smell': 'Alot'} @Input: self: instance of ControlFile class Description see class documentation. @Return: string of ControlFile class attributes with their values ''' attrs = vars(self) return ', '.join("%s: %s" % item for item in attrs.items()) def to_list(self): ''' @Description: Just generates a list of strings containing the attributes and assigned values except the attributes "_expanded", "exedir", "ecmwfdatadir" and "flexpart_root_scripts". @Input: self: instance of ControlFile class Description see class documentation. @Return: l: list A sorted list of the all ControlFile class attributes with their values except the attributes "_expanded", "exedir", "ecmwfdatadir" and "flexpart_root_scripts". ''' attrs = vars(self) l = list() for item in attrs.items(): if '_expanded' in item[0]: pass elif 'exedir' in item[0]: pass elif 'flexpart_root_scripts' in item[0]: pass elif 'ecmwfdatadir' in item[0]: pass else: if isinstance(item[1], list): stot = '' for s in item[1]: stot += s + ' ' l.append("%s %s" % (item[0], stot)) else: l.append("%s %s" % item) return sorted(l) # def to_dict(self): # ''' # ''' # parameters_dict = vars(self) # # remove unneeded parameter # parameters_dict.pop('_expanded', None) # parameters_dict.pop('exedir', None) # parameters_dict.pop('flexpart_root_scripts', None) # parameters_dict.pop('ecmwfdatadir', None) # parameters_dict_str = {} # for key, value in parameters_dict.iteritems(): # if isinstance(value, list): # parameters_dict_str[str(key)] = get_list_as_string(value, ' ') # else: # parameters_dict_str[str(key)] = str(value) # return parameters_dict_str