Index: source/python/mods/__init__.py
===================================================================
--- source/python/mods/__init__.py	(revision 25b14bea5de21f28364c210382513c1c9b792d61)
+++ source/python/mods/__init__.py	(revision 25b14bea5de21f28364c210382513c1c9b792d61)
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#*******************************************************************************
+# @Author: Anne Philipp (University of Vienna)
+#
+# @Date: September 2018
+#
+# @License:
+#    (C) Copyright 2015-2018.
+#
+#    This software is licensed under the terms of the Apache Licence Version 2.0
+#    which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+#
+#*******************************************************************************
Index: source/python/mods/disaggregation.py
===================================================================
--- source/python/mods/disaggregation.py	(revision 25b14bea5de21f28364c210382513c1c9b792d61)
+++ source/python/mods/disaggregation.py	(revision 25b14bea5de21f28364c210382513c1c9b792d61)
@@ -0,0 +1,141 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#*******************************************************************************
+# @Author: Anne Philipp (University of Vienna)
+#
+# @Date: March 2018
+#
+# @Change History:
+#
+#    November 2015 - Leopold Haimberger (University of Vienna):
+#        - migration of the methods dapoly and darain from Fortran
+#          (flex_extract_v6 and earlier) to Python
+#
+#    April 2018 - Anne Philipp (University of Vienna):
+#        - applied PEP8 style guide
+#        - added structured documentation
+#        - outsourced the disaggregation functions dapoly and darain
+#          to a new module named disaggregation
+#
+# @License:
+#    (C) Copyright 2015-2018.
+#
+#    This software is licensed under the terms of the Apache Licence Version 2.0
+#    which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+#
+# @Module Description:
+#    disaggregation of deaccumulated flux data from an ECMWF model FG field.
+#    Initially the flux data to be concerned are:
+#    - large-scale precipitation
+#    - convective precipitation
+#    - surface sensible heat flux
+#    - surface solar radiation
+#    - u stress
+#    - v stress
+#    Different versions of disaggregation is provided for rainfall
+#    data (darain, modified linear) and the surface fluxes and
+#    stress data (dapoly, cubic polynomial).
+#
+# @Module Content:
+#    - dapoly
+#    - darain
+#
+#*******************************************************************************
+
+# ------------------------------------------------------------------------------
+# MODULES
+# ------------------------------------------------------------------------------
+
+# ------------------------------------------------------------------------------
+# FUNCTIONS
+# ------------------------------------------------------------------------------
+def dapoly(alist):
+    '''
+    @Author: P. JAMES
+
+    @Date: 2000-03-29
+
+    @ChangeHistory:
+        June 2003     - A. BECK (2003-06-01)
+            adaptaions
+        November 2015 - Leopold Haimberger (University of Vienna)
+            migration from Fortran to Python
+
+    @Description:
+        Interpolation of deaccumulated fluxes of an ECMWF model FG field
+        using a cubic polynomial solution which conserves the integrals
+        of the fluxes within each timespan.
+        disaggregationregation is done for 4 accumluated timespans which generates
+        a new, disaggregated value which is output at the central point
+        of the 4 accumulation timespans. This new point is used for linear
+        interpolation of the complete timeseries afterwards.
+
+    @Input:
+        alist: list of size 4, array(2D), type=float
+            List of 4 timespans as 2-dimensional, horizontal fields.
+            E.g. [[array_t1], [array_t2], [array_t3], [array_t4]]
+
+    @Return:
+        nfield: array(2D), type=float
+            New field which replaces the field at the second position
+            of the accumulation timespans.
+
+    '''
+    pya = (alist[3] - alist[0] + 3. * (alist[1] - alist[2])) / 6.
+    pyb = (alist[2] + alist[0]) / 2. - alist[1] - 9. * pya / 2.
+    pyc = alist[1] - alist[0] - 7. * pya / 2. - 2. * pyb
+    pyd = alist[0] - pya / 4. - pyb / 3. - pyc / 2.
+    nfield = 8. * pya + 4. * pyb + 2. * pyc + pyd
+
+    return nfield
+
+
+def darain(alist):
+    '''
+    @Author: P. JAMES
+
+    @Date: 2000-03-29
+
+    @ChangeHistory:
+        June 2003     - A. BECK (2003-06-01)
+            adaptaions
+        November 2015 - Leopold Haimberger (University of Vienna)
+            migration from Fortran to Python
+
+    @Description:
+        Interpolation of deaccumulated fluxes of an ECMWF model FG rainfall
+        field using a modified linear solution which conserves the integrals
+        of the fluxes within each timespan.
+        disaggregationregation is done for 4 accumluated timespans which generates
+        a new, disaggregated value which is output at the central point
+        of the 4 accumulation timespans. This new point is used for linear
+        interpolation of the complete timeseries afterwards.
+
+    @Input:
+        alist: list of size 4, array(2D), type=float
+            List of 4 timespans as 2-dimensional, horizontal fields.
+            E.g. [[array_t1], [array_t2], [array_t3], [array_t4]]
+
+    @Return:
+        nfield: array(2D), type=float
+            New field which replaces the field at the second position
+            of the accumulation timespans.
+    '''
+    xa = alist[0]
+    xb = alist[1]
+    xc = alist[2]
+    xd = alist[3]
+    xa[xa < 0.] = 0.
+    xb[xb < 0.] = 0.
+    xc[xc < 0.] = 0.
+    xd[xd < 0.] = 0.
+
+    xac = 0.5 * xb
+    mask = xa + xc > 0.
+    xac[mask] = xb[mask] * xc[mask] / (xa[mask] + xc[mask])
+    xbd = 0.5 * xc
+    mask = xb + xd > 0.
+    xbd[mask] = xb[mask] * xc[mask] / (xb[mask] + xd[mask])
+    nfield = xac + xbd
+
+    return nfield
Index: source/python/mods/get_mars_data.py
===================================================================
--- source/python/mods/get_mars_data.py	(revision 25b14bea5de21f28364c210382513c1c9b792d61)
+++ source/python/mods/get_mars_data.py	(revision 25b14bea5de21f28364c210382513c1c9b792d61)
@@ -0,0 +1,291 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#*******************************************************************************
+# @Author: Anne Fouilloux (University of Oslo)
+#
+# @Date: October 2014
+#
+# @Change History:
+#
+#    November 2015 - Leopold Haimberger (University of Vienna):
+#        - moved the getEIdata program into a function "get_mars_data"
+#        - moved the AgurmentParser into a seperate function
+#        - adatpted the function for the use in flex_extract
+#        - renamed file to get_mars_data
+#
+#    February 2018 - Anne Philipp (University of Vienna):
+#        - applied PEP8 style guide
+#        - added structured documentation
+#        - minor changes in programming style for consistence
+#        - added function main and moved function calls vom __main__ there
+#          (necessary for better documentation with docstrings for later
+#          online documentation)
+#        - use of UIFiles class for file selection and deletion
+#
+#
+# @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.
+#
+# @Program Functionality:
+#    This program can be used as a module in the whole flex_extract process
+#    or can be run by itself to just extract MARS data from ECMWF. To do so,
+#    a couple of necessary parameters has to be passed with the program call.
+#    See documentation for more details.
+#
+# @Program Content:
+#    - main
+#    - get_mars_data
+#    - do_retrievement
+#
+#*******************************************************************************
+
+# ------------------------------------------------------------------------------
+# MODULES
+# ------------------------------------------------------------------------------
+import os
+import sys
+import datetime
+import inspect
+try:
+    ecapi = True
+    import ecmwfapi
+except ImportError:
+    ecapi = False
+
+# software specific classes and modules from flex_extract
+import _config
+from tools import my_error, normal_exit, get_cmdline_arguments, read_ecenv
+from classes.EcFlexpart import EcFlexpart
+from classes.UioFiles import UioFiles
+# ------------------------------------------------------------------------------
+# FUNCTION
+# ------------------------------------------------------------------------------
+def main():
+    '''
+    @Description:
+        If get_mars_data is called from command line, this function controls
+        the program flow and calls the argumentparser function and
+        the get_mars_data function for retrieving EC data.
+
+    @Input:
+        <nothing>
+
+    @Return:
+        <nothing>
+    '''
+
+    args = get_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')
+        sys.exit(1)
+
+    env_parameter = read_ecenv(_config.PATH_ECMWF_ENV)
+    c.assign_args_to_control(args, env_parameter)
+    c.assign_envs_to_control(env_parameter)
+    c.check_conditions(args.queue)
+
+    get_mars_data(c)
+    normal_exit(c.mailfail, 'Done!')
+
+    return
+
+def get_mars_data(c):
+    '''
+    @Description:
+        Retrieves the EC data needed for a FLEXPART simulation.
+        Start and end dates for retrieval period is set. Retrievals
+        are divided into smaller periods if necessary and datechunk parameter
+        is set.
+
+    @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.
+
+    @Return:
+        <nothing>
+    '''
+
+    if not os.path.exists(c.inputdir):
+        os.makedirs(c.inputdir)
+
+    if c.request == 0 or c.request == 2:
+        print("Retrieving EC data!")
+    elif c.request == 1:
+        print("Printing mars requests!")
+
+    print("start date %s " % (c.start_date))
+    print("end date %s " % (c.end_date))
+
+    if ecapi:
+        server = ecmwfapi.ECMWFService("mars")
+    else:
+        server = False
+
+    c.ecapi = ecapi
+    print('Using ECMWF WebAPI: ' + str(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]),
+                          month=int(c.start_date[4:6]),
+                          day=int(c.start_date[6:]))
+    startm1 = start - datetime.timedelta(days=1)
+
+    # set end date of retrieval period
+    end = datetime.date(year=int(c.end_date[:4]),
+                        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)
+
+    # --------------  flux data ------------------------------------------------
+    if c.request == 0 or c.request == 2:
+        print('... removing old flux content of ' + c.inputdir)
+        tobecleaned = UioFiles(c.inputdir,
+                               '*_acc_*.' + str(os.getppid()) + '.*.grb')
+        tobecleaned.delete_files()
+
+    # 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:
+        do_retrievement(c, server, startm1, endp1, datechunk, fluxes=True)
+
+    # if forecast data longer than 24h are to be retrieved,
+    # collect accumulation data (flux data)
+    # with the exact start and end date
+    # (disaggregation will be done for the
+    # exact time period with boundary conditions)
+    else:
+        do_retrievement(c, server, start, end, datechunk, fluxes=True)
+
+    # --------------  non flux data --------------------------------------------
+    if c.request == 0 or c.request == 2:
+        print('... removing old non flux content of ' + 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:
+        flexpart = EcFlexpart(c, fluxes)
+        tmpday = day + delta_t_m1
+        if tmpday < end:
+            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.request, c.inputdir)
+        except IOError:
+            my_error(c.mailfail, 'MARS request failed')
+
+        day += delta_t
+
+    return
+
+if __name__ == "__main__":
+    main()
Index: source/python/mods/plot_retrieved.py
===================================================================
--- source/python/mods/plot_retrieved.py	(revision 25b14bea5de21f28364c210382513c1c9b792d61)
+++ source/python/mods/plot_retrieved.py	(revision 25b14bea5de21f28364c210382513c1c9b792d61)
@@ -0,0 +1,670 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#*******************************************************************************
+# @Author: Leopold Haimberger (University of Vienna)
+#
+# @Date: November 2015
+#
+# @Change History:
+#
+#    February 2018 - Anne Philipp (University of Vienna):
+#        - applied PEP8 style guide
+#        - added documentation
+#        - created function main and moved the two function calls for
+#          arguments and plotting into it
+#        - added function get_basics to extract the boundary conditions
+#          of the data fields from the first grib file it gets.
+#
+# @License:
+#    (C) Copyright 2015-2018.
+#
+#    This software is licensed under the terms of the Apache Licence Version 2.0
+#    which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+#
+# @Program Functionality:
+#    Simple tool for creating maps and time series of retrieved fields.
+#
+# @Program Content:
+#    - main
+#    - get_basics
+#    - get_files_per_date
+#    - plot_retrieved
+#    - plot_timeseries
+#    - plot_map
+#    - get_plot_args
+#
+#*******************************************************************************
+
+# ------------------------------------------------------------------------------
+# MODULES
+# ------------------------------------------------------------------------------
+import time
+import datetime
+import os
+import inspect
+import sys
+from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
+import matplotlib
+import matplotlib.pyplot as plt
+from mpl_toolkits.basemap import Basemap
+from eccodes import codes_grib_new_from_file, codes_get, codes_release, \
+                    codes_get_values
+import numpy as np
+
+# software specific classes and modules from flex_extract
+import _config
+from classes.ControlFile import ControlFile
+from classes.UioFiles import UioFiles
+
+font = {'family': 'monospace', 'size': 12}
+matplotlib.rcParams['xtick.major.pad'] = '20'
+matplotlib.rc('font', **font)
+# ------------------------------------------------------------------------------
+# FUNCTION
+# ------------------------------------------------------------------------------
+def main():
+    '''
+    @Description:
+        If plot_retrieved is called from command line, this function controls
+        the program flow and calls the argumentparser function and
+        the plot_retrieved function for plotting the retrieved GRIB data.
+
+    @Input:
+        <nothing>
+
+    @Return:
+        <nothing>
+    '''
+    args, c = get_plot_args()
+    plot_retrieved(c)
+
+    return
+
+def get_basics(ifile, verb=False):
+    """
+    @Description:
+        An example grib file will be opened and basic information will
+        be extracted. These information are important for later use and the
+        initialization of numpy arrays for data storing.
+
+    @Input:
+        ifile: string
+            Contains the full absolute path to the ECMWF grib file.
+
+        verb (opt): bool
+            Is True if there should be extra output in verbose mode.
+            Default value is False.
+
+    @Return:
+        data: dict
+            Contains basic informations of the ECMWF grib files, e.g.
+            'Ni', 'Nj', 'latitudeOfFirstGridPointInDegrees',
+            'longitudeOfFirstGridPointInDegrees',
+            'latitudeOfLastGridPointInDegrees',
+            'longitudeOfLastGridPointInDegrees',
+            'jDirectionIncrementInDegrees',
+            'iDirectionIncrementInDegrees'
+    """
+
+    data = {}
+
+    # --- open file ---
+    print("Opening file for getting information data --- %s" %
+          os.path.basename(ifile))
+
+    with open(ifile) as f:
+
+        # load first message from file
+        gid = codes_grib_new_from_file(f)
+
+        # information needed from grib message
+        keys = ['Ni',
+                'Nj',
+                'latitudeOfFirstGridPointInDegrees',
+                'longitudeOfFirstGridPointInDegrees',
+                'latitudeOfLastGridPointInDegrees',
+                'longitudeOfLastGridPointInDegrees',
+                'jDirectionIncrementInDegrees',
+                'iDirectionIncrementInDegrees']
+
+        if verb:
+            print '\nInformations are: '
+        for key in keys:
+            # Get the value of the key in a grib message.
+            data[key] = codes_get(gid, key)
+            if verb:
+                print "%s = %s" % (key, data[key])
+        if verb:
+            print '\n'
+
+        # Free the memory for the message referred as gribid.
+        codes_release(gid)
+
+    return data
+
+def get_files_per_date(files, datelist):
+    '''
+    @Description:
+        The filenames contain dates which are used to select a list
+        of files for a specific time period specified in datelist.
+
+    @Input:
+        files: instance of UioFiles
+            For description see class documentation.
+            It contains the attribute "files" which is a list of pathes
+            to filenames.
+
+        datelist: list of datetimes
+            Contains the list of dates which should be processed for plotting.
+
+    @Return:
+        filelist: list of strings
+            Contains the selected files for the time period.
+    '''
+
+    filelist = []
+    for filename in files:
+        filedate = filename[-8:]
+        ddate = datetime.datetime.strptime(filedate, '%y%m%d%H')
+        if ddate in datelist:
+            filelist.append(filename)
+
+    return filelist
+
+def plot_retrieved(c):
+    '''
+    @Description:
+        Reads GRIB data from a specified time period, a list of levels
+        and a specified list of parameter.
+
+    @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, DEBUG, INPUTDIR,
+            OUTPUTDIR, FLEXPART_ROOT_SCRIPTS
+            For more information about format and content of the parameter see
+            documentation.
+
+    @Return:
+        <nothing>
+    '''
+    start = datetime.datetime.strptime(c.start_date, '%Y%m%d%H')
+    end = datetime.datetime.strptime(c.end_date, '%Y%m%d%H')
+
+    # create datelist between start and end date
+    datelist = [start] # initialise datelist with first date
+    run_date = start
+    while run_date < end:
+        run_date += datetime.timedelta(hours=int(c.dtime))
+        datelist.append(run_date)
+
+    print 'datelist: ', datelist
+
+    c.paramIds = np.asarray(c.paramIds, dtype='int')
+    c.levels = np.asarray(c.levels, dtype='int')
+    c.area = np.asarray(c.area)
+
+    files = UioFiles(c.inputdir, c.prefix+'*')
+    ifiles = get_files_per_date(files.files, datelist)
+    ifiles.sort()
+
+    gdict = get_basics(ifiles[0], verb=False)
+
+    fdict = dict()
+    fmeta = dict()
+    fstamp = dict()
+    for p in c.paramIds:
+        for l in c.levels:
+            key = '{:0>3}_{:0>3}'.format(p, l)
+            fdict[key] = []
+            fmeta[key] = []
+            fstamp[key] = []
+
+    for filename in ifiles:
+        f = open(filename)
+        print "Opening file for reading data --- %s" % filename
+        fdate = datetime.datetime.strptime(filename[-8:], "%y%m%d%H")
+
+        # Load in memory a grib message from a file.
+        gid = codes_grib_new_from_file(f)
+        while gid is not None:
+            gtype = codes_get(gid, 'type')
+            paramId = codes_get(gid, 'paramId')
+            parameterName = codes_get(gid, 'parameterName')
+            level = codes_get(gid, 'level')
+
+            if paramId in c.paramIds and level in c.levels:
+                key = '{:0>3}_{:0>3}'.format(paramId, level)
+                print 'key: ', key
+                if fstamp[key]:
+                    for i in range(len(fstamp[key])):
+                        if fdate < fstamp[key][i]:
+                            fstamp[key].insert(i, fdate)
+                            fmeta[key].insert(i, [paramId, parameterName, gtype,
+                                                  fdate, level])
+                            fdict[key].insert(i, np.flipud(np.reshape(
+                                codes_get_values(gid),
+                                [gdict['Nj'], gdict['Ni']])))
+                            break
+                        elif fdate > fstamp[key][i] and i == len(fstamp[key])-1:
+                            fstamp[key].append(fdate)
+                            fmeta[key].append([paramId, parameterName, gtype,
+                                               fdate, level])
+                            fdict[key].append(np.flipud(np.reshape(
+                                codes_get_values(gid),
+                                [gdict['Nj'], gdict['Ni']])))
+                            break
+                        elif fdate > fstamp[key][i] and i != len(fstamp[key])-1 \
+                             and fdate < fstamp[key][i+1]:
+                            fstamp[key].insert(i, fdate)
+                            fmeta[key].insert(i, [paramId, parameterName, gtype,
+                                                  fdate, level])
+                            fdict[key].insert(i, np.flipud(np.reshape(
+                                codes_get_values(gid),
+                                [gdict['Nj'], gdict['Ni']])))
+                            break
+                        else:
+                            pass
+                else:
+                    fstamp[key].append(fdate)
+                    fmeta[key].append((paramId, parameterName, gtype,
+                                       fdate, level))
+                    fdict[key].append(np.flipud(np.reshape(
+                        codes_get_values(gid), [gdict['Nj'], gdict['Ni']])))
+
+            codes_release(gid)
+
+            # Load in memory a grib message from a file.
+            gid = codes_grib_new_from_file(f)
+
+        f.close()
+
+    for k in fdict.iterkeys():
+        print 'fmeta: ', len(fmeta), fmeta
+        fml = fmeta[k]
+        fdl = fdict[k]
+        print 'fm1: ', len(fml), fml
+        for fd, fm in zip(fdl, fml):
+            print fm
+            ftitle = fm[1] + ' {} '.format(fm[-1]) + \
+                datetime.datetime.strftime(fm[3], '%Y%m%d%H')
+            pname = '_'.join(fm[1].split()) + '_{}_'.format(fm[-1]) + \
+                datetime.datetime.strftime(fm[3], '%Y%m%d%H')
+            plot_map(c, fd, fm, gdict, ftitle, pname, 'png')
+
+    for k in fdict.iterkeys():
+        fml = fmeta[k]
+        fdl = fdict[k]
+        fsl = fstamp[k]
+        if fdl:
+            fm = fml[0]
+            fd = fdl[0]
+            ftitle = fm[1] + ' {} '.format(fm[-1]) + \
+                datetime.datetime.strftime(fm[3], '%Y%m%d%H')
+            pname = '_'.join(fm[1].split()) + '_{}_'.format(fm[-1]) + \
+                datetime.datetime.strftime(fm[3], '%Y%m%d%H')
+            lat = -20.
+            lon = 20.
+            plot_timeseries(c, fdl, fml, fsl, lat, lon, gdict,
+                            ftitle, pname, 'png')
+
+    return
+
+def plot_timeseries(c, flist, fmetalist, ftimestamps, lat, lon,
+                    gdict, ftitle, filename, fending, show=False):
+    '''
+    @Description:
+        Creates a timeseries plot for a given lat/lon position.
+
+    @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, DEBUG, INPUTDIR,
+            OUTPUTDIR, FLEXPART_ROOT_SCRIPTS
+            For more information about format and content of the parameter see
+            documentation.
+
+        flist: numpy array, 2d
+            The actual data values to be plotted from the grib messages.
+
+        fmetalist: list of strings
+            Contains some meta date for the data field to be plotted:
+            parameter id, parameter Name, grid type, datetime, level
+
+        ftimestamps: list of datetime
+            Contains the time stamps.
+
+        lat: float
+            The latitude for which the timeseries should be plotted.
+
+        lon: float
+            The longitude for which the timeseries should be plotted.
+
+        gdict: dict
+            Contains basic informations of the ECMWF grib files, e.g.
+            'Ni', 'Nj', 'latitudeOfFirstGridPointInDegrees',
+            'longitudeOfFirstGridPointInDegrees',
+            'latitudeOfLastGridPointInDegrees',
+            'longitudeOfLastGridPointInDegrees',
+            'jDirectionIncrementInDegrees',
+            'iDirectionIncrementInDegrees'
+
+        ftitle: string
+            The title of the timeseries.
+
+        filename: string
+            The time series is stored in a file with this name.
+
+        fending: string
+            Contains the type of plot, e.g. pdf or png
+
+        show: boolean
+            Decides if the plot is shown after plotting or hidden.
+
+    @Return:
+        <nothing>
+    '''
+    print 'plotting timeseries'
+
+    t1 = time.time()
+
+    #llx = gdict['longitudeOfFirstGridPointInDegrees']
+    #if llx > 180. :
+    #    llx -= 360.
+    #lly = gdict['latitudeOfLastGridPointInDegrees']
+    #dxout = gdict['iDirectionIncrementInDegrees']
+    #dyout = gdict['jDirectionIncrementInDegrees']
+    #urx = gdict['longitudeOfLastGridPointInDegrees']
+    #ury = gdict['latitudeOfFirstGridPointInDegrees']
+    #numxgrid = gdict['Ni']
+    #numygrid = gdict['Nj']
+
+    farr = np.asarray(flist)
+    #(time, lat, lon)
+
+    #lonindex = linspace(llx, urx, numxgrid)
+    #latindex = linspace(lly, ury, numygrid)
+
+    ts = farr[:, 0, 0]
+
+    fig = plt.figure(figsize=(12, 6.7))
+
+    plt.plot(ftimestamps, ts)
+    plt.title(ftitle)
+
+    plt.savefig(c.outputdir + '/' + filename + '_TS.' + fending,
+                facecolor=fig.get_facecolor(),
+                edgecolor='none',
+                format=fending)
+    print 'created ', c.outputdir + '/' + filename
+    if show:
+        plt.show()
+    fig.clf()
+    plt.close(fig)
+
+    print time.time() - t1, 's'
+
+    return
+
+def plot_map(c, flist, fmetalist, gdict, ftitle, filename, fending, show=False):
+    '''
+    @Description:
+        Creates a basemap plot with imshow for a given data field.
+
+    @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, DEBUG, INPUTDIR,
+            OUTPUTDIR, FLEXPART_ROOT_SCRIPTS
+            For more information about format and content of the parameter see
+            documentation.
+
+        flist: numpy array, 2d
+            The actual data values to be plotted from the grib messages.
+
+        fmetalist: list of strings
+            Contains some meta date for the data field to be plotted:
+            parameter id, parameter Name, grid type, datetime, level
+
+        gdict: dict
+            Contains basic informations of the ECMWF grib files, e.g.
+            'Ni', 'Nj', 'latitudeOfFirstGridPointInDegrees',
+            'longitudeOfFirstGridPointInDegrees',
+            'latitudeOfLastGridPointInDegrees',
+            'longitudeOfLastGridPointInDegrees',
+            'jDirectionIncrementInDegrees',
+            'iDirectionIncrementInDegrees'
+
+        ftitle: string
+            The titel of the plot.
+
+        filename: string
+            The plot is stored in a file with this name.
+
+        fending: string
+            Contains the type of plot, e.g. pdf or png
+
+        show: boolean
+            Decides if the plot is shown after plotting or hidden.
+
+    @Return:
+        <nothing>
+    '''
+    print 'plotting map'
+
+    t1 = time.time()
+
+    fig = plt.figure(figsize=(12, 6.7))
+    #mbaxes = fig.add_axes([0.05, 0.15, 0.8, 0.7])
+
+    llx = gdict['longitudeOfFirstGridPointInDegrees'] #- 360
+    if llx > 180.:
+        llx -= 360.
+    lly = gdict['latitudeOfLastGridPointInDegrees']
+    #dxout = gdict['iDirectionIncrementInDegrees']
+    #dyout = gdict['jDirectionIncrementInDegrees']
+    urx = gdict['longitudeOfLastGridPointInDegrees']
+    ury = gdict['latitudeOfFirstGridPointInDegrees']
+    #numxgrid = gdict['Ni']
+    #numygrid = gdict['Nj']
+
+    m = Basemap(projection='cyl', llcrnrlon=llx, llcrnrlat=lly,
+                urcrnrlon=urx, urcrnrlat=ury, resolution='i')
+
+    #lw = 0.5
+    m.drawmapboundary()
+    #x = linspace(llx, urx, numxgrid)
+    #y = linspace(lly, ury, numygrid)
+
+    #xx, yy = m(*meshgrid(x, y))
+
+    #s = m.contourf(xx, yy, flist)
+
+    s = plt.imshow(flist.T,
+                   extent=(llx, urx, lly, ury),
+                   alpha=1.0,
+                   interpolation='nearest'
+                   #vmin=vn,
+                   #vmax=vx,
+                   #cmap=my_cmap,
+                   #levels=levels,
+                   #cmap=my_cmap,
+                   #norm=LogNorm(vn,vx)
+                  )
+
+    plt.title(ftitle, y=1.08)
+    cb = m.colorbar(s, location="right", pad="10%")
+    cb.set_label('label', size=14)
+
+    thickline = np.arange(lly, ury+1, 10.)
+    thinline = np.arange(lly, ury+1, 5.)
+    m.drawparallels(thickline,
+                    color='gray',
+                    dashes=[1, 1],
+                    linewidth=0.5,
+                    labels=[1, 1, 1, 1],
+                    xoffset=1.)
+    m.drawparallels(np.setdiff1d(thinline, thickline),
+                    color='lightgray',
+                    dashes=[1, 1],
+                    linewidth=0.5,
+                    labels=[0, 0, 0, 0])
+
+    thickline = np.arange(llx, urx+1, 10.)
+    thinline = np.arange(llx, urx+1, 5.)
+    m.drawmeridians(thickline,
+                    color='gray',
+                    dashes=[1, 1],
+                    linewidth=0.5,
+                    labels=[1, 1, 1, 1],
+                    yoffset=1.)
+    m.drawmeridians(np.setdiff1d(thinline, thickline),
+                    color='lightgray',
+                    dashes=[1, 1],
+                    linewidth=0.5,
+                    labels=[0, 0, 0, 0])
+
+    m.drawcoastlines()
+    m.drawcountries()
+
+    plt.savefig(c.outputdir + '/' + filename + '_MAP.' + fending,
+                facecolor=fig.get_facecolor(),
+                edgecolor='none',
+                format=fending)
+    print 'created ', c.outputdir + '/' + filename
+    if show:
+        plt.show()
+    fig.clf()
+    plt.close(fig)
+
+    print time.time() - t1, 's'
+
+    return
+
+def get_plot_args():
+    '''
+    @Description:
+        Assigns the command line arguments and reads CONTROL file
+        content. Apply default values for non mentioned arguments.
+
+    @Input:
+        <nothing>
+
+    @Return:
+        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='Plot retrieved GRIB data from ' + \
+                            'ECMWF MARS archive',
+                            formatter_class=ArgumentDefaultsHelpFormatter)
+
+# the most important arguments
+    parser.add_argument("--start_date", dest="start_date",
+                        help="start date YYYYMMDD")
+    parser.add_argument("--end_date", dest="end_date",
+                        help="end_date YYYYMMDD")
+
+    parser.add_argument("--start_step", dest="start_step",
+                        help="start step in hours")
+    parser.add_argument("--end_step", dest="end_step",
+                        help="end step in hours")
+
+# some arguments that override the default in the CONTROL file
+    parser.add_argument("--levelist", dest="levelist",
+                        help="vertical levels to be retrieved, e.g. 30/to/60")
+    parser.add_argument("--area", dest="area",
+                        help="area defined as north/west/south/east")
+    parser.add_argument("--paramIds", dest="paramIds",
+                        help="parameter IDs")
+    parser.add_argument("--prefix", dest="prefix", default='EN',
+                        help="output file name prefix")
+
+# set the working directories
+    parser.add_argument("--inputdir", dest="inputdir", default=None,
+                        help="root directory for storing intermediate files")
+    parser.add_argument("--outputdir", dest="outputdir", default=None,
+                        help="root directory for storing output files")
+    parser.add_argument("--flexpart_root_scripts", dest="flexpart_root_scripts",
+                        help="FLEXPART root directory (to find \
+                        'grib2flexpart and COMMAND file)\n \
+                        Normally flex_extract resides in the scripts directory \
+                        of the FLEXPART distribution")
+
+    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:
+        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'
+            exit(1)
+
+    if args.levelist:
+        c.levels = args.levelist.split('/')
+    else:
+        c.levels = [0]
+
+    if args.area:
+        c.area = args.area.split('/')
+    else:
+        c.area = '[0,0]'
+
+    c.paramIds = args.paramIds.split('/')
+
+    if args.start_step:
+        c.start_step = int(args.start_step)
+    else:
+        c.start_step = 0
+
+    if args.end_step:
+        c.end_step = int(args.end_step)
+    else:
+        c.end_step = 0
+
+    c.start_date = args.start_date
+    c.end_date = args.end_date
+
+    c.prefix = args.prefix
+
+    c.inputdir = args.inputdir
+
+    if args.outputdir:
+        c.outputdir = args.outputdir
+    else:
+        c.outputdir = c.inputdir
+
+    return args, c
+
+if __name__ == "__main__":
+    main()
Index: source/python/mods/prepare_flexpart.py
===================================================================
--- source/python/mods/prepare_flexpart.py	(revision 25b14bea5de21f28364c210382513c1c9b792d61)
+++ source/python/mods/prepare_flexpart.py	(revision 25b14bea5de21f28364c210382513c1c9b792d61)
@@ -0,0 +1,196 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#*******************************************************************************
+# @Author: Anne Fouilloux (University of Oslo)
+#
+# @Date: October 2014
+#
+# @Change History:
+#
+#    November 2015 - Leopold Haimberger (University of Vienna):
+#        - using the WebAPI also for general MARS retrievals
+#        - job submission on ecgate and cca
+#        - job templates suitable for twice daily operational dissemination
+#        - dividing retrievals of longer periods into digestable chunks
+#        - retrieve also longer term forecasts, not only analyses and
+#          short term forecast data
+#        - conversion into GRIB2
+#        - conversion into .fp format for faster execution of FLEXPART
+#
+#    February 2018 - Anne Philipp (University of Vienna):
+#        - applied PEP8 style guide
+#        - added documentation
+#        - minor changes in programming style for consistence
+#        - BUG: removed call of clean_up-Function after call of
+#               prepareFlexpart in main since it is already called in
+#               prepareFlexpart at the end!
+#        - created function main and moved the two function calls for
+#          arguments and prepare_flexpart into it
+#
+# @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.
+#
+# @Program Functionality:
+#    This program prepares the final version of the grib files which are
+#    then used by FLEXPART. It converts the bunch of grib files extracted
+#    via get_mars_data by doing for example the necessary conversion to get
+#    consistent grids or the disaggregation of flux data. Finally, the
+#    program combines the data fields in files per available hour with the
+#    naming convention xxYYMMDDHH, where xx should be 2 arbitrary letters
+#    (mostly xx is chosen to be "EN").
+#
+# @Program Content:
+#    - main
+#    - prepare_flexpart
+#
+#*******************************************************************************
+
+# ------------------------------------------------------------------------------
+# MODULES
+# ------------------------------------------------------------------------------
+import datetime
+import os
+import inspect
+import sys
+import socket
+
+# software specific classes and modules from flex_extract
+import _config
+from classes.UioFiles import UioFiles
+from tools import clean_up, get_cmdline_arguments, read_ecenv
+from classes.EcFlexpart import EcFlexpart
+
+ecapi = 'ecmwf' not in socket.gethostname()
+try:
+    if ecapi:
+        import ecmwfapi
+except ImportError:
+    ecapi = False
+
+# ------------------------------------------------------------------------------
+# FUNCTION
+# ------------------------------------------------------------------------------
+def main():
+    '''
+    @Description:
+        If prepare_flexpart is called from command line, this function controls
+        the program flow and calls the argumentparser function and
+        the prepare_flexpart function for preparation of GRIB data for FLEXPART.
+
+    @Input:
+        <nothing>
+
+    @Return:
+        <nothing>
+    '''
+
+    args = get_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')
+        sys.exit(1)
+
+    env_parameter = read_ecenv(_config.PATH_ECMWF_ENV)
+    c.assign_args_to_control(args, env_parameter)
+    c.assign_envs_to_control(env_parameter)
+    c.check_conditions(args.queue)
+    prepare_flexpart(args.ppid, c)
+
+    return
+
+def prepare_flexpart(ppid, c):
+    '''
+    @Description:
+        Lists all grib files retrieved from MARS with get_mars_data and
+        uses prepares data for the use in FLEXPART. Specific data fields
+        are converted to a different grid and the flux data are going to be
+        disaggregated. The data fields are collected by hour and stored in
+        a file with a specific FLEXPART relevant naming convention.
+
+    @Input:
+        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
+            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.
+
+    @Return:
+        <nothing>
+    '''
+
+    if not ppid:
+        c.ppid = str(os.getppid())
+    else:
+        c.ppid = ppid
+
+    c.ecapi = ecapi
+
+    # create the start and end date
+    start = datetime.date(year=int(c.start_date[:4]),
+                          month=int(c.start_date[4:6]),
+                          day=int(c.start_date[6:]))
+
+    end = datetime.date(year=int(c.end_date[:4]),
+                        month=int(c.end_date[4:6]),
+                        day=int(c.end_date[6:]))
+
+    # 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
+    flexpart = EcFlexpart(c, fluxes=True)
+    flexpart.write_namelist(c, _config.FILE_NAMELIST)
+    flexpart.deacc_fluxes(inputfiles, c)
+
+    # get a list of all files from the root inputdir
+    inputfiles = UioFiles(c.inputdir, '????__??.*' + c.ppid + '.*')
+
+    # produce FLEXPART-ready GRIB files and process them -
+    # copy/transfer/interpolate them or make them GRIB2
+    flexpart = EcFlexpart(c, fluxes=False)
+    flexpart.create(inputfiles, c)
+    flexpart.process_output(c)
+
+    # check if in debugging mode, then store all files
+    # otherwise delete temporary files
+    if int(c.debug) != 0:
+        print('\nTemporary files left intact')
+    else:
+        clean_up(c)
+
+    return
+
+if __name__ == "__main__":
+    main()
Index: source/python/mods/profiling.py
===================================================================
--- source/python/mods/profiling.py	(revision 25b14bea5de21f28364c210382513c1c9b792d61)
+++ source/python/mods/profiling.py	(revision 25b14bea5de21f28364c210382513c1c9b792d61)
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#************************************************************************
+# ToDo AP
+# - check license of book content
+#************************************************************************
+#*******************************************************************************
+#
+# @Author: Anne Philipp (University of Vienna)
+#
+# @Date: March 2018
+#
+# @License:
+#    (C) Copyright 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.
+#
+# @Program functionality:
+#    This module is not part of flex_extract. It is just used for testing and
+#    performance analysis of some functions.
+#
+# @Program Content:
+#    - timefn
+#
+#*******************************************************************************
+
+# ------------------------------------------------------------------------------
+# MODULES
+# ------------------------------------------------------------------------------
+from functools import wraps
+import time
+
+# ------------------------------------------------------------------------------
+# FUNCTION
+# ------------------------------------------------------------------------------
+def timefn(fn):
+    '''
+    @Description:
+        Decorator function. It takes the inner function as an argument.
+    '''
+    @wraps(fn)
+    def measure_time(*args, **kwargs):
+        '''
+        @Descripton:
+            Passes the arguments through fn for execution. Around the
+            execution of fn the time is captured to execute the fn function
+            and prints the result along with the function name.
+
+            This is taken from the book "High Performance Python" from
+            Micha Gorelick and Ian Ozsvald, O'Reilly publisher, 2014,
+            ISBN: 978-1-449-36159-4
+
+        @Input:
+            *args: undefined
+                A variable number of positional arguments.
+
+            **kwargs: undefined
+                A variable number of key/value arguments.
+
+        @Return:
+            <nothing>
+        '''
+
+        t1 = time.time()
+        result = fn(*args, **kwargs)
+        t2 = time.time()
+        print("@timefn:" + fn.func_name + " took " + str(t2 - t1) + " seconds")
+
+        return result
+
+    return measure_time
Index: source/python/mods/tools.py
===================================================================
--- source/python/mods/tools.py	(revision 25b14bea5de21f28364c210382513c1c9b792d61)
+++ source/python/mods/tools.py	(revision 25b14bea5de21f28364c210382513c1c9b792d61)
@@ -0,0 +1,533 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#*******************************************************************************
+# @Author: Anne Philipp (University of Vienna)
+#
+# @Date: May 2018
+#
+# @Change History:
+#    October 2014 - Anne Fouilloux (University of Oslo)
+#        - created functions silent_remove and product (taken from ECMWF)
+#
+#    November 2015 - Leopold Haimberger (University of Vienna)
+#        - created functions: interpret_args_and_control, clean_up
+#          my_error, normal_exit, init128, to_param_id
+#
+#    April 2018 - Anne Philipp (University of Vienna):
+#        - applied PEP8 style guide
+#        - added documentation
+#        - moved all functions from file Flexparttools to this file tools
+#        - added function get_list_as_string
+#        - seperated args and control interpretation
+#
+# @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.
+#
+# @Modul Description:
+#    This module contains a couple of helpful functions which are
+#    used in different places in flex_extract.
+#
+# @Module Content:
+#    - get_cmdline_arguments
+#    - clean_up
+#    - my_error
+#    - normal_exit
+#    - product
+#    - silent_remove
+#    - init128
+#    - to_param_id
+#    - get_list_as_string
+#    - make_dir
+#
+#*******************************************************************************
+
+# ------------------------------------------------------------------------------
+# MODULES
+# ------------------------------------------------------------------------------
+import os
+import errno
+import sys
+import glob
+import subprocess
+import traceback
+from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
+
+# ------------------------------------------------------------------------------
+# FUNCTIONS
+# ------------------------------------------------------------------------------
+
+def get_cmdline_arguments():
+    '''
+    @Description:
+        Decomposes the command line arguments and assigns them to variables.
+        Apply default values for non mentioned arguments.
+
+    @Input:
+        <nothing>
+
+    @Return:
+        args: instance of ArgumentParser
+            Contains the commandline arguments from script/program call.
+    '''
+
+    parser = ArgumentParser(description='Retrieve FLEXPART input from \
+                                ECMWF MARS archive',
+                            formatter_class=ArgumentDefaultsHelpFormatter)
+
+    # the most important arguments
+    parser.add_argument("--start_date", dest="start_date", default=None,
+                        help="start date YYYYMMDD")
+    parser.add_argument("--end_date", dest="end_date", default=None,
+                        help="end_date YYYYMMDD")
+    parser.add_argument("--date_chunk", dest="date_chunk", default=None,
+                        help="# of days to be retrieved at once")
+
+    # some arguments that override the default in the CONTROL file
+    parser.add_argument("--basetime", dest="basetime", default=None,
+                        help="base such as 00/12 (for half day retrievals)")
+    parser.add_argument("--step", dest="step", default=None,
+                        help="steps such as 00/to/48")
+    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", default=None,
+                        help="area defined as north/west/south/east")
+
+    # set the working directories
+    parser.add_argument("--inputdir", dest="inputdir", default=None,
+                        help="root directory for storing intermediate files")
+    parser.add_argument("--outputdir", dest="outputdir", default=None,
+                        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 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", default=None,
+                        help="specify parent process id for \
+                        rerun of prepare_flexpart")
+
+    # arguments for job submission to ECMWF, only needed by submit.py
+    parser.add_argument("--job_template", dest='job_template',
+                        default="job.temp",
+                        help="job template file for submission to ECMWF")
+    parser.add_argument("--queue", dest="queue", default=None,
+                        help="queue for submission to ECMWF \
+                        (e.g. ecgate or cca )")
+    parser.add_argument("--controlfile", dest="controlfile",
+                        default='CONTROL.temp',
+                        help="file with CONTROL parameters")
+    parser.add_argument("--debug", dest="debug", default=None,
+                        help="debug mode - leave temporary files intact")
+    parser.add_argument("--request", dest="request", default=None,
+                        help="list all mars request in file mars_requests.dat \
+                        and skip submission to mars")
+
+    args = parser.parse_args()
+
+    return args
+
+def read_ecenv(filename):
+    '''
+    @Description:
+        Reads the file into a dictionary where the key values are the parameter
+        names.
+
+    @Input:
+        filename: string
+            Path to file where the ECMWV environment parameters are stored.
+
+    @Return:
+        envs: dict
+            Contains the environment parameter ecuid, ecgid, gateway
+            and destination for ECMWF server environments.
+    '''
+    envs= {}
+
+    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):
+    '''
+    @Description:
+        Remove all files from intermediate directory
+        (inputdir from CONTROL file).
+
+    @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.
+
+    @Return:
+        <nothing>
+    '''
+
+    print("clean_up")
+
+    cleanlist = glob.glob(c.inputdir + "/*")
+    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(clist)
+
+    print("Done")
+
+    return
+
+
+def my_error(users, message='ERROR'):
+    '''
+    @Description:
+        Prints a specified error message which can be passed to the function
+        before exiting the program.
+
+    @Input:
+        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
+            Error message. Default value is "ERROR".
+
+    @Return:
+        <nothing>
+    '''
+
+    print(message)
+
+    # comment if user does not want email notification directly from python
+    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:
+        Prints a specific exit message which can be passed to the function.
+
+    @Input:
+        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
+            Message for exiting program. Default value is "Done!".
+
+    @Return:
+        <nothing>
+
+    '''
+    print(message)
+
+    # comment if user does not want notification directly from python
+    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,
+                                 stderr=subprocess.PIPE,
+                                 bufsize=1)
+            pout = p.communicate(input=message+'\n\n')[0]
+        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
+
+
+def product(*args, **kwds):
+    '''
+    @Description:
+        This method is taken from an example at the ECMWF wiki website.
+        https://software.ecmwf.int/wiki/display/GRIB/index.py; 2018-03-16
+
+        This method combines the single characters of the passed arguments
+        with each other. So that each character of each argument value
+        will be combined with each character of the other arguments as a tuple.
+
+        Example:
+        product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
+        product(range(2), repeat = 3) --> 000 001 010 011 100 101 110 111
+
+    @Input:
+        *args: tuple
+            Positional arguments (arbitrary number).
+
+        **kwds: dictionary
+            Contains all the keyword arguments from *args.
+
+    @Return:
+        prod: tuple
+            Return will be done with "yield". A tuple of combined arguments.
+            See example in description above.
+    '''
+    pools = map(tuple, args) * kwds.get('repeat', 1)
+    result = [[]]
+    for pool in pools:
+        result = [x + [y] for x in result for y in pool]
+    for prod in result:
+        yield tuple(prod)
+
+    return
+
+
+def silent_remove(filename):
+    '''
+    @Description:
+        Remove file if it exists.
+        The function does not fail if the file does not exist.
+
+    @Input:
+        filename: string
+            The name of the file to be removed without notification.
+
+    @Return:
+        <nothing>
+    '''
+    try:
+        os.remove(filename)
+    except OSError as e:
+        if e.errno != errno.ENOENT:
+            # errno.ENOENT  =  no such file or directory
+            raise  # re-raise exception if a different error occured
+
+    return
+
+
+def init128(filepath):
+    '''
+    @Description:
+        Opens and reads the grib file with table 128 information.
+
+    @Input:
+        filepath: string
+            Path to file of ECMWF grib table number 128.
+
+    @Return:
+        table128: dictionary
+            Contains the ECMWF grib table 128 information.
+            The key is the parameter number and the value is the
+            short name of the parameter.
+    '''
+    table128 = dict()
+    with open(filepath) as f:
+        fdata = f.read().split('\n')
+    for data in fdata:
+        if data[0] != '!':
+            table128[data[0:3]] = data[59:64].strip()
+
+    return table128
+
+
+def to_param_id(pars, table):
+    '''
+    @Description:
+        Transform parameter names to parameter ids
+        with ECMWF grib table 128.
+
+    @Input:
+        pars: string
+            Addpar argument from CONTROL file in the format of
+            parameter names instead of ids. The parameter short
+            names are sepearted with "/" and they are passed as
+            one single string.
+
+        table: dictionary
+            Contains the ECMWF grib table 128 information.
+            The key is the parameter number and the value is the
+            short name of the parameter.
+
+    @Return:
+        ipar: list of integer
+            List of addpar parameters from CONTROL file transformed to
+            parameter ids in the format of integer.
+    '''
+    cpar = pars.upper().split('/')
+    ipar = []
+    for par in cpar:
+        for k, v in table.iteritems():
+            if par == k or par == v:
+                ipar.append(int(k))
+                break
+        else:
+            print('Warning: par ' + par + ' not found in table 128')
+
+    return ipar
+
+def get_list_as_string(list_obj, concatenate_sign=', '):
+    '''
+    @Description:
+        Converts a list of arbitrary content into a single string.
+
+    @Input:
+        list_obj: list
+            A list with arbitrary content.
+
+        concatenate_sign: string, optional
+            A string which is used to concatenate the single
+            list elements. Default value is ", ".
+
+    @Return:
+        str_of_list: string
+            The content of the list as a single string.
+    '''
+
+    str_of_list = concatenate_sign.join(str(l) for l in list_obj)
+
+    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 name including the 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-file-put command to send a file to the ECMWF servers.
+
+        NOTE:
+        The return value is just for testing reasons. It does not have
+        to be used from the calling function since the whole error handling
+        is done in here.
+
+    @Input:
+        ecd: string
+            The path were the file is stored.
+
+        filename: string
+            The name of the file to send to the ECMWF server.
+
+        target: string
+            The target queue where the file should be sent to.
+
+        ecuid: string
+            The user id on ECMWF server.
+
+        ecgid: string
+            The group id on ECMWF server.
+
+    @Return:
+        rcode: string
+            Resulting code of command execution. If successful the string
+            will be empty.
+    '''
+
+    try:
+        rcode = subprocess.check_output(['ecaccess-file-put',
+                                          ecd + '/' + filename,
+                                          target + ':/home/ms/' +
+                                          ecgid + '/' + ecuid +
+                                          '/' + filename],
+                                         stderr=subprocess.STDOUT)
+    except subprocess.CalledProcessError as e:
+        print('... ERROR CODE:\n ... ' + str(e.returncode))
+        print('... ERROR MESSAGE:\n ... ' + str(e))
+
+        print('\n... Do you have a valid ecaccess certification key?')
+        sys.exit('... ECACCESS-FILE-PUT FAILED!')
+
+    return rcode
+
+def submit_job_to_ecserver(target, jobname):
+    '''
+    @Description:
+        Uses ecaccess-job-submit command to submit a job to the ECMWF server.
+
+        NOTE:
+        The return value is just for testing reasons. It does not have
+        to be used from the calling function since the whole error handling
+        is done in here.
+
+    @Input:
+        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:
+        rcode: string
+            Resulting code of command execution. If successful the string
+            will contain an integer number, representing the id of the job
+            at the ecmwf server.
+    '''
+
+    try:
+        rcode = subprocess.check_output(['ecaccess-job-submit',
+                                         '-queueName', target,
+                                         jobname])
+    except subprocess.CalledProcessError as e:
+        print('... ERROR CODE:\n ... ' + str(e.returncode))
+        print('... ERROR MESSAGE:\n ... ' + str(e))
+
+
+        print('\n... Do you have a valid ecaccess certification key?')
+        sys.exit('... ECACCESS-JOB-SUBMIT FAILED!')
+
+    return rcode
