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 by subclassing BaseScenario and specifying the scenario options therein. You can override parameters of the module 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):
        super().__init__()
        self.seed = 12
        self.start_date = Date(2010, 1, 1)
        self.end_date = Date(2011, 1, 1)
        self.pop_size = 200
        self.number_of_draws = 2
        self.runs_per_draw = 2

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

    def modules(self):
        return [
            demography.Demography(resourcefilepath=self.resources),
            enhanced_lifestyle.Lifestyle(resourcefilepath=self.resources),
        ]

    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 would have identical configuration except the simulation seed.

class BaseScenario[source]

Bases: object

An abstract base class for creating Scenarios

A scenario is a configuration of a simulation. Users should subclass this class and 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

  • draw_parameters - override parameters for draws from the scenario

log_configuration(**kwargs)[source]

Implementation must return a dictionary configuring logging.

Example:

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

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

Example:

return [
    demography.Demography(resourcefilepath=self.resources),
    enhanced_lifestyle.Lifestyle(resourcefilepath=self.resources),
    healthsystem.HealthSystem(resourcefilepath=self.resources, disable=True, service_availability=['*']),
    ...
]
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]
    },
}
Parameters
  • 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

save_draws(return_config=False, **kwargs)[source]
make_grid(ranges: dict) DataFrame[source]

Utility method to flatten an n-dimension grid of parameters for use in scenarios

Typically used in draw_parameters determining a set of parameters for a draw. This function will check that the number of draws of the scenario is equal to the number of coordinates in the grid.

Parameter ranges is a dictionary of { string key: iterable }, where iterable can be, for example, an np.array or list. The function will return a DataFrame where each key is a column and each row represents a single coordinate in the grid.

Usage (in draw_parameters):

grid = self.make_grid({'p_one': np.linspace(0, 1.0, 5), 'p_two': np.linspace(3.0, 4.0, 2)})
return {
    'Mockitis': {
        grid['p_one'][draw_number],
        grid['p_two'][draw_number]
    }
}
Parameters

ranges (dict) – each item of dict represents points across a single dimension

class ScenarioLoader(scenario_path)[source]

Bases: object

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

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

Bases: object

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

setup_draws()[source]
get_draw(draw_number)[source]
get_run_config(scenario_path)[source]
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_draw(draw_number)[source]
get_samples_for_draw(draw)[source]
get_sample(draw, sample_number)[source]
run_sample_by_number(output_directory, draw_number, sample_number)[source]
run_sample(sample, output_directory=None)[source]
run()[source]
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 https://github.com/skeeto/hash-prospector

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.

Param

x an integer

Returns

an integer