Multi Simulation: What and Why?
With BioDynaMo it is possible to run multiple simulations in parallel, as separate processes. We refer to this as "Multi Simulation". This can be a useful feature when you want to repeat a certain simulation multiple times; possibly with different runtime parameters. Instead of running the simulations consecutively, with Multi Simulation it is possible to run multiple instances simultaneously, on one or more machines. This allows you to explore a parameter space and obtain results at a much faster pace. The more computing resources are available, the faster the simulations are completed. BioDynaMo offers a couple of default algorithms on exploring a parameter space (e.g. parameter sweep, particle swarm). The algorithms benefit from Multi Simulation by running each iteration in a separate process.
MPI
Multi Simulation uses MPI to spawn different processes and schedule the simulations on your system(s).
If you work with more than one machine, you are required to have the
same OpenMPI versions installed on all the machines in order for Multi Simulation to work properly.
Furthermore, MPI requires you to have a passwordless SSH login to the other machines.
How to use Multi Simulation
In order to run a simulation in Multi Simulation mode, you need to make a few changes.
Main function
In the main
function of your simulation you need to call the MultiSimulation
wrapper
around your regular Simulate
call:
int main(int argc, const char** argv) {
bdm::experimental::MultiSimulation pe(argc, argv);
return pe.Execute(Simulate);
}
Simulate function
Your Simulate
function also should conform to the following signature in order to use Multi Simulation:
void Simulate(int argc, const char** argv, TimeSeries* result,
Param* final_params = nullptr) {
auto set_param = [&](Param* param) {
param->Restore(std::move(*final_params));
};
Simulation simulation(argc, argv, set_param);
// Your simulation code...
}
result
is a TimeSeries
object that can be populated with results that are of interest in your simulation.
For some optimization algorithms, like ParticleSwarm, this must be populated with such results to be able to minimize the error between simulated data and real-life data.
final_params
are the unique set of parameters that a simulation instance receives from the Multi Simulation runtime. You must therefore configure your simulation with these parameters before you define your simulation using the Restore
functionality.
Optimization parameters
The Multi Simulation runtime expects you to define which parameter space exploration algorithm you want to use.
This can be done by defining a OptimizationParam
in your parameter configuration:
{
"bdm::OptimizationParam": {
"algorithm" : "<algorithm name>",
"params" : [
{
"_typename": "<parameter type>",
"param_name" : "<parameter name>",
...
}
]
}
}
- The
algorithm
should be the name of the algorithm you wish to use (e.g. "ParameterSweep", "ParticleSwarm") -
The
params
should be a list of simulation parameters you wish to explore. In the code block above, there is only one parameter block, but this can be a comma-separated list of multiple parameter blocks.- The
_typename
should be the type of parameter it concerns (e.g. a uniform range of parameters, a set of parameters). See "core/multi_simulation/optimization_param_type" for a list of available parameter types - The
param_name
should be the name of the parameter in your simulation, including any namespace identifiers (e.g. "bdm::SimParam::my_param") - Each parameter type has a number of extra fields that need to be filled in. For example, for a RangeParam (a uniform range of values), you would also need to specify the
lower_bound
,upper_bound
andstride
in its parameter block.
- The
Command line execution
Since Multi Simulation relies on MPI, we must use the mpirun
binary to run the simulation with
$ mpirun -np <N> <your_simulation_binary> --config=param.json
param.json
contains the optimization parameter information as described earlier (this can also instead be inlined with the inline-config
command line argument).
This command spawns N-1
number of processes that each will start a
simulation (N-1
because one process is always reserved as the managing process). The number of simulations that will eventually be performed depends
on your optimization algorithm: the more parameters you would like to explore,
the higher the number of simulations that need to be executed.
It is very likely that the total number of simulations will be greater than N-1
. Since
there can only be at most N-1
simulation running at any given point in time,
the other simulations are queued, and scheduled to be executed whenever
computing resources become available.
If you wish to run your simulations on multiple machines (e.g. a cluster, or cloud instances), it can simply be done as follows:
$ mpirun -np <N> --hostfile <path/to/hostfile> <your_simulation_binary> --config=param.json
The hostfile
should contain the names (e.g. IP addresses) of the machines in
your cluster. For detailed information on how to create a hostfile, please check
out the OpenMPI docs 1.
Performance tuning
Since we rely on MPI to distribute the simulation workloads over a specified number of processes, we are able to finetune the performance through the many options that come with the MPI implementation. Important for the performance of multi-threaded applications is being able to tweak the number of threads that each process is able to spawn, the thread affinity, and other related parameters. These parameters are conveniently described online 3.