Index: .gitignore
===================================================================
--- .gitignore	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
+++ .gitignore	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -0,0 +1,37 @@
+#
+# gitignore lists all directories and files which should not be versionized!!! 
+#
+
+# these dirs and files shouldn't be versionized at any time in this project!!!
+*.pyc
+*.o
+*.mod
+*.tar*
+/work*
+/src/CONVERT2
+/python/ECMWF_ENV
+
+
+# temporary ignorance of the following files!
+Content_Paper2.txt
+DOCUFPEXTRACT.txt
+FLEXEXTRACT_CONTENT.txt
+NewDocu.odt
+dokuECMWFDATA
+
+/python/.cache/
+/python/CONTROL.temp.backup
+
+/python/SphinxDoc/
+/python/assoc.txt
+/python/classes.dot
+/python/classes.dot.png
+
+/python/packages.dot
+/python/packages.dot.png
+/python/prepare_flexpart.py.lprof
+/python/pylintrc
+/python/testecmwfapi.py
+
+/pythontest/
+
Index: doc/.~lock.ErrorDebug.ods#
===================================================================
--- doc/.~lock.ErrorDebug.ods#	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
+++ doc/.~lock.ErrorDebug.ods#	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -0,0 +1,1 @@
+,philipa8,localhost,21.08.2018 16:15,file:///home/philipa8/.config/libreoffice/4;
Index: mk_upload_tarball.sh
===================================================================
--- mk_upload_tarball.sh	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
+++ mk_upload_tarball.sh	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -0,0 +1,13 @@
+#!/bin/bash
+#
+# @Author: Anne Philipp
+#
+# @Date: June, 7 2018
+#
+# @Description: Makes a tarball for uploading on flexpart.eu
+#
+
+tarname='flex_extract_v7.1.tar.gz'
+
+
+tar --exclude='./src/*.o' --exclude='./src/*.mod' --exclude='./src/CONVERT2' --exclude='./python/*.pyc' --exclude='./python/*.ksh' --exclude='./python/ECMWF_ENV' --exclude='./python/*sh' --exclude='*sh' --exclude='*tar.gz' --exclude='work' --exclude='./python/job.temp' -zcvf $tarname . 
Index: python/CONTROL.temp
===================================================================
--- python/CONTROL.temp	(revision ccab8091e3f70844b2b6e73b9aa5e6b41aaf5ff5)
+++ python/CONTROL.temp	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -1,3 +1,3 @@
-DAY1
+DAY1 20130501
 DAY2
 DTIME 3
Index: python/CONTROL.test
===================================================================
--- python/CONTROL.test	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
+++ python/CONTROL.test	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -0,0 +1,18 @@
+DTIME 3
+TYPE AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC
+TIME 00 00 00 00 00 00 06 00 00 00 00 00 12 12 12 12 12 12 18 12 12 12 12 12
+STEP 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11
+CLASS EI
+STREAM OPER
+EXPVER 1
+GRID 5000  
+LEFT -15000
+LOWER 30000
+UPPER 75000
+RIGHT 45000
+LEVELIST 55/to/60
+RESOL 63
+GAUSS 1
+ADDPAR 186/187/188/235/139/39
+PREFIX EItest_
+ECTRANS 1
Index: python/CONTROL.worktest
===================================================================
--- python/CONTROL.worktest	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
+++ python/CONTROL.worktest	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -0,0 +1,37 @@
+DAY1 20100101
+DAY2 
+DTIME 3
+TYPE AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC
+TIME 00 00 00 00 00 00 06 00 00 00 00 00 12 12 12 12 12 12 18 12 12 12 12 12
+STEP 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11
+CLASS EI
+STREAM OPER
+NUMBER OFF
+EXPVER 1
+GRID 5000  
+LEFT -10000
+LOWER 30000
+UPPER 40000
+RIGHT 10000
+LEVEL 60
+LEVELIST 58/to/60
+RESOL 63
+GAUSS 1
+ACCURACY 16
+OMEGA 0
+OMEGADIFF 0
+ETA 0
+ETADIFF 0
+DPDETA 1
+SMOOTH 0
+FORMAT GRIB1
+ADDPAR 186/187/188/235/139/39
+PREFIX EI
+ECSTORAGE 0
+ECTRANS 1
+ECFSDIR ectmp:/${USER}/econdemand/
+MAILFAIL ${USER} 
+MAILOPS ${USER}
+GRIB2FLEXPART 0
+EOF
+
Index: python/CONTROL_EI
===================================================================
--- python/CONTROL_EI	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
+++ python/CONTROL_EI	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -0,0 +1,37 @@
+DAY1
+DAY2
+DTIME 3
+TYPE AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC
+TIME 00 00 00 00 00 00 06 00 00 00 00 00 12 12 12 12 12 12 18 12 12 12 12 12
+STEP 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11
+CLASS EI
+STREAM OPER
+NUMBER OFF
+EXPVER 1
+GRID 5000  
+LEFT -15000
+LOWER 30000
+UPPER 75000
+RIGHT 45000
+LEVEL 60
+LEVELIST 55/to/60
+RESOL 63
+GAUSS 1
+ACCURACY 16
+OMEGA 0
+OMEGADIFF 0
+ETA 0
+ETADIFF 0
+DPDETA 1
+SMOOTH 0
+FORMAT GRIB1
+ADDPAR 186/187/188/235/139/39
+PREFIX EI
+ECSTORAGE 0
+ECTRANS 1
+ECFSDIR ectmp:/${USER}/econdemand/
+MAILFAIL ${USER} 
+MAILOPS ${USER}
+GRIB2FLEXPART 0
+EOF
+
Index: python/CONTROL_FC
===================================================================
--- python/CONTROL_FC	(revision d69b6776d6d39e0af0d38c95cbfd78284c9866e4)
+++ python/CONTROL_FC	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -1,8 +1,11 @@
-DAY1 20131107
-DAY2 20131108
-DTIME 1
+DAY1 
+DAY2 
+DTIME 3
 M_TYPE FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC
 M_TIME 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 M_STEP 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
+ACCTYPE FC
+ACCTIME 00
+ACCMAXSTEP 36
 M_MAXSTEP 36
 M_LEVEL 137
@@ -13,26 +16,16 @@
 M_EXPVER 1
 M_GRID 1000  
-M_LEFT -179000
-M_LOWER -90000
-M_UPPER 90000
-M_RIGHT 180000
+M_LEFT -25000
+M_LOWER 10000
+M_UPPER 60000
+M_RIGHT 60000
 M_RESOL 159
-M_GAUSS 0
-M_ACCURACY 16
-M_OMEGA 0
-M_OMEGADIFF 0
 M_ETA 1
-M_ETADIFF 0
 M_DPDETA 1
 M_SMOOTH 0
-M_FORMAT GRIB1
 M_ADDPAR /186/187/188/235/139/39
 M_WRF 1
 M_CWC 1
 PREFIX EE
-ECSTORAGE 1
-ECTRANS 0
-ECFSDIR ectmp:/${USER}/econdemand/
-MAILOPS ${USER}
-MAILFAIL ${USER}
+ECTRANS 1
 EOF
Index: python/CONTROL_PF.temp
===================================================================
--- python/CONTROL_PF.temp	(revision d69b6776d6d39e0af0d38c95cbfd78284c9866e4)
+++ python/CONTROL_PF.temp	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -34,5 +34,5 @@
 MAILOPS ${USER}
 MAILFAIL ${USER}
-FLEXPARTDIR ${HOME}/ECMWFDATA7.0/flexpart_code
+FLEXPARTDIR ${HOME}/flex_extract_v7.1/flexpart_code
 GRIB2FLEXPART grib2flexpart
 EOF
Index: python/ControlFile.py
===================================================================
--- python/ControlFile.py	(revision e1228f354a5d6085d76098e26080ddbfcabb84d2)
+++ python/ControlFile.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -1,8 +1,4 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-#************************************************************************
-# ToDo AP
-# - write a test class
-#************************************************************************
 #*******************************************************************************
 # @Author: Leopold Haimberger (University of Vienna)
@@ -19,4 +15,8 @@
 #          self-explanation naming
 #        - outsource of class ControlFile
+#        - initialisation of class attributes ( to avoid high number of
+#          conditional statements and set default values )
+#        - divided assignment of attributes and the check of conditions
+#        - outsourced the commandline argument assignments to control attributes
 #
 # @License:
@@ -36,27 +36,14 @@
 # @Class Content:
 #    - __init__
+#    - __read_controlfile__
 #    - __str__
+#    - assign_args_to_control
+#    - assign_envs_to_control
+#    - check_conditions
+#    - check_install_conditions
 #    - 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
+#
 #
 #*******************************************************************************
@@ -66,4 +53,5 @@
 # ------------------------------------------------------------------------------
 import os
+import sys
 import inspect
 
@@ -92,7 +80,8 @@
         '''
         @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.
+            Initialises the instance of ControlFile class and defines
+            all class attributes with default values. Afterwards calls
+            function __read_controlfile__ to read parameter from
+            Control file.
 
         @Input:
@@ -106,12 +95,85 @@
             <nothing>
         '''
+
+        # list of all possible class attributes and their default values
+        self.controlfile = filename
+        self.start_date = None
+        self.end_date = None
+        self.date_chunk = 3
+        self.dtime = None
+        self.basetime = None
+        self.maxstep = None
+        self.type = None
+        self.time = None
+        self.step = None
+        self.marsclass = None
+        self.stream = None
+        self.number = 'OFF'
+        self.expver = None
+        self.grid = None
+        self.area = ''
+        self.left = None
+        self.lower = None
+        self.upper = None
+        self.right = None
+        self.level = None
+        self.levelist = None
+        self.resol = None
+        self.gauss = 0
+        self.accuracy = 24
+        self.omega = 0
+        self.omegadiff = 0
+        self.eta = 0
+        self.etadiff = 0
+        self.etapar = 77
+        self.dpdeta = 1
+        self.smooth = 0
+        self.format = 'GRIB1'
+        self.addpar = None
+        self.prefix = 'EN'
+        self.cwc = 0
+        self.wrf = 0
+        self.ecfsdir = 'ectmp:/${USER}/econdemand/'
+        self.mailfail = ['${USER}']
+        self.mailops = ['${USER}']
+        self.grib2flexpart = 0
+        self.ecstorage = 0
+        self.ectrans = 0
+        self.inputdir = '../work'
+        self.outputdir = self.inputdir
+        self.ecmwfdatadir = None
+        self.exedir = None
+        self.flexpart_root_scripts = None
+        self.makefile = None
+        self.destination = None
+        self.gateway = None
+        self.ecuid = None
+        self.ecgid = None
+        self.install_target = None
+        self.debug = 0
+
+        self.__read_controlfile__()
+
+        return
+
+    def __read_controlfile__(self):
+        '''
+        @Description:
+            Read CONTROL file and assign all CONTROL file variables.
+
+        @Input:
+            self: instance of ControlFile class
+                Description see class documentation.
+
+        @Return:
+            <nothing>
+        '''
         from tools import my_error
 
         # read whole CONTROL file
-        with open(filename) as f:
+        with open(self.controlfile) as f:
             fdata = f.read().split('\n')
 
         # go through every line and store parameter
-        # as class variable
         for ldata in fdata:
             data = ldata.split()
@@ -145,7 +207,8 @@
                                 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)
+                                my_error(self.mailfail,
+                                         'Could not find variable '
+                                         + data[1][j+1:k] + ' while reading ' +
+                                         self.controlfile)
                         setattr(self, data[0].lower() + '_expanded', data[1])
                     else:
@@ -159,34 +222,162 @@
                 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'):
+        # script directory
+        self.ecmwfdatadir = os.path.dirname(os.path.abspath(inspect.getfile(
+            inspect.currentframe()))) + '/../'
+
+        # Fortran source directory
+        self.exedir = self.ecmwfdatadir + 'src/'
+
+        return
+
+    def __str__(self):
+        '''
+        @Description:
+            Prepares a string which have all the ControlFile
+            class attributes with its associated values.
+            Each attribute is printed in one line and in
+            alphabetical order.
+
+            Example:
+            'age': 10
+            'color': 'Spotted'
+            'kids': 0
+            'legs': 2
+            'name': 'Dog'
+            'smell': 'Alot'
+
+        @Input:
+            self: instance of ControlFile class
+                Description see class documentation.
+
+        @Return:
+            string of ControlFile class attributes with their values
+        '''
+        import collections
+
+        attrs = vars(self)
+        attrs = collections.OrderedDict(sorted(attrs.items()))
+
+        return '\n'.join("%s: %s" % item for item in attrs.items())
+
+    def assign_args_to_control(self, args):
+        '''
+        @Description:
+            Overwrites the existing ControlFile instance attributes with
+            the command line arguments.
+
+        @Input:
+            self: instance of ControlFile class
+                Description see class documentation.
+
+            args: instance of ArgumentParser
+                Contains the commandline arguments from script/program call.
+
+        @Return:
+            <nothing>
+        '''
+
+        # get dictionary of command line parameters and eliminate all
+        # parameters which are None (were not specified)
+        args_dict = vars(args)
+        arguments = {k : args_dict[k] for k in args_dict
+                     if args_dict[k] != None}
+
+        # assign all passed command line arguments to ControlFile instance
+        for k, v in arguments.iteritems():
+            setattr(self, str(k), v)
+
+        return
+
+    def assign_envs_to_control(self, envs):
+        '''
+        @Description:
+            Assigns the ECMWF environment parameter.
+
+        @Input:
+            envs: dict of strings
+                Contains the ECMWF environment parameternames "ECUID", "ECGID",
+                "DESTINATION" and "GATEWAY" with its corresponding values.
+                They were read from the file "ECMWF_ENV".
+
+        @Return:
+            <nothing>
+        '''
+
+        for k, v in envs.iteritems():
+            setattr(self, str(k).lower(), str(v))
+
+        return
+
+    def check_conditions(self):
+        '''
+        @Description:
+            Checks a couple of necessary attributes and conditions,
+            such as if they exist and contain values.
+            Otherwise set default values.
+
+        @Input:
+            self: instance of ControlFile class
+                Description see class documentation.
+
+        @Return:
+            <nothing>
+        '''
+        from tools import my_error
+        import numpy as np
+
+        # check for having at least a starting date
+        # otherwise program is not allowed to run
+        if self.start_date is None:
+            print 'start_date specified neither in command line nor ' + \
+                  'in CONTROL file ' +  self.controlfile
+            print 'Try "' + sys.argv[0].split('/')[-1] + \
+                  ' -h" to print usage information'
+            sys.exit(1)
+
+        # retrieve just one day if end_date isn't set
+        if self.end_date is None:
             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'
