runme performs the preliminary steps needed to run a model program — create a
run directory, copy the executable and parameter files, link input data — and
then runs it, either in the background or by submitting to a SLURM queue. It can
run a single simulation or a whole ensemble, and can generate ensembles by
factorial combination or by sampling parameter distributions.
runme is an installable Python package providing the runme command. It is
self-contained: the ensemble functionality that used to require the separate
runner library (via jobrun) is now built in.
runme builds on the runner package by
Mahé Perrette, a flexible framework for sampling parameters and for running and
analyzing model ensembles. runme reimplements a focused subset of that
functionality — factorial combination, Latin-hypercube and Monte-Carlo sampling,
and ensemble execution — while stripping away the more complex methods (Bayesian
analysis, iterative importance sampling, weighted resampling). Here the ensemble
"run" step is handled simply by calling runme itself, rather than by wrapping a
separate per-simulation script.
If you need those more advanced methods, use the original
perrette/runner package directly.
pip install git+https://github.com/fesmc/runmeThis puts the runme command on your path. To upgrade later, add --upgrade (or
--force-reinstall) to the same command. The only dependencies are numpy and
scipy (used by the ensemble sampling), installed automatically.
Once installed, runme --init scaffolds a project (see below), runme --config
manages your local settings, and runme --list shows the available HPC queues.
The quickest way is runme --init in your model directory. It creates a
.runme/ directory with templates to edit:
cd $MODEL_PATH
runme --init # creates .runme/{info.json, runme_config, queues.json}
# edit .runme/info.json for your model; set hpc/account in .runme/runme_config
runme --config # creates your local .runme_config from the templateRun runme --init again at any time to validate the configuration: it reports
missing files or keys, flags unset placeholders, checks that your hpc exists in
the queues file, and fills in any genuinely-missing template files (without
overwriting existing ones).
The rest of this section explains the files --init scaffolds.
.runme/info.json describes the executables, the parameter files to copy, and
the input folders to link. It is the one genuinely project-specific file:
{
"exe_default" : "libmodel/bin/model.x",
"par_path_as_argument" : true,
"exe_aliases" : { "main" : "libmodel/bin/model.x" },
"grp_aliases" : {},
"par_paths" : { "alias" : "None" },
"files" : ["None"],
"dir-special" : { "None" : "target_dir_name" },
"links" : ["input", "ice_data", "maps"]
}Then create a local .runme_config with your per-host settings (the HPC name,
account, email, OpenMP threads, and the paths to your info and queues files):
{
"hpc" : "dkrz_levante",
"account" : "ba1442",
"jobname" : "model",
"omp" : 16,
"mem" : -1,
"queues_file" : ".runme/queues.json",
"info_file" : ".runme/info.json",
"email" : "",
"mail_type" : ["FAIL", "REQUEUE"]
}That's it. The queues definition and SLURM submit templates are shipped with the
package, so you don't need to copy them into every project. runme resolves each
configuration file through a fallback chain:
- the path given in
.runme_config(your project's.runme/), ~/.config/runme/<name>(a user-wide override),- the default bundled in the package.
So a project usually carries only .runme/info.json and .runme_config. Provide
your own .runme/queues.json or .runme/submit_slurm[_omp] only when you need to
override the packaged defaults.
- Inspect available queues with
runme --list(orrunme --list HPC). - Inspect the active config with
runme --config. - If you use a new HPC not in the packaged
queues.json, add it (and please open an issue/PR so the package stays up to date). On the new cluster's login node,runme check queues [NAME]introspects SLURM (viascontrol/sacctmgr), prints a ready-made block of the(partition, qos, wall)triplets you can actually submit to, and offers to merge it into your queues file. Aliases are guessed from whichever of partition/qos varies, falling back toqueue1, queue2, ...(rename them afterwards) when both vary.
runme -o output/run -n par/model.nml # stage only (create rundir, copy files)
runme -r -o output/run -n par/model.nml # stage and run in the background
runme -s -o output/run -n par/model.nml -q short # stage and write a SLURM submit script
runme -r -s -o output/run -n par/model.nml -q short # stage, write submit script, and sbatch itThe steps carried out are:
- create the run directory,
- copy the executable into it,
- copy the relevant parameter files,
- link the input-data folders,
- run in the background or submit to the queue (or, with neither
-rnor-s, just stage everything).
Parameters can be modified inline with -p KEY=VALUE [KEY=VALUE ...]; the changes
are written to the parameter file copied into the run directory. A -p key must
already exist in one of the parameter files being staged — runme will not create
new parameters, so a typo'd name is reported rather than silently added.
A value may be a vector, written as a bracket literal: -p 'ctl.years=[10,20,30]'
sets a single array-valued parameter (serialized as [10, 20, 30] in TOML/.jl,
space-separated in a namelist). Commas inside the brackets belong to the vector,
not to an ensemble dimension. Quote the entry — [ is a glob character in most
shells.
Parameter files are read and written in the format implied by their extension:
Fortran namelist (.nml, .par), TOML (.toml), JSON (.json), and a flat
line format (.jl) of group.name = value assignments — one per line, which
also happens to be valid Julia (the file includes cleanly when the matching
structs already exist). All use the same group.name keys, so a TOML
[control] table (or a JSON {"control": {...}} object) with tau = 1.0 is
addressed as control.tau, exactly like the namelist group.
For projects whose executable takes the parameter file as an argument
(par_path_as_argument=true), -n names that file: it is copied into the run
directory and passed to the model.
For projects that read their own fixed-name parameter files
(par_path_as_argument=false, e.g. climber-x), -n is optional and acts as
an overlay: the parameters in the named file are merged into the project's
default parameter files. Precedence is
default parameter files → -n overlay → -p overrides
so a -p flag wins over the same parameter set in the overlay file.
A case is just a normal (partial or complete) parameter file (namelist, TOML,
JSON, or .jl) kept in a cases/ folder, capturing a configuration worth
reusing. Use one via -n:
pass its path, or pass a bare name and runme looks it up under cases/
(cases/NAME, or cases/NAME.* when a single file matches, so the extension can
be omitted):
runme -r -o output/run -n spinup # uses cases/spinup(.nml)
runme -r -o output/run -n spinup -p ctl.year=10 # case, then tweak on topBecause a case is loaded through the overlay path above, -p overrides layer on
top of it — handy for running permutations from a saved baseline.
Save the parameters applied in any run directory as a case with:
runme case save NAME -o RUNDIRThis reads RUNDIR/runme.json and writes its applied parameters as a partial
parameter file to cases/NAME — cases/NAME.nml by default, or the format
given by an explicit extension (e.g. NAME.toml). It works for an ensemble
member directory too.
Every run directory — for a single simulation or for each ensemble member — is self-describing and contains:
- the executable, the (parameter-edited) parameter files, and the input-data links;
runme.json— a machine-readable record of the run: the fullrunmecommand, the model command line, the applied parameters, the git revision, and a status (staged/prepared/running/submitted);params.txt— a one-row table of the parameter names and values for this run;info.txt— the same row prefixed with therunidand suffixed with therundir, so a directory can be located and loaded uniformly.
Because single simulations and ensemble members write the same files, downstream tooling can load any run directory the same way.
Any -p value that is a comma list, a range, or a distribution turns the run into
an ensemble. The output directory -o OUTDIR then holds one run directory per
ensemble member:
runme -r -o OUTDIR -n par/model.nml -p ctl.n_accel=1,5,10This runs three simulations in OUTDIR/0, OUTDIR/1, OUTDIR/2. Single-valued
-p entries given alongside ensemble dimensions are fixed overrides applied to
every member:
runme -r -o OUTDIR -n par/model.nml -p ctl.n_accel=1,5,10 ctl.year=5000 smb.alb_ice=0.3,0.4A list of vector values is an ensemble over those vectors — -p ctl.years=[10,20],[30,40]
runs two members, one per vector (whereas -p ctl.years=[10,20] is a single fixed
vector on every run).
Use -a for run directories named from the parameter values instead of the run id:
runme -r -a -o OUTDIR -n par/model.nml -p ctl.n_accel=1,5,10In OUTDIR:
params.txt/info.txt— the full parameter table (ensemble dimensions and fixed overrides);info.txtadds therunidandrundircolumns.params_ensemble.txt/info_ensemble.txt— only the permuted ensemble dimensions.
runid ctl.n_accel rundir
0 1 0
1 5 1
2 10 2
Each member run directory additionally gets its own single-row params.txt /
info.txt and a runme.json record, so any run directory — single or ensemble
member — loads the same way.
Run only some members with -j (slurm --array syntax):
runme -r -o OUTDIR -n par/model.nml -p ctl.n_accel=1,5,10 -j 0,2 # members 0 and 2
runme -r -o OUTDIR -n par/model.nml -i lhs.txt -j 0-9 # first ten membersFor complex ensembles, a two-step approach is often clearer: generate the
parameter set first (so you can check it and keep it for reproducibility), then
run it with -i.
Factorial combination:
runme product ctl.n_accel=1,5,10 smb.alb_ice=0.3,0.4 -o grid.txt
runme -r -o OUTDIR -n par/model.nml -i grid.txtLatin-hypercube (or Monte-Carlo) sampling of distributions:
runme sample atm.c_trop=U?0.8,1.2 smb.alb_ice=N?0.35,0.05 -N 100 --seed 4 -o lhs.txt
runme -r -o OUTDIR -n par/model.nml -i lhs.txtDistribution specs: U?MIN,MAX (uniform), N?MEAN,SD (normal), or any
scipy.stats distribution as TYPE?[SHP,]LOC,SCALE. Discrete values (a=1,2,3)
and ranges (a=0:10:5) are also accepted.
Add --dry-run to print what would be staged and run for each member without
creating or running anything.
Some models (e.g. climber-x, and sometimes yelmox) generate interpolation maps between grids on their first run and cache them in a shared, linked input folder. Launching a whole ensemble before those maps exist makes every member try to build the same maps at once. To avoid that, do one map-generating run first.
Add --gen-maps to your normal command. It runs a single simulation into a
mapgen/ subfolder of -o OUTDIR — the single sim itself, or member 0 of an
ensemble (plus any fixed -p overrides) — and then exits:
runme -r -o OUTDIR -n par/model.nml -p ctl.n_accel=1,5,10 --gen-maps # warms the maps
runme -r -o OUTDIR -n par/model.nml -p ctl.n_accel=1,5,10 # the real ensembleThe first command stages and runs OUTDIR/mapgen/; once it finishes, drop
--gen-maps and re-run the same command to launch the real single run or
ensemble, which reuses the cached maps. mapgen/ sits alongside the member
directories (0, 1, …) and is left in place.
Run/submit flags are honoured as given: with -r the mapgen run runs in the
background, and with -s -r it is submitted to the queue (wait for that job to
finish before launching the ensemble).