tlo.scenario module

Creating and running simulation scenarios for TLOmodel.

Scenarios are used to specify, configure and run a single or set of TLOmodel simulations. A scenario is created by subclassing BaseScenario and specifying the scenario options therein. You can override parameters of the simulation modules in various ways in the scenario. See the BaseScenario class for more information.

The subclass of BaseScenario is then used to create draws, which can be considered a fully-specified configuration of the scenario, or a parameter draw.

Each draw is run one or more times - run is a single execution of the simulation. Each run of a draw has a different seed but is otherwise identical. Each run has its own simulation seed, introducing randomness into each simulation. A collection of runs for a given draw describes the random variation in the simulation.

A simple example of a subclass of BaseScenario:

class MyTestScenario(BaseScenario):
    def __init__(self):
            seed = 12,
            start_date = Date(2010, 1, 1),
            end_date = Date(2011, 1, 1),
            initial_population_size = 200,
            number_of_draws = 2,
            runs_per_draw = 2,

    def log_configuration(self):
        return {
            'filename': 'my_test_scenario',
            'directory': './outputs',
            'custom_levels': {'*': logging.INFO}

    def modules(self):
        return [

    def draw_parameters(self, draw_number, rng):
        return {
            'Lifestyle': {
                'init_p_urban': rng.randint(10, 20) / 100.0,

In summary:

  • A scenario specifies the configuration of the simulation. The simulation start and end dates, initial population size, logging setup and registered modules. Optionally, you can also override parameters of modules.

  • A draw is a realisation of a scenario configuration. A scenario can have one or more draws. Draws are uninteresting unless you are overriding parameters. If you do not override any model parameters, you would only have one draw.

  • A run is the result of running the simulation using a specific configuration. Each draw would run one or more times. Each run for the same draw will have an identical configuration except the simulation seed.

class BaseScenario(seed: int | None = None, start_date: Timestamp | None = None, end_date: Timestamp | None = None, initial_population_size: int | None = None, number_of_draws: int = 1, runs_per_draw: int = 1, resources_path: Path = PosixPath('resources'))[source]

Bases: ABC

An abstract base class for creating scenarios.

A scenario is a configuration of a simulation. Users should subclass this class and must implement the following methods:

  • __init__ - to set scenario attributes,

  • log_configuration - to configure filename, directory and logging levels for simulation output,

  • modules - to list disease, intervention and health system modules for the simulation.

Users may also optionally implement:

  • draw_parameters - override parameters for draws from the scenario.

abstract log_configuration(**kwargs)[source]

Implementation must return a dictionary configuring logging.


return {
    'filename': 'test_scenario',
    'directory': './outputs',
    'custom_levels': {
        '*': logging.WARNING,
        'tlo.methods.demography': logging.INFO
abstract modules()[source]

Implementation must return a list of instances of TLOmodel modules to register in the simulation.


return [
draw_parameters(draw_number, rng)[source]

Implementation must return a dictionary of parameters to override for each draw.

The overridden parameters must be scalar (i.e. float, integer or string) as the following examples demonstrate. The argument draw_number and a random number generator are available, if required.

  • Change a parameter to a fixed value: {'Labour': {'average_age_at_pregnancy': 25}}

  • Sample a value from a distribution: {'Lifestyle': {'init_p_urban': rng.randint(10, 20) / 100.0}}

  • Set a value based on the draw number: {'Labour': {'average_age_at_pregnancy': [25, 30, 35][draw_number]}}

Implementation of this method in a subclass is optional. If no parameters are to be overridden, returns None. If no parameters are overridden, only one draw of the scenario is required.

A full example for a scenario with 10 draws:

return {
    'Lifestyle': {
        'init_p_urban': rng.randint(10, 20) / 100.0,
    'Labour': {
        'average_age_at_pregnancy': -10 * rng.exponential(0.1),
        'some_other_parameter': np.arange(0.1, 1.1, 0.1)[draw_number]
  • draw_number (int) – the specific draw number currently being executed by the simulation engine

  • rng (numpy.random.RandomState) – the scenario’s random number generator for sampling from distributions


Returns the log configuration for the scenario, with some post_processing.

save_draws(return_config=False, **kwargs)[source]
class ScenarioLoader(scenario_path)[source]

Bases: object

A utility class to load a scenario class from a file path

class DrawGenerator(scenario_class, number_of_draws, runs_per_draw)[source]

Bases: object

Creates and saves a JSON representation of draws from a scenario.

save_config(config, output_path)[source]
class SampleRunner(run_configuration_path)[source]

Bases: object

Reads scenario draws from a JSON configuration and handles running of samples

property number_of_draws
property runs_per_draw
get_sample(draw, sample_number)[source]
run_sample_by_number(output_directory, draw_number, sample_number)[source]

Runs a single sample from a draw, saving the output to the given directory


Run all samples for the scenario. Used by tlo scenario-run to run the scenario locally

static override_parameters(sim, overridden_params)[source]
static low_bias_32(x)[source]

A simple integer hash function with uniform distribution. Following description taken from

The integer hash function transforms an integer hash key into an integer hash result. For a hash function, the distribution should be uniform. This implies when the hash result is used to calculate hash bucket address, all buckets are equally likely to be picked. In addition, similar hash keys should be hashed to very different hash results. Ideally, a single bit change in the hash key should influence all bits of the hash result.


x an integer


an integer


Make a list of dictionaries corresponding to a grid across parameter space.

The parameters values in each parameter dictionary corresponds to an element in the Cartesian product of iterables describing the values taken by a collection of module specific parameters.

Intended for use in BaseScenario.draw_parameters to determine the set of parameters for a scenario draw.

Example usage (in BaseScenario.draw_parameters):

return make_cartesian_parameter_grid(
        "Mockitis": {
            "numeric_parameter": np.linspace(0, 1.0, 5),
            "categorical_parameter": ["category_a", "category_b"]
        "HealthSystem": {
            "cons_availability": ["default", "all"]

In practice it will be more performant to call make_cartesian_parameter_grid once in the scenario __init__ method, store this as an attribute of the scenario and reuse this in each call to draw_parameters.


module_parameter_values_dict (dict) – A dictionary mapping from module names (as strings) to dictionaries mapping from (string) parameter names associated with the model to iterables of the values over which parameter should take in the grid.


A list of dictionaries mapping from module names (as strings) to dictionaries mapping from (string) parameter names associated with the model to parameter values, with each dictionary in the list corresponding to a single point in the Cartesian grid across the parameter space.