From 092aaf1bfb2e76aea6d9a2079adf1b4bd81dcd37 Mon Sep 17 00:00:00 2001
From: Anne Philipp <anne.philipp@univie.ac.at>
Date: Fri, 14 Dec 2018 00:53:49 +0100
Subject: [PATCH] modularized the init function; implemented disaggregation
 with new interpolation method

---
 source/python/classes/EcFlexpart.py | 627 ++++++++++++++++++++--------
 1 file changed, 445 insertions(+), 182 deletions(-)

diff --git a/source/python/classes/EcFlexpart.py b/source/python/classes/EcFlexpart.py
index 7b66a26..8ebe300 100644
--- a/source/python/classes/EcFlexpart.py
+++ b/source/python/classes/EcFlexpart.py
@@ -89,7 +89,7 @@ from eccodes import (codes_index_select, codes_new_from_index, codes_get,
 # software specific classes and modules from flex_extract
 sys.path.append('../')
 import _config
-from GribTools import GribTools
+from GribUtil import GribUtil
 from mods.tools import (init128, to_param_id, silent_remove, product,
                         my_error, make_dir, get_informations, get_dimensions)
 from MarsRetrieval import MarsRetrieval
@@ -124,43 +124,85 @@ class EcFlexpart(object):
         ------
 
         '''
-        # set a counter for the number of mars requests generated
+        # set a counter for the number of generated mars requests
         self.mreq_count = 0
 
-        # different mars types for retrieving data for flexpart
-        self.types = dict()
-
-        # Pure forecast mode
-        if c.purefc:
-            c.type = [c.type[0]]
-            c.step = ['{:0>3}'.format(int(c.step[0]))]
-            c.time = [c.time[0]]
-            for i in range(1, c.maxstep + 1):
-                c.type.append(c.type[0])
-                c.step.append('{:0>3}'.format(i))
-                c.time.append(c.time[0])
-
         self.inputdir = c.inputdir
         self.dataset = c.dataset
         self.basetime = c.basetime
         self.dtime = c.dtime
-        i = 0
+        self.acctype = c.acctype
+        self.acctime = c.acctime
+        self.accmaxstep = c.accmaxstep
+        self.marsclass = c.marsclass
+        self.stream = c.stream
+        self.number = c.number
+        self.resol = c.resol
+        self.accuracy = c.accuracy
+        self.addpar = c.addpar
+        self.level = c.level
+        self.expver = c.expver
+        self.levelist = c.levelist
+        self.glevelist = '1/to/' + c.level # in case of gaussian grid
+        self.gaussian = c.gaussian
+        self.grid = c.grid
+        self.area = c.area
+        self.purefc = c.purefc
+        self.outputfilelist = []
+
+        # Define the different types of field combinations (type, time, step)
+        self.types = {}
+        # Define the parameters and their level types, level list and
+        # grid resolution for the retrieval job
+        self.params = {}
+
+        if fluxes:
+            self._create_params_fluxes()
+        else:
+            self._create_params(c.gauss, c.eta, c.omega, c.cwc, c.wrf)
+
         if fluxes and not c.purefc:
-            self.types[str(c.acctype)] = {'times': str(c.acctime),
-                                          'steps': '{}/to/{}/by/{}'.format(
-                                              c.dtime, c.accmaxstep, c.dtime)}
+            self._create_field_types_fluxes()
         else:
-            for ty, st, ti in zip(c.type, c.step, c.time):
-                btlist = range(24)
-                if c.basetime == '12':
-                    btlist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
-                if c.basetime == '00':
-                    btlist = [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0]
-
-                if ((ty.upper() == 'AN' and (int(c.time[i]) % int(c.dtime)) == 0) or
-                    (ty.upper() != 'AN' and (int(c.step[i]) % int(c.dtime)) == 0 and
-                     (int(c.step[i]) % int(c.dtime) == 0)) ) and \
-                    (int(c.time[i]) in btlist or c.purefc):
+            self._create_field_types(c.type, c.time, c.step)
+        return
+
+    def _create_field_types(self, ftype, ftime, fstep):
+        '''Create the combination of field type, time and forecast step.
+
+        Parameters:
+        -----------
+        ftype : :obj:`list` of :obj:`string`
+            List of field types.
+
+        ftime : :obj:`list` of :obj:`string`
+            The time in hours of the field.
+
+        fstep : :obj:`string`
+            Specifies the forecast time step from forecast base time.
+            Valid values are hours (HH) from forecast base time.
+
+        Return
+        ------
+
+        '''
+        i = 0
+        for ty, st, ti in zip(ftype, fstep, ftime):
+            btlist = range(24)
+            if self.basetime == '12':
+                btlist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+            if self.basetime == '00':
+                btlist = [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0]
+
+            # if ((ty.upper() == 'AN' and (int(c.time[i]) % int(c.dtime)) == 0) or
+                # (ty.upper() != 'AN' and (int(c.step[i]) % int(c.dtime)) == 0 and
+                 # (int(c.step[i]) % int(c.dtime) == 0)) ) and \
+                 # (int(c.time[i]) in btlist or c.purefc):
+
+            if (int(ti) in btlist) or self.purefc:
+
+                if ((ty.upper() == 'AN' and (int(ti) % int(self.dtime)) == 0) or
+                    (ty.upper() != 'AN' and (int(st) % int(self.dtime)) == 0)):
 
                     if ty not in self.types.keys():
                         self.types[ty] = {'times': '', 'steps': ''}
@@ -174,109 +216,153 @@ class EcFlexpart(object):
                         if self.types[ty]['steps']:
                             self.types[ty]['steps'] += '/'
                         self.types[ty]['steps'] += st
-                i += 1
+            i += 1
+        return
 
-        self.marsclass = c.marsclass
-        self.stream = c.stream
-        self.number = c.number
-        self.resol = c.resol
-        self.accuracy = c.accuracy
-        self.level = c.level
-        self.expver = c.expver
-        self.levelist = c.levelist
-        # for gaussian grid retrieval
-        self.glevelist = '1/to/' + c.level
-        self.gaussian = c.gaussian
-        self.grid = c.grid
-        self.area = c.area
-        self.outputfilelist = []
+    def _create_field_types_fluxes(self):
+        '''Create the combination of field type, time and forecast step
+        for the flux data.
 
+        Parameters:
+        -----------
 
-        # Now comes the nasty part that deals with the different
-        # scenarios we have:
-        # 1) Calculation of etadot on
-        #    a) Gaussian grid
-        #    b) Output grid
-        #    c) Output grid using parameter 77 retrieved from MARS
-        # 3) Calculation/Retrieval of omega
-        # 4) Download also data for WRF
-
-        # Different grids need different retrievals
-        # SH = Spherical Harmonics, GG = Gaussian Grid,
-        # OG = Output Grid, ML = MultiLevel, SL = SingleLevel
-        self.params = {'SH__ML': '', 'SH__SL': '',
-                       'GG__ML': '', 'GG__SL': '',
-                       'OG__ML': '', 'OG__SL': '',
-                       'OG_OROLSM_SL': '', 'OG_acc_SL': ''}
-        # the self.params dictionary stores a list of
-        # [param, levtype, levelist, grid] per key
-
-        if fluxes is False:
-            self.params['SH__SL'] = ['LNSP', 'ML', '1', 'OFF']
-            #                        "SD/MSL/TCC/10U/10V/2T/2D/129/172"
-            self.params['OG__SL'] = ["141/151/164/165/166/167/168/129/172", \
-                                     'SFC', '1', self.grid]
-            if c.addpar:
-                if c.addpar[0] == '/':
-                    c.addpar = c.addpar[1:]
-                self.params['OG__SL'][0] += '/' + '/'.join(c.addpar)
-
-            if c.marsclass.upper() == 'EA' or c.marsclass.upper() == 'EP':
-                self.params['OG_OROLSM__SL'] = ["160/27/28/244",
-                                                'SFC', '1', self.grid]
-            else:
-                self.params['OG_OROLSM__SL'] = ["160/27/28/173", \
-                                                'SFC', '1', self.grid]
-
-            self.params['OG__ML'] = ['T/Q', 'ML', self.levelist, self.grid]
-
-            #if c.gauss == '0' and c.eta == '1':
-            if not c.gauss and c.eta:
-                # the simplest case
-                self.params['OG__ML'][0] += '/U/V/77'
-            #elif c.gauss == '0' and c.eta == '0':
-            elif not c.gauss and not c.eta:
-            # this is not recommended (inaccurate)
-                self.params['OG__ML'][0] += '/U/V'
-            #elif c.gauss == '1' and c.eta == '0':
-            elif c.gauss and not c.eta:
-                # this is needed for data before 2008, or for reanalysis data
-                self.params['GG__SL'] = ['Q', 'ML', '1', \
-                                         '{}'.format((int(self.resol) + 1) / 2)]
-                self.params['SH__ML'] = ['U/V/D', 'ML', self.glevelist, 'OFF']
-            else:
-                print('Warning: This is a very costly parameter combination, \
-                      use only for debugging!')
-                self.params['GG__SL'] = ['Q', 'ML', '1', \
-                                         '{}'.format((int(self.resol) + 1) / 2)]
-                self.params['GG__ML'] = ['U/V/D/77', 'ML', self.glevelist, \
-                                         '{}'.format((int(self.resol) + 1) / 2)]
+        Return
+        ------
 
-            if c.omega:
-                self.params['OG__ML'][0] += '/W'
+        '''
+        self.types[str(self.acctype)] = {'times': str(self.acctime),
+                                         'steps': '{}/to/{}/by/{}'.format(
+                                             self.dtime,
+                                             self.accmaxstep,
+                                             self.dtime)}
+        return
 
-            # add cloud water content if necessary
-            if c.cwc:
-                self.params['OG__ML'][0] += '/CLWC/CIWC'
+    def _create_params(self, gauss, eta, omega, cwc, wrf):
+        '''Define the specific parameter settings for retrievment.
+
+        The different parameters need specific grid types and level types
+        for retrievement. We might get following combination of types
+        (depending on selection and availability):
+        (These are short cuts for the grib file names (leading sequence)
+        SH__ML, OG__ML, GG__ML, SH__SL, OG__SL, GG__SL, OG_OROLSM_SL
+        where:
+            SH = Spherical Harmonics, GG = Gaussian Grid, OG = Output Grid,
+            ML = Model Level, SL = Surface Level
+
+        For each of this combination there is a list of parameter names,
+        the level type, the level list and the grid resolution.
+
+        There are different scenarios for data extraction from MARS:
+        1) Retrieval of etadot
+           eta=1, gauss=0, omega=0
+        2) Calculation of etadot from divergence
+           eta=0, gauss=1, omega=0
+        3) Calculation of etadot from omega (for makes sense for debugging)
+           eta=0, gauss=0, omega=1
+        4) Retrieval and Calculation of etadot (only for debugging)
+           eta=1, gauss=1, omega=0
+        5) Download also specific model and surface level data for FLEXPART-WRF
 
