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):
super().__init__(
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 [
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 will have an identical configuration except the simulation seed.
- class BaseScenario(seed: Optional[int] = None, start_date: Optional[Timestamp] = None, end_date: Optional[Timestamp] = None, initial_population_size: Optional[int] = 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.
Example:
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.
Example:
return [ demography.Demography(resourcefilepath=self.resources), enhanced_lifestyle.Lifestyle(resourcefilepath=self.resources), healthsystem.HealthSystem( resourcefilepath=self.resources, disable=True,d 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
- 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.
- 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¶
- 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
- make_cartesian_parameter_grid(module_parameter_values_dict)[source]¶
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"] } } )[draw_number]
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 todraw_parameters
.- 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.
- Returns
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.