Skip to content

Commit 2c7a1f0

Browse files
committed
move batch_jobs to workflow_jobs
1 parent 6704570 commit 2c7a1f0

File tree

11 files changed

+208
-134
lines changed

11 files changed

+208
-134
lines changed

config/cesm/config_files.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@
5151
<schema>$CIMEROOT/config/xml_schemas/config_batch.xsd</schema>
5252
</entry>
5353

54+
<entry id="WORKFLOW_SPEC_FILE">
55+
<type>char</type>
56+
<default_value>$CIMEROOT/config/$MODEL/machines/config_workflow.xml</default_value>
57+
<group>case_last</group>
58+
<file>env_case.xml</file>
59+
<desc>file containing workflow (for documentation only - DO NOT EDIT)</desc>
60+
<schema>$CIMEROOT/config/xml_schemas/config_workflow.xsd</schema>
61+
</entry>
62+
5463
<entry id="INPUTDATA_SPEC_FILE">
5564
<type>char</type>
5665
<default_value>$CIMEROOT/config/$MODEL/config_inputdata.xml</default_value>

config/cesm/machines/config_batch.xml

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0"?>
2-
<config_batch version="2.0">
2+
<config_batch version="2.1">
33
<!--
44
File: config_batch.xml
55
Purpose: abstract out the parts of run scripts that are different, and use this configuration to
@@ -541,25 +541,4 @@
541541
<queue walltimemax="00:60:00" nodemin="1" nodemax="50" default="true">default</queue>
542542
</queues>
543543
</batch_system>
544-
545-
<batch_jobs>
546-
<!-- order matters, with no-batch jobs will be run in the order listed here -->
547-
<job name="case.run">
548-
<template>template.case.run</template>
549-
<prereq>$BUILD_COMPLETE and not $TEST</prereq>
550-
</job>
551-
<job name="case.test">
552-
<template>template.case.test</template>
553-
<prereq>$BUILD_COMPLETE and $TEST</prereq>
554-
</job>
555-
<job name="case.st_archive">
556-
<template>template.st_archive</template>
557-
<task_count>1</task_count>
558-
<walltime>0:20:00</walltime>
559-
<!-- If DOUT_S is true and case.run (or case.test) exits successfully then run st_archive-->
560-
<dependency>case.run or case.test</dependency>
561-
<prereq>$DOUT_S</prereq>
562-
</job>
563-
</batch_jobs>
564-
565544
</config_batch>

config/config_headers.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010
</header>
1111
</file>
1212

13+
<file name="env_workflow.xml">
14+
<header>
15+
These variables may be changed anytime during a run, they
16+
control jobs that will be submitted and their dependancies.
17+
</header>
18+
</file>
19+
1320
<file name="env_case.xml">
1421
<header>
1522
These variables CANNOT BE CHANGED once a case has been created.

config/xml_schemas/config_batch.xsd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<xs:element name="batch_mail_type_flag" type="xs:string"/>
2525
<xs:element name="batch_mail_type" type="xs:string"/>
2626
<xs:element name="batch_mail_default" type="xs:string"/>
27-
<xs:element name="template" type="xs:NCName"/>
27+
<xs:element name="template" type="xs:anyURI"/>
2828
<xs:element name="task_count" type="xs:integer"/>
2929
<xs:element name="walltime" type="xs:string"/>
3030
<xs:element name="dependency" type="xs:string"/>
@@ -37,7 +37,7 @@
3737
<xs:complexType>
3838
<xs:sequence>
3939
<xs:element ref="batch_system" maxOccurs="unbounded" />
40-
<xs:element ref="batch_jobs"/>
40+
<xs:element ref="batch_jobs" minOccurs="0" maxOccurs="1"/>
4141
</xs:sequence>
4242
<xs:attribute ref="version" use="required"/>
4343
</xs:complexType>

