Preparing Model Inputs for EMSA

Input types

No matter which use case you choose, EMSA will always need the following inputs:

  • Model Parameters: Key values that define the dynamics of the epidemic model.

  • Model Structure: The compartments and transitions between them.

  • Age Vector: Age distribution of the population.

  • Contact Matrix: Interaction rates between different population groups.

In addition, if you are performing sensitivity analysis, you will need to provide a sampling configuration, which can include data such as the initial values of the simulation, sampled parameters and their ranges, varying hyperparameters, and target variables.

For further description see Format of the inputs.

Passing the inputs to the package

Now we will take a look at how we can load the inputs and pass them to EMSA.

Model data

For the more ‘static’ part of the inputs (age vector, contact matrix, model parameters), we need to create an object, which will contain these as member variables, allowing us to access them using the dot operator.

To achieve this, you can either:

1. Create a DataLoader class inheriting from DataLoaderBase

Example: DataLoader class with separate methods for loading different parts of model data

import torch
from emsa.utils.dataloader import DataLoaderBase

# Custom DataLoader class
class DataLoader(DataLoaderBase):
    def __init__(self):
        super().__init__()

        # Load age data, model parameters, and contact matrix
        self._get_age_data()
        self._get_model_parameters_data()
        self._get_contact_mtx()

        # Set the computation device to CPU
        self.device = "cpu"

    # Implementation of the methods needed to load and preprocess the data

2. Load them into a dictionary and create a SimpleNamespace object

import torch
from types import SimpleNamespace

# Model parameters
params = {"gamma": 0.2, "alpha": 0.3}

# Contact matrix (1D tensor for simplicity)
contact_data = torch.tensor(1)

# Age distribution (single age group with population size of 10,000)
age_data = torch.tensor([10000])

# Combine data into a namespace
data = SimpleNamespace(
    **{
        "params": params,           # Model parameters
        "cm": contact_data,         # Contact matrix
        "age_data": age_data,       # Age distribution
        "n_age": 1,                 # Number of age groups
        "device": "cpu"             # Computation device (CPU)
    }
)

The first option is more pythonic, however if the data loading logic is simple, option 2 can suffice.

Model structure and parameters

These inputs should be handled differently depending on the use case:

Case 1: Model evaluation

When using EMSA for evaluating a certain model, we only need a dictionary containing the model structure, and a data object with the attributes described in the previous section.

from emsa.model.epidemic_model import EpidemicModel


data = ...
model_struct = ...

model = EpidemicModel(data=data, model_struct=model_struct)

Case 2: Sensitivity analysis

When performing sensitivity analysis, the model structure and the sampling configuration should be saved inside json files, and the path to those json files shall be passed along to the Simulation object.

from emsa.generics.simulation_generic import SimulationGeneric


data = ...
model_struct_path = '...'
sampling_config_path = '...'
sim = SimulationGeneric(
    data=data,
    model_struct_path=model_struct_path,
    sampling_config_path=sampling_config_path
)