ESM Runscripts - Using the Workflow Manager
Introduction
Starting with Release 6.0, esm_runscripts allows to define additional phases for e.g. data processing, coupling. Such subjobs can be arranged into clusters, and the order of execution can be set in a flexible and short way from the runscript. This is applicable for both pre- and postprocessing, but especially useful for iterative coupling jobs, like e.g. coupling pism to vilma (see below). In this section we explain the basic concept, describe the keywords that have to be set in the runscript in order to make use of this feature, and give some examples on how to integrate pre- and postprocessing jobs and how to set up phases for iterative coupling.
Default phases of a general model simulation run
ESM-Tools uses the workflow manager itself to organize the default workflow phases of a simulation run. Since Release 6.0 the default workflow phases are the following:
newrun --> prepcompute --> compute --> observe_compute --> tidy (+ resubmit next run)
These standard phases are all separated and independant phases, each submitted (or started) by the previous phase in one of three ways (see below). Here is what each of the standard phases does:
Phase |
Function |
Started by |
---|---|---|
newrun |
Initializes a new experiment, only very basic stuff, like creating (empty) folders needed by any of the following subjobs/phases. NEEDS TO BE THE FIRST SUBJOB/PHASE OF ANY EXPERIMENT. |
|
prepcompute |
Prepares the compute job. All the (Python) functionality that needs to be run, up to the job submission. Includes copying files, editing namelists, write batch scripts, etc. |
|
compute |
Actual model integration, nothing else. No Python codes involved. |
sbatch |
observe_compute |
Python job running at the same time as compute, checking if the compute job is still running, looking for some known errors for monitoring / job termination. |
sbatch (compute), started by its own esm_runscripts call |
tidy |
Sorts the produced outputs, restarts and log files into the correct folders, checks for missing and unknown files, builds coupler restart files if not present |
observe_compute |
It is important to understand that none of this has to be edited by the users. The above described workflow phases form the default set of phases. Changing anyone of these phases may lead esm-tools to fail.
Inspect workflow phases
To inspect the workflow and workflow phases that are defined by e.g. a choosen setup or in an already run simulation/experiment, you can run esm_runscript with the -i (–inspect) option. This can be done for two different cases:
To inspect the workflow previous to running a certain experiment. For exampl, if you want to add a new workflow phase, and need to know which phases are already defined in a choosen setup or model configuration:
esm_runscripts runscript.yaml -i workflow
To inspect a workflow from an experiment that has beed carried out already or created during a check-run (-c):
esm_runscripts runscript.yaml -e <expid> -i workflow
It will display the workflow configuration showing the order of workflow phases and their attributes and possible dependencies. This output should help to find out the correct keyworkds to be set when integrating a new workflow phase.
Example output:
Workflow sequence (cluster [phases])
------------------------------------
prepcompute ['prepcompute'] -> compute ['compute'] -> tidy ['tidy'] -> prepcompute ['prepcompute'] and my_own_new_cluster ['my_new_last_phase', 'my_second_new_phase']
Defining additional workflow phases
If it is necessary to complement the default workflow with simulation specific processing steps, this sequence of default workflow phases can be extended by adapting the runscipt or any component specific configuration files. The workflow manager will evaluate these additional phases and integrate them into the default sequence of the workflow. In order to integrate the additional phases correctly, theses phases have to be defined by providing the following information. In the following, we will explain how an additional phase can be defined by describing the necessary keywords and what kind of restrictions need to be taken into account.
- In order to integrate a user defined phase into the default workflow, the following information need to be provided:
Name of the script to be run
Name of the python script used for setting up the environment
Path to the folder in which both of the above scripts can be found
Information on how often the phase should be called
Information about between which other phases the new user defined phase is to be inserted into the workflow
In case it isn’t clear: Which phase should resubmit the next run.
- In general, a workflow can be defined in the runscript or in any component configuration file. But there are some restrictions to the definition that needs to be taken into account:
The name of each phase needs to be unique. Otherwise, an exception error will be raised.
The names of the default phases are not allowed to be used for any new phases. This will also cause an exception error during runtime.
Settings in the runscript will overwrite settings in other config files. (See also Hierarchy of YAML configuration files.)
Keywords to define a new workflow phase
To define a new phase, the following keywords and mappings (key/value pairs) are available. (Keywords that are indicated with < >
need to be adapted by the user.)
Keyword |
Mandatory |
(Default) values |
Function |
---|---|---|---|
workflow |
yes |
– |
Chapter headline in a runscript or configuration section, indicating that an alterations to the standard workflow will be defined here. |
phases |
yes |
user defined string |
Section within the |
<new_phase_name> |
yes |
user defined string |
Section within the |
run_after: <value> or run_before: <value> |
no |
default: last phase in (default) workflow (e.g. tidy) |
Key/value entry in each |
submit_to_batch_system: <value> |
no |
false, true |
Key/value entry in each |
run_on_queue: <value> |
no |
None |
Key/value entry in each |
batch_or_shell: <value> |
no |
shell, batch |
Key/value entry in each |
cluster: <value> |
no |
Phase name |
Key/value entry in each |
order_in_cluster: <value> |
no |
sequential, concurrent |
Key/value entry in each |
script: <value> |
yes |
None |
Key/value entry in each |
script_dir: <value> |
yes |
None |
Key/value entry in each |
call_function: <value> |
no |
None |
Key/value entry in each |
env_preparation: <value> |
no |
None |
Key/value entry in each |
nproc: <value> |
no |
1 |
Key/value entry in each |
run_only: <value> |
no |
None |
Key/value entry in each |
skip_chunk_number: <value> |
no |
None |
Key/value entry in each |
trigger_next_run: <value> |
no |
false, true |
If phase should trigger next run |
Syntax example
The following code snippet shows the general syntax for defining a new workflow phase.
workflow:
phases:
<new_phase_name>:
run_after: <value>
submit_to_batch_system: <value>
run_on_queue: <value>
cluster: <value>
order_in_cluster: <value>
script: <value>
call_function: <value>
env_preparation: <value>
nproc: <value>
run_only: <value>
skip_chunk_number: <value>
trigger_next_run: <value>
Workflow defaults
A minimal example of defining a new workflow phase is given in Example 1. This will integrate a new phase with the following default assumptions:
The new phase will be run after the last phase of the default workflow.
The script given for this phase is run as a subprocess (not a batch run).
The next run of the overall experiment will be (still) triggered by the last phase of the default workflow and not the new phase.
Examples for the definition of new workflow phases
Example 1: Adding an additional postprocessing subjob
In the case of a simple postprocessing task (here for model Echam), that sould be run as the last task of each run, independantly from restarting the experiment, the corresponding minimal code snippet in a runscript could look like this:
echam:
[...other information...]
workflow:
phases:
my_postprocessing:
script_dir: <value>
script: <values>
Example 2: Adding an additional preprocessing subjob
A preprocessing job basically is configured the same way as a postprocessing job, but the run_before keyword is needed now, to define when the new phase should be run:
echam:
[...other information...]
workflow:
phases:
my_preprocessing:
run_before: prepcompute
script_dir: <value>
script: <values>
Example 3: Adding a new phase as the last task in a run
To integrate a new phase that should be run as the last task in every run but before the next run starts, use the following example:
echam:
[...other information...]
workflow:
phases:
my_new_last_phase:
script_dir: <value>
script: <values>
trigger_next_run: True
Example 4: Adding multiple user phases that can be run concurrently in a workflow cluster
It is possible to define multiple new phases that should start at the same but can be run independently from each other. This can be done by assigning these phases to the same workflow cluster and run them concurrently over the batch system:
echam:
[...other information...]
workflow:
phases:
my_new_last_phase:
script_dir: <value>
script: <values>
submit_to_batch_system: True
run_on_queue: <value>
cluster: my_own_new_cluster
my_second_new_phase:
script_dir: <value>
script: <values>
submit_to_batch_system: True
run_on_queue: <value>
cluster: my_own_new_cluster
Example 5: Adding an iterative coupling job
Writing a runscript for iterative coupling using the workflow manager requires some more changes. The principal idea is that each coupling step consists of two data processing jobs, one pre- and one postprocessing job. This is done this way as to make the coupling modular, and enable the modeller to easily replace one of the coupled components by a different implementation. This is of course up to the user to decide, but we generally advise to do so, and the iterative couplings distributed with ESM-Tools are organized this way.
echam:
[...other information...]
workflow:
subjobs:
couple_in:
nproc: 1
run_before: prepcompute
script: coupling_ice2echam.functions
script_dir: ${general.script_dir}/echam
call_function: ice2echam
env_preparation: env_echam.py
run_only: first_run_in_chunk
skip_chunk_number: 1
couple_out:
nproc: 1
run_after: tidy
script: coupling_echam2ice.functions
script_dir: ${general.script_dir}/echam
call_function: echam2ice
env_preparation: env_echam.py
run_only: last_run_in_chunk
trigger_next_run: True
fesom:
[...other information...]
workflow:
subjobs:
couple_in:
nproc: 1
run_before: prepcompute
script: coupling_ice2fesom.functions
script_dir: ${general.script_dir}/fesom
call_function: ice2fesom
env_preparation: env_fesom.py
run_only: first_run_in_chunk
skip_chunk_number: 1
couple_out:
nproc: 1
run_after: tidy
script: coupling_fesom2ice.functions
script_dir: ${general.script_dir}/fesom
call_function: fesom2ice
env_preparation: env_fesom.py
run_only: last_run_in_chunk
trigger_next_run: True