libEnsemble
Overview
libEnsemble is a complete Python toolkit for steering dynamic ensembles of calculations. Workflows are highly portable and detect/integrate heterogeneous resources with little effort. For instance, libEnsemble can automatically detect, assign, and reassign allocated processors and GPUs to ensemble members.
Users select or supply generator and simulator functions to express their ensembles; the generator typically steers the ensemble based on prior simulator results. Such functions can also launch and monitor external executables at any scale.
Installation
Begin by loading the python
module:
$ module load cray-python
libEnsemble is available on PyPI, conda-forge,
the xSDK, and E4S. Most users install libEnsemble
via pip
:
$ pip install libensemble
Installing libEnsemble in a virtual environment is highly recommended. See the Python on OCLF Systems page for more information.
Examples
For a very simple example of using libEsemble see the Simple Sine Tutorial on libEnsemble’s documentation.
For an example that runs a small ensemble with an application that offloads work to a GPU, see this GPU App Tutorial.
Additional information on compiling/running the above sample GPU app is available here.
See this video for an example workflow on Spock. The channel will soon publish a Frontier-specific guide.
Example Code
import numpy as np
from tutorial_gen import gen_random_sample
from tutorial_sim import sim_find_sine
from libensemble.libE import libE
from libensemble.tools import add_unique_random_streams
libE_specs = {"nworkers": 4, "comms": "local"}
gen_specs = {
"gen_f": gen_random_sample, # Our generator function
"out": [("x", float, (1,))], # gen_f output (name, type, size).
"user": {
"lower": np.array([-3]), # random sampling lower bound
"upper": np.array([3]), # random sampling upper bound
"gen_batch_size": 5, # number of values gen_f will generate per call
},
}
sim_specs = {
"sim_f": sim_find_sine, # Our simulator function
"in": ["x"], # Input field names. 'x' from gen_f output
"out": [("y", float)], # sim_f output. 'y' = sine('x')
}
persis_info = add_unique_random_streams({}, 5) # Initialize manager/workers random streams
exit_criteria = {"sim_max": 80} # Stop libEnsemble after 80 simulations
H, persis_info, flag = libE(sim_specs, gen_specs, exit_criteria, persis_info, libE_specs=libE_specs)
Job Submission
Upon initialization, libEnsemble will detect available nodes and GPUs from the Slurm environment, and allocate those resources towards application-launches.
Start an interactive session:
$ salloc --nodes=2 -A <project_id> --time=00:10:00
Within the session (multiprocessing
comms, all processes on first node):
$ python my_libensemble_script.py --comms local --nworkers 8