Source code for epimodels._parameters

#
# Phe Parameter Classes
#
# This file is part of EPIMODELS
# (https://github.com/I-Bouros/multi-epi-model-cross-analysis.git) which is
# released under the MIT license. See accompanying LICENSE for copyright
# notice and full license details.
#
"""
This script contains code for the Parameter classes for all the epidemiological
model include in the `epimodels` Python module.

The Parameter classes store the model parameters as class features and with the
object then fed into the model when :meth:`simulate` is called on the model
class.

"""

import numpy as np
from iteration_utilities import deepflatten

import epimodels as em

#
# PheICs Class
#


[docs] class PheICs(object): """PheICs: Base class for the ICs of the PHE model: a deterministic SEIR used by the Public Health England to model the Covid-19 epidemic in UK based on region. Parameters ---------- susceptibles_IC : list of lists Initial number of susceptibles classified by age (column name) and region (row name). exposed1_IC : list of lists Initial number of exposed of the first type classified by age (column name) and region (row name). exposed2_IC : list of lists Initial number of exposed of the second type classified by age (column name) and region (row name). infectives1_IC :list of lists Initial number of infectives of the first type classified by age (column name) and region (row name). infectives2_IC : list of lists Initial number of infectives of the second type classified by age (column name) and region (row name). recovered_IC : list of lists Initial number of recovered classified by age (column name) and region (row name). """ def __init__(self, model, susceptibles_IC, exposed1_IC, exposed2_IC, infectives1_IC, infectives2_IC, recovered_IC): super(PheICs, self).__init__() # Set model if not isinstance(model, em.PheSEIRModel): raise TypeError('The model must be a PHE SEIR Model.') self.model = model # Check inputs format self._check_parameters_input( susceptibles_IC, exposed1_IC, exposed2_IC, infectives1_IC, infectives2_IC, recovered_IC) # Set ICs parameters self.susceptibles = susceptibles_IC self.exposed1 = exposed1_IC self.exposed2 = exposed2_IC self.infectives1 = infectives1_IC self.infectives2 = infectives2_IC self.recovered = recovered_IC def _check_parameters_input(self, susceptibles_IC, exposed1_IC, exposed2_IC, infectives1_IC, infectives2_IC, recovered_IC): """ Check correct format of ICs input. Parameters ---------- susceptibles_IC : list of lists Initial number of susceptibles classified by age (column name) and region (row name). exposed1_IC : list of lists Initial number of exposed of the first type classified by age (column name) and region (row name). exposed2_IC : list of lists Initial number of exposed of the second type classified by age (column name) and region (row name). infectives1_IC :list of lists Initial number of infectives of the first type classified by age (column name) and region (row name). infectives2_IC : list of lists Initial number of infectives of the second type classified by age (column name) and region (row name). recovered_IC : list of lists Initial number of recovered classified by age (column name) and region (row name). """ if np.asarray(susceptibles_IC).ndim != 2: raise ValueError('The initial numbers of susceptibles storage \ format must be 2-dimensional.') if np.asarray(susceptibles_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ susceptibles.') if np.asarray(susceptibles_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ susceptibles.') for ic in np.asarray(susceptibles_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of susceptibles must be integer \ or float.') if np.asarray(exposed1_IC).ndim != 2: raise ValueError('The initial numbers of exposed of the first \ type storage format must be 2-dimensional.') if np.asarray(exposed1_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed of the first type.') if np.asarray(exposed1_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed of the first type.') for ic in np.asarray(exposed1_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of exposed of the first type \ must be integer or float.') if np.asarray(exposed2_IC).ndim != 2: raise ValueError('The initial numbers of exposed of the second \ type storage format must be 2-dimensional.') if np.asarray(exposed2_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed of the second type.') if np.asarray(exposed2_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed of the second type.') for ic in np.asarray(exposed2_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of exposed of the second type \ must be integer or float.') if np.asarray(infectives1_IC).ndim != 2: raise ValueError('The initial numbers of infectives of the first \ type storage format must be 2-dimensional.') if np.asarray(infectives1_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ infectives of the first type.') if np.asarray(infectives1_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ infectives of the first type.') for ic in np.asarray(infectives1_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of infectives of the first type\ must be integer or float.') if np.asarray(infectives2_IC).ndim != 2: raise ValueError('The initial numbers of infectives of the second\ type storage format must be 2-dimensional.') if np.asarray(infectives2_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ infectives of the second type.') if np.asarray(infectives2_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ infectives of the second type.') for ic in np.asarray(infectives2_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of infectives of the second type\ must be integer or float.') if np.asarray(recovered_IC).ndim != 2: raise ValueError('The initial numbers of recovered storage format \ must be 2-dimensional.') if np.asarray(recovered_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ recovered.') if np.asarray(recovered_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ recovered.') for ic in np.asarray(recovered_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of recovered must be integer or \ float.') def __call__(self): """ Returns the initial conditions of the :class:`PheSEIRModel` the class relates to. Returns ------- List of lists List of the initial conditions of the :class:`PheSEIRModel` the class relates to. """ return [self.susceptibles, self.exposed1, self.exposed2, self.infectives1, self.infectives2, self.recovered]
# # PheRegParameters Class #
[docs] class PheRegParameters(object): """PheRegParameters: Base class for the regional and time dependent parameters of the PHE model: a deterministic SEIR used by the Public Health England to model the Covid-19 epidemic in UK based on region. Parameters ---------- initial_r : list Initial values of the reproduction number by region. region_index : int Index of region for which we wish to simulate. betas : list of lists Temporal and regional fluctuation matrix. times : list List of time points at which we wish to evaluate the ODEs system. """ def __init__(self, model, initial_r, region_index, betas, times): super(PheRegParameters, self).__init__() # Set model if not isinstance(model, em.PheSEIRModel): raise TypeError('The model must be a PHE SEIR Model.') self.model = model # Check inputs format self._check_parameters_input(initial_r, region_index, betas, times) # Set regional and time dependent parameters self.initial_r = initial_r self.region_index = region_index self.betas = betas self.times = times def _check_parameters_input(self, initial_r, region_index, betas, times): """ Check correct format of the regional and time dependent parameters input. Parameters ---------- initial_r : list Initial values of the reproduction number by region. region_index : int Index of region for which we wish to simulate. betas : list of lists Temporal and regional fluctuation matrix. times : list List of time points at which we wish to evaluate the ODEs system. """ # Check times format if not isinstance(times, list): raise TypeError('Time points of evaluation must be given in a list\ format.') for _ in times: if not isinstance(_, (int, float)): raise TypeError('Time points of evaluation must be integer or \ float.') if _ <= 0: raise ValueError('Time points of evaluation must be > 0.') if np.asarray(initial_r).ndim != 1: raise ValueError('The initial reproduction numbers storage format \ must be 1-dimensional.') if np.asarray(initial_r).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial reproduction \ numbers.') for _ in np.asarray(initial_r): if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial reproduction numbers must be integer or \ float.') if not isinstance(region_index, int): raise TypeError('Index of region to evaluate must be integer.') if region_index <= 0: raise ValueError('Index of region to evaluate must be >= 1.') if region_index > len(self.model.regions): raise ValueError('Index of region to evaluate is out of bounds.') if np.asarray(betas).ndim != 2: raise ValueError('The temporal and regional fluctuations storage\ format must be 2-dimensional.') if np.asarray(betas).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the temporal and regional \ fluctuation.') if np.asarray(betas).shape[1] != len(times): raise ValueError( 'Wrong number of columns for the temporal and regional \ fluctuation.') def __call__(self): """ Returns the regional and time dependent parameters of the :class:`PheSEIRModel` the class relates to. Returns ------- List of lists List of the regional and time dependent parameters of the :class:`PheSEIRModel` the class relates to. """ return [self.initial_r, self.region_index, self.betas]
# # PheDiseaseParameters Class #
[docs] class PheDiseaseParameters(object): """PheDiseaseParameters: Base class for the disease-specific parameters of the PHE model: a deterministic SEIR used by the Public Health England to model the Covid-19 epidemic in UK based on region. Parameters ---------- dL : int or float Mean latent period. dI : int or float Mean infection period. """ def __init__(self, model, dL, dI): super(PheDiseaseParameters, self).__init__() # Set model if not isinstance(model, em.PheSEIRModel): raise TypeError('The model must be a PHE SEIR Model.') self.model = model # Check inputs format self._check_parameters_input(dL, dI) # Set disease-specific parameters self.dL = dL self.dI = dI def _check_parameters_input(self, dL, dI): """ Check correct format of the disease-specific parameters input. Parameters ---------- dL : int or float Mean latent period. dI : int or float Mean infection period. """ if not isinstance(dL, (float, int)): raise TypeError('Mean latent period must be float or integer.') if dL <= 0: raise ValueError('Mean latent period must be > 0.') if not isinstance(dI, (float, int)): raise TypeError('Mean infection period must be float or integer.') if dI <= 0: raise ValueError('Mean infection period must be > 0.') def __call__(self): """ Returns the disease-specific parameters of the :class:`PheSEIRModel` the class relates to. Returns ------- List of lists List of the disease-specific parameters of the :class:`PheSEIRModel` the class relates to. """ return [self.dL, self.dI]
# # PheSimParameters Class #
[docs] class PheSimParameters(object): """PheSimParameters: Base class for the simulation method's parameters of the PHE model: a deterministic SEIR used by the Public Health England to model the Covid-19 epidemic in UK based on region. Parameters ---------- delta_t : float Time step for the 'homemade' solver. method: str The type of solver implemented by the simulator. """ def __init__(self, model, delta_t, method): super(PheSimParameters, self).__init__() # Set model if not isinstance(model, em.PheSEIRModel): raise TypeError('The model must be a PHE SEIR Model.') self.model = model # Check inputs format self._check_parameters_input(delta_t, method) # Set other simulation parameters self.delta_t = delta_t self.method = method def _check_parameters_input(self, delta_t, method): """ Check correct format of the simulation method's parameters input. Parameters ---------- delta_t : float Time step for the 'homemade' solver. method: str The type of solver implemented by the simulator. """ if not isinstance(delta_t, (float, int)): raise TypeError( 'Time step for ODE solver must be float or integer.') if delta_t <= 0: raise ValueError('Time step for ODE solver must be > 0.') if not isinstance(method, str): raise TypeError('Simulation method must be a string.') if method not in ( 'my-solver', 'RK45', 'RK23', 'Radau', 'BDF', 'LSODA', 'DOP853'): raise ValueError('Simulation method not available.') def __call__(self): """ Returns the simulation method's parameters of the :class:`PheSEIRModel` the class relates to. Returns ------- List of lists List of the simulation method's parameters of the :class:`PheSEIRModel` the class relates to. """ return [self.delta_t, self.method]
# # PheParametersController Class #
[docs] class PheParametersController(object): """PheParametersController Class: Base class for the parameters of the PHE model: a deterministic SEIR used by the Public Health England to model the Covid-19 epidemic in UK based on region. In order to simulate using the PHE model, the following parameters are required, which are stored as part of this class. Parameters ---------- model : PheSEIRModel The model whose parameters are stored. regional_parameters : PheRegParameters Class of the regional and time dependent parameters used in the simulation of the model. ICs : PheICs Class of the ICs used in the simulation of the model. disease_parameters : PheDiseaseParameters Class of the disease-specific parameters used in the simulation of the model. simulation_parameters : PheSimParameters Class of the simulation method's parameters used in the simulation of the model. """ def __init__( self, model, regional_parameters, ICs, disease_parameters, simulation_parameters): # Instantiate class super(PheParametersController, self).__init__() # Set model if not isinstance(model, em.PheSEIRModel): raise TypeError('The model must be a PHE SEIR Model.') self.model = model # Check inputs format self._check_parameters_input( regional_parameters, ICs, disease_parameters, simulation_parameters) # Set regional and time dependent parameters self.regional_parameters = regional_parameters # Set ICs parameters self.ICs = ICs # Set disease-specific parameters self.disease_parameters = disease_parameters # Set other simulation parameters self.simulation_parameters = simulation_parameters def _check_parameters_input( self, regional_parameters, ICs, disease_parameters, simulation_parameters): """ Check correct format of input of simulate method. Parameters ---------- regional_parameters : PheRegParameters Class of the regional and time dependent parameters used in the simulation of the model. ICs : PheICs Class of the ICs used in the simulation of the model. disease_parameters : PheDiseaseParameters Class of the disease-specific parameters used in the simulation of the model. simulation_parameters : PheSimParameters Class of the simulation method's parameters used in the simulation of the model. """ if not isinstance(regional_parameters, PheRegParameters): raise TypeError('The model`s regional and time dependent\ parameters must be of a PHE SEIR Model.') if regional_parameters.model != self.model: raise ValueError('The regional and time dependent parameters do \ not correspond to the right model.') if not isinstance(ICs, PheICs): raise TypeError('The model`s ICs parameters must be of a PHE\ SEIR Model.') if ICs.model != self.model: raise ValueError('ICs do not correspond to the right model.') if not isinstance(disease_parameters, PheDiseaseParameters): raise TypeError('The model`s disease-specific parameters must be \ of a PHE SEIR Model.') if disease_parameters.model != self.model: raise ValueError('The disease-specific parameters do not \ correspond to the right model.') if not isinstance(simulation_parameters, PheSimParameters): raise TypeError('The model`s simulation method`s parameters must\ be of a PHE SEIR Model.') if simulation_parameters.model != self.model: raise ValueError('The simulation method`s parameters do not \ correspond to the right model.') def __call__(self): """ Returns the list of all the parameters used for the simulation of the PHE model in their order, which will be then separated within the :class:`PheSEIRModel` class. Returns ------- list List of all the parameters used for the simulation of the PHE model in their order. """ parameters = [] # Add the regional and time dependent parameters parameters.extend(self.regional_parameters()[:2]) # Add ICs parameters.extend(self.ICs()) # Add betas parameters.extend(self.regional_parameters()[2]) # Add disease-specific parameters parameters.extend(self.disease_parameters()) # Add other simulation parameters parameters.extend(self.simulation_parameters()) return list(deepflatten(parameters, ignore=str))
# # Roche Parameter Classes # # # RocheICs Class #
[docs] class RocheICs(object): """RocheICs: Base class for the ICs of the Roche model: deterministic SEIRD used by the F. Hoffmann-La Roche Ltd to model the Covid-19 epidemic and the effects of non-pharmaceutical interventions (NPIs) on the epidemic dynamic in different countries. Parameters ---------- susceptibles_IC : list of lists Initial number of susceptibles classified by age (column name) and region (row name). exposed_IC : list of lists Initial number of exposed classified by age (column name) and region (row name). infectives_pre_IC :list of lists Initial number of presymptomatic infectives classified by age (column name) and region (row name). infectives_asym_IC :list of lists Initial number of asymptomatic infectives classified by age (column name) and region (row name). infectives_sym_IC :list of lists Initial number of symptomatic infectives classified by age (column name) and region (row name). infectives_pre_ss_IC : list of lists Initial number of presymptomatic superspreader infectives classified by age (column name) and region (row name). infectives_asym_ss_IC : list of lists Initial number of asymptomatic superspreader infectives classified by age (column name) and region (row name). infectives_sym_ss_IC : list of lists Initial number of symptomatic superspreader infectives classified by age (column name) and region (row name). infectives_q_IC : list of lists Initial number of symptomatic infectives quarantined classified by age (column name) and region (row name). recovered_IC : list of lists Initial number of symptomatic recovered classified by age (column name) and region (row name). recovered_asym_IC : list of lists Initial number of asymptomatic recovered classified by age (column name) and region (row name). dead_IC: list of lists Initial number of dead classified by age (column name) and region (row name). """ def __init__(self, model, susceptibles_IC, exposed_IC, infectives_pre_IC, infectives_asym_IC, infectives_sym_IC, infectives_pre_ss_IC, infectives_asym_ss_IC, infectives_sym_ss_IC, infectives_q_IC, recovered_IC, recovered_asym_IC, dead_IC): super(RocheICs, self).__init__() # Set model if not isinstance(model, em.RocheSEIRModel): raise TypeError('The model must be a Roche SEIRD Model.') self.model = model # Check inputs format self._check_parameters_input( susceptibles_IC, exposed_IC, infectives_pre_IC, infectives_asym_IC, infectives_sym_IC, infectives_pre_ss_IC, infectives_asym_ss_IC, infectives_sym_ss_IC, infectives_q_IC, recovered_IC, recovered_asym_IC, dead_IC) # Set ICs parameters self.susceptibles = susceptibles_IC self.exposed = exposed_IC self.infectives_pre = infectives_pre_IC self.infectives_asym = infectives_asym_IC self.infectives_sym = infectives_sym_IC self.infectives_pre_ss = infectives_pre_ss_IC self.infectives_asym_ss = infectives_asym_ss_IC self.infectives_sym_ss = infectives_sym_ss_IC self.infectives_q = infectives_q_IC self.recovered = recovered_IC self.recovered_asym = recovered_asym_IC self.dead = dead_IC def _check_parameters_input(self, susceptibles_IC, exposed_IC, infectives_pre_IC, infectives_asym_IC, infectives_sym_IC, infectives_pre_ss_IC, infectives_asym_ss_IC, infectives_sym_ss_IC, infectives_q_IC, recovered_IC, recovered_asym_IC, dead_IC): """ Check correct format of ICs input. Parameters ---------- susceptibles_IC : list of lists Initial number of susceptibles classified by age (column name) and region (row name). exposed_IC : list of lists Initial number of exposed classified by age (column name) and region (row name). infectives_pre_IC :list of lists Initial number of presymptomatic infectives classified by age (column name) and region (row name). infectives_asym_IC :list of lists Initial number of asymptomatic infectives classified by age (column name) and region (row name). infectives_sym_IC :list of lists Initial number of symptomatic infectives classified by age (column name) and region (row name). infectives_pre_ss_IC : list of lists Initial number of presymptomatic superspreader infectives classified by age (column name) and region (row name). infectives_asym_ss_IC : list of lists Initial number of asymptomatic superspreader infectives classified by age (column name) and region (row name). infectives_sym_ss_IC : list of lists Initial number of symptomatic superspreader infectives classified by age (column name) and region (row name). infectives_q_IC : list of lists Initial number of symptomatic infectives quarantined classified by age (column name) and region (row name). recovered_IC : list of lists Initial number of symptomatic recovered classified by age (column name) and region (row name). recovered_asym_IC : list of lists Initial number of asymptomatic recovered classified by age (column name) and region (row name). dead_IC: list of lists Initial number of dead classified by age (column name) and region (row name). """ if np.asarray(susceptibles_IC).ndim != 2: raise ValueError('The initial numbers of susceptibles storage \ format must be 2-dimensional.') if np.asarray(susceptibles_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ susceptibles.') if np.asarray(susceptibles_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ susceptibles.') for ic in np.asarray(susceptibles_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of susceptibles must be integer \ or float.') if np.asarray(exposed_IC).ndim != 2: raise ValueError('The initial numbers of exposed storage format \ must be 2-dimensional.') if np.asarray(exposed_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed.') if np.asarray(exposed_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed.') for ic in np.asarray(exposed_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of exposed must be integer or \ float.') if np.asarray(infectives_pre_IC).ndim != 2: raise ValueError('The initial numbers of presymptomatic infectives\ storage format must be 2-dimensional.') if np.asarray(infectives_pre_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ presymptomatic infectives.') if np.asarray(infectives_pre_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ presymptomatic infectives.') for ic in np.asarray(infectives_pre_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of presymptomatic infectives must\ be integer or float.') if np.asarray(infectives_asym_IC).ndim != 2: raise ValueError('The initial numbers of asymptomatic infectives\ storage format must be 2-dimensional.') if np.asarray(infectives_asym_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ asymptomatic infectives.') if np.asarray(infectives_asym_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ asymptomatic infectives.') for ic in np.asarray(infectives_asym_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of asymptomatic infectives must \ be integer or float.') if np.asarray(infectives_sym_IC).ndim != 2: raise ValueError('The initial numbers of symptomatic infectives \ storage format must be 2-dimensional.') if np.asarray(infectives_sym_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ symptomatic infectives.') if np.asarray(infectives_sym_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ symptomatic infectives.') for ic in np.asarray(infectives_sym_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of symptomatic infectives must be\ integer or float.') if np.asarray(infectives_pre_ss_IC).ndim != 2: raise ValueError('The initial numbers of presymptomatic \ super-spreader infectives storage format must be \ 2-dimensional.') if np.asarray(infectives_pre_ss_IC).shape[0] != len( self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ presymptomatic super-spreader infectives.') if np.asarray(infectives_pre_ss_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ presymptomatic super-spreader infectives.') for ic in np.asarray(infectives_pre_ss_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of presymptomatic super-spreader \ infectives must be integer or float.') if np.asarray(infectives_asym_ss_IC).ndim != 2: raise ValueError('The initial numbers of asymptomatic \ super-spreader infectives storage format must be \ 2-dimensional.') if np.asarray(infectives_asym_ss_IC).shape[0] != len( self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ asymptomatic super-spreader infectives.') if np.asarray(infectives_asym_ss_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ asymptomatic super-spreader infectives.') for ic in np.asarray(infectives_asym_ss_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of asymptomatic super-spreader \ infectives must be integer or float.') if np.asarray(infectives_sym_ss_IC).ndim != 2: raise ValueError('The initial numbers of symptomatic \ super-spreader infectives storage format must be \ 2-dimensional.') if np.asarray(infectives_sym_ss_IC).shape[0] != len( self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ symptomatic super-spreader infectives.') if np.asarray(infectives_sym_ss_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ symptomatic super-spreader infectives.') for ic in np.asarray(infectives_sym_ss_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of symptomatic super-spreader \ infectives must be integer or float.') if np.asarray(infectives_q_IC).ndim != 2: raise ValueError('The initial numbers of quarantined \ infectives storage format must be 2-dimensional.') if np.asarray(infectives_q_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ quarantined infectives.') if np.asarray(infectives_q_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ quarantined infectives.') for ic in np.asarray(infectives_q_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of quarantined \ infectives must be integer or float.') if np.asarray(recovered_IC).ndim != 2: raise ValueError('The initial numbers of symptomatic recovered\ storage format must be 2-dimensional.') if np.asarray(recovered_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ symptomatic recovered.') if np.asarray(recovered_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ symptomatic recovered.') for ic in np.asarray(recovered_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of symptomatic recovered must be\ integer or float.') if np.asarray(recovered_asym_IC).ndim != 2: raise ValueError('The initial numbers of asymptomatic recovered\ storage format must be 2-dimensional.') if np.asarray(recovered_asym_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ asymptomatic recovered.') if np.asarray(recovered_asym_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ asymptomatic recovered.') for ic in np.asarray(recovered_asym_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of asymptomatic recovered must be\ integer or float.') if np.asarray(dead_IC).ndim != 2: raise ValueError('The initial numbers of dead storage format \ must be 2-dimensional.') if np.asarray(dead_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ dead.') if np.asarray(dead_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ dead.') for ic in np.asarray(dead_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of dead must be integer or \ float.') def __call__(self): """ Returns the initial conditions of the :class:`RocheSEIRModel` the class relates to. Returns ------- List of lists List of the initial conditions of the :class:`RocheSEIRModel` the class relates to. """ return [self.susceptibles, self.exposed, self.infectives_pre, self.infectives_asym, self.infectives_sym, self.infectives_pre_ss, self.infectives_asym_ss, self.infectives_sym_ss, self.infectives_q, self.recovered, self.recovered_asym, self.dead]
# # RocheCompartmentTimes Class #
[docs] class RocheCompartmentTimes(object): """RocheCompartmentTimes: Base class for the average-time-in-compartment parameters of the Roche model: deterministic SEIRD used by the F. Hoffmann-La Roche Ltd to model the Covid-19 epidemic and the effects of non-pharmaceutical interventions (NPIs) on the epidemic dynamic in different countries. Parameters ---------- k : float or int The average time it takes for an individual to become infectious once exposed. Non age-dependent. kS : float or int The average time it takes for an individual to develop symptoms (or remain asymptomatic) once they becomes infectious. Non age-dependent. kQ : float or int The average time it takes for an individual to enter quarantine once they develop symptoms. Non age-dependent. kR : float or int or list The average time it takes for a quarantined individual to recover or die. Age-dependent. kRI : float or int or list The average time it takes for an asymptomatic individual to recover. Age-dependent. """ def __init__(self, model, k, kS, kQ, kR, kRI): super(RocheCompartmentTimes, self).__init__() # Set model if not isinstance(model, em.RocheSEIRModel): raise TypeError('The model must be a Roche SEIRD Model.') self.model = model # Check inputs format self._check_parameters_input(k, kS, kQ, kR, kRI) # Set average-time-in-compartment parameters self.k = k self.kS = kS self.kQ = kQ if isinstance(kR, (float, int)): self.kR = kR * np.ones(self.model._num_ages) else: self.kR = kR if isinstance(kRI, (float, int)): self.kRI = kRI * np.ones(self.model._num_ages) else: self.kRI = kRI def _check_parameters_input(self, k, kS, kQ, kR, kRI): """ Check correct format of the average-time-in-compartment parameters input. Parameters ---------- k : float or int The average time it takes for an individual to become infectious once exposed. Non age-dependent. kS : float or int The average time it takes for an individual to develop symptoms (or remain asymptomatic) once they becomes infectious. Non age-dependent. kQ : float or int The average time it takes for an individual to enter quarantine once they develop symptoms. Non age-dependent. kR : float or int The average time it takes for a quarantined individual to recover or die. Age-dependent. kRI : float or int The average time it takes for an asymptomatic individual to recover. Age-dependent. """ if not isinstance(k, (float, int)): raise TypeError('The average time it takes for an individual to \ become infectious once exposed must be float or integer.') if k <= 0: raise ValueError('The average time it takes for an individual to \ become infectious once exposed must be > 0.') if not isinstance(kS, (float, int)): raise TypeError('The average time it takes for an individual to \ develop symptoms (or remain asymptomatic) once they becomes \ infectious must be float or integer.') if kS <= 0: raise ValueError('The average time it takes for an individual to \ develop symptoms (or remain asymptomatic) once they becomes \ infectious must be > 0.') if not isinstance(kQ, (float, int)): raise TypeError('The average time it takes for an individual to \ enter quarantine once they develop symptoms must be float or \ integer.') if kQ <= 0: raise ValueError('The average time it takes for an individual to \ enter quarantine once they develop symptoms must be > 0.') if isinstance(kR, (float, int)): kR = [kR] if np.asarray(kR).ndim != 1: raise ValueError('The average time it takes for a quarantined \ individual to recover or die storage format must be \ 1-dimensional.') if (np.asarray(kR).shape[0] != self.model._num_ages) and ( np.asarray(kR).shape[0] != 1): raise ValueError( 'Wrong number of age groups for the average time it takes \ for a quarantined individual to recover or die.') for _ in kR: if not isinstance(_, (float, int)): raise TypeError('The average time it takes for a quarantined \ individual to recover or die must be float or integer.') if _ <= 0: raise ValueError('The average time it takes for a quarantined \ individual to recover or die must be > 0.') if isinstance(kRI, (float, int)): kRI = [kRI] if np.asarray(kRI).ndim != 1: raise ValueError('The average times it takes for an asymptomatic \ individual to recover storage format must be 1-dimensional.') if (np.asarray(kRI).shape[0] != self.model._num_ages) and ( np.asarray(kRI).shape[0] != 1): raise ValueError( 'Wrong number of age groups for the average times it takes\ for an asymptomatic individual to recover.') for _ in kRI: if not isinstance(_, (float, int)): raise TypeError('The average times it takes for an \ asymptomatic individual to recover must be float or \ integer.') if _ <= 0: raise ValueError('The average times it takes for an \ asymptomatic individual to recover must be > 0.') def __call__(self): """ Returns the average-time-in-compartment parameters of the :class:`RocheSEIRModel` the class relates to. Returns ------- List of lists List of the average-time-in-compartment parameters of the :class:`RocheSEIRModel` the class relates to. """ return [self.k, self.kS, self.kQ, self.kR, self.kRI]
# # RocheProportions Class #
[docs] class RocheProportions(object): """RocheProportions: Base class for the proportions of asymptomatic, super-spreader and dead cases parameters of the Roche model: deterministic SEIRD used by the F. Hoffmann-La Roche Ltd to model the Covid-19 epidemic and the effects of non-pharmaceutical interventions (NPIs) on the epidemic dynamic in different countries. Parameters ---------- Pa : int or float or list Proportion of asymptomatic cases. Pss : int or float Proportion of super-spreader cases. Pd : int or float or list Proportion of dead cases. """ def __init__(self, model, Pa, Pss, Pd): super(RocheProportions, self).__init__() # Set model if not isinstance(model, em.RocheSEIRModel): raise TypeError('The model must be a Roche SEIRD Model.') self.model = model # Check inputs format self._check_parameters_input(Pa, Pss, Pd) # Set proportions of asymptomatic, super-spreader and dead cases if isinstance(Pa, (float, int)): self.Pa = Pa * np.ones(self.model._num_ages) else: self.Pa = Pa self.Pss = Pss if isinstance(Pd, (float, int)): self.Pd = Pd * np.ones(self.model._num_ages) else: self.Pd = Pd def _check_parameters_input(self, Pa, Pss, Pd): """ Check correct format of the proportions of asymptomatic, super-spreader and dead cases parameters input. Parameters ---------- Pa : int or float or list Proportion of asymptomatic cases. Pss : int or float Proportion of super-spreader cases. Pd : int or float or list Proportion of dead cases. """ if isinstance(Pa, (float, int)): Pa = [Pa] if np.asarray(Pa).ndim != 1: raise ValueError('The proportions of people that go on to be \ asymptomatic storage format must be 1-dimensional.') if (np.asarray(Pa).shape[0] != self.model._num_ages) and ( np.asarray(Pa).shape[0] != 1): raise ValueError( 'Wrong number of age groups for the proportions of people \ that go on to be asymptomatic.') for _ in Pa: if not isinstance(_, (float, int)): raise TypeError('The proportions of people that go on to be \ asymptomatic must be float or integer.') if _ < 0: raise ValueError('The proportions of people that go on to be \ asymptomatic must be >= 0.') if _ > 1: raise ValueError('The proportions of people that go on to be \ asymptomatic must be <= 1.') if not isinstance(Pss, (float, int)): raise TypeError('The proportions of people that go on to be \ super-spreaders must be float or integer.') if Pss < 0: raise ValueError('The proportions of people that go on to be \ super-spreaders must be >= 0.') if Pss > 1: raise ValueError('The proportions of people that go on to be \ super-spreaders must be <= 1.') if isinstance(Pd, (float, int)): Pd = [Pd] if np.asarray(Pd).ndim != 1: raise ValueError('The proportions of people that go on to be \ dead storage format must be 1-dimensional.') if (np.asarray(Pd).shape[0] != self.model._num_ages) and ( np.asarray(Pd).shape[0] != 1): raise ValueError( 'Wrong number of age groups for the proportions of people \ that go on to be dead.') for _ in Pd: if not isinstance(_, (float, int)): raise TypeError('The proportions of people that go on to be \ dead must be float or integer.') if _ < 0: raise ValueError('The proportions of people that go on to be \ dead must be >= 0.') if _ > 1: raise ValueError('The proportions of people that go on to be \ dead must be <= 1.') def __call__(self): """ Returns the proportions of asymptomatic, super-spreader and dead cases parameters of the :class:`RocheSEIRModel` the class relates to. Returns ------- List of lists List of the proportions of asymptomatic, super-spreader and dead cases parameters of the :class:`RocheSEIRModel` the class relates to. """ return [self.Pa, self.Pss, self.Pd]
# # RocheTransmission Class #
[docs] class RocheTransmission(object): """RocheTransmission: Base class for the transmission-specific parameters of the Roche model: deterministic SEIRD used by the F. Hoffmann-La Roche Ltd to model the Covid-19 epidemic and the effects of non-pharmaceutical interventions (NPIs) on the epidemic dynamic in different countries. Parameters ---------- beta_min : int or float The minimum possible transmission rate of the virus. beta_max : int or float The maximum possible transmission rate of the virus. bss : int or float The relative increase in transmission of a super-spreader case. gamma : : int or float The sharpness of the intervention wave used for function continuity purposes. s50 : int or float The stringency index needed to reach 50% of the maximum effect on the infection rate. """ def __init__(self, model, beta_min, beta_max, bss, gamma, s50): super(RocheTransmission, self).__init__() # Set model if not isinstance(model, em.RocheSEIRModel): raise TypeError('The model must be a Roche SEIRD Model.') self.model = model # Check inputs format self._check_parameters_input(beta_min, beta_max, bss, gamma, s50) # Set transmission-specific parameters self.beta_min = beta_min self.beta_max = beta_max self.bss = bss self.gamma = gamma self.s50 = s50 def _check_parameters_input(self, beta_min, beta_max, bss, gamma, s50): """ Check correct format of the transmission-specific parameters input. Parameters ---------- beta_min : int or float The minimum possible transmission rate of the virus. beta_max : int or float The maximum possible transmission rate of the virus. bss : int or float The relative increase in transmission of a super-spreader case. gamma : : int or float The sharpness of the intervention wave used for function continuity purposes. s50 : int or float The stringency index needed to reach 50% of the maximum effect on the infection rate. """ if not isinstance(beta_min, (float, int)): raise TypeError('The minimum possible transmission rate must be \ float or integer.') if beta_min <= 0: raise ValueError('The minimum and maximum possible transmission \ rate must be > 0.') if not isinstance(beta_max, (float, int)): raise TypeError('The maximum possible transmission rate must be \ float or integer.') if beta_max <= 0: raise ValueError('The minimum and maximum possible transmission \ rate must be > 0.') if not isinstance(bss, (float, int)): raise TypeError('The relative increase in transmission of a \ super-spreader must be float or integer.') if bss <= 0: raise ValueError('The relative increase in transmission of a \ super-spreader must be > 0.') if not isinstance(gamma, (float, int)): raise TypeError( 'The sharpness of the intervention wave must be float or \ integer.') if gamma < 0: raise ValueError('The sharpness of the intervention wave must be \ => 0.') if not isinstance(s50, (float, int)): raise TypeError( 'The half-effect stringency index must be float or integer.') if s50 <= 0: raise ValueError('The half-effect stringency index must be > 0.') if s50 > 100: raise ValueError('The half-effect stringency index must be <=100.') def __call__(self): """ Returns the transmission-specific parameters of the :class:`RocheSEIRModel` the class relates to. Returns ------- List of lists List of the transmission-specific parameters of the :class:`RocheSEIRModel` the class relates to. """ return [self.beta_min, self.beta_max, self.bss, self.gamma, self.s50]
# # RocheSimParameters Class #
[docs] class RocheSimParameters(object): """RocheSimParameters: Base class for the simulation method's parameters of the Roche model: deterministic SEIRD used by the F. Hoffmann-La Roche Ltd to model the Covid-19 epidemic and the effects of non-pharmaceutical interventions (NPIs) on the epidemic dynamic in different countries. Parameters ---------- region_index : int Index of region for which we wish to simulate. method: str The type of solver implemented by the simulator. times : list List of time points at which we wish to evaluate the ODEs system. """ def __init__(self, model, region_index, method, times): super(RocheSimParameters, self).__init__() # Set model if not isinstance(model, em.RocheSEIRModel): raise TypeError('The model must be a Roche SEIRD Model.') self.model = model # Check inputs format self._check_parameters_input(region_index, method, times) # Set other simulation parameters self.region_index = region_index self.method = method self.times = times def _check_parameters_input(self, region_index, method, times): """ Check correct format of the simulation method's parameters input. Parameters ---------- region_index : int Index of region for which we wish to simulate. method: str The type of solver implemented by the simulator. times : list List of time points at which we wish to evaluate the ODEs system. """ if not isinstance(times, list): raise TypeError('Time points of evaluation must be given in a list\ format.') for _ in times: if not isinstance(_, (int, float)): raise TypeError('Time points of evaluation must be integer or \ float.') if _ <= 0: raise ValueError('Time points of evaluation must be > 0.') if not isinstance(region_index, int): raise TypeError('Index of region to evaluate must be integer.') if region_index <= 0: raise ValueError('Index of region to evaluate must be >= 1.') if region_index > len(self.model.regions): raise ValueError('Index of region to evaluate is out of bounds.') if not isinstance(method, str): raise TypeError('Simulation method must be a string.') if method not in ( 'RK45', 'RK23', 'Radau', 'BDF', 'LSODA', 'DOP853'): raise ValueError('Simulation method not available.') def __call__(self): """ Returns the simulation method's parameters of the :class:`RocheSEIRModel` the class relates to. Returns ------- List of lists List of the simulation method's parameters of the :class:`RocheSEIRModel` the class relates to. """ return [self.region_index, self.method]
# # RocheParametersController Class #
[docs] class RocheParametersController(object): """RocheParametersController Class: Base class for the parameters of the Roche model: deterministic SEIRD used by the F. Hoffmann-La Roche Ltd to model the Covid-19 epidemic and the effects of non-pharmaceutical interventions (NPIs) on the epidemic dynamic in different countries. In order to simulate using the Roche model, the following parameters are required, which are stored as part of this class. Parameters ---------- model : RocheSEIRModel The model whose parameters are stored. ICs : RocheICs Class of the ICs used in the simulation of the model. compartment_times : RocheCompartmentTimes Class of the average-time-in-compartment parameters used in the simulation of the model. proportion_parameters : RocheProportions Class of the proportions of asymptomatic, super-spreader and dead cases parameters used in the simulation of the model. transmission_parameters : RocheTransmission Class of the parameters used to compute transmission of virus used in the simulation of the model. simulation_parameters : RocheSimParameters Class of the simulation method's parameters used in the simulation of the model. """ def __init__( self, model, ICs, compartment_times, proportion_parameters, transmission_parameters, simulation_parameters): # Instantiate class super(RocheParametersController, self).__init__() # Set model if not isinstance(model, em.RocheSEIRModel): raise TypeError('The model must be a Roche SEIRD Model.') self.model = model # Check inputs format self._check_parameters_input( ICs, compartment_times, proportion_parameters, transmission_parameters, simulation_parameters) # Set ICs parameters self.ICs = ICs # Set average-time-in-compartment parameters self.compartment_times = compartment_times # Set proportions of asymptomatic, super-spreader and dead # cases parameters self.proportion_parameters = proportion_parameters # Set transmission-specific parameters self.transmission_parameters = transmission_parameters # Set other simulation parameters self.simulation_parameters = simulation_parameters def _check_parameters_input( self, ICs, compartment_times, proportion_parameters, transmission_parameters, simulation_parameters): """ Check correct format of input of simulate method. Parameters ---------- ICs : RocheICs Class of the ICs used in the simulation of the model. compartment_times : RocheCompartmentTimes Class of the average-time-in-compartment parameters used in the simulation of the model. proportion_parameters : RocheProportions Class of the proportions of asymptomatic, super-spreader and dead cases parameters used in the simulation of the model. transmission_parameters : RocheTransmission Class of the parameters used to compute transmission of virus used in the simulation of the model. simulation_parameters : RocheSimParameters Class of the simulation method's parameters used in the simulation of the model. """ if not isinstance(ICs, RocheICs): raise TypeError('The model`s ICs parameters must be of a Roche \ SEIRD Model.') if ICs.model != self.model: raise ValueError('ICs do not correspond to the right model.') if not isinstance(compartment_times, RocheCompartmentTimes): raise TypeError('The model`s average-time-in-compartment \ parameters must be of a Roche SEIRD Model.') if compartment_times.model != self.model: raise ValueError('The average-time-in-compartment parameters do \ not correspond to the right model.') if not isinstance(proportion_parameters, RocheProportions): raise TypeError('The model`s proportions of asymptomatic, \ super-spreader and dead cases parameters must \ be of a Roche SEIRD Model.') if proportion_parameters.model != self.model: raise ValueError('The proportions of asymptomatic, super-spreader \ and dead cases parameters do not correspond to the \ right model.') if not isinstance(transmission_parameters, RocheTransmission): raise TypeError('The model`s transmission-specific parameters must\ be a of a Roche SEIRD Model.') if transmission_parameters.model != self.model: raise ValueError('The transmission-specific parameters do not \ correspond to the right model.') if not isinstance(simulation_parameters, RocheSimParameters): raise TypeError('The model`s simulation method`s parameters must \ be of a Roche SEIR Model.') if simulation_parameters.model != self.model: raise ValueError('The simulation method`s parameters do not \ correspond to the right model.') def __call__(self): """ Returns the list of all the parameters used for the simulation of the Roche model in their order, which will be then separated within the :class:`RocheSEIRModel` class. Returns ------- list List of all the parameters used for the simulation of the Roche model in their order. """ parameters = [] # Add the region index parameters parameters.append(self.simulation_parameters()[0]) # Add ICs parameters.extend(self.ICs()) # Add average-time-in-compartment parameters parameters.extend(self.compartment_times()) # Add proportions of asymptomatic, super-spreader and dead # cases parameters parameters.extend(self.proportion_parameters()) # Add transmission-specific parameters parameters.extend(self.transmission_parameters()) # Add other simulation parameters parameters.append(self.simulation_parameters()[1]) return list(deepflatten(parameters, ignore=str))
# # Warwick Model Parameter Classes # # # WarwickICs Class #
[docs] class WarwickICs(object): """WarwickICs: Base class for the ICs of the Warwick model: a deterministic SEIR developed by University of Warwick to model the Covid-19 epidemic and the effects of within-household dynamics on the epidemic trajectory in different countries. Parameters ---------- susceptibles_IC : list of lists Initial number of susceptibles classified by age (column name) and region (row name). exposed_1_f_IC : list of lists Initial number of exposed by a first household case classified by age (column name) and region (row name) in compartment 1. exposed_1_sd_IC : list of lists Initial number of exposed by a subsequent detected household case classified by age (column name) and region (row name) in compartment 1. exposed_1_su_IC : list of lists Initial number of exposed by a subsequent undetected household case classified by age (column name) and region (row name) in compartment 1. exposed_1_q_IC : list of lists Initial number of exposed by a quarantined household case classified by age (column name) and region (row name) in compartment 1. exposed_2_f_IC : list of lists Initial number of exposed by a first household case classified by age (column name) and region (row name) in compartment 2. exposed_2_sd_IC : list of lists Initial number of exposed by a subsequent detected household case classified by age (column name) and region (row name) in compartment 2. exposed_2_su_IC : list of lists Initial number of exposed by a subsequent undetected household case classified by age (column name) and region (row name) in compartment 2. exposed_2_q_IC : list of lists Initial number of exposed by a quarantined household case classified by age (column name) and region (row name) in compartment 2. exposed_3_f_IC : list of lists Initial number of exposed by a first household case classified by age (column name) and region (row name) in compartment 3. exposed_3_sd_IC : list of lists Initial number of exposed by a subsequent detected household case classified by age (column name) and region (row name) in compartment 3. exposed_3_su_IC : list of lists Initial number of exposed by a subsequent undetected household case classified by age (column name) and region (row name) in compartment 3. exposed_3_q_IC : list of lists Initial number of exposed by a quarantined household case classified by age (column name) and region (row name) in compartment 3. detected_f_IC :list of lists Initial number of detected infectives by a first household case classified by age (column name) and region (row name). detected_qf_IC :list of lists Initial number of detected infectives by a quarantined first household case classified by age (column name) and region (row name). detected_sd_IC :list of lists Initial number of detected infectives by a subsequent detected household case classified by age (column name) and region (row name). detected_su_IC :list of lists Initial number of detected infectives by a subsequent undetected household case classified by age (column name) and region (row name). detected_qs_IC :list of lists Initial number of detected infectives by a quarantined subsequent household case classified by age (column name) and region (row name). undetected_f_IC :list of lists Initial number of undetected infectives by a first household case classified by age (column name) and region (row name). undetected_s_IC :list of lists Initial number of undetected infectives by a subsequent household case classified by age (column name) and region (row name). undetected_q_IC :list of lists Initial number of undetected infectives by a quarantined household case classified by age (column name) and region (row name). recovered_IC : list of lists Initial number of recovered classified by age (column name) and region (row name). """ def __init__(self, model, susceptibles_IC, exposed_1_f_IC, exposed_1_sd_IC, exposed_1_su_IC, exposed_1_q_IC, exposed_2_f_IC, exposed_2_sd_IC, exposed_2_su_IC, exposed_2_q_IC, exposed_3_f_IC, exposed_3_sd_IC, exposed_3_su_IC, exposed_3_q_IC, detected_f_IC, detected_qf_IC, detected_sd_IC, detected_su_IC, detected_qs_IC, undetected_f_IC, undetected_s_IC, undetected_q_IC, recovered_IC): super(WarwickICs, self).__init__() # Set model if not isinstance(model, em.WarwickSEIRModel): raise TypeError('The model must be a Warwick SEIR Model.') self.model = model # Check inputs format self._check_parameters_input( susceptibles_IC, exposed_1_f_IC, exposed_1_sd_IC, exposed_1_su_IC, exposed_1_q_IC, exposed_2_f_IC, exposed_2_sd_IC, exposed_2_su_IC, exposed_2_q_IC, exposed_3_f_IC, exposed_3_sd_IC, exposed_3_su_IC, exposed_3_q_IC, detected_f_IC, detected_qf_IC, detected_sd_IC, detected_su_IC, detected_qs_IC, undetected_f_IC, undetected_s_IC, undetected_q_IC, recovered_IC) # Set ICs parameters self.susceptibles = susceptibles_IC self.exposed_1_f = exposed_1_f_IC self.exposed_1_sd = exposed_1_sd_IC self.exposed_1_su = exposed_1_su_IC self.exposed_1_q = exposed_1_q_IC self.exposed_2_f = exposed_2_f_IC self.exposed_2_sd = exposed_2_sd_IC self.exposed_2_su = exposed_2_su_IC self.exposed_2_q = exposed_3_q_IC self.exposed_3_f = exposed_3_f_IC self.exposed_3_sd = exposed_3_sd_IC self.exposed_3_su = exposed_3_su_IC self.exposed_3_q = exposed_3_q_IC self.detected_f = detected_f_IC self.detected_qf = detected_qf_IC self.detected_sd = detected_sd_IC self.detected_su = detected_su_IC self.detected_qs = detected_qs_IC self.undetected_f = undetected_f_IC self.undetected_s = undetected_s_IC self.undetected_q = undetected_q_IC self.recovered = recovered_IC def _check_parameters_input( self, susceptibles_IC, exposed_1_f_IC, exposed_1_sd_IC, exposed_1_su_IC, exposed_1_q_IC, exposed_2_f_IC, exposed_2_sd_IC, exposed_2_su_IC, exposed_2_q_IC, exposed_3_f_IC, exposed_3_sd_IC, exposed_3_su_IC, exposed_3_q_IC, detected_f_IC, detected_qf_IC, detected_sd_IC, detected_su_IC, detected_qs_IC, undetected_f_IC, undetected_s_IC, undetected_q_IC, recovered_IC): """ Check correct format of ICs input. Parameters ---------- susceptibles_IC : list of lists Initial number of susceptibles classified by age (column name) and region (row name). exposed_1_f_IC : list of lists Initial number of exposed by a first household case classified by age (column name) and region (row name) in compartment 1. exposed_1_sd_IC : list of lists Initial number of exposed by a subsequent detected household case classified by age (column name) and region (row name) in compartment 1. exposed_1_su_IC : list of lists Initial number of exposed by a subsequent undetected household case classified by age (column name) and region (row name) in compartment 1. exposed_1_q_IC : list of lists Initial number of exposed by a quarantined household case classified by age (column name) and region (row name) in compartment 1. exposed_2_f_IC : list of lists Initial number of exposed by a first household case classified by age (column name) and region (row name) in compartment 2. exposed_2_sd_IC : list of lists Initial number of exposed by a subsequent detected household case classified by age (column name) and region (row name) in compartment 2. exposed_2_su_IC : list of lists Initial number of exposed by a subsequent undetected household case classified by age (column name) and region (row name) in compartment 2. exposed_2_q_IC : list of lists Initial number of exposed by a quarantined household case classified by age (column name) and region (row name) in compartment 2. exposed_3_f_IC : list of lists Initial number of exposed by a first household case classified by age (column name) and region (row name) in compartment 3. exposed_3_sd_IC : list of lists Initial number of exposed by a subsequent detected household case classified by age (column name) and region (row name) in compartment 3. exposed_3_su_IC : list of lists Initial number of exposed by a subsequent undetected household case classified by age (column name) and region (row name) in compartment 3. exposed_3_q_IC : list of lists Initial number of exposed by a quarantined household case classified by age (column name) and region (row name) in compartment 3. detected_f_IC :list of lists Initial number of detected infectives by a first household case classified by age (column name) and region (row name). detected_qf_IC :list of lists Initial number of detected infectives by a quarantined first household case classified by age (column name) and region (row name). detected_sd_IC :list of lists Initial number of detected infectives by a subsequent detected household case classified by age (column name) and region (row name). detected_su_IC :list of lists Initial number of detected infectives by a subsequent undetected household case classified by age (column name) and region (row name). detected_qs_IC :list of lists Initial number of detected infectives by a quarantined subsequent household case classified by age (column name) and region (row name). undetected_f_IC :list of lists Initial number of undetected infectives by a first household case classified by age (column name) and region (row name). undetected_s_IC :list of lists Initial number of undetected infectives by a subsequent household case classified by age (column name) and region (row name). undetected_q_IC :list of lists Initial number of undetected infectives by a quarantined household case classified by age (column name) and region (row name). recovered_IC : list of lists Initial number of recovered classified by age (column name) and region (row name). """ if np.asarray(susceptibles_IC).ndim != 2: raise ValueError('The initial numbers of susceptibles storage \ format must be 2-dimensional.') if np.asarray(susceptibles_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ susceptibles.') if np.asarray(susceptibles_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ susceptibles.') for ic in np.asarray(susceptibles_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of susceptibles must be integer \ or float.') if np.asarray(exposed_1_f_IC).ndim != 2: raise ValueError('The initial numbers of exposed by a first \ household case storage format must be 2-dimensional.') if np.asarray(exposed_1_f_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a first household case.') if np.asarray(exposed_1_f_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a first household case.') for ic in np.asarray(exposed_1_f_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of exposed by a first household \ case must be integer or float.') if np.asarray(exposed_1_sd_IC).ndim != 2: raise ValueError('The initial numbers of exposed by a subsequent \ detected household casee storage format must be \ 2-dimensional.') if np.asarray(exposed_1_sd_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a subsequent detected household case.') if np.asarray(exposed_1_sd_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a subsequent detected household case.') for ic in np.asarray(exposed_1_sd_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of exposed by a subsequent \ detected household case must be integer or float.') if np.asarray(exposed_1_su_IC).ndim != 2: raise ValueError('The initial numbers of exposed by a subsequent \ undetected household case storage format must be \ 2-dimensional.') if np.asarray(exposed_1_su_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a subsequent undetected household case.') if np.asarray(exposed_1_su_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a subsequent undetected household case.') for ic in np.asarray(exposed_1_su_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of exposed by a subsequent \ undetected household case must be integer or \ float.') if np.asarray(exposed_1_q_IC).ndim != 2: raise ValueError('The initial numbers of exposed by a quarantined \ household case storage format must be 2-dimensional.') if np.asarray(exposed_1_q_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a quarantined household case.') if np.asarray(exposed_1_q_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a quarantined household case.') for ic in np.asarray(exposed_1_q_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of exposed by a quarantined \ household case type must be integer or float.') if np.asarray(exposed_2_f_IC).ndim != 2: raise ValueError('The initial numbers of exposed by a first \ household case storage format must be 2-dimensional.') if np.asarray(exposed_2_f_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a first household case.') if np.asarray(exposed_2_f_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a first household case.') for ic in np.asarray(exposed_2_f_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of exposed by a first household \ case must be integer or float.') if np.asarray(exposed_2_sd_IC).ndim != 2: raise ValueError('The initial numbers of exposed by a subsequent \ detected household cases storage format must be \ 2-dimensional.') if np.asarray(exposed_2_sd_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a subsequent detected household case.') if np.asarray(exposed_2_sd_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a subsequent detected household case.') for ic in np.asarray(exposed_2_sd_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of exposed by a subsequent \ detected household case must be integer or float.') if np.asarray(exposed_2_su_IC).ndim != 2: raise ValueError('The initial numbers of exposed by a subsequent \ undetected household case storage format must be \ 2-dimensional.') if np.asarray(exposed_2_su_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a subsequent undetected household case.') if np.asarray(exposed_2_su_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a subsequent undetected household case.') for ic in np.asarray(exposed_2_su_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of exposed by a subsequent \ undetected household case must be integer or \ float.') if np.asarray(exposed_2_q_IC).ndim != 2: raise ValueError('The initial numbers of exposed by a quarantined \ household case storage format must be 2-dimensional.') if np.asarray(exposed_2_q_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a quarantined household case.') if np.asarray(exposed_2_q_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a quarantined household case.') for ic in np.asarray(exposed_2_q_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of exposed by a quarantined \ household case type must be integer or float.') if np.asarray(exposed_3_f_IC).ndim != 2: raise ValueError('The initial numbers of exposed by a first \ household case storage format must be 2-dimensional.') if np.asarray(exposed_3_f_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a first household case.') if np.asarray(exposed_3_f_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a first household case.') for ic in np.asarray(exposed_3_f_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of exposed by a first household \ case must be integer or float.') if np.asarray(exposed_3_sd_IC).ndim != 2: raise ValueError('The initial numbers of exposed by a subsequent \ detected household cases storage format must be \ 2-dimensional.') if np.asarray(exposed_3_sd_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a subsequent detected household case.') if np.asarray(exposed_3_sd_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a subsequent detected household case.') for ic in np.asarray(exposed_3_sd_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of exposed by a subsequent \ detected household case must be integer or float.') if np.asarray(exposed_3_su_IC).ndim != 2: raise ValueError('The initial numbers of exposed by a subsequent \ undetected household case storage format must be \ 2-dimensional.') if np.asarray(exposed_3_su_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a subsequent undetected household case.') if np.asarray(exposed_3_su_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a subsequent undetected household case.') for ic in np.asarray(exposed_3_su_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of exposed by a subsequent \ undetected household case must be integer or \ float.') if np.asarray(exposed_3_q_IC).ndim != 2: raise ValueError('The initial numbers of exposed by a quarantined \ household case storage format must be 2-dimensional.') if np.asarray(exposed_3_q_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a quarantined household case.') if np.asarray(exposed_3_q_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ exposed by a quarantined household case.') for ic in np.asarray(exposed_3_q_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of exposed by a quarantined \ household case type must be integer or float.') if np.asarray(detected_f_IC).ndim != 2: raise ValueError('The initial numbers of detected infectives by a \ first household case storage format must be 2-dimensional.') if np.asarray(detected_f_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ detected infectives by a first household case.') if np.asarray(detected_f_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ detected infectives by a first household case.') for ic in np.asarray(detected_f_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of detected infectives by a \ first household case must be integer or float.') if np.asarray(detected_sd_IC).ndim != 2: raise ValueError('The initial numbers of detected infectives by a\ subsequent detected household case storage format must be \ 2-dimensional.') if np.asarray(detected_sd_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ detected infectives by a subsequent detected \ household case.') if np.asarray(detected_sd_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ detected infectives by a subsequent detected\ household case.') for ic in np.asarray(detected_sd_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of detected infectives by a\ subsequent detected household case must be integer\ or float.') if np.asarray(detected_su_IC).ndim != 2: raise ValueError('The initial numbers of detected infectives by a \ subsequent undetected household case storage format must \ be 2-dimensional.') if np.asarray(detected_su_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ detected infectives by a subsequent undetected \ household case.') if np.asarray(detected_su_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ detected infectives by a subsequent undetected \ household case.') for ic in np.asarray(detected_su_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of detected infectives by \ a subsequent detected household case\ must be integer or float.') if np.asarray(detected_qf_IC).ndim != 2: raise ValueError('The initial numbers of detected infectives by a \ quarantined first household case storage format must be \ 2-dimensional.') if np.asarray(detected_qf_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ detected infectives by a quarantined first household\ case.') if np.asarray(detected_qf_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ detected infectives by a quarantined first household\ case.') for ic in np.asarray(detected_qf_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of detected infectives by a \ quarantined first household case must be integer\ or float.') if np.asarray(detected_qs_IC).ndim != 2: raise ValueError('The initial numbers of detected infectives by a \ quarantined subsequent household case storage format must \ be 2-dimensional.') if np.asarray(detected_qs_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ detected infectives by a quarantined subsequent\ household case.') if np.asarray(detected_qs_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ detected infectives by a quarantined subsequent\ household case.') for ic in np.asarray(detected_qs_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of detected infectives by a \ quarantined subsequent household case\ must be integer or float.') if np.asarray(undetected_f_IC).ndim != 2: raise ValueError('The initial numbers of undetected infectives \ by a first household case storage format must \ be 2-dimensional.') if np.asarray(undetected_f_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ undetected infectives by a first household case.') if np.asarray(undetected_f_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ undetected infectives by a first household case.') for ic in np.asarray(undetected_f_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of undetected infectives by a \ first household case must be integer or float.') if np.asarray(undetected_s_IC).ndim != 2: raise ValueError('The initial undetected infectives by a \ subsequent household case storage format must be \ 2-dimensional.') if np.asarray(undetected_s_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ undetected infectives by a subsequent household case.') if np.asarray(undetected_s_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ undetected infectives by a subsequent household case.') for ic in np.asarray(undetected_s_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of undetected infectives by a\ subsequent household case must be integer or\ float.') if np.asarray(undetected_q_IC).ndim != 2: raise ValueError('The initial numbers of undetected infectives by\ a quarantined household case storage format must be\ 2-dimensional.') if np.asarray(undetected_q_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ undetected infectives by a quarantined household\ case.') if np.asarray(undetected_q_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ undetected infectives by a quarantined household\ case.') for ic in np.asarray(undetected_q_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of undetected infectives by\ a quarantined household case must be integer or\ float.') if np.asarray(recovered_IC).ndim != 2: raise ValueError('The initial numbers of recovered storage format \ must be 2-dimensional.') if np.asarray(recovered_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the initial numbers of \ recovered.') if np.asarray(recovered_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the initial numbers of \ recovered.') for ic in np.asarray(recovered_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The initial numbers of recovered must be integer or \ float.') def __call__(self): """ Returns the initial conditions of the :class:`WarwickSEIRModel` the class relates to. Returns ------- List of lists List of the initial conditions of the :class:`WarwickSEIRModel` the class relates to. """ return [self.susceptibles, self.exposed_1_f, self.exposed_1_sd, self.exposed_1_su, self.exposed_1_q, self.exposed_2_f, self.exposed_2_sd, self.exposed_2_su, self.exposed_2_q, self.exposed_3_f, self.exposed_3_sd, self.exposed_3_su, self.exposed_3_q, self.detected_f, self.detected_qf, self.detected_sd, self.detected_su, self.detected_qs, self.undetected_f, self.undetected_s, self.undetected_q, self.recovered]
# # WarwickRegParameters Class #
[docs] class WarwickRegParameters(object): """WarwickRegParameters: Base class for the regional and time dependent parameters of the Warwick model: a deterministic SEIR developed by University of Warwick to model the Covid-19 epidemic and the effects of within-household dynamics on the epidemic trajectory in different countries. Parameters ---------- region_index : int Index of region for which we wish to simulate. H : list List of region dependent quarantine proportions. """ def __init__(self, model, region_index, H): super(WarwickRegParameters, self).__init__() # Set model if not isinstance(model, em.WarwickSEIRModel): raise TypeError('The model must be a Warwick SEIR Model.') self.model = model # Check inputs format self._check_parameters_input(region_index, H) # Set regional and time dependent parameters self.region_index = region_index self.H = H def _check_parameters_input(self, region_index, H): """ Check correct format of the regional and time dependent parameters input. Parameters ---------- region_index : int Index of region for which we wish to simulate. H : list List of region-dependent household quarantine proportions. """ if not isinstance(region_index, int): raise TypeError('Index of region to evaluate must be integer.') if region_index <= 0: raise ValueError('Index of region to evaluate must be >= 1.') if region_index > len(self.model.regions): raise ValueError('Index of region to evaluate is out of bounds.') if np.asarray(H).ndim != 1: raise ValueError('The region-dependent household quarantine \ proportions storage format must be 1-dimensional.') if np.asarray(H).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the region-dependent \ household quarantine proportions.') for h in H: if not isinstance(h, (float, int)): raise TypeError('The region-dependent household quarantine \ proportions must be float or integer.') if h < 0: raise ValueError('The region-dependent household quarantine\ proportions must be => 0.') if h > 1: raise ValueError('The region-dependent household quarantine\ proportions must be <= 1.') def __call__(self): """ Returns the regional and time dependent parameters of the :class:`WarwickSEIRModel` the class relates to. Returns ------- List of lists List of the regional and time dependent parameters of the :class:`WarwickSEIRModel` the class relates to. """ return [self.region_index, self.H]
# # WarwickDiseaseParameters Class #
[docs] class WarwickDiseaseParameters(object): """WarwickDiseaseParameters: Base class for the disease-specific parameters of the Warwick model: a deterministic SEIR developed by University of Warwick to model the Covid-19 epidemic and the effects of within-household dynamics on the epidemic trajectory in different countries. Parameters ---------- tau : int or float Reduction in transmission for an asymptomatic infectious compared to the symptomatic case. d : int or float or list Age-dependent probabilities of displaying symptoms. """ def __init__(self, model, tau, d): super(WarwickDiseaseParameters, self).__init__() # Set model if not isinstance(model, em.WarwickSEIRModel): raise TypeError('The model must be a Warwick SEIR Model.') self.model = model # Check inputs format self._check_parameters_input(tau, d) # Set disease-specific parameters self.tau = tau if isinstance(d, (float, int)): self.d = d * np.ones(self.model._num_ages) else: self.d = d def _check_parameters_input(self, tau, d): """ Check correct format of the disease-specific parameters input. Parameters ---------- tau : int or float Reduction in transmission for an asymptomatic infectious compared to the symptomatic case. d : int or float or list Age-dependent probabilities of displaying symptoms. """ if not isinstance(tau, (float, int)): raise TypeError('Reduction in transmission must be float or\ integer.') if tau < 0: raise ValueError('Reduction in transmission must be => 0.') if tau > 1: raise ValueError('Reduction in transmission must be <= 1 .') if isinstance(d, (float, int)): d = [d] if np.asarray(d).ndim != 1: raise ValueError('The age-dependent probabilities of displaying\ symptoms storage format must be 1-dimensional.') if (np.asarray(d).shape[0] != self.model._num_ages) and ( np.asarray(d).shape[0] != 1): raise ValueError( 'Wrong number of age groups for the age-dependent \ probabilities of displaying symptoms.') for _ in d: if not isinstance(_, (float, int)): raise TypeError('The age-dependent probabilities of displaying\ symptoms must be float or integer.') if _ < 0: raise ValueError('The age-dependent probabilities of \ displaying symptoms must be => 0.') if _ > 1: raise ValueError('The age-dependent probabilities of \ displaying symptoms must be <= 1.') def __call__(self): """ Returns the disease-specific parameters of the :class:`WarwickSEIRModel` the class relates to. Returns ------- List of lists List of the disease-specific parameters of the :class:`WarwickSEIRModel` the class relates to. """ return [self.tau, self.d]
# # WarwickTransmission Class #
[docs] class WarwickTransmission(object): """RocheTransmission: Base class for the transmission-specific parameters of the Warwick model: a deterministic SEIR developed by University of Warwick to model the Covid-19 epidemic and the effects of within-household dynamics on the epidemic trajectory in different countries. Parameters ---------- epsilon : int or float Rate of progression to infection from exposed. gamma : int or float Rate of recovery. sigma : int or float or list Age-dependent susceptibility to infection. """ def __init__(self, model, epsilon, gamma, sigma): super(WarwickTransmission, self).__init__() # Set model if not isinstance(model, em.WarwickSEIRModel): raise TypeError('The model must be a Warwick SEIR Model.') self.model = model # Check inputs format self._check_parameters_input(epsilon, gamma, sigma) # Set transmission-specific parameters self.epsilon = epsilon self.gamma = gamma if isinstance(sigma, (float, int)): self.sigma = sigma * np.ones(self.model._num_ages) else: self.sigma = sigma def _check_parameters_input(self, epsilon, gamma, sigma): """ Check correct format of the transmission-specific parameters input. Parameters ---------- epsilon : int or float Rate of progression to infection from exposed. gamma : int or float Recovery rate. sigma : int or float or list Age-dependent susceptibility to infection. """ if not isinstance(epsilon, (float, int)): raise TypeError( 'The Rate of progression to infection from exposed must \ be float or integer.') if epsilon < 0: raise ValueError('The rate of progression to infection \ from exposed must be => 0.') if not isinstance(gamma, (float, int)): raise TypeError( 'The recovery rate must be float or integer.') if gamma < 0: raise ValueError('The recovery rate must be => 0.') if isinstance(sigma, (float, int)): sigma = [sigma] if np.asarray(sigma).ndim != 1: raise ValueError('The age-dependent susceptibility to infection\ storage format must be 1-dimensional.') if (np.asarray(sigma).shape[0] != self.model._num_ages) and ( np.asarray(sigma).shape[0] != 1): raise ValueError( 'Wrong number of age groups for the age-dependent \ susceptibility to infection.') for _ in sigma: if not isinstance(_, (float, int)): raise TypeError('The age-dependent susceptibility to \ infection must be float or integer.') if _ < 0: raise ValueError('The age-dependent susceptibility to \ infection must be => 0.') def __call__(self): """ Returns the transmission-specific parameters of the :class:`WarwickSEIRModel` the class relates to. Returns ------- List of lists List of the transmission-specific parameters of the :class:`WarwickSEIRModel` the class relates to. """ return [self.epsilon, self.gamma, self.sigma]
# # WarwickSimParameters Class #
[docs] class WarwickSimParameters(object): """WarwickSimParameters: Base class for the simulation method's parameters of the Warwick model: a deterministic SEIR developed by University of Warwick to model the Covid-19 epidemic and the effects of within-household dynamics on the epidemic trajectory in different countries. Parameters ---------- method: str The type of solver implemented by the simulator. times : list List of time points at which we wish to evaluate the ODEs system. """ def __init__(self, model, method, times): super(WarwickSimParameters, self).__init__() # Set model if not isinstance(model, em.WarwickSEIRModel): raise TypeError('The model must be a Warwick SEIR Model.') self.model = model # Check inputs format self._check_parameters_input(method, times) # Set other simulation parameters self.method = method self.times = times def _check_parameters_input(self, method, times): """ Check correct format of the simulation method's parameters input. Parameters ---------- method: str The type of solver implemented by the simulator. times : list List of time points at which we wish to evaluate the ODEs system. """ if not isinstance(method, str): raise TypeError('Simulation method must be a string.') if method not in ( 'RK45', 'RK23', 'Radau', 'BDF', 'LSODA', 'DOP853'): raise ValueError('Simulation method not available.') # Check times format if not isinstance(times, list): raise TypeError('Time points of evaluation must be given in a list\ format.') for _ in times: if not isinstance(_, (int, float)): raise TypeError('Time points of evaluation must be integer or \ float.') if _ <= 0: raise ValueError('Time points of evaluation must be > 0.') def __call__(self): """ Returns the simulation method's parameters of the :class:`WarwickSEIRModel` the class relates to. Returns ------- List of lists List of the simulation method's parameters of the :class:`WarwickSEIRModel` the class relates to. """ return self.method
# # WarwickSocDistParameters Class #
[docs] class WarwickSocDistParameters(object): """WarwickSocDistParameters: Base class for the social distancing parameters of the Warwick model: a deterministic SEIR developed by University of Warwick to model the Covid-19 epidemic and the effects of within-household dynamics on the epidemic trajectory in different countries. Parameters ---------- theta: list of int or float List of proportions of work interactions in public-facing `industries`. phi : list of int or float List of scaling factors between pre- and full-lockdown contact matrices. q_H : list of int or float List of increases in the amount of household interactions during lockdown. q_S : list of int or float List of reductions in attendance at school during lockdown. q_W : list of int or float List of reductions in attendance at workplaces during lockdown. q_O : list of int or float List of reductions in engagement with shopping and leisure activities during lockdown. times_npis: list of int List of times of points at which the social distancing parameters changes. """ def __init__(self, model, theta=[0.3], phi=[0], q_H=[1.25], q_S=[0.05], q_W=[0.2], q_O=[0.05], times_npis=[1]): super(WarwickSocDistParameters, self).__init__() # Set model if not isinstance(model, em.WarwickSEIRModel): raise TypeError('The model must be a Warwick SEIR Model.') self.model = model # Check inputs format self._check_parameters_input( theta, phi, q_H, q_S, q_W, q_O, times_npis) # Set other simulation parameters self.times_npis = times_npis n_changes = np.asarray(self.times_npis).shape[0] if isinstance(theta, (float, int)): self.theta = theta * np.ones(n_changes) else: self.theta = theta if isinstance(phi, (float, int)): self.phi = phi * np.ones(n_changes) else: self.phi = phi if isinstance(q_H, (float, int)): self.q_H = q_H * np.ones(n_changes) else: self.q_H = q_H if isinstance(q_S, (float, int)): self.q_S = q_S * np.ones(n_changes) else: self.q_S = q_S if isinstance(q_W, (float, int)): self.q_W = q_W * np.ones(n_changes) else: self.q_W = q_W if isinstance(q_O, (float, int)): self.q_O = q_O * np.ones(n_changes) else: self.q_O = q_O def _check_parameters_input( self, theta, phi, q_H, q_S, q_W, q_O, times_npis): """ Check correct format of the simulation method's parameters input. Parameters ---------- theta: list of int or float List of proportions of work interactions in public-facing `industries`. phi : list of int or float List of scaling factors between pre- and full-lockdown contact matrices. q_H : list of int or float List of increases in the amount of household interactions during lockdown. q_S : list of int or float List of reductions in attendance at school during lockdown. q_W : list of int or float List of reductions in attendance at workplaces during lockdown. q_O : list of int or float List of reductions in engagement with shopping and leisure activities during lockdown. times_npis: list of int List of times of points at which the social distancing parameters changes. """ if not isinstance(times_npis, list): raise TypeError('Time points of intervention changes must be given\ in a list format.') for _ in times_npis: if not isinstance(_, (int, float)): raise TypeError('Time points of intervention changes must be\ integer or float.') if _ <= 0: raise ValueError('Time points of intervention changes must be\ > 0.') if isinstance(theta, (float, int)): theta = [theta] if np.asarray(theta).ndim != 1: raise ValueError('The proportion of work interactions in \ public-facing `industries` storage format must be\ 1-dimensional.') if (np.asarray(theta).shape[0] != np.asarray( times_npis).shape[0]) and (np.asarray(theta).shape[0] != 1): raise ValueError( 'Wrong number of age groups for the proportion of work\ interactions in public-facing `industries`.') for _ in theta: if not isinstance(_, (float, int)): raise TypeError('The proportion of work interactions in \ public-facing `industries` must be float or integer.') if _ < 0: raise ValueError('The proportion of work interactions in \ public-facing `industries` must be => 0.') if _ > 1: raise ValueError('The proportion of work interactions in \ public-facing `industries` must be <= 1.') if isinstance(phi, (float, int)): phi = [phi] if np.asarray(phi).ndim != 1: raise ValueError('The scaling factor between pre- and \ full-lockdown contact matrices storage format must be\ 1-dimensional.') if (np.asarray(phi).shape[0] != np.asarray( times_npis).shape[0]) and (np.asarray(phi).shape[0] != 1): raise ValueError( 'Wrong number of age groups for the scaling factor between\ pre- and full-lockdown contact matrices.') for _ in phi: if not isinstance(_, (float, int)): raise TypeError('The scaling factor between pre- and \ full-lockdown contact matrices must be float or integer.') if _ < 0: raise ValueError('The scaling factor between pre- and \ full-lockdown contact matrices must be => 0.') if _ > 1: raise ValueError('The scaling factor between pre- and \ full-lockdown contact matrices must be <= 1.') if isinstance(q_H, (float, int)): q_H = [q_H] if np.asarray(q_H).ndim != 1: raise ValueError('The increase in the amount of household \ interactions during lockdown storage format must be\ 1-dimensional.') if (np.asarray(q_H).shape[0] != np.asarray( times_npis).shape[0]) and (np.asarray(q_H).shape[0] != 1): raise ValueError( 'Wrong number of age groups for the increase in the amount\ of household interactions during lockdown.') for _ in q_H: if not isinstance(_, (float, int)): raise TypeError('The increase in the amount of household \ interactions during lockdown must be float or integer.') if _ < 1: raise ValueError('The increase in the amount of household \ interactions during lockdown must be => 1.') if isinstance(q_S, (float, int)): q_S = [q_S] if np.asarray(q_S).ndim != 1: raise ValueError('The reduction in attendance at school during\ lockdown storage format must be 1-dimensional.') if (np.asarray(q_S).shape[0] != np.asarray( times_npis).shape[0]) and (np.asarray(q_S).shape[0] != 1): raise ValueError( 'Wrong number of age groups for the reduction in \ attendance at school during lockdown.') for _ in q_S: if not isinstance(_, (float, int)): raise TypeError('The reduction in attendance at school during\ lockdown must be float or integer.') if _ < 0: raise ValueError('The reduction in attendance at school during\ lockdown must be => 0.') if _ > 1: raise ValueError('The reduction in attendance at school during\ lockdown must be <= 1.') if isinstance(q_W, (float, int)): q_W = [q_W] if np.asarray(q_W).ndim != 1: raise ValueError('The reduction in attendance at workplaces during\ lockdown storage format must be 1-dimensional.') if (np.asarray(q_W).shape[0] != np.asarray( times_npis).shape[0]) and (np.asarray(q_W).shape[0] != 1): raise ValueError( 'Wrong number of age groups for the reduction in \ attendance at workplaces during lockdown.') for _ in q_W: if not isinstance(_, (float, int)): raise TypeError('The reduction in attendance at workplaces\ during lockdown must be float or integer.') if _ < 0: raise ValueError('The reduction in attendance at workplaces\ during lockdown must be => 0.') if _ > 1: raise ValueError('The reduction in attendance at workplaces\ during lockdown must be <= 1.') if isinstance(q_O, (float, int)): q_O = [q_O] if np.asarray(q_O).ndim != 1: raise ValueError('The reduction in engagement with shopping and \ leisure activities during lockdown storage format must be\ 1-dimensional.') if (np.asarray(q_O).shape[0] != np.asarray( times_npis).shape[0]) and (np.asarray(q_O).shape[0] != 1): raise ValueError( 'Wrong number of age groups for the reduction in \ engagement with shopping and leisure activities during\ lockdown.') for _ in q_O: if not isinstance(_, (float, int)): raise TypeError('The reduction in engagement with shopping and\ leisure activities during lockdown must be float or\ integer.') if _ < 0: raise ValueError('The reduction in engagement with shopping \ and leisure activities during lockdown must be => 0.') if _ > 1: raise ValueError('The reduction in engagement with shopping \ and leisure activities during lockdown must be <= 1.') def __call__(self): """ Returns the social distancing parameters of the :class:`WarwickSEIRModel` the class relates to. Returns ------- List of lists List of the social distancing parameters of the :class:`WarwickSEIRModel` the class relates to. """ return [ self.theta, self.phi, self.q_H, self.q_S, self.q_W, self.q_O, self.times_npis]
# # WarwickParametersController Class #
[docs] class WarwickParametersController(object): """WarwickParametersController Class: Base class for the parameters of the Warwick model: a deterministic SEIR developed by University of Warwick to model the Covid-19 epidemic and the effects of within-household dynamics on the epidemic trajectory in different countries. In order to simulate using the Warwick model, the following parameters are required, which are stored as part of this class. Parameters ---------- model : WarwickSEIRModel The model whose parameters are stored. regional_parameters : WarwickRegParameters Class of the regional and time dependent parameters used in the simulation of the model. ICs : WarwickICs Class of the ICs used in the simulation of the model. disease_parameters : WarwickDiseaseParameters Class of the disease-specific parameters used in the simulation of the model. transmission_parameters : WarwickTransmission Class of the rates of progression parameters used in the simulation of the model. simulation_parameters : WarwickSimParameters Class of the simulation method's parameters used in the simulation of the model. soc_dist_parameters : WarwickSocDistParameters Class of the social distancing parameters used in the simulation of the model. """ def __init__( self, model, regional_parameters, ICs, disease_parameters, transmission_parameters, simulation_parameters, soc_dist_parameters=None): # Instantiate class super(WarwickParametersController, self).__init__() # Set model if not isinstance(model, em.WarwickSEIRModel): raise TypeError('The model must be a Warwick SEIR Model.') self.model = model # Check inputs format self._check_parameters_input( regional_parameters, ICs, disease_parameters, transmission_parameters, simulation_parameters, soc_dist_parameters) # Set regional and time dependent parameters self.regional_parameters = regional_parameters # Set ICs parameters self.ICs = ICs # Set disease-specific parameters self.disease_parameters = disease_parameters # Set transmission-specific parameters self.transmission_parameters = transmission_parameters # Set other simulation parameters self.simulation_parameters = simulation_parameters # Set social distancing parameters if soc_dist_parameters is not None: self.soc_dist_parameters = soc_dist_parameters else: self.soc_dist_parameters = WarwickSocDistParameters(model) def _check_parameters_input( self, regional_parameters, ICs, disease_parameters, transmission_parameters, simulation_parameters, soc_dist_parameters): """ Check correct format of input of simulate method. Parameters ---------- model : WarwickSEIRModel The model whose parameters are stored. regional_parameters : WarwickRegParameters Class of the regional and time dependent parameters used in the simulation of the model. ICs : WarwickICs Class of the ICs used in the simulation of the model. disease_parameters : WarwickDiseaseParameters Class of the disease-specific parameters used in the simulation of the model. transmission_parameters : WarwickTransmission Class of the rates of progression parameters used in the simulation of the model. simulation_parameters : WarwickSimParameters Class of the simulation method's parameters used in the simulation of the model. """ if not isinstance(regional_parameters, WarwickRegParameters): raise TypeError('The model`s regional and time dependent\ parameters must be of a Warwick SEIR Model.') if regional_parameters.model != self.model: raise ValueError('The regional and time dependent parameters do \ not correspond to the right model.') if not isinstance(ICs, WarwickICs): raise TypeError('The model`s ICs parameters must be of a Warwick\ SEIR Model.') if ICs.model != self.model: raise ValueError('ICs do not correspond to the right model.') if not isinstance(disease_parameters, WarwickDiseaseParameters): raise TypeError('The model`s disease-specific parameters must be \ of a Warwick SEIR Model.') if disease_parameters.model != self.model: raise ValueError('The disease-specific parameters do not \ correspond to the right model.') if not isinstance(transmission_parameters, WarwickTransmission): raise TypeError('The model`s transmission-specific parameters must\ be a of a Warwick SEIRD Model.') if transmission_parameters.model != self.model: raise ValueError('The transmission-specific parameters do not \ correspond to the right model.') if not isinstance(simulation_parameters, WarwickSimParameters): raise TypeError('The model`s simulation method`s parameters must\ be of a Warwick SEIR Model.') if simulation_parameters.model != self.model: raise ValueError('The simulation method`s parameters do not \ correspond to the right model.') if soc_dist_parameters is not None: if not isinstance(soc_dist_parameters, WarwickSocDistParameters): raise TypeError('The model`s social distancing parameters must\ be of a Warwick SEIR Model.') if soc_dist_parameters.model != self.model: raise ValueError('The simulation method`s parameters do not \ correspond to the right model.') def __call__(self): """ Returns the list of all the parameters used for the simulation of the Warwick model in their order, which will be then separated within the :class:`WarwickSEIRModel` class. Returns ------- list List of all the parameters used for the simulation of the Warwick model in their order. """ parameters = [] # Add the regional and time dependent parameters parameters.append(self.regional_parameters()[0]) # Add ICs parameters.extend(self.ICs()) # Add sigma parameters.extend(self.transmission_parameters()[2]) # Add tau parameters.append(self.disease_parameters()[0]) # Add epsilon parameters.append(self.transmission_parameters()[0]) # Add gamma parameters.append(self.transmission_parameters()[1]) # Add d parameters.extend(self.disease_parameters()[1]) # Add H parameters.extend(self.regional_parameters()[1]) # Add other simulation parameters parameters.append(self.simulation_parameters()) return list(deepflatten(parameters, ignore=str))