Metadata-Version: 1.2
Name: epipack
Version: 0.1.4
Summary: Fast prototyping of epidemiological models based on reaction equations. Analyze the ODEs analytically or numerically, or run stochastic simulations on networks/well-mixed systems.
Home-page: https://github.com/benmaier/epipack
Author: Benjamin F. Maier
Author-email: contact@benmaier.org
License: MIT
Project-URL: Documentation, http://epipack.benmaier.org
Project-URL: Contributing Statement, https://github.com/benmaier/epipack/blob/master/CONTRIBUTING.md
Project-URL: Bug Reports, https://github.com/benmaier/epipack/issues
Project-URL: Source, https://github.com/benmaier/epipack/
Project-URL: PyPI, https://pypi.org/project/epipack/
Description: .. image:: https://github.com/benmaier/epipack/raw/master/img/logo_12_lila_medium.png
           :alt: logo
        
        Fast prototyping of epidemiological models based on reaction equations.
        Analyze the ODEs analytically or numerically, or run/animate stochastic
        simulations on networks/well-mixed systems.
        
        -  repository: https://github.com/benmaier/epipack/
        -  documentation: http://epipack.benmaier.org/
        
        .. code:: python
        
           import epipack as epk
           from epipack.vis import visualize
           import netwulf as nw
        
           network, _, __ = nw.load('cookbook/readme_vis/MHRN.json')
           N = len(network['nodes'])
           links = [ (l['source'], l['target'], 1.0) for l in network['links'] ]
        
           S, I, R = list("SIR")
           model = epk.StochasticEpiModel([S,I,R],N,links)\
                       .set_link_transmission_processes([ (I, S, 1.0, I, I) ])\
                       .set_node_transition_processes([ (I, 1.0, R) ])\
                       .set_random_initial_conditions({ S: N-5, I: 5 })
        
           visualize(model, network, sampling_dt=0.1)
        
        .. image:: https://github.com/benmaier/epipack/raw/master/img/SIR_example.gif
           :alt: sir-example
        
        Idea
        ----
        
        Simple compartmental models of infectious diseases are useful to
        investigate effects of certain processes on disease dissemination. Using
        pen and paper, quickly adding/removing compartments and transition
        processes is easy, yet the analytical and numerical analysis or
        stochastic simulations can be tedious to set up and debug—especially
        when the model changes (even slightly). ``epipack`` aims at streamlining
        this process such that all the analysis steps can be performed in an
        efficient manner, simply by defining processes based on reaction
        equations. ``epipack`` provides three main base classes to accomodate
        different problems.
        
        -  ``EpiModel``: Define a model based on transition, birth, death,
           fission, fusion, or transmission reactions, integrate the ordinary
           differential equations (ODEs) of the corresponding well-mixed system
           numerically or simulate it using Gillespie's algorithm. Process rates
           can be numerical functions of time and the system state.
        -  ``SymbolicEpiModel``: Define a model based on transition, birth,
           death, fission, fusion, or transmission reactions. Obtain the ODEs,
           fixed points, Jacobian, and the Jacobian's eigenvalues at fixed
           points as symbolic expressions. Process rates can be symbolic
           expressions of time and the system state. Set numerical parameter
           values and integrate the ODEs numerically or simulate the stochastic
           systems using Gillespie's algorithm.
        -  ``StochasticEpiModel``: Define a model based on node transition and
           link transmission reactions. Add conditional link transmission
           reactions. Simulate your model on any (un-/)directed, (un-/)weighted
           static/temporal network, or in a well-mixed system.
        
        Additionally, epipack provides a visualization framework to animate
        stochastic simulations on networks, lattices, well-mixed systems, or
        reaction-diffusion systems based on ``MatrixEpiModel``.
        
        Check out the `Example <#examples>`__ section for some demos.
        
        Note that the internal simulation algorithm for network simulations is
        based on the following paper:
        
        "Efficient sampling of spreading processes on complex networks using a
        composition and rejection algorithm", G.St-Onge, J.-G. Young, L.
        Hébert-Dufresne, and L. J. Dubé, Comput. Phys. Commun. 240, 30-37
        (2019), http://arxiv.org/abs/1808.05859.
        
        Install
        -------
        
        .. code:: bash
        
           pip install epipack
        
        ``epipack`` was developed and tested for
        
        -  Python 3.6
        -  Python 3.7
        -  Python 3.8
        
        So far, the package's functionality was tested on Mac OS X and CentOS
        only.
        
        Dependencies
        ------------
        
        ``epipack`` directly depends on the following packages which will be
        installed by ``pip`` during the installation process
        
        -  ``numpy>=1.17``
        -  ``scipy>=1.3``
        -  ``sympy==1.6``
        -  ``pyglet<1.6``
        -  ``matplotlib>=3.0.0``
        -  ``ipython>=7.14.0``
        -  ``ipywidgets>=7.5.1``
        
        Please note that **fast network simulations are only available if you
        install**
        
        -  ``SamplableSet==2.0``
           (`SamplableSet <http://github.com/gstonge/SamplableSet>`__)
        
        **manually** (pip won't do it for you).
        
        Documentation
        -------------
        
        The full documentation is available at
        `epipack.benmaier.org <http://epipack.benmaier.org>`__.
        
        Changelog
        ---------
        
        Changes are logged in a `separate
        file <https://github.com/benmaier/epipack/blob/master/CHANGELOG.md>`__.
        
        License
        -------
        
        This project is licensed under the `MIT
        License <https://github.com/benmaier/epipack/blob/master/LICENSE>`__.
        Note that this excludes any images/pictures/figures shown here or in the
        documentation.
        
        Contributing
        ------------
        
        If you want to contribute to this project, please make sure to read the
        `code of
        conduct <https://github.com/benmaier/epipack/blob/master/CODE_OF_CONDUCT.md>`__
        and the `contributing
        guidelines <https://github.com/benmaier/epipack/blob/master/CONTRIBUTING.md>`__.
        In case you're wondering about what to contribute, we're always
        collecting ideas of what we want to implement next in the `outlook
        notes <https://github.com/benmaier/epipack/blob/master/OUTLOOK.md>`__.
        
        |Contributor Covenant|
        
        Examples
        --------
        
        Let's define an SIRS model with infection rate ``eta``, recovery rate
        ``rho``, and waning immunity rate ``omega`` and analyze the system
        
        Pure Numeric Models
        ~~~~~~~~~~~~~~~~~~~
        
        Basic Definition (EpiModel)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
        
        Define a pure numeric model with ``EpiModel``. Integrate the ODEs or
        simulate the system stochastically.
        
        .. code:: python
        
           from epipack import EpiModel
           import matplotlib.pyplot as plt
           import numpy as np
        
           S, I, R = list("SIR")
           N = 1000
        
           SIRS = EpiModel([S,I,R],N)\
               .set_processes([
                   #### transmission process ####
                   # S + I (eta=2.5/d)-> I + I
                   (S, I, 2.5, I, I),
        
                   #### transition processes ####
                   # I (rho=1/d)-> R
                   # R (omega=1/14d)-> S
                   (I, 1, R),
                   (R, 1/14, S),
               ])\
               .set_initial_conditions({S:N-10, I:10})
        
           t = np.linspace(0,40,1000) 
           result_int = SIRS.integrate(t)
           t_sim, result_sim = SIRS.simulate(t[-1])
        
           for C in SIRS.compartments:
               plt.plot(t, result_int[C])
               plt.plot(t_sim, result_sim[C])
        
        .. image:: https://github.com/benmaier/epipack/raw/master/img/numeric_model.png
           :alt: numeric-model
        
        Functional Rates
        ^^^^^^^^^^^^^^^^
        
        It's also straight-forward to define temporally varying (functional)
        rates.
        
        .. code:: python
        
           import numpy as np
           from epipack import SISModel
        
           N = 100
           recovery_rate = 1.0
        
           def infection_rate(t, y, *args, **kwargs):
               return 3 + np.sin(2*np.pi*t/100)
        
           SIS = SISModel(
                       infection_rate=infection_rate, 
                       recovery_rate=recovery_rate,
                       initial_population_size=N
                       )\
                   .set_initial_conditions({
                       'S': 90,
                       'I': 10,
                   })
        
           t = np.arange(200)
           result_int = SIS.integrate(t)
           t_sim, result_sim = SIS.simulate(199)
        
           for C in SIS.compartments:
               plt.plot(t_sim, result_sim[C])
               plt.plot(t, result_int[C])
        
        .. image:: https://github.com/benmaier/epipack/raw/master/img/numeric_model_time_varying_rate.png
           :alt: numeric-model-time-varying
        
        Symbolic Models
        ~~~~~~~~~~~~~~~
        
        Basic Definition
        ^^^^^^^^^^^^^^^^
        
        Symbolic models are more powerful because they can do the same as the
        pure numeric models while also offering the possibility to do analytical
        evaluations
        
        .. code:: python
        
           from epipack import SymbolicEpiModel
           import sympy as sy
        
           S, I, R, eta, rho, omega = sy.symbols("S I R eta rho omega")
        
           SIRS = SymbolicEpiModel([S,I,R])\
               .set_processes([
                   (S, I, eta, I, I),
                   (I, rho, R),
                   (R, omega, S),
               ])    
        
        Analytical Evaluations
        ^^^^^^^^^^^^^^^^^^^^^^
        
        Print the ODE system in a Jupyter notebook
        
        .. code:: python
        
           >>> SIRS.ODEs_jupyter()
        
        .. image:: https://github.com/benmaier/epipack/raw/master/img/ODEs.png
           :alt: ODEs
        
        Get the Jacobian
        
        .. code:: python
        
           >>> SIRS.jacobian()
        
        .. image:: https://github.com/benmaier/epipack/raw/master/img/jacobian.png
           :alt: Jacobian
        
        Find the fixed points
        
        .. code:: python
        
           >>> SIRS.find_fixed_points()
        
        .. image:: https://github.com/benmaier/epipack/raw/master/img/fixed_points.png
           :alt: fixedpoints
        
        Get the eigenvalues at the disease-free state in order to find the
        epidemic threshold
        
        .. code:: python
        
           >>> SIRS.get_eigenvalues_at_disease_free_state()
           {-omega: 1, eta - rho: 1, 0: 1}
        
        Numerical Evaluations
        ^^^^^^^^^^^^^^^^^^^^^
        
        Set numerical parameter values and integrate the ODEs numerically
        
        .. code:: python
        
           >>> SIRS.set_parameter_values({eta: 2.5, rho: 1.0, omega:1/14})
           >>> t = np.linspace(0,40,1000)
           >>> result = SIRS.integrate(t)
        
        If set up as
        
        .. code:: python
        
           >>> N = 10000
           >>> SIRS = SymbolicEpiModel([S,I,R],N)
        
        the system can simulated directly.
        
        .. code:: python
        
           >>> t_sim, result_sim = SIRS.simulate(40)
        
        Temporally Varying Rates
        ^^^^^^^^^^^^^^^^^^^^^^^^
        
        Let's set up some temporally varying rates
        
        .. code:: python
        
           from epipack import SymbolicEpiModel
           import sympy as sy
        
           S, I, R, eta, rho, omega, t, T = \
                   sy.symbols("S I R eta rho omega t T")
        
           N = 1000
           SIRS = SymbolicEpiModel([S,I,R],N)\
               .set_processes([
                   (S, I, 2+sy.cos(2*sy.pi*t/T), I, I),
                   (I, rho, R),
                   (R, omega, S),
               ])  
        
           SIRS.ODEs_jupyter()
        
        .. image:: https://github.com/benmaier/epipack/raw/master/img/SIRS-forced-ODEs.png
           :alt: SIRS-forced-ODEs
        
        Now we can integrate the ODEs or simulate the system using Gillespie's
        SSA for inhomogeneous Poisson processes.
        
        .. code:: python
        
           import numpy as np
        
           SIRS.set_parameter_values({
               rho : 1,
               omega : 1/14,
               T : 100,
           })
           SIRS.set_initial_conditions({S:N-100, I:100})
           _t = np.linspace(0,200,1000)
           result = SIRS.integrate(_t)
           t_sim, result_sim = SIRS.simulate(max(_t))
        
        .. image:: https://github.com/benmaier/epipack/raw/master/img/symbolic_model_time_varying_rate.png
           :alt: SIRS-forced-results
        
        Interactive Analyses
        ^^^^^^^^^^^^^^^^^^^^
        
        ``epipack`` offers a classs called ``InteractiveIntegrator`` that allows
        an interactive exploration of a system in a Jupyter notebook.
        
        Make sure to first run
        
        .. code:: bash
        
           %matplotlib widget
        
        in a cell.
        
        .. code:: python
        
           from epipack import SymbolicEpiModel
           from epipack.interactive import InteractiveIntegrator, Range, LogRange
           import sympy
        
           S, I, R, R0, tau, omega = sympy.symbols("S I R R_0 tau omega")
        
           I0 = 0.01
           model = SymbolicEpiModel([S,I,R])\
                        .set_processes([
                               (S, I, R0/tau, I, I),
                               (I, 1/tau, R),
                               (R, omega, S),
                           ])\
                        .set_initial_conditions({S:1-I0, I:I0})
        
           # define a log slider, a linear slider and a constant value
           parameters = {
               R0: LogRange(min=0.1,max=10,step_count=1000),
               tau: Range(min=0.1,max=10,value=8.0),
               omega: 1/14
           }
        
           t = np.logspace(-3,2,1000)
           InteractiveIntegrator(model, parameters, t, figsize=(4,4))
        
        .. image:: https://github.com/benmaier/epipack/raw/master/img/interactive.gif
           :alt: interactive
        
        Pure Stochastic Models
        ~~~~~~~~~~~~~~~~~~~~~~
        
        On a Network
        ^^^^^^^^^^^^
        
        Let's simulate an SIRS system on a random graph (using the parameter
        definitions above).
        
        .. code:: python
        
           from epipack import StochasticEpiModel
           import networkx as nx
        
           k0 = 50
           R0 = 2.5
           rho = 1
           eta = R0 * rho / k0
           omega = 1/14
           N = int(1e4)
           edges = [ (e[0], e[1], 1.0) for e in \
                     nx.fast_gnp_random_graph(N,k0/(N-1)).edges() ]
        
           SIRS = StochasticEpiModel(
                       compartments=list('SIR'),
                       N=N,
                       edge_weight_tuples=edges
                       )\
                   .set_link_transmission_processes([
                       ('I', 'S', eta, 'I', 'I'),
                   ])\
                   .set_node_transition_processes([
                       ('I', rho, 'R'),
                       ('R', omega, 'S'),
                   ])\        
                   .set_random_initial_conditions({
                                                   'S': N-100,
                                                   'I': 100
                                                  })
           t_s, result_s = SIRS.simulate(40)
        
        .. image:: https://github.com/benmaier/epipack/raw/master/img/network_simulation.png
           :alt: network-simulation
        
        Visualize
        ^^^^^^^^^
        
        Likewise, it's straight-forward to visualize this system
        
        .. code:: python
        
           >>> from epipack.vis import visualize
           >>> from epipack.networks import get_random_layout
           >>> layouted_network = get_random_layout(N, edges)
           >>> visualize(SIRS, layouted_network, sampling_dt=0.1, config={'draw_links': False})
        
        .. image:: https://github.com/benmaier/epipack/raw/master/img/SIRS_visualization.gif
           :alt: sirs-example
        
        On a Lattice
        ^^^^^^^^^^^^
        
        A lattice is nothing but a network, we can use ``get_grid_layout`` and
        ``get_2D_lattice_links`` to set up a visualization.
        
        .. code:: python
        
           from epipack.vis import visualize
           from epipack import (
               StochasticSIRModel, 
               get_2D_lattice_links, 
               get_grid_layout
           )
        
           # define links and network layout
           N_side = 100
           N = N_side**2
           links = get_2D_lattice_links(N_side, periodic=True, diagonal_links=True)
           lattice = get_grid_layout(N)
        
           # define model
           R0 = 3; recovery_rate = 1/8
           model = StochasticSIRModel(N,R0,recovery_rate,
                                      edge_weight_tuples=links)
           model.set_random_initial_conditions({'I':20,'S':N-20})
        
           sampling_dt = 1
        
           visualize(model,lattice,sampling_dt,
                   config={
                            'draw_nodes_as_rectangles':True,
                            'draw_links':False,
                          }
                     )
        
        .. image:: https://github.com/benmaier/epipack/raw/master/img/SIR_lattice_vis.gif
           :alt: sir-lattice
        
        Reaction-Diffusion Models
        ~~~~~~~~~~~~~~~~~~~~~~~~~
        
        Since reaction-diffusion systems in discrete space can be interpreted as
        being based on reaction equations, we can set those up using
        ``epipack``'s framework.
        
        Checkout the docs on `Reaction-Diffusion
        Systems <http://epipack.benmaier.org/tutorial/reaction_diffusion.html>`__.
        
        Every node in a network is associated with a compartment and we're using
        ``MatrixEpiModel`` because it's faster than ``EpiModel``.
        
        .. code:: python
        
           from epipack import MatrixEpiModel
        
           N = 100
           base_compartments = list("SIR")
           compartments = [ (node, C) for node in range(N) for C in base_compartments ]
           model = MatrixEpiModel(compartments)
        
        Now, we define both epidemiological and movement processes on a
        hypothetical list ``links``.
        
        .. code:: python
        
           infection_rate = 2
           recovery_rate = 1
           mobility_rate = 0.1
        
           quadratic_processes = []
           linear_processes = []
        
           for node in range(N):
               quadratic_processes.append(
                       (  (node, "S"), (node, "I"), infection_rate, (node, "I"), (node, "I") ),
                   )
        
               linear_processes.append(
                         ( (node, "I"), recovery_rate, (node, "R") ) 
                   )
        
           for u, v, w in links:
               for C in base_compartments:
        
                   linear_processes.extend([
                             ( (u, C), w*mobility_rate, (v, C) ),
                             ( (v, C), w*mobility_rate, (u, C) ),
                       ])
        
        .. image:: https://github.com/benmaier/epipack/raw/master/img/reac_diff_lattice.gif
           :alt: reac-diff-lattice
        
        Dev notes
        ---------
        
        Fork this repository, clone it, and install it in dev mode.
        
        .. code:: bash
        
           git clone git@github.com:YOURUSERNAME/epipack.git
           make
        
        If you want to upload to PyPI, first convert the new ``README.md`` to
        ``README.rst``
        
        .. code:: bash
        
           make readme
        
        It will give you warnings about bad ``.rst``-syntax. Fix those errors in
        ``README.rst``. Then wrap the whole thing
        
        .. code:: bash
        
           make pypi
        
        It will probably give you more warnings about ``.rst``-syntax. Fix those
        until the warnings disappear. Then do
        
        .. code:: bash
        
           make upload
        
        .. |Contributor Covenant| image:: https://img.shields.io/badge/Contributor%20Covenant-v1.4%20adopted-ff69b4.svg
           :target: code-of-conduct.md
        
Platform: UNKNOWN
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Requires-Python: >=3.6