scripts/lib/CIME/XML/batch.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,15 @@ def get_batch_jobs(self):
112112
and the second a dict of qualifiers for the job
113113
"""
114114
jobs = []
115-
bnode = self.get_child("batch_jobs")
116-
for jnode in self.get_children(root=bnode):
117-
if self.name(jnode) == "job":
118-
name = self.get(jnode, "name")
119-
jdict = {}
120-
for child in self.get_children(root=jnode):
121-
jdict[self.name(child)] = self.text(child)
122-
123-
jobs.append((name, jdict))
115+
bnode = self.get_optional_child("batch_jobs")
116+
if bnode:
117+
for jnode in self.get_children(root=bnode):
118+
if self.name(jnode) == "job":
119+
name = self.get(jnode, "name")
120+
jdict = {}
121+
for child in self.get_children(root=jnode):
122+
jdict[self.name(child)] = self.text(child)
123+
124+
jobs.append((name, jdict))
124125

125126
return jobs

scripts/lib/CIME/XML/env_batch.py

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@
1515

1616
class EnvBatch(EnvBase):
1717

18-
def __init__(self, case_root=None, infile="env_batch.xml"):
18+
def __init__(self, case_root=None, infile="env_batch.xml", schema=None):
1919
"""
2020
initialize an object interface to file env_batch.xml in the case directory
2121
"""
2222
self._batchtype = None
2323
# This arbitrary setting should always be overwritten
2424
self._default_walltime = "00:20:00"
25-
schema = os.path.join(get_cime_root(), "config", "xml_schemas", "env_batch.xsd")
25+
if not schema:
26+
schema = os.path.join(get_cime_root(), "config", "xml_schemas", "env_batch.xsd")
2627
super(EnvBatch,self).__init__(case_root, infile, schema=schema)
2728

2829
# pylint: disable=arguments-differ
@@ -32,21 +33,6 @@ def set_value(self, item, value, subgroup=None, ignore_type=False):
3233
"""
3334
val = None
3435

