How To Write a Template¶
autojob uses Jinja2 to template task and calculation scripts. For details
on syntax, please see the Jinja2 documentation.
How to Structure Script Templates¶
Although autojob does not
place any restrictions on the structure of task and calculation scripts, we
have found that the following structure for task scripts works quite well:
Specify scheduler resources
Configure environment: load modules, activate virtual environment, define environment variables
Execute task: CLI command or by calling calculation script,
autojob runHarvest task results:
autojob harvestClean up directory:
autojob cleanAdvance workflow:
autojob restartandautojob advance
For calculation scripts, the only requirement is that upon successful execution,
calculation scripts should write an output trajectory file to
SETTINGS.OUTPUT_ATOMS_FILE. For example,
# my_run.py.j2
from ase.calculators.emt import EMT
import ase.io
atoms = ase.io.read({{ task_inputs.atoms_filename }})
atoms.calc = EMT()
atoms.calc.calculate(atoms, properties=["energy"])
atoms.write({{ settings.OUTPUT_ATOMS_FILE }})
When this template is rendered, {{ task_inputs.atoms_filename }} will be
replaced with the input atoms filename of the task whose inputs are being written.
Similarly, {{ settings.OUTPUT_ATOMS_FILE }} will be replaced with the default
output atoms filename.
See also
How to Access Task Attributes¶
In autojob-defined tasks, the InputWriter protocol is implemented
such that task and calculation script templates are passed each attribute of the
task as a variable to the Jinja context. That is, the task_metadata can
be accessed in templates via the variable task_metadata, and the name of the
input atoms filename can be accessed in templates as task_inputs.atoms_filename.
In addition, script templates are passed the values of autojob settings so that
the name of the default archive file can be accessed as settings.ARCHIVE_FILE.
#!/bin/bash
# my_task_script.sh.j2
{% for x in task_inputs.items() %}
echo {{ x }}
{% endfor %}
{% for x in task_metadata.items() %}
echo {{ x }}
{% endfor %}
{% for x in settings.items() %}
echo {{ x }}
{% endfor %}
cp {{ task_inputs.atoms_filename }} {{ settings.OUTPUT_ATOMS_FILE }}
autojob harvest
The task script template above, my_task_script.sh.j2, will generate as task script
that will print out the task inputs, task metadata, and settings active when the
task script is written to a file. In addition, the task script will copy the
input atoms file to a filename matching the default output atoms filename and then
run autojob harvest.
How to Specify SLURM Parameters¶
autojob specially formats the keys and values of SchedulerInputs fields
for use in task scripts. SLURM submission scripts must specify resource requirements
as comments that precede any executable code. To do write task scripts that can
be submitted with SLURM, try the following:
#!/bin/bash
# my_task_script.sh.j2
{% if scheduler_inputs %}
{% for key, value in scheduler_inputs.items() %}
{% if value %}
#SBATCH {{ key }}={{ value }}
{% endif %}
{% endfor %}
{% endif %}
How to Write Auto-Restarting Templates¶
autojob run is a CLI utility that can be used to run timed commands within
task scripts.
autojob run --buffer=0.1 --time-source=run.sh 'python run.py'
When executed within a task script in which scheduler inputs are specified as
outlined in How to Specify SLURM Parameters, the snippet above will execute the command
python run.py with a time limit. The time limit will be determined by
reading the value of the --time SLURM option set in the run.sh script.
Specifically, autojob run will allow the command to run for 10% of the
total time specified by --time. If the argument to --buffer is greater
than 1, then it will be interpreted as the number of seconds to leave at the
end of the total time. To take advantage of templating, autojob run should
be incorporated into task script templates like so:
autojob run --buffer=0.1 --time-source={{ task_inputs.task_script }} 'python {{ calculation_inputs.calculation_script }}'
To set the time limit by directly templating the scheduler input value, use this snippet:
autojob run --buffer=0.1 --time={{ scheduler_inputs.time }} 'python {{ calculation_inputs.calculation_script }}'
autojob run exits with code 124 if the time limit was reached. That means
that task scripts can check this exit code and use it determine whether to
restart or advance the task. For example,
#!/bin/bash
# my_task_script.sh.j2
...
autojob run --buffer=0.1 --time={{ scheduler_inputs.time }} 'python {{ calculation_inputs.calculation_script }}'
exit_code=$?
...
if [ $exit_code = 124 ]; then
autojob restart; else;
autojob advance; fi
...
An example of this logic can also be found in the calc.sh.j2 template.
Tip
Type autojob run -h into the terminal for more complete help.