+
+        # assure consistency of levelist and level
+        if self.levelist is None:
+            if self.level is None:
+                print 'Warning: neither levelist nor level ' + \
+                      'specified in CONTROL file'
+                sys.exit(1)
             else:
                 self.levelist = '1/to/' + self.level
         else:
-            if 'to' in self.levelist:
+            if 'to' in self.levelist.lower():
                 self.level = self.levelist.split('/')[2]
             else:
                 self.level = self.levelist.split('/')[-1]
 
-        if not hasattr(self, 'maxstep'):
-            # find out maximum step
+        # if area was provided at command line
+        # decompse area into its 4 components
+        if self.area:
+            afloat = '.' in self.area
+            l = self.area.split('/')
+            if afloat:
+                for i, item in enumerate(l):
+                    item = str(int(float(item) * 1000))
+            self.upper, self.left, self.lower, self.right = l
+
+        # prepare step for correct usage
+        if '/' in self.step:
+            l = self.step.split('/')
+            if 'to' in self.step.lower():
+                if 'by' in self.step.lower():
+                    ilist = np.arange(int(l[0]), int(l[2]) + 1, int(l[4]))
+                    self.step = ['{:0>3}'.format(i) for i in ilist]
+                else:
+                    my_error(self.mailfail, self.step + ':\n' +
+                             'if "to" is used, please use "by" as well')
+            else:
+                self.step = l
+
+        # if maxstep wasn't provided
+        # search for it in the "step" parameter
+        if self.maxstep is None:
             self.maxstep = 0
             for s in self.step:
@@ -196,48 +387,84 @@
             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'):
+        # set root scripts since it is needed later on
+        if not self.flexpart_root_scripts:
             self.flexpart_root_scripts = self.ecmwfdatadir
 
+        if not isinstance(self.mailfail, list):
+            if ',' in self.mailfail:
+                self.mailfail = self.mailfail.split(',')
+            elif ' ' in self.mailfail:
+                self.mailfail = self.mailfail.split()
+            else:
+                self.mailfail = [self.mailfail]
+
+        if not isinstance(self.mailops, list):
+            if ',' in self.mailops:
+                self.mailops = self.mailops.split(',')
+            elif ' ' in self.mailops:
+                self.mailops = self.mailops.split()
+            else:
+                self.mailops = [self.mailops]
+
+        if not self.gateway or not self.destination or \
+           not self.ecuid or not self.ecgid:
+            print '\nEnvironment variables GATWAY, DESTINATION, ECUID and ' + \
+                  'ECGID were not set properly!'
+            print 'Please check for excistence of file "ECMWF_ENV" in the ' + \
+                  'python directory!'
+            sys.exit(1)
+
         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 check_install_conditions(self):
+        '''
+        @Description:
+            Checks a couple of necessary attributes and conditions
+            for the installation such as if they exist and contain values.
+            Otherwise set default values.
+
+        @Input:
+            self: instance of ControlFile class
+                Description see class documentation.
+
+        @Return:
+            <nothing>
+        '''
+
+        if self.install_target and \
+           self.install_target not in ['local', 'ecgate', 'cca']:
+            print 'ERROR: unknown or missing installation target '
+            print 'target: ', self.install_target
+            print 'please specify correct installation target \
+                   (local | ecgate | cca)'
+            print 'use -h or --help for help'
+            sys.exit(1)
+
+        if self.install_target and self.install_target != 'local':
+            if not self.ecgid or not self.ecuid or \
+               not self.gateway or not self.destination:
+                print 'Please enter your ECMWF user id and group id as well as \
+                       the \nname of the local gateway and the ectrans \
+                       destination '
+                print 'with command line options --ecuid --ecgid \
+                       --gateway --destination'
+                print 'Try "' + sys.argv[0].split('/')[-1] + \
+                      ' -h" to print usage information'
+                print 'Please consult ecaccess documentation or ECMWF user \
+                       support for further details'
+                sys.exit(1)
+
+            if not self.flexpart_root_scripts:
+                self.flexpart_root_scripts = '${HOME}'
+            else:
+                self.flexpart_root_scripts = self.flexpart_root_scripts
+        else:
+            if not self.flexpart_root_scripts:
+                self.flexpart_root_scripts = '../'
+
+        if not self.makefile:
+            self.makefile = 'Makefile.gfortran'
+
+        return
 
     def to_list(self):
@@ -259,5 +486,8 @@
         '''
 
-        attrs = vars(self)
+        import collections
+
+        attrs = collections.OrderedDict(sorted(vars(self).items()))
+
         l = list()
 
@@ -283,22 +513,2 @@
         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
Index: python/EcFlexpart.py
===================================================================
--- python/EcFlexpart.py	(revision e1228f354a5d6085d76098e26080ddbfcabb84d2)
+++ python/EcFlexpart.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -1,14 +1,4 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-#************************************************************************
-# ToDo AP
-# - specifiy file header documentation
-# - add class description in header information
-# - apply classtests
-# - add references to ECMWF specific software packages
-# - add describtion of deacc_fluxes
-# - change name of func deacc ( weil disagg )
-# - add desc of retrieve function
-#************************************************************************
 #*******************************************************************************
 # @Author: Anne Fouilloux (University of Oslo)
@@ -151,5 +141,5 @@
 
             fluxes: boolean, optional
-                Decides if a the flux parameter settings are stored or
+                Decides if the flux parameter settings are stored or
                 the rest of the parameter list.
                 Default value is False.
@@ -175,5 +165,5 @@
         self.dtime = c.dtime
         i = 0
-        if fluxes is True and c.maxstep < 24:
+        if fluxes and c.maxstep <= 24:
             # no forecast beyond one day is needed!
             # Thus, prepare flux data manually as usual
@@ -192,5 +182,5 @@
                     btlist = [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0]
 
-                if i % int(c.dtime) == 0 and c.maxstep > 24 or i in btlist:
+                if i % int(c.dtime) == 0 and (i in btlist or c.maxstep > 24):
 
                     if ty not in self.types.keys():
@@ -207,5 +197,4 @@
                         self.types[ty]['steps'] += st
                 i += 1
-
 
         self.marsclass = c.marsclass
@@ -304,13 +293,13 @@
                                          '{}'.format((int(self.resol) + 1) / 2)]
 
-            if c.omega == '1':
+            if hasattr(c, 'omega') and c.omega == '1':
                 self.params['OG__ML'][0] += '/W'
 
             # add cloud water content if necessary
-            if c.cwc == '1':
+            if hasattr(c, 'cwc') and c.cwc == '1':
                 self.params['OG__ML'][0] += '/CLWC/CIWC'
 
             # add vorticity and geopotential height for WRF if necessary
-            if c.wrf == '1':
+            if hasattr(c, 'wrf') and c.wrf == '1':
                 self.params['OG__ML'][0] += '/Z/VO'
                 if '/D' not in self.params['OG__ML'][0]:
@@ -740,5 +729,5 @@
                                            c.gateway, '-remote', c.destination,
                                            '-source', ofile])
-                print('ectrans:', p)
+                #print('ectrans:', p)
 
         if int(c.ecstorage) == 1 and c.ecapi is False:
@@ -890,5 +879,5 @@
 
         for prod in product(*index_vals):
-            # flag for Fortran program CONVERT2, initially False
+            # flag for Fortran program CONVERT2 and file merging
             convertFlag = False
             print 'current prod: ', prod
@@ -906,8 +895,11 @@
             # prepare some date and time parameter before reading the data
             if gid is not None:
-                # Fortran program CONVERT2 is only done if gid at this time is
-                # not None, therefore save information in convertFlag
+                # Combine all temporary data files into final grib file if
+                # gid is at least one time not None. Therefore set convertFlag
+                # to save information. The fortran program CONVERT2 is also
+                # only done if convertFlag is True
                 convertFlag = True
                 # remove old fort.* files and open new ones
+                # they are just valid for a single product
                 for k, f in fdict.iteritems():
                     silent_remove(c.inputdir + "/fort." + k)
@@ -922,5 +914,4 @@
                                               '%Y%m%d%H')
                 timestamp += timedelta(hours=int(step))
-
                 cdateH = datetime.strftime(timestamp, '%Y%m%d%H')
 
@@ -966,5 +957,5 @@
                 levtype = grib_get(gid, 'typeOfLevel')
                 if paramId == 133 and gridtype == 'reduced_gg':
-                # Relative humidity (Q.grb) is used as a template only
+                # Specific humidity (Q.grb) is used as a template only
                 # so we need the first we "meet"
                     with open(c.inputdir + '/fort.18', 'w') as fout:
@@ -1028,6 +1019,6 @@
                            not available for this type or date/time\n'
                     print 'Check parameters CLASS, TYPE, STREAM, START_DATE\n'
-                    my_error(c, 'fort.21 is empty while parameter eta is set \
-                                to 1 in CONTROL file')
+                    my_error(c.mailfail, 'fort.21 is empty while parameter eta \
+                             is set to 1 in CONTROL file')
 
                 # create the corresponding output file fort.15
@@ -1061,5 +1052,6 @@
                 with open(fnout, 'wb') as fout:
                     for f in flist:
-                        shutil.copyfileobj(open(c.inputdir + '/' + f, 'rb'), fout)
+                        shutil.copyfileobj(
+                            open(c.inputdir + '/' + f, 'rb'), fout)
 
                 if c.omega == '1':
@@ -1068,5 +1060,5 @@
                             open(c.inputdir + '/fort.25', 'rb'), fout)
 
-        if c.wrf == '1':
+        if hasattr(c, 'wrf') and c.wrf == '1':
             fwrf.close()
 
@@ -1307,4 +1299,3 @@
         grib_index_release(iid)
 
-        exit()
         return
Index: python/GribTools.py
===================================================================
--- python/GribTools.py	(revision e1228f354a5d6085d76098e26080ddbfcabb84d2)
+++ python/GribTools.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -309,5 +309,4 @@
                     iid = grib_index_new_from_file(filename, index_keys)
                 else:
-                    print 'in else zweig'
                     grib_index_add_file(iid, filename)
 
Index: python/MarsRetrieval.py
===================================================================
--- python/MarsRetrieval.py	(revision None)
+++ python/MarsRetrieval.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -79,5 +79,5 @@
     '''
 
