source: flex_extract.git/source/python/classes/EcFlexpart.py @ 0934db1

ctbtodev
Last change on this file since 0934db1 was 0934db1, checked in by Anne Philipp <anne.philipp@…>, 6 years ago

rechanged eccodes implementation, does not work with fortran grib_api lib

  • Property mode set to 100644
File size: 54.2 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#*******************************************************************************
4# @Author: Anne Fouilloux (University of Oslo)
5#
6# @Date: October 2014
7#
8# @Change History:
9#
10#    November 2015 - Leopold Haimberger (University of Vienna):
11#        - extended with class Control
12#        - removed functions mkdir_p, daterange, years_between, months_between
13#        - added functions darain, dapoly, to_param_id, init128, normal_exit,
14#          my_error, clean_up, install_args_and_control,
15#          interpret_args_and_control,
16#        - removed function __del__ in class EIFLexpart
17#        - added the following functions in EIFlexpart:
18#            - create_namelist
19#            - process_output
20#            - deacc_fluxes
21#        - modified existing EIFlexpart - functions for the use in
22#          flex_extract
23#        - retrieve also longer term forecasts, not only analyses and
24#          short term forecast data
25#        - added conversion into GRIB2
26#        - added conversion into .fp format for faster execution of FLEXPART
27#          (see https://www.flexpart.eu/wiki/FpCtbtoWo4FpFormat)
28#
29#    February 2018 - Anne Philipp (University of Vienna):
30#        - applied PEP8 style guide
31#        - added documentation
32#        - removed function getFlexpartTime in class EcFlexpart
33#        - outsourced class ControlFile
34#        - outsourced class MarsRetrieval
35#        - changed class name from EIFlexpart to EcFlexpart
36#        - applied minor code changes (style)
37#        - removed "dead code" , e.g. retrieval of Q since it is not needed
38#        - removed "times" parameter from retrieve-method since it is not used
39#        - seperated function "retrieve" into smaller functions (less code
40#          duplication, easier testing)
41#
42# @License:
43#    (C) Copyright 2014-2018.
44#
45#    This software is licensed under the terms of the Apache Licence Version 2.0
46#    which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
47#
48# @Class Description:
49#    FLEXPART needs grib files in a specifc format. All necessary data fields
50#    for one time step are stored in a single file. The class represents an
51#    instance with all the parameter and settings necessary for retrieving
52#    MARS data and modifing them so they are fitting FLEXPART need. The class
53#    is able to disaggregate the fluxes and convert grid types to the one needed
54#    by FLEXPART, therefore using the FORTRAN program.
55#
56# @Class Content:
57#    - __init__
58#    - write_namelist
59#    - retrieve
60#    - process_output
61#    - create
62#    - deacc_fluxes
63#
64# @Class Attributes:
65#
66#  TODO
67#
68#*******************************************************************************
69#pylint: disable=unsupported-assignment-operation
70# this is disabled because for this specific case its an error in pylint
71#pylint: disable=consider-using-enumerate
72# this is not useful in this case
73# ------------------------------------------------------------------------------
74# MODULES
75# ------------------------------------------------------------------------------
76import os
77import sys
78import glob
79import shutil
80import subprocess
81from datetime import datetime, timedelta
82import numpy as np
83
84from gribapi import (grib_set, grib_index_select, grib_new_from_index, grib_get,
85                     grib_write, grib_get_values, grib_set_values, grib_release,
86                     grib_index_release, grib_index_get)
87
88# from eccodes import (codes_index_select, codes_new_from_index, codes_get,
89                     # codes_get_values, codes_set_values, codes_set,
90                     # codes_write, codes_release, codes_new_from_index,
91                     # codes_index_release, codes_index_get)
92
93# software specific classes and modules from flex_extract
94sys.path.append('../')
95import _config
96from GribTools import GribTools
97from mods.tools import (init128, to_param_id, silent_remove, product,
98                        my_error, make_dir)
99from MarsRetrieval import MarsRetrieval
100import mods.disaggregation as disaggregation
101
102# ------------------------------------------------------------------------------
103# CLASS
104# ------------------------------------------------------------------------------
105class EcFlexpart(object):
106    '''
107    Class to retrieve FLEXPART specific ECMWF data.
108    '''
109    # --------------------------------------------------------------------------
110    # CLASS FUNCTIONS
111    # --------------------------------------------------------------------------
112    def __init__(self, c, fluxes=False):
113        '''
114        @Description:
115            Creates an object/instance of EcFlexpart with the
116            associated settings of its attributes for the retrieval.
117
118        @Input:
119            self: instance of EcFlexpart
120                The current object of the class.
121
122            c: instance of class ControlFile
123                Contains all the parameters of CONTROL file and
124                command line.
125                For more information about format and content of the parameter
126                see documentation.
127
128            fluxes: boolean, optional
129                Decides if the flux parameter settings are stored or
130                the rest of the parameter list.
131                Default value is False.
132
133        @Return:
134            <nothing>
135        '''
136        # set a counter for the number of mars requests generated
137        self.mreq_count = 0
138
139        # different mars types for retrieving data for flexpart
140        self.types = dict()
141
142        # Pure forecast mode
143        if c.maxstep > len(c.type) and 'AN' not in c.type:
144            c.type = [c.type[0]]
145            c.step = ['{:0>3}'.format(int(c.step[0]))]
146            c.time = [c.time[0]]
147            for i in range(1, c.maxstep + 1):
148                c.type.append(c.type[0])
149                c.step.append('{:0>3}'.format(i))
150                c.time.append(c.time[0])
151
152        self.inputdir = c.inputdir
153        self.dataset = c.dataset
154        self.basetime = c.basetime
155        self.dtime = c.dtime
156        i = 0
157        if fluxes and c.maxstep <= 24:
158            # no forecast beyond one day is needed!
159            # Thus, prepare flux data manually as usual
160            # with only forecast fields with start times at 00/12
161            # (but without 00/12 fields since these are
162            # the initialisation times of the flux fields
163            # and therefore are zero all the time)
164            self.types[str(c.acctype)] = {'times': str(c.acctime),
165                                          'steps': '{}/to/{}/by/{}'.format(
166                                              c.dtime, c.accmaxstep, c.dtime)}
167        else:
168            for ty, st, ti in zip(c.type, c.step, c.time):
169                btlist = range(24)
170                if c.basetime == '12':
171                    btlist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
172                if c.basetime == '00':
173                    btlist = [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0]
174
175                if ((ty.upper() == 'AN' and (int(c.time[i]) % int(c.dtime)) == 0) or
176                    (ty.upper() != 'AN' and (int(c.step[i]) % int(c.dtime)) == 0 and
177                     (int(c.step[i]) % int(c.dtime) == 0)) ) and \
178                    (int(c.time[i]) in btlist or c.maxstep > 24):
179
180                    if ty not in self.types.keys():
181                        self.types[ty] = {'times': '', 'steps': ''}
182
183                    if ti not in self.types[ty]['times']:
184                        if self.types[ty]['times']:
185                            self.types[ty]['times'] += '/'
186                        self.types[ty]['times'] += ti
187
188                    if st not in self.types[ty]['steps']:
189                        if self.types[ty]['steps']:
190                            self.types[ty]['steps'] += '/'
191                        self.types[ty]['steps'] += st
192                i += 1
193
194        self.marsclass = c.marsclass
195        self.stream = c.stream
196        self.number = c.number
197        self.resol = c.resol
198        self.accuracy = c.accuracy
199        self.level = c.level
200        self.expver = c.expver
201        self.levelist = c.levelist
202        # for gaussian grid retrieval
203        self.glevelist = '1/to/' + c.level
204        self.gaussian = c.gaussian
205
206        if 'N' in c.grid:  # Gaussian output grid
207            self.grid = c.grid
208            self.area = 'G'
209        else:
210            self.grid = '{}/{}'.format(int(c.grid) / 1000., int(c.grid) / 1000.)
211            self.area = '{}/{}/{}/{}'.format(int(c.upper) / 1000.,
212                                             int(c.left) / 1000.,
213                                             int(c.lower) / 1000.,
214                                             int(c.right) / 1000.)
215
216        self.outputfilelist = []
217
218
219        # Now comes the nasty part that deals with the different
220        # scenarios we have:
221        # 1) Calculation of etadot on
222        #    a) Gaussian grid
223        #    b) Output grid
224        #    c) Output grid using parameter 77 retrieved from MARS
225        # 3) Calculation/Retrieval of omega
226        # 4) Download also data for WRF
227
228        # Different grids need different retrievals
229        # SH = Spherical Harmonics, GG = Gaussian Grid,
230        # OG = Output Grid, ML = MultiLevel, SL = SingleLevel
231        self.params = {'SH__ML': '', 'SH__SL': '',
232                       'GG__ML': '', 'GG__SL': '',
233                       'OG__ML': '', 'OG__SL': '',
234                       'OG_OROLSM_SL': '', 'OG_acc_SL': ''}
235        # the self.params dictionary stores a list of
236        # [param, levtype, levelist, grid] per key
237
238        if fluxes is False:
239            self.params['SH__SL'] = ['LNSP', 'ML', '1', 'OFF']
240            #                        "SD/MSL/TCC/10U/10V/2T/2D/129/172"
241            self.params['OG__SL'] = ["141/151/164/165/166/167/168/129/172", \
242                                     'SFC', '1', self.grid]
243            if c.addpar:
244                if c.addpar[0] == '/':
245                    c.addpar = c.addpar[1:]
246                self.params['OG__SL'][0] += '/' + '/'.join(c.addpar)
247
248            if c.marsclass.upper() == 'EA' or c.marsclass.upper() == 'EP':
249                self.params['OG_OROLSM__SL'] = ["160/27/28/244",
250                                                'SFC', '1', self.grid]
251            else:
252                self.params['OG_OROLSM__SL'] = ["160/27/28/173", \
253                                                'SFC', '1', self.grid]
254
255            self.params['OG__ML'] = ['T/Q', 'ML', self.levelist, self.grid]
256
257            #if c.gauss == '0' and c.eta == '1':
258            if not c.gauss and c.eta:
259                # the simplest case
260                self.params['OG__ML'][0] += '/U/V/77'
261            #elif c.gauss == '0' and c.eta == '0':
262            elif not c.gauss and not c.eta:
263            # this is not recommended (inaccurate)
264                self.params['OG__ML'][0] += '/U/V'
265            #elif c.gauss == '1' and c.eta == '0':
266            elif c.gauss and not c.eta:
267                # this is needed for data before 2008, or for reanalysis data
268                self.params['GG__SL'] = ['Q', 'ML', '1', \
269                                         '{}'.format((int(self.resol) + 1) / 2)]
270                self.params['SH__ML'] = ['U/V/D', 'ML', self.glevelist, 'OFF']
271            else:
272                print('Warning: This is a very costly parameter combination, \
273                      use only for debugging!')
274                self.params['GG__SL'] = ['Q', 'ML', '1', \
275                                         '{}'.format((int(self.resol) + 1) / 2)]
276                self.params['GG__ML'] = ['U/V/D/77', 'ML', self.glevelist, \
277                                         '{}'.format((int(self.resol) + 1) / 2)]
278
279            if c.omega:
280                self.params['OG__ML'][0] += '/W'
281
282            # add cloud water content if necessary
283            if c.cwc:
284                self.params['OG__ML'][0] += '/CLWC/CIWC'
285
286            # add vorticity and geopotential height for WRF if necessary
287            if c.wrf:
288                self.params['OG__ML'][0] += '/Z/VO'
289                if '/D' not in self.params['OG__ML'][0]:
290                    self.params['OG__ML'][0] += '/D'
291                #wrf_sfc = 'sp/msl/skt/2t/10u/10v/2d/z/lsm/sst/ci/sd/stl1/ /
292                #           stl2/stl3/stl4/swvl1/swvl2/swvl3/swvl4'.upper()
293                wrf_sfc = '134/235/167/165/166/168/129/172/34/31/141/ \
294                           139/170/183/236/39/40/41/42'
295                lwrt_sfc = wrf_sfc.split('/')
296                for par in lwrt_sfc:
297                    if par not in self.params['OG__SL'][0]:
298                        self.params['OG__SL'][0] += '/' + par
299
300        else:
301            self.params['OG_acc_SL'] = ["LSP/CP/SSHF/EWSS/NSSS/SSR", \
302                                        'SFC', '1', self.grid]
303
304        return
305
306
307    def _mk_targetname(self, ftype, param, date):
308        '''
309        @Description:
310            Creates the filename for the requested grib data to be stored in.
311            This name is passed as the "target" parameter in the request.
312
313        @Input:
314            ftype: string
315                Shortcut name of the type of the field. E.g. AN, FC, PF, ...
316
317            param: string
318                Shortcut of the grid type. E.g. SH__ML, SH__SL, GG__ML,
319                GG__SL, OG__ML, OG__SL, OG_OROLSM_SL, OG_acc_SL
320
321            date: string
322                The date period of the grib data to be stored in this file.
323
324        @Return:
325            targetname: string
326                The target filename for the grib data.
327        '''
328        targetname = (self.inputdir + '/' + ftype + param + '.' + date + '.' +
329                      str(os.getppid()) + '.' + str(os.getpid()) + '.grb')
330
331        return targetname
332
333
334    def _start_retrievement(self, request, par_dict):
335        '''
336        @Description:
337            Creates the Mars Retrieval and prints or submits the request
338            depending on the status of the request variable.
339
340        @Input:
341            self: instance of EcFlexpart
342                The current object of the class.
343
344            request: integer
345                Selects the mode of retrieval.
346                0: Retrieves the data from ECMWF.
347                1: Prints the mars requests to an output file.
348                2: Retrieves the data and prints the mars request.
349
350            par_dict: dictionary
351                Contains all parameter which have to be set for creating the
352                Mars Retrievals. The parameter are:
353                marsclass, dataset, stream, type, levtype, levelist, resol,
354                gaussian, accuracy, grid, target, area, date, time, number,
355                step, expver, param
356
357        @Return:
358            <nothing>
359        '''
360        # increase number of mars requests
361        self.mreq_count += 1
362
363        MR = MarsRetrieval(self.server,
364                           self.public,
365                           marsclass=par_dict['marsclass'],
366                           dataset=par_dict['dataset'],
367                           stream=par_dict['stream'],
368                           type=par_dict['type'],
369                           levtype=par_dict['levtype'],
370                           levelist=par_dict['levelist'],
371                           resol=par_dict['resol'],
372                           gaussian=par_dict['gaussian'],
373                           accuracy=par_dict['accuracy'],
374                           grid=par_dict['grid'],
375                           target=par_dict['target'],
376                           area=par_dict['area'],
377                           date=par_dict['date'],
378                           time=par_dict['time'],
379                           number=par_dict['number'],
380                           step=par_dict['step'],
381                           expver=par_dict['expver'],
382                           param=par_dict['param'])
383
384        if request == 0:
385            MR.display_info()
386            MR.data_retrieve()
387        elif request == 1:
388            MR.print_infodata_csv(self.inputdir, self.mreq_count)
389        elif request == 2:
390            MR.print_infodata_csv(self.inputdir, self.mreq_count)
391            MR.display_info()
392            MR.data_retrieve()
393        else:
394            print('Failure')
395
396        return
397
398
399    def _mk_index_values(self, inputdir, inputfiles, keys):
400        '''
401        @Description:
402            Creates an index file for a set of grib parameter keys.
403            The values from the index keys are returned in a list.
404
405        @Input:
406            keys: dictionary
407                List of parameter names which serves as index.
408
409            inputfiles: instance of UioFiles
410                Contains a list of files.
411
412        @Return:
413            iid: grib_index
414                This is a grib specific index structure to access
415                messages in a file.
416
417            index_vals: list
418                Contains the values from the keys used for a distinct selection
419                of grib messages in processing  the grib files.
420                Content looks like e.g.:
421                index_vals[0]: ('20171106', '20171107', '20171108') ; date
422                index_vals[1]: ('0', '1200', '1800', '600') ; time
423                index_vals[2]: ('0', '12', '3', '6', '9') ; stepRange
424        '''
425        iid = None
426        index_keys = keys
427
428        indexfile = os.path.join(inputdir, _config.FILE_GRIB_INDEX)
429        silent_remove(indexfile)
430        grib = GribTools(inputfiles.files)
431        # creates new index file
432        iid = grib.index(index_keys=index_keys, index_file=indexfile)
433
434        # read the values of index keys
435        index_vals = []
436        for key in index_keys:
437            #index_vals.append(grib_index_get(iid, key))
438            #print(index_vals[-1])
439            key_vals = grib_index_get(iid, key)
440            print(key_vals)
441            # have to sort the steps for disaggregation,
442            # therefore convert to int first
443            if key == 'step':
444                key_vals = [int(k) for k in key_vals]
445                key_vals.sort()
446                key_vals = [str(k) for k in key_vals]
447            index_vals.append(key_vals)
448            # index_vals looks for example like:
449            # index_vals[0]: ('20171106', '20171107', '20171108') ; date
450            # index_vals[1]: ('0', '1200') ; time
451            # index_vals[2]: (3', '6', '9', '12') ; stepRange
452
453        return iid, index_vals
454
455
456    def retrieve(self, server, dates, public, request, inputdir='.'):
457        '''
458        @Description:
459            Finalizing the retrieval information by setting final details
460            depending on grid type.
461            Prepares MARS retrievals per grid type and submits them.
462
463        @Input:
464            self: instance of EcFlexpart
465                The current object of the class.
466
467            server: instance of ECMWFService or ECMWFDataServer
468                The connection to the ECMWF server. This is different
469                for member state users which have full access and non
470                member state users which have only access to the public
471                data sets. The decision is made from command line argument
472                "public"; for public access its True (ECMWFDataServer)
473                for member state users its False (ECMWFService)
474
475            dates: string
476                Contains start and end date of the retrieval in the format
477                "YYYYMMDD/to/YYYYMMDD"
478
479            request: integer
480                Selects the mode of retrieval.
481                0: Retrieves the data from ECMWF.
482                1: Prints the mars requests to an output file.
483                2: Retrieves the data and prints the mars request.
484
485            inputdir: string, optional
486                Path to the directory where the retrieved data is about
487                to be stored. The default is the current directory ('.').
488
489        @Return:
490            <nothing>
491        '''
492        self.dates = dates
493        self.server = server
494        self.public = public
495        self.inputdir = inputdir
496        oro = False
497
498        # define times with datetime module
499        t12h = timedelta(hours=12)
500        t24h = timedelta(hours=24)
501
502        # dictionary which contains all parameter for the mars request,
503        # entries with a "None" will change in different requests and will
504        # therefore be set in each request seperately
505        retr_param_dict = {'marsclass':self.marsclass,
506                           'dataset':self.dataset,
507                           'stream':None,
508                           'type':None,
509                           'levtype':None,
510                           'levelist':None,
511                           'resol':self.resol,
512                           'gaussian':None,
513                           'accuracy':self.accuracy,
514                           'grid':None,
515                           'target':None,
516                           'area':None,
517                           'date':None,
518                           'time':None,
519                           'number':self.number,
520                           'step':None,
521                           'expver':self.expver,
522                           'param':None}
523
524        for ftype in self.types:
525            # fk contains field types such as
526            #     [AN, FC, PF, CV]
527            # fv contains all of the items of the belonging key
528            #     [times, steps]
529            for pk, pv in self.params.iteritems():
530                # pk contains one of these keys of params
531                #     [SH__ML, SH__SL, GG__ML, GG__SL, OG__ML, OG__SL,
532                #      OG_OROLSM_SL, OG_acc_SL]
533                # pv contains all of the items of the belonging key
534                #     [param, levtype, levelist, grid]
535                if isinstance(pv, str):
536                    continue
537                retr_param_dict['type'] = ftype
538                retr_param_dict['time'] = self.types[ftype]['times']
539                retr_param_dict['step'] = self.types[ftype]['steps']
540                retr_param_dict['date'] = self.dates
541                retr_param_dict['stream'] = self.stream
542                retr_param_dict['target'] = \
543                    self._mk_targetname(ftype,
544                                        pk,
545                                        retr_param_dict['date'].split('/')[0])
546                retr_param_dict['param'] = pv[0]
547                retr_param_dict['levtype'] = pv[1]
548                retr_param_dict['levelist'] = pv[2]
549                retr_param_dict['grid'] = pv[3]
550                retr_param_dict['area'] = self.area
551                retr_param_dict['gaussian'] = self.gaussian
552
553                if pk == 'OG__SL':
554                    pass
555                if pk == 'OG_OROLSM__SL' and not oro:
556                    oro = True
557                    # in CERA20C (class EP) there is no stream "OPER"!
558                    if self.marsclass.upper() != 'EP':
559                        retr_param_dict['stream'] = 'OPER'
560                    retr_param_dict['type'] = 'AN'
561                    retr_param_dict['time'] = '00'
562                    retr_param_dict['step'] = '000'
563                    retr_param_dict['date'] = self.dates.split('/')[0]
564                    retr_param_dict['target'] = self._mk_targetname('',
565                                            pk, retr_param_dict['date'])
566                elif pk == 'OG_OROLSM__SL' and oro:
567                    continue
568                if pk == 'GG__SL' and pv[0] == 'Q':
569                    retr_param_dict['area'] = ""
570                    retr_param_dict['gaussian'] = 'reduced'
571
572    # ------  on demand path  --------------------------------------------------
573                if not self.basetime:
574                    # ******* start retrievement
575                    self._start_retrievement(request, retr_param_dict)
576    # ------  operational path  ------------------------------------------------
577                else:
578                    # check if mars job requests fields beyond basetime.
579                    # if yes eliminate those fields since they may not
580                    # be accessible with user's credentials
581
582                    enddate = retr_param_dict['date'].split('/')[-1]
583                    elimit = datetime.strptime(enddate + self.basetime,
584                                               '%Y%m%d%H')
585
586                    if self.basetime == '12':
587                        # --------------  flux data ----------------------------
588                        if 'acc' in pk:
589
590                        # Strategy:
591                        # if maxtime-elimit >= 24h reduce date by 1,
592                        # if 12h <= maxtime-elimit<12h reduce time for last date
593                        # if maxtime-elimit<12h reduce step for last time
594                        # A split of the MARS job into 2 is likely necessary.
595
596
597                            startdate = retr_param_dict['date'].split('/')[0]
598                            enddate = datetime.strftime(elimit - t24h,'%Y%m%d')
599                            retr_param_dict['date'] = '/'.join([startdate,
600                                                                'to',
601                                                                enddate])
602
603                            # ******* start retrievement
604                            self._start_retrievement(request, retr_param_dict)
605
606                            retr_param_dict['date'] = \
607                                datetime.strftime(elimit - t12h, '%Y%m%d')
608                            retr_param_dict['time'] = '00'
609                            retr_param_dict['target'] = \
610                                self._mk_targetname(ftype, pk,
611                                                    retr_param_dict['date'])
612
613                            # ******* start retrievement
614                            self._start_retrievement(request, retr_param_dict)
615
616                        # --------------  non flux data ------------------------
617                        else:
618                            # ******* start retrievement
619                            self._start_retrievement(request, retr_param_dict)
620
621                    else: # basetime = 0
622                        retr_param_dict['date'] = \
623                            datetime.strftime(elimit - t24h, '%Y%m%d')
624
625                        timesave = ''.join(retr_param_dict['time'])
626
627                        if '/' in retr_param_dict['time']:
628                            times = retr_param_dict['time'].split('/')
629                            steps = retr_param_dict['step'].split('/')
630                            while (pk != 'OG_OROLSM__SL' and
631                                   'acc' not in pk and
632                                   (int(times[0]) + int(steps[0])) <= 12):
633                                times = times[1:]
634
635                            if len(times) > 1:
636                                retr_param_dict['time'] = '/'.join(times)
637                            else:
638                                retr_param_dict['time'] = times[0]
639
640                        # ******* start retrievement
641                        self._start_retrievement(request, retr_param_dict)
642
643                        if (pk != 'OG_OROLSM__SL' and
644                            int(retr_param_dict['step'].split('/')[0]) == 0 and
645                            int(timesave.split('/')[0]) == 0):
646
647                            retr_param_dict['date'] = \
648                                datetime.strftime(elimit, '%Y%m%d')
649                            retr_param_dict['time'] = '00'
650                            retr_param_dict['step'] = '000'
651                            retr_param_dict['target'] = \
652                                self._mk_targetname(ftype, pk,
653                                                    retr_param_dict['date'])
654
655                            # ******* start retrievement
656                            self._start_retrievement(request, retr_param_dict)
657
658        if request == 0 or request == 2:
659            print('MARS retrieve done ... ')
660        elif request == 1:
661            print('MARS request printed ...')
662
663        return
664
665
666    def write_namelist(self, c):
667        '''
668        @Description:
669            Creates a namelist file in the temporary directory and writes
670            the following values to it: maxl, maxb, mlevel,
671            mlevelist, mnauf, metapar, rlo0, rlo1, rla0, rla1,
672            momega, momegadiff, mgauss, msmooth, meta, metadiff, mdpdeta
673
674        @Input:
675            self: instance of EcFlexpart
676                The current object of the class.
677
678            c: instance of class ControlFile
679                Contains all the parameters of CONTROL file and
680                command line.
681                For more information about format and content of the parameter
682                see documentation.
683
684            filename: string
685                Name of the namelist file.
686
687        @Return:
688            <nothing>
689        '''
690
691        from genshi.template.text import NewTextTemplate
692        from genshi.template import  TemplateLoader
693
694        loader = TemplateLoader(_config.PATH_TEMPLATES, auto_reload=False)
695        namelist_template = loader.load(_config.TEMPFILE_NAMELIST,
696                                       cls=NewTextTemplate)
697
698        self.inputdir = c.inputdir
699        area = np.asarray(self.area.split('/')).astype(float)
700        grid = np.asarray(self.grid.split('/')).astype(float)
701
702        if area[1] > area[3]:
703            area[1] -= 360
704        maxl = int((area[3] - area[1]) / grid[1]) + 1
705        maxb = int((area[0] - area[2]) / grid[0]) + 1
706
707        stream = namelist_template.generate(
708            maxl = str(maxl),
709            maxb = str(maxb),
710            mlevel = str(self.level),
711            mlevelist = str(self.levelist),
712            mnauf = str(self.resol),
713            metapar = '77',
714            rlo0 = str(area[1]),
715            rlo1 = str(area[3]),
716            rla0 = str(area[2]),
717            rla1 = str(area[0]),
718            momega = str(c.omega),
719            momegadiff = str(c.omegadiff),
720            mgauss = str(c.gauss),
721            msmooth = str(c.smooth),
722            meta = str(c.eta),
723            metadiff = str(c.etadiff),
724            mdpdeta = str(c.dpdeta)
725        )
726
727        namelistfile = os.path.join(self.inputdir, _config.FILE_NAMELIST)
728
729        with open(namelistfile, 'w') as f:
730            f.write(stream.render('text'))
731
732        return
733
734
735    def deacc_fluxes(self, inputfiles, c):
736        '''
737        @Description:
738            Goes through all flux fields in ordered time and de-accumulate
739            the fields. Afterwards the fields are disaggregated in time.
740            Different versions of disaggregation is provided for rainfall
741            data (darain, modified linear) and the surface fluxes and
742            stress data (dapoly, cubic polynomial).
743
744        @Input:
745            self: instance of EcFlexpart
746                The current object of the class.
747
748            inputfiles: instance of UioFiles
749                Contains a list of files.
750
751            c: instance of class ControlFile
752                Contains all the parameters of CONTROL file and
753                command line.
754                For more information about format and content of the parameter
755                see documentation.
756
757        @Return:
758            <nothing>
759        '''
760
761        table128 = init128(_config.PATH_GRIBTABLE)
762        pars = to_param_id(self.params['OG_acc_SL'][0], table128)
763
764        iid = None
765        index_vals = None
766
767        # get the values of the keys which are used for distinct access
768        # of grib messages via product
769        index_keys = ["date", "time", "step"]
770        iid, index_vals = self._mk_index_values(c.inputdir,
771                                                inputfiles,
772                                                index_keys)
773        # index_vals looks like e.g.:
774        # index_vals[0]: ('20171106', '20171107', '20171108') ; date
775        # index_vals[1]: ('0', '1200', '1800', '600') ; time
776        # index_vals[2]: ('0', '12', '3', '6', '9') ; stepRange
777
778        valsdict = {}
779        svalsdict = {}
780#        stepsdict = {}
781        for p in pars:
782            valsdict[str(p)] = []
783            svalsdict[str(p)] = []
784#            stepsdict[str(p)] = []
785
786        print('maxstep: ', c.maxstep)
787
788        # "product" genereates each possible combination between the
789        # values of the index keys
790        for prod in product(*index_vals):
791            # e.g. prod = ('20170505', '0', '12')
792            #             (  date    ,time, step)
793
794            print('current product: ', prod)
795
796            for i in range(len(index_keys)):
797                grib_index_select(iid, index_keys[i], prod[i])
798
799            # get first id from current product
800            gid = grib_new_from_index(iid)
801
802            # if there is no data for this specific time combination / product
803            # skip the rest of the for loop and start with next timestep/product
804            if not gid:
805                continue
806
807            # create correct timestamp from the three time informations
808            cdate = str(grib_get(gid, 'date'))
809            ctime = '{:0>2}'.format(grib_get(gid, 'time')/100)
810            cstep = '{:0>3}'.format(grib_get(gid, 'step'))
811            t_date = datetime.strptime(cdate + ctime, '%Y%m%d%H')
812            t_dt = t_date + timedelta(hours=int(cstep))
813            t_m1dt = t_date + timedelta(hours=int(cstep)-int(c.dtime))
814            t_m2dt = t_date + timedelta(hours=int(cstep)-2*int(c.dtime))
815            t_enddate = None
816
817            if c.maxstep > 12:
818                fnout = os.path.join(c.inputdir, 'flux' +
819                                     t_date.strftime('%Y%m%d.%H') +
820                                     '.{:0>3}'.format(step-2*int(c.dtime)))
821                gnout = os.path.join(c.inputdir, 'flux' +
822                                     t_date.strftime('%Y%m%d.%H') +
823                                     '.{:0>3}'.format(step-int(c.dtime)))
824                hnout = os.path.join(c.inputdir, 'flux' +
825                                     t_date.strftime('%Y%m%d.%H') +
826                                     '.{:0>3}'.format(step))
827            else:
828                fnout = os.path.join(c.inputdir, 'flux' +
829                                     t_m2dt.strftime('%Y%m%d%H'))
830                gnout = os.path.join(c.inputdir, 'flux' +
831                                     t_m1dt.strftime('%Y%m%d%H'))
832                hnout = os.path.join(c.inputdir, 'flux' +
833                                     t_dt.strftime('%Y%m%d%H'))
834
835            print("outputfile = " + fnout)
836
837            # read message for message and store relevant data fields
838            # data keywords are stored in pars
839            while 1:
840                if not gid:
841                    break
842                cparamId = str(grib_get(gid, 'paramId'))
843                step = grib_get(gid, 'step')
844                time = grib_get(gid, 'time')
845                ni = grib_get(gid, 'Ni')
846                nj = grib_get(gid, 'Nj')
847                if cparamId in valsdict.keys():
848                    values = grib_get_values(gid)
849                    vdp = valsdict[cparamId]
850                    svdp = svalsdict[cparamId]
851 #                   sd = stepsdict[cparamId]
852
853                    if cparamId == '142' or cparamId == '143':
854                        fak = 1. / 1000.
855                    else:
856                        fak = 3600.
857
858                    values = (np.reshape(values, (nj, ni))).flatten() / fak
859                    vdp.append(values[:])  # save the accumulated values
860                    if c.marsclass.upper() == 'EA' or \
861                       step <= int(c.dtime):
862                        svdp.append(values[:] / int(c.dtime))
863                    else:  # deaccumulate values
864                        svdp.append((vdp[-1] - vdp[-2]) / int(c.dtime))
865
866                    print(cparamId, time, step, len(values),
867                          values[0], np.std(values))
868
869                    # len(svdp) correspond to the time
870                    if len(svdp) >= 3:
871                        if len(svdp) > 3:
872                            if cparamId == '142' or cparamId == '143':
873                                values = disaggregation.darain(svdp)
874                            else:
875                                values = disaggregation.dapoly(svdp)
876
877                            if not (step == c.maxstep and c.maxstep > 12 \
878                                    or t_dt == t_enddate):
879                                vdp.pop(0)
880                                svdp.pop(0)
881                        else:
882                            if c.maxstep > 12:
883                                values = svdp[1]
884                            else:
885                                values = svdp[0]
886
887                        grib_set_values(gid, values)
888
889                        if c.maxstep > 12:
890                            grib_set(gid, 'step', max(0, step-2*int(c.dtime)))
891                        else:
892                            grib_set(gid, 'step', 0)
893                            grib_set(gid, 'time', t_m2dt.hour*100)
894                            grib_set(gid, 'date', int(t_m2dt.strftime('%Y%m%d')))
895
896                        with open(fnout, 'w') as f_handle:
897                            grib_write(gid, f_handle)
898
899                        if c.basetime:
900                            t_enddate = datetime.strptime(c.end_date +
901                                                          c.basetime,
902                                                          '%Y%m%d%H')
903                        else:
904                            t_enddate = t_date + timedelta(2*int(c.dtime))
905
906                        # squeeze out information of last two steps contained
907                        # in svdp
908                        # if step+int(c.dtime) == c.maxstep and c.maxstep>12
909                        # or t_dt+timedelta(hours = int(c.dtime))
910                        # >= t_enddate:
911                        # Note that svdp[0] has not been popped in this case
912
913                        if step == c.maxstep and c.maxstep > 12 or \
914                           t_dt == t_enddate:
915
916                            values = svdp[3]
917                            grib_set_values(gid, values)
918                            grib_set(gid, 'step', 0)
919                            truedatetime = t_m2dt + timedelta(hours=
920                                                              2*int(c.dtime))
921                            grib_set(gid, 'time', truedatetime.hour * 100)
922                            grib_set(gid, 'date', truedatetime.year * 10000 +
923                                      truedatetime.month * 100 +
924                                      truedatetime.day)
925                            with open(hnout, 'w') as h_handle:
926                                grib_write(gid, h_handle)
927
928                            #values = (svdp[1]+svdp[2])/2.
929                            if cparamId == '142' or cparamId == '143':
930                                values = disaggregation.darain(list(reversed(svdp)))
931                            else:
932                                values = disaggregation.dapoly(list(reversed(svdp)))
933
934                            grib_set(gid, 'step', 0)
935                            truedatetime = t_m2dt + timedelta(hours=int(c.dtime))
936                            grib_set(gid, 'time', truedatetime.hour * 100)
937                            grib_set(gid, 'date', truedatetime.year * 10000 +
938                                     truedatetime.month * 100 +
939                                     truedatetime.day)
940                            grib_set_values(gid, values)
941                            with open(gnout, 'w') as g_handle:
942                                grib_write(gid, g_handle)
943
944                grib_release(gid)
945
946                gid = grib_new_from_index(iid)
947
948        grib_index_release(iid)
949
950        return
951
952
953    def create(self, inputfiles, c):
954        '''
955        @Description:
956            This method is based on the ECMWF example index.py
957            https://software.ecmwf.int/wiki/display/GRIB/index.py
958
959            An index file will be created which depends on the combination
960            of "date", "time" and "stepRange" values. This is used to iterate
961            over all messages in each grib file which were passed through the
962            parameter "inputfiles" to seperate specific parameters into fort.*
963            files. Afterwards the FORTRAN program is called to convert
964            the data fields all to the same grid and put them in one file
965            per unique time step (combination of "date", "time" and
966            "stepRange").
967
968        @Input:
969            self: instance of EcFlexpart
970                The current object of the class.
971
972            inputfiles: instance of UioFiles
973                Contains a list of files.
974
975            c: instance of class ControlFile
976                Contains all the parameters of CONTROL file and
977                command line.
978                For more information about format and content of the parameter
979                see documentation.
980
981        @Return:
982            <nothing>
983        '''
984
985        if c.wrf:
986            table128 = init128(_config.PATH_GRIBTABLE)
987            wrfpars = to_param_id('sp/mslp/skt/2t/10u/10v/2d/z/lsm/sst/ci/sd/\
988                                   stl1/stl2/stl3/stl4/swvl1/swvl2/swvl3/swvl4',
989                                  table128)
990
991        # these numbers are indices for the temporary files "fort.xx"
992        # which are used to seperate the grib fields to,
993        # for the Fortran program input
994        # 10: U,V | 11: T | 12: lnsp | 13: D | 16: sfc fields
995        # 17: Q | 18: Q , gaussian| 19: w | 21: etadot | 22: clwc+ciwc
996        fdict = {'10':None, '11':None, '12':None, '13':None, '16':None,
997                 '17':None, '18':None, '19':None, '21':None, '22':None}
998
999        iid = None
1000        index_vals = None
1001
1002        # get the values of the keys which are used for distinct access
1003        # of grib messages via product
1004        index_keys = ["date", "time", "step"]
1005        iid, index_vals = self._mk_index_values(c.inputdir,
1006                                                inputfiles,
1007                                                index_keys)
1008        # index_vals looks like e.g.:
1009        # index_vals[0]: ('20171106', '20171107', '20171108') ; date
1010        # index_vals[1]: ('0', '1200', '1800', '600') ; time
1011        # index_vals[2]: ('0', '12', '3', '6', '9') ; stepRange
1012
1013        # "product" genereates each possible combination between the
1014        # values of the index keys
1015        for prod in product(*index_vals):
1016            # e.g. prod = ('20170505', '0', '12')
1017            #             (  date    ,time, step)
1018
1019            print('current product: ', prod)
1020
1021            for i in range(len(index_keys)):
1022                grib_index_select(iid, index_keys[i], prod[i])
1023
1024            # get first id from current product
1025            gid = grib_new_from_index(iid)
1026
1027            # if there is no data for this specific time combination / product
1028            # skip the rest of the for loop and start with next timestep/product
1029            if not gid:
1030                continue
1031
1032            # remove old fort.* files and open new ones
1033            # they are just valid for a single product
1034            for k, f in fdict.iteritems():
1035                fortfile = os.path.join(c.inputdir, 'fort.' + k)
1036                silent_remove(fortfile)
1037                fdict[k] = open(fortfile, 'w')
1038
1039            # create correct timestamp from the three time informations
1040            cdate = str(grib_get(gid, 'date'))
1041            ctime = '{:0>2}'.format(grib_get(gid, 'time')/100)
1042            cstep = '{:0>3}'.format(grib_get(gid, 'step'))
1043            timestamp = datetime.strptime(cdate + ctime, '%Y%m%d%H')
1044            timestamp += timedelta(hours=int(cstep))
1045            cdate_hour = datetime.strftime(timestamp, '%Y%m%d%H')
1046
1047            # if the timestamp is out of basetime start/end date period,
1048            # skip this specific product
1049            if c.basetime:
1050                start_time = datetime.strptime(c.end_date + c.basetime,
1051                                                '%Y%m%d%H') - time_delta
1052                end_time = datetime.strptime(c.end_date + c.basetime,
1053                                             '%Y%m%d%H')
1054                if timestamp < start_time or timestamp > end_time:
1055                    continue
1056
1057            if c.wrf:
1058                if 'olddate' not in locals() or cdate != olddate:
1059                    fwrf = open(os.path.join(c.outputdir,
1060                                'WRF' + cdate + '.' + ctime + '.000.grb2'), 'w')
1061                    olddate = cdate[:]
1062
1063            # savedfields remembers which fields were already used.
1064            savedfields = []
1065            # sum of cloud liquid and ice water content
1066            scwc = None
1067            while 1:
1068                if not gid:
1069                    break
1070                paramId = grib_get(gid, 'paramId')
1071                gridtype = grib_get(gid, 'gridType')
1072                levtype = grib_get(gid, 'typeOfLevel')
1073                if paramId == 77: # ETADOT
1074                    grib_write(gid, fdict['21'])
1075                elif paramId == 130: # T
1076                    grib_write(gid, fdict['11'])
1077                elif paramId == 131 or paramId == 132: # U, V wind component
1078                    grib_write(gid, fdict['10'])
1079                elif paramId == 133 and gridtype != 'reduced_gg': # Q
1080                    grib_write(gid, fdict['17'])
1081                elif paramId == 133 and gridtype == 'reduced_gg': # Q, gaussian
1082                    grib_write(gid, fdict['18'])
1083                elif paramId == 135: # W
1084                    grib_write(gid, fdict['19'])
1085                elif paramId == 152: # LNSP
1086                    grib_write(gid, fdict['12'])
1087                elif paramId == 155 and gridtype == 'sh': # D
1088                    grib_write(gid, fdict['13'])
1089                elif paramId == 246 or paramId == 247: # CLWC, CIWC
1090                    # sum cloud liquid water and ice
1091                    if scwc is None:
1092                        scwc = grib_get_values(gid)
1093                    else:
1094                        scwc += grib_get_values(gid)
1095                        grib_set_values(gid, scwc)
1096                        grib_set(gid, 'paramId', 201031)
1097                        grib_write(gid, fdict['22'])
1098                elif c.wrf and paramId in [129, 138, 155] and \
1099                      levtype == 'hybrid': # Z, VO, D
1100                    # do not do anything right now
1101                    # these are specific parameter for WRF
1102                    pass
1103                else:
1104                    if paramId not in savedfields:
1105                        # SD/MSL/TCC/10U/10V/2T/2D/Z/LSM/SDOR/CVL/CVH/SR
1106                        # and all ADDPAR parameter
1107                        grib_write(gid, fdict['16'])
1108                        savedfields.append(paramId)
1109                    else:
1110                        print('duplicate ' + str(paramId) + ' not written')
1111
1112                try:
1113                    if c.wrf:
1114                        # model layer
1115                        if levtype == 'hybrid' and \
1116                           paramId in [129, 130, 131, 132, 133, 138, 155]:
1117                            grib_write(gid, fwrf)
1118                        # sfc layer
1119                        elif paramId in wrfpars:
1120                            grib_write(gid, fwrf)
1121                except AttributeError:
1122                    pass
1123
1124                grib_release(gid)
1125                gid = grib_new_from_index(iid)
1126
1127            for f in fdict.values():
1128                f.close()
1129
1130            # call for Fortran program to convert e.g. reduced_gg grids to
1131            # regular_ll and calculate detadot/dp
1132            pwd = os.getcwd()
1133            os.chdir(c.inputdir)
1134            if os.stat('fort.21').st_size == 0 and c.eta:
1135                print('Parameter 77 (etadot) is missing, most likely it is \
1136                       not available for this type or date/time\n')
1137                print('Check parameters CLASS, TYPE, STREAM, START_DATE\n')
1138                my_error(c.mailfail, 'fort.21 is empty while parameter eta \
1139                         is set to 1 in CONTROL file')
1140
1141            # Fortran program creates file fort.15 (with u,v,etadot,t,sp,q)
1142            p = subprocess.check_call([os.path.join(
1143                c.exedir, _config.FORTRAN_EXECUTABLE)], shell=True)
1144            os.chdir(pwd)
1145
1146            # create name of final output file, e.g. EN13040500 (ENYYMMDDHH)
1147            if c.maxstep > 12:
1148                suffix = cdate[2:8] + '.' + ctime + '.' + cstep
1149            else:
1150                suffix = cdate_hour[2:10]
1151            fnout = os.path.join(c.inputdir, c.prefix + suffix)
1152            print("outputfile = " + fnout)
1153            # collect for final processing
1154            self.outputfilelist.append(os.path.basename(fnout))
1155
1156            # create outputfile and copy all data from intermediate files
1157            # to the outputfile (final GRIB input files for FLEXPART)
1158            orolsm = os.path.basename(glob.glob(c.inputdir +
1159                                        '/OG_OROLSM__SL.*.' + c.ppid + '*')[0])
1160            fluxfile = 'flux' + cdate[0:2] + suffix
1161            if not c.cwc:
1162                flist = ['fort.15', fluxfile, 'fort.16', orolsm]
1163            else:
1164                flist = ['fort.15', 'fort.22', fluxfile, 'fort.16', orolsm]
1165
1166            with open(fnout, 'wb') as fout:
1167                for f in flist:
1168                    shutil.copyfileobj(open(os.path.join(c.inputdir, f), 'rb'),
1169                                       fout)
1170
1171            if c.omega:
1172                with open(os.path.join(c.outputdir, 'OMEGA'), 'wb') as fout:
1173                    shutil.copyfileobj(open(os.path.join(c.inputdir, 'fort.25'),
1174                                            'rb'), fout)
1175
1176        if c.wrf:
1177            fwrf.close()
1178
1179        grib_index_release(iid)
1180
1181        return
1182
1183
1184    def process_output(self, c):
1185        '''
1186        @Description:
1187            The grib files are postprocessed depending on the selection in
1188            CONTROL file. The resulting files are moved to the output
1189            directory if its not equal to the input directory.
1190            The following modifications might be done if
1191            properly switched in CONTROL file:
1192            GRIB2 - Conversion to GRIB2
1193            ECTRANS - Transfer of files to gateway server
1194            ECSTORAGE - Storage at ECMWF server
1195
1196        @Input:
1197            self: instance of EcFlexpart
1198                The current object of the class.
1199
1200            c: instance of class ControlFile
1201                Contains all the parameters of CONTROL file and
1202                command line.
1203                For more information about format and content of the parameter
1204                see documentation.
1205
1206        @Return:
1207            <nothing>
1208
1209        '''
1210
1211        print('\n\nPostprocessing:\n Format: {}\n'.format(c.format))
1212
1213        if not c.ecapi:
1214            print('ecstorage: {}\n ecfsdir: {}\n'.
1215                  format(c.ecstorage, c.ecfsdir))
1216            print('ectrans: {}\n gateway: {}\n destination: {}\n '
1217                  .format(c.ectrans, c.gateway, c.destination))
1218
1219        print('Output filelist: ')
1220        print(self.outputfilelist)
1221
1222        for ofile in self.outputfilelist:
1223            ofile = os.path.join(self.inputdir, ofile)
1224
1225            if c.format.lower() == 'grib2':
1226                p = subprocess.check_call(['grib_set', '-s', 'edition=2, \
1227                                           productDefinitionTemplateNumber=8',
1228                                           ofile, ofile + '_2'])
1229                p = subprocess.check_call(['mv', ofile + '_2', ofile])
1230
1231            if c.ectrans and not c.ecapi:
1232                p = subprocess.check_call(['ectrans', '-overwrite', '-gateway',
1233                                           c.gateway, '-remote', c.destination,
1234                                           '-source', ofile])
1235
1236            if c.ecstorage and not c.ecapi:
1237                p = subprocess.check_call(['ecp', '-o', ofile,
1238                                           os.path.expandvars(c.ecfsdir)])
1239
1240            if c.outputdir != c.inputdir:
1241                p = subprocess.check_call(['mv',
1242                                           os.path.join(c.inputdir, ofile),
1243                                           c.outputdir])
1244
1245        return
1246
1247
1248    def prepare_fp_files(self, c):
1249        '''
1250        @Description:
1251            Conversion of GRIB files to FLEXPART binary format.
1252
1253        @Input:
1254            c: instance of class ControlFile
1255                Contains all the parameters of CONTROL file and
1256                command line.
1257                For more information about format and content of the parameter
1258                see documentation.
1259
1260
1261        @Return:
1262            <nothing>
1263        '''
1264        # generate AVAILABLE file
1265        # Example of AVAILABLE file data:
1266        # 20131107 000000      EN13110700              ON DISC
1267        clist = []
1268        for ofile in self.outputfilelist:
1269            fname = ofile.split('/')
1270            if '.' in fname[-1]:
1271                l = fname[-1].split('.')
1272                timestamp = datetime.strptime(l[0][-6:] + l[1],
1273                                              '%y%m%d%H')
1274                timestamp += timedelta(hours=int(l[2]))
1275                cdate = datetime.strftime(timestamp, '%Y%m%d')
1276                chms = datetime.strftime(timestamp, '%H%M%S')
1277            else:
1278                cdate = '20' + fname[-1][-8:-2]
1279                chms = fname[-1][-2:] + '0000'
1280            clist.append(cdate + ' ' + chms + ' '*6 +
1281                         fname[-1] + ' '*14 + 'ON DISC')
1282        clist.sort()
1283        with open(c.outputdir + '/' + 'AVAILABLE', 'w') as f:
1284            f.write('\n'.join(clist) + '\n')
1285
1286        # generate pathnames file
1287        pwd = os.path.abspath(c.outputdir)
1288        with open(pwd + '/pathnames', 'w') as f:
1289            f.write(pwd + '/Options/\n')
1290            f.write(pwd + '/\n')
1291            f.write(pwd + '/\n')
1292            f.write(pwd + '/AVAILABLE\n')
1293            f.write(' = == = == = == = == = == ==  = \n')
1294
1295        # create Options dir if necessary
1296        if not os.path.exists(pwd + '/Options'):
1297            make_dir(pwd+'/Options')
1298
1299        # read template COMMAND file
1300        with open(os.path.expandvars(os.path.expanduser(
1301            c.flexpart_root_scripts)) + '/../Options/COMMAND', 'r') as f:
1302            lflist = f.read().split('\n')
1303
1304        # find index of list where to put in the
1305        # date and time information
1306        # usually after the LDIRECT parameter
1307        i = 0
1308        for l in lflist:
1309            if 'LDIRECT' in l.upper():
1310                break
1311            i += 1
1312
1313        # insert the date and time information of run start and end
1314        # into the list of lines of COMMAND file
1315        lflist = lflist[:i+1] + \
1316                 [clist[0][:16], clist[-1][:16]] + \
1317                 lflist[i+3:]
1318
1319        # write the new COMMAND file
1320        with open(pwd + '/Options/COMMAND', 'w') as g:
1321            g.write('\n'.join(lflist) + '\n')
1322
1323        # change to outputdir and start the grib2flexpart run
1324        # afterwards switch back to the working dir
1325        os.chdir(c.outputdir)
1326        p = subprocess.check_call([
1327            os.path.expandvars(os.path.expanduser(c.flexpart_root_scripts))
1328            + '/../FLEXPART_PROGRAM/grib2flexpart', 'useAvailable', '.'])
1329        os.chdir(pwd)
1330
1331        return
Note: See TracBrowser for help on using the repository browser.
hosted by ZAMG