-            # add vorticity and geopotential height for WRF if necessary
-            if c.wrf:
-                self.params['OG__ML'][0] += '/Z/VO'
-                if '/D' not in self.params['OG__ML'][0]:
-                    self.params['OG__ML'][0] += '/D'
-                #wrf_sfc = 'sp/msl/skt/2t/10u/10v/2d/z/lsm/sst/ci/sd/stl1/ /
-                #           stl2/stl3/stl4/swvl1/swvl2/swvl3/swvl4'.upper()
-                wrf_sfc = '134/235/167/165/166/168/129/172/34/31/141/ \
-                           139/170/183/236/39/40/41/42'
-                lwrt_sfc = wrf_sfc.split('/')
-                for par in lwrt_sfc:
-                    if par not in self.params['OG__SL'][0]:
-                        self.params['OG__SL'][0] += '/' + par
+        Parameters:
+        -----------
+        gauss : :obj:`integer`
+            Gaussian grid is retrieved.
+
+        eta : :obj:`integer`
+            Etadot parameter will be directly retrieved.
+
+        omega : :obj:`integer`
+            The omega paramterwill be retrieved.
+
+        cwc : :obj:`integer`
+            The cloud liquid and ice water content will be retrieved.
 
+        wrf : :obj:`integer`
+            Additional model level and surface level data will be retrieved for
+            WRF/FLEXPART-WRF simulations.
+
+        Return
+        ------
+
+        '''
+        # SURFACE FIELDS
+        #-----------------------------------------------------------------------
+        self.params['SH__SL'] = ['LNSP', 'ML', '1', 'OFF']
+        self.params['OG__SL'] = ['SD/MSL/TCC/10U/10V/2T/2D/Z/LSM', \
+                                 'SFC', '1', self.grid]
+        if self.addpar:
+            self.params['OG__SL'][0] += self.addpar
+
+        if self.marsclass.upper() == 'EA' or self.marsclass.upper() == 'EP':
+            self.params['OG_OROLSM__SL'] = ["SDOR/CVL/CVH/FSR",
+                                            'SFC', '1', self.grid]
+        else:
+            self.params['OG_OROLSM__SL'] = ["SDOR/CVL/CVH/SR", \
+                                            'SFC', '1', self.grid]
+
+        # MODEL LEVEL FIELDS
+        #-----------------------------------------------------------------------
+        self.params['OG__ML'] = ['T/Q', 'ML', self.levelist, self.grid]
+
+        if not gauss and eta:
+            self.params['OG__ML'][0] += '/U/V/ETADOT'
+        elif gauss and not eta:
+            self.params['GG__SL'] = ['Q', 'ML', '1', \
+                                     '{}'.format((int(self.resol) + 1) / 2)]
+            self.params['SH__ML'] = ['U/V/D', 'ML', self.glevelist, 'OFF']
+        elif not gauss and not eta:
+            self.params['OG__ML'][0] += '/U/V'
         else:
-            self.params['OG_acc_SL'] = ["LSP/CP/SSHF/EWSS/NSSS/SSR", \
-                                        'SFC', '1', self.grid]
+            print('Warning: Collecting etadot and parameters for gaussian grid \
+                            is a very costly parameter combination, \
+                            use this combination only for debugging!')
+            self.params['GG__SL'] = ['Q', 'ML', '1', \
+                                     '{}'.format((int(self.resol) + 1) / 2)]
+            self.params['GG__ML'] = ['U/V/D/77', 'ML', self.glevelist, \
+                                     '{}'.format((int(self.resol) + 1) / 2)]
+
+        if omega:
+            self.params['OG__ML'][0] += '/W'
+
+        if cwc:
+            self.params['OG__ML'][0] += '/CLWC/CIWC'
+
+        # ADDITIONAL FIELDS FOR FLEXPART-WRF MODEL (IF QUESTIONED)
+        #-----------------------------------------------------------------------
+        if wrf:
+            self.params['OG__ML'][0] += '/Z/VO'
+            if '/D' not in self.params['OG__ML'][0]:
+                self.params['OG__ML'][0] += '/D'
+            wrf_sfc = ['SP','SKT','SST','CI','STL1','STL2', 'STL3','STL4',
+                       'SWVL1','SWVL2','SWVL3','SWVL4']
+            for par in wrf_sfc:
+                if par not in self.params['OG__SL'][0]:
+                    self.params['OG__SL'][0] += '/' + par
+
+        return
+
+
+    def _create_params_fluxes(self):
+        '''Define the parameter setting for flux data.
+
+        Flux data are accumulated fields in time and are stored on the
+        surface level. The leading short cut name for the grib files is:
+        "OG_acc_SL" with OG for Regular Output Grid, SL for Surface Level, and
+        acc for Accumulated Grid.
+        The params dictionary stores a list of parameter names, the level type,
+        the level list and the grid resolution.
+
+        The flux data are: LSP/CP/SSHF/EWSS/NSSS/SSR
+
+        Parameters:
+        -----------
+
+        Return
+        ------
 