-    def __init__(self, server, marsclass="ei", dtype="", levtype="",
+    def __init__(self, server, marsclass="ei", type="", levtype="",
                  levelist="", repres="", date="", resol="", stream="",
                  area="", time="", step="", expver="1", number="",
@@ -107,5 +107,5 @@
                 Default is the ERA-Interim dataset "ei".
 
-            dtype: string, optional
+            type: string, optional
                 Determines the type of fields to be retrieved.
                 Selects between observations, images or fields.
@@ -286,5 +286,5 @@
         self.server = server
         self.marsclass = marsclass
-        self.dtype = dtype
+        self.type = type
         self.levtype = levtype
         self.levelist = levelist
Index: python/UioFiles.py
===================================================================
--- python/UioFiles.py	(revision None)
+++ python/UioFiles.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -34,5 +34,6 @@
 # @Class Content:
 #    - __init__
-#    - list_files
+#    - __str__
+#    - __list_files__
 #    - delete_files
 #
@@ -51,5 +52,5 @@
 # software specific module from flex_extract
 #import profiling
-from tools import silent_remove
+from tools import silent_remove, get_list_as_string
 
 # ------------------------------------------------------------------------------
@@ -66,5 +67,5 @@
     # CLASS FUNCTIONS
     # --------------------------------------------------------------------------
-    def __init__(self, pattern):
+    def __init__(self, path, pattern):
         '''
         @Description:
@@ -75,4 +76,7 @@
                 Description see class documentation.
 
+            path: string
+                Directory where to list the files.
+
             pattern: string
                 Regular expression pattern. For example: '*.grb'
@@ -82,11 +86,14 @@
         '''
 
+        self.path = path
         self.pattern = pattern
         self.files = None
+
+        self.__list_files__(self.path)
 
         return
 
     #@profiling.timefn
-    def list_files(self, path, callid=0):
+    def __list_files__(self, path, callid=0):
         '''
         @Description:
@@ -99,5 +106,5 @@
 
             path: string
-                Directory where to list the files.
+                Path to the files.
 
             callid: integer
@@ -129,7 +136,27 @@
         if subdirs:
             for subdir in subdirs:
-                self.list_files(os.path.join(path, subdir), callid=1)
+                self.__list_files__(os.path.join(path, subdir), callid=1)
 
         return
+
+    def __str__(self):
+        '''
+        @Description:
+            Converts the list of files into a single string.
+            The entries are sepereated by "," sign.
+
+        @Input:
+            self: instance of UioFiles
+                Description see class documentation.
+
+        @Return:
+            files_string: string
+                The content of the list as a single string.
+        '''
+
+        filenames = [os.path.basename(f) for f in self.files]
+        files_string = get_list_as_string(filenames, concatenate_sign=', ')
+
+        return files_string
 
     def delete_files(self):
Index: python/_config.py
===================================================================
--- python/_config.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
+++ python/_config.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#*******************************************************************************
+# @Author: Anne Philipp (University of Vienna)
+#
+# @Date: August 2018
+#
+# @Change History:
+#
+# @License:
+#    (C) Copyright 2014-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.
+#
+# @Description:
+#    Contains constant value parameter for flex_extract.
+#
+#*******************************************************************************
+
+# ------------------------------------------------------------------------------
+# MODULES
+# ------------------------------------------------------------------------------
+import os
+import sys
+import inspect
+
+
+_VERSION_STR = '7.1'
+
+
+# add path to pythonpath
+LOCAL_PYTHON_PATH = os.path.dirname(os.path.abspath(
+    inspect.getfile(inspect.currentframe())))
+if LOCAL_PYTHON_PATH not in sys.path:
+    sys.path.append(LOCAL_PYTHON_PATH)
Index: python/compilejob.ksh
===================================================================
--- python/compilejob.ksh	(revision 991df6ad0a703d97e1e192a0a6106e1d9ba47e8e)
+++ python/compilejob.ksh	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -5,5 +5,5 @@
 # start with sbatch NAME_OF_THIS_FILE directly on machine
 
-#SBATCH --workdir=/scratch/ms/spatlh00/lh0
+#SBATCH --workdir=/scratch/ms/at/km4a
 #SBATCH --qos=normal
 #SBATCH --job-name=flex_ecmwf
@@ -33,9 +33,6 @@
   module load grib_api/1.14.5
   module load emos/437-r64
-export FLEXPART_ROOT_SCRIPTS=$HOME
-#  export ECMWFDATA=$FLEXPART_ROOT/ECMWFDATA$VERSION
-#  export PYTHONPATH=$ECMWFDATA/python
-#  export PATH=${PATH}:$ECMWFDATA/python
-  export MAKEFILE=Makefile.gfortran
+export FLEXPART_ROOT_SCRIPTS=${HOME}
+export MAKEFILE=Makefile.gfortran
   ;;
   *cca*)
@@ -49,15 +46,12 @@
   export GROUP=`echo $HOME | awk -F / '{print $4}'`
   export SCRATCH=/scratch/ms/${GROUP}/${USER}
-export FLEXPART_ROOT_SCRIPTS=$HOME
-#  export ECMWFDATA=$FLEXPART_ROOT/ECMWFDATA$VERSION
-#  export PYTHONPATH=$ECMWFDATA/python
-#  export PATH=${PATH}:$ECMWFDATA/python
-  export MAKEFILE=Makefile.CRAY
+export FLEXPART_ROOT_SCRIPTS=${HOME}
+export MAKEFILE=Makefile.gfortran
   ;;
 esac
 
-mkdir -p $FLEXPART_ROOT_SCRIPTS/ECMWFDATA$VERSION
-cd $FLEXPART_ROOT_SCRIPTS/ECMWFDATA$VERSION   # if FLEXPART_ROOT is not set this means cd to the home directory
-tar -xvf $HOME/ECMWFDATA$VERSION.tar
+mkdir -p $FLEXPART_ROOT_SCRIPTS/flex_extract_v$VERSION
+cd $FLEXPART_ROOT_SCRIPTS/flex_extract_v$VERSION   # if FLEXPART_ROOT is not set this means cd to the home directory
+tar -xvf $HOME/flex_extract_v$VERSION.tar
 cd src
 \rm *.o *.mod CONVERT2
Index: python/compilejob.temp
===================================================================
--- python/compilejob.temp	(revision efdb01a8ac2d5cef85c651177aa18ac69dd660db)
+++ python/compilejob.temp	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -34,7 +34,4 @@
   module load emos/437-r64
   export FLEXPART_ROOT_SCRIPTS=
-#  export ECMWFDATA=$FLEXPART_ROOT/ECMWFDATA$VERSION
-#  export PYTHONPATH=$ECMWFDATA/python
-#  export PATH=${PATH}:$ECMWFDATA/python
   export MAKEFILE=Makefile.gfortran
   ;;
@@ -50,14 +47,11 @@
   export SCRATCH=/scratch/ms/${GROUP}/${USER}
   export FLEXPART_ROOT_SCRIPTS=
-#  export ECMWFDATA=$FLEXPART_ROOT/ECMWFDATA$VERSION
-#  export PYTHONPATH=$ECMWFDATA/python
-#  export PATH=${PATH}:$ECMWFDATA/python
   export MAKEFILE=Makefile.CRAY
   ;;
 esac
 
-mkdir -p $FLEXPART_ROOT_SCRIPTS/ECMWFDATA$VERSION
-cd $FLEXPART_ROOT_SCRIPTS/ECMWFDATA$VERSION   # if FLEXPART_ROOT is not set this means cd to the home directory
-tar -xvf $HOME/ECMWFDATA$VERSION.tar
+mkdir -p $FLEXPART_ROOT_SCRIPTS/flex_extract_v$VERSION
+cd $FLEXPART_ROOT_SCRIPTS/flex_extract_v$VERSION   # if FLEXPART_ROOT is not set this means cd to the home directory
+tar -xvf $HOME/flex_extract_v$VERSION.tar
 cd src
 \rm *.o *.mod CONVERT2
Index: python/disaggregation.py
===================================================================
--- python/disaggregation.py	(revision None)
+++ python/disaggregation.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -1,9 +1,4 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-#************************************************************************
-# ToDo AP
-# - check alist of size 4 ?
-# - write a test, IMPORTANT
-#************************************************************************
 #*******************************************************************************
 # @Author: Anne Philipp (University of Vienna)
@@ -12,4 +7,5 @@
 #
 # @Change History:
+#
 #    November 2015 - Leopold Haimberger (University of Vienna):
 #        - migration of the methods dapoly and darain from Fortran
@@ -29,5 +25,5 @@
 #
 # @Module Description:
-#    disaggregationregation of deaccumulated flux data from an ECMWF model FG field.
+#    disaggregation of deaccumulated flux data from an ECMWF model FG field.
 #    Initially the flux data to be concerned are:
 #    - large-scale precipitation
Index: python/get_mars_data.py
===================================================================
--- python/get_mars_data.py	(revision None)
+++ python/get_mars_data.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -22,5 +22,5 @@
 #          online documentation)
 #        - use of UIFiles class for file selection and deletion
-
+#
 #
 # @License:
@@ -39,4 +39,5 @@
 #    - main
 #    - get_mars_data
+#    - do_retrievement
 #
 #*******************************************************************************
@@ -56,5 +57,5 @@
 
 # software specific classes and modules from flex_extract
-from tools import my_error, normal_exit, interpret_args_and_control
+from tools import my_error, normal_exit, get_cmdline_arguments, read_ecenv
 from EcFlexpart import EcFlexpart
 from UioFiles import UioFiles
@@ -82,7 +83,26 @@
         <nothing>
     '''
-    args, c = interpret_args_and_control()
+
+    args = get_cmdline_arguments()
+
+    try:
+        c = ControlFile(args.controlfile)
+    except IOError:
+        try:
+            c = ControlFile(LOCAL_PYTHON_PATH + args.controlfile)
+        except IOError:
+            print 'Could not read CONTROL file "' + args.controlfile + '"'
+            print 'Either it does not exist or its syntax is wrong.'
+            print 'Try "' + sys.argv[0].split('/')[-1] + \
+                  ' -h" to print usage information'
+            sys.exit(1)
+
+    env_parameter = read_ecenv(c.ecmwfdatadir + 'python/ECMWF_ENV')
+    c.assign_args_to_control(args, env_parameter)
+    c.assign_envs_to_control(env_parameter)
+    c.check_conditions()
+
     get_mars_data(c)
-    normal_exit(c)
+    normal_exit(c.mailfail, 'Done!')
 
     return
@@ -129,4 +149,22 @@
     print 'ecapi: ', c.ecapi
 
+    # basetime geht rückwärts
+
+    # if basetime 00
+    # dann wird von 12 am vortag bis 00 am start tag geholt
+    # aber ohne 12 selbst sondern 12 + step
+
+    # if basetime 12
+    # dann wird von 00 + step bis 12 am start tag geholt
+
+    # purer forecast wird vorwärts bestimmt.
+    # purer forecast mode ist dann wenn  größer 24 stunden
+    # wie kann das noch festgestellt werden ????
+    # nur FC und steps mehr als 24 ?
+    # die einzige problematik beim reinen forecast ist die benennung der files!
+    # also sobald es Tagesüberschneidungen gibt
+    # allerdings ist das relevant und ersichtlich an den NICHT FLUSS DATEN
+
+
     # set start date of retrieval period
     start = datetime.date(year=int(c.start_date[:4]),
@@ -134,6 +172,4 @@
                           day=int(c.start_date[6:]))
     startm1 = start - datetime.timedelta(days=1)
-    if c.basetime == '00':
-        start = startm1
 
     # set end date of retrieval period
@@ -141,43 +177,30 @@
                         month=int(c.end_date[4:6]),
                         day=int(c.end_date[6:]))
+
+    # set time period for one single retrieval
+    datechunk = datetime.timedelta(days=int(c.date_chunk))
+
+    if c.basetime == '00':
+        start = startm1
+
     if c.basetime == '00' or c.basetime == '12':
+        # endp1 = end + datetime.timedelta(days=1)
+        endp1 = end
+    else:
+        # endp1 = end + datetime.timedelta(days=2)
         endp1 = end + datetime.timedelta(days=1)
-    else:
-        endp1 = end + datetime.timedelta(days=2)
-
-    # set time period of one single retrieval
-    datechunk = datetime.timedelta(days=int(c.date_chunk))
 
     # --------------  flux data ------------------------------------------------
     print 'removing old flux content of ' + c.inputdir
-    tobecleaned = UioFiles('*_acc_*.' + str(os.getppid()) + '.*.grb')
-    tobecleaned.list_files(c.inputdir)
+    tobecleaned = UioFiles(c.inputdir,
+                           '*_acc_*.' + str(os.getppid()) + '.*.grb')
     tobecleaned.delete_files()
 
-    # if forecast for maximum one day (upto 23h) are to be retrieved,
+    # if forecast for maximum one day (upto 24h) are to be retrieved,
     # collect accumulation data (flux data)
     # with additional days in the beginning and at the end
     # (used for complete disaggregation of original period)
-    if c.maxstep < 24:
-        day = startm1
-        while day < endp1:
-            # retrieve MARS data for the whole period
-            flexpart = EcFlexpart(c, fluxes=True)
-            tmpday = day + datechunk - datetime.timedelta(days=1)
-            if tmpday < endp1:
-                dates = day.strftime("%Y%m%d") + "/to/" + \
-                        tmpday.strftime("%Y%m%d")
-            else:
-                dates = day.strftime("%Y%m%d") + "/to/" + \
-                        end.strftime("%Y%m%d")
-
-            print "retrieve " + dates + " in dir " + c.inputdir
-
-            try:
-                flexpart.retrieve(server, dates, c.inputdir)
-            except IOError:
-                my_error(c, 'MARS request failed')
-
-            day += datechunk
+    if c.maxstep <= 24:
+        do_retrievement(c, server, startm1, endp1, datechunk, fluxes=True)
 
     # if forecast data longer than 24h are to be retrieved,
@@ -187,36 +210,67 @@
     # exact time period with boundary conditions)
     else:
-        day = start
-        while day <= end:
-            # retrieve MARS data for the whole period
-            flexpart = EcFlexpart(c, fluxes=True)
-            tmpday = day + datechunk - datetime.timedelta(days=1)
-            if tmpday < end:
-                dates = day.strftime("%Y%m%d") + "/to/" + \
-                        tmpday.trftime("%Y%m%d")
-            else:
-                dates = day.strftime("%Y%m%d") + "/to/" + \
-                        end.strftime("%Y%m%d")
-
-            print "retrieve " + dates + " in dir " + c.inputdir
-
-            try:
-                flexpart.retrieve(server, dates, c.inputdir)
-            except IOError:
-                my_error(c, 'MARS request failed')
-
-            day += datechunk
+        do_retrievement(c, server, start, end, datechunk, fluxes=True)
 
     # --------------  non flux data --------------------------------------------
     print 'removing old non flux content of ' + c.inputdir
-    tobecleaned = UioFiles('*__*.' + str(os.getppid()) + '.*.grb')
-    tobecleaned.list_files(c.inputdir)
+    tobecleaned = UioFiles(c.inputdir,
+                           '*__*.' + str(os.getppid()) + '.*.grb')
     tobecleaned.delete_files()
+
+    do_retrievement(c, server, start, end, datechunk, fluxes=False)
+
+    return
+
+def do_retrievement(c, server, start, end, delta_t, fluxes=False):
+    '''
+    @Description:
+        Divides the complete retrieval period in smaller chunks and
+        retrieves the data from MARS.
+
+    @Input:
+        c: instance of ControlFile
+            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.
+
+        server: instance of ECMWFService
+            The server connection to ECMWF
+
+        start: instance of datetime
+            The start date of the retrieval.
+
+        end: instance of datetime
+            The end date of the retrieval.
+
+        delta_t: instance of datetime
+            Delta_t +1 is the maximal time period of a single
+            retrieval.
+
+        fluxes: boolean, optional
+            Decides if the flux parameters are to be retrieved or
+            the rest of the parameter list.
+            Default value is False.
+
+    @Return:
+        <nothing>
+    '''
+
+    # since actual day also counts as one day,
+    # we only need to add datechunk - 1 days to retrieval
+    # for a period
+    delta_t_m1 = delta_t - datetime.timedelta(days=1)
 
     day = start
     while day <= end:
-        # retrieve all non flux MARS data for the whole period
-        flexpart = EcFlexpart(c, fluxes=False)
-        tmpday = day + datechunk - datetime.timedelta(days=1)
+        flexpart = EcFlexpart(c, fluxes)
+        tmpday = day + delta_t_m1
         if tmpday < end:
             dates = day.strftime("%Y%m%d") + "/to/" + \
@@ -231,7 +285,7 @@
             flexpart.retrieve(server, dates, c.inputdir)
         except IOError:
-            my_error(c, 'MARS request failed')
-
-        day += datechunk
+            my_error(c.mailfail, 'MARS request failed')
+
+        day += delta_t
 
     return
Index: python/install.py
===================================================================
--- python/install.py	(revision ff99eae65dfaeec1221e06572d770ebd48feb3f4)
+++ python/install.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -1,10 +1,4 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-#************************************************************************
-# ToDo AP
-# - create a class Installation and divide installation in 3 subdefs for
-#   ecgate, local and cca seperatly
-# - Change History ist nicht angepasst ans File! Original geben lassen
-#************************************************************************
 #*******************************************************************************
 # @Author: Leopold Haimberger (University of Vienna)
@@ -37,6 +31,12 @@
 # @Program Content:
 #    - main
-#    - install_args_and_control
+#    - get_install_cmdline_arguments
 #    - install_via_gateway
+#    - mk_tarball
+#    - mk_env_vars
+#    - mk_compilejob
+#    - mk_job_template
+#    - delete_convert_build
+#    - make_convert_build
 #
 #*******************************************************************************
@@ -47,5 +47,4 @@
 import os
 import sys
-import glob
 import subprocess
 import inspect
@@ -54,4 +53,6 @@
 # software specific classes and modules from flex_extract
 from ControlFile import ControlFile
+from UioFiles import UioFiles
+from tools import make_dir, put_file_to_ecserver, submit_job_to_ecserver
 
 # add path to pythonpath so that python finds its buddies
@@ -61,4 +62,6 @@
     sys.path.append(LOCAL_PYTHON_PATH)
 
+_VERSION_STR = '7.1'
+
 # ------------------------------------------------------------------------------
 # FUNCTIONS
@@ -78,22 +81,27 @@
 
     os.chdir(LOCAL_PYTHON_PATH)
-    args, c = install_args_and_control()
-
-    if args.install_target is not None:
-        install_via_gateway(c, args.install_target)
-    else:
-        print 'Please specify installation target (local|ecgate|cca)'
-        print 'use -h or --help for help'
-
-    sys.exit()
-
-    return
-
-
-def install_args_and_control():
-    '''
-    @Description:
-        Assigns the command line arguments for installation and reads
-        CONTROL file content. Apply default values for non mentioned arguments.
+    args = get_install_cmdline_arguments()
+
+    try:
+        c = ControlFile(args.controlfile)
+    except IOError:
+        print 'Could not read CONTROL file "' + args.controlfile + '"'
+        print 'Either it does not exist or its syntax is wrong.'
+        print 'Try "' + sys.argv[0].split('/')[-1] + \
+              ' -h" to print usage information'
+        exit(1)
+
+    c.assign_args_to_control(args)
+    c.check_install_conditions()
+
+    install_via_gateway(c)
+
+    return
+
+def get_install_cmdline_arguments():
+    '''
+    @Description:
+        Decomposes the command line arguments and assigns them to variables.
+        Apply default values for non mentioned arguments.
 
     @Input:
@@ -103,5 +111,51 @@
         args: instance of ArgumentParser
             Contains the commandline arguments from script/program call.
-
+    '''
+    parser = ArgumentParser(description='Install flex_extract software locally or \
+                            on ECMWF machines',
+                            formatter_class=ArgumentDefaultsHelpFormatter)
+
+    parser.add_argument('--target', dest='install_target', default=None,
+                        help="Valid targets: local | ecgate | cca , \
+                        the latter two are at ECMWF")
+    parser.add_argument("--makefile", dest="makefile", default=None,
+                        help='Name of Makefile to use for compiling CONVERT2')
+    parser.add_argument("--ecuid", dest="ecuid", default=None,
+                        help='user id at ECMWF')
+    parser.add_argument("--ecgid", dest="ecgid", default=None,
+                        help='group id at ECMWF')
+    parser.add_argument("--gateway", dest="gateway", default=None,
+                        help='name of local gateway server')
+    parser.add_argument("--destination", dest="destination", default=None,
+                        help='ecaccess destination, e.g. leo@genericSftp')
+
+    parser.add_argument("--flexpart_root_scripts", dest="flexpart_root_scripts",
+                        default=None, help="FLEXPART root directory on ECMWF \
+                        servers (to find grib2flexpart and COMMAND file)\n\
+                        Normally flex_extract resides in the scripts directory \
+                        of the FLEXPART distribution, thus the:")
+
+    # arguments for job submission to ECMWF, only needed by submit.py
+    parser.add_argument("--job_template", dest='job_template',
+                        default="job.temp.o",
+                        help="job template file for submission to ECMWF")
+
+    parser.add_argument("--controlfile", dest="controlfile",
+                        default='CONTROL.temp',
+                        help="file with CONTROL parameters")
+
+    args = parser.parse_args()
+
+    return args
+
+
+def install_via_gateway(c):
+    '''
+    @Description:
+        Perform the actual installation on local machine or prepare data
+        transfer to remote gate and submit a job script which will
+        install everything on the remote gate.
+
+    @Input:
         c: instance of class ControlFile
             Contains all necessary information of a CONTROL file. The parameters
@@ -113,291 +167,325 @@
             For more information about format and content of the parameter see
             documentation.
-    '''
-    parser = ArgumentParser(description='Install ECMWFDATA software locally or \
-                            on ECMWF machines',
-                            formatter_class=ArgumentDefaultsHelpFormatter)
-
-    parser.add_argument('--target', dest='install_target',
-                        help="Valid targets: local | ecgate | cca , \
-                        the latter two are at ECMWF")
-    parser.add_argument("--makefile", dest="makefile",
-                        help='Name of Makefile to use for compiling CONVERT2')
-    parser.add_argument("--ecuid", dest="ecuid",
-                        help='user id at ECMWF')
-    parser.add_argument("--ecgid", dest="ecgid",
-                        help='group id at ECMWF')
-    parser.add_argument("--gateway", dest="gateway",
-                        help='name of local gateway server')
-    parser.add_argument("--destination", dest="destination",
-                        help='ecaccess destination, e.g. leo@genericSftp')
-
-    parser.add_argument("--flexpart_root_scripts", dest="flexpart_root_scripts",
-                        help="FLEXPART root directory on ECMWF servers \
-                        (to find grib2flexpart and COMMAND file)\n\
-                        Normally ECMWFDATA resides in the scripts directory \
-                        of the FLEXPART distribution, thus the:")
-
-# arguments for job submission to ECMWF, only needed by submit.py
-    parser.add_argument("--job_template", dest='job_template',
-                        default="job.temp.o",
-                        help="job template file for submission to ECMWF")
-
-    parser.add_argument("--controlfile", dest="controlfile",
-                        default='CONTROL.temp',
-                        help="file with CONTROL parameters")
-
-    args = parser.parse_args()
-
-    try:
-        c = ControlFile(args.controlfile)
-    except IOError:
-        print 'Could not read CONTROL file "' + args.controlfile + '"'
-        print 'Either it does not exist or its syntax is wrong.'
-        print 'Try "' + sys.argv[0].split('/')[-1] + \
-              ' -h" to print usage information'
-        exit(1)
-
-    if args.install_target != 'local':
-        if args.ecgid is None or args.ecuid is None or args.gateway is None \
-           or args.destination is None:
-            print 'Please enter your ECMWF user id and group id as well as \
-                   the \nname of the local gateway and the ectrans \
-                   destination '
-            print 'with command line options --ecuid --ecgid \
-                   --gateway --destination'
-            print 'Try "' + sys.argv[0].split('/')[-1] + \
-                  ' -h" to print usage information'
-            print 'Please consult ecaccess documentation or ECMWF user support \
-                   for further details'
-            sys.exit(1)
-        else:
-            c.ecuid = args.ecuid
-            c.ecgid = args.ecgid
-            c.gateway = args.gateway
-            c.destination = args.destination
-
-    if args.makefile:
-        c.makefile = args.makefile
-
-    if args.install_target == 'local':
-        if args.flexpart_root_scripts is None:
-            c.flexpart_root_scripts = '../'
-        else:
-            c.flexpart_root_scripts = args.flexpart_root_scripts
-
-    if args.install_target != 'local':
-        if args.flexpart_root_scripts is None:
-            c.ec_flexpart_root_scripts = '${HOME}'
-        else:
-            c.ec_flexpart_root_scripts = args.flexpart_root_scripts
-
-    return args, c
-
-
-def install_via_gateway(c, target):
-    '''
-    @Description:
-        Perform the actual installation on local machine or prepare data
-        transfer to remote gate and submit a job script which will
-        install everything on the remote gate.
-
-    @Input:
-        c: instance of class ControlFile
-            Contains all necessary information of a CONTROL file. The parameters
-            are: DAY1, DAY2, DTIME, MAXSTEP, TYPE, TIME, STEP, CLASS, 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
-            For more information about format and content of the parameter see
-            documentation.
-
-        target: string
-            The target where the installation should be processed.
-            E.g. "local", "ecgate" or "cca"
-
-    @Return:
-        <nothing>
-    '''
+
+    @Return:
+        <nothing>
+    '''
+
     ecd = c.ecmwfdatadir
-    template = ecd + 'python/compilejob.temp'
-    job = ecd + 'python/compilejob.ksh'
-    fo = open(job, 'w')
-#AP could do with open(template) as f, open(job, 'w') as fo:
-#AP or nested with statements
-    with open(template) as f:
-        fdata = f.read().split('\n')
-        for data in fdata:
-            if 'MAKEFILE=' in data:
-                if c.makefile is not None:
-                    data = 'export MAKEFILE=' + c.makefile
-            if 'FLEXPART_ROOT_SCRIPTS=' in data:
-                if c.flexpart_root_scripts != '../':
-                    data = 'export FLEXPART_ROOT_SCRIPTS=' + \
-                            c.flexpart_root_scripts
-                else:
-                    data = 'export FLEXPART_ROOT_SCRIPTS=$HOME'
-            if target.lower() != 'local':
-                if '--workdir' in data:
-                    data = '#SBATCH --workdir=/scratch/ms/' + c.ecgid + \
-                            '/' + c.ecuid
-                if '##PBS -o' in data:
-                    data = '##PBS -o /scratch/ms/' + c.ecgid + '/' + c.ecuid + \
-                            'flex_ecmwf.$Jobname.$Job_ID.out'
-                if 'FLEXPART_ROOT_SCRIPTS=' in data:
-                    if c.ec_flexpart_root_scripts != '../':
-                        data = 'export FLEXPART_ROOT_SCRIPTS=' + \
-                                c.ec_flexpart_root_scripts
-                    else:
-                        data = 'export FLEXPART_ROOT_SCRIPTS=$HOME'
-            fo.write(data + '\n')
-    f.close()
-    fo.close()
-
-    if target.lower() != 'local':
-        template = ecd + 'python/job.temp.o'
-#AP hier eventuell Zeile für Zeile lesen und dann if Entscheidung
-        with open(template) as f:
-            fdata = f.read().split('\n')
-        f.close()
-        fo = open(template[:-2], 'w')
-        for data in fdata:
-            if '--workdir' in data:
-                data = '#SBATCH --workdir=/scratch/ms/' + c.ecgid + \
-                        '/' + c.ecuid
-            if '##PBS -o' in data:
-                data = '##PBS -o /scratch/ms/' + c.ecgid + '/' + \
-                        c.ecuid + 'flex_ecmwf.$Jobname.$Job_ID.out'
-            if  'export PATH=${PATH}:' in data:
-                data += c.ec_flexpart_root_scripts + '/ECMWFDATA7.1/python'
-            if 'cat>>' in data or 'cat >>' in data:
-                i = data.index('>')
-                fo.write(data[:i] + data[i+1:] + '\n')
-                fo.write('GATEWAY ' + c.gateway + '\n')
-                fo.write('DESTINATION ' + c.destination + '\n')
-                fo.write('EOF\n')
-
-            fo.write(data + '\n')
-        fo.close()
-
-        job = ecd + 'python/ECMWF_ENV'
-        with open(job, 'w') as fo:
-            fo.write('ECUID ' + c.ecuid + '\n')
-            fo.write('ECGID ' + c.ecgid + '\n')
-            fo.write('GATEWAY ' + c.gateway + '\n')
-            fo.write('DESTINATION ' + c.destination + '\n')
-        fo.close()
-
-    if target.lower() == 'local':
-        # compile CONVERT2
-        if c.flexpart_root_scripts is None or c.flexpart_root_scripts == '../':
-            print 'Warning: FLEXPART_ROOT_SCRIPTS has not been specified'
-            print 'Only CONVERT2 will be compiled in ' + ecd + '/../src'
-        else:
+    tarball_name = 'flex_extract_v' + _VERSION_STR + '.tar'
+    target_dir = 'flex_extract_v' + _VERSION_STR
+    fortran_executable = 'CONVERT2'
+
+    if c.install_target.lower() != 'local':
+
+        mk_compilejob(ecd + 'python/compilejob.temp', c.makefile,
+                      c.install_target, c.ecuid, c.ecgid,
+                      c.flexpart_root_scripts)
+
+        mk_job_template(ecd + 'python/job.temp.o', c.ecuid, c.ecgid, c.gateway,
+                        c.destination, c.flexpart_root_scripts)
+
+        mk_env_vars(ecd, c.ecuid, c.ecgid, c.gateway, c.destination)
+
+        #os.chdir('/')
+
+        mk_tarball(ecd, tarball_name)
+
+        put_file_to_ecserver(ecd, tarball_name, c.install_target,
+                             c.ecuid, c.ecgid)
+
+        submit_job_to_ecserver(ecd + '/python/', c.install_target,
+                               'compilejob.ksh')
+
+        print 'job compilation script has been submitted to ecgate for ' + \
+              'installation in ' + c.flexpart_root_scripts + \
+               '/' + target_dir
+        print 'You should get an email with subject flexcompile within ' + \
+              'the next few minutes!'
+
+    else: #local
+        if not c.flexpart_root_scripts or c.flexpart_root_scripts == '../':
+            print 'WARNING: FLEXPART_ROOT_SCRIPTS has not been specified'
+            print 'There will be only the compilation of ' + \
+                  ' in ' + ecd + '/src'
+            os.chdir(ecd + '/src')
+        else: # creates the target working directory for flex_extract
             c.flexpart_root_scripts = os.path.expandvars(os.path.expanduser(
                 c.flexpart_root_scripts))
             if os.path.abspath(ecd) != os.path.abspath(c.flexpart_root_scripts):
                 os.chdir('/')
-                p = subprocess.check_call(['tar', '-cvf',
-                                           ecd + '../ECMWFDATA7.1.tar',
-                                           ecd + 'python',
-                                           ecd + 'grib_templates',
-                                           ecd + 'src'])
-                try:
-                    os.makedirs(c.flexpart_root_scripts + '/ECMWFDATA7.1')
-                finally:
-                    pass
-                os.chdir(c.flexpart_root_scripts + '/ECMWFDATA7.1')
-                p = subprocess.check_call(['tar', '-xvf',
-                                           ecd + '../ECMWFDATA7.1.tar'])
-                os.chdir(c.flexpart_root_scripts + '/ECMWFDATA7.1/src')
-
-        os.chdir('../src')
-        print(('install ECMWFDATA7.1 software on ' + target + ' in directory '
-               + os.getcwd()))
-        if c.makefile is None:
-            makefile = 'Makefile.local.ifort'
-        else:
-            makefile = c.makefile
-        flist = glob.glob('*.mod') + glob.glob('*.o')
-        if flist:
-            p = subprocess.check_call(['rm'] + flist)
-        try:
-            print 'Using makefile: ' + makefile
-            p = subprocess.check_call(['make', '-f', makefile])
-            p = subprocess.check_call(['ls', '-l', 'CONVERT2'])
-        except subprocess.CalledProcessError as e:
-            print 'compile failed with the following error:'
-            print e.output
-            print 'please edit ' + makefile + \
+                mk_tarball(ecd, tarball_name)
+                make_dir(c.flexpart_root_scripts + '/' + target_dir)
+                os.chdir(c.flexpart_root_scripts + '/' + target_dir)
+                print 'Untar ...'
+                subprocess.check_call(['tar', '-xvf',
+                                       ecd + '../' + tarball_name])
+                os.chdir(c.flexpart_root_scripts + '/' + target_dir + '/src')
+
+        # Create Fortran executable - CONVERT2
+        print 'Install ' + target_dir + ' software on ' + \
+              c.install_target + ' in directory ' + \
+              os.path.abspath(os.getcwd() + '/../') + '\n'
+
+        delete_convert_build('')
+        make_convert_build('', c.makefile, fortran_executable)
+
+    return
+
+def mk_tarball(ecd, tarname):
+    '''
+    @Description:
+        Creates a tarball from all files which need to be sent to the
+        installation directory.
+        It does not matter if this is local or remote.
+        Collects all python files, the Fortran source and makefiles,
+        the ECMWF_ENV file, the CONTROL files as well as
+        the korn shell and template files.
+
+    @Input:
+        ecd: string
+            The path were the file is to be stored.
+
+        tarname: string
+            The name of the file to send to the ECMWF server.
+
+    @Return:
+        <nothing>
+    '''
+
+    print 'Create tarball ...'
+    try:
+        subprocess.check_call(['tar -cvf '+
+                               ecd + '../' + tarname + ' ' +
+                               ecd + 'python/*py ' +
+                               ecd + 'python/CONTROL* ' +
+                               ecd + 'python/*ksh ' +
+                               ecd + 'python/*temp* ' +
+                               ecd + 'python/ECMWF_ENV ' +
+                               ecd + 'grib_templates ' +
+                               ecd + 'src/*.f ' +
+                               ecd + 'src/*.f90 ' +
+                               ecd + 'src/*.h ' +
+                               ecd + 'src/Makefile*'], shell=True)
+    except subprocess.CalledProcessError as e:
+        print 'ERROR:'
+        print e.output
+        sys.exit('could not make installation tar ball!')
+
+    return
+
+def mk_env_vars(ecd, ecuid, ecgid, gateway, destination):
+    '''
+    @Description:
+        Creates a file named ECMWF_ENV which contains the
+        necessary environmental variables at ECMWF servers.
+
+    @Input:
+        ecd: string
+            The path were the file is to be stored.
+
+        ecuid: string
+            The user id on ECMWF server.
+
+        ecgid: string
+            The group id on ECMWF server.
+
+        gateway: string
+            The gateway server the user is using.
+
+        destination: string
+            The remote destination which is used to transfer files
+            from ECMWF server to local gateway server.
+
+    @Return:
+        <nothing>
+    '''
+
+    with open(ecd + 'python/ECMWF_ENV', 'w') as fo:
+        fo.write('ECUID ' + ecuid + '\n')
+        fo.write('ECGID ' + ecgid + '\n')
+        fo.write('GATEWAY ' + gateway + '\n')
+        fo.write('DESTINATION ' + destination + '\n')
+
+    return
+
+def mk_compilejob(template, makefile, target, ecuid, ecgid, fp_root):
+    '''
+    @Description:
+        Modifies the original job template file so that it is specified
+        for the user and the environment were it will be applied. Result
+        is stored in a new file "job.temp" in the python directory.
+
+    @Input:
+        template: string
+            File which contains the original text for the job template.
+            It must contain the complete path to the file.
+
+        makefile: string
+            Name of the makefile which should be used to compile FORTRAN
+            CONVERT2 program.
+
+        target: string
+            The target where the installation should be done, e.g. the queue.
+
+        ecuid: string
+            The user id on ECMWF server.
+
+        ecgid: string
+            The group id on ECMWF server.
+
+        fp_root: string
+           Path to the root directory of FLEXPART environment or flex_extract
+           environment.
+
+    @Return:
+        <nothing>
+    '''
+
+    with open(template) as f:
+        fdata = f.read().split('\n')
+
+    with open(template[:-4] + 'ksh', 'w') as fo:
+        for data in fdata:
+            if 'MAKEFILE=' in data:
+                data = 'export MAKEFILE=' + makefile
+            elif 'FLEXPART_ROOT_SCRIPTS=' in data:
+                if fp_root != '../':
+                    data = 'export FLEXPART_ROOT_SCRIPTS=' + fp_root
+                else:
+                    data = 'export FLEXPART_ROOT_SCRIPTS=$HOME'
+            elif target.lower() != 'local':
+                if '--workdir' in data:
+                    data = '#SBATCH --workdir=/scratch/ms/' + \
+                            ecgid + '/' + ecuid
+                elif '##PBS -o' in data:
+                    data = '##PBS -o /scratch/ms/' + ecgid + '/' + ecuid + \
+                           'flex_ecmwf.$Jobname.$Job_ID.out'
+                elif 'FLEXPART_ROOT_SCRIPTS=' in data:
+                    if fp_root != '../':
+                        data = 'export FLEXPART_ROOT_SCRIPTS=' + fp_root
+                    else:
+                        data = 'export FLEXPART_ROOT_SCRIPTS=$HOME'
+            fo.write(data + '\n')
+
+    return
+
+def mk_job_template(template, ecuid, ecgid, gateway, destination, fp_root):
+    '''
+    @Description:
+        Modifies the original job template file so that it is specified
+        for the user and the environment were it will be applied. Result
+        is stored in a new file "job.temp" in the python directory.
+
+    @Input:
+        template: string
+            File which contains the original text for the job template.
+            It must contain the complete path to the file.
+
+        ecuid: string
+            The user id on ECMWF server.
+
+        ecgid: string
+            The group id on ECMWF server.
+
+        gateway: string
+            The gateway server the user is using.
+
+        destination: string
+            The remote destination which is used to transfer files
+            from ECMWF server to local gateway server.
+
+        fp_root: string
+           Path to the root directory of FLEXPART environment or flex_extract
+           environment.
+
+    @Return:
+        <nothing>
+    '''
+
+    with open(template) as f:
+        fdata = f.read().split('\n')
+
+    with open(template[:-2], 'w') as fo:
+        for data in fdata:
+            if '--workdir' in data:
+                data = '#SBATCH --workdir=/scratch/ms/' + ecgid + \
+                        '/' + ecuid
+            elif '##PBS -o' in data:
+                data = '##PBS -o /scratch/ms/' + ecgid + '/' + \
+                        ecuid + 'flex_ecmwf.$Jobname.$Job_ID.out'
+            elif  'export PATH=${PATH}:' in data:
+                data += fp_root + '/flex_extract_v7.1/python'
+
+            fo.write(data + '\n')
+    return
+
+def delete_convert_build(ecd):
+    '''
+    @Description:
+        Clean up the Fortran source directory and remove all
+        build files (e.g. *.o, *.mod and CONVERT2)
+
+    @Input:
+        ecd: string
+            The path to the Fortran program.
+
+    @Return:
+        <nothing>
+    '''
+
+    modfiles = UioFiles(ecd, '*.mod')
+    objfiles = UioFiles(ecd, '*.o')
+    exefile = UioFiles(ecd, 'CONVERT2')
+
+    modfiles.delete_files()
+    objfiles.delete_files()
+    exefile.delete_files()
+
+    return
+
+def make_convert_build(ecd, makefile, f_executable):
+    '''
+    @Description:
+        Compiles the Fortran code and generates the executable.
+
+    @Input:
+        ecd: string
+            The path were the file is to be stored.
+
+        makefile: string
+            The name of the makefile which should be used.
+
+        f_executable: string
+            The name of the executable the Fortran program generates after
+            compilation.
+
+    @Return:
+        <nothing>
+    '''
+
+    try:
+        print 'Using makefile: ' + makefile
+        p = subprocess.Popen(['make', '-f', ecd + makefile],
+                             stdin=subprocess.PIPE,
+                             stdout=subprocess.PIPE,
+                             stderr=subprocess.PIPE,
+                             bufsize=1)
+        pout, perr = p.communicate()
+        print pout
+        if p.returncode != 0:
+            print perr
+            print 'Please edit ' + makefile + \
                   ' or try another Makefile in the src directory.'
-            print 'most likely GRIB_API_INCLUDE_DIR, GRIB_API_LIB  \
-                   and EMOSLIB must be adapted.'
+            print 'Most likely GRIB_API_INCLUDE_DIR, GRIB_API_LIB ' \
+                  'and EMOSLIB must be adapted.'
             print 'Available Makefiles:'
-            print glob.glob('Makefile*')
-    elif target.lower() == 'ecgate':
-        os.chdir('/')
-        p = subprocess.check_call(['tar', '-cvf',
-                                   ecd + '../ECMWFDATA7.1.tar',
-                                   ecd + 'python',
-                                   ecd + 'grib_templates',
-                                   ecd + 'src'])
-        try:
-            p = subprocess.check_call(['ecaccess-file-put',
-                                       ecd + '../ECMWFDATA7.1.tar',
-                                       'ecgate:/home/ms/' + c.ecgid + '/' +
-                                       c.ecuid + '/ECMWFDATA7.1.tar'])
-        except subprocess.CalledProcessError as e:
-            print 'ecaccess-file-put failed! \
-                   Probably the eccert key has expired.'
-            exit(1)
-
-        try:
-            p = subprocess.check_call(['ecaccess-job-submit',
-                                       '-queueName',
-                                       target,
-                                       ecd + 'python/compilejob.ksh'])
-            print 'compilejob.ksh has been submitted to ecgate for  \
-                   installation in ' + c.ec_flexpart_root_scripts + \
-                   '/ECMWFDATA7.1'
-            print 'You should get an email with subject flexcompile within  \
-                   the next few minutes'
-        except subprocess.CalledProcessError as e:
-            print 'ecaccess-job-submit failed!'
-            exit(1)
-
-    elif target.lower() == 'cca':
-        os.chdir('/')
-        p = subprocess.check_call(['tar', '-cvf',
-                                   ecd + '../ECMWFDATA7.1.tar',
-                                   ecd + 'python',
-                                   ecd + 'grib_templates',
-                                   ecd + 'src'])
-        try:
-            p = subprocess.check_call(['ecaccess-file-put',
-                                       ecd + '../ECMWFDATA7.1.tar',
-                                       'cca:/home/ms/' + c.ecgid + '/' +
-                                       c.ecuid + '/ECMWFDATA7.1.tar'])
-        except subprocess.CalledProcessError as e:
-            print 'ecaccess-file-put failed! \
-                   Probably the eccert key has expired.'
-            exit(1)
-
-        try:
-            p = subprocess.check_call(['ecaccess-job-submit',
-                                       '-queueName',
-                                       target,
-                                       ecd + 'python/compilejob.ksh'])
-            print 'compilejob.ksh has been submitted to cca for installation in ' +\
-                  c.ec_flexpart_root_scripts + '/ECMWFDATA7.1'
-            print 'You should get an email with subject flexcompile \
-                   within the next few minutes'
-        except subprocess.CalledProcessError as e:
-            print 'ecaccess-job-submit failed!'
-            exit(1)
-
+            print UioFiles('.', 'Makefile*')
+            sys.exit('Compilation failed!')
+    except ValueError as e:
+        print 'ERROR: Makefile call failed:'
+        print e
     else:
-        print 'ERROR: unknown installation target ', target
-        print 'Valid targets: ecgate, cca, local'
+        subprocess.check_call(['ls', '-l', ecd + f_executable])
 
     return
Index: python/job.ksh
===================================================================
--- python/job.ksh	(revision ccab8091e3f70844b2b6e73b9aa5e6b41aaf5ff5)
+++ python/job.ksh	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -33,7 +33,5 @@
   module load grib_api/1.14.5
   module load emos/437-r64
-#  export ECMWFDATA=$HOME/ECMWFDATA$VERSION
-#  export PYTHONPATH=$ECMWFDATA/python
-  export PATH=${PATH}:${HOME}/ECMWFDATA7.1/python
+  export PATH=${PATH}:${HOME}/flex_extract_v7.1/python
   ;;
   *cca*)
