From 7d31e2958d31f9b736b6c38a441351d41a267149 Mon Sep 17 00:00:00 2001 From: Samuel Brand Date: Wed, 28 Feb 2024 13:32:09 +0000 Subject: [PATCH 01/13] more doc strings --- EpiAware/Project.toml | 3 +- EpiAware/src/EpiAware.jl | 60 ++++++---- EpiAware/src/epimodel.jl | 113 +++++++++++++++--- .../toy_model_log_infs_RW.jl | 1 - 4 files changed, 135 insertions(+), 42 deletions(-) diff --git a/EpiAware/Project.toml b/EpiAware/Project.toml index 468202dbf..92629ff92 100644 --- a/EpiAware/Project.toml +++ b/EpiAware/Project.toml @@ -6,6 +6,7 @@ version = "0.1.0-DEV" [deps] DataFramesMeta = "1313f7d8-7da2-5740-9ea0-a2ca25f37964" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" +DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" LogExpFunctions = "2ab3a3ac-af41-5b50-aa03-7779005ae688" Optim = "429524aa-4258-5aef-a3af-852621145aeb" @@ -17,6 +18,7 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" Turing = "fce5fe82-541a-59a6-adf8-730c64b5f9a0" [compat] +DataFramesMeta = "0.14" Distributions = "0.25" LinearAlgebra = "1.9" LogExpFunctions = "0.3" @@ -27,5 +29,4 @@ Random = "1.9" ReverseDiff = "1.15" SparseArrays = "1.10" Turing = "0.30" -DataFramesMeta = "0.14" julia = "1.9" diff --git a/EpiAware/src/EpiAware.jl b/EpiAware/src/EpiAware.jl index 29f9d2e03..cd13dab2d 100644 --- a/EpiAware/src/EpiAware.jl +++ b/EpiAware/src/EpiAware.jl @@ -1,35 +1,47 @@ """ - EpiAware + module EpiAware -This module provides functionality for calculating Rt (effective reproduction number) with and without - considering renewal processes. +`EpiAware` provides functionality for fitting epidemiological models to data. It is built on + top of the `Turing` probabilistic programming language, and provides a set of utilities + for constructing and fitting models to data. -# Dependencies +## Core model structure -- Distributions: for working with probability distributions. -- Turing: for probabilistic programming. -- LogExpFunctions: for working with logarithmic, logistic and exponential functions. -- LinearAlgebra: for linear algebra operations. -- SparseArrays: for working with sparse arrays. -- Random: for generating random numbers. -- ReverseDiff: for automatic differentiation. -- Optim: for optimization algorithms. -- Zygote: for automatic differentiation. +An epidemiological model in `EpiAware` consists of composable structs with core abstract + types. The core types are: + +1. `AbstractEpiModel`: Subtypes of this abstract type represent different models for the + spread of an infectious disease. Each model type has a corresponding + `make_epi_inference_model` function that constructs a `Turing` model for fitting the + model to data. Implemented concrete subtypes: + - `Renewal`: A renewal process model for the spread of an infectious disease. + - `ExpGrowthRate`: An exponential growth rate model for the spread of an infectious + disease. + - `DirectInfections`: A model for the spread of an infectious disease based on modelling + direct infections. +2. `AbstractLatentProcess`: Subtypes of this abstract type represent different latent + processes that can be used in an epidemiological model. Implemented concrete subtype: + - `RandomWalkLatentProcess`: A random walk latent process. +3. `AbstractObservationProcess`: Subtypes of this abstract type represent different + observation processes that can be used in an epidemiological model. + Implemented concrete subtypes: + - `DelayObservation`: An observation process that models the delay between the time + of infection and the time of observation as a convolution, followed by a negative + binomial distributed sample. + +## Imports + +$(IMPORTS) + +## Exports + +$(EXPORTS) """ module EpiAware -using Distributions, - Turing, - LogExpFunctions, - LinearAlgebra, - SparseArrays, - Random, - ReverseDiff, - Optim, - Parameters, - QuadGK, - DataFramesMeta +using Distributions, Turing, LogExpFunctions, LinearAlgebra, SparseArrays, Random, + ReverseDiff, Optim, Parameters, QuadGK, DataFramesMeta, DocStringExtensions # Exported utilities export create_discrete_pmf, spread_draws, scan diff --git a/EpiAware/src/epimodel.jl b/EpiAware/src/epimodel.jl index adb993575..fdcdafd84 100644 --- a/EpiAware/src/epimodel.jl +++ b/EpiAware/src/epimodel.jl @@ -1,11 +1,41 @@ +""" + $(TYPEDEF) + +Abstract type for models that define the latent infection process. +""" abstract type AbstractEpiModel end -struct EpiData{T <: Real, F <: Function} +""" + $(TYPEDEF) + +Immutable struct for storing fixed parameters of the latent infection process. + +$(TYPEDFIELDS) +""" +struct EpiData{T <: AbstractFloat, F <: Function} + """ + Discrete time generation interval. First element is probability of infectee on time + step after infection time step. + """ gen_int::Vector{T} + "length of generation interval vector." len_gen_int::Integer + "Bijector/link/transformation function for unconstrained latent infections." transformation::F - #Inner constructors for EpiData object + @doc """ + function EpiData(gen_int, transformation::Function) + + Constructor function for an immutable struct for storing fixed parameters of the latent + infection process. + + # Arguments + - `gen_int`: Discrete time generation interval. First element is probability of infectee on + time step after infection time step. + - `transformation`: Bijector/link/transformation function for unconstrained latent + infections. + + """ function EpiData(gen_int, transformation::Function) @assert all(gen_int .>= 0) "Generation interval must be non-negative" @@ -16,6 +46,25 @@ struct EpiData{T <: Real, F <: Function} transformation) end + @doc """ + function EpiData(gen_distribution::ContinuousDistribution; + D_gen, + Δd = 1.0, + transformation::Function = exp) + + Constructor function for an immutable struct for storing fixed parameters of the latent + infection process. + + # Arguments + - `gen_distribution::ContinuousDistribution`: Continuous generation interval distribution. + This is converted to a discrete distribution using `create_discrete_pmf`, and then left + truncated to condition on zero infectees on the same time step as the infector. + - `D_gen`: Right truncation of the generation interval distribution. + - `Δd`: Time step size for discretisation of the generation interval distribution. + - `transformation`: Bijector/link/transformation function for unconstrained latent + infections. + + """ function EpiData(gen_distribution::ContinuousDistribution; D_gen, Δd = 1.0, @@ -27,45 +76,77 @@ struct EpiData{T <: Real, F <: Function} end end +""" + $(TYPEDEF) + +A struct representing a direct infections model for latent infections. + +# Fields +$(TYPEDFIELDS) +""" struct DirectInfections{S <: Sampleable} <: AbstractEpiModel + "Latent infection process data as an `EpiData` object." data::EpiData + "The prior distribution for initial infections" initialisation_prior::S end +""" + $(TYPEDEF) + +A struct representing an exponetial growth rate model for latent infections. + +# Fields +$(TYPEDFIELDS) +""" struct ExpGrowthRate{S <: Sampleable} <: AbstractEpiModel + "Latent infection process data as an `EpiData` object." data::EpiData + "The prior distribution for initial infections" initialisation_prior::S end +""" + $(TYPEDEF) + +A struct representing a renewal model for latent infections. + +# Fields +$(TYPEDFIELDS) +""" struct Renewal{S <: Sampleable} <: AbstractEpiModel data::EpiData initialisation_prior::S end -""" - function (epimodel::Renewal)(recent_incidence, Rt) +renewal_eqn::String = raw""" + ```math + I_t = R_t \sum_{i=1}^{n-1} I_{t-i} g_i + ``` + """ + +@doc """ + $(TYPEDEF) Compute new incidence based on recent incidence and Rt. This is a callable function on `Renewal` structs, that encodes new incidence prediction given recent incidence and Rt according to basic renewal process. +"""*renewal_eqn* + """ -```math -I_t = R_t \\sum_{i=1}^{n-1} I_{t-i} g_i -``` + where `I_t` is the new incidence, `R_t` is the reproduction number, `I_{t-i}` is the recent incidence + and `g_i` is the generation interval. -where `I_t` is the new incidence, `R_t` is the reproduction number, `I_{t-i}` is the recent incidence -and `g_i` is the generation interval. + # Arguments + - `recent_incidence`: Array of recent incidence values. + - `Rt`: Reproduction number. -# Arguments -- `recent_incidence`: Array of recent incidence values. -- `Rt`: Reproduction number. - -# Returns -- Tuple containing the updated incidence array and the new incidence value. + # Returns + - Tuple containing the updated incidence array and the new incidence value. -""" + """ function (epimodel::Renewal)(recent_incidence, Rt) new_incidence = Rt * dot(recent_incidence, epimodel.data.gen_int) return ([new_incidence; recent_incidence[1:(epimodel.data.len_gen_int - 1)]], diff --git a/EpiAware/test/predictive_checking/toy_model_log_infs_RW.jl b/EpiAware/test/predictive_checking/toy_model_log_infs_RW.jl index 1170a634a..7b75557c0 100644 --- a/EpiAware/test/predictive_checking/toy_model_log_infs_RW.jl +++ b/EpiAware/test/predictive_checking/toy_model_log_infs_RW.jl @@ -94,7 +94,6 @@ In this case we use the `DirectInfections` model. rwp = EpiAware.RandomWalkLatentProcess(Normal(), truncated(Normal(0.0, 0.01), 0.0, 0.5)) -obs_mdl = delay_observations_model() #Define the observation model - no delay model time_horizon = 100 From 8ae3a8aa35b55dd08d340802c5f6cf984b5ba4ec Mon Sep 17 00:00:00 2001 From: Samuel Brand Date: Wed, 28 Feb 2024 14:11:24 +0000 Subject: [PATCH 02/13] remove bad doc string --- EpiAware/src/epimodel.jl | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/EpiAware/src/epimodel.jl b/EpiAware/src/epimodel.jl index fdcdafd84..0dbd1a2fe 100644 --- a/EpiAware/src/epimodel.jl +++ b/EpiAware/src/epimodel.jl @@ -125,28 +125,6 @@ renewal_eqn::String = raw""" ``` """ -@doc """ - $(TYPEDEF) - -Compute new incidence based on recent incidence and Rt. - -This is a callable function on `Renewal` structs, that encodes new incidence prediction -given recent incidence and Rt according to basic renewal process. -"""*renewal_eqn* - """ - - where `I_t` is the new incidence, `R_t` is the reproduction number, `I_{t-i}` is the recent incidence - and `g_i` is the generation interval. - - - # Arguments - - `recent_incidence`: Array of recent incidence values. - - `Rt`: Reproduction number. - - # Returns - - Tuple containing the updated incidence array and the new incidence value. - - """ function (epimodel::Renewal)(recent_incidence, Rt) new_incidence = Rt * dot(recent_incidence, epimodel.data.gen_int) return ([new_incidence; recent_incidence[1:(epimodel.data.len_gen_int - 1)]], From 807fd87137216a7f26fa8702f20ab3edd29386fa Mon Sep 17 00:00:00 2001 From: Samuel Brand Date: Thu, 29 Feb 2024 10:03:43 +0000 Subject: [PATCH 03/13] add compat for DocStringExtenstions --- EpiAware/Project.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/EpiAware/Project.toml b/EpiAware/Project.toml index 92629ff92..ba03db338 100644 --- a/EpiAware/Project.toml +++ b/EpiAware/Project.toml @@ -19,6 +19,7 @@ Turing = "fce5fe82-541a-59a6-adf8-730c64b5f9a0" [compat] DataFramesMeta = "0.14" +DocStringExtensions = "0.9" Distributions = "0.25" LinearAlgebra = "1.9" LogExpFunctions = "0.3" From 6764db833c5475bc64deed44da01c55c04579d41 Mon Sep 17 00:00:00 2001 From: Samuel Brand <48288458+SamuelBrand1@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:58:44 +0000 Subject: [PATCH 04/13] Update EpiAware/src/EpiAware.jl AbstractModel doc mention Co-authored-by: Sam Abbott --- EpiAware/src/EpiAware.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EpiAware/src/EpiAware.jl b/EpiAware/src/EpiAware.jl index 876ada1ae..94a70bc6c 100644 --- a/EpiAware/src/EpiAware.jl +++ b/EpiAware/src/EpiAware.jl @@ -9,7 +9,8 @@ An epidemiological model in `EpiAware` consists of composable structs with core abstract types. The core types are: - +1. `AbstractModel`: This overarching type is used to abstract `Turing` models and is inheried by the other abstract types we use. +`` 1. `AbstractEpiModel`: Subtypes of this abstract type represent different models for the spread of an infectious disease. Each model type has a corresponding `make_epi_inference_model` function that constructs a `Turing` model for fitting the From e7ffcf521835013ad0bfcebc81e22bc37fdb9e47 Mon Sep 17 00:00:00 2001 From: Samuel Brand <48288458+SamuelBrand1@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:58:59 +0000 Subject: [PATCH 05/13] renumber Co-authored-by: Sam Abbott --- EpiAware/src/EpiAware.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EpiAware/src/EpiAware.jl b/EpiAware/src/EpiAware.jl index 94a70bc6c..be29e10e6 100644 --- a/EpiAware/src/EpiAware.jl +++ b/EpiAware/src/EpiAware.jl @@ -11,7 +11,7 @@ An epidemiological model in `EpiAware` consists of composable structs with core types. The core types are: 1. `AbstractModel`: This overarching type is used to abstract `Turing` models and is inheried by the other abstract types we use. `` -1. `AbstractEpiModel`: Subtypes of this abstract type represent different models for the +2. `AbstractEpiModel`: Subtypes of this abstract type represent different models for the spread of an infectious disease. Each model type has a corresponding `make_epi_inference_model` function that constructs a `Turing` model for fitting the model to data. Implemented concrete subtypes: From ff8b1295170a73858215ba0b666b4483c9c5d078 Mon Sep 17 00:00:00 2001 From: Samuel Brand <48288458+SamuelBrand1@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:59:13 +0000 Subject: [PATCH 06/13] update name Co-authored-by: Sam Abbott --- EpiAware/src/EpiAware.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EpiAware/src/EpiAware.jl b/EpiAware/src/EpiAware.jl index be29e10e6..2b8ebda88 100644 --- a/EpiAware/src/EpiAware.jl +++ b/EpiAware/src/EpiAware.jl @@ -22,7 +22,7 @@ An epidemiological model in `EpiAware` consists of composable structs with core direct infections. 2. `AbstractLatentProcess`: Subtypes of this abstract type represent different latent processes that can be used in an epidemiological model. Implemented concrete subtype: - - `RandomWalkLatentProcess`: A random walk latent process. + - `RandomWalk`: A random walk latent process. 3. `AbstractObservationProcess`: Subtypes of this abstract type represent different observation processes that can be used in an epidemiological model. Implemented concrete subtypes: From 5a5f1e64d79062d52aa53c2fa66e6681e094a500 Mon Sep 17 00:00:00 2001 From: Samuel Brand <48288458+SamuelBrand1@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:59:26 +0000 Subject: [PATCH 07/13] rename Co-authored-by: Sam Abbott --- EpiAware/src/EpiAware.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EpiAware/src/EpiAware.jl b/EpiAware/src/EpiAware.jl index 2b8ebda88..df7d9463a 100644 --- a/EpiAware/src/EpiAware.jl +++ b/EpiAware/src/EpiAware.jl @@ -20,7 +20,7 @@ An epidemiological model in `EpiAware` consists of composable structs with core disease. - `DirectInfections`: A model for the spread of an infectious disease based on modelling direct infections. -2. `AbstractLatentProcess`: Subtypes of this abstract type represent different latent +3. `AbstractLatentModel`: Subtypes of this abstract type represent different latent processes that can be used in an epidemiological model. Implemented concrete subtype: - `RandomWalk`: A random walk latent process. 3. `AbstractObservationProcess`: Subtypes of this abstract type represent different From 8a4b6d57d7cfdfa24a886488408714a713af5cdd Mon Sep 17 00:00:00 2001 From: Samuel Brand <48288458+SamuelBrand1@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:59:35 +0000 Subject: [PATCH 08/13] rename Co-authored-by: Sam Abbott --- EpiAware/src/EpiAware.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EpiAware/src/EpiAware.jl b/EpiAware/src/EpiAware.jl index df7d9463a..f4b829b05 100644 --- a/EpiAware/src/EpiAware.jl +++ b/EpiAware/src/EpiAware.jl @@ -23,7 +23,7 @@ An epidemiological model in `EpiAware` consists of composable structs with core 3. `AbstractLatentModel`: Subtypes of this abstract type represent different latent processes that can be used in an epidemiological model. Implemented concrete subtype: - `RandomWalk`: A random walk latent process. -3. `AbstractObservationProcess`: Subtypes of this abstract type represent different +4. `AbstractObservationModel`: Subtypes of this abstract type represent different observation processes that can be used in an epidemiological model. Implemented concrete subtypes: - `DelayObservation`: An observation process that models the delay between the time From a16e5db6f470ec9a1764d983ae7c50f35a2c27e5 Mon Sep 17 00:00:00 2001 From: Samuel Brand <48288458+SamuelBrand1@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:59:45 +0000 Subject: [PATCH 09/13] rename Co-authored-by: Sam Abbott --- EpiAware/src/EpiAware.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EpiAware/src/EpiAware.jl b/EpiAware/src/EpiAware.jl index f4b829b05..cda3ebdb5 100644 --- a/EpiAware/src/EpiAware.jl +++ b/EpiAware/src/EpiAware.jl @@ -13,7 +13,7 @@ An epidemiological model in `EpiAware` consists of composable structs with core `` 2. `AbstractEpiModel`: Subtypes of this abstract type represent different models for the spread of an infectious disease. Each model type has a corresponding - `make_epi_inference_model` function that constructs a `Turing` model for fitting the + `make_epi_aware` function that constructs a `Turing` model for fitting the model to data. Implemented concrete subtypes: - `Renewal`: A renewal process model for the spread of an infectious disease. - `ExpGrowthRate`: An exponential growth rate model for the spread of an infectious From b15ec12c91045f43a1cb5c176fd8da93232e7a24 Mon Sep 17 00:00:00 2001 From: Samuel Brand <48288458+SamuelBrand1@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:59:54 +0000 Subject: [PATCH 10/13] rename Co-authored-by: Sam Abbott --- EpiAware/src/EpiAware.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EpiAware/src/EpiAware.jl b/EpiAware/src/EpiAware.jl index cda3ebdb5..812960d01 100644 --- a/EpiAware/src/EpiAware.jl +++ b/EpiAware/src/EpiAware.jl @@ -24,7 +24,7 @@ An epidemiological model in `EpiAware` consists of composable structs with core processes that can be used in an epidemiological model. Implemented concrete subtype: - `RandomWalk`: A random walk latent process. 4. `AbstractObservationModel`: Subtypes of this abstract type represent different - observation processes that can be used in an epidemiological model. + observation models that can be used in an epidemiological model. Implemented concrete subtypes: - `DelayObservation`: An observation process that models the delay between the time of infection and the time of observation as a convolution, followed by a negative From 2efce6d025388d54bf53d8c418967bc6856688da Mon Sep 17 00:00:00 2001 From: Samuel Brand Date: Thu, 29 Feb 2024 12:02:53 +0000 Subject: [PATCH 11/13] reorder Project.toml --- EpiAware/Project.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EpiAware/Project.toml b/EpiAware/Project.toml index ba03db338..b5ddd270c 100644 --- a/EpiAware/Project.toml +++ b/EpiAware/Project.toml @@ -19,10 +19,10 @@ Turing = "fce5fe82-541a-59a6-adf8-730c64b5f9a0" [compat] DataFramesMeta = "0.14" -DocStringExtensions = "0.9" Distributions = "0.25" -LinearAlgebra = "1.9" +DocStringExtensions = "0.9" LogExpFunctions = "0.3" +LinearAlgebra = "1.9" Optim = "1.9" Parameters = "0.12" QuadGK = "2.9" From 67753c306134ed13ef0ecea6bb3e45d43ee5d825 Mon Sep 17 00:00:00 2001 From: Samuel Brand Date: Thu, 29 Feb 2024 13:39:38 +0000 Subject: [PATCH 12/13] fixed compat order --- EpiAware/Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EpiAware/Project.toml b/EpiAware/Project.toml index b5ddd270c..5508f766d 100644 --- a/EpiAware/Project.toml +++ b/EpiAware/Project.toml @@ -21,8 +21,8 @@ Turing = "fce5fe82-541a-59a6-adf8-730c64b5f9a0" DataFramesMeta = "0.14" Distributions = "0.25" DocStringExtensions = "0.9" -LogExpFunctions = "0.3" LinearAlgebra = "1.9" +LogExpFunctions = "0.3" Optim = "1.9" Parameters = "0.12" QuadGK = "2.9" From d635af9fdaee3b8e2da7604cfed11b085b013646 Mon Sep 17 00:00:00 2001 From: Samuel Brand <48288458+SamuelBrand1@users.noreply.github.com> Date: Thu, 29 Feb 2024 13:40:23 +0000 Subject: [PATCH 13/13] Update EpiAware/src/EpiAware.jl Co-authored-by: Sam Abbott --- EpiAware/src/EpiAware.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/EpiAware/src/EpiAware.jl b/EpiAware/src/EpiAware.jl index 7b4c28b48..e7ddec694 100644 --- a/EpiAware/src/EpiAware.jl +++ b/EpiAware/src/EpiAware.jl @@ -10,7 +10,6 @@ An epidemiological model in `EpiAware` consists of composable structs with core abstract types. The core types are: 1. `AbstractModel`: This overarching type is used to abstract `Turing` models and is inheried by the other abstract types we use. -`` 2. `AbstractEpiModel`: Subtypes of this abstract type represent different models for the spread of an infectious disease. Each model type has a corresponding `make_epi_aware` function that constructs a `Turing` model for fitting the