12. Scripting¶
We will focus on bash scripting here, for an example see the mkmh97.sh script. A typical script will contain the following components
hash-bang the first line of the script, and optionally include
nemo_functions.sh
where various convenience functions are maintained
#! /usr/bin/env bash
#
source nemo_functions.sh
and make the script executable
chmod +x script_name
parse the command line, ideally with a NEMO like
keyword=value
- optionally add qtrun directives to also allow to run it with a GUI frontend
run=run1 # directory and run ID #> ENTRY
nbody=1000 # number of bodies #> RADIO 1000,10000,100000,1000000
eps=0.05 # softening #> SCALE 0:1:0.01
and then parsing could be achieved as follows
for arg in "$@"; do
export "$arg"
done
3. optionally, but highly recommended, some matching –HELP tags that can be retrieved using the –help command line option
#--HELP
a=1 # the a value #> SCALE 0:10:1
b=2 # the b value #> SCALE 0:20:2
#--HELP
if [ "$1" == "--help" ] || [ "$1" == "-h" ]; then
set +x
awk 'BEGIN{s=0} {if ($1=="#--HELP") s=1-s; else if(s) print $0; }' $0
exit 0
fi
optionally maintain a set of nemopars or nemovar
_pars=nemopars.rc
save_vars="run nbody"
show_vars $save_vars >> $_pars
source $_pars
echo "a1=$a1" >> $_pars
5. the body of the script, shell variables, nemopars variables etc. should be used where possible.
12.1. Example: Creating a runfile¶
A runfile is a simple text file, where each line in this file can be executed, for example using
bash in a serial fashion. If each line is independant from all others, they can be executed in parallel using
gnu parallel
or sbatch
(a common HPC batch queue system). For example the following command
in NEMO produces a runfile with 4 lines:
mkrunfile.py progname a=1,2 b=2,4 c=10 > example1.run
progname a=1 b=2 c=10
progname a=2 b=2 c=10
progname a=1 b=4 c=10
progname a=2 b=4 c=10
where the example1.run
file can be executed with any of the following commands. Depending on your
resources of course. Memory, number of cores etc.
bash example1.run
parallel -j 4 < example1.run
sbatch_nemo.sh example1.run
in particular the last sbatch_nemo.sh
example will likely need to be tailored for your sbatch based (HPC) system.
Note
Unless the parameters take care of this, you will need to ensure data are written to files that do not
collide with each other. For example a directory or file that encodes the values of the parameters,
or are numerically sorted (e.g. run010, run011)
Currently mkrunfile.py
does not have an automated way for this yet.
And here is an example of creating a runfile from a table with values
awk '{printf("progname runfile=run_%s a=%s b=%s\n", $1,$2,$3) }' example1.tab
12.2. Example: Extracting results from run directories¶
A common workflow is to run a series of simulations and walking over a multi-dimensional parameter space. This usually results into running each simulations in its own run-directory, plus storing parameters and possibly resulting values in a parameter file for later extraction. The directory name could even contain the value of these parameters as well. Several common strategies have been seen in the wild, we list three:
# 1. simply enumerated (e.g id=001,002,003,....) parameters stored inside
run_${id}
# 2. linear list of directories, parameters stored inside
run_${a}_${b}_${c}
# 3. hierarchical directories, parameters stored inside
run/$a/$b/$c
Although easier to visually identify the values of the parameters in 2. and 3., they don’t scale very
well if a new parameter is introduced. In the first case a simple lookup table can be created using
nemopars
, thus making it easier to find which parameters are used in while run directory. Here’s
an example:
nemopars id,a,b,c run_*/nemopars.rc > run.pars
12.3. Summary¶
Summarizing, here are the recommended methods to maintain and extract NEMO variables.
nemopars: extract parameters from a bash-style rc file (python should also be able to use it)
nemovar: get and set NEMOVAR variables
show_vars: alias via nemo_functions.sh