+        '''
+        self.params['OG_acc_SL'] = ["LSP/CP/SSHF/EWSS/NSSS/SSR", \
+                                    'SFC', '1', self.grid]
         return
 
 
@@ -400,7 +486,7 @@ class EcFlexpart(object):
 
         indexfile = os.path.join(inputdir, _config.FILE_GRIB_INDEX)
         silent_remove(indexfile)
-        grib = GribTools(inputfiles.files)
+        grib = GribUtil(inputfiles.files)
         # creates new index file
         iid = grib.index(index_keys=index_keys, index_file=indexfile)
 
@@ -748,20 +834,31 @@ class EcFlexpart(object):
                                                 index_keys)
         # index_vals looks like e.g.:
         # index_vals[0]: ('20171106', '20171107', '20171108') ; date
-        # index_vals[1]: ('0', '1200', '1800', '600') ; time
+        # index_vals[1]: ('0', '600', '1200', '1800') ; time
         # index_vals[2]: ('0', '12', '3', '6', '9') ; stepRange
 
         if c.rrint:
-            start_date = datetime.strptime(c.start_date + '00', '%Y%m%d%H')
-            end_date = datetime.strptime(c.end_date + '23', '%Y%m%d%H')
+            if not c.purefc:
+                start_date = datetime.strptime(c.start_date + '00', '%Y%m%d%H')
+                end_date = datetime.strptime(c.end_date + '23', '%Y%m%d%H')
+            else:
+                sdate_str = c.start_date + '{:0>2}'.format(index_vals[1][0])
+                start_date = datetime.strptime(sdate_str, '%Y%m%d%H')
+                edate_str = c.end_date + '{:0>2}'.format(index_vals[1][-1])
+                end_date = datetime.strptime(edate_str, '%Y%m%d%H')
+                end_date = end_date + timedelta(hours=c.maxstep)
+
             info = get_informations(os.path.join(c.inputdir,
                                                  inputfiles.files[0]))
-            dims = get_dimensions(c, info)
+            dims = get_dimensions(info, c.purefc, c.dtime, index_vals,
+                                  start_date, end_date)
             # create numpy array
             lsp_np = np.zeros((dims[1] * dims[0], dims[2]), dtype=np.float64)
             cp_np = np.zeros((dims[1] * dims[0], dims[2]), dtype=np.float64)
             it_lsp = 0
             it_cp = 0
+            date_list = []
+            step_list = []
 
         # initialize dictionaries to store values
         orig_vals = {}
@@ -791,12 +888,15 @@ class EcFlexpart(object):
 
             # create correct timestamp from the three time informations
             cdate = str(codes_get(gid, 'date'))
-            ctime = '{:0>2}'.format(codes_get(gid, 'time')/100)
-            cstep = '{:0>3}'.format(codes_get(gid, 'step'))
+            time = codes_get(gid, 'time')/100 # integer
+            step = codes_get(gid, 'step') # integer
+            ctime = '{:0>2}'.format(time)
+            cstep = '{:0>3}'.format(step)
+
             t_date = datetime.strptime(cdate + ctime, '%Y%m%d%H')
-            t_dt = t_date + timedelta(hours=int(cstep))
-            t_m1dt = t_date + timedelta(hours=int(cstep)-int(c.dtime))
-            t_m2dt = t_date + timedelta(hours=int(cstep)-2*int(c.dtime))
+            t_dt = t_date + timedelta(hours=step)
+            t_m1dt = t_date + timedelta(hours=step-int(c.dtime))
+            t_m2dt = t_date + timedelta(hours=step-2*int(c.dtime))
             t_enddate = None
 
             if c.purefc:
@@ -822,16 +922,16 @@ class EcFlexpart(object):
             h_handle = open(hnout, 'w')
             g_handle = open(gnout, 'w')
 
-            # read message for message and store relevant data fields
+            # read message for message and store relevant data fields, where
             # data keywords are stored in pars
             while True:
                 if not gid:
                     break
-                parId = codes_get(gid, 'paramId')
-                step = codes_get(gid, 'step')
-                time = codes_get(gid, 'time')
-                ni = codes_get(gid, 'Ni')
-                nj = codes_get(gid, 'Nj')
+                parId = codes_get(gid, 'paramId') # integer
+                step = codes_get(gid, 'step') # integer
+                time = codes_get(gid, 'time') # integer
+                ni = codes_get(gid, 'Ni') # integer
+                nj = codes_get(gid, 'Nj') # integer
                 if parId not in orig_vals.keys():
                     # parameter is not a flux, find next one
                     continue
@@ -860,23 +960,32 @@ class EcFlexpart(object):
 
                 # store precipitation if new disaggregation method is selected
                 # only the exact days are needed
-                if start_date <= t_dt <= end_date:
-                    print 'DATE: ', t_dt
-                    if c.rrint and parId == 142:
-                        print len(deac_vals[parId])
-                        lsp_np[:,it_lsp] = deac_vals[parId][-1][:]
-                        it_lsp += 1
-                    elif c.rrint and parId == 143:
-                        cp_np[:,it_cp] = deac_vals[parId][-1][:]
-                        it_cp += 1
+                if c.rrint:
+                    if start_date <= t_dt <= end_date:
+                        if not c.purefc:
+                            if t_dt not in date_list:
+                                date_list.append(t_dt)
+                                step_list = [0]
+                        else:
+                            if t_date not in date_list:
+                                date_list.append(t_date)
+                            if step not in step_list:
+                                step_list.append(step)
+                        if c.rrint and parId == 142:
+                            lsp_np[:,it_lsp] = deac_vals[parId][-1][:]
+                            it_lsp += 1
+                        elif c.rrint and parId == 143:
+                            cp_np[:,it_cp] = deac_vals[parId][-1][:]
+                            it_cp += 1
 
                 # information printout
                 print(parId, time, step, len(values), values[0], np.std(values))
 
                 # length of deac_vals[parId] corresponds to the
-                # number of time steps (max. 4)
+                # number of time steps, max. 4 are needed for disaggegration
+                # with the old and original method
                 # run over all grib messages and perform
-                # shifting in time for old disaggegration method
+                # shifting in time
                 if len(deac_vals[parId]) >= 3:
                     if len(deac_vals[parId]) > 3:
                         if not c.rrint and (parId == 142 or parId == 143):
@@ -923,32 +1032,40 @@ class EcFlexpart(object):
 
                             if step == c.maxstep and c.purefc or \
                                t_dt == t_enddate:
+                                # last step
+                                if c.purefc:
+                                    values = deac_vals[parId][3]
+                                    codes_set_values(gid, values)
+                                    codes_set(gid, 'stepRange', step)
+                                    #truedatetime = t_m2dt + timedelta(hours=2*int(c.dtime))
+                                    codes_write(gid, h_handle)
+                                else:
+                                    values = deac_vals[parId][3]
+                                    codes_set_values(gid, values)
+                                    codes_set(gid, 'stepRange', 0)
+                                    truedatetime = t_m2dt + timedelta(hours=2*int(c.dtime))
+                                    codes_set(gid, 'time', truedatetime.hour * 100)
+                                    codes_set(gid, 'date', int(truedatetime.strftime('%Y%m%d')))
+                                    codes_write(gid, h_handle)
 
-                                values = deac_vals[parId][3]
-                                codes_set_values(gid, values)
-                                codes_set(gid, 'stepRange', 0)
-                                truedatetime = t_m2dt + timedelta(hours=
-                                                                  2*int(c.dtime))
-                                codes_set(gid, 'time', truedatetime.hour * 100)
-                                codes_set(gid, 'date', truedatetime.year * 10000 +
-                                          truedatetime.month * 100 +
-                                          truedatetime.day)
-                                codes_write(gid, h_handle)
-
-                                #values = (deac_vals[parId][1]+deac_vals[parId][2])/2.
                                 if parId == 142 or parId == 143:
                                     values = disaggregation.darain(list(reversed(deac_vals[parId])))
                                 else:
                                     values = disaggregation.dapoly(list(reversed(deac_vals[parId])))
 
-                                codes_set(gid, 'stepRange', 0)
-                                truedatetime = t_m2dt + timedelta(hours=int(c.dtime))
-                                codes_set(gid, 'time', truedatetime.hour * 100)
-                                codes_set(gid, 'date', truedatetime.year * 10000 +
-                                          truedatetime.month * 100 +
-                                          truedatetime.day)
-                                codes_set_values(gid, values)
-                                codes_write(gid, g_handle)
+                                # step before last step
+                                if c.purefc:
+                                    codes_set(gid, 'stepRange', step-int(c.dtime))
+                                    #truedatetime = t_m2dt + timedelta(hours=int(c.dtime))
+                                    codes_set_values(gid, values)
+                                    codes_write(gid, g_handle)
+                                else:
+                                    codes_set(gid, 'stepRange', 0)
+                                    truedatetime = t_m2dt + timedelta(hours=int(c.dtime))
+                                    codes_set(gid, 'time', truedatetime.hour * 100)
+                                    codes_set(gid, 'date', int(truedatetime.strftime('%Y%m%d')))
+                                    codes_set_values(gid, values)
+                                    codes_write(gid, g_handle)
 
                 codes_release(gid)
 
@@ -960,19 +1077,164 @@ class EcFlexpart(object):
 
         codes_index_release(iid)
 
-        # disaggregation.IA3(lsp_np)
-        # pro gitterpunkt die zeitserie disagg, oder geht es auch mit feld
-        # wenn zurück dann über zeitschritte itterieren und rausschreiben.
-        # original in die flux
-        # subgrid wohin? extrafiles die beide oder jeweils einen subgrid beinhalten?
-        # kann time hh und mm fassen?
+        if c.rrint:
+            self._create_rr_grib_dummy(inputfiles.files[0], c.inputdir)
+
+            self._prep_new_rrint(ni, nj, lsp_np.shape[1], lsp_np,
+                                 cp_np, date_list, step_list, c)
+
+        return
+
+    def _prep_new_rrint(self, ni, nj, nt, lsp_np, cp_np, date_list, step_list, c):
+        '''Calculates and writes out the disaggregated precipitation fields.
 
