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

ctbtodev
Last change on this file since 8209738 was 8209738, checked in by anphi <anne.philipp@…>, 4 years ago

language corrections in comment sections and print commands

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