source: flex_extract.git/source/python/mods/checks.py @ ae2756e

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

added a check for the number parameter

  • Property mode set to 100644
File size: 25.0 KB
RevLine 
[97f4f4c]1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
[6f951ca]3#*******************************************************************************
[97f4f4c]4# @Author: Anne Philipp (University of Vienna)
5#
6# @Date: November 2018
7#
8# @Change History:
9#
10# @License:
[6f951ca]11#    (C) Copyright 2014-2019.
12#    Anne Philipp, Leopold Haimberger
[97f4f4c]13#
[6f951ca]14#    This work is licensed under the Creative Commons Attribution 4.0
15#    International License. To view a copy of this license, visit
16#    http://creativecommons.org/licenses/by/4.0/ or send a letter to
17#    Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
[97f4f4c]18#*******************************************************************************
[6f951ca]19'''This module contains check methods for the CONTROL paramaters.
20'''
[97f4f4c]21
22# ------------------------------------------------------------------------------
23# MODULES
24# ------------------------------------------------------------------------------
25
[45fc9b4]26import os
[6f951ca]27import sys
[3f36e42]28import _config
[45fc9b4]29import exceptions
30from tools import my_error, silent_remove
31from datetime import datetime
[ae2756e]32import numpy as np
[97f4f4c]33# ------------------------------------------------------------------------------
34# FUNCTIONS
35# ------------------------------------------------------------------------------
36
[45fc9b4]37def check_logicals_type(c, logicals):
38    '''Check that the logical variables have correct type integer.
39
40    Parameters
41    ----------
[6f951ca]42    c : ControlFile
[45fc9b4]43        Contains all the parameters of CONTROL file and
44        command line.
45
[6f951ca]46    logicals : list of (str or int)
[45fc9b4]47        Names of the switches that are used to control the flow of the
48        program.
49
50    Return
51    ------
52
53    '''
54
55    for var in logicals:
56        if not isinstance(getattr(c, var), int):
57            setattr(c, var, int(getattr(c, var)))
58
59    return
[97f4f4c]60
[3f36e42]61def check_grid(grid):
[a55ac71]62    '''Convert grid into correct Lat/Lon format. E.g. '0.5/0.5'
63
64    Checks on format of original grid. Wether it is in the order of 1000 or 1.
65    Convert to correct grid format and substitute into "Lat/Lon" format string.
66
67    Parameters
68    ----------
[6f951ca]69    grid : str
[a55ac71]70        Contains grid information
71
72    Return
73    ------
[6f951ca]74    grid : str
[a55ac71]75        Contains grid in format Lat/lon. E.g. 0.1/0.1
76    '''
[97f4f4c]77
[3f36e42]78    if 'N' in grid:
79        return grid
[97f4f4c]80    if '/' in grid:
81        gridx, gridy = grid.split('/')
82        if gridx == gridy:
83            grid = gridx
84        else:
85            raise ValueError('GRID parameter contains two values '
86                             'which are unequal %s' (grid))
87    # determine grid format
88    if float(grid) / 100. >= 0.5:
89        # grid is defined in 1/1000 degrees; old format
90        grid = '{}/{}'.format(float(grid) / 1000.,
91                              float(grid) / 1000.)
92    elif float(grid) / 100. < 0.5:
93        # grid is defined in normal degree; new format
94        grid = '{}/{}'.format(float(grid), float(grid))
95
[3f36e42]96    return grid
97
98def check_area(grid, area, upper, lower, left , right):
[a55ac71]99    '''Defines the correct area string.
100
101    Checks on the format of the four area components. Wether it is of
102    the order of 1000 or 1. Also checks wether area was already set by command
103    line, then the four components are overwritten.
104    Convert to correct format of the order of magnitude "1" and sets the
105    area parameter (North/West/South/East).
106    E.g.: -5./20./10./10.
[3f36e42]107
[a55ac71]108    Parameters
109    ----------
[6f951ca]110    grid : str
[45fc9b4]111        Contains grid information.
112
[6f951ca]113    area : str
[45fc9b4]114        Contains area informtion.
115
[6f951ca]116    upper : str
[45fc9b4]117        The northern most latitude.
118
[6f951ca]119    lower : str
[45fc9b4]120        The souther most latitude.
121
[6f951ca]122    left : str
[45fc9b4]123        The western most longitude.
124
[6f951ca]125    right : str
[45fc9b4]126        The eastern most longiude.
[3f36e42]127
[a55ac71]128    Return
129    ------
[6f951ca]130    grid : str
[a55ac71]131        Contains grid in format Lat/lon. E.g. 0.1/0.1
[3f36e42]132    '''
133    if 'N' in grid:  # Gaussian output grid
134        area = 'G'
135        return area
136
137    # if area was provided decompose area into its 4 components
138    if area:
139        components = area.split('/')
140        upper, left, lower, right = components
141
[97f4f4c]142    # determine area format
[45fc9b4]143    if ((abs(float(upper) / 10000.) >= 0.01 or float(upper) / 1000. == 0. ) and
144        (abs(float(lower) / 10000.) >= 0.01 or float(lower) / 1000. == 0. ) and
145        (abs(float(left) / 10000.) >= 0.01 or float(left) / 1000. == 0. ) and
146        (abs(float(right) / 10000.) >= 0.01 or float(right) / 1000. == 0.)):
[97f4f4c]147        # area is defined in 1/1000 degrees; old format
148        area = '{}/{}/{}/{}'.format(float(upper) / 1000.,
149                                    float(left) / 1000.,
150                                    float(lower) / 1000.,
151                                    float(right) / 1000.)
[45fc9b4]152    elif (abs(float(upper) / 10000.) < 0.05 and
153          abs(float(lower) / 10000.) < 0.05 and
154          abs(float(left) / 10000.) < 0.05 and
155          abs(float(right) / 10000.) < 0.05):
[97f4f4c]156        # area is already in new format
157        area = '{}/{}/{}/{}'.format(float(upper),
158                                    float(left),
159                                    float(lower),
160                                    float(right))
161    else:
162        raise ValueError('The area components have different '
[d2febd4]163                         'formats (upper, lower, left, right): '
164                         '{}/{}/{}/{}'.format(str(upper), str(lower),
165                                              str(left) , str(right)))
[97f4f4c]166
[3f36e42]167    return area
168
169def check_levels(levelist, level):
[a55ac71]170    '''Defines correct level list and guarantees that the maximum level is
171    one of the available maximum levels.
[3f36e42]172
173    Parameters
174    ----------
[6f951ca]175    levelist : str
[a55ac71]176        Specifies the level list.
177        Examples: model level: 1/to/137, pressure levels: 500/to/1000
178
[6f951ca]179    level : str
[a55ac71]180        Specifies the maximum level.
[3f36e42]181
182    Return
183    ------
[6f951ca]184    levelist : str
[a55ac71]185        Specifies the required levels. It has to have a valid
186        correspondence to the selected levtype.
187        Examples: model level: 1/to/137, pressure levels: 500/to/1000
188
[6f951ca]189    level : str
[a55ac71]190        Specifies the maximum level. It has to be one of the
191        available maximum level number as contained in the variable
192        MAX_LEVEL_LIST in "_config". E.g. [16, 19, 31, 40, 50, 60, 62, 91, 137]
[3f36e42]193
194    '''
195    # assure consistency of levelist and level
196    if not levelist and not level:
197        raise ValueError('ERROR: neither levelist nor level '
198                         'specified in CONTROL file')
199    elif not levelist and level:
200        levelist = '1/to/' + level
201    elif (levelist and not level) or \
202         (levelist[-1] != level[-1]):
203        level = levelist.split('/')[-1]
204    else:
205        pass
206
207    # check if max level is a valid level
208    if int(level) not in _config.MAX_LEVEL_LIST:
209        raise ValueError('ERROR: \n'
210                         'LEVEL must be the maximum level of a specified '
211                         'level list from ECMWF, e.g. {} \n'
212                         'Check parameter "LEVEL" or the max level of '
213                         '"LEVELIST"!'.format(str(_config.MAX_LEVEL_LIST)))
214
215    return levelist, level
216
217
218def check_ppid(c, ppid):
219    '''Sets the current PPID.
220
221    Parameters
222    ----------
[6f951ca]223    c : ControlFile
[3f36e42]224            Contains all the parameters of CONTROL file and
225            command line.
226
[6f951ca]227    ppid : int or None
[3f36e42]228        Contains the ppid number provided by the command line parameter
229        of is None otherwise.
230
231    Return
232    ------
233
234    '''
235
236    if not ppid:
237        c.ppid = str(os.getppid())
238    else:
239        c.ppid = ppid
240
241    return
242
[4d3b052]243
[45fc9b4]244def check_purefc(ftype):
[4d3b052]245    '''Check for a pure forecast mode.
246
247    Parameters
248    ----------
[6f951ca]249    ftype : list of str
[4d3b052]250        List of field types.
251
252    Return
253    ------
254    True or False:
255        True if pure forecasts are to be retrieved. False if there are
256        analysis fields in between.
257    '''
258
[45fc9b4]259    if 'AN' not in ftype and '4V' not in ftype:
[4d3b052]260        # pure forecast
[45fc9b4]261        return 1
262
263    return 0
264
265
266def check_step(step, mailfail):
267    '''Checks on step format and convert into a list of steps.
268
269    If the steps were defined with "to" and "by" they are converted into
270    a list of steps. If the steps were set in a string, it is
271    converted into a list.
272
273    Parameters
274    ----------
[6f951ca]275    step : list of str or str
[45fc9b4]276        Specifies the forecast time step from forecast base time.
277        Valid values are hours (HH) from forecast base time.
278
[6f951ca]279    mailfail : list of str
[45fc9b4]280        Contains all email addresses which should be notified.
281        It might also contain just the ecmwf user name which will trigger
282        mailing to the associated email address for this user.
283
284    Return
285    ------
[6f951ca]286    step : list of str
[45fc9b4]287        List of forecast steps in format e.g. [001, 002, ...]
288    '''
289
290    if '/' in step:
291        steps = step.split('/')
292        if 'to' in step.lower() and 'by' in step.lower():
293            ilist = np.arange(int(steps[0]),
294                              int(steps[2]) + 1,
295                              int(steps[4]))
296            step = ['{:0>3}'.format(i) for i in ilist]
297        elif 'to' in step.lower() and 'by' not in step.lower():
298            my_error(mailfail, step + ':\n' +
299                     'if "to" is used in steps parameter, '
300                     'please use "by" as well')
301        else:
302            step = steps
303
304    if not isinstance(step, list):
305        step = [step]
306
307    return step
308
309def check_type(ftype, steps):
310    '''Check if type variable is of type list and if analysis field has
311    forecast step 0.
312
313    Parameters
314    ----------
[6f951ca]315    ftype : list of str or str
[45fc9b4]316        List of field types.
317
[6f951ca]318    steps : str
[45fc9b4]319        Specifies the forecast time step from forecast base time.
320        Valid values are hours (HH) from forecast base time.
321
322    Return
323    ------
[6f951ca]324    ftype : list of str
[45fc9b4]325        List of field types.
326    '''
327    if not isinstance(ftype, list):
328        ftype = [ftype]
329
330    for i, val in enumerate(ftype):
331        if ftype[i] == 'AN' and int(steps[i]) != 0:
332            print('Analysis retrievals must have STEP = 0 (now set to 0)')
333            ftype[i] = 0
334
335    return ftype
336
337def check_time(ftime):
338    '''Check if time variable is of type list. Otherwise convert to list.
339
340    Parameters
341    ----------
[6f951ca]342    ftime : list of str or str
[45fc9b4]343        The time in hours of the field.
344
345    Return
346    ------
[6f951ca]347    ftime : list of str
[45fc9b4]348        The time in hours of the field.
349    '''
350    if not isinstance(ftime, list):
351        ftime = [ftime]
352
353    return ftime
354
355def check_len_type_time_step(ftype, ftime, steps, maxstep, purefc):
356    '''Check if
357
358    Parameters
359    ----------
[6f951ca]360    ftype : list of str
[45fc9b4]361        List of field types.
362
[6f951ca]363    ftime : list of str or str
[45fc9b4]364        The time in hours of the field.
365
[6f951ca]366    steps : str
[45fc9b4]367        Specifies the forecast time step from forecast base time.
368        Valid values are hours (HH) from forecast base time.
369
[6f951ca]370    maxstep : int
[45fc9b4]371        The maximum forecast time step in hours from the forecast base time.
372        This is the maximum step for non flux (accumulated) forecast data.
373
[6f951ca]374    purefc : int
[45fc9b4]375        Switch for definition of pure forecast mode or not.
376
377    Return
378    ------
[6f951ca]379    ftype : list of str
[45fc9b4]380        List of field types.
381
[6f951ca]382    ftime : list of str
[45fc9b4]383        The time in hours of the field.
384
[6f951ca]385    steps : str
[45fc9b4]386        Specifies the forecast time step from forecast base time.
387        Valid values are hours (HH) from forecast base time.
388    '''
389    if not (len(ftype) == len(ftime) == len(steps)):
390        raise ValueError('ERROR: The number of field types, times and steps '
391                         'are not the same! Please check the setting in the '
392                         'CONTROL file!')
393
394    # if pure forecast is selected and only one field type/time is set
395    # prepare a complete list of type/time/step combination upto maxstep
396    if len(ftype) == 1 and purefc:
397        ftype = []
398        steps = []
399        ftime = []
400        for i in range(0, maxstep + 1):
401            ftype.append(ftype[0])
402            steps.append('{:0>3}'.format(i))
403            ftime.append(ftime[0])
404
405    return ftype, ftime, steps
406
407def check_mail(mail):
408    '''Check the string of mail addresses, seperate them and convert to a list.
409
410    Parameters
411    ----------
[6f951ca]412    mail : list of str or str
[45fc9b4]413        Contains email addresses for notifications.
414        It might also contain just the ecmwf user name which will trigger
415        mailing to the associated email address for this user.
416
417    Return
418    ------
[6f951ca]419    mail : list of str
[45fc9b4]420        Contains email addresses for notifications.
421        It might also contain just the ecmwf user name which will trigger
422        mailing to the associated email address for this user.
423
424    '''
425    if not isinstance(mail, list):
426        if ',' in mail:
427            mail = mail.split(',')
428        elif ' ' in mail:
429            mail = mail.split()
430        else:
431            mail = [mail]
432
433    return mail
434
435def check_queue(queue, gateway, destination, ecuid, ecgid):
436    '''Check if the necessary ECMWF parameters are set if the queue is
437    one of the QUEUES_LIST (in _config).
438
439    Parameters
440    ----------
[6f951ca]441    queue : str
[45fc9b4]442        Name of the queue if submitted to the ECMWF servers.
443        Used to check if ecuid, ecgid, gateway and destination
444        are set correctly and are not empty.
445
[6f951ca]446    gateway : str
[45fc9b4]447        The address of the gateway server.
448
[6f951ca]449    destination : str
[45fc9b4]450        The name of the destination of the gateway server for data
451        transfer through ectrans. E.g. name@genericSftp
452
[6f951ca]453    ecuid : str
[45fc9b4]454        ECMWF user id.
455
[6f951ca]456    ecgid : str
[45fc9b4]457        ECMWF group id.
458
459    Return
460    ------
461
462    '''
463    if queue in _config.QUEUES_LIST and \
464        not gateway or not destination or \
465        not ecuid or not ecgid:
466        raise ValueError('\nEnvironment variables GATEWAY, DESTINATION, ECUID '
467                         'and ECGID were not set properly! \n '
468                         'Please check for existence of file "ECMWF_ENV" '
469                         'in the run directory!')
470    return
471
472def check_pathes(idir, odir, fpdir, fedir):
473    '''Check if output and flexpart pathes are set.
474
475    Parameters
476    ----------
[6f951ca]477    idir : str
[45fc9b4]478        Path to the temporary directory for MARS retrieval data.
479
[6f951ca]480    odir : str
[45fc9b4]481        Path to the final output directory where the FLEXPART input files
482        will be stored.
[4d3b052]483
[6f951ca]484    fpdir : str
[45fc9b4]485        Path to FLEXPART root directory.
[4d3b052]486
[6f951ca]487    fedir : str
[45fc9b4]488        Path to flex_extract root directory.
489
490    Return
491    ------
[6f951ca]492    odir : str
[45fc9b4]493        Path to the final output directory where the FLEXPART input files
494        will be stored.
495
[6f951ca]496    fpdir : str
[45fc9b4]497        Path to FLEXPART root directory.
498
499    '''
500    if not fpdir:
501        fpdir = fedir
502
503    if not odir:
504        odir = idir
505
506    return odir, fpdir
507
508def check_dates(start, end):
509    '''Checks if there is at least a start date for a one day retrieval.
510
511    Checks if end date lies after start date and end date is set.
512
513    Parameters
514    ----------
[6f951ca]515    start : str
[45fc9b4]516        The start date of the retrieval job.
517
[6f951ca]518    end : str
[45fc9b4]519        The end date of the retrieval job.
520
521    Return
522    ------
[6f951ca]523    start : str
[45fc9b4]524        The start date of the retrieval job.
525
[6f951ca]526    end : str
[45fc9b4]527        The end date of the retrieval job.
[4d3b052]528
[3f36e42]529    '''
[45fc9b4]530    # check for having at least a starting date
531    # otherwise program is not allowed to run
532    if not start:
533        raise ValueError('start_date was neither specified in command line nor '
534                         'in CONTROL file.\n'
535                         'Try "{} -h" to print usage information'
536                         .format(sys.argv[0].split('/')[-1]) )
537
538    # retrieve just one day if end_date isn't set
539    if not end:
540        end = start
541
542    dstart = datetime.strptime(start, '%Y%m%d')
543    dend = datetime.strptime(end, '%Y%m%d')
544    if dstart > dend:
545        raise ValueError('ERROR: Start date is after end date! \n'
546                         'Please adapt the dates in CONTROL file or '
547                         'command line! (start={}; end={})'.format(start, end))
548
549    return start, end
550
551def check_maxstep(maxstep, steps):
552    '''Convert maxstep into integer if it is already given. Otherwise, select
553    maxstep by going through the steps list.
554
555    Parameters
556    ----------
[6f951ca]557    maxstep : str
[45fc9b4]558        The maximum forecast time step in hours from the forecast base time.
559        This is the maximum step for non flux (accumulated) forecast data.
560
[6f951ca]561    steps : str
[45fc9b4]562        Specifies the forecast time step from forecast base time.
563        Valid values are hours (HH) from forecast base time.
564
565    Return
566    ------
[6f951ca]567    maxstep : int
[45fc9b4]568        The maximum forecast time step in hours from the forecast base time.
569        This is the maximum step for non flux (accumulated) forecast data.
570
571    '''
572    # if maxstep wasn't provided
573    # search for it in the "step" parameter
574    if not maxstep:
575        maxstep = 0
576        for s in steps:
577            if int(s) > maxstep:
578                maxstep = int(s)
579    else:
580        maxstep = int(maxstep)
581
582    return maxstep
583
584def check_basetime(basetime):
585    '''Check if basetime is set and contains one of the two
586    possible values (0, 12).
587
588    Parameters
589    ----------
[d4696e0]590    basetime : int or str or None
[45fc9b4]591        The time for a half day retrieval. The 12 hours upfront are to be
592        retrieved.
593
594    Return
595    ------
[d4696e0]596    basetime : int or None
597        The time for a half day retrieval. The 12 hours upfront are to be
598        retrieved.
[45fc9b4]599    '''
[d4696e0]600    if basetime is not None:
601        basetime = int(basetime)
602        if basetime != 0 and basetime != 12:
[45fc9b4]603            raise ValueError('ERROR: Basetime has an invalid value '
604                             '-> {}'.format(str(basetime)))
[d4696e0]605    return basetime
[45fc9b4]606
607def check_request(request, marsfile):
608    '''Check if there is an old mars request file and remove it.
609
610    Parameters
611    ----------
[6f951ca]612    request : int
[45fc9b4]613        Selects the mode of retrieval.
614        0: Retrieves the data from ECMWF.
615        1: Prints the mars requests to an output file.
616        2: Retrieves the data and prints the mars request.
617
[6f951ca]618    marsfile : str
[45fc9b4]619        Path to the mars request file.
620
621    Return
622    ------
623
624    '''
625    if request != 0:
626        if os.path.isfile(marsfile):
627            silent_remove(marsfile)
628    return
629
630def check_public(public, dataset):
631    '''Check wether the dataset parameter is set for a
632    public data set retrieval.
[3f36e42]633
634    Parameters
635    ----------
[6f951ca]636    public : int
[45fc9b4]637        Specifies if public data are to be retrieved or not.
638
[6f951ca]639    dataset : str
[45fc9b4]640        Specific name which identifies the public dataset.
[3f36e42]641
642    Return
643    ------
644
645    '''
[45fc9b4]646    if public and not dataset:
647        raise ValueError('ERROR: If public mars data wants to be retrieved, '
648                         'the "dataset"-parameter has to be set too!')
[3f36e42]649    return
[45fc9b4]650
651def check_acctype(acctype, ftype):
652    '''Guarantees that the accumulation field type is set.
653
654    If not set, it is derivated as in the old method (TYPE[1]).
655
656    Parameters
657    ----------
[6f951ca]658    acctype : str
[45fc9b4]659        The field type for the accumulated forecast fields.
660
[6f951ca]661    ftype : list of str
[45fc9b4]662        List of field types.
663
664    Return
665    ------
[6f951ca]666    acctype : str
[45fc9b4]667        The field type for the accumulated forecast fields.
668    '''
669    if not acctype:
670        print('... Control parameter ACCTYPE was not defined.')
671        try:
672            if len(ftype) == 1 and ftype[0] != 'AN':
[d4696e0]673                print('... Use same field type as for the non-flux fields.')
[45fc9b4]674                acctype = ftype[0]
675            elif len(ftype) > 1 and ftype[1] != 'AN':
[d4696e0]676                print('... Use old setting by using TYPE[1] for flux forecast!')
[45fc9b4]677                acctype = ftype[1]
678        except:
679            raise ValueError('ERROR: Accumulation field type could not be set!')
680    else:
681        if acctype.upper() == 'AN':
682            raise ValueError('ERROR: Accumulation forecast fields can not be '
683                             'of type "analysis"!')
684    return acctype
685
686
[d4696e0]687def check_acctime(acctime, marsclass, purefc):
[45fc9b4]688    '''Guarantees that the accumulation forecast times were set.
689
[d4696e0]690    If it is not set, it tries to set the value for some of the
[45fc9b4]691    most commonly used data sets. Otherwise it raises an error.
692
693    Parameters
694    ----------
[6f951ca]695    acctime : str
[45fc9b4]696        The starting time from the accumulated forecasts.
697
[d4696e0]698    marsclass : str
699        ECMWF data classification identifier.
[45fc9b4]700
[6f951ca]701    purefc : int
[45fc9b4]702        Switch for definition of pure forecast mode or not.
703
704    Return
705    ------
[6f951ca]706    acctime : str
[45fc9b4]707        The starting time from the accumulated forecasts.
708    '''
[d4696e0]709
[45fc9b4]710    if not acctime:
711        print('... Control parameter ACCTIME was not defined.')
[6f951ca]712        print('... Value will be set depending on field type:\n '
[d4696e0]713              '\t\t EA=06/18\n\t\t EI/OD=00/12\n\t\t EP=18')
714        if marsclass.upper() == 'EA': # Era 5
[45fc9b4]715            acctime = '06/18'
[d4696e0]716        elif marsclass.upper() == 'EI': # Era-Interim
[45fc9b4]717            acctime = '00/12'
[d4696e0]718        elif marsclass.upper() == 'EP': # CERA
[45fc9b4]719            acctime = '18'
[d4696e0]720        elif marsclass.upper() == 'OD' and not purefc: # On-demand
[45fc9b4]721            acctime = '00/12'
722        else:
723            raise ValueError('ERROR: Accumulation forecast time can not '
724                             'automatically be derived!')
725    return acctime
726
[d4696e0]727def check_accmaxstep(accmaxstep, marsclass, purefc, maxstep):
[45fc9b4]728    '''Guarantees that the accumulation forecast step were set.
729
730    Parameters
731    ----------
[6f951ca]732    accmaxstep : str
[45fc9b4]733        The maximum forecast step for the accumulated forecast fields.
734
[d4696e0]735    marsclass : str
736        ECMWF data classification identifier.
[45fc9b4]737
[6f951ca]738    purefc : int
[45fc9b4]739        Switch for definition of pure forecast mode or not.
740
[6f951ca]741    maxstep : str
[45fc9b4]742        The maximum forecast time step in hours from the forecast base time.
743        This is the maximum step for non flux (accumulated) forecast data.
744
745    Return
746    ------
[6f951ca]747    accmaxstep : str
[45fc9b4]748        The maximum forecast step for the accumulated forecast fields.
749    '''
750    if not accmaxstep:
751        print('... Control parameter ACCMAXSTEP was not defined.')
752        print('... Value will be set depending on field type/time: '
[d4696e0]753              '\n\t\t EA/EI/OD=12\n\t\t EP=24')
754        if marsclass.upper() in ['EA', 'EI', 'OD'] and not purefc:
[45fc9b4]755            # Era 5, Era-Interim, On-demand operational
756            accmaxstep = '12'
[d4696e0]757        elif marsclass.upper() == 'EP': # CERA
[4c1d7de]758            accmaxstep = '24'
[45fc9b4]759        elif purefc and accmaxstep != maxstep:
760            accmaxstep = maxstep
761            print('... For pure forecast mode, the accumulated forecast must '
762                  'have the same maxstep as the normal forecast fields!\n'
763                  '\t\t Accmaxstep was set to maxstep!')
764        else:
765            raise ValueError('ERROR: Accumulation forecast step can not '
766                             'automatically be derived!')
767    else:
768        if purefc and int(accmaxstep) != int(maxstep):
769            accmaxstep = maxstep
770            print('... For pure forecast mode, the accumulated forecast must '
771                          'have the same maxstep as the normal forecast fields!\n'
772                          '\t\t Accmaxstep was set to maxstep!')
773    return accmaxstep
774
775def check_addpar(addpar):
776    '''Check that addpar has correct format of additional parameters in
777    a single string, so that it can be easily appended to the hard coded
778    parameters that are retrieved in any case.
779
780    Parameters
781    ----------
[6f951ca]782    addpar : str or list of str
[45fc9b4]783        List of additional parameters to be retrieved.
784
785    Return
786    ------
[6f951ca]787    addpar : str
[45fc9b4]788        List of additional parameters to be retrieved.
789    '''
790
791    if addpar and isinstance(addpar, str):
792        if '/' in addpar:
793            parlist = addpar.split('/')
794            parlist = [p for p in parlist if p is not '']
795        else:
796            parlist = [addpar]
797
798        addpar = '/' + '/'.join(parlist)
799
800    return addpar
801
[f2616a3]802
803def check_job_chunk(job_chunk):
[6f951ca]804    '''Checks that if job chunk is set, the number is positive and non zero.
[f2616a3]805
806    Parameters
807    ----------
[6f951ca]808    job_chunk : int
[f2616a3]809        The number of days for a single job script.
810
811    Return
812    ------
[6f951ca]813    job_chunk : int
[f2616a3]814        The number of days for a single job script.
815    '''
[6f951ca]816    if not job_chunk:
817        return job_chunk
818
[f2616a3]819    if job_chunk < 0:
820        raise ValueError('ERROR: The number of job chunk is negative!\n'
821                         'It has to be a positive number!')
822    elif job_chunk == 0:
823        job_chunk = None
824    else:
825        pass
826
827    return job_chunk
[ae2756e]828
829
830def check_number(number, mailfail):
831    '''Check for correct string format of ensemble member numbers.
832
833    Parameters
834    ----------
835    number : str
836        List of ensemble member forecast runs.
837
838    mailfail : list of str
839        Contains all email addresses which should be notified.
840        It might also contain just the ecmwf user name which will trigger
841        mailing to the associated email address for this user.
842
843    Return
844    ------
845    number : str
846        String with list of ensemble member forecast runs. E.g. '01/02/03/04'
847    '''
848
849    if '/' in number:
850        numbers = number.split('/')
851        if 'to' in number.lower() and 'by' in number.lower():
852            number = '{:0>3}'.format(int(numbers[0])) + '/TO/' + \
853                     '{:0>3}'.format(int(numbers[2])) + '/BY/' + \
854                     '{:0>3}'.format(int(numbers[4]))
855        elif 'to' in number.lower() and 'by' not in number.lower():
856            number = '{:0>3}'.format(int(numbers[0])) + '/TO/' + \
857                     '{:0>3}'.format(int(numbers[2]))
858        else:
859            numbers = ['{:0>3}'.format(i) for i in numbers]
860            number = '{:0>3}/'.join(numbers)
861    elif number.isdigit():
862        number = '{:0>3}'.format(int(number))
863    else:
864        pass
865
866    return number
Note: See TracBrowser for help on using the repository browser.
hosted by ZAMG