35-
if item == "JOB_WALLCLOCK_TIME":
36-
#Most systems use %H:%M:%S format for wallclock but LSF
37-
#uses %H:%M this code corrects the value passed in to be
38-
#the correct format - if we find we have more exceptions
39-
#than this we may need to generalize this further
40-
walltime_format = self.get_value("walltime_format", subgroup=None)
41-
if walltime_format is not None and walltime_format.count(":") != value.count(":"): # pylint: disable=maybe-no-member
42-
if value.count(":") == 1:
43-
t_spec = "%H:%M"
44-
elif value.count(":") == 2:
45-
t_spec = "%H:%M:%S"
46-
else:
47-
expect(False, "could not interpret format for wallclock time {}".format(value))
48-
value = format_time(walltime_format, t_spec, value)
49-
5036
if item == "JOB_QUEUE":
5137
expect(value in self._get_all_queue_names() or ignore_type,
5238
"Unknown Job Queue specified use --force to set")
@@ -214,14 +200,16 @@ def make_batch_script(self, input_template, job, case, outfile=None):
214200
# make sure batch script is exectuble
215201
os.chmod(output_name, os.stat(output_name).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
216202

217-
def set_job_defaults(self, batch_jobs, case):
203+
def set_job_defaults(self, batch_jobs, case, env_workflow=None):
218204
if self._batchtype is None:
219205
self._batchtype = self.get_batch_system_type()
220206

221207
if self._batchtype == "none":
222208
return
223-
224-
known_jobs = self.get_jobs()
209+
if env_workflow:
210+
known_jobs = env_workflow.get_jobs()
211+
else:
212+
known_jobs = self.get_jobs()
225213

226214
for job, jsect in batch_jobs:
227215
if job not in known_jobs:
@@ -281,9 +269,12 @@ def set_job_defaults(self, batch_jobs, case):
281269
walltime = specs[3]
282270

283271
walltime = self._default_walltime if walltime is None else walltime # last-chance fallback
284-
285-
self.set_value("JOB_QUEUE", queue, subgroup=job, ignore_type=specs is None)
286-
self.set_value("JOB_WALLCLOCK_TIME", walltime, subgroup=job)
272+
if env_workflow:
273+
env_workflow.set_value("JOB_QUEUE", queue, subgroup=job, ignore_type=specs is None)
274+
env_workflow.set_value("JOB_WALLCLOCK_TIME", walltime, subgroup=job)
275+
else:
276+
self.set_value("JOB_QUEUE", queue, subgroup=job, ignore_type=specs is None)
277+
self.set_value("JOB_WALLCLOCK_TIME", walltime, subgroup=job)
287278
logger.debug("Job {} queue {} walltime {}".format(job, queue, walltime))
288279

289280
def _match_attribs(self, attribs, case, queue):
@@ -426,8 +417,11 @@ def get_submit_args(self, case, job):
426417

427418
def submit_jobs(self, case, no_batch=False, job=None, user_prereq=None, skip_pnl=False,
428419
allow_fail=False, resubmit_immediate=False, mail_user=None, mail_type=None,
429-
batch_args=None, dry_run=False):
430-
alljobs = self.get_jobs()
420+
batch_args=None, dry_run=False, runwithcylc=False):
421+
if runwithcylc:
422+
alljobs = [job]
423+
else:
424+
alljobs = self.get_jobs()
431425
startindex = 0
432426
jobs = []
433427
firstjob = job
@@ -439,15 +433,20 @@ def submit_jobs(self, case, no_batch=False, job=None, user_prereq=None, skip_pnl
439433
logger.debug( "Index {:d} job {} startindex {:d}".format(index, job, startindex))
440434
if index < startindex:
441435
continue
442-
try:
443-
prereq = self.get_value('prereq', subgroup=job, resolved=False)
444-
if prereq is None or job == firstjob or (dry_run and prereq == "$BUILD_COMPLETE"):
445-
prereq = True
446-
else:
447-
prereq = case.get_resolved_value(prereq)
448-
prereq = eval(prereq)
449-
except:
450-
expect(False,"Unable to evaluate prereq expression '{}' for job '{}'".format(self.get_value('prereq',subgroup=job), job))
436+
jobfile = get_batch_script_for_job(job)
437+
if not os.path.isfile(jobfile):
438+
logger.info("Jobfile {} not found in case, skipping job step".format(jobfile))
439+
prereq = False
440+
else:
441+
try:
442+
prereq = self.get_value('prereq', subgroup=job, resolved=False)
443+
if prereq is None or job == firstjob or (dry_run and prereq == "$BUILD_COMPLETE"):
444+
prereq = True
445+
else:
446+
prereq = case.get_resolved_value(prereq)
447+
prereq = eval(prereq)
448+
except:
449+
expect(False,"Unable to evaluate prereq expression '{}' for job '{}'".format(self.get_value('prereq',subgroup=job), job))
451450

452451
if prereq:
453452
jobs.append((job, self.get_value('dependency', subgroup=job)))
@@ -489,7 +488,7 @@ def submit_jobs(self, case, no_batch=False, job=None, user_prereq=None, skip_pnl
489488
resubmit_immediate=resubmit_immediate,
490489
dep_jobs=dep_jobs,
491490
allow_fail=allow_fail,
492-
no_batch=no_batch,
491+
no_batch=no_batch or runwithcylc,
493492
mail_user=mail_user,
494493
mail_type=mail_type,
495494
batch_args=batch_args,
@@ -874,6 +873,14 @@ def make_all_batch_files(self, case):
874873
machdir = case.get_value("MACHDIR")
875874
logger.info("Creating batch scripts")
876875
for job in self.get_jobs():
877-
input_batch_script = os.path.join(machdir,self.get_value('template', subgroup=job))
878-
logger.info("Writing {} script from input template {}".format(job, input_batch_script))
879-
self.make_batch_script(input_batch_script, job, case)
876+
template = self.get_value('template', subgroup=job)
877+
template = template.replace('$CASEROOT', self._caseroot)
878+
if os.path.isabs(template):
879+
input_batch_script = template
880+
else:
881+
input_batch_script = os.path.join(machdir,template)
882+
if os.path.isfile(input_batch_script):
883+
logger.info("Writing {} script from input template {}".format(job, input_batch_script))
884+
self.make_batch_script(input_batch_script, job, case)
885+
else:
886+
logger.warning("Input template file {} for job {} does not exist or cannot be read.".format(input_batch_script, job))

scripts/lib/CIME/XML/generic_xml.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ def scan_optional_child(self, nodename, attributes=None, root=None):
332332
"""
333333
nodes = self.scan_children(nodename, attributes=attributes, root=root)
334334

335-
expect(len(nodes) <= 1, "Multiple matches for nodename '{}' and attrs '{}' in file '{}'".format(nodename, attributes, self.filename))
335+
expect(len(nodes) <= 1, "Multiple matches for nodename '{}' and attrs '{}' in file '{}', found {} matches".format(nodename, attributes, self.filename, len(nodes)))
336336
return nodes[0] if nodes else None
337337

338338
def scan_children(self, nodename, attributes=None, root=None):

scripts/lib/CIME/case/case.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from CIME.XML.compsets import Compsets
2323
from CIME.XML.grids import Grids
2424
from CIME.XML.batch import Batch
25+
from CIME.XML.workflow import Workflow
2526
from CIME.XML.pio import PIO
2627
from CIME.XML.archive import Archive
2728
from CIME.XML.env_test import EnvTest
@@ -32,6 +33,7 @@
3233
from CIME.XML.env_run import EnvRun
3334
from CIME.XML.env_archive import EnvArchive
3435
from CIME.XML.env_batch import EnvBatch
36+
from CIME.XML.env_workflow import EnvWorkflow
3537
from CIME.XML.generic_xml import GenericXML
3638
from CIME.user_mod_support import apply_user_mods
3739
from CIME.aprun import get_aprun_cmd_for_case
@@ -201,6 +203,7 @@ def read_xml(self):
201203
self._env_entryid_files.append(EnvBuild(self._caseroot, components=components))
202204
self._env_entryid_files.append(EnvMachPes(self._caseroot, components=components))
203205
self._env_entryid_files.append(EnvBatch(self._caseroot))
206+
self._env_entryid_files.append(EnvWorkflow(self._caseroot))
204207
if os.path.isfile(os.path.join(self._caseroot,"env_test.xml")):
205208
self._env_entryid_files.append(EnvTest(self._caseroot, components=components))
206209
self._env_generic_files = []
@@ -939,19 +942,28 @@ def configure(self, compset_name, grid_name, machine_name=None,
939942

940943
batch_system_type = machobj.get_value("BATCH_SYSTEM")
941944
logger.info("Batch_system_type is {}".format(batch_system_type))
942-
batch = Batch(batch_system=batch_system_type, machine=machine_name)
945+
batch = Batch(batch_system=batch_system_type, machine=machine_name, files=files)
943946
bjobs = batch.get_batch_jobs()
947+
# Workflow is optional in cime5.6 to support backward compatibility
948+
# it was originally part of the config_batch/env_batch file.
949+
workflow = None
950+
if not bjobs:
951+
workflow = Workflow(files=files)
952+
bjobs = workflow.get_workflow_jobs()
953+
env_workflow = self.get_env("workflow")
944954

945955
env_batch.set_batch_system(batch, batch_system_type=batch_system_type)
946-
env_batch.create_job_groups(bjobs, test)
956+
if workflow:
957+
env_workflow.create_job_groups(bjobs, test)
958+
else:
959+
env_batch.create_job_groups(bjobs, test)
960+
env_batch.set_job_defaults(bjobs, self)
947961

948962
if walltime:
949963
self.set_value("USER_REQUESTED_WALLTIME", walltime, subgroup=self.get_primary_job())
950964
if queue:
951965
self.set_value("USER_REQUESTED_QUEUE", queue, subgroup=self.get_primary_job())
952966

953-
env_batch.set_job_defaults(bjobs, self)
954-
955967
# Make sure that parallel IO is not specified if total_tasks==1
956968
if self.total_tasks == 1:
957969
for compclass in self._component_classes:
@@ -1364,6 +1376,8 @@ def set_file(self, xmlfile):
13641376
new_env_file = EnvMachPes(infile=xmlfile, components=components)
13651377
elif ftype == "env_batch.xml":
13661378
new_env_file = EnvBatch(infile=xmlfile)
1379+
elif ftype == "env_workflow.xml":
1380+
new_env_file = EnvWorkflow(infile=xmlfile)
13671381
elif ftype == "env_test.xml":
13681382
new_env_file = EnvTest(infile=xmlfile)
13691383
if new_env_file is not None:

src/drivers/mct/cime_config/config_component.xml

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2607,64 +2607,6 @@
26072607
<desc>External script to be run after model completion</desc>
26082608
</entry>
26092609

2610-
<!-- Job Submission stuff -->
2611-
<entry id="USER_REQUESTED_QUEUE">
2612-
<type>char</type>
2613-
<group>job_submission</group>
2614-
<file>env_batch.xml</file>
2615-
<desc>Store user override for queue</desc>
2616-
</entry>
2617-
2618-
<entry id="USER_REQUESTED_WALLTIME">
2619-
<type>char</type>
2620-
<group>job_submission</group>
2621-
<file>env_batch.xml</file>
2622-
<desc>Store user override for walltime</desc>
2623-
</entry>
2624-
2625-
<entry id="JOB_QUEUE">
2626-
<type>char</type>
2627-
<valid_values></valid_values>
2628-
<default_value></default_value>
2629-
<group>job_submission</group>
2630-
<file>env_batch.xml</file>
2631-
<desc>The machine queue in which to submit the job. Default determined in config_machines.xml can be overwritten by testing</desc>
2632-
</entry>
2633-
2634-
<entry id="JOB_WALLCLOCK_TIME">
2635-
<type>char</type>
2636-
<valid_values></valid_values>
2637-
<default_value></default_value>
2638-
<group>job_submission</group>
2639-
<file>env_batch.xml</file>
2640-
<desc>The machine wallclock setting. Default determined in config_machines.xml can be overwritten by testing</desc>
2641-
</entry>
2642-
2643-
<entry id="BATCH_COMMAND_FLAGS">
2644-
<type>char</type>
2645-
<valid_values></valid_values>
2646-
<default_value></default_value>
2647-
<group>job_submission</group>
2648-
<file>env_batch.xml</file>
2649-
<desc>Override the batch submit command this job. Do not include executable or dependencies</desc>
2650-
</entry>
2651-
2652-
<entry id="PROJECT">
2653-
<type>char</type>
2654-
<default_value></default_value>
2655-
<group>job_submission</group>
2656-
<file>env_batch.xml</file>
2657-
<desc>project for project-sensitive build and run paths, and job scripts</desc>
2658-
</entry>
2659-
2660-
<entry id="CHARGE_ACCOUNT">
2661-
<type>char</type>
2662-
<default_value></default_value>
2663-
<group>job_submission</group>
2664-
<file>env_batch.xml</file>
2665-
<desc>project to charge in scripts if different from PROJECT</desc>
2666-
</entry>
2667-
26682610
<entry id="MODEL_VERSION">
26692611
<type>char</type>
26702612
<default_value>unknown</default_value>

0 commit comments

Comments
 (0)