@@ -43,15 +41,6 @@
   module load python
   export SCRATCH=$TMPDIR
-#  export ECMWFDATA=$HOME/ECMWFDATA$VERSION
-#  export PYTHONPATH=$ECMWFDATA/python
-  export PATH=${PATH}:${HOME}/ECMWFDATA7.1/python
+  export PATH=${PATH}:${HOME}/flex_extract_v7.1/python
   ;;
-#  *)
-#  export ECMWFDATA=$HOME/ECMWFDATA$VERSION
-#  export PATH=/opt/anaconda/bin:$ECMWFDATA/python:${PATH}
-#  export PYTHONPATH=/opt/anaconda/lib/python2.7/site-packages/grib_api:$ECMWFDATA/python
-#  export SCRATCH=$ECMWFDATA/python
-#  which python
-#  ;;
 esac
 
@@ -63,32 +52,39 @@
 
 cat >$CONTROL<<EOF
-GATEWAY srvx8.img.univie.ac.at
-DESTINATION annep@genericSftp
-accuracy 16
+accuracy 24
 addpar 186 187 188 235 139 39 
+area 
 basetime None
+controlfile CONTROL.test
 cwc 0
 date_chunk 3
-debug 1
+debug 0
+destination annep@genericSftp
 dpdeta 1
 dtime 3
 ecfsdir ectmp:/${USER}/econdemand/
