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

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

BUGFIX (ticket #263): Corrected installation check for parameters GATEWAY and DESTINATION

  • 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
121    Checks on the format of the four area components. Wether it is of
122    the order of 1000 or 1. Also checks wether area was already set by command
123    line, then the four components are overwritten.
124    Convert to correct format of the order of magnitude "1" and sets the
125    area parameter (North/West/South/East).
126    E.g.: -5./20./10./10.
[3f36e42]127
[a55ac71]128    Parameters
129    ----------
[6f951ca]130    grid : str
[45fc9b4]131        Contains grid information.
132
[6f951ca]133    area : str
[45fc9b4]134        Contains area informtion.
135
[6f951ca]136    upper : str
[45fc9b4]137        The northern most latitude.
138
[6f951ca]139    lower : str
[45fc9b4]140        The souther most latitude.
141
[6f951ca]142    left : str
[45fc9b4]143        The western most longitude.
144
[6f951ca]145    right : str
[45fc9b4]146        The eastern most longiude.
[3f36e42]147
[a55ac71]148    Return
149    ------
[6f951ca]150    grid : str
[a55ac71]151        Contains grid in format Lat/lon. E.g. 0.1/0.1
[3f36e42]152    '''
153    if 'N' in grid:  # Gaussian output grid
154        area = 'G'
155        return area
156
157    # if area was provided decompose area into its 4 components
158    if area:
159        components = area.split('/')
160        upper, left, lower, right = components
161
[97f4f4c]162    # determine area format
[0f89116]163    if all([(abs(float(upper) / 10000.) >= 0.01 or float(upper) / 1000. == 0.),
164            (abs(float(lower) / 10000.) >= 0.01 or float(lower) / 1000. == 0.),
165            (abs(float(left) / 10000.) >= 0.01 or float(left) / 1000. == 0.),
166            (abs(float(right) / 10000.) >= 0.01 or float(right) / 1000. == 0.)]):
[97f4f4c]167        # area is defined in 1/1000 degrees; old format
168        area = '{}/{}/{}/{}'.format(float(upper) / 1000.,
169                                    float(left) / 1000.,
170                                    float(lower) / 1000.,
171                                    float(right) / 1000.)
[0f89116]172    elif all([abs(float(upper) / 10000.) < 0.05,
173              abs(float(lower) / 10000.) < 0.05,
174              abs(float(left) / 10000.) < 0.05,
175              abs(float(right) / 10000.) < 0.05]):
[97f4f4c]176        # area is already in new format
177        area = '{}/{}/{}/{}'.format(float(upper),
178                                    float(left),
179                                    float(lower),
180                                    float(right))
181    else:
182        raise ValueError('The area components have different '
[d2febd4]183                         'formats (upper, lower, left, right): '
184                         '{}/{}/{}/{}'.format(str(upper), str(lower),
[0f89116]185                                              str(left), str(right)))
[97f4f4c]186
[3f36e42]187    return area
188
189def check_levels(levelist, level):
[a55ac71]190    '''Defines correct level list and guarantees that the maximum level is
191    one of the available maximum levels.
[3f36e42]192
193    Parameters
194    ----------
[6f951ca]195    levelist : str
[a55ac71]196        Specifies the level list.
197        Examples: model level: 1/to/137, pressure levels: 500/to/1000
198
[6f951ca]199    level : str
[a55ac71]200        Specifies the maximum level.
[3f36e42]201
202    Return
203    ------
[6f951ca]204    levelist : str
[a55ac71]205        Specifies the required levels. It has to have a valid
206        correspondence to the selected levtype.
207        Examples: model level: 1/to/137, pressure levels: 500/to/1000
208
[6f951ca]209    level : str
[a55ac71]210        Specifies the maximum level. It has to be one of the
211        available maximum level number as contained in the variable
212        MAX_LEVEL_LIST in "_config". E.g. [16, 19, 31, 40, 50, 60, 62, 91, 137]
[3f36e42]213
214    '''
215    # assure consistency of levelist and level
216    if not levelist and not level:
217        raise ValueError('ERROR: neither levelist nor level '
218                         'specified in CONTROL file')
219    elif not levelist and level:
220        levelist = '1/to/' + level
221    elif (levelist and not level) or \
222         (levelist[-1] != level[-1]):
223        level = levelist.split('/')[-1]
224    else:
225        pass
226
227    # check if max level is a valid level
228    if int(level) not in _config.MAX_LEVEL_LIST:
229        raise ValueError('ERROR: \n'
230                         'LEVEL must be the maximum level of a specified '
231                         'level list from ECMWF, e.g. {} \n'
232                         'Check parameter "LEVEL" or the max level of '
233                         '"LEVELIST"!'.format(str(_config.MAX_LEVEL_LIST)))
234
235    return levelist, level
236
237
238def check_ppid(c, ppid):
239    '''Sets the current PPID.
240
241    Parameters
242    ----------
[6f951ca]243    c : ControlFile
[3f36e42]244            Contains all the parameters of CONTROL file and
245            command line.
246
[6f951ca]247    ppid : int or None
[3f36e42]248        Contains the ppid number provided by the command line parameter
249        of is None otherwise.
250
251    Return
252    ------
253
254    '''
255
256    if not ppid:
257        c.ppid = str(os.getppid())
258    else:
259        c.ppid = ppid
260
261    return
262
[4d3b052]263
[45fc9b4]264def check_purefc(ftype):
[4d3b052]265    '''Check for a pure forecast mode.
266
267    Parameters
268    ----------
[6f951ca]269    ftype : list of str
[4d3b052]270        List of field types.
271
272    Return
273    ------
274    True or False:
275        True if pure forecasts are to be retrieved. False if there are
276        analysis fields in between.
277    '''
278
[45fc9b4]279    if 'AN' not in ftype and '4V' not in ftype:
[4d3b052]280        # pure forecast
[45fc9b4]281        return 1
282
283    return 0
284
285
[0f89116]286def check_step(step):
[45fc9b4]287    '''Checks on step format and convert into a list of steps.
288
289    If the steps were defined with "to" and "by" they are converted into
290    a list of steps. If the steps were set in a string, it is
291    converted into a list.
292
293    Parameters
294    ----------
[6f951ca]295    step : list of str or str
[45fc9b4]296        Specifies the forecast time step from forecast base time.
297        Valid values are hours (HH) from forecast base time.
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    '''
[0f89116]405    if not len(ftype) == len(ftime) == len(steps):
[45fc9b4]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 \
[50f9ca6]481            (not ecuid or not ecgid):
482        raise ValueError('\nEnvironment variables ECUID '
[45fc9b4]483                         'and ECGID were not set properly! \n '
484                         'Please check for existence of file "ECMWF_ENV" '
485                         'in the run directory!')
[50f9ca6]486    elif queue in _config.QUEUES_LIST and \
487             (not gateway or not destination):
488        print('WARNING: Parameters GATEWAY and DESTINATION were '
489              'not properly set for working on ECMWF server. \n'
490              'There will be no transfer of output files to the '
491              'local gateway server possible!')
[45fc9b4]492    return
493
494def check_pathes(idir, odir, fpdir, fedir):
495    '''Check if output and flexpart pathes are set.
496
497    Parameters
498    ----------
[6f951ca]499    idir : str
[45fc9b4]500        Path to the temporary directory for MARS retrieval data.
501
[6f951ca]502    odir : str
[45fc9b4]503        Path to the final output directory where the FLEXPART input files
504        will be stored.
[4d3b052]505
[6f951ca]506    fpdir : str
[45fc9b4]507        Path to FLEXPART root directory.
[4d3b052]508
[6f951ca]509    fedir : str
[45fc9b4]510        Path to flex_extract root directory.
511
512    Return
513    ------
[6f951ca]514    odir : str
[45fc9b4]515        Path to the final output directory where the FLEXPART input files
516        will be stored.
517
[6f951ca]518    fpdir : str
[45fc9b4]519        Path to FLEXPART root directory.
520
521    '''
522    if not fpdir:
523        fpdir = fedir
524
525    if not odir:
526        odir = idir
527
528    return odir, fpdir
529
530def check_dates(start, end):
531    '''Checks if there is at least a start date for a one day retrieval.
532
533    Checks if end date lies after start date and end date is set.
534
535    Parameters
536    ----------
[6f951ca]537    start : str
[45fc9b4]538        The start date of the retrieval job.
539
[6f951ca]540    end : str
[45fc9b4]541        The end date of the retrieval job.
542
543    Return
544    ------
[6f951ca]545    start : str
[45fc9b4]546        The start date of the retrieval job.
547
[6f951ca]548    end : str
[45fc9b4]549        The end date of the retrieval job.
[4d3b052]550
[3f36e42]551    '''
[45fc9b4]552    # check for having at least a starting date
553    # otherwise program is not allowed to run
554    if not start:
555        raise ValueError('start_date was neither specified in command line nor '
556                         'in CONTROL file.\n'
557                         'Try "{} -h" to print usage information'
[0f89116]558                         .format(sys.argv[0].split('/')[-1]))
[45fc9b4]559
560    # retrieve just one day if end_date isn't set
561    if not end:
562        end = start
563
564    dstart = datetime.strptime(start, '%Y%m%d')
565    dend = datetime.strptime(end, '%Y%m%d')
566    if dstart > dend:
567        raise ValueError('ERROR: Start date is after end date! \n'
568                         'Please adapt the dates in CONTROL file or '
569                         'command line! (start={}; end={})'.format(start, end))
570
571    return start, end
572
573def check_maxstep(maxstep, steps):
574    '''Convert maxstep into integer if it is already given. Otherwise, select
575    maxstep by going through the steps list.
576
577    Parameters
578    ----------
[6f951ca]579    maxstep : str
[45fc9b4]580        The maximum forecast time step in hours from the forecast base time.
581        This is the maximum step for non flux (accumulated) forecast data.
582
[6f951ca]583    steps : str
[45fc9b4]584        Specifies the forecast time step from forecast base time.
585        Valid values are hours (HH) from forecast base time.
586
587    Return
588    ------
[6f951ca]589    maxstep : int
[45fc9b4]590        The maximum forecast time step in hours from the forecast base time.
591        This is the maximum step for non flux (accumulated) forecast data.
592
593    '''
594    # if maxstep wasn't provided
595    # search for it in the "step" parameter
596    if not maxstep:
597        maxstep = 0
598        for s in steps:
599            if int(s) > maxstep:
600                maxstep = int(s)
601    else:
602        maxstep = int(maxstep)
603
604    return maxstep
605
606def check_basetime(basetime):
607    '''Check if basetime is set and contains one of the two
608    possible values (0, 12).
609
610    Parameters
611    ----------
[d4696e0]612    basetime : int or str or None
[45fc9b4]613        The time for a half day retrieval. The 12 hours upfront are to be
614        retrieved.
615
616    Return
617    ------
[d4696e0]618    basetime : int or None
619        The time for a half day retrieval. The 12 hours upfront are to be
620        retrieved.
[45fc9b4]621    '''
[d4696e0]622    if basetime is not None:
623        basetime = int(basetime)
624        if basetime != 0 and basetime != 12:
[45fc9b4]625            raise ValueError('ERROR: Basetime has an invalid value '
626                             '-> {}'.format(str(basetime)))
[d4696e0]627    return basetime
[45fc9b4]628
629def check_request(request, marsfile):
630    '''Check if there is an old mars request file and remove it.
631
632    Parameters
633    ----------
[6f951ca]634    request : int
[45fc9b4]635        Selects the mode of retrieval.
636        0: Retrieves the data from ECMWF.
637        1: Prints the mars requests to an output file.
638        2: Retrieves the data and prints the mars request.
639
[6f951ca]640    marsfile : str
[45fc9b4]641        Path to the mars request file.
642
643    Return
644    ------
645
646    '''
647    if request != 0:
648        if os.path.isfile(marsfile):
649            silent_remove(marsfile)
650    return
651
652def check_public(public, dataset):
653    '''Check wether the dataset parameter is set for a
654    public data set retrieval.
[3f36e42]655
656    Parameters
657    ----------
[6f951ca]658    public : int
[45fc9b4]659        Specifies if public data are to be retrieved or not.
660
[6f951ca]661    dataset : str
[45fc9b4]662        Specific name which identifies the public dataset.
[3f36e42]663
664    Return
665    ------
666
667    '''
[45fc9b4]668    if public and not dataset:
669        raise ValueError('ERROR: If public mars data wants to be retrieved, '
670                         'the "dataset"-parameter has to be set too!')
[3f36e42]671    return
[45fc9b4]672
673def check_acctype(acctype, ftype):
674    '''Guarantees that the accumulation field type is set.
675
676    If not set, it is derivated as in the old method (TYPE[1]).
677
678    Parameters
679    ----------
[6f951ca]680    acctype : str
[45fc9b4]681        The field type for the accumulated forecast fields.
682
[6f951ca]683    ftype : list of str
[45fc9b4]684        List of field types.
685
686    Return
687    ------
[6f951ca]688    acctype : str
[45fc9b4]689        The field type for the accumulated forecast fields.
690    '''
691    if not acctype:
692        print('... Control parameter ACCTYPE was not defined.')
693        try:
694            if len(ftype) == 1 and ftype[0] != 'AN':
[d4696e0]695                print('... Use same field type as for the non-flux fields.')
[45fc9b4]696                acctype = ftype[0]
697            elif len(ftype) > 1 and ftype[1] != 'AN':
[d4696e0]698                print('... Use old setting by using TYPE[1] for flux forecast!')
[45fc9b4]699                acctype = ftype[1]
700        except:
701            raise ValueError('ERROR: Accumulation field type could not be set!')
702    else:
703        if acctype.upper() == 'AN':
704            raise ValueError('ERROR: Accumulation forecast fields can not be '
705                             'of type "analysis"!')
706    return acctype
707
708
[e7708b2]709def check_acctime(acctime, marsclass, purefc, time):
[45fc9b4]710    '''Guarantees that the accumulation forecast times were set.
711
[d4696e0]712    If it is not set, it tries to set the value for some of the
[45fc9b4]713    most commonly used data sets. Otherwise it raises an error.
714
715    Parameters
716    ----------
[6f951ca]717    acctime : str
[45fc9b4]718        The starting time from the accumulated forecasts.
719
[d4696e0]720    marsclass : str
721        ECMWF data classification identifier.
[45fc9b4]722
[6f951ca]723    purefc : int
[45fc9b4]724        Switch for definition of pure forecast mode or not.
725
726    Return
727    ------
[6f951ca]728    acctime : str
[45fc9b4]729        The starting time from the accumulated forecasts.
730    '''
[d4696e0]731
[45fc9b4]732    if not acctime:
733        print('... Control parameter ACCTIME was not defined.')
[6f951ca]734        print('... Value will be set depending on field type:\n '
[d4696e0]735              '\t\t EA=06/18\n\t\t EI/OD=00/12\n\t\t EP=18')
736        if marsclass.upper() == 'EA': # Era 5
[45fc9b4]737            acctime = '06/18'
[d4696e0]738        elif marsclass.upper() == 'EI': # Era-Interim
[45fc9b4]739            acctime = '00/12'
[d4696e0]740        elif marsclass.upper() == 'EP': # CERA
[45fc9b4]741            acctime = '18'
[d4696e0]742        elif marsclass.upper() == 'OD' and not purefc: # On-demand
[45fc9b4]743            acctime = '00/12'
[e7708b2]744        elif marsclass.upper() == 'OD' and purefc: # On-demand
745            acctime = time[0]
[45fc9b4]746        else:
747            raise ValueError('ERROR: Accumulation forecast time can not '
748                             'automatically be derived!')
749    return acctime
750
[d4696e0]751def check_accmaxstep(accmaxstep, marsclass, purefc, maxstep):
[45fc9b4]752    '''Guarantees that the accumulation forecast step were set.
753
754    Parameters
755    ----------
[6f951ca]756    accmaxstep : str
[45fc9b4]757        The maximum forecast step for the accumulated forecast fields.
758
[d4696e0]759    marsclass : str
760        ECMWF data classification identifier.
[45fc9b4]761
[6f951ca]762    purefc : int
[45fc9b4]763        Switch for definition of pure forecast mode or not.
764
[6f951ca]765    maxstep : str
[45fc9b4]766        The maximum forecast time step in hours from the forecast base time.
767        This is the maximum step for non flux (accumulated) forecast data.
768
769    Return
770    ------
[6f951ca]771    accmaxstep : str
[45fc9b4]772        The maximum forecast step for the accumulated forecast fields.
773    '''
774    if not accmaxstep:
775        print('... Control parameter ACCMAXSTEP was not defined.')
776        print('... Value will be set depending on field type/time: '
[d4696e0]777              '\n\t\t EA/EI/OD=12\n\t\t EP=24')
778        if marsclass.upper() in ['EA', 'EI', 'OD'] and not purefc:
[45fc9b4]779            # Era 5, Era-Interim, On-demand operational
780            accmaxstep = '12'
[d4696e0]781        elif marsclass.upper() == 'EP': # CERA
[4c1d7de]782            accmaxstep = '24'
[45fc9b4]783        elif purefc and accmaxstep != maxstep:
784            accmaxstep = maxstep
785            print('... For pure forecast mode, the accumulated forecast must '
786                  'have the same maxstep as the normal forecast fields!\n'
787                  '\t\t Accmaxstep was set to maxstep!')
788        else:
789            raise ValueError('ERROR: Accumulation forecast step can not '
790                             'automatically be derived!')
791    else:
792        if purefc and int(accmaxstep) != int(maxstep):
793            accmaxstep = maxstep
794            print('... For pure forecast mode, the accumulated forecast must '
[0f89116]795                  'have the same maxstep as the normal forecast fields!\n'
796                  '\t\t Accmaxstep was set to maxstep!')
[45fc9b4]797    return accmaxstep
798
799def check_addpar(addpar):
800    '''Check that addpar has correct format of additional parameters in
801    a single string, so that it can be easily appended to the hard coded
802    parameters that are retrieved in any case.
803
804    Parameters
805    ----------
[6f951ca]806    addpar : str or list of str
[45fc9b4]807        List of additional parameters to be retrieved.
808
809    Return
810    ------
[6f951ca]811    addpar : str
[45fc9b4]812        List of additional parameters to be retrieved.
813    '''
814
815    if addpar and isinstance(addpar, str):
816        if '/' in addpar:
817            parlist = addpar.split('/')
818            parlist = [p for p in parlist if p is not '']
819        else:
820            parlist = [addpar]
821
822        addpar = '/' + '/'.join(parlist)
823
824    return addpar
825
[f2616a3]826
827def check_job_chunk(job_chunk):
[6f951ca]828    '''Checks that if job chunk is set, the number is positive and non zero.
[f2616a3]829
830    Parameters
831    ----------
[6f951ca]832    job_chunk : int
[f2616a3]833        The number of days for a single job script.
834
835    Return
836    ------
[6f951ca]837    job_chunk : int
[f2616a3]838        The number of days for a single job script.
839    '''
[6f951ca]840    if not job_chunk:
841        return job_chunk
[e7708b2]842    else:
843        job_chunk = int(job_chunk)
[6f951ca]844
[f2616a3]845    if job_chunk < 0:
846        raise ValueError('ERROR: The number of job chunk is negative!\n'
847                         'It has to be a positive number!')
848    elif job_chunk == 0:
849        job_chunk = None
850    else:
851        pass
852
853    return job_chunk
[ae2756e]854
855
[0f89116]856def check_number(number):
[ae2756e]857    '''Check for correct string format of ensemble member numbers.
858
859    Parameters
860    ----------
861    number : str
862        List of ensemble member forecast runs.
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