source: flex_extract.git/source/python/submit.py @ a1011e7

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

python2 downgrade

  • Property mode set to 100755
File size: 8.7 KB
RevLine 
[a1011e7]1#!/usr/bin/env python
[64cf353]2# -*- coding: utf-8 -*-
[991df6a]3#*******************************************************************************
4# @Author: Anne Fouilloux (University of Oslo)
5#
6# @Date: October 2014
7#
8# @Change History:
9#
10#    November 2015 - Leopold Haimberger (University of Vienna):
11#        - job submission on ecgate and cca
12#        - job templates suitable for twice daily operational dissemination
13#
14#    February 2018 - Anne Philipp (University of Vienna):
15#        - applied PEP8 style guide
16#        - added documentation
17#        - minor changes in programming style (for consistence)
[2fb99de]18#        - changed path names to variables from config file
19#        - added option for writing mars requests to extra file
[6f951ca]20#          additionally, as option without submitting the mars jobs
21#        - splitted submit function to use genshi templates for the
22#          job script and avoid code duplication
[991df6a]23#
24# @License:
[6f951ca]25#    (C) Copyright 2014-2019.
26#    Anne Philipp, Leopold Haimberger
[991df6a]27#
[6f951ca]28#    This work is licensed under the Creative Commons Attribution 4.0
29#    International License. To view a copy of this license, visit
30#    http://creativecommons.org/licenses/by/4.0/ or send a letter to
31#    Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
[991df6a]32#*******************************************************************************
[6f951ca]33'''This script allows the user to extract meteorological fields from the ECMWF.
34
35It prepares the settings for retrieving the data from ECMWF servers and
36process the resulting files to prepare them for the use with FLEXPART or
37FLEXTRA.
38
39If it is supposed to work locally then it works through the necessary
40functions get_mars_data and prepare_flexpart. Otherwise it prepares
41a job script (korn shell) which will do the necessary work on the
42ECMWF server. This script will de submitted via the ecaccess command
43ecaccess-job-submit.
44
45This file can also be imported as a module which then contains the following
46functions:
47
48    * main - the main function of the script
49    * submit - calls mk_jobscript depending on operation mode and submits its
50    * mk_jobscript - creates the job script from a template
51
52Type: submit.py --help
53to get information about command line parameters.
54Read the documentation for usage instructions.
55'''
[efdb01a]56
[64cf353]57# ------------------------------------------------------------------------------
58# MODULES
59# ------------------------------------------------------------------------------
[a1011e7]60from __future__ import print_function
61
[efdb01a]62import os
63import sys
[d69b677]64import subprocess
65import inspect
[54a8a01]66import collections
[f2616a3]67from datetime import datetime, timedelta
[efdb01a]68
69# software specific classes and modules from flex_extract
[54a8a01]70import _config
[f20af73]71from mods.tools import (setup_controldata, normal_exit, get_cmdline_args,
[79729d5]72                         submit_job_to_ecserver, read_ecenv)
[25b14be]73from mods.get_mars_data import get_mars_data
74from mods.prepare_flexpart import prepare_flexpart
75from classes.ControlFile import ControlFile
[991df6a]76
[d727af2]77
[64cf353]78# ------------------------------------------------------------------------------
[6f951ca]79# METHODS
[64cf353]80# ------------------------------------------------------------------------------
[991df6a]81
[d69b677]82def main():
[274f9ef]83    '''Get the arguments from script call and from CONTROL file.
84    Decides from the argument "queue" if the local version
85    is done "queue=None" or the gateway version with "queue=ecgate"
86    or "queue=cca".
87
88    Parameters
89    ----------
[d69b677]90
[d727af2]91
[274f9ef]92    Return
93    ------
[64cf353]94
95    '''
[ff99eae]96
[f20af73]97    c, ppid, queue, job_template = setup_controldata()
[ff99eae]98
[efdb01a]99    # on local side
[f20af73]100    # starting from an ECMWF server this would also be the local side
[2fb99de]101    called_from_dir = os.getcwd()
[f20af73]102    if queue is None:
[64cf353]103        if c.inputdir[0] != '/':
[ff99eae]104            c.inputdir = os.path.join(called_from_dir, c.inputdir)
[64cf353]105        if c.outputdir[0] != '/':
[ff99eae]106            c.outputdir = os.path.join(called_from_dir, c.outputdir)
[54a8a01]107        get_mars_data(c)
[2fb99de]108        if c.request == 0 or c.request == 2:
[f20af73]109            prepare_flexpart(ppid, c)
[96e1533]110            exit_message = 'FLEX_EXTRACT IS DONE!'
[2fb99de]111        else:
[96e1533]112            exit_message = 'PRINTING MARS_REQUESTS DONE!'
113    # send files to ECMWF server
[d69b677]114    else:
[f20af73]115        submit(job_template, c, queue)
[e0e99a5]116        exit_message = 'FLEX_EXTRACT JOB SCRIPT IS SUBMITED!'
[64cf353]117
[403cbf1]118    normal_exit(exit_message)
[96e1533]119
[64cf353]120    return
121
122def submit(jtemplate, c, queue):
[ff2a11c]123    '''Prepares the job script and submits it to the specified queue.
[274f9ef]124
125    Parameters
126    ----------
[6f951ca]127    jtemplate : str
[274f9ef]128        Job template file from sub-directory "_templates" for
129        submission to ECMWF. It contains all necessary
130        module and variable settings for the ECMWF environment as well as
131        the job call and mail report instructions.
132        Default is "job.temp".
133
[6f951ca]134    c : ControlFile
[274f9ef]135        Contains all the parameters of CONTROL file and
136        command line.
137
[6f951ca]138    queue : str
[274f9ef]139        Name of queue for submission to ECMWF (e.g. ecgate or cca )
140
141    Return
142    ------
143
[64cf353]144    '''
145
[d4696e0]146    if not c.oper:
[54a8a01]147    # --------- create on demand job script ------------------------------------
[a4531f1]148        if c.purefc:
[2fb99de]149            print('---- Pure forecast mode! ----')
[54a8a01]150        else:
[2fb99de]151            print('---- On-demand mode! ----')
[54a8a01]152
[ff2a11c]153        job_file = os.path.join(_config.PATH_JOBSCRIPTS,
154                                jtemplate[:-5] + '.ksh')
[54a8a01]155
[f2616a3]156        # divide time periode into specified number of job chunks
157        # to have multiple job scripts
158        if c.job_chunk:
159            start = datetime.strptime(c.start_date, '%Y%m%d')
160            end = datetime.strptime(c.end_date, '%Y%m%d')
161            chunk = timedelta(days=c.job_chunk)
[fc05fbd]162            oneday = timedelta(days=1)
[54a8a01]163
[f2616a3]164            while start <= end:
165                if (start + chunk) <= end:
[fc05fbd]166                    c.end_date = (start + chunk - oneday).strftime("%Y%m%d")
[f2616a3]167                else:
168                    c.end_date = end.strftime("%Y%m%d")
169
170                clist = c.to_list()
171                mk_jobscript(jtemplate, job_file, clist)
172
173                job_id = submit_job_to_ecserver(queue, job_file)
174                print('The job id is: ' + str(job_id.strip()))
175
176                start = start + chunk
177                c.start_date = start.strftime("%Y%m%d")
178        # submit a single job script
179        else:
180            clist = c.to_list()
181
182            mk_jobscript(jtemplate, job_file, clist)
183
184            job_id = submit_job_to_ecserver(queue, job_file)
185            print('The job id is: ' + str(job_id.strip()))
[54a8a01]186
187    else:
188    # --------- create operational job script ----------------------------------
[2fb99de]189        print('---- Operational mode! ----')
[ff2a11c]190
[2fb99de]191        job_file = os.path.join(_config.PATH_JOBSCRIPTS,
192                                jtemplate[:-5] + 'oper.ksh')
[54a8a01]193
194        c.start_date = '${MSJ_YEAR}${MSJ_MONTH}${MSJ_DAY}'
195        c.end_date = '${MSJ_YEAR}${MSJ_MONTH}${MSJ_DAY}'
[d4696e0]196        c.basetime = '${MSJ_BASETIME}'
[ff2a11c]197        if c.maxstep > 24:
[54a8a01]198            c.time = '${MSJ_BASETIME} {MSJ_BASETIME}'
199
[ff2a11c]200        clist = c.to_list()
[54a8a01]201
[ff2a11c]202        mk_jobscript(jtemplate, job_file, clist)
[d69b677]203
[f2616a3]204        job_id = submit_job_to_ecserver(queue, job_file)
205        print('The job id is: ' + str(job_id.strip()))
206
207    print('You should get an email per job with subject flex.hostname.pid')
[d69b677]208
[64cf353]209    return
[d69b677]210
[ff2a11c]211def mk_jobscript(jtemplate, job_file, clist):
212    '''Creates the job script from template.
213
214    Parameters
215    ----------
[6f951ca]216    jtemplate : str
[ff2a11c]217        Job template file from sub-directory "_templates" for
218        submission to ECMWF. It contains all necessary
219        module and variable settings for the ECMWF environment as well as
220        the job call and mail report instructions.
221        Default is "job.temp".
222
[6f951ca]223    job_file : str
[ff2a11c]224        Path to the job script file.
225
[6f951ca]226    clist : list of str
[ff2a11c]227        Contains all necessary parameters for ECMWF CONTROL file.
228
229    Return
230    ------
231
232    '''
233    from genshi.template.text import NewTextTemplate
234    from genshi.template import  TemplateLoader
235    from genshi.template.eval import UndefinedError
236
237    # load template and insert control content as list
238    try:
239        loader = TemplateLoader(_config.PATH_TEMPLATES, auto_reload=False)
240        control_template = loader.load(jtemplate,
241                                       cls=NewTextTemplate)
242
243        stream = control_template.generate(control_content=clist)
244    except UndefinedError as e:
245        print('... ERROR ' + str(e))
246
247        sys.exit('\n... error occured while trying to generate jobscript')
248    except OSError as e:
249        print('... ERROR CODE: ' + str(e.errno))
250        print('... ERROR MESSAGE:\n \t ' + str(e.strerror))
251
252        sys.exit('\n... error occured while trying to generate jobscript')
253
254    # create jobscript file
255    try:
256        with open(job_file, 'w') as f:
257            f.write(stream.render('text'))
258    except OSError as e:
259        print('... ERROR CODE: ' + str(e.errno))
260        print('... ERROR MESSAGE:\n \t ' + str(e.strerror))
261
262        sys.exit('\n... error occured while trying to write ' + job_file)
263
264    return
265
[f2616a3]266
[d69b677]267if __name__ == "__main__":
268    main()
Note: See TracBrowser for help on using the repository browser.
hosted by ZAMG