Multirun Setup

Last updated on 29th April 2024

The RunnerBackend and ModelRunner classes need to be used together to setup and run a simulation that can run multiple times.

This guide assumes you have a Model created which implements simudyne.core.Model The following imports are assumed

Imports required for multirun (Java)

import simudyne.core.runner.ModelRunner;
import simudyne.core.runner.RunResult;
import simudyne.core.runner.RunnerBackend;

The RunnerBackend class is needed to set up the ModelRunner. The default RunnerBackend can be created by using the RunnerBackend create method. This will create an instance of the RunnerBackend that can be used to run the model locally.

Create a model runner (Java)

RunnerBackend runnerBackend = RunnerBackend.create();

Create the ModelRunner for a specific model with RunnerBackend#forModel passing the class of the model or RunnerBackend#forConfig passing the ModelConfiguration for the model

Create a model runner for a specific model (Java)

ModelRunner modelRunner = runnerBackend.forModel(myModel.class);

ModelRunner for Batch simulations

Use the ModelRunner to set the number of ticks(steps) to run each run of the model for, and the number of runs (number of times to run the full simulation).

withInput can optionally be used to set values of @Input variables in the model.

Setting inputs (Java)

modelRunner
    .forRuns(100)
    .forTicks(50)
    .withInput("{\"myBooleanInput\": false}")
    .withInput("{\"myStringInput\": \"aString\"}");

To run the model and wait for the results, use ModelRunner#run. Alternatively, the model can be run as an asynchronous process in the background. This means that while its running, the progress can be tracked.

// To run the model and wait for it to complete
RunResult runResult = modelRunner.run();

// To run the model a a background process and track the progress
Future<RunResult> runResultFuture = modelRunner.runAsync();
modelRunner.getProgress();
// Wait for final result
RunResult runResult = Await.result(runResultFuture, Duration.Inf());

Improving multirun performance

The multirun results are stored in memory to be returned to the user. If only the file output matters, this behaviour can be disabled in order to improve performance by setting the config field 'core.return-data' to false.

To read more on flags and configuration, see Model Config.

If this field is set to false, the returned RunResult will be empty.

ModelRunner for Scenario simulations

A scenario is a simulation that can be setup to run a series of ticks with different input parameters for each tick. Each series can be run multiple times with a different seed.

The current implementation of scenario does not possess a Java API. The following example will guide you through a simple scenario simulation. If you wish to see all scenario's features, please use the REST API documentation

We need to register the model and start the server.

  Server.register("Game of Life", GameOfLife.class);
  Server.run();

The model is now available for us to query. In this example, we will update gridSize of the Game of Life Model. We will set two runs with different seeds.

The parameters sent to the servers are:

  • Simulation parameters:

    • modelName is the name the model was registered with.
    • output URI is the path you want to export the data to.
    • scenarios contain the definition of all scenarios. Here, there is only one scenario object.
  • Scenario Parameters:

    • seeds is the list of seeds each run will be using. There are two seeds, so you will have two distinct runs.
    • scenarioData represents the parameters input per tick. Here we specified the tick 0, which is the setup, and the tick 10. The last one determines the number of ticks the simulation will run for.
curl -X POST \
  http://localhost:8080/api/simulations/scenario \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
  "modelName": "Game of Life", 
  "output": {"uri": "/tmp/scenarios"},
  "scenarios":[{
    "seeds": [1234, 2314]
    "scenarioData": {
        "0": {"gridSize":10},
        "10": {}
      }
  }]
}'

The server will return the following:

{"id":"f78057c4-f7f2-477b-bed1-3a690c7be864","name":"Game of Life","description":"","public":false,"session":"744d5b5b-ac16-4361-be3e-da5836c234bb","kind":"pojo"}

Now that this simulation has completed, go in the /tmp/scenarios/ we specified. Open the folder named as the id returned by the server, then runs. Inside are 2 files and 2 folders.

  • finished.json will be created when a simulation is completed
  • metadata.json will contains useful information. Refer to the REST API documentation for a complete description.

We only have one scenario, and two runs, this information is present in the folders names:

  • scenario_0001.run0001
  • scenario_0001.run0002

In the results.json file in each of the results folder, you can find the seed that we setup earlier as well as all data output. To have more details about the simulation output, refer to the documentation about the output directory structure.

Running a distributed multirun

Using Spark

Running a distributed multirun simulation depends on different packages and imports.

These elements can be found in the spark requirement tutorial and the spark runner tutorial tutorials.

To setup a distributed multirun, create a new instance of the SparkRunnerBackend as the RunnerBackend. All other methods are the same as for the local RunnerBackend.

Multirun with spark (Java)

RunnerBackend runnerBackend = new SparkRunnerBackend();
ModelRunner modelRunner = runnerBackend.forModel(myModel.class);

Extracting information from the RunResult is explained in Multirun Output