Source code for warwickmodel._parameters

#
# Parameter Classes
#
# This file is part of WARWICKMODEL
# (https://github.com/I-Bouros/warwick-covid-transmission.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 the epidemiological
model include in the `warwickmodel` 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 warwickmodel as wm

#
# ICs Class
#


[docs] class ICs(object): """ICs: Base class for the ICs of the model: a deterministic SEIR used by the Universities of Warwick and Lancaster to model the Covid-19 epidemic and the effects of vaccines and waning immunity on the epidemic trajectory in different countries. Parameters ---------- susceptibles_IC : list of lists Initial number of susceptibles classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). exposed1_IC : list of lists Initial number of exposed of the first type classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). exposed2_IC : list of lists Initial number of exposed of the second type classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). exposed3_IC : list of lists Initial number of exposed of the third type classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). exposed4_IC : list of lists Initial number of exposed of the forth type classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). exposed5_IC : list of lists Initial number of exposed of the fifth type classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). infectives_sym_IC :list of lists Initial number of symptomatic infectives classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). infectives_asym_IC : list of lists Initial number of asymptomatic infectives classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). recovered_IC : list of lists Initial number of recovered classifed by age (column name) and region (row name). """ def __init__(self, model, susceptibles_IC, exposed1_IC, exposed2_IC, exposed3_IC, exposed4_IC, exposed5_IC, infectives_sym_IC, infectives_asym_IC, recovered_IC): super(ICs, self).__init__() # Set model if not isinstance(model, wm.WarwickLancSEIRModel): raise TypeError( 'The model must be a Warwick-Lancaster SEIR Model.') self.model = model # Check inputs format self._check_parameters_input( susceptibles_IC, exposed1_IC, exposed2_IC, exposed3_IC, exposed4_IC, exposed5_IC, infectives_sym_IC, infectives_asym_IC, recovered_IC) # Set ICs parameters self.susceptibles = susceptibles_IC self.exposed1 = exposed1_IC self.exposed2 = exposed2_IC self.exposed3 = exposed3_IC self.exposed4 = exposed4_IC self.exposed5 = exposed5_IC self.infectives_sym = infectives_sym_IC self.infectives_asym = infectives_asym_IC self.recovered = recovered_IC def _check_parameters_input( self, susceptibles_IC, exposed1_IC, exposed2_IC, exposed3_IC, exposed4_IC, exposed5_IC, infectives_sym_IC, infectives_asym_IC, recovered_IC): """ Check correct format of ICs input. Parameters ---------- susceptibles_IC : list of lists Initial number of susceptibles classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). exposed1_IC : list of lists Initial number of exposed of the first type classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). exposed2_IC : list of lists Initial number of exposed of the second type classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). exposed3_IC : list of lists Initial number of exposed of the third type classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). exposed4_IC : list of lists Initial number of exposed of the forth type classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). exposed5_IC : list of lists Initial number of exposed of the fifth type classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). infectives_sym_IC :list of lists Initial number of symptomatic infectives classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). infectives_asym_IC : list of lists Initial number of asymptomatic infectives classifed by age (column name) and region (row name) for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity) (column name II). recovered_IC : list of lists Initial number of recovered classifed by age (column name) and region (row name). """ if np.asarray(susceptibles_IC).ndim != 2: raise ValueError('The inital 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 inital numbers of \ susceptibles.') if np.asarray(susceptibles_IC).shape[1] != 6 * self.model._num_ages: raise ValueError( 'Wrong number of rows for the inital numbers of \ susceptibles.') for ic in np.asarray(susceptibles_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The inital numbers of susceptibles must be integer or\ float.') if np.asarray(exposed1_IC).ndim != 2: raise ValueError('The inital 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 inital numbers of \ exposed of the first type.') if np.asarray(exposed1_IC).shape[1] != 6 * self.model._num_ages: raise ValueError( 'Wrong number of rows for the inital 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 inital numbers of exposed of the first type must \ be integer or float.') if np.asarray(exposed2_IC).ndim != 2: raise ValueError('The inital 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 inital numbers of \ exposed of the second type.') if np.asarray(exposed2_IC).shape[1] != 6 * self.model._num_ages: raise ValueError( 'Wrong number of rows for the inital 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 inital numbers of exposed of the second type must\ be integer or float.') if np.asarray(exposed3_IC).ndim != 2: raise ValueError('The inital numbers of exposed of the third type\ storage format must be 2-dimensional.') if np.asarray(exposed3_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the inital numbers of \ exposed of the third type.') if np.asarray(exposed3_IC).shape[1] != 6 * self.model._num_ages: raise ValueError( 'Wrong number of rows for the inital numbers of \ exposed of the third type.') for ic in np.asarray(exposed3_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The inital numbers of exposed of the third type must\ be integer or float.') if np.asarray(exposed4_IC).ndim != 2: raise ValueError('The inital numbers of exposed of the fourth type\ storage format must be 2-dimensional.') if np.asarray(exposed4_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the inital numbers of \ exposed of the fourth type.') if np.asarray(exposed4_IC).shape[1] != 6 * self.model._num_ages: raise ValueError( 'Wrong number of rows for the inital numbers of \ exposed of the fourth type.') for ic in np.asarray(exposed4_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The inital numbers of exposed of the fourth type must\ be integer or float.') if np.asarray(exposed5_IC).ndim != 2: raise ValueError('The inital numbers of exposed of the fifth type\ storage format must be 2-dimensional.') if np.asarray(exposed5_IC).shape[0] != len(self.model.regions): raise ValueError( 'Wrong number of rows for the inital numbers of \ exposed of the fifth type.') if np.asarray(exposed5_IC).shape[1] != 6 * self.model._num_ages: raise ValueError( 'Wrong number of rows for the inital numbers of \ exposed of the fifth type.') for ic in np.asarray(exposed5_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The inital numbers of exposed of the fifth type must\ be integer or float.') if np.asarray(infectives_sym_IC).ndim != 2: raise ValueError('The inital 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 inital numbers of \ symptomatic infectives.') if np.asarray(infectives_sym_IC).shape[1] != 6 * self.model._num_ages: raise ValueError( 'Wrong number of rows for the inital 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 inital numbers of symptomatic infectives must be\ integer or float.') if np.asarray(infectives_asym_IC).ndim != 2: raise ValueError('The inital 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 inital numbers of \ asymptomatic infectives.') if np.asarray(infectives_asym_IC).shape[1] != 6 * self.model._num_ages: raise ValueError( 'Wrong number of rows for the inital 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 inital numbers of asymptomatic infectives must be\ integer or float.') if np.asarray(recovered_IC).ndim != 2: raise ValueError('The inital 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 inital numbers of \ recovered.') if np.asarray(recovered_IC).shape[1] != self.model._num_ages: raise ValueError( 'Wrong number of rows for the inital numbers of \ recovered.') for ic in np.asarray(recovered_IC): for _ in ic: if not isinstance(_, (np.integer, np.floating)): raise TypeError( 'The inital numbers of recovered must be integer or \ float.')
[docs] def total_population(self): """ Returns the country-specific total number of individuals in each age group. Returns ------- List of lists List of the ountry-specific total number of individuals in each age group using the initial conditions of the :class:`WarwickLancSEIRModel` the class relates to. """ a = self.model._num_ages total_pop = 0 ics_vac_stat = [self.susceptibles, self.exposed1, self.exposed2, self.exposed3, self.exposed4, self.exposed5, self.infectives_sym, self.infectives_asym] for _ in ics_vac_stat: total_pop += np.asarray(_)[:, :a] + np.asarray(_)[:, a:(2*a)] + \ np.asarray(_)[:, (2*a):(3*a)] + np.asarray(_)[:, (3*a):(4*a)] \ + np.asarray(_)[:, (4*a):(5*a)] + np.asarray(_)[:, (5*a):(6*a)] return total_pop + np.array(self.recovered)
def __call__(self): """ Returns the initial conditions of the :class:`WarwickLancSEIRModel` the class relates to. Returns ------- List of lists List of the initial conditions of the :class:`WarwickLancSEIRModel` the class relates to. """ ics = [] a = self.model._num_ages # Susceptibles ics += [ np.asarray(self.susceptibles)[:, :a], np.asarray(self.susceptibles)[:, a:(2*a)], np.asarray(self.susceptibles)[:, (2*a):(3*a)], np.asarray(self.susceptibles)[:, (3*a):(4*a)], np.asarray(self.susceptibles)[:, (4*a):(5*a)], np.asarray(self.susceptibles)[:, (5*a):(6*a)]] # Exposed unvaccinated ics += [ np.asarray(self.exposed1)[:, :a], np.asarray(self.exposed2)[:, :a], np.asarray(self.exposed3)[:, :a], np.asarray(self.exposed4)[:, :a], np.asarray(self.exposed5)[:, :a]] # Exposed fully vaccinated ics += [ np.asarray(self.exposed1)[:, a:(2*a)], np.asarray(self.exposed2)[:, a:(2*a)], np.asarray(self.exposed3)[:, a:(2*a)], np.asarray(self.exposed4)[:, a:(2*a)], np.asarray(self.exposed5)[:, a:(2*a)]] # Exposed boosted ics += [ np.asarray(self.exposed1)[:, (2*a):(3*a)], np.asarray(self.exposed2)[:, (2*a):(3*a)], np.asarray(self.exposed3)[:, (2*a):(3*a)], np.asarray(self.exposed4)[:, (2*a):(3*a)], np.asarray(self.exposed5)[:, (2*a):(3*a)]] # Exposed partially waned ics += [ np.asarray(self.exposed1)[:, (3*a):(4*a)], np.asarray(self.exposed2)[:, (3*a):(4*a)], np.asarray(self.exposed3)[:, (3*a):(4*a)], np.asarray(self.exposed4)[:, (3*a):(4*a)], np.asarray(self.exposed5)[:, (3*a):(4*a)]] # Exposed fully waned ics += [ np.asarray(self.exposed1)[:, (4*a):(5*a)], np.asarray(self.exposed2)[:, (4*a):(5*a)], np.asarray(self.exposed3)[:, (4*a):(5*a)], np.asarray(self.exposed4)[:, (4*a):(5*a)], np.asarray(self.exposed5)[:, (4*a):(5*a)]] # Exposed previous variant ics += [ np.asarray(self.exposed1)[:, (5*a):(6*a)], np.asarray(self.exposed2)[:, (5*a):(6*a)], np.asarray(self.exposed3)[:, (5*a):(6*a)], np.asarray(self.exposed4)[:, (5*a):(6*a)], np.asarray(self.exposed5)[:, (5*a):(6*a)]] # Symptomatic infected ics += [ np.asarray(self.infectives_sym)[:, :a], np.asarray(self.infectives_sym)[:, a:(2*a)], np.asarray(self.infectives_sym)[:, (2*a):(3*a)], np.asarray(self.infectives_sym)[:, (3*a):(4*a)], np.asarray(self.infectives_sym)[:, (4*a):(5*a)], np.asarray(self.infectives_sym)[:, (5*a):(6*a)]] # Asymptomatic infected ics += [ np.asarray(self.infectives_asym)[:, :a], np.asarray(self.infectives_asym)[:, a:(2*a)], np.asarray(self.infectives_asym)[:, (2*a):(3*a)], np.asarray(self.infectives_asym)[:, (3*a):(4*a)], np.asarray(self.infectives_asym)[:, (4*a):(5*a)], np.asarray(self.infectives_asym)[:, (5*a):(6*a)]] return ics + [self.recovered]
# # RegParameters Class #
[docs] class RegParameters(object): """RegParameters: Base class for the regional and time dependent parameters of the model: a deterministic SEIR used by the Universities of Warwick and Lancaster to model the Covid-19 epidemic and the effects of vaccines and waning immunity on the epidemic trajectory in different countries. Parameters ---------- region_index : int Index of region for which we wish to simulate. """ def __init__(self, model, region_index): super(RegParameters, self).__init__() # Set model if not isinstance(model, wm.WarwickLancSEIRModel): raise TypeError( 'The model must be a Warwick-Lancaster SEIR Model.') self.model = model # Check inputs format self._check_parameters_input(region_index) # Set regional and time dependent parameters self.region_index = region_index def _check_parameters_input(self, region_index): """ Check correct format of the regional and time dependent parameters input. Parameters ---------- region_index : int Index of region for which we wish to simulate. """ 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.') def __call__(self): """ Returns the regional and time dependent parameters of the :class:`WarwickLancSEIRModel` the class relates to. Returns ------- List of lists List of the regional and time dependent parameters of the :class:`WarwickLancSEIRModel` the class relates to. """ return self.region_index
# # DiseaseParameters Class #
[docs] class DiseaseParameters(object): """DiseaseParameters: Base class for the disease-specific parameters of the model: a deterministic SEIR used by the Universities of Warwick and Lancaster to model the Covid-19 epidemic and the effects of vaccines and waning immunity on the epidemic trajectory in different countries. Parameters ---------- d : int or float or list Age-dependent probabilities of dispalying symptoms. tau : int or float Reduction in transmission for an asymptomatic infectious compared to the symptomatic case. we : list Rates of waning of immunity for current and an older variant. omega : int or float Change in susceptibility due to the variant. """ def __init__(self, model, d, tau, we, omega): super(DiseaseParameters, self).__init__() # Set model if not isinstance(model, wm.WarwickLancSEIRModel): raise TypeError( 'The model must be a Warwick-Lancaster SEIR Model.') self.model = model # Check inputs format self._check_parameters_input(d, tau, we, omega) # 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 self.we = we self.omega = omega def _check_parameters_input(self, d, tau, we, omega): """ Check correct format of the disease-specific parameters input. Parameters ---------- d : int or float or list Age-dependent probabilities of dispalying symptoms. tau : int or float Reduction in transmission for an asymptomatic infectious compared to the symptomatic case. we : list Rates of waning of immunity for current and an older variant. omega : int or float Change in susceptibility due to the variant. """ 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 dispalying\ 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 dispalying symptoms.') for _ in d: if not isinstance(_, (float, int)): raise TypeError('The age-dependent probabilities of dispalying\ symptoms must be float or integer.') if _ < 0: raise ValueError('The age-dependent probabilities of \ dispalying symptoms must be => 0.') if _ > 1: raise ValueError('The age-dependent probabilities of \ dispalying symptoms must be <= 1.') if isinstance(we, (float, int)): we = [we, we, 0] # if we only model one variant if np.asarray(we).ndim != 1: raise ValueError('The rates of waning of immunity for current\ and an older variant storage format must be 1-dimensional.') if np.asarray(we).shape[0] != 3: raise ValueError( 'Wrong number of rates of waning of immunity for\ current and an older variant.') for _ in we: if not isinstance(_, (float, int)): raise TypeError('The Rates of waning of immunity for\ current and an older variant must be float or integer.') if _ < 0: raise ValueError('The Rates of waning of immunity for\ current and an older variant must be => 0.') if not isinstance(omega, (float, int)): raise TypeError('Change in susceptibility due to the variant must \ be float or integer.') if omega < 0: raise ValueError('Change in susceptibility due to the variant must\ be => 0.') def __call__(self): """ Returns the disease-specific parameters of the :class:`WarwickLancSEIRModel` the class relates to. Returns ------- List of lists List of the disease-specific parameters of the :class:`WarwickLancSEIRModel` the class relates to. """ return [self.d, self.tau, self.we, self.omega]
# # Transmission Class #
[docs] class Transmission(object): """Transmission: Base class for the transmission-specific parameters of the model: a deterministic SEIR used by the Universities of Warwick and Lancaster to model the Covid-19 epidemic and the effects of vaccines and waning immunity on the epidemic trajectory in different countries. Parameters ---------- beta : int or float or list Age-dependent susceptibility to infection. alpha : int or float Rate of progression to infection from exposed. gamma : int or float or list Age-dependent rate of recovery. """ def __init__(self, model, beta, alpha, gamma): super(Transmission, self).__init__() # Set model if not isinstance(model, wm.WarwickLancSEIRModel): raise TypeError( 'The model must be a Warwick-Lancaster SEIR Model.') self.model = model # Check inputs format self._check_parameters_input(beta, alpha, gamma) # Set transmission-specific parameters self.alpha = alpha if isinstance(beta, (float, int)): self.beta = beta * np.ones(self.model._num_ages) else: self.beta = beta if isinstance(gamma, (float, int)): self.gamma = gamma * np.ones(self.model._num_ages) else: self.gamma = gamma def _check_parameters_input(self, beta, alpha, gamma): """ Check correct format of the transmission-specific parameters input. Parameters ---------- beta : int or float or list Age-dependent susceptibility to infection. alpha : int or float Rate of progression to infection from exposed. gamma : int or float or list Age-dependent rate of recovery. """ if not isinstance(alpha, (float, int)): raise TypeError( 'The rate of progression to infection from exposed must \ be float or integer.') if alpha < 0: raise ValueError('The rate of progression to infection \ from exposed must be => 0.') if isinstance(beta, (float, int)): beta = [beta] if np.asarray(beta).ndim != 1: raise ValueError('The age-dependent susceptibility to infection\ storage format must be 1-dimensional.') if (np.asarray(beta).shape[0] != self.model._num_ages) and ( np.asarray(beta).shape[0] != 1): raise ValueError( 'Wrong number of age groups for the age-dependent \ susceptibility to infection.') for _ in beta: 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.') if isinstance(gamma, (float, int)): gamma = [gamma] if np.asarray(gamma).ndim != 1: raise ValueError('The age-dependent recovery rate\ storage format must be 1-dimensional.') if (np.asarray(gamma).shape[0] != self.model._num_ages) and ( np.asarray(gamma).shape[0] != 1): raise ValueError( 'Wrong number of age groups for the age-dependent \ recovery rate.') for _ in gamma: if not isinstance(_, (float, int)): raise TypeError('The age-dependent srecovery rate must \ be float or integer.') if _ < 0: raise ValueError('The age-dependent recovery rate must \ be => 0.') def __call__(self): """ Returns the transmission-specific parameters of the :class:`WarwickLancSEIRModel` the class relates to. Returns ------- List of lists List of the transmission-specific parameters of the :class:`WarwickLancSEIRModel` the class relates to. """ return [self.beta, self.alpha, self.gamma]
# # SimParameters Class #
[docs] class SimParameters(object): """SimParameters: Base class for the simulation method's parameters of the model: a deterministic SEIR used by the Universities of Warwick and Lancaster to model the Covid-19 epidemic and the effects of vaccines and waning immunity 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. eps : boolean Indicator parameter for deploying boosters to the recovered compartment. """ def __init__(self, model, method, times, eps=False): super(SimParameters, self).__init__() # Set model if not isinstance(model, wm.WarwickLancSEIRModel): raise TypeError( 'The model must be a Warwick-Lancaster SEIR Model.') self.model = model # Check inputs format self._check_parameters_input(method, times, eps) # Set other simulation parameters self.method = method self.times = times self.eps = eps def _check_parameters_input(self, method, times, eps): """ 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. eps : boolean Indicator parameter for deploying boosters to the recovered compartment. """ # 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 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.') if not isinstance(eps, bool): raise TypeError('Indicator parameter for deploying boosters to \ the recovered compartment must be a boolean.') def __call__(self): """ Returns the simulation method's parameters of the :class:`WarwickLancSEIRModel` the class relates to. Returns ------- List List of the simulation method's parameters of the :class:`WarwickLancSEIRModel` the class relates to. """ return [self.method, self.eps]
# # SocDistParameters Class #
[docs] class SocDistParameters(object): """SocDistParameters: Base class for the social distancing parameters of the model: a deterministic SEIR used by the Universities of Warwick and Lancaster to model the Covid-19 epidemic and the effects of vaccines and waning immunity on the epidemic trajectory in different countries. Parameters ---------- phi : int or float or list Country-specific control factor. """ def __init__(self, model, phi=1): super(SocDistParameters, self).__init__() # Set model if not isinstance(model, wm.WarwickLancSEIRModel): raise TypeError( 'The model must be a Warwick-Lancaster SEIR Model.') self.model = model # Check inputs format self._check_parameters_input(phi) # Set social distancing parameters if isinstance(phi, (float, int)): self.phi = phi * np.ones(len(self.model.regions)) else: self.phi = phi def _check_parameters_input(self, phi): """ Check correct format of the social distancing parameters input. Parameters ---------- phi : int or float or list Country-specific control factor. """ if isinstance(phi, (float, int)): phi = [phi] if np.asarray(phi).ndim != 1: raise ValueError('The country-specific control factor\ storage format must be 1-dimensional.') if (np.asarray(phi).shape[0] != len(self.model.regions)) and ( np.asarray(phi).shape[0] != 1): raise ValueError( 'Wrong number of regions for the country-specific control\ factor.') for _ in phi: if not isinstance(_, (float, int)): raise TypeError('The country-specific control factor must \ be float or integer.') if _ < 0: raise ValueError('The country-specific control factor \ must be => 0.') if _ > 1: raise ValueError('The country-specific control factor \ must be <= 1.') def __call__(self): """ Returns the social distancing parameters of the :class:`WarwickLancSEIRModel` the class relates to. Returns ------- List List of the social distancing parameters of the :class:`WarwickLancSEIRModel` the class relates to. """ return self.phi
# # VaccineParameters Class #
[docs] class VaccineParameters(object): """VaccineParameters: Base class for the vaccination-specific parameters of the model: a deterministic SEIR used by the Universities of Warwick and Lancaster to model the Covid-19 epidemic and the effects of vaccines and waning immunity on the epidemic trajectory in different countries. Parameters ---------- vac : int or float or list Country-specific vaccination rate of the susceptible population. vacb : int or float or list Country-specific booster vaccination rate. adult : list List of the proportions of each age-group that are boosted or vaccinated. nu_tra : int or float or list Vaccine effects on transmission for infected individuals of different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity). nu_symp : int or float or list Vaccine effects on symptom development for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity). nu_inf : int or float or list Vaccine effects on susceptability for susceptible individuals of different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity). nu_sev_h : int or float or list Vaccine effects on hospitalised severe outcomes for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity). nu_sev_d : int or float or list Vaccine effects on dead severe outcomes for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity). """ def __init__( self, model, vac, vacb, adult, nu_tra, nu_symp, nu_inf, nu_sev_h, nu_sev_d): super(VaccineParameters, self).__init__() # Set model if not isinstance(model, wm.WarwickLancSEIRModel): raise TypeError( 'The model must be a Warwick-Lancaster SEIR Model.') self.model = model # Check inputs format self._check_parameters_input( vac, vacb, adult, nu_tra, nu_symp, nu_inf, nu_sev_h, nu_sev_d) # Set vaccination parameters self.adult = adult if isinstance(vac, (float, int)): self.vac = vac * np.ones(len(self.model.regions)) else: self.vac = vac if isinstance(vacb, (float, int)): self.vacb = vacb * np.ones(len(self.model.regions)) else: self.vacb = vacb if isinstance(nu_tra, (float, int)): self.nu_tra = nu_tra * np.ones(6) else: self.nu_tra = nu_tra if isinstance(nu_symp, (float, int)): self.nu_symp = nu_symp * np.ones(6) else: self.nu_symp = nu_symp if isinstance(nu_inf, (float, int)): self.nu_inf = nu_inf * np.ones(6) else: self.nu_inf = nu_inf if isinstance(nu_sev_h, (float, int)): self.nu_sev_h = nu_sev_h * np.ones(6) else: self.nu_sev_h = nu_sev_h if isinstance(nu_sev_d, (float, int)): self.nu_sev_d = nu_sev_d * np.ones(6) else: self.nu_sev_d = nu_sev_d def _check_parameters_input( self, vac, vacb, adult, nu_tra, nu_symp, nu_inf, nu_sev_h, nu_sev_d): """ Check correct format of the vaccination-specific parameters input. Parameters ---------- vac : int or float or list Country-specific vaccination rate of the susceptible population. vacb : int or float or list Country-specific booster vaccination rate. adult : list List of the proportions of each age-group that are boosted or vaccinated. nu_tra : int or float or list Vaccine effects on transmission for infected individuals of different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity). nu_symp : int or float or list Vaccine effects on symptom development for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity). nu_inf : int or float or list Vaccine effects on susceptability for susceptible individuals of different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity). nu_sev_h : int or float or list Vaccine effects on hospitalised severe outcomes for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity). nu_sev_d : int or float or list Vaccine effects on dead severe outcomes for different vaccination statuses (unvaccinated, fully-vaccinated, boosted, partially-waned, fully-waned, previous-variant immunity). """ if isinstance(vac, (float, int)): vac = [vac] if np.asarray(vac).ndim != 1: raise ValueError('The country-specific vaccination rate of the \ susceptible population storage format must be 1-dimensional.') if (np.asarray(vac).shape[0] != len(self.model.regions)) and ( np.asarray(vac).shape[0] != 1): raise ValueError( 'Wrong number of regions for the country-specific \ vaccination rate of the susceptible population.') for _ in vac: if not isinstance(_, (float, int)): raise TypeError('The country-specific vaccination rate of the \ susceptible population must be float or integer.') if _ < 0: raise ValueError('The country-specific vaccination rate of the\ susceptible population must be => 0.') if isinstance(vacb, (float, int)): vacb = [vacb] if np.asarray(vacb).ndim != 1: raise ValueError('The country-specific booster vaccination rate \ storage format must be 1-dimensional.') if (np.asarray(vacb).shape[0] != len(self.model.regions)) and ( np.asarray(vacb).shape[0] != 1): raise ValueError( 'Wrong number of regions for the country-specific \ booster vaccination rate.') for _ in vacb: if not isinstance(_, (float, int)): raise TypeError('The country-specific booster vaccination \ rate must be float or integer.') if _ < 0: raise ValueError('The country-specific booster vaccination \ rate must be => 0.') if np.asarray(adult).ndim != 1: raise ValueError('The list of the proportions of each age-group \ that are boosted or vaccinated storage format must be \ 1-dimensional.') if np.asarray(adult).shape[0] != len(self.model.age_groups): raise ValueError( 'Wrong number of age-groups for the list of the \ proportions of each age-group that are boosted or \ vaccinated.') for _ in adult: if not isinstance(_, (float, int)): raise TypeError('The proportions of each age-group that are \ boosted or vaccinated must be float or integer.') if _ < 0: raise ValueError('The proportions of each age-group that are \ boosted or vaccinated must be => 0.') if _ > 1: raise ValueError('The proportions of each age-group that are \ boosted or vaccinated must be <= 1.') if isinstance(nu_tra, (float, int)): nu_tra = [nu_tra] if np.asarray(nu_tra).ndim != 1: raise ValueError('Vaccine effects on transmission for different \ vaccination statuses storage format must be 1-dimensional.') if (np.asarray(nu_tra).shape[0] != 6) and ( np.asarray(nu_tra).shape[0] != 1): raise ValueError( 'Wrong number of regions for the vaccine effects on \ transmission for different vaccination statuses.') for _ in nu_tra: if not isinstance(_, (float, int)): raise TypeError('Vaccine effects on transmission for \ different vaccination statuses must be float or integer.') if _ < 0: raise ValueError('Vaccine effects on transmission for \ different vaccination statuses must be => 0.') if isinstance(nu_symp, (float, int)): nu_symp = [nu_symp] if np.asarray(nu_symp).ndim != 1: raise ValueError('Vaccine effects on symptom development for \ different vaccination statuses storage format must be \ 1-dimensional.') if (np.asarray(nu_symp).shape[0] != 6) and ( np.asarray(nu_symp).shape[0] != 1): raise ValueError( 'Wrong number of regions for the vaccine effects on \ symptom development for different vaccination statuses.') for _ in nu_symp: if not isinstance(_, (float, int)): raise TypeError('Vaccine effects on symptom development for \ different vaccination statuses must be float or integer.') if _ < 0: raise ValueError('Vaccine effects on symptom development for \ different vaccination statuses must be => 0.') if isinstance(nu_inf, (float, int)): nu_inf = [nu_inf] if np.asarray(nu_inf).ndim != 1: raise ValueError('Vaccine effects on infectiousness for different \ vaccination statuses storage format must be 1-dimensional.') if (np.asarray(nu_inf).shape[0] != 6) and ( np.asarray(nu_inf).shape[0] != 1): raise ValueError( 'Wrong number of regions for the vaccine effects on \ infectiousness for different vaccination statuses.') for _ in nu_inf: if not isinstance(_, (float, int)): raise TypeError('Vaccine effects on infectiousness for \ different vaccination statuses must be float or integer.') if _ < 0: raise ValueError('Vaccine effects on infectiousness for \ different vaccination statuses must be => 0.') if isinstance(nu_sev_h, (float, int)): nu_sev_h = [nu_sev_h] if np.asarray(nu_sev_h).ndim != 1: raise ValueError('Vaccine effects on hospitalised severe outcomes\ for different vaccination statuses storage format must be \ 1-dimensional.') if (np.asarray(nu_sev_h).shape[0] != 6) and ( np.asarray(nu_sev_h).shape[0] != 1): raise ValueError( 'Wrong number of regions for the vaccine effects on \ hospitalised severe outcomes for different vaccination \ statuses.') for _ in nu_sev_h: if not isinstance(_, (float, int)): raise TypeError('Vaccine effects on hospitalised severe \ outcomes for different vaccination statuses must be float \ or integer.') if _ < 0: raise ValueError('Vaccine effects on hospitalised severe \ outcomes for different vaccination statuses must be => 0.') if isinstance(nu_sev_d, (float, int)): nu_sev_d = [nu_sev_d] if np.asarray(nu_sev_d).ndim != 1: raise ValueError('Vaccine effects on dead severe outcomes for \ different vaccination statuses storage format must be \ 1-dimensional.') if (np.asarray(nu_sev_d).shape[0] != 6) and ( np.asarray(nu_sev_d).shape[0] != 1): raise ValueError( 'Wrong number of regions for the vaccine effects on \ dead severe outcomes for different vaccination statuses.') for _ in nu_sev_d: if not isinstance(_, (float, int)): raise TypeError('Vaccine effects on dead severe outcomes for \ different vaccination statuses must be float or integer.') if _ < 0: raise ValueError('Vaccine effects on dead severe outcomes for \ different vaccination statuses must be => 0.') def __call__(self): """ Returns the vaccine-specific parameters of the :class:`WarwickLancSEIRModel` the class relates to. Returns ------- List List of the vaccine-specific parameters of the :class:`WarwickLancSEIRModel` the class relates to. """ return [ self.vac, self.vacb, self.adult, self.nu_tra, self.nu_symp, self.nu_inf, self.nu_sev_h, self.nu_sev_d]
# # ParametersController Class #
[docs] class ParametersController(object): """ParametersController Class: Base class for the paramaters of the model: a deterministic SEIR used by the Universities of Warwick and Lancaster to model the Covid-19 epidemic and the effects of vaccines and waning immunity 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 : WarwickLancSEIRModel The model whose parameters are stored. regional_parameters : RegParameters Class of the regional and time dependent parameters used in the simulation of the model. ICs_parameters : ICs Class of the Ics used in the simulation of the model. disease_parameters : DiseaseParameters Class of the disease-specific parameters used in the simulation of the model. transmission_parameters : Transmission Class of the rates of progression parameters used in the simulation of the model. simulation_parameters : SimParameters Class of the simulation method's parameters used in the simulation of the model. vaccine_parameters : VaccineParameters Class of the vaccine-specific parameters used in the simulation of the model. soc_dist_parameters : SocDistParameters Class of the social distancing parameters used in the simulation of the model. """ def __init__( self, model, regional_parameters, ICs_parameters, disease_parameters, transmission_parameters, simulation_parameters, vaccine_parameters, soc_dist_parameters=None): # Instantiate class super(ParametersController, self).__init__() # Set model if not isinstance(model, wm.WarwickLancSEIRModel): raise TypeError( 'The model must be a Warwick-Lancaster SEIR Model.') self.model = model # Check inputs format self._check_parameters_input( regional_parameters, ICs_parameters, disease_parameters, transmission_parameters, simulation_parameters, vaccine_parameters, soc_dist_parameters) # Set regional and time dependent parameters self.regional_parameters = regional_parameters # Set ICs parameters self.ICs = ICs_parameters # 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 vaccine-specific parameters self.vaccine_parameters = vaccine_parameters # Set social distancing parameters if soc_dist_parameters is not None: self.soc_dist_parameters = soc_dist_parameters else: self.soc_dist_parameters = SocDistParameters(model) def _check_parameters_input( self, regional_parameters, ICs_parameters, disease_parameters, transmission_parameters, simulation_parameters, vaccine_parameters, soc_dist_parameters): """ Check correct format of input of simulate method. Parameters ---------- model : WarwickLancSEIRModel The model whose parameters are stored. regional_parameters : RegParameters Class of the regional and time dependent parameters used in the simulation of the model. ICs_parameters : ICs Class of the Ics used in the simulation of the model. disease_parameters : DiseaseParameters Class of the disease-specific parameters used in the simulation of the model. transmission_parameters : Transmission Class of the rates of progression parameters used in the simulation of the model. vaccine_parameters : VaccineParameters Class of the vaccine-specific parameters used in the simulation of the model. simulation_parameters : SimParameters Class of the simulation method's parameters used in the simulation of the model. """ if not isinstance(regional_parameters, RegParameters): raise TypeError('The model`s regional and time dependent\ parameters must be of a Warwick-Lancaster 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_parameters, ICs): raise TypeError('The model`s ICs parameters must be of a Warwick\ -Lancaster SEIR Model.') if ICs_parameters.model != self.model: raise ValueError('ICs do not correspond to the right model.') if not isinstance(disease_parameters, DiseaseParameters): raise TypeError('The model`s disease-specific parameters must be \ of a Warwick-Lancaster 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, Transmission): raise TypeError('The model`s transmission-specific parameters must\ be a of a Warwick-Lancaster 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, SimParameters): raise TypeError('The model`s simulation method`s parameters must\ be of a Warwick-Lancaster SEIR Model.') if simulation_parameters.model != self.model: raise ValueError('The simulation method`s parameters do not \ correspond to the right model.') if not isinstance(vaccine_parameters, VaccineParameters): raise TypeError('The model`s vaccine-specific parameters must\ be a of a Warwick-Lancaster SEIRD Model.') if vaccine_parameters.model != self.model: raise ValueError('The vaccine-specific parameters do not \ correspond to the right model.') if soc_dist_parameters is not None: if not isinstance(soc_dist_parameters, SocDistParameters): raise TypeError('The model`s social distancing parameters must\ be of a Warwick-Lancaster 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:`WarwickLancSEIRModel` 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()) # Add ICs parameters.extend(self.ICs()) # Add transmission-specific parameters parameters.extend(self.transmission_parameters()) # Add disease-specific parameters.extend(self.disease_parameters()) # Add other simulation parameters parameters.extend(self.simulation_parameters()) return list(deepflatten(parameters, ignore=str))