source: flex_extract.git/Source/Python/Mods/checks.py @ 8463d78

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

made python3 again, now working

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