+ecgid at
 ecstorage 0
 ectrans 1
-end_date 20160809
+ecuid km4a
+end_date 20000101
 eta 0
 etadiff 0
+etapar 77
 expver 1
 format GRIB1
+gateway srvx8.img.univie.ac.at
 gauss 1
 grib2flexpart 0
 grid 5000
 inputdir ../work
+install_target None
+job_template job.temp
 left -15000
 level 60
 levelist 55/to/60
 lower 30000
-mailfail ${USER}
-mailops ${USER}
+mailfail ${USER} 
+mailops ${USER} 
 makefile None
 marsclass EI
@@ -98,9 +94,10 @@
 omegadiff 0
 outputdir ../work
-prefix EI
+prefix EItest_
+queue ecgate
 resol 63
 right 45000
 smooth 0
-start_date 20160809
+start_date 20000101
 step 00 01 02 03 04 05 00 07 08 09 10 11 00 01 02 03 04 05 00 07 08 09 10 11 
 stream OPER
@@ -108,4 +105,5 @@
 type AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC 
 upper 75000
+wrf 0
 EOF
 
Index: python/job.temp
===================================================================
--- python/job.temp	(revision 991df6ad0a703d97e1e192a0a6106e1d9ba47e8e)
+++ python/job.temp	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -33,7 +33,5 @@
   module load grib_api/1.14.5
   module load emos/437-r64
-#  export ECMWFDATA=$HOME/ECMWFDATA$VERSION
-#  export PYTHONPATH=$ECMWFDATA/python
-  export PATH=${PATH}:${HOME}/ECMWFDATA7.1/python
+  export PATH=${PATH}:${HOME}/flex_extract_v7.1/python
   ;;
   *cca*)
@@ -43,15 +41,6 @@
   module load python
   export SCRATCH=$TMPDIR
-#  export ECMWFDATA=$HOME/ECMWFDATA$VERSION
-#  export PYTHONPATH=$ECMWFDATA/python
-  export PATH=${PATH}:${HOME}/ECMWFDATA7.1/python
+  export PATH=${PATH}:${HOME}/flex_extract_v7.1/python
   ;;
-#  *)
-#  export ECMWFDATA=$HOME/ECMWFDATA$VERSION
-#  export PATH=/opt/anaconda/bin:$ECMWFDATA/python:${PATH}
-#  export PYTHONPATH=/opt/anaconda/lib/python2.7/site-packages/grib_api:$ECMWFDATA/python
-#  export SCRATCH=$ECMWFDATA/python
-#  which python
-#  ;;
 esac
 
@@ -63,8 +52,4 @@
 
 cat >$CONTROL<<EOF
-GATEWAY srvx8.img.univie.ac.at
-DESTINATION annep@genericSftp
-EOF
-cat >>$CONTROL<<EOF
 EOF
 
Index: python/job.temp.o
===================================================================
--- python/job.temp.o	(revision efdb01a8ac2d5cef85c651177aa18ac69dd660db)
+++ python/job.temp.o	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -33,6 +33,4 @@
   module load grib_api/1.14.5
   module load emos/437-r64
-#  export ECMWFDATA=$HOME/ECMWFDATA$VERSION
-#  export PYTHONPATH=$ECMWFDATA/python
   export PATH=${PATH}:
   ;;
@@ -43,15 +41,6 @@
   module load python
   export SCRATCH=$TMPDIR
-#  export ECMWFDATA=$HOME/ECMWFDATA$VERSION
-#  export PYTHONPATH=$ECMWFDATA/python
   export PATH=${PATH}:
   ;;
-#  *)
-#  export ECMWFDATA=$HOME/ECMWFDATA$VERSION
-#  export PATH=/opt/anaconda/bin:$ECMWFDATA/python:${PATH}
-#  export PYTHONPATH=/opt/anaconda/lib/python2.7/site-packages/grib_api:$ECMWFDATA/python
-#  export SCRATCH=$ECMWFDATA/python
-#  which python
-#  ;;
 esac
 
@@ -62,5 +51,5 @@
 export CONTROL=CONTROL
 
-cat >>$CONTROL<<EOF
+cat >$CONTROL<<EOF
 EOF
 
Index: python/joboper.ksh
===================================================================
--- python/joboper.ksh	(revision ccab8091e3f70844b2b6e73b9aa5e6b41aaf5ff5)
+++ python/joboper.ksh	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -33,7 +33,5 @@
   module load grib_api/1.14.5
   module load emos/437-r64
-#  export ECMWFDATA=$HOME/ECMWFDATA$VERSION
-#  export PYTHONPATH=$ECMWFDATA/python
-  export PATH=${PATH}:${HOME}/ECMWFDATA7.1/python
+  export PATH=${PATH}:${HOME}/flex_extract_v7.1/python
   ;;
   *cca*)
@@ -43,15 +41,6 @@
   module load python
   export SCRATCH=$TMPDIR
-#  export ECMWFDATA=$HOME/ECMWFDATA$VERSION
-#  export PYTHONPATH=$ECMWFDATA/python
-  export PATH=${PATH}:${HOME}/ECMWFDATA7.1/python
+  export PATH=${PATH}:${HOME}/flex_extract_v7.1/python
   ;;
-#  *)
-#  export ECMWFDATA=$HOME/ECMWFDATA$VERSION
-#  export PATH=/opt/anaconda/bin:$ECMWFDATA/python:${PATH}
-#  export PYTHONPATH=/opt/anaconda/lib/python2.7/site-packages/grib_api:$ECMWFDATA/python
-#  export SCRATCH=$ECMWFDATA/python
-#  which python
-#  ;;
 esac
 
@@ -67,28 +56,38 @@
 accuracy 16
 addpar 186 187 188 235 139 39 
+area 
+base_time ${MSJ_BASETIME}
 basetime None
+controlfile CONTROL.temp
 cwc 0
 date_chunk 3
 debug 1
+destination None
 dpdeta 1
 dtime 3
 ecfsdir ectmp:/${USER}/econdemand/
+ecgid None
 ecstorage 0
 ectrans 1
-start_date ${MSJ_YEAR}${MSJ_MONTH}${MSJ_DAY}
+ecuid None
+end_date ${MSJ_YEAR}${MSJ_MONTH}${MSJ_DAY}
 eta 0
 etadiff 0
+etapar 77
 expver 1
 format GRIB1
+gateway None
 gauss 1
 grib2flexpart 0
 grid 5000
 inputdir ../work
+install_target None
+job_template job.temp
 left -15000
 level 60
 levelist 55/to/60
 lower 30000
-mailfail ${USER}
-mailops ${USER}
+mailfail ${USER} 
+mailops ${USER} 
 makefile None
 marsclass EI
@@ -99,4 +98,5 @@
 outputdir ../work
 prefix EI
+queue ecgate
 resol 63
 right 45000
@@ -108,4 +108,5 @@
 type AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC AN FC FC FC FC FC 
 upper 75000
+wrf 0
 EOF
 
