source: flex_extract.git/Source/Python/submit.py @ 0540bd0

dev
Last change on this file since 0540bd0 was 0540bd0, checked in by Anne Tipka <anne.tipka@…>, 18 months ago

added option to provide event(ECMWF trigger events) information to CONTROL files and start the job in operational mode

  • Property mode set to 100755
File size: 8.9 KB
Line 
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
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)
18#        - changed path names to variables from config file
19#        - added option for writing mars requests to extra file
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
23#    June 2020 - Anne Philipp
24#        - changed finale job_file to filename from config file
25#          instead of generating from the template filename
26#
27# @License:
28#    (C) Copyright 2014-2020.
29#    Anne Philipp, Leopold Haimberger
30#
31#    SPDX-License-Identifier: CC-BY-4.0
32#
33#    This work is licensed under the Creative Commons Attribution 4.0
34#    International License. To view a copy of this license, visit
35#    http://creativecommons.org/licenses/by/4.0/ or send a letter to
36#    Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
37#*******************************************************************************
38'''This script allows the user to extract meteorological fields from the ECMWF.
39
40It prepares the settings for retrieving the data from ECMWF servers and
41process the resulting files to prepare them for the use with FLEXPART or
42FLEXTRA.
43
44If it is supposed to work locally then it works through the necessary
45functions get_mars_data and prepare_flexpart. Otherwise it prepares
46a job script (korn shell) which will do the necessary work on the
47ECMWF server. This script will de submitted via the ecaccess command
48ecaccess-job-submit.
49
50This file can also be imported as a module which then contains the following
51functions:
52
53    * main - the main function of the script
54    * submit - calls mk_jobscript depending on operation mode and submits its
55    * mk_jobscript - creates the job script from a template
56
57Type: submit.py --help
58to get information about command line parameters.
59Read the documentation for usage instructions.
60'''
61
62# ------------------------------------------------------------------------------
63# MODULES
64# ------------------------------------------------------------------------------
65from __future__ import print_function
66
67import os
68import sys
69from datetime import datetime, timedelta
70
71# software specific classes and modules from flex_extract
72import _config
73from Mods.tools import (setup_controldata, normal_exit,
74                        submit_job_to_ecserver)
75from Mods.get_mars_data import get_mars_data
76from Mods.prepare_flexpart import prepare_flexpart
77
78# ------------------------------------------------------------------------------
79# METHODS
80# ------------------------------------------------------------------------------
81
82def main():
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    ----------
90
91
92    Return
93    ------
94
95    '''
96
97    c, ppid, queue, job_template = setup_controldata()
98
99    # on local side
100    # starting from an ECMWF server this would also be the local side
101    called_from_dir = os.getcwd()
102    if queue is None:
103        if c.inputdir[0] != '/':
104            c.inputdir = os.path.join(called_from_dir, c.inputdir)
105        if c.outputdir[0] != '/':
106            c.outputdir = os.path.join(called_from_dir, c.outputdir)
107        get_mars_data(c)
108        if c.request == 0 or c.request == 2:
109            prepare_flexpart(ppid, c)
110            exit_message = 'FLEX_EXTRACT IS DONE!'
111        else:
112            exit_message = 'PRINTING MARS_REQUESTS DONE!'
113    # send files to ECMWF server
114    else:
115        submit(job_template, c, queue)
116        exit_message = 'FLEX_EXTRACT JOB SCRIPT IS SUBMITTED!'
117
118    normal_exit(exit_message)
119
120    return
121
122def submit(jtemplate, c, queue):
123    '''Prepares the job script and submits it to the specified queue.
124
125    Parameters
126    ----------
127    jtemplate : str
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 _config.TEMPFILE_JOB.
133
134    c : ControlFile
135        Contains all the parameters of CONTROL file and
136        command line.
137
138    queue : str
139        Name of queue for submission to ECMWF (e.g. ecgate or cca )
140
141    Return
142    ------
143
144    '''
145
146    if not c.oper:
147    # --------- create on demand job script ------------------------------------
148        if c.purefc:
149            print('---- Pure forecast mode! ----')
150        else:
151            print('---- On-demand mode! ----')
152
153        job_file = os.path.join(_config.PATH_JOBSCRIPTS,
154                                _config.FILE_JOB_OD)
155
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)
162            oneday = timedelta(days=1)
163
164            while start <= end:
165                if (start + chunk) <= end:
166                    c.end_date = (start + chunk - oneday).strftime("%Y%m%d")
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()))
186
187    else:
188    # --------- create operational job script ----------------------------------
189        print('---- Operational mode! ----')
190
191        job_file = os.path.join(_config.PATH_JOBSCRIPTS,
192                                _config.FILE_JOB_OP)
193
194        c.start_date = '${MSJ_YEAR}${MSJ_MONTH}${MSJ_DAY}'
195        c.end_date = '${MSJ_YEAR}${MSJ_MONTH}${MSJ_DAY}'
196        c.basetime = '${MSJ_BASETIME}'
197        if c.maxstep > 24:
198            c.time = '${MSJ_BASETIME} {MSJ_BASETIME}'
199
200        clist = c.to_list()
201
202        mk_jobscript(jtemplate, job_file, clist)
203
204        #job_id = submit_job_to_ecserver(queue, job_file)
205        job_id = submit_eventjob_to_ecserver(queue, c.eventjobname,
206                                             c.eventid, c.ecuid)
207
208        print('The job id is: ' + str(job_id.strip()))
209
210    print('You should get an email per job with subject flex.hostname.pid')
211
212    return
213
214def mk_jobscript(jtemplate, job_file, clist):
215    '''Creates the job script from template.
216
217    Parameters
218    ----------
219    jtemplate : str
220        Job template file from sub-directory "Templates" for
221        submission to ECMWF. It contains all necessary
222        module and variable settings for the ECMWF environment as well as
223        the job call and mail report instructions.
224        Default is _config.TEMPFILE_JOB.
225
226    job_file : str
227        Path to the job script file.
228
229    clist : list of str
230        Contains all necessary parameters for ECMWF CONTROL file.
231
232    Return
233    ------
234
235    '''
236    from genshi.template.text import NewTextTemplate
237    from genshi.template import  TemplateLoader
238    from genshi.template.eval import UndefinedError
239
240    # load template and insert control content as list
241    try:
242        loader = TemplateLoader(_config.PATH_TEMPLATES, auto_reload=False)
243        control_template = loader.load(jtemplate,
244                                       cls=NewTextTemplate)
245
246        stream = control_template.generate(control_content=clist)
247    except UndefinedError as e:
248        print('... ERROR ' + str(e))
249
250        sys.exit('\n... error occured while trying to generate jobscript')
251    except OSError as e:
252        print('... ERROR CODE: ' + str(e.errno))
253        print('... ERROR MESSAGE:\n \t ' + str(e.strerror))
254
255        sys.exit('\n... error occured while trying to generate jobscript')
256
257    # create jobscript file
258    try:
259        with open(job_file, 'w') as f:
260            f.write(stream.render('text'))
261    except OSError as e:
262        print('... ERROR CODE: ' + str(e.errno))
263        print('... ERROR MESSAGE:\n \t ' + str(e.strerror))
264
265        sys.exit('\n... error occured while trying to write ' + job_file)
266
267    return
268
269
270if __name__ == "__main__":
271    main()
Note: See TracBrowser for help on using the repository browser.
hosted by ZAMG