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

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

updated rrint processes (added missing rr for ensembles and wrote all precip fields into the output files with different steps to distingush)

  • Property mode set to 100755
File size: 8.7 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#
24# @License:
25#    (C) Copyright 2014-2019.
26#    Anne Philipp, Leopold Haimberger
27#
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.
32#*******************************************************************************
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'''
56
57# ------------------------------------------------------------------------------
58# MODULES
59# ------------------------------------------------------------------------------
60import os
61import sys
62import subprocess
63import inspect
64import collections
65from datetime import datetime, timedelta
66
67# software specific classes and modules from flex_extract
68import _config
69from mods.tools import (setup_controldata, normal_exit, get_cmdline_args,
70                         submit_job_to_ecserver, read_ecenv)
71from mods.get_mars_data import get_mars_data
72from mods.prepare_flexpart import prepare_flexpart
73from classes.ControlFile import ControlFile
74
75
76# ------------------------------------------------------------------------------
77# METHODS
78# ------------------------------------------------------------------------------
79
80def main():
81    '''Get the arguments from script call and from CONTROL file.
82    Decides from the argument "queue" if the local version
83    is done "queue=None" or the gateway version with "queue=ecgate"
84    or "queue=cca".
85
86    Parameters
87    ----------
88
89
90    Return
91    ------
92
93    '''
94
95    c, ppid, queue, job_template = setup_controldata()
96
97    # on local side
98    # starting from an ECMWF server this would also be the local side
99    called_from_dir = os.getcwd()
100    if queue is None:
101        if c.inputdir[0] != '/':
102            c.inputdir = os.path.join(called_from_dir, c.inputdir)
103        if c.outputdir[0] != '/':
104            c.outputdir = os.path.join(called_from_dir, c.outputdir)
105        get_mars_data(c)
106        if c.request == 0 or c.request == 2:
107            prepare_flexpart(ppid, c)
108            exit_message = 'FLEX_EXTRACT IS DONE!'
109        else:
110            exit_message = 'PRINTING MARS_REQUESTS DONE!'
111    # send files to ECMWF server
112    else:
113        submit(job_template, c, queue)
114        exit_message = 'FLEX_EXTRACT JOB SCRIPT IS SUBMITED!'
115
116    normal_exit(exit_message)
117
118    return
119
120def submit(jtemplate, c, queue):
121    '''Prepares the job script and submits it to the specified queue.
122
123    Parameters
124    ----------
125    jtemplate : str
126        Job template file from sub-directory "_templates" for
127        submission to ECMWF. It contains all necessary
128        module and variable settings for the ECMWF environment as well as
129        the job call and mail report instructions.
130        Default is "job.temp".
131
132    c : ControlFile
133        Contains all the parameters of CONTROL file and
134        command line.
135
136    queue : str
137        Name of queue for submission to ECMWF (e.g. ecgate or cca )
138
139    Return
140    ------
141
142    '''
143
144    if not c.oper:
145    # --------- create on demand job script ------------------------------------
146        if c.purefc:
147            print('---- Pure forecast mode! ----')
148        else:
149            print('---- On-demand mode! ----')
150
151        job_file = os.path.join(_config.PATH_JOBSCRIPTS,
152                                jtemplate[:-5] + '.ksh')
153
154        # divide time periode into specified number of job chunks
155        # to have multiple job scripts
156        if c.job_chunk:
157            start = datetime.strptime(c.start_date, '%Y%m%d')
158            end = datetime.strptime(c.end_date, '%Y%m%d')
159            chunk = timedelta(days=c.job_chunk)
160            oneday = timedelta(days=1)
161
162            while start <= end:
163                if (start + chunk) <= end:
164                    c.end_date = (start + chunk - oneday).strftime("%Y%m%d")
165                else:
166                    c.end_date = end.strftime("%Y%m%d")
167
168                clist = c.to_list()
169                mk_jobscript(jtemplate, job_file, clist)
170
171                job_id = submit_job_to_ecserver(queue, job_file)
172                print('The job id is: ' + str(job_id.strip()))
173
174                start = start + chunk
175                c.start_date = start.strftime("%Y%m%d")
176        # submit a single job script
177        else:
178            clist = c.to_list()
179
180            mk_jobscript(jtemplate, job_file, clist)
181
182            job_id = submit_job_to_ecserver(queue, job_file)
183            print('The job id is: ' + str(job_id.strip()))
184
185    else:
186    # --------- create operational job script ----------------------------------
187        print('---- Operational mode! ----')
188
189        job_file = os.path.join(_config.PATH_JOBSCRIPTS,
190                                jtemplate[:-5] + 'oper.ksh')
191
192        c.start_date = '${MSJ_YEAR}${MSJ_MONTH}${MSJ_DAY}'
193        c.end_date = '${MSJ_YEAR}${MSJ_MONTH}${MSJ_DAY}'
194        c.basetime = '${MSJ_BASETIME}'
195        if c.maxstep > 24:
196            c.time = '${MSJ_BASETIME} {MSJ_BASETIME}'
197
198        clist = c.to_list()
199
200        mk_jobscript(jtemplate, job_file, clist)
201
202        job_id = submit_job_to_ecserver(queue, job_file)
203        print('The job id is: ' + str(job_id.strip()))
204
205    print('You should get an email per job with subject flex.hostname.pid')
206
207    return
208
209def mk_jobscript(jtemplate, job_file, clist):
210    '''Creates the job script from template.
211
212    Parameters
213    ----------
214    jtemplate : str
215        Job template file from sub-directory "_templates" for
216        submission to ECMWF. It contains all necessary
217        module and variable settings for the ECMWF environment as well as
218        the job call and mail report instructions.
219        Default is "job.temp".
220
221    job_file : str
222        Path to the job script file.
223
224    clist : list of str
225        Contains all necessary parameters for ECMWF CONTROL file.
226
227    Return
228    ------
229
230    '''
231    from genshi.template.text import NewTextTemplate
232    from genshi.template import  TemplateLoader
233    from genshi.template.eval import UndefinedError
234
235    # load template and insert control content as list
236    try:
237        loader = TemplateLoader(_config.PATH_TEMPLATES, auto_reload=False)
238        control_template = loader.load(jtemplate,
239                                       cls=NewTextTemplate)
240
241        stream = control_template.generate(control_content=clist)
242    except UndefinedError as e:
243        print('... ERROR ' + str(e))
244
245        sys.exit('\n... error occured while trying to generate jobscript')
246    except OSError as e:
247        print('... ERROR CODE: ' + str(e.errno))
248        print('... ERROR MESSAGE:\n \t ' + str(e.strerror))
249
250        sys.exit('\n... error occured while trying to generate jobscript')
251
252    # create jobscript file
253    try:
254        with open(job_file, 'w') as f:
255            f.write(stream.render('text'))
256    except OSError as e:
257        print('... ERROR CODE: ' + str(e.errno))
258        print('... ERROR MESSAGE:\n \t ' + str(e.strerror))
259
260        sys.exit('\n... error occured while trying to write ' + job_file)
261
262    return
263
264
265if __name__ == "__main__":
266    main()
Note: See TracBrowser for help on using the repository browser.
hosted by ZAMG