-        print lsp_np.shape
-        print lsp_np
+        Disaggregation is done in time and original times are written to the
+        flux files, while the additional subgrid times are written to
+        extra files.
 
+        Parameters
+        ----------
+        ni : :obj:`integer`
+            Amount of zonal grid points.
+
+        nj : :obj:`integer`
+            Amount of meridional grid points.
+
+        nt : :obj:`integer`
+            Number of time steps.
+
+        lsp_np : :obj:`numpy array` of :obj:`float`
+            The large scale precipitation fields for each time step.
+            Shape (ni * nj, nt).
+
+        cp_np : :obj:`numpy array` of :obj:`float`
+            The convective precipitation fields for each time step.
+            Shape (ni * nj, nt).
+
+        date_list : :obj:`list` of :obj:`datetime`
+            The list of dates for which the disaggregation is to be done.
+
+        step_list : :obj:`list` of :obj:`integer`
+            The list of steps for a single forecast time.
+            Only necessary for pure forecasts.
 
+        c : :obj:`ControlFile`
+            Contains all the parameters of CONTROL file and
+            command line.
+
+        Return
+        ------
+
+        '''
+        print('... disaggregation or precipitation with new method.')
+        lsp_new_np = np.zeros((ni * nj, nt * 3), dtype=np.float64)
+        cp_new_np = np.zeros((ni * nj, nt * 3), dtype=np.float64)
+
+        # do the disaggregation, but neglect the last value of the
+        # time series. This one corresponds for example to 24 hour,
+        # which we don't need.
+        for ix in range(ni*nj):
+            lsp_new_np[ix,:] = disaggregation.IA3(lsp_np[ix,:])[:-1]
+            cp_new_np[ix,:] = disaggregation.IA3(cp_np[ix,:])[:-1]
+
+        # write to grib files (full/orig times to flux file and inbetween
+        # times into seperate end files)
+        print('... write disaggregated precipitation to files.')
+        it = 0
+        for date in date_list:
+            for step in step_list:
+                tmpfile = os.path.join(c.inputdir, 'rr_grib_dummy.grb')
+
+                if c.purefc:
+                    fluxfilename = 'flux' + date.strftime('%Y%m%d.%H') + \
+                                   '.{:0>3}'.format(step)
+                    filename1 = c.prefix + date.strftime('%y%m%d.%H') + \
+                                '.{:0>3}'.format(step) + '_1'
+                    filename2 = c.prefix + date.strftime('%y%m%d.%H') + \
+                                '.{:0>3}'.format(step) + '_2'
+                else:
+                    fluxfilename = 'flux' + date.strftime('%Y%m%d%H')
+                    filename1 = c.prefix + date.strftime('%y%m%d%H') + '_1'
+                    filename2 = c.prefix + date.strftime('%y%m%d%H') + '_2'
+
+                # collect for final processing
+                self.outputfilelist.append(os.path.basename(fluxfilename))
+                self.outputfilelist.append(os.path.basename(filename1))
+                self.outputfilelist.append(os.path.basename(filename2))
+
+                # write original time step to flux file as usual
+                fluxfile = GribUtil(os.path.join(c.inputdir, fluxfilename))
+                fluxfile.set_keys(tmpfile, filemode='a', strict=True,
+                                  wherekeynames=['paramId'], wherekeyvalues=[142],
+                                  keynames=['date','time','stepRange','values'],
+                                  keyvalues=[int(date.strftime('%Y%m%d')),
+                                             date.hour*100, step, lsp_new_np[:,it]],
+                                 )
+                fluxfile.set_keys(tmpfile, filemode='a', strict=True,
+                                  wherekeynames=['paramId'], wherekeyvalues=[143],
+                                  keynames=['date','time','stepRange','values'],
+                                  keyvalues=[int(date.strftime('%Y%m%d')),
+                                             date.hour*100, step, cp_new_np[:,it]]
+                                 )
+
+                # write first subgrid time step
+                endfile1 = GribUtil(os.path.join(c.inputdir, filename1))
+                endfile1.set_keys(tmpfile, filemode='w', strict=True,
+                                  wherekeynames=['paramId'], wherekeyvalues=[142],
+                                  keynames=['date','time','stepRange','values'],
+                                  keyvalues=[int(date.strftime('%Y%m%d')),
+                                             date.hour*100, step, lsp_new_np[:,it+1]]
+                                  )
+                endfile1.set_keys(tmpfile, filemode='a', strict=True,
+                                  wherekeynames=['paramId'], wherekeyvalues=[143],
+                                  keynames=['date','time','stepRange','values'],
+                                  keyvalues=[int(date.strftime('%Y%m%d')),
+                                             date.hour*100, step, cp_new_np[:,it+1]]
+                                 )
+
+                # write second subgrid time step
+                endfile2 = GribUtil(os.path.join(c.inputdir, filename2))
+                endfile2.set_keys(tmpfile, filemode='w', strict=True,
+                                  wherekeynames=['paramId'], wherekeyvalues=[142],
+                                  keynames=['date','time','stepRange','values'],
+                                  keyvalues=[int(date.strftime('%Y%m%d')),
+                                             date.hour*100, step, lsp_new_np[:,it+2]]
+                                 )
+                endfile2.set_keys(tmpfile, filemode='a', strict=True,
+                                  wherekeynames=['paramId'], wherekeyvalues=[143],
+                                  keynames=['date','time','stepRange','values'],
+                                  keyvalues=[int(date.strftime('%Y%m%d')),
+                                             date.hour*100, step, cp_new_np[:,it+2]]
+                                 )
+                it = it + 3 # jump to next original time step
         return
 
+    def _create_rr_grib_dummy(self, ifile, inputdir):
+        '''Creates a grib file with a dummy message for the two precipitation
+        types lsp and cp each.
+
+        Parameters
+        ----------
+        ifile : :obj:`string`
+            Filename of the input file to read the grib messages from.
+
+        inputdir : :obj:`string`, optional
+            Path to the directory where the retrieved data is stored.
+
+        Return
+        ------
+
+        '''
+
+        gribfile = GribUtil(os.path.join(inputdir,'rr_grib_dummy.grb'))
+
+        gribfile.copy_dummy_msg(ifile, keynames=['paramId'],
+                      keyvalues=[142], filemode='w')
+
+        gribfile.copy_dummy_msg(ifile, keynames=['paramId'],
+                      keyvalues=[143], filemode='a')
+
+        return
 
     def create(self, inputfiles, c):
         '''An index file will be created which depends on the combination