Index: python/mk_install_tar.sh
===================================================================
--- python/mk_install_tar.sh	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
+++ python/mk_install_tar.sh	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -0,0 +1,15 @@
+#!/bin/bash
+#
+# @Author: Anne Philipp
+#
+# @Date: June, 7 2018
+#
+# @Description: Makes a tarball for installation
+#
+
+tarname='flex_extract_v7.1.tar.gz'
+path='/nas/tmc/Anne/Interpolation/flexextract/flexextract/python/../'
+
+tar -cvf $tarname ${path}python/*py ${path}python/CONTROL* ${path}python/*ksh ${path}python/*temp ${path}python/ECMWF_ENV ${path}python/*json ${path}grib_templates ${path}src/*.f ${path}src/*.f90 ${path}src/*.h ${path}src/Makefile*  
+
+
Index: python/plot_retrieved.py
===================================================================
--- python/plot_retrieved.py	(revision ff99eae65dfaeec1221e06572d770ebd48feb3f4)
+++ python/plot_retrieved.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -1,10 +1,4 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-#************************************************************************
-# ToDo AP
-# - documentation der Funktionen
-# - docu der progam functionality
-# - apply pep8
-#************************************************************************
 #*******************************************************************************
 # @Author: Leopold Haimberger (University of Vienna)
@@ -34,4 +28,5 @@
 #    - main
 #    - get_basics
+#    - get_files_per_date
 #    - plot_retrieved
 #    - plot_timeseries
@@ -219,6 +214,5 @@
     c.area = np.asarray(c.area)
 
-    files = UioFiles(c.prefix+'*')
-    files.list_files(c.inputdir)
+    files = UioFiles(c.inputdir, c.prefix+'*')
     ifiles = get_files_per_date(files.files, datelist)
     ifiles.sort()
@@ -622,5 +616,5 @@
                         help="FLEXPART root directory (to find \
                         'grib2flexpart and COMMAND file)\n \
-                        Normally ECMWFDATA resides in the scripts directory \
+                        Normally flex_extract resides in the scripts directory \
                         of the FLEXPART distribution")
 
Index: python/prepare_flexpart.py
===================================================================
--- python/prepare_flexpart.py	(revision None)
+++ python/prepare_flexpart.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -1,9 +1,4 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-#************************************************************************
-# ToDo AP
-# - wieso start=startm1 wenn basetime = 0 ?  wenn die fluxes nicht mehr
-#   relevant sind? verstehe ich nicht
-#************************************************************************
 #*******************************************************************************
 # @Author: Anne Fouilloux (University of Oslo)
@@ -62,8 +57,9 @@
 import sys
 import socket
+import _config
 
 # software specific classes and modules from flex_extract
 from UioFiles import UioFiles
-from tools import interpret_args_and_control, clean_up
+from tools import clean_up, get_cmdline_arguments, read_ecenv
 from EcFlexpart import EcFlexpart
 
@@ -81,4 +77,5 @@
     sys.path.append(LOCAL_PYTHON_PATH)
 
+
 # ------------------------------------------------------------------------------
 # FUNCTION
@@ -97,10 +94,28 @@
         <nothing>
     '''
-    args, c = interpret_args_and_control()
-    prepare_flexpart(args, c)
+
+    args = get_cmdline_arguments()
+
+    try:
+        c = ControlFile(args.controlfile)
+    except IOError:
+        try:
+            c = ControlFile(LOCAL_PYTHON_PATH + args.controlfile)
+        except IOError:
+            print 'Could not read CONTROL file "' + args.controlfile + '"'
+            print 'Either it does not exist or its syntax is wrong.'
+            print 'Try "' + sys.argv[0].split('/')[-1] + \
+                  ' -h" to print usage information'
+            sys.exit(1)
+
+    env_parameter = read_ecenv(c.ecmwfdatadir + 'python/ECMWF_ENV')
+    c.assign_args_to_control(args, env_parameter)
+    c.assign_envs_to_control(env_parameter)
+    c.check_conditions()
+    prepare_flexpart(args.ppid, c)
 
     return
 
-def prepare_flexpart(args, c):
+def prepare_flexpart(ppid, c):
     '''
     @Description:
@@ -112,6 +127,7 @@
 
     @Input:
-        args: instance of ArgumentParser
-            Contains the commandline arguments from script/program call.
+        ppid: int
+            Contains the ppid number of the current ECMWF job. If it is called
+            from this script, it is "None".
 
         c: instance of class ControlFile
@@ -132,8 +148,8 @@
     '''
 
-    if not args.ppid:
+    if not ppid:
         c.ppid = str(os.getppid())
     else:
-        c.ppid = args.ppid
+        c.ppid = ppid
 
     c.ecapi = ecapi
@@ -148,17 +164,19 @@
                         day=int(c.end_date[6:]))
 
-    # to deaccumulate the fluxes correctly
-    # one day ahead of the start date and
-    # one day after the end date is needed
-    startm1 = start - datetime.timedelta(days=1)
-#    endp1 = end + datetime.timedelta(days=1)
-
-    # get all files with flux data to be deaccumulated
-    inputfiles = UioFiles('*OG_acc_SL*.' + c.ppid + '.*')
-    inputfiles.list_files(c.inputdir)
+    # assign starting date minus 1 day
+    # since for basetime 00 we need the 12 hours upfront
+    # (the day before from 12 UTC to current day 00 UTC)
+    if c.basetime == '00':
+        start = start - datetime.timedelta(days=1)
+
+    print 'Prepare ' + start.strftime("%Y%m%d") + \
+           "/to/" + end.strftime("%Y%m%d")
 
     # create output dir if necessary
     if not os.path.exists(c.outputdir):
         os.makedirs(c.outputdir)
+
+    # get all files with flux data to be deaccumulated
+    inputfiles = UioFiles(c.inputdir, '*OG_acc_SL*.' + c.ppid + '.*')
 
     # deaccumulate the flux data
@@ -167,17 +185,9 @@
     flexpart.deacc_fluxes(inputfiles, c)
 
-    print 'Prepare ' + start.strftime("%Y%m%d") + \
-          "/to/" + end.strftime("%Y%m%d")
-
     # get a list of all files from the root inputdir
-    inputfiles = UioFiles('????__??.*' + c.ppid + '.*')
-    inputfiles.list_files(c.inputdir)
-
-    # produce FLEXPART-ready GRIB files and
-    # process GRIB files -
+    inputfiles = UioFiles(c.inputdir, '????__??.*' + c.ppid + '.*')
+
+    # produce FLEXPART-ready GRIB files and process them -
     # copy/transfer/interpolate them or make them GRIB2
-    if c.basetime == '00':
-        start = startm1
-
     flexpart = EcFlexpart(c, fluxes=False)
     flexpart.create(inputfiles, c)
@@ -187,5 +197,5 @@
     # otherwise delete temporary files
     if int(c.debug) != 0:
-        print 'Temporary files left intact'
+        print '\nTemporary files left intact'
     else:
         clean_up(c)
Index: python/profiling.py
===================================================================
--- python/profiling.py	(revision ff99eae65dfaeec1221e06572d770ebd48feb3f4)
+++ python/profiling.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -3,5 +3,5 @@
 #************************************************************************
 # ToDo AP
-# - check of license of book content
+# - check license of book content
 #************************************************************************
 #*******************************************************************************
Index: thon/set_CTBTO_env.csh
===================================================================
--- python/set_CTBTO_env.csh	(revision d69b6776d6d39e0af0d38c95cbfd78284c9866e4)
+++ 	(revision )
@@ -1,12 +1,0 @@
-#!/bin/csh
-
-# script to prepare CTBTO environment for
-# ECMWFDATA7.0
-# 
-# Leo Haimberger 1.3.2016
-
-setenv PATH /dvl/atm/klinkl/software/local/bin:$PATH
-setenv PYTHONPATH /dvl/atm/klinkl/software/local/lib/python2.7/site-packages/grib_api
-setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:/dvl/atm/klinkl/software/local/lib/
-setenv GRIB_API_INCLUDE_DIR /dvl/atm/klinkl/software/local/include/
-setenv GRIB_API_LIB '-L/dvl/atm/klinkl/software/local/lib -Bstatic  -lgrib_api_f77 -lgrib_api_f90 -lgrib_api -lemosR64 -Bdynamic  -lm  -ljasper'
Index: thon/set_CTBTO_env.sh
===================================================================
--- python/set_CTBTO_env.sh	(revision d69b6776d6d39e0af0d38c95cbfd78284c9866e4)
+++ 	(revision )
@@ -1,12 +1,0 @@
-#!/bin/bash
-
-# script to prepare CTBTO environment for
-# ECMWFDATA7.0
-# 
-# Leo Haimberger 1.3.2016
-
-export PATH=/dvl/atm/klinkl/software/local/bin:$PATH
-export PYTHONPATH=/dvl/atm/klinkl/software/local/lib/python2.7/site-packages/grib_api
-export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/dvl/atm/klinkl/software/local/lib/
-export GRIB_API_INCLUDE_DIR=/dvl/atm/klinkl/software/local/include/
-export GRIB_API_LIB='-L/dvl/atm/klinkl/software/local/lib -Bstatic  -lgrib_api_f77 -lgrib_api_f90 -lgrib_api -lemosR64 -Bdynamic  -lm  -ljasper'
Index: python/submit.py
===================================================================
--- python/submit.py	(revision ff99eae65dfaeec1221e06572d770ebd48feb3f4)
+++ python/submit.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -44,15 +44,13 @@
 import subprocess
 import inspect
+import collections
 
 # software specific classes and modules from flex_extract
-from tools import interpret_args_and_control, normal_exit
+import _config
+from tools import normal_exit, get_cmdline_arguments, submit_job_to_ecserver, \
+                  read_ecenv
 from get_mars_data import get_mars_data
 from prepare_flexpart import prepare_flexpart
-
-# add path to pythonpath so that python finds its buddies
-LOCAL_PYTHON_PATH = os.path.dirname(os.path.abspath(
-    inspect.getfile(inspect.currentframe())))
-if LOCAL_PYTHON_PATH not in sys.path:
-    sys.path.append(LOCAL_PYTHON_PATH)
+from ControlFile import ControlFile
 
 # ------------------------------------------------------------------------------
@@ -76,7 +74,26 @@
 
     called_from_dir = os.getcwd()
-    args, c = interpret_args_and_control()
+
+    args = get_cmdline_arguments()
+
+    try:
+        c = ControlFile(args.controlfile)
+    except IOError:
+        try:
+            c = ControlFile(LOCAL_PYTHON_PATH + args.controlfile)
+        except IOError:
+            print 'Could not read CONTROL file "' + args.controlfile + '"'
+            print 'Either it does not exist or its syntax is wrong.'
+            print 'Try "' + sys.argv[0].split('/')[-1] + \
+                  ' -h" to print usage information'
+            sys.exit(1)
+
+    env_parameter = read_ecenv(c.ecmwfdatadir + 'python/ECMWF_ENV')
+    c.assign_args_to_control(args)
+    c.assign_envs_to_control(env_parameter)
+    c.check_conditions()
 
     # on local side
+    # on ECMWF server this would be the local side
     if args.queue is None:
         if c.inputdir[0] != '/':
@@ -84,7 +101,7 @@
         if c.outputdir[0] != '/':
             c.outputdir = os.path.join(called_from_dir, c.outputdir)
-        get_mars_data(args, c)
-        prepare_flexpart(args, c)
-        normal_exit(c)
+        get_mars_data(c)
+        prepare_flexpart(args.ppid, c)
+        normal_exit(c.mailfail, 'Done!')
     # on ECMWF server
     else:
@@ -125,48 +142,52 @@
     '''
 
-    # read template file and split from newline signs
+    # read template file and get index for CONTROL input
     with open(jtemplate) as f:
         lftext = f.read().split('\n')
-        insert_point = lftext.index('EOF')
+    insert_point = lftext.index('EOF')
 
-    # put all parameters of ControlFile instance into a list
-    clist = c.to_list() # ondemand
-    colist = []  # operational
-    mt = 0
+    if not c.basetime:
+    # --------- create on demand job script ------------------------------------
+        if c.maxstep > 24:
+            print '---- Pure forecast mode! ----'
+        else:
+            print '---- On-demand mode! ----'
+        job_file = jtemplate[:-4] + 'ksh'
+        clist = c.to_list()
 
-    for elem in clist:
-        if 'maxstep' in elem:
-            mt = int(elem.split(' ')[1])
+        lftextondemand = lftext[:insert_point] + clist + lftext[insert_point:]
 
-    for elem in clist:
-        if 'start_date' in elem:
-            elem = 'start_date ' + '${MSJ_YEAR}${MSJ_MONTH}${MSJ_DAY}'
-        if 'end_date' in elem:
-            elem = 'end_date ' + '${MSJ_YEAR}${MSJ_MONTH}${MSJ_DAY}'
-        if 'base_time' in elem:
-            elem = 'base_time ' + '${MSJ_BASETIME}'
-        if 'time' in elem and mt > 24:
-            elem = 'time ' + '${MSJ_BASETIME} {MSJ_BASETIME}'
-        colist.append(elem)
+        with open(job_file, 'w') as f:
+            f.write('\n'.join(lftextondemand))
 
-    lftextondemand = lftext[:insert_point] + clist + lftext[insert_point + 2:]
-    lftextoper = lftext[:insert_point] + colist + lftext[insert_point + 2:]
+        submit_job_to_ecserver('', queue, job_file)
 
-    with open('job.ksh', 'w') as h:
-        h.write('\n'.join(lftextondemand))
+    else:
+    # --------- create operational job script ----------------------------------
+        print '---- Operational mode! ----'
+        job_file = jtemplate[:-5] + 'oper.ksh'
+        #colist = []
 
-    with open('joboper.ksh', 'w') as h:
-        h.write('\n'.join(lftextoper))
+        if c.maxstep:
+            mt = int(c.maxstep)
+        else:
+            mt = 0
 
-    # submit job script to queue
-    try:
-        p = subprocess.check_call(['ecaccess-job-submit', '-queueName',
-                                   queue, 'job.ksh'])
-    except subprocess.CalledProcessError as e:
-        print 'ecaccess-job-submit failed!'
-        print 'Error Message: '
-        print e.output
-        exit(1)
+        c.start_date = '${MSJ_YEAR}${MSJ_MONTH}${MSJ_DAY}'
+        c.end_date = '${MSJ_YEAR}${MSJ_MONTH}${MSJ_DAY}'
+        c.base_time = '${MSJ_BASETIME}'
+        if mt > 24:
+            c.time = '${MSJ_BASETIME} {MSJ_BASETIME}'
 
+        colist = c.to_list()
+
+        lftextoper = lftext[:insert_point] + colist + lftext[insert_point + 2:]
+
+        with open(job_file, 'w') as f:
+            f.write('\n'.join(lftextoper))
+
+        submit_job_to_ecserver('', queue, job_file)
+
+    # --------------------------------------------------------------------------
     print 'You should get an email with subject flex.hostname.pid'
 
Index: python/test_suite.py
===================================================================
--- python/test_suite.py	(revision None)
+++ python/test_suite.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -1,10 +1,4 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-#************************************************************************
-# ToDo AP
-# - provide more tests
-# - provide more documentation
-#************************************************************************
-
 #*******************************************************************************
 # @Author: Leopold Haimberger (University of Vienna)
@@ -25,5 +19,5 @@
 #
 # @Program Functionality:
-#    This script triggers the ECMWFDATA test suite. Call with
+#    This script triggers the flex_extract test suite. Call with
 #    test_suite.py [test group]
 #
Index: python/tools.py
===================================================================
--- python/tools.py	(revision None)
+++ python/tools.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -1,11 +1,4 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-#************************************************************************
-# ToDo AP
-# - check my_error
-# - check normal_exit
-# - check get_list_as_string
-# - seperate args and control interpretation
-#************************************************************************
 #*******************************************************************************
 # @Author: Anne Philipp (University of Vienna)
@@ -26,4 +19,5 @@
 #        - moved all functions from file Flexparttools to this file tools
 #        - added function get_list_as_string
+#        - seperated args and control interpretation
 #
 # @License:
@@ -38,5 +32,5 @@
 #
 # @Module Content:
-#    - interpret_args_and_control
+#    - get_cmdline_arguments
 #    - clean_up
 #    - my_error
@@ -47,4 +41,5 @@
 #    - to_param_id
 #    - get_list_as_string
+#    - make_dir
 #
 #*******************************************************************************
@@ -57,12 +52,7 @@
 import sys
 import glob
-import inspect
 import subprocess
 import traceback
 from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
-import numpy as np
-
-# software specific class from flex_extract
-from ControlFile import ControlFile
 
 # ------------------------------------------------------------------------------
@@ -70,9 +60,9 @@
 # ------------------------------------------------------------------------------
 
-def interpret_args_and_control():
-    '''
-    @Description:
-        Assigns the command line arguments and reads CONTROL file
-        content. Apply default values for non mentioned arguments.
+def get_cmdline_arguments():
+    '''
+    @Description:
+        Decomposes the command line arguments and assigns them to variables.
+        Apply default values for non mentioned arguments.
 
     @Input:
@@ -82,25 +72,14 @@
         args: instance of ArgumentParser
             Contains the commandline arguments from script/program call.
-
-        c: instance of class ControlFile
-            Contains all necessary information of a CONTROL file. The parameters
-            are: DAY1, DAY2, DTIME, MAXSTEP, TYPE, TIME, STEP, CLASS, 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, DEBUG, INPUTDIR,
-            OUTPUTDIR, FLEXPART_ROOT_SCRIPTS
-            For more information about format and content of the parameter see
-            documentation.
-
-    '''
+    '''
+
     parser = ArgumentParser(description='Retrieve FLEXPART input from \
-                            ECMWF MARS archive',
+                                ECMWF MARS archive',
                             formatter_class=ArgumentDefaultsHelpFormatter)
 
     # the most important arguments
-    parser.add_argument("--start_date", dest="start_date",
+    parser.add_argument("--start_date", dest="start_date", default=None,
                         help="start date YYYYMMDD")
-    parser.add_argument("--end_date", dest="end_date",
+    parser.add_argument("--end_date", dest="end_date", default=None,
                         help="end_date YYYYMMDD")
     parser.add_argument("--date_chunk", dest="date_chunk", default=None,
@@ -108,11 +87,11 @@
 
     # some arguments that override the default in the CONTROL file
-    parser.add_argument("--basetime", dest="basetime",
+    parser.add_argument("--basetime", dest="basetime", default=None,
                         help="base such as 00/12 (for half day retrievals)")
-    parser.add_argument("--step", dest="step",
+    parser.add_argument("--step", dest="step", default=None,
                         help="steps such as 00/to/48")
-    parser.add_argument("--levelist", dest="levelist",
+    parser.add_argument("--levelist", dest="levelist", default=None,
                         help="Vertical levels to be retrieved, e.g. 30/to/60")
-    parser.add_argument("--area", dest="area",
+    parser.add_argument("--area", dest="area", default=None,
                         help="area defined as north/west/south/east")
 
@@ -123,11 +102,12 @@
                         help="root directory for storing output files")
     parser.add_argument("--flexpart_root_scripts", dest="flexpart_root_scripts",
+                        default=None,
                         help="FLEXPART root directory (to find grib2flexpart \
-                        and COMMAND file)\n Normally ECMWFDATA resides in \
+                        and COMMAND file)\n Normally flex_extract resides in \
                         the scripts directory of the FLEXPART distribution")
 
     # this is only used by prepare_flexpart.py to rerun a postprocessing step
-    parser.add_argument("--ppid", dest="ppid",
-                        help="Specify parent process id for \
+    parser.add_argument("--ppid", dest="ppid", default=None,
+                        help="specify parent process id for \
                         rerun of prepare_flexpart")
 
@@ -136,5 +116,5 @@
                         default="job.temp",
                         help="job template file for submission to ECMWF")
-    parser.add_argument("--queue", dest="queue",
+    parser.add_argument("--queue", dest="queue", default=None,
                         help="queue for submission to ECMWF \
                         (e.g. ecgate or cca )")
@@ -142,103 +122,32 @@
                         default='CONTROL.temp',
                         help="file with CONTROL parameters")
-    parser.add_argument("--debug", dest="debug", default=0,
-                        help="Debug mode - leave temporary files intact")
+    parser.add_argument("--debug", dest="debug", default=None,
+                        help="debug mode - leave temporary files intact")
 
     args = parser.parse_args()
 
-    # create instance of ControlFile for specified controlfile
-    # and assign the parameters (and default values if necessary)
-    try:
-        c = ControlFile(args.controlfile)
-    except IOError:
-        try:
-            LOCAL_PYTHON_PATH = os.path.dirname(os.path.abspath(
-                inspect.getfile(inspect.currentframe())))
-            c = ControlFile(LOCAL_PYTHON_PATH + args.controlfile)
-        except IOError:
-            print 'Could not read CONTROL file "' + args.controlfile + '"'
-            print 'Either it does not exist or its syntax is wrong.'
-            print 'Try "' + sys.argv[0].split('/')[-1] + \
-                  ' -h" to print usage information'
-            exit(1)
-
-    # check for having at least a starting date
-    if  args.start_date is None and getattr(c, 'start_date') is None:
-        print 'start_date specified neither in command line nor \
-               in CONTROL file ' + args.controlfile
-        print 'Try "' + sys.argv[0].split('/')[-1] + \
-              ' -h" to print usage information'
-        exit(1)
-
-    # save all existing command line parameter to the ControlFile instance
-    # if parameter is not specified through the command line or CONTROL file
-    # set default values
-    if args.start_date is not None:
-        c.start_date = args.start_date
-    if args.end_date is not None:
-        c.end_date = args.end_date
-    if c.end_date is None:
-        c.end_date = c.start_date
-    if args.date_chunk is not None:
-        c.date_chunk = args.date_chunk
-
-    if not hasattr(c, 'debug'):
-        c.debug = args.debug
-
-    if args.inputdir is None and args.outputdir is None:
-        c.inputdir = '../work'
-        c.outputdir = '../work'
-    else:
-        if args.inputdir is not None:
-            c.inputdir = args.inputdir
-        if args.outputdir is None:
-            c.outputdir = args.inputdir
-        if args.outputdir is not None:
-            c.outputdir = args.outputdir
-        if args.inputdir is None:
-            c.inputdir = args.outputdir
-
-    if hasattr(c, 'outputdir') is False and args.outputdir is None:
-        c.outputdir = c.inputdir
-    else:
-        if args.outputdir is not None:
-            c.outputdir = args.outputdir
-
-    if args.area is not None:
-        afloat = '.' in args.area
-        l = args.area.split('/')
-        if afloat:
-            for i, item in enumerate(l):
-                item = str(int(float(item) * 1000))
-        c.upper, c.left, c.lower, c.right = l
-
-    # NOTE: basetime activates the ''operational mode''
-    if args.basetime is not None:
-        c.basetime = args.basetime
-
-    if args.step is not None:
-        l = args.step.split('/')
-        if 'to' in args.step.lower():
-            if 'by' in args.step.lower():
-                ilist = np.arange(int(l[0]), int(l[2]) + 1, int(l[4]))
-                c.step = ['{:0>3}'.format(i) for i in ilist]
-            else:
-                my_error(None, args.step + ':\n' +
-                         'please use "by" as well if "to" is used')
-        else:
-            c.step = l
-
-    if args.levelist is not None:
-        c.levelist = args.levelist
-        if 'to' in c.levelist:
-            c.level = c.levelist.split('/')[2]
-        else:
-            c.level = c.levelist.split('/')[-1]
-
-    if args.flexpart_root_scripts is not None:
-        c.flexpart_root_scripts = args.flexpart_root_scripts
-
-    return args, c
-
+    return args
+
+def read_ecenv(filename):
+    '''
+    @Description:
+        Reads the file into a dictionary where the key values are the parameter
+        names.
+
+    @Input:
+        filename: string
+            Name of file where the ECMWV environment parameters are stored.
+
+    @Return:
+        envs: dict
+    '''
+    envs= {}
+    print filename
+    with open(filename, 'r') as f:
+        for line in f:
+            data = line.strip().split()
+            envs[str(data[0])] = str(data[1])
+
+    return envs
 
 def clean_up(c):
@@ -269,9 +178,9 @@
 
     cleanlist = glob.glob(c.inputdir + "/*")
-    for cl in cleanlist:
-        if c.prefix not in cl:
-            silent_remove(cl)
+    for clist in cleanlist:
+        if c.prefix not in clist:
+            silent_remove(clist)
         if c.ecapi is False and (c.ectrans == '1' or c.ecstorage == '1'):
-            silent_remove(cl)
+            silent_remove(clist)
 
     print "Done"
@@ -280,5 +189,5 @@
 
 
-def my_error(c, message='ERROR'):
+def my_error(users, message='ERROR'):
     '''
     @Description:
@@ -287,16 +196,8 @@
 
     @Input:
-        c: instance of class ControlFile
-            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.
+        user: list of strings
+            Contains all email addresses which should be notified.
+            It might also contain just the ecmwf user name which wil trigger
+            mailing to the associated email address for this user.
 
         message: string, optional
@@ -310,28 +211,29 @@
 
     # comment if user does not want email notification directly from python
-    try:
-        target = []
-        target.extend(c.mailfail)
-    except AttributeError:
-        target = []
-        target.extend(os.getenv('USER'))
-
-    for t in target:
-        p = subprocess.Popen(['mail', '-s ECMWFDATA v7.0 ERROR',
-                              os.path.expandvars(t)],
-                             stdin=subprocess.PIPE,
-                             stdout=subprocess.PIPE,
-                             stderr=subprocess.PIPE,
-                             bufsize=1)
-        tr = '\n'.join(traceback.format_stack())
-        pout = p.communicate(input=message + '\n\n' + tr)[0]
-        print 'Email sent to ' + os.path.expandvars(t) + ' ' + pout.decode()
-
-    exit(1)
-
-    return
-
-
-def normal_exit(c, message='Done!'):
+    for user in users:
+        if '${USER}' in user:
+            user = os.getenv('USER')
+        try:
+            p = subprocess.Popen(['mail', '-s flex_extract_v7.1 ERROR',
+                                  os.path.expandvars(user)],
+                                 stdin=subprocess.PIPE,
+                                 stdout=subprocess.PIPE,
+                                 stderr=subprocess.PIPE,
+                                 bufsize=1)
+            trace = '\n'.join(traceback.format_stack())
+            pout = p.communicate(input=message + '\n\n' + trace)[0]
+        except ValueError as e:
+            print 'ERROR: ', e
+            sys.exit('Email could not be sent!')
+        else:
+            print 'Email sent to ' + os.path.expandvars(user) + ' ' + \
+                  pout.decode()
+
+    sys.exit(1)
+
+    return
+
+
+def normal_exit(users, message='Done!'):
     '''
     @Description:
@@ -339,16 +241,8 @@
 
     @Input:
-        c: instance of class ControlFile
-            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.
+        user: list of strings
+            Contains all email addresses which should be notified.
+            It might also contain just the ecmwf user name which wil trigger
+            mailing to the associated email address for this user.
 
         message: string, optional
@@ -362,10 +256,10 @@
 
     # comment if user does not want notification directly from python
-    try:
-        target = []
-        target.extend(c.mailops)
-        for t in target:
-            p = subprocess.Popen(['mail', '-s ECMWFDATA v7.0 normal exit',
-                                  os.path.expandvars(t)],
+    for user in users:
+        if '${USER}' in user:
+            user = os.getenv('USER')
+        try:
+            p = subprocess.Popen(['mail', '-s flex_extract_v7.1 normal exit',
+                                  os.path.expandvars(user)],
                                  stdin=subprocess.PIPE,
                                  stdout=subprocess.PIPE,
@@ -373,7 +267,10 @@
                                  bufsize=1)
             pout = p.communicate(input=message+'\n\n')[0]
-            print 'Email sent to ' + os.path.expandvars(t) + ' ' + pout.decode()
-    finally:
-        pass
+        except ValueError as e:
+            print 'ERROR: ', e
+            print 'Email could not be sent!'
+        else:
+            print 'Email sent to ' + os.path.expandvars(user) + ' ' + \
+                  pout.decode()
 
     return
@@ -433,5 +330,5 @@
     except OSError as e:
         # this would be "except OSError, e:" before Python 2.6
-        if e.errno is not  errno.ENOENT:
+        if e.errno != errno.ENOENT:
             # errno.ENOENT  =  no such file or directory
             raise  # re-raise exception if a different error occured
@@ -521,2 +418,96 @@
 
     return str_of_list
+
+def make_dir(directory):
+    '''
+    @Description:
+        Creates a directory and gives a warning if the directory
+        already exists. The program stops only if there is another problem.
+
+    @Input:
+        directory: string
+            The directory path which should be created.
+
+    @Return:
+        <nothing>
+    '''
+    try:
+        os.makedirs(directory)
+    except OSError as e:
+        if e.errno != errno.EEXIST:
+            # errno.EEXIST = directory already exists
+            raise # re-raise exception if a different error occured
+        else:
+            print 'WARNING: Directory {0} already exists!'.format(directory)
+
+    return
+
+def put_file_to_ecserver(ecd, filename, target, ecuid, ecgid):
+    '''
+    @Description:
+        Uses the ecaccess command to send a file to the ECMWF servers.
+        Catches and prints the error if it failed.
+
+    @Input:
+        ecd: string
+            The path were the file is to be stored.
+
+        filename: string
+            The name of the file to send to the ECMWF server.
+
+        target: string
+            The target where the file should be sent to, e.g. the queue.
+
+        ecuid: string
+            The user id on ECMWF server.
+
+        ecgid: string
+            The group id on ECMWF server.
+
+    @Return:
+        <nothing>
+    '''
+
+    try:
+        subprocess.check_call(['ecaccess-file-put',
+                               ecd + '../' + filename,
+                               target + ':/home/ms/' +
+                               ecgid + '/' + ecuid +
+                               '/' + filename])
+    except subprocess.CalledProcessError as e:
+        print 'ERROR:'
+        print e
+        sys.exit('ecaccess-file-put failed!\n' + \
+                 'Probably the eccert key has expired.')
+
+    return
+
+def submit_job_to_ecserver(ecd, target, jobname):
+    '''
+    @Description:
+        Uses ecaccess to submit a job to the ECMWF server.
+        Catches and prints the error if one arise.
+
+    @Input:
+        ecd: string
+            The path were the file is to be stored.
+
+        target: string
+            The target where the file should be sent to, e.g. the queue.
+
+        jobname: string
+            The name of the jobfile to be submitted to the ECMWF server.
+
+    @Return:
+        <nothing>
+    '''
+
+    try:
+        subprocess.check_call(['ecaccess-job-submit',
+                               '-queueName', target,
+                               jobname])
+    except subprocess.CalledProcessError as e:
+        print '... ERROR CODE: ', e.returncode
+        sys.exit('... ECACCESS-JOB-SUBMIT FAILED!')
+
+    return
Index: pythontest/TestTools.py
===================================================================
--- pythontest/TestTools.py	(revision efdb01a8ac2d5cef85c651177aa18ac69dd660db)
+++ pythontest/TestTools.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -4,6 +4,7 @@
 import unittest
 import sys
+import os
 sys.path.append('../python')
-from Tools import init128, toparamId
+from tools import init128, to_param_id, my_error, read_ecenv
 
 
@@ -25,11 +26,32 @@
 
 
-    def test_toparamId(self):
+    def test_to_param_id(self):
         '''
         '''
         table128 = init128('../grib_templates/ecmwf_grib1_table_128')
-        pars = toparamId("T/SP/LSP/SSHF", table128)
+        pars = to_param_id("T/SP/LSP/SSHF", table128)
         for par in pars:
             self.assertIn(par, [130, 134, 142, 146])
+
+    def test_error_notifcation(self):
+        '''
+        '''
+        with self.assertRaises(SystemExit) as re:
+            my_error(['${USER}', 'anne.philipp@univie.ac.at'], 'Failed!')
+        self.assertEqual(re.exception.code, 1)
+
+    def test_read_ecenv(self):
+
+        envs_ref = {'ECUID': 'km4a',
+                    'ECGID': 'at',
+                    'GATEWAY': 'srvx8.img.univie.ac.at',
+                    'DESTINATION': 'annep@genericSftp'
+                   }
+        envs = read_ecenv(os.getcwd() + '/TestData/ECMWF_ENV')
+
+        self.assertDictEqual(envs_ref, envs)
+
+
+
 
 
Index: pythontest/TestUIOFiles.py
===================================================================
--- pythontest/TestUIOFiles.py	(revision efdb01a8ac2d5cef85c651177aa18ac69dd660db)
+++ pythontest/TestUIOFiles.py	(revision 54a8a01d975ad8c2dea60c93439d9bc0ef426132)
@@ -6,8 +6,8 @@
 import sys
 sys.path.append('../python')
-import UIOFiles
+import UioFiles
 
 
-class TestUIOFiles(unittest.TestCase):
+class TestUioFiles(unittest.TestCase):
     '''
     Test class to test the UIOFiles methods.
@@ -52,6 +52,6 @@
 
         # Initialise and collect filenames
-        files = UIOFiles.UIOFiles(['.grb'])
-        files.listFiles(self.testpath, '*')
+        files = UioFiles.UioFiles(['.grb'])
+        files.list_files(self.testpath, '*')
         # get the basename to just check for equality of filenames
         filelist = [os.path.basename(f) for f in files.files]