@@ -1028,7 +1290,7 @@ class EcFlexpart(object):
                                                 index_keys)
         # index_vals looks like e.g.:
         # index_vals[0]: ('20171106', '20171107', '20171108') ; date
-        # index_vals[1]: ('0', '1200', '1800', '600') ; time
+        # index_vals[1]: ('0', '600', '1200', '1800') ; time
         # index_vals[2]: ('0', '12', '3', '6', '9') ; stepRange
 
         # "product" genereates each possible combination between the
@@ -1116,6 +1378,7 @@ class EcFlexpart(object):
                         codes_set_values(gid, scwc)
                         codes_set(gid, 'paramId', 201031)
                         codes_write(gid, fdict['22'])
+                        scwc = None
                 elif c.wrf and paramId in [129, 138, 155] and \
                       levtype == 'hybrid': # Z, VO, D
                     # do not do anything right now
@@ -1315,7 +1578,7 @@ class EcFlexpart(object):
 
         # read template COMMAND file
         with open(os.path.expandvars(os.path.expanduser(
-            c.flexpart_root_scripts)) + '/../Options/COMMAND', 'r') as f:
+            c.flexpartdir)) + '/../Options/COMMAND', 'r') as f:
             lflist = f.read().split('\n')
 
         # find index of list where to put in the
@@ -1341,7 +1604,7 @@ class EcFlexpart(object):
         # afterwards switch back to the working dir
         os.chdir(c.outputdir)
         p = subprocess.check_call([
-            os.path.expandvars(os.path.expanduser(c.flexpart_root_scripts))
+            os.path.expandvars(os.path.expanduser(c.flexpartdir))
             + '/../FLEXPART_PROGRAM/grib2flexpart', 'useAvailable', '.'])
         os.chdir(pwd)
 
-